File indexing completed on 2023-10-01 04:14:07

0001 /********************************************f*******************************
0002                           mapmanager.cpp  -  description
0003                              -------------------
0004     begin                : Wed Mar 7 2001
0005     copyright            : (C) 2001 by KMud Development Team
0006                            (C) 2007 Tomas Mecir <kmuddy@kmuddy.com>
0007     email                : kmud-devel@kmud.de
0008  ***************************************************************************/
0009 
0010 /***************************************************************************
0011  *                                                                         *
0012  *   This program is free software; you can redistribute it and/or modify  *
0013  *   it under the terms of the GNU General Public License as published by  *
0014  *   the Free Software Foundation; either version 2 of the License, or     *
0015  *   (at your option) any later version.                                   *
0016  *                                                                         *
0017  ***************************************************************************/
0018 
0019 #include "cmapmanager.h"
0020 
0021 #include <kdebug.h>
0022 #include <kstandarddirs.h>
0023 #include <klocale.h>
0024 #include <kservicetypetrader.h>
0025 #include <kmessagebox.h>
0026 #include <kstandardaction.h>
0027 #include <kfiledialog.h>
0028 #include <kpagedialog.h>
0029 
0030 #include <QIcon>
0031 #include <QQueue>
0032 #include <QTimer>
0033 #include <QUndoStack>
0034 
0035 #include "cmapzone.h"
0036 #include "cmappath.h"
0037 #include "cmaptext.h"
0038 #include "cmaproom.h"
0039 #include "cmapview.h"
0040 #include "cmaplevel.h"
0041 #include "cmapview.h"
0042 #include "cmaptoolbase.h"
0043 #include "cmappluginbase.h"
0044 #include "cmapzonemanager.h"
0045 
0046 #include "cmapcmdelementcreate.h"
0047 #include "cmapcmdelementdelete.h"
0048 #include "cmapcmdelementproperties.h"
0049 #include "cmapcmdgroup.h"
0050 #include "cmapcmdmovemap.h"
0051 #include "cmapcmdmoveplayer.h"
0052 #include "cmapcmdleveldelete.h"
0053 #include "cmapcmdlevelcreate.h"
0054 #include "cmapcmdtogglepathtwoway.h"
0055 #include "cmapfilefilterbase.h"
0056 
0057 #include "kmuddy_mapper.h"
0058 
0059 #include "filefilters/cmapfilefilterxml.h"
0060 
0061 #include "dialogs/dlgmaproomproperties.h"
0062 #include "dialogs/dlgmappathproperties.h"
0063 #include "dialogs/dlgmaptextproperties.h"
0064 #include "dialogs/dlgspeedwalkprogress.h"
0065 #include "dialogs/dlgmapspeedwalk.h"
0066 #include "dialogs/dlgmapcolor.h"
0067 #include "dialogs/dlgmapdirections.h"
0068 #include "dialogs/dlgmapmovement.h"
0069 
0070 #include "cactionmanager.h"
0071 #include "cdialoglist.h"
0072 #include "cglobalsettings.h"
0073 #include "cstatus.h"
0074 
0075 CMapManager::CMapManager (QWidget *parent, KMuddyMapper *mapper, int sessId) :
0076   cActionBase ("map-manager", 0),
0077   m_sessId (sessId),
0078   mapperPlugin (mapper)
0079 {
0080   kDebug() << "constructor begins";
0081 
0082   // register action handlers
0083   addEventHandler ("dialog-create", 50, PT_STRING);
0084   addEventHandler ("dialog-save", 50, PT_STRING);
0085 
0086   mapData = new CMapData();
0087 
0088   // Setup vars
0089   loginRoom = nullptr;
0090   currentRoom = nullptr;
0091   elementEdit = nullptr;
0092 
0093   /** Create undo/redo history */
0094   commandHistory = new QUndoStack();
0095   //FIXME_jp: Needs to be configurable
0096   commandHistory->setUndoLimit(30);
0097   commandHistory->clear();
0098   historyGroup = nullptr;
0099   m_commandsActive = true;
0100 
0101   initFileFilters();
0102 
0103   activeView = nullptr;
0104 
0105   setDefaultOptions();
0106 
0107   speedwalkActive = false;
0108 
0109   speedwalkProgressDlg = new DlgSpeedwalkProgress();
0110   speedwalkProgressDlg->hide();
0111   connect(speedwalkProgressDlg,SIGNAL(abortSpeedwalk()),this,SLOT(slotAbortSpeedwalk()));
0112 
0113   m_zoneCount = 0;
0114   m_levelCount = 0;
0115   m_zoneManager = nullptr;
0116 
0117   setUndoActive (false);
0118   createNewMap();  // because some things break if a map doesn't exist
0119   activeView = new CMapView(this, parent);
0120 
0121   m_zoneManager = new CMapZoneManager(sessId, this);
0122   if (!m_zoneManager->zonesModel()->rowCount())
0123     m_zoneManager->createZone (i18n ("Map #1"));
0124   m_zoneManager->loadZone(0);
0125 
0126   initPlugins();
0127   activeView->initGUI();
0128 
0129   readOptions();
0130 
0131   openMapView ();
0132   setUndoActive (true);
0133 
0134   kDebug() << "constructor ends";
0135 }
0136 
0137 CMapManager::~CMapManager()
0138 {
0139   kDebug() << "CMapManager::~CMapManager() start";
0140   removeEventHandler ("dialog-create");
0141   removeEventHandler ("dialog-save");
0142 
0143   if (mapData)
0144     delete mapData;
0145   mapData = nullptr;
0146   delete m_zoneManager;
0147   delete activeView;
0148 
0149   if (commandHistory)
0150     delete commandHistory;
0151 
0152   qDeleteAll(m_fileFilter);
0153   m_fileFilter.clear();
0154 
0155   kDebug() << "CMapManager::~CMapManager() end";
0156 }
0157 
0158 void CMapManager::eventStringHandler (QString event, int, QString &par1, const QString &)
0159 {
0160   if (event == "dialog-create") {
0161     if (par1 == "profile-prefs")
0162       createProfileConfigPanes ();
0163     else if (par1 == "app-prefs")
0164       createGlobalConfigPanes ();
0165   }
0166   if (event == "dialog-save") {
0167     if (par1 == "profile-prefs") {
0168     } else if (par1 == "app-prefs") {
0169       // TODO: the first two should be profile prefs
0170       mapDirection->slotOkPressed();
0171       mapMovement->slotOkPressed();
0172 
0173       mapColor->slotOkPressed();
0174       mapSpeedwalk->slotOkPressed();
0175       saveGlobalConfig ();
0176     }
0177   }
0178 }
0179 
0180 void CMapManager::createProfileConfigPanes ()
0181 {
0182   /*KPageDialog *dlg = */(KPageDialog *) cDialogList::self()->getDialog ("profile-prefs");
0183 
0184   for (CMapPluginBase *plugin : pluginList)
0185     plugin->createProfileConfigPanes();
0186 }
0187 
0188 void CMapManager::createGlobalConfigPanes ()
0189 {
0190   KPageDialog *dlg = (KPageDialog *) cDialogList::self()->getDialog ("app-prefs");
0191 
0192   KPageWidgetItem *item;
0193   QFrame *frmdir = new QFrame (dlg);
0194   item = dlg->addPage (frmdir, i18n ("Mapper: Directions"));
0195   item->setIcon (QIcon::fromTheme ("gear"));
0196   QFrame *frmmovement = new QFrame (dlg);
0197   item = dlg->addPage (frmmovement, i18n ("Mapper: Movement"));
0198   item->setIcon (QIcon::fromTheme ("run"));
0199   QFrame *frmcolor = new QFrame (dlg);
0200   item = dlg->addPage (frmcolor, i18n ("Mapper: Colors"));
0201   item->setIcon (QIcon::fromTheme ("colorize"));
0202   QFrame *frmspeedwalk = new QFrame (dlg);
0203   item = dlg->addPage (frmspeedwalk, i18n ("Mapper: Speedwalk"));
0204   item->setIcon (QIcon::fromTheme ("launch"));
0205 
0206   QVBoxLayout *dirlayout = new QVBoxLayout (frmdir);
0207   QVBoxLayout *movementlayout = new QVBoxLayout (frmmovement);
0208   QVBoxLayout *colorlayout = new QVBoxLayout (frmcolor);
0209   QVBoxLayout *speedwalklayout = new QVBoxLayout (frmspeedwalk);
0210   mapDirection = new DlgMapDirections (this, frmdir);
0211   mapMovement = new DlgMapMovement (this, frmmovement);
0212   mapColor = new DlgMapColor(this, frmcolor);
0213   mapSpeedwalk = new DlgMapSpeedwalk(this, frmspeedwalk);
0214   dirlayout->addWidget (mapDirection);
0215   movementlayout->addWidget (mapMovement);
0216   colorlayout->addWidget (mapColor);
0217   speedwalklayout->addWidget (mapSpeedwalk);
0218 
0219   for (CMapPluginBase *plugin : pluginList)
0220     plugin->createGlobalConfigPanes();
0221 }
0222 
0223 QList<CMapPropertiesPaneBase *> CMapManager::createPropertyPanes(elementTyp type,CMapElement *element,QWidget *parent)
0224 {
0225   QList<CMapPropertiesPaneBase *> res;
0226   for (CMapPluginBase *plugin : pluginList)
0227     res.append(plugin->createPropertyPanes(type, element, parent));
0228   return res;
0229 }
0230 
0231 
0232 /** This will setup the import/export file filters */
0233 void CMapManager::initFileFilters()
0234 {
0235   m_fileFilter.append(new CMapFileFilterXML(this));
0236 }
0237 
0238 #include "plugins/standard/cmappluginstandard.h"
0239 
0240 /** Used to create the plugins */
0241 void CMapManager::initPlugins()
0242 {
0243   int pluginCount = 0;
0244   toolList.clear();
0245   pluginList.clear();
0246   kDebug() << "Loading Static Plugins...\n";
0247   // These used to be plug-ins, but now I'm linking them in statically, and just pretend that they are plug-ins.
0248   // This is because linking to the mapper part is causing issues.
0249   CMapPluginBase *plugin;
0250   plugin = new CMapPluginStandard (activeView);
0251   pluginList.append (plugin);
0252 
0253   for (CMapPluginBase *plugin : pluginList)
0254   {
0255     kDebug() << "Tools in plugin : " << plugin->getToolList()->count();
0256     foreach (CMapToolBase *tool, *plugin->getToolList())
0257     {
0258       toolList.append(tool);
0259     }
0260 
0261 //      getActiveView()->insertChildClient(plugin);
0262     
0263     pluginCount++;
0264   }
0265 
0266   kDebug() << "Finished loading " << pluginCount << " plugins\n";
0267   kDebug() << "Finished loading " << toolList.count() << " tools\n";
0268   
0269   if (!toolList.isEmpty())
0270   {
0271     currentTool = toolList.first();
0272     currentTool->setChecked(true);
0273   }
0274   else
0275   {
0276     kWarning() << "No tools loaded!\n";
0277     currentTool = nullptr;
0278   }
0279 
0280     if (pluginCount==0)
0281     {
0282     kWarning() << "No plugins loaded!\n";
0283     }
0284 
0285      kDebug() << "XML File : " << activeView->xmlFile(); 
0286 }
0287 
0288 /** Used to get a list of the plugins */
0289 QLinkedList<CMapPluginBase *> CMapManager::getPluginList()
0290 {
0291   return pluginList;
0292 }
0293 
0294 /** Used to get a pointer to the map data */
0295 CMapData *CMapManager::getMapData() const
0296 {
0297   return mapData;
0298 }
0299 
0300 CMapZone *CMapManager::getZone(bool noCreate)
0301 {
0302   CMapZone *zone = mapData->rootZone;
0303   if ((!zone) && (!noCreate))
0304     zone = new CMapZone(this);
0305 
0306   return zone;
0307 }
0308 
0309 /** Used to create a new view of the map */
0310 void CMapManager::openMapView()
0311 {
0312   if (loginRoom)
0313     activeView->showPosition(QPoint(loginRoom->getX(),loginRoom->getY()),loginRoom->getLevel());
0314   else
0315   {
0316     CMapRoom *firstRoom = findFirstRoom(nullptr);
0317     if (firstRoom)
0318       displayLevel(firstRoom->getLevel(), true);
0319   }
0320 }
0321 
0322 void CMapManager::displayLevel(CMapLevel *level, bool centerView)
0323 {
0324   CMapView *mapView = getActiveView();
0325   mapView->showPosition(level, centerView);
0326 }
0327 
0328 /** This method is used to covert cords so that they snap to the grid */
0329 QPoint CMapManager::cordsSnapGrid(QPoint oldPos)
0330 {
0331   QPoint newPos;
0332 
0333   int oldx = (int)(oldPos.x() / mapData->gridSize.width());
0334   int oldy =  (int)(oldPos.y() / mapData->gridSize.height());
0335   newPos.setX( oldx * mapData->gridSize.width());
0336   newPos.setY( oldy * mapData->gridSize.height());
0337 
0338   return newPos;
0339 }
0340 
0341 /**
0342  * Used to create a new view of the a given level and
0343  * center the view on the given position.
0344  */
0345 void CMapManager::openNewMapView(QPoint pos,CMapLevel *level)
0346 {
0347   CMapView *mapView = getActiveView();
0348   mapView->showPosition(pos,level);
0349 }
0350 
0351 /** Used to set properties of the view widget */
0352 void CMapManager::setPropertiesAllViews(QCursor *cursor,bool mouseTracking)
0353 {  
0354   activeView->setCursor(*cursor);
0355   activeView->setMouseTracking(mouseTracking);
0356 }
0357 
0358 /** Used to unselect all the elements in a level */
0359 void CMapManager::unselectElements(CMapLevel *level)
0360 {
0361   QList<CMapElement *> lst = level->getAllElements();
0362   foreach (CMapElement *element, lst)
0363   {
0364     element->setSelected(false);
0365     element->setEditMode(false);
0366   }  
0367 }
0368 
0369 /** Used to convert a text direction to a direction type */
0370 QString CMapManager::directionToText(directionTyp dir, QString specialCmd, bool shortName)
0371 {
0372   if ((uint)dir < NUM_DIRECTIONS)
0373   {
0374     if (shortName && ((uint)dir < NUM_DIRECTIONS / 2)) dir = (directionTyp) ((int)dir + NUM_DIRECTIONS / 2);
0375     return mapData->directions[dir];
0376   }
0377   else
0378   {
0379     return specialCmd;
0380   }
0381 }
0382 
0383 /** Used to convert a direction type to a text direction */
0384 directionTyp CMapManager::textToDirection(QString text)
0385 {
0386   directionTyp dir = SPECIAL;  
0387 
0388   for (uint i = 0; i < NUM_DIRECTIONS; ++i)
0389   {
0390     if (text == mapData->directions[i])
0391     {
0392       if (i>9)
0393       {
0394         dir = (directionTyp)(i-10);
0395       }
0396       else
0397       {
0398         dir =  (directionTyp)i;
0399       }
0400       break;
0401     }
0402   }
0403   
0404   return dir;
0405 }
0406 
0407 /** Used to set the login room */
0408 void CMapManager::setLoginRoom(CMapRoom *room)
0409 {
0410   openCommandGroup(i18n("Change Login Room"));
0411   if (loginRoom)
0412   {
0413     CMapCmdElementProperties *cmdRemove = new CMapCmdElementProperties(this,i18n("Remove Login Room Status"),loginRoom);
0414     cmdRemove->getOrgProperties().writeEntry("Login",true);
0415     cmdRemove->getNewProperties().writeEntry("Login",false);
0416 
0417     addCommand(cmdRemove);
0418   }
0419 
0420   CMapCmdElementProperties *cmdSet = new CMapCmdElementProperties(this,i18n("Set Login Room Status"),room);
0421 
0422   cmdSet->getOrgProperties().writeEntry("Login",false);
0423   cmdSet->getNewProperties().writeEntry("Login",true);
0424 
0425   addCommand(cmdSet);
0426 
0427   closeCommandGroup();
0428 }
0429 
0430 /** Uesd to return the login room */
0431 CMapRoom *CMapManager::getLoginRoom()
0432 {
0433   return loginRoom;
0434 }
0435 
0436 /** Should only be called by CMapRoom.setCurrentRoom() */
0437 void CMapManager::setCurrentRoomWithoutUndo(CMapRoom *room)
0438 {
0439   currentRoom = room;
0440 }
0441 
0442 /** Should only be called by CMapRoom.setLoginRoom() */
0443 void CMapManager::setLoginRoomWithoutUndo(CMapRoom *room)
0444 {
0445   loginRoom = room;
0446 }
0447 
0448 
0449 /** Used to set the current room */
0450 void CMapManager::setCurrentRoom(CMapRoom *room)
0451 {
0452   openCommandGroup(i18n("Change Current Room"));
0453 
0454   CMapCmdElementProperties *cmdRemove = new CMapCmdElementProperties(this,i18n("Remove Current Room Status"),currentRoom);
0455   cmdRemove->getOrgProperties().writeEntry("Current",true);
0456   cmdRemove->getNewProperties().writeEntry("Current",false);
0457   addCommand(cmdRemove);
0458 
0459   CMapCmdElementProperties *cmdSet = new CMapCmdElementProperties(this,i18n("Set Current Room Status"),room);
0460   cmdSet->getOrgProperties().writeEntry("Current",false);
0461   cmdSet->getNewProperties().writeEntry("Current",true);
0462   addCommand(cmdSet);
0463 
0464   closeCommandGroup();
0465 }
0466 
0467 /** Uesd to return the current room */
0468 CMapRoom *CMapManager::getCurrentRoom()
0469 {
0470   return currentRoom;
0471 }
0472 
0473 /** This method is used to find a element from a list of properties
0474   * @param properties The list of proerties
0475   * @return The element if it's found otherwise NULL */
0476 CMapElement *CMapManager::findElement(KConfigGroup properties)
0477 {
0478   elementTyp type = (elementTyp)properties.readEntry("Type",(uint)OTHER);
0479 
0480   if (type == OTHER) return nullptr;
0481 
0482   if (type==PATH)
0483   {
0484     CMapLevel *srcLevel = findLevel(properties.readEntry("SrcLevel",-1));
0485     CMapRoom *srcRoom = srcLevel->findRoom(properties.readEntry("SrcRoom",-1));
0486     if (!srcRoom) return nullptr;
0487     directionTyp srcDir = (directionTyp)properties.readEntry("SrcDir",0);
0488 
0489     QString specialCommand = properties.readEntry("SpecialCmdSrc","");
0490     return srcRoom->getPathDirection(srcDir,specialCommand);
0491   }
0492 
0493   CMapLevel *level = findLevel(properties.readEntry("Level",-5));
0494   if (!level) return nullptr;
0495 
0496   if (type == ROOM)
0497   {
0498     CMapRoom *room = level->findRoom(properties.readEntry("RoomID",-5));
0499     return room;
0500   }
0501 
0502   int x = properties.readEntry("X",-5);
0503   int y = properties.readEntry("Y",-5);
0504 
0505   foreach (CMapText *text, *level->getTextList())
0506     if ((text->getX()==x) && (text->getY()==y))
0507       return text;
0508 
0509   return nullptr;
0510 }
0511 
0512 /** Used to erase the map. This will erase all elements and can't be undone */
0513 void CMapManager::eraseMap(void)
0514 {
0515   if (!mapData->rootZone) return;
0516 
0517   eraseZone(mapData->rootZone);
0518   delete mapData->rootZone;
0519   mapData->rootZone = nullptr;
0520 
0521   m_zoneCount = 0;
0522   m_levelCount = 0;
0523 
0524   if (activeView) activeView->setLevel(nullptr);
0525 
0526   for (CMapPluginBase *plugin : pluginList)
0527     plugin->mapErased();
0528 
0529   loginRoom = nullptr;
0530   currentRoom = nullptr;
0531   elementEdit = nullptr;
0532 }
0533 
0534 void CMapManager::eraseZone(CMapZone *zone)
0535 {
0536   if (zone == nullptr)
0537     return;
0538 
0539   QList<CMapLevel *> levels;
0540   for (unsigned int idx = 0; idx < zone->levelCount(); ++idx)
0541     levels.append(zone->getLevel(idx));
0542   foreach (CMapLevel *level, levels)
0543   {
0544     // TODO: this seems to not delete things correctly
0545     foreach (CMapRoom *room, *level->getRoomList())
0546     {        
0547       room->getPathList()->clear();
0548       room->getConnectingPathList()->clear();
0549     }
0550     level->getRoomList()->clear();
0551     level->getTextList()->clear();
0552 
0553     delete level;
0554   }
0555 }
0556 
0557 /** Create new bottom or top level depending on the given direction */
0558 CMapLevel *CMapManager::createLevel(directionTyp dir)
0559 {
0560   CMapLevel *result = nullptr;
0561 
0562   CMapCmdLevelCreate *cmd = nullptr;
0563 
0564   int pos = (dir == UP) ? getZone()->levelCount() : 0;
0565   if (getUndoActive())
0566   {
0567     cmd = new CMapCmdLevelCreate(this,i18n("Create Level"),pos);
0568     addCommand(cmd);
0569     
0570     result = cmd->getLevel();
0571   }
0572   else
0573   {
0574     result = new CMapLevel(this, pos);
0575   }
0576   
0577   return result;
0578 }
0579 
0580 /** This is used to find a level with a given id
0581   * @param id The id of the level to find
0582   * @return Null if no level is found otherwise a pointer to the level */
0583 CMapLevel *CMapManager::findLevel(unsigned int id)
0584 {
0585   CMapZone *zone = getZone();
0586   for (unsigned int idx = 0; idx < zone->levelCount(); ++idx)
0587   {
0588     CMapLevel *level = zone->getLevel(idx);
0589     if (level->getLevelID() == id)
0590       return level;
0591   }
0592 
0593   return nullptr;
0594 }
0595 
0596 /** Create new map */
0597 void CMapManager::createNewMap()
0598 {
0599   // Create the root zone
0600   getMapData()->rootZone = nullptr;  
0601 
0602   CMapZone *zone = getZone();
0603 
0604   // Create a empty room in the first level of the new zone
0605   CMapRoom *room = CMapElementUtil::createRoom(this, QPoint(2 * mapData->gridSize.width(),2 * mapData->gridSize.height()),zone->firstLevel());
0606   setCurrentRoomWithoutUndo(room);
0607   setLoginRoomWithoutUndo(room);
0608 
0609   if (!activeView) return;
0610 
0611   if (currentRoom) activeView->showPosition(currentRoom->getLowPos(),zone->firstLevel());
0612 
0613   if (activeView->getCurrentlyViewedLevel()==nullptr)  
0614     activeView->showPosition(loginRoom,true);
0615 
0616   for (CMapPluginBase *plugin : pluginList)
0617     plugin->newMapCreated();
0618 
0619   activeView->changed();
0620 }
0621 
0622 /** Used to create a new room that can be undone/redone
0623    * @param pos The position to create the room
0624    * @param level The level to create the room in
0625    */
0626 void CMapManager::createRoom(QPoint pos,CMapLevel *level)
0627 {
0628   if (getUndoActive())
0629   {
0630     KMemConfig properties;
0631     KConfigGroup props = properties.group("Properties");
0632     props.writeEntry("Type",(int)ROOM);
0633     props.writeEntry("X",pos.x());
0634     props.writeEntry("Y",pos.y());
0635     props.writeEntry("Level",level->getLevelID());
0636     CMapCmdElementCreate *command = new CMapCmdElementCreate(this,i18n("Create Room"));
0637     command->addElement(&properties);
0638     addCommand(command);
0639   }
0640   else
0641   {
0642     CMapElementUtil::createRoom(this, pos, level);
0643   }
0644 }
0645 
0646 /** Used to create a new text label */
0647 void CMapManager::createText(QPoint pos,CMapLevel *level,QString str)
0648 {
0649   if (getUndoActive())
0650   {
0651     KMemConfig properties;
0652     KConfigGroup props = properties.group("Properties");
0653     props.writeEntry("Type",(int)TEXT);
0654     props.writeEntry("X",pos.x());
0655     props.writeEntry("Y",pos.y());
0656 
0657     if (level)
0658     {
0659       props.writeEntry("Level",level->getLevelID());
0660     }
0661     
0662     props.writeEntry("Text",str);
0663 
0664     CMapCmdElementCreate *command = new CMapCmdElementCreate(this,i18n("Create Text"));
0665     command->addElement(&properties);
0666     addCommand(command);
0667   }
0668   else
0669   {
0670     CMapElementUtil::createText(this, pos, level, str);
0671   }
0672 }
0673 
0674 /** Used to create a new text label */
0675 void CMapManager::createText(QPoint pos,CMapLevel *level,QString str,QFont font,QColor col)
0676 {
0677   if (getUndoActive())
0678   {
0679     KMemConfig properties;
0680     KConfigGroup props = properties.group("Properties");
0681     props.writeEntry("Type",(int)TEXT);
0682     props.writeEntry("X",pos.x());
0683     props.writeEntry("Y",pos.y());
0684     if (level)
0685     {
0686       props.writeEntry("Level",level->getLevelID());
0687     }
0688 
0689     props.writeEntry("Text",str);
0690     props.writeEntry("Font",font);
0691     props.writeEntry("Color",col);
0692 
0693     CMapCmdElementCreate *command = new CMapCmdElementCreate(this,i18n("Create Text"));
0694     command->addElement(&properties);
0695     addCommand(command);
0696   }
0697   else
0698   {
0699     CMapElementUtil::createText(this, pos, level, str, font, col);
0700   }
0701 }
0702 
0703 
0704 /** Used to create a new path*/
0705 CMapPath *CMapManager::createPath(QPoint srcPos,CMapLevel *srcLevel,directionTyp srcDir,
0706                                   QPoint destPos,CMapLevel *destLevel,directionTyp destDir)
0707 {
0708   CMapRoom *room=nullptr;
0709   CMapRoom *srcRoom=nullptr;
0710   CMapRoom *destRoom=nullptr;
0711 
0712   if (!srcLevel || !destLevel)
0713     return nullptr;
0714 
0715   foreach (room, *srcLevel->getRoomList())
0716   {
0717     if (room->getLowPos() == srcPos)
0718     {
0719       srcRoom = room;
0720       break;
0721     }
0722   }
0723 
0724   foreach (room, *destLevel->getRoomList())
0725   {
0726     if (room->getLowPos()  == destPos)
0727     {
0728       destRoom = room;
0729        break;
0730     }
0731   }
0732 
0733   return createPath(srcRoom,srcDir,destRoom,destDir);
0734 }
0735 
0736 CMapPath *CMapManager::createPath(CMapRoom *srcRoom,CMapRoom *destRoom)
0737 {
0738   CMapPath *result = nullptr;
0739 
0740   KMemConfig properties;
0741   KConfigGroup props = properties.group("Properties");
0742   // Auto-set the directions if possible
0743   directionTyp srcDir = srcRoom->bestDirectionToRoom(destRoom);
0744   directionTyp destDir = getOpsiteDirection(srcDir);
0745   if (srcDir != SPECIAL) {
0746     // nothing if there is an exit already
0747     if (srcRoom->getPathDirection(srcDir, QString())) srcDir = SPECIAL;
0748     if (destRoom->getPathDirection(destDir, QString())) destDir = SPECIAL;
0749   }
0750   props.writeEntry("SrcDir", (int) srcDir);
0751   props.writeEntry("DestDir", (int) destDir);
0752 
0753   DlgMapPathProperties d(this,props,false);
0754 
0755   if (!d.exec()) return nullptr;
0756 
0757   srcDir = (directionTyp)props.readEntry("SrcDir",0);
0758   destDir = (directionTyp)props.readEntry("DestDir",0);
0759   QString specialCmdSrc = props.readEntry("SpecialCmdSrc");
0760   QString specialCmdDest = props.readEntry("SpecialCmdDest");
0761 
0762   if (srcRoom->getPathDirection(srcDir,specialCmdSrc) || destRoom->getPathDirection(destDir,specialCmdDest))
0763   {
0764     KMessageBox::information (nullptr,i18n("A path already exists at this location"),i18n("KMuddy Mapper"));
0765     return nullptr;
0766   }
0767 
0768   // create
0769   props.writeEntry("Type",(int)PATH);
0770   props.writeEntry("SrcRoom",srcRoom->getRoomID());
0771   props.writeEntry("SrcDir",(int)srcDir);
0772   props.writeEntry("SrcLevel",srcRoom->getLevel()->getLevelID());
0773   props.writeEntry("DestRoom",destRoom->getRoomID());
0774   props.writeEntry("DestDir",(int)destDir);        
0775   props.writeEntry("DestLevel",destRoom->getLevel()->getLevelID());
0776 
0777   CMapCmdElementCreate *command = new CMapCmdElementCreate(this,i18n("Create Path"));
0778   command->addElement(&properties);
0779 
0780   addCommand(command);
0781 
0782   QList<CMapElement *> *elements=command->getElements();
0783 
0784   foreach (CMapElement *el, *elements)
0785     if (el->getElementType()==PATH)
0786       result = (CMapPath *)el;
0787 
0788   return result;
0789 }
0790 
0791 
0792 /** Used to create a new path*/
0793 CMapPath *CMapManager::createPath (CMapRoom *srcRoom,directionTyp srcDir,CMapRoom *destRoom,directionTyp destDir,bool undoable, bool twoWay)
0794 {
0795   // FIXME_jp : Allow this to call lowlevel mapper methods when undo is not active
0796   //            but becarefull of second stage stuff
0797 
0798   CMapPath *result = nullptr;
0799   
0800   KMemConfig properties;
0801   KConfigGroup props = properties.group("Properties");
0802   props.writeEntry("Type",(int)PATH);
0803   props.writeEntry("SrcRoom",srcRoom->getRoomID());
0804   props.writeEntry("SrcLevel",srcRoom->getLevel()->getLevelID());
0805   props.writeEntry("SrcDir",(int)srcDir);
0806   props.writeEntry("DestRoom",destRoom->getRoomID());
0807   props.writeEntry("DestLevel",destRoom->getLevel()->getLevelID());
0808   props.writeEntry("DestDir",(int)destDir);
0809   props.writeEntry("PathTwoWay",twoWay);
0810 
0811   CMapCmdElementCreate *command = new CMapCmdElementCreate(this,i18n("Create Path"));
0812   command->addElement(&properties);
0813   bool active = getUndoActive();
0814   if (!undoable)
0815   {
0816     setUndoActive(false);
0817   }
0818     
0819   addCommand(command);
0820 
0821   if (!undoable)
0822   {
0823     setUndoActive(active);
0824   }
0825 
0826   QList<CMapElement *> *elements=command->getElements();
0827   foreach (CMapElement *el, *elements)
0828     if (el->getElementType()==PATH)
0829       result = (CMapPath *)el;
0830 
0831   return result;
0832 }
0833 
0834 
0835 /** Find the first room in the map, if one can't be found then create one */
0836 CMapRoom *CMapManager::findFirstRoom(CMapRoom *existingRoom)
0837 {
0838   CMapZone *zone = getZone();
0839   for (unsigned int idx = 0; idx < zone->levelCount(); ++idx)
0840   {
0841     CMapLevel *level = zone->getLevel(idx);
0842     foreach (CMapRoom *room, *level->getRoomList())
0843       if (room!=existingRoom)
0844         return room;
0845   }
0846 
0847   // If we get to this point then no room was found so create one
0848   return CMapElementUtil::createRoom(this, QPoint(2 * mapData->gridSize.width(),2 * mapData->gridSize.height()), getZone()->firstLevel());
0849 }
0850 
0851 void CMapManager::deleteLevel(CMapLevel *level)
0852 {
0853   //FIXME_jp: Check to see what happens when all levels are deleted.
0854     //          It may be nessecary to create a new one.
0855 
0856   // Delete the level
0857   CMapCmdLevelDelete *cmd = new CMapCmdLevelDelete(this,i18n("Delete Level"),level);
0858   addCommand(cmd);
0859 }
0860 
0861 
0862 /** Check to see if a string is a valid move command
0863   * @param dirCmd The command that was typed
0864   * @return True, if a valid command otherwise false */
0865 bool CMapManager::validMoveCmd(QString dirCmd)
0866 {
0867   if (dirCmd.isEmpty()) return false;
0868 
0869   // check for directions
0870   for (uint i = 0; i < NUM_DIRECTIONS; ++i)
0871     if (mapData->directions[i] == dirCmd)
0872       return true;
0873   
0874   if (currentRoom)
0875     foreach (CMapPath *path, *currentRoom->getPathList())
0876       if (path->getSpecialExit() && (path->getSpecialCmd()==dirCmd))
0877         return true;
0878 
0879   return false;
0880 }
0881 
0882 /** Used to delete a element from the map, should not be used by deleteElement as
0883   * it does not use groups                                                */
0884 // FIXME_jp : This method can be removed if the deleteElement method is recursive
0885 void CMapManager::deleteElementWithoutGroup(CMapElement *element,bool delOpsite)
0886 {
0887   KMemConfig properties;
0888 
0889   element->saveProperties(properties.group("Properties"));
0890 
0891   CMapCmdElementDelete *command = new CMapCmdElementDelete(this,i18n("Delete Element"),delOpsite);
0892 
0893   command->addElement(&properties);
0894   addCommand(command);
0895 }
0896 
0897 /** Used to delete a element from the map */
0898 void CMapManager::deleteElement(CMapElement *element,bool delOpsite)
0899 {
0900   openCommandGroup(i18n("Delete Element"));
0901 
0902   // If the element is a room, then we also need to delete all its paths
0903   if (element->getElementType()==ROOM)
0904   {
0905     CMapRoom *room = (CMapRoom *)element;
0906     if (room->getLinkedElement())  
0907     {
0908       deleteElementWithoutGroup(room->getLinkedElement(),true);
0909     }
0910 
0911     QList<CMapPath *> wipePaths;
0912     // Delete the paths for the room
0913     foreach (CMapPath *path, *room->getPathList())
0914       if (!wipePaths.contains(path))
0915         wipePaths.push_back(path);
0916     // Delete any paths connecting with this room
0917     foreach (CMapPath *path, *room->getConnectingPathList())
0918       if (!wipePaths.contains(path))
0919         wipePaths.push_back(path);
0920     foreach (CMapPath *path, wipePaths)
0921       deleteElementWithoutGroup(path,false);
0922   }
0923 
0924   if (element->getElementType() == ZONE)
0925   {
0926     // Delete the levels in the zone
0927     CMapZone *zone = (CMapZone *)element;
0928     QList<CMapLevel *> levels;
0929     for (unsigned int idx = 0; idx < zone->levelCount(); ++idx)
0930       levels.append(zone->getLevel(idx));
0931     foreach (CMapLevel *level, levels)
0932       deleteLevel(level);
0933   }
0934 
0935   deleteElementWithoutGroup(element,delOpsite);
0936 
0937   closeCommandGroup();
0938 }
0939 
0940 bool CMapManager::isClean() const
0941 {
0942   return commandHistory->isClean();
0943 }
0944 
0945 /** Used to load a map */
0946 void CMapManager::importMap(const QString& file,CMapFileFilterBase *filter)
0947 {
0948   QFile f(file);
0949 
0950   setUndoActive(false);
0951   commandHistory->clear();
0952   historyGroup = nullptr;
0953 
0954   eraseMap();
0955 
0956   if (!f.exists())
0957     createNewMap();
0958   else {
0959     // Load the map using the correct filter
0960     filter->loadData(file);
0961   }
0962 
0963   if (!getLoginRoom())
0964   {
0965     CMapRoom *firstRoom = findFirstRoom(nullptr);
0966     setLoginRoom(firstRoom);
0967   }
0968 
0969   setCurrentRoomWithoutUndo(loginRoom);
0970 
0971   if (loginRoom && activeView)
0972   {
0973     if (activeView->getCurrentlyViewedLevel()==nullptr)  
0974       activeView->showPosition(loginRoom,true);
0975     setCurrentRoom(loginRoom);
0976   }
0977 
0978   setUndoActive(true);
0979 }
0980 
0981 /** Used to save a map */
0982 void CMapManager::exportMap(const QString& url,CMapFileFilterBase *filter)
0983 {
0984   filter->saveData(url);
0985   commandHistory->setClean();
0986 }
0987 
0988 /** Used to inform to change the state of the navigation tools */
0989 void CMapManager::activeViewChanged(void)
0990 {
0991   if (!activeView) return;
0992   CMapLevel *level = activeView->getCurrentlyViewedLevel();
0993   if (!level) return;
0994 
0995   // nothing here at this time
0996 }
0997 
0998 void CMapManager::levelChanged(CMapLevel *level)
0999 {
1000   if (level==nullptr)
1001     return;
1002 
1003   activeView->changedLevel(level);
1004 }
1005 
1006 /** Used to inform the various parts of the mapper that a element has changed */
1007 void CMapManager::changedElement(CMapElement *element)
1008 {
1009   if (element==nullptr)
1010     return;
1011   if (!activeView) return;
1012 
1013   for (CMapPluginBase *plugin : pluginList)
1014     plugin->elementChanged(element);
1015 
1016   activeView->changedElement(element);
1017 }
1018 
1019 /** Used to inform the various parts of the mapper that a element has added */
1020 void CMapManager::addedElement(CMapElement *element)
1021 {
1022   if (!activeView) return;
1023   if (activeView->getCurrentlyViewedLevel())
1024     activeView->addedElement(element);
1025 }
1026 
1027 
1028 /** Used to alter the path properties */
1029 bool CMapManager::propertiesPath(CMapPath *path)
1030 {
1031   DlgMapPathProperties d(this,path);
1032 
1033   return d.exec();
1034 }
1035 
1036 /** Used to alter the room properties */
1037 bool CMapManager::propertiesRoom(CMapRoom *room)
1038 {
1039   openCommandGroup("Change room properties");
1040   DlgMapRoomProperties d(this,room);
1041 
1042   bool b = d.exec();
1043   
1044   closeCommandGroup();
1045   
1046   return b;
1047 }
1048 
1049 /** Used to alter the text properties */
1050 bool CMapManager::propertiesText(CMapText *text)
1051 {
1052   DlgMapTextProperties d(this,text);
1053 
1054   if (d.exec())
1055   {
1056     text->updateLinkElements();
1057     return true;
1058   }
1059 
1060   return false;
1061 }
1062 
1063 void CMapManager::setDefaultOptions()
1064 {
1065   cGlobalSettings *gs = cGlobalSettings::self();
1066   // directions
1067   gs->setDefaultString ("mapper-direction-north", "north");
1068   gs->setDefaultString ("mapper-direction-northeast", "northeast");
1069   gs->setDefaultString ("mapper-direction-east", "east");
1070   gs->setDefaultString ("mapper-direction-southeast", "southeast");
1071   gs->setDefaultString ("mapper-direction-south", "south");
1072   gs->setDefaultString ("mapper-direction-southwest", "southwest");
1073   gs->setDefaultString ("mapper-direction-west", "west");
1074   gs->setDefaultString ("mapper-direction-northwest", "northwest");
1075   gs->setDefaultString ("mapper-direction-up", "up");
1076   gs->setDefaultString ("mapper-direction-down", "down");
1077   gs->setDefaultString ("mapper-direction-n", "n");
1078   gs->setDefaultString ("mapper-direction-ne", "ne");
1079   gs->setDefaultString ("mapper-direction-e", "e");
1080   gs->setDefaultString ("mapper-direction-se", "se");
1081   gs->setDefaultString ("mapper-direction-s", "s");
1082   gs->setDefaultString ("mapper-direction-sw", "sw");
1083   gs->setDefaultString ("mapper-direction-w", "w");
1084   gs->setDefaultString ("mapper-direction-nw", "nw");
1085   gs->setDefaultString ("mapper-direction-u", "u");
1086   gs->setDefaultString ("mapper-direction-d", "d");
1087 
1088   // move check
1089   gs->setDefaultBool ("mapper-movement-validcheck", false);
1090 
1091   gs->setDefaultColor ("mapper-color-Background", QColor(12*16,12*16,12*16));
1092   gs->setDefaultColor ("mapper-color-Grid",QColor(160,160,160));
1093   gs->setDefaultColor ("mapper-color-LowerRoom", Qt::darkGray);
1094   gs->setDefaultColor ("mapper-color-LowerZone", Qt::darkGray);
1095   gs->setDefaultColor ("mapper-color-LowerText", Qt::darkGray);
1096   gs->setDefaultColor ("mapper-color-DefaultRoom", QColor(32,255,0));
1097   gs->setDefaultColor ("mapper-color-DefaultZone", QColor(32,255,0));
1098   gs->setDefaultColor ("mapper-color-HigherRoom", Qt::white);
1099   gs->setDefaultColor ("mapper-color-HigherZone", Qt::white);
1100   gs->setDefaultColor ("mapper-color-HigherText", Qt::white);
1101   gs->setDefaultColor ("mapper-color-LowerPath", Qt::darkGray);
1102   gs->setDefaultColor ("mapper-color-DefaultPath", Qt::black);
1103   gs->setDefaultColor ("mapper-color-HigherPath", Qt::white);
1104   gs->setDefaultColor ("mapper-color-DefaultText", Qt::black);
1105   gs->setDefaultColor ("mapper-color-Selected", Qt::blue);
1106   gs->setDefaultColor ("mapper-color-Special", Qt::yellow);
1107   gs->setDefaultColor ("mapper-color-Login", Qt::blue);
1108   gs->setDefaultColor ("mapper-color-Edit", Qt::red);
1109   gs->setDefaultColor ("mapper-color-Current", Qt::red);
1110 
1111   // read speedwalk options
1112   gs->setDefaultBool ("mapper-speedwalk-abort-active", true);
1113   gs->setDefaultInt ("mapper-speedwalk-abort-limit", 100);
1114   gs->setDefaultInt ("mapper-speedwalk-delay", 0);
1115 
1116 
1117 }
1118 
1119 /** Used to read the map options */
1120 void CMapManager::readOptions()
1121 {  
1122   cGlobalSettings *gs = cGlobalSettings::self();
1123 
1124   // Read directions
1125   getMapData()->directions[NORTH] = gs->getString ("mapper-direction-north");
1126   getMapData()->directions[NORTHEAST] = gs->getString ("mapper-direction-northeast");
1127   getMapData()->directions[EAST] = gs->getString ("mapper-direction-east");
1128   getMapData()->directions[SOUTHEAST] = gs->getString ("mapper-direction-southeast");
1129   getMapData()->directions[SOUTH] = gs->getString ("mapper-direction-south");
1130   getMapData()->directions[SOUTHWEST] = gs->getString ("mapper-direction-southwest");
1131   getMapData()->directions[WEST] = gs->getString ("mapper-direction-west");
1132   getMapData()->directions[NORTHWEST] = gs->getString ("mapper-direction-northwest");
1133   getMapData()->directions[UP] = gs->getString ("mapper-direction-up");
1134   getMapData()->directions[DOWN] = gs->getString ("mapper-direction-down");
1135 
1136   int half = NUM_DIRECTIONS/2;
1137   getMapData()->directions[NORTH+half] = gs->getString ("mapper-direction-n");
1138   getMapData()->directions[NORTHEAST+half] = gs->getString ("mapper-direction-ne");
1139   getMapData()->directions[EAST+half] = gs->getString ("mapper-direction-e");
1140   getMapData()->directions[SOUTHEAST+half] = gs->getString ("mapper-direction-se");
1141   getMapData()->directions[SOUTH+half] = gs->getString ("mapper-direction-s");
1142   getMapData()->directions[SOUTHWEST+half] = gs->getString ("mapper-direction-sw");
1143   getMapData()->directions[WEST+half] = gs->getString ("mapper-direction-w");
1144   getMapData()->directions[NORTHWEST+half] = gs->getString ("mapper-direction-nw");
1145   getMapData()->directions[UP+half] = gs->getString ("mapper-direction-u");
1146   getMapData()->directions[DOWN+half] = gs->getString ("mapper-direction-d");
1147 
1148   // Read movecheck config
1149   getMapData()->validRoomCheck = gs->getBool ("mapper-movement-validcheck");
1150   int count = gs->getInt ("mapper-movement-check-count");
1151   getMapData()->failedMoveMsg.clear();
1152   for (int i = 1; i <= count; ++i)
1153     getMapData()->failedMoveMsg << gs->getString ("mapper-movement-check-" + QString::number (i));
1154 
1155   // Read map colors
1156   mapData->backgroundColor=gs->getColor ("mapper-color-Background");
1157   mapData->gridColor=gs->getColor ("mapper-color-Grid");
1158   mapData->lowerRoomColor=gs->getColor ("mapper-color-LowerRoom");
1159   mapData->lowerZoneColor=gs->getColor ("mapper-color-LowerZone");
1160   mapData->lowerTextColor=gs->getColor ("mapper-color-LowerText");
1161   mapData->defaultRoomColor=gs->getColor ("mapper-color-DefaultRoom");
1162   mapData->defaultZoneColor=gs->getColor ("mapper-color-DefaultZone");
1163   mapData->higherRoomColor=gs->getColor ("mapper-color-HigherRoom");
1164   mapData->higherZoneColor=gs->getColor ("mapper-color-HigherZone");
1165   mapData->higherTextColor=gs->getColor ("mapper-color-HigherText");
1166   mapData->lowerPathColor=gs->getColor ("mapper-color-LowerPath");
1167   mapData->defaultPathColor=gs->getColor ("mapper-color-DefaultPath");
1168   mapData->higherPathColor=gs->getColor ("mapper-color-HigherPath");
1169   mapData->defaultTextColor=gs->getColor ("mapper-color-DefaultText");
1170   mapData->selectedColor=gs->getColor ("mapper-color-Selected");
1171   mapData->specialColor = gs->getColor ("mapper-color-Special");
1172   mapData->loginColor=gs->getColor ("mapper-color-Login");
1173   mapData->editColor=gs->getColor ("mapper-color-Edit");
1174   mapData->currentColor=gs->getColor ("mapper-color-Current");
1175 
1176   // read speedwalk options
1177   mapData->speedwalkAbortActive = gs->getBool ("mapper-speedwalk-abort-active");
1178   mapData->speedwalkAbortLimit = gs->getInt ("mapper-speedwalk-abort-limit");
1179   mapData->speedwalkDelay = gs->getInt ("mapper-speedwalk-delay");
1180 
1181   activeView->readOptions();
1182 
1183   for (CMapPluginBase *plugin : pluginList)
1184     plugin->loadConfigOptions();
1185 }
1186 
1187 /** Used to write the map options */
1188 void CMapManager::saveGlobalConfig()
1189 {
1190   cGlobalSettings *gs = cGlobalSettings::self();
1191 
1192   // directions
1193   gs->setString ("mapper-direction-north", getMapData()->directions[NORTH]);
1194   gs->setString ("mapper-direction-northeast", getMapData()->directions[NORTHEAST]);
1195   gs->setString ("mapper-direction-east", getMapData()->directions[EAST]);
1196   gs->setString ("mapper-direction-southeast", getMapData()->directions[SOUTHEAST]);
1197   gs->setString ("mapper-direction-south", getMapData()->directions[SOUTH]);
1198   gs->setString ("mapper-direction-southeast", getMapData()->directions[SOUTHWEST]);
1199   gs->setString ("mapper-direction-west", getMapData()->directions[WEST]);
1200   gs->setString ("mapper-direction-northwest", getMapData()->directions[NORTHWEST]);
1201   gs->setString ("mapper-direction-up", getMapData()->directions[UP]);
1202   gs->setString ("mapper-direction-down", getMapData()->directions[DOWN]);
1203 
1204   int half = NUM_DIRECTIONS/2;
1205   gs->setString ("mapper-direction-n", getMapData()->directions[NORTH+half]);
1206   gs->setString ("mapper-direction-ne", getMapData()->directions[NORTHEAST+half]);
1207   gs->setString ("mapper-direction-e", getMapData()->directions[EAST+half]);
1208   gs->setString ("mapper-direction-se", getMapData()->directions[SOUTHEAST+half]);
1209   gs->setString ("mapper-direction-s", getMapData()->directions[SOUTH+half]);
1210   gs->setString ("mapper-direction-sw", getMapData()->directions[SOUTHWEST+half]);
1211   gs->setString ("mapper-direction-w", getMapData()->directions[WEST+half]);
1212   gs->setString ("mapper-direction-nw", getMapData()->directions[NORTHWEST+half]);
1213   gs->setString ("mapper-direction-u", getMapData()->directions[UP+half]);
1214   gs->setString ("mapper-direction-d", getMapData()->directions[DOWN+half]);
1215 
1216   // movement
1217   gs->setBool ("mapper-movement-validcheck", getMapData()->validRoomCheck);
1218   gs->setInt ("mapper-movement-check-count", getMapData()->failedMoveMsg.size());
1219   int idx = 0;
1220   QStringList::iterator it;
1221   for (it = getMapData()->failedMoveMsg.begin(); it != getMapData()->failedMoveMsg.end(); ++it)
1222     gs->setString ("mapper-movement-check-" + QString::number (++idx), *it);
1223 
1224   gs->setColor ("mapper-color-Background", mapData->backgroundColor);
1225   gs->setColor ("mapper-color-Grid", mapData->gridColor);
1226   gs->setColor ("mapper-color-LowerRoom", mapData->lowerRoomColor);
1227   gs->setColor ("mapper-color-LowerZone", mapData->lowerZoneColor);
1228   gs->setColor ("mapper-color-LowerText", mapData->lowerTextColor);
1229   gs->setColor ("mapper-color-HigherZone", mapData->higherZoneColor);
1230   gs->setColor ("mapper-color-DefaultRoom", mapData->defaultRoomColor);
1231   gs->setColor ("mapper-color-DefaultZone", mapData->defaultZoneColor);
1232   gs->setColor ("mapper-color-DefaultText", mapData->defaultTextColor);
1233   gs->setColor ("mapper-color-HigherRoom", mapData->higherRoomColor);
1234   gs->setColor ("mapper-color-HigherText", mapData->higherTextColor);
1235   gs->setColor ("mapper-color-LowerPath", mapData->lowerPathColor);
1236   gs->setColor ("mapper-color-DefaultPath",mapData->defaultPathColor);
1237   gs->setColor ("mapper-color-HigherPath", mapData->higherPathColor);
1238   gs->setColor ("mapper-color-Selected", mapData->selectedColor);
1239   gs->setColor ("mapper-color-Special", mapData->specialColor);
1240   gs->setColor ("mapper-color-Login", mapData->loginColor);
1241   gs->setColor ("mapper-color-Edit", mapData->editColor);
1242   gs->setColor ("mapper-color-Current", mapData->currentColor);
1243 
1244   for (CMapPluginBase *plugin : pluginList)
1245     plugin->saveConfigOptions();
1246 
1247   gs->setBool ("mapper-speedwalk-abort-active", mapData->speedwalkAbortActive);
1248   gs->setInt ("mapper-speedwalk-abort-limit", mapData->speedwalkAbortLimit);
1249   gs->setInt ("mapper-speedwalk-delay", mapData->speedwalkDelay);
1250 
1251   redrawAllViews();
1252 }
1253 
1254 void CMapManager::getCounts(int *levels,int *rooms,int *paths,int *labels)
1255 {
1256   *rooms = 0;
1257   *labels = 0;
1258   *paths = 0;
1259   CMapZone *zone = getZone();
1260   *levels = zone->levelCount();
1261 
1262   for (unsigned int idx = 0; idx < zone->levelCount(); ++idx)
1263   {
1264     CMapLevel *level = zone->getLevel(idx);
1265 
1266     foreach (CMapRoom *room, *level->getRoomList())
1267       *paths += room->getPathList()->count();
1268 
1269     *rooms += level->getRoomList()->count();
1270     *labels += level->getTextList()->count();
1271   }
1272 }
1273 
1274 directionTyp CMapManager::getOpsiteDirection(directionTyp dir)
1275 {
1276   directionTyp result = SOUTH;
1277   switch (dir)
1278   {
1279     case NORTH     : result = SOUTH; break;
1280     case SOUTH     : result = NORTH; break;
1281     case EAST      : result = WEST; break;
1282     case WEST      : result = EAST; break;
1283     case NORTHWEST : result = SOUTHEAST; break;
1284     case NORTHEAST : result = SOUTHWEST; break;
1285     case SOUTHWEST : result = NORTHEAST; break;
1286     case SOUTHEAST : result = NORTHWEST; break;
1287     case UP        : result = DOWN; break;
1288     case DOWN      : result = UP; break;
1289     case SPECIAL   : result = SPECIAL; break;
1290   }
1291 
1292   return result;
1293 }
1294 
1295 /** Used to set the current tool */
1296 void CMapManager::setCurrentTool(CMapToolBase *tool)
1297 {
1298   if (currentTool)
1299     currentTool->toolUnselected();
1300 
1301   currentTool=tool;
1302 
1303   if (currentTool)
1304     currentTool->toolSelected();
1305 
1306   activeView->changed();
1307 }
1308 
1309 /** Usd to get the current tool */
1310 CMapToolBase *CMapManager::getCurrentTool(void)
1311 {
1312   return currentTool;
1313 }
1314 
1315 /** This method puts a element into edit state */
1316 void CMapManager::setEditElement(CMapElement *element)
1317 {
1318   if (elementEdit)
1319   {
1320     elementEdit->setEditMode(false);
1321     changedElement(elementEdit);
1322   }
1323 
1324   element->setEditMode(true);
1325   elementEdit = element;
1326   changedElement(elementEdit);
1327 }
1328 
1329 /** This is used to remove edit state from element being edited */
1330 void CMapManager::unsetEditElement(void)
1331 {
1332   if (elementEdit)
1333   {
1334     elementEdit->setEditMode(false);
1335     changedElement(elementEdit);
1336   }
1337 }
1338 
1339 /** This gets the element that is being edited */
1340 CMapElement *CMapManager::getEditElement(void)
1341 {
1342   return elementEdit;
1343 }
1344 
1345 /** This cancels any editing */
1346 void CMapManager::stopEditing(void)
1347 {
1348   if (elementEdit)
1349   {
1350     elementEdit->setEditMode(false);
1351   }
1352 
1353   elementEdit = nullptr;
1354 }
1355 
1356 int CMapManager::getUndoActive(void)
1357 {
1358   return m_commandsActive;
1359 }
1360 
1361 /** This is used to tell the mapper if commands should be added to the history list */
1362 void CMapManager::setUndoActive(bool active)
1363 {
1364   m_commandsActive = active;
1365 }
1366 
1367 /** Used to add a command to the command history */
1368 void CMapManager::addCommand(CMapCommand *command)
1369 {
1370   if (getUndoActive())
1371   {
1372     if (historyGroup)
1373     {
1374       // If there is a history group, it will -not- execute anything. That will happen once the group gets closed.
1375       historyGroup->addCommand(command);
1376     }
1377     else
1378     {
1379       commandHistory->push(command);
1380     }
1381   }
1382   else
1383   {
1384     command->redo();
1385   }
1386 }
1387 
1388 void CMapManager::openCommandGroup(QString name)
1389 {
1390   CMapCmdGroup *group = new CMapCmdGroup(this,name);
1391   group->setPreviousGroup(historyGroup);
1392   historyGroup = group;
1393 }
1394 
1395 void CMapManager::closeCommandGroup()
1396 {
1397   CMapCmdGroup *currentGroup = historyGroup;
1398   CMapCmdGroup *oldGroup =historyGroup->getPreviousGroup();
1399   historyGroup = oldGroup;
1400   addCommand(currentGroup);
1401 }
1402 
1403 /** move the player relative to the current position of the player
1404   * @param cmd The move command used to move the player */
1405 void CMapManager::movePlayerBy(QString cmd)
1406 {
1407   QString specialCmd = "";
1408   directionTyp dir = textToDirection(cmd);
1409 
1410   if (dir == SPECIAL)
1411     specialCmd = cmd;
1412 
1413   movePlayerBy(dir, getActiveView()->getCreateMode(), specialCmd);
1414 }
1415 
1416 /** move the player relative to the current position of the player
1417   * This command has support for special paths, but can only move
1418   * anlong exsiting special paths. In other words, it is unable to
1419   * create special paths.
1420   */
1421 void CMapManager::movePlayerBy(directionTyp dir,bool create,QString specialCmd)
1422 {
1423   // Make sure that the room we are currently in is visible
1424   if (!currentRoom) return;
1425 
1426   CMapCmdMovePlayer *cmd = new CMapCmdMovePlayer(this, dir, specialCmd, create);
1427   addCommand(cmd);
1428 }
1429 
1430 /** Used to walk the player in the mud to a given room */
1431 void CMapManager::walkPlayerTo(CMapRoom *toRoom)
1432 {
1433   QQueue<CMapRoom *> roomsToVisit;
1434   CMapRoom *destRoom;
1435   CMapRoom *srcRoom;
1436   CMapPath *path;
1437   CMapRoom *foundRoom;
1438   signed int time = 0;
1439   bool bFound = false;
1440   CMapPath *foundPath = nullptr;
1441 
1442   int speedWalkAbortCount = 0;
1443 
1444   if ((!currentRoom) || (currentRoom == toRoom)) return;
1445 
1446   if (speedwalkActive)
1447   {
1448     KMessageBox::information (nullptr,i18n("Speedwalking is already in progress"),i18n("KMuddy Mapper"));
1449     return;
1450   }
1451 
1452   speedwalkActive = true;
1453 
1454   pathToWalk.clear();
1455 
1456   // Reset the seach count for all the rooms
1457   for (unsigned int idx = 0; idx < getZone()->levelCount(); ++idx)
1458   {
1459     CMapLevel *level = getZone()->getLevel(idx);
1460     foreach (CMapRoom *room, *level->getRoomList())
1461       room->setMoveTime(-1);
1462   }
1463 
1464   // Init things for the start room
1465   srcRoom = currentRoom;
1466   destRoom = (CMapRoom *)toRoom;
1467   srcRoom->setMoveTime(time++);
1468 
1469   // enqueue starting room
1470   roomsToVisit.enqueue(srcRoom);
1471   CMapRoom* room;
1472 
1473   // this is the Breadth First Search Algorithm
1474   while (!(roomsToVisit.isEmpty() || bFound))
1475   {
1476     foundRoom = roomsToVisit.dequeue();
1477 
1478     // for all neighbours of foundRoom
1479     foreach (path, *foundRoom->getPathList())
1480     {
1481       room = path->getDestRoom();
1482 
1483       if (room == destRoom)
1484       {
1485         bFound = true;
1486         break;
1487       }
1488 
1489       // neighbour has not been visited yet, enqueue it
1490       if (room->getMoveTime() == -1)
1491       {
1492         room->setMoveTime(time++);
1493         roomsToVisit.enqueue(room);
1494       }
1495     }
1496   }
1497 
1498   // Check to see if we were unable to find any paths
1499   if (!bFound)
1500   {
1501     speedwalkActive = false;
1502     KMessageBox::information (nullptr,i18n("The automapper was unable to find a path to requested room"),i18n("KMuddy Mapper"));
1503     return;
1504   }
1505 
1506   speedWalkAbortCount=0;
1507   
1508   // Trace steps that need to be taken backwards from the dest to the src room
1509   while(destRoom != srcRoom)
1510   {
1511     time = destRoom->getConnectingPathList()->first()->getSrcRoom()->getMoveTime();
1512     foundRoom = destRoom->getConnectingPathList()->first()->getSrcRoom();
1513 
1514     // Find the room with the shortest time as this is the room we
1515     // should be moving to.
1516     foreach (path, *destRoom->getConnectingPathList())
1517     {
1518       if (time == -1 || (path->getSrcRoom()->getMoveTime()<=time && path->getSrcRoom()->getMoveTime()!=-1))
1519       {
1520         time = path->getSrcRoom()->getMoveTime();
1521         foundRoom = path->getSrcRoom();
1522         foundPath = path;
1523       }
1524     }
1525 
1526     pathToWalk.append(directionToText(foundPath->getSrcDir(),foundPath->getSpecialCmd()));
1527 
1528     destRoom=foundRoom;
1529     // Check to make sure that tings are not stuck in a loop and abort
1530     // if the move limit is reached
1531 
1532     speedWalkAbortCount++;
1533     if (mapData->speedwalkAbortActive && (speedWalkAbortCount == mapData->speedwalkAbortLimit))
1534     {
1535       speedwalkActive = false;
1536       KMessageBox::information (nullptr,i18n("Speedwalk abort because move limit was reached"),i18n("KMuddy Mapper"));
1537 
1538       return;
1539     }
1540   }
1541 
1542   speedwalkProgressDlg->setTotalSteps(pathToWalk.count());
1543   speedwalkProgressDlg->setProgress(0);
1544 
1545   cActionManager *am = cActionManager::self();
1546   cStatus *status = dynamic_cast<cStatus *>(am->object ("status", am->activeSession()));
1547   if (status)
1548     status->statusBar()->addPermanentWidget(speedwalkProgressDlg,0);
1549   speedwalkProgressDlg->show();
1550   speedwalkProgress = 0;
1551 
1552   // Start walking path
1553   slotWalkPlayerAlongPath();
1554 }
1555 
1556 void CMapManager::slotAbortSpeedwalk(void)
1557 {
1558   pathToWalk.clear();
1559   speedwalkActive = false;
1560   speedwalkProgressDlg->setProgress(speedwalkProgressDlg->getTotalSteps());
1561   speedwalkProgressDlg->hide();
1562   cActionManager *am = cActionManager::self();
1563   cStatus *status = dynamic_cast<cStatus *>(am->object ("status", am->activeSession()));
1564   if (status)
1565     status->statusBar()->removeWidget(speedwalkProgressDlg);
1566 }
1567 
1568 /** Used to recersivly move the play along a speedwalk path */
1569 void CMapManager::slotWalkPlayerAlongPath(void)
1570 {
1571   if (speedwalkActive)
1572   {
1573     QString dir = pathToWalk.takeFirst();
1574 
1575     // TODO: using active session isn't a very good idea; progress bar should be shown on the mapper window, not in KMuddy's status bar; furthermore, the mapper should distinguish sessions and switch maps when session changes or something - until all this gets done, we cannot implement this any better
1576     mapperPlugin->sendCommand (mapperPlugin->activeSession(), dir);
1577     speedwalkProgressDlg->setProgress(++speedwalkProgress);
1578 
1579     // Walk the path
1580     if (!pathToWalk.isEmpty())
1581     {
1582       QTimer::singleShot( mapData->speedwalkDelay * 100, this, SLOT(slotWalkPlayerAlongPath()) );
1583     }
1584     else
1585     {
1586       slotAbortSpeedwalk();
1587     }
1588   }
1589 }
1590 
1591 /** This method is used to convert a direction into a offset */
1592 void CMapManager::directionToCord(directionTyp dir, QSize distance,QPoint *pos)
1593 {
1594   int x = pos->x();
1595   int y = pos->y();
1596 
1597   switch (dir)
1598   {
1599     case NORTH     : x = 0;
1600                      y = -distance.height();
1601                      break;
1602     case EAST      : x = distance.width();
1603                      y = 0;
1604                      break;
1605     case SOUTH     : x = 0;
1606                      y = distance.height();
1607                      break;
1608     case WEST      : x = -distance.width();
1609                      y = 0;
1610                          break;
1611     case NORTHEAST : x = distance.width();
1612                      y = -distance.height();
1613                      break;
1614     case NORTHWEST : x = -distance.width();
1615                      y = -distance.height();
1616                      break;
1617     case SOUTHEAST : x = distance.width();
1618                      y = distance.height();
1619                      break;
1620     case SOUTHWEST : x = -distance.width();
1621                      y = distance.height();
1622                      break;
1623     case UP        : break;
1624     case DOWN      : break;
1625     case SPECIAL   : break;
1626   }
1627 
1628   pos->setX(x);
1629   pos->setY(y);
1630 }
1631 
1632 /** This method is used to move the elements in a zone by the given vector */
1633 void CMapManager::moveMap(QPoint inc,CMapZone *)
1634 {
1635   CMapCmdMoveMap *cmd = new CMapCmdMoveMap(this,inc,i18n("Move Elements in map"));
1636   addCommand(cmd);
1637 }
1638 
1639 /** This method is used to make a path two way */
1640 void CMapManager::makePathTwoWay(CMapPath *path)
1641 {
1642   if (!path->getOpsitePath())
1643   {
1644     CMapCmdTogglePathTwoWay *cmd =  new CMapCmdTogglePathTwoWay(this,i18n("Make Path Two-Way"),path);
1645     addCommand(cmd);
1646   }
1647 }
1648 
1649 /** This method is used to make a path one way */
1650 void CMapManager::makePathOneWay(CMapPath *path)
1651 {
1652   if (path->getOpsitePath())
1653   {
1654     CMapCmdTogglePathTwoWay *cmd =  new CMapCmdTogglePathTwoWay(this,i18n("Make Path One-Way"),path);
1655     addCommand(cmd);
1656   }
1657 }
1658 
1659 /** Get the main window */
1660 CMapView *CMapManager::getActiveView()
1661 {  
1662   return activeView;
1663 }                                                                    
1664 
1665 /** Used to repaint all the views */
1666 void CMapManager::redrawAllViews(void)
1667 {
1668   activeView->changed();
1669 }
1670 
1671 CMapFileFilterBase *CMapManager::nativeFilter(bool isLoad)
1672 {
1673   for (CMapFileFilterBase *filter : m_fileFilter)
1674   {
1675     if (isLoad && (!filter->supportLoad())) continue;
1676     if ((!isLoad) && (!filter->supportSave())) continue;
1677     if (filter->isNative()) return filter;
1678   }
1679   return nullptr;
1680 }
1681 
1682 QString CMapManager::defaultSavePath () const
1683 {
1684   return KStandardDirs::locateLocal ("appdata", "maps/");
1685 }
1686 
1687 /** This is a debug function and not for genreal use */
1688 void CMapManager::changeProperties(CMapElement *element,QString key,QString oldData,QString newData)
1689 {
1690   CMapCmdElementProperties *cmd = new CMapCmdElementProperties(this,i18n("Change Element Property"),element);
1691   cmd->getOrgProperties().writeEntry(key,oldData);
1692   cmd->getNewProperties().writeEntry(key,newData);
1693   addCommand(cmd);
1694 }
1695 
1696 /** This is a debug function and not for genreal use */
1697 void CMapManager::changeProperties(CMapElement *element,QString key,int oldData,int newData)
1698 {
1699   CMapCmdElementProperties *cmd = new CMapCmdElementProperties(this,i18n("Change Element Property"),element);
1700   cmd->getOrgProperties().writeEntry(key,oldData);
1701   cmd->getNewProperties().writeEntry(key,newData);
1702   addCommand(cmd);
1703 }
1704 
1705 /** This is a debug function and not for genreal use */
1706 void CMapManager::generateTestMap()
1707 {
1708   kDebug() << "creating test map";
1709   bool smallMap = false;
1710 
1711   /////////////////////////////////////////////////////////////////////
1712   // Create a new empty map
1713   setUndoActive(false);
1714   commandHistory->clear();
1715   historyGroup = nullptr;
1716   eraseMap();
1717   createNewMap();
1718   setUndoActive(true);
1719 
1720   /////////////////////////////////////////////////////////////////////
1721   // Create a test map
1722   // Test rooms and paths
1723 
1724   openCommandGroup("Create Test Map");
1725 
1726   if (!smallMap)
1727   {
1728     movePlayerBy(SOUTH,true,"");
1729     movePlayerBy(SOUTH,true,"");
1730     movePlayerBy(SOUTH,true,"");
1731     movePlayerBy(WEST,true,"");
1732     movePlayerBy(NORTH,true,"");
1733     movePlayerBy(EAST,true,"");
1734     movePlayerBy(EAST,true,"");
1735     movePlayerBy(SOUTH,true,"");
1736     movePlayerBy(SOUTH,true,"");
1737     movePlayerBy(SOUTH,true,"");
1738     movePlayerBy(EAST,true,"");
1739     movePlayerBy(EAST,true,"");
1740     movePlayerBy(EAST,true,"");
1741     movePlayerBy(EAST,true,"");
1742 
1743     movePlayerBy(UP,true,"");
1744     movePlayerBy(EAST,true,"");
1745     movePlayerBy(EAST,true,"");
1746     movePlayerBy(EAST,true,"");
1747     movePlayerBy(EAST,true,"");
1748     movePlayerBy(SOUTH,true,"");
1749     movePlayerBy(SOUTH,true,"");
1750     movePlayerBy(SOUTH,true,"");
1751     movePlayerBy(SOUTH,true,"");
1752     movePlayerBy(SOUTH,true,"");
1753     movePlayerBy(SOUTH,true,"");
1754     movePlayerBy(EAST,true,"");
1755     movePlayerBy(EAST,true,"");
1756     movePlayerBy(DOWN,true,"");
1757 
1758     movePlayerBy(DOWN,true,"");
1759     movePlayerBy(SOUTH,true,"");
1760     movePlayerBy(SOUTH,true,"");
1761     movePlayerBy(SOUTH,true,"");
1762     movePlayerBy(SOUTH,true,"");
1763     movePlayerBy(SOUTH,true,"");
1764     movePlayerBy(EAST,true,"");
1765     movePlayerBy(EAST,true,"");
1766     movePlayerBy(UP,true,"");
1767 
1768     movePlayerBy(SOUTH,true,"");
1769     movePlayerBy(WEST,true,"");
1770 
1771     // Test text
1772     changeProperties(getZone(),"Label","",i18n("Root Zone"));
1773 
1774   }
1775 
1776   CMapLevel *level = getZone()->firstLevel();
1777   if (level->getNextLevel())
1778     level = level->getNextLevel();
1779 
1780   QFont font = QFont("times");
1781   font.setPointSize(25);
1782   createText(QPoint(160,20),level,"Test Map",font,Qt::black);
1783 
1784 
1785   if (!smallMap)
1786   {
1787     CMapRoom *test1=CMapElementUtil::createRoom(this, QPoint(14*20,14*20),level);
1788     changeProperties(test1,"Label","",i18n("Test room 1"));
1789     changeProperties(test1,"LabelPos",(int)CMapRoom::HIDE,(int)CMapRoom::WEST);
1790     CMapRoom *test2=CMapElementUtil::createRoom(this, QPoint(20*20,20*20),level);
1791     changeProperties(test2,"Label","",i18n("Test room 2"));
1792     changeProperties(test2,"LabelPos",(int)CMapRoom::HIDE,(int)CMapRoom::EAST);
1793     CMapRoom *test3=CMapElementUtil::createRoom(this, QPoint(14*20,20*20),level);
1794     changeProperties(test3,"Label","",i18n("Test room 3"));
1795     changeProperties(test3,"LabelPos",(int)CMapRoom::HIDE,(int)CMapRoom::WEST);
1796     CMapRoom *test4=CMapElementUtil::createRoom(this, QPoint(20*20,14*20),level);
1797     changeProperties(test4,"Label","",i18n("Test room 4"));
1798     changeProperties(test4,"LabelPos",(int)CMapRoom::HIDE,(int)CMapRoom::NORTH);
1799 
1800     createPath(QPoint(14*20,14*20),level,SOUTHEAST,
1801                 QPoint(20*20,20*20),level,NORTHWEST);
1802     createPath(QPoint(20*20,20*20),level,NORTHWEST,
1803          QPoint(14*20,14*20),level,SOUTHEAST);
1804     createPath(QPoint(14*20,20*20),level,NORTHEAST,
1805                            QPoint(20*20,14*20),level,SOUTHWEST);
1806 
1807     createPath(QPoint(20*20,14*20),level,SOUTHWEST,
1808                            QPoint(14*20,20*20),level,NORTHEAST);
1809 
1810     CMapPath *specialPath = createPath(test1,SPECIAL,test4,SPECIAL);
1811     makePathTwoWay(specialPath);
1812 
1813     CMapCmdElementProperties *cmd = new CMapCmdElementProperties(this,i18n("Set Special Exit"),specialPath);
1814     cmd->getOrgProperties().writeEntry("SpecialCmdSrc","");
1815     cmd->getOrgProperties().writeEntry("SpecialCmdDest","");
1816     cmd->getOrgProperties().writeEntry("SpecialExit",false);
1817     cmd->getNewProperties().writeEntry("SpecialCmdSrc","enter");
1818     cmd->getNewProperties().writeEntry("SpecialCmdDest","out");
1819     cmd->getNewProperties().writeEntry("SpecialExit",true);
1820     addCommand(cmd);
1821   }
1822   closeCommandGroup();
1823   kDebug() << "test map created";
1824 }
1825 
1826 #include "moc_cmapmanager.cpp"