File indexing completed on 2023-09-24 04:17:27

0001 /***************************************************************************
0002                                cmapclipboard.cpp
0003                              -------------------
0004     begin                : Wed Jul 3 2002
0005     copyright            : (C) 2002 by Kmud Developer Team
0006     email                : kmud-devel@kmud.de
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include "cmapclipboard.h"
0019 
0020 #include <kactioncollection.h>
0021 #include <kdebug.h>
0022 #include <klocale.h>
0023 
0024 #include <QAction>
0025 
0026 #include "cmapmanager.h"
0027 #include "cmappath.h"
0028 #include "cmapzone.h"
0029 #include "cmaptext.h"
0030 #include "cmaproom.h"
0031 #include "cmaplevel.h"
0032 #include "cmapview.h"
0033 #include "cmapcmdelementcreate.h"
0034 #include "cmapcmdelementproperties.h"
0035 
0036 #include "kmemconfig.h"
0037 
0038 CMapClipboard::CMapClipboard(CMapManager *mapManager, CMapView *view, QObject *parent) :
0039   QObject(parent),
0040   m_mapManager(mapManager),
0041   m_view(view),
0042   m_parent(parent)
0043 {
0044     kDebug() << "CMapClipboard::CMapClipboard constructor begins";
0045 
0046     m_clipboard = nullptr;
0047     initActions();
0048     kDebug() << "CMapClipboard::CMapClipboard constructor ends";
0049 }
0050 
0051 CMapClipboard::~CMapClipboard()
0052 {
0053     if (m_clipboard)
0054         delete m_clipboard;
0055 }
0056 
0057 /** This is used to create the clipboard actions */
0058 void CMapClipboard::initActions(void)
0059 {
0060   // Edit menu
0061   KActionCollection *acol = m_view->actionCollection();
0062 
0063   m_editSelectAll = new QAction (m_parent);
0064   m_editSelectAll->setText (i18n ("Select All"));
0065   connect (m_editSelectAll, SIGNAL (triggered ()), this, SLOT (slotSelectAll ()));
0066   acol->addAction ("editSelectAll", m_editSelectAll);
0067   m_editUnselectAll = new QAction (m_parent);
0068   m_editUnselectAll->setText (i18n ("Unselect All"));
0069   connect (m_editUnselectAll, SIGNAL (triggered ()), this, SLOT (slotUnselectAll ()));
0070   acol->addAction ("editUnselectAll", m_editUnselectAll);
0071   m_editSelectInvert = new QAction (m_parent);
0072   m_editSelectInvert->setText (i18n ("Invert Selection"));
0073   connect (m_editSelectInvert, SIGNAL (triggered ()), this, SLOT (slotInvertSelection ()));
0074   acol->addAction ("editSelectInvert", m_editSelectInvert);
0075   m_editDelete = new QAction (m_parent);
0076   m_editDelete->setText (i18n ("Delete"));
0077   connect (m_editDelete, SIGNAL (triggered ()), this, SLOT (slotDelete ()));
0078   acol->addAction ("editDelete", m_editDelete);
0079   m_editCopy = new QAction (m_parent);
0080   m_editCopy->setText (i18n ("Copy"));
0081   connect (m_editCopy, SIGNAL (triggered ()), this, SLOT (slotCopy ()));
0082   acol->addAction ("editCopy", m_editCopy);
0083   m_editCut = new QAction (m_parent);
0084   m_editCut->setText (i18n ("Cut"));
0085   connect (m_editCut, SIGNAL (triggered ()), this, SLOT (slotCut ()));
0086   acol->addAction ("editCut", m_editCut);
0087   m_editPaste = new QAction (m_parent);
0088   m_editPaste->setText (i18n ("Paste"));
0089   connect (m_editPaste, SIGNAL (triggered ()), this, SLOT (slotPaste ()));
0090   acol->addAction ("editPaste", m_editPaste);
0091 }
0092 
0093 /** This method is used to set the enabled start of the actions */
0094 void CMapClipboard::enableActions(bool enabled)
0095 {
0096     m_editSelectAll->setEnabled(enabled);
0097     m_editUnselectAll->setEnabled(enabled);
0098     m_editSelectInvert->setEnabled(enabled);
0099     m_editDelete->setEnabled(enabled);
0100     m_editCopy->setEnabled(enabled);
0101     m_editCut->setEnabled(enabled);
0102     m_editPaste->setEnabled(enabled);
0103 }
0104 
0105 /** This method is called to copy the selected elements into the clipboard */
0106 void CMapClipboard::slotCopy()
0107 {
0108   if (m_clipboard)
0109     delete m_clipboard;
0110 
0111   m_clipboard = new KMemConfig();
0112 
0113   if (m_mapManager->getActiveView())
0114   {
0115     int group = 0;
0116     // Copy all the elements except for paths that are selected
0117     CMapLevel *level = m_mapManager->getActiveView()->getCurrentlyViewedLevel();
0118     QList<CMapElement *> lst = level->getAllElements();
0119     foreach (CMapElement *element, lst)
0120     {
0121       if (!element->getSelected()) continue;
0122       group++;
0123       QString grp;
0124       grp.sprintf("%d",group);
0125       KConfigGroup clipGroup = m_clipboard->group(grp);
0126 
0127       switch (element->getElementType())
0128       {
0129         case ROOM : {
0130                       CMapRoom *room = (CMapRoom *)element;
0131                       room->saveProperties(clipGroup);
0132                       clipGroup.deleteEntry("RoomID");
0133                       clipGroup.writeEntry("LabelPos",(int)CMapRoom::HIDE);
0134                     }
0135                     break;
0136         case TEXT : if (!((CMapText *)element)->getLinkElement())
0137                     {
0138                       element->saveProperties(clipGroup);
0139                       clipGroup.deleteEntry("TextID");
0140                     }
0141                     break;
0142         default   : break;
0143       }
0144     }
0145 
0146     // Copy all the path elements into the clipboard
0147     int pathGroup = 0;
0148 
0149     for (unsigned int idx = 0; idx < m_mapManager->getZone()->levelCount(); ++idx)
0150     {
0151       CMapLevel *level = m_mapManager->getZone()->getLevel(idx);
0152 
0153       foreach (CMapRoom *room, *level->getRoomList())
0154       {
0155         foreach (CMapPath *path, *room->getPathList())
0156         {
0157           if ((path->getSrcRoom()->getSelected() || path->getSrcRoom()->getZone()->getSelected()) &&
0158               (path->getDestRoom()->getSelected() || path->getDestRoom()->getZone()->getSelected()))
0159           { 
0160             copyPath (&pathGroup,path);
0161           }
0162         }
0163       }
0164     }
0165 
0166     // Copy all the linked text elements
0167     int linkGroup =0;
0168 
0169     foreach (CMapElement *element, lst)
0170     {
0171       if (element->getSelected() && element->getElementType()==TEXT)
0172       {
0173         CMapText *text = (CMapText *)element;
0174         CMapElement *link = text->getLinkElement();
0175         if (link)
0176         {
0177           linkGroup++;
0178           QString grp;
0179           grp.sprintf("LINK%d",linkGroup);
0180           KConfigGroup clipGroup = m_clipboard->group(grp);
0181 
0182           text->saveProperties(clipGroup);
0183 
0184           clipGroup.writeEntry("LinkLevelNum",link->getLevel()->getNumber());
0185 
0186           clipGroup.writeEntry("LinkX",link->getX());
0187           clipGroup.writeEntry("LinkY",link->getY());
0188           clipGroup.writeEntry("LinkZone",link->getZone()->getZoneID());
0189         }
0190       }
0191     }
0192 
0193     // Copy the selected paths
0194     KConfigGroup header = m_clipboard->group("Header");
0195     header.writeEntry("Elements",group);
0196     header.writeEntry("Paths",pathGroup);
0197     header.writeEntry("Links",linkGroup);
0198   }
0199 }
0200 
0201 /** This method is used to copy a path into the clipboard */                        
0202 void CMapClipboard::copyPath(int *pathGroup,CMapPath *path)
0203 {
0204     (*pathGroup)++;
0205     QString grp;
0206     grp.sprintf("PATH%d",*pathGroup);
0207         KConfigGroup pGroup = m_clipboard->group(grp);
0208 
0209     path->saveProperties(pGroup);
0210     pGroup.writeEntry("SrcLevelNum",path->getSrcRoom()->getLevel()->getNumber());
0211     pGroup.writeEntry("DestLevelNum",path->getDestRoom()->getLevel()->getNumber());
0212     pGroup.writeEntry("SrcX",path->getSrcRoom()->getX());
0213     pGroup.writeEntry("SrcY",path->getSrcRoom()->getY());
0214     pGroup.writeEntry("DestX",path->getDestRoom()->getX());
0215     pGroup.writeEntry("DestY",path->getDestRoom()->getY());
0216     pGroup.writeEntry("SrcZone",path->getSrcRoom()->getZone()->getZoneID());
0217     pGroup.writeEntry("DestZone",path->getDestRoom()->getZone()->getZoneID());
0218 }
0219 
0220 /** This method is called to copy the selected elements into the clipboard, then delete them */
0221 void CMapClipboard::slotCut()
0222 {
0223     slotCopy();
0224     slotDelete();
0225 }
0226 
0227 /** This method is called to paste the elements in the clipboard onto the current map */
0228 void CMapClipboard::slotPaste()
0229 {   
0230     m_mapManager->openCommandGroup("Paste");
0231     
0232     if (m_clipboard && m_mapManager->getActiveView())
0233     {
0234         pasteElements();
0235         pastePaths();
0236         pasteLinks();
0237     }
0238 
0239 
0240     m_mapManager->closeCommandGroup();
0241 }
0242 
0243 /** This method is used to paste elements that are not paths or linked text elements */
0244 void CMapClipboard::pasteElements()
0245 {
0246 
0247     // Paste the non path elements
0248 
0249     // Get the number of elements in the clipboard  
0250         KConfigGroup header = m_clipboard->group("Header");
0251     int elements = header.readEntry("Elements",0);
0252     if (elements>0)
0253     {
0254         // Interate through each element in the clipboard
0255         for (int i=1;i<=elements; i++)
0256         {
0257             // Change to the group for the current element
0258             QString grp;
0259             grp.sprintf("%d",i);
0260                         KConfigGroup group = m_clipboard->group(grp);
0261     
0262             // Get the level number in the zone that the element is to be insterted into
0263             int levelNum = group.readEntry("LevelNum",-5);
0264 
0265             // Get the zone that the element came from
0266             int orgZone = group.readEntry("Zone",-5);
0267             if (levelNum == -5 || orgZone == -5)
0268             {
0269                 // The level num was not found so this is not a zone copy
0270             }
0271             else
0272             {
0273                 CMapZone *zone = m_mapManager->getZone();
0274 
0275                 // Check to see if the level exists and if not create it
0276                 CMapLevel *level = nullptr;
0277                 if (levelNum >= (int)zone->levelCount())
0278                 {
0279                     level = m_mapManager->createLevel(UP);
0280                 }
0281                 else
0282                 {
0283                     level = zone->getLevel(levelNum);
0284                 }
0285 
0286                 // Update the clipboard with the new level that the element is to be pasted into
0287                 group.writeEntry("Level",level->getLevelID());
0288             }
0289 
0290             // Copy the properties to new properties the remove unwanted keys
0291             KMemConfig properties;
0292                         KConfigGroup props = properties.group("Properties");
0293             group.copyTo(&props);
0294 
0295             int x = props.readEntry("X",-5);
0296             int y = props.readEntry("Y",-5);
0297 
0298             props.writeEntry("X",x + m_mapManager->getMapData()->gridSize.width());
0299             props.writeEntry("Y",y + m_mapManager->getMapData()->gridSize.height());
0300 
0301             // Create the command used to add a new element
0302             CMapCmdElementCreate *command = new CMapCmdElementCreate(m_mapManager,i18n("Paste Element"));
0303 
0304             command->addElement(&properties,"Properties");
0305     
0306             // Execute the commmand
0307             m_mapManager->addCommand(command);
0308 
0309             // Check the created elements to see if a zone was created
0310             QList<CMapElement *> *elements = command->getElements();
0311 
0312             foreach (CMapElement *el, *elements)
0313             {
0314                 // Update the elements properties
0315                 CMapCmdElementProperties *cmd = new CMapCmdElementProperties(m_mapManager,i18n("Update Properties"),el);
0316                 cmd->setNewProperties(props);
0317                 m_mapManager->addCommand(cmd);
0318             }
0319         }
0320     }
0321 }
0322 
0323 /** This method is used to paste path elements */
0324 void CMapClipboard::pastePaths()
0325 {
0326     // Paste the path elements
0327     // Get the number of elements in the clipboard  
0328         KConfigGroup header = m_clipboard->group("Header");
0329     int paths = header.readEntry("Paths",0);
0330 
0331     if (paths>0)
0332     {
0333         // Interate through each element in the clipboard
0334         for (int i=1;i<=paths; i++)
0335         {
0336             // Change to the group for the current element
0337             QString grp;
0338             grp.sprintf("PATH%d",i);
0339                         KConfigGroup group = m_clipboard->group(grp);
0340 
0341             int srcLevelNum = group.readEntry("SrcLevelNum",-5);
0342             int destLevelNum = group.readEntry("DestLevelNum",-5);
0343 
0344             if (srcLevelNum==-5 || destLevelNum ==-5)
0345             {
0346                 // Should never get here
0347             }
0348             else
0349             {
0350                 // Lookup witch zone the element is to be pasted into
0351                 CMapZone *zone = m_mapManager->getZone();
0352 
0353                 // Check to see if the level exists and if not create it
0354                 CMapLevel *srcLevel = zone->getLevel(srcLevelNum);
0355                 CMapLevel *destLevel = zone->getLevel(destLevelNum);
0356 
0357                 KMemConfig properties;
0358                                 KConfigGroup props = properties.group("Properties");
0359                     group.copyTo(&props);
0360 
0361                 int srcX = props.readEntry("SrcX",-5);
0362                 int srcY = props.readEntry("SrcY",-5);
0363 
0364                 srcX+=m_mapManager->getMapData()->gridSize.width();
0365                 srcY+=m_mapManager->getMapData()->gridSize.height();
0366 
0367                 int destX = props.readEntry("DestX",-5);
0368                 int destY = props.readEntry("DestY",-5);
0369 
0370                 destX+=m_mapManager->getMapData()->gridSize.width();
0371                 destY+=m_mapManager->getMapData()->gridSize.height();
0372 
0373                 // Update the clipboard with the new level that the element is to be pasted into
0374                 props.writeEntry("SrcRoom", srcLevel->findRoomAt(QPoint(srcX,srcY))->getRoomID());
0375                 props.writeEntry("DestRoom", destLevel->findRoomAt(QPoint(destX,destY))->getRoomID());
0376                 props.writeEntry("SrcLevel",srcLevel->getLevelID());
0377                 props.writeEntry("DestLevel",destLevel->getLevelID());
0378 
0379                 // Create the command used to add a new element and the execute it
0380                 CMapCmdElementCreate *command = new CMapCmdElementCreate(m_mapManager,i18n("Paste Path"));
0381                 command->addElement(&properties);
0382                 m_mapManager->addCommand(command);
0383             }
0384         }
0385     }
0386 }
0387 
0388 /** This method is used to update linked text elements with the correct properties from the clibboard */
0389 void CMapClipboard::pasteLinks()
0390 {
0391     // Update link elements with the correct properties
0392         KConfigGroup header = m_clipboard->group("Header");
0393     int links = header.readEntry("Links",0);
0394 
0395     if (links>0)
0396     {
0397         // Interate through each element in the clipboard
0398         for (int i=1;i<=links; i++)
0399         {
0400             // Change to the group for the current element
0401             QString grp;
0402             grp.sprintf("LINK%d",i);
0403                         KConfigGroup group = m_clipboard->group(grp);
0404 
0405             int linkLevelNum = group.readEntry("LinkLevelNum",-5);
0406 
0407             if (linkLevelNum==-5)
0408             {
0409                 // Should never get here
0410             }
0411             else
0412             {
0413                 // Get the zone that the element came from
0414                 CMapZone *zone = m_mapManager->getZone();
0415 
0416                 // Check to see if the level exists and if not create it
0417                 CMapLevel *linkLevel = zone->getLevel(linkLevelNum);    
0418 
0419                 // Copy link text element properties to new properties
0420                 KMemConfig properties;
0421                                 KConfigGroup props = properties.group("Properties");
0422                     group.copyTo(&props);
0423 
0424                 // Get cordianets of text element and linked element, and adjust them for any offsets
0425                 int x = props.readEntry("LinkX",-5);
0426                 int y = props.readEntry("LinkY",-5);
0427 
0428                 x+=m_mapManager->getMapData()->gridSize.width();
0429                 y+=m_mapManager->getMapData()->gridSize.height();
0430 
0431                 int textX = props.readEntry("X",-5);
0432                 int textY = props.readEntry("Y",-5);
0433                 props.writeEntry("X",textX + m_mapManager->getMapData()->gridSize.width());
0434                 props.writeEntry("Y",textY + m_mapManager->getMapData()->gridSize.height());
0435 
0436                 // Setup the properties so that the text element will be linked to the new element
0437                 CMapElement *link = linkLevel->findElementAt(QPoint(x,y));
0438                 if (link->getElementType()==ZONE)
0439                 {
0440                     props.writeEntry("LinkedID",((CMapZone *)link)->getZoneID());
0441                 }
0442                 else
0443                 {
0444                     props.writeEntry("LinkedID",((CMapRoom *)link)->getRoomID());
0445                 }
0446                 props.writeEntry("LinkedLevel",link->getLevel()->getLevelID());
0447 
0448                 // Create the command used to add a new element
0449                 CMapCmdElementCreate *command = new CMapCmdElementCreate(m_mapManager,i18n("Paste Element"));
0450                 command->addElement(&properties,"Properties");
0451                 m_mapManager->addCommand(command);
0452 
0453                 // Check the created elements to see if a zone was created
0454                 QList<CMapElement *> *elements=command->getElements();
0455 
0456                 foreach (CMapElement *el, *elements)
0457                 {
0458                     // Update the elements properties
0459                     CMapCmdElementProperties *cmd = new CMapCmdElementProperties(m_mapManager,i18n("Update Properties"),el);
0460                     cmd->setNewProperties(props);
0461                     m_mapManager->addCommand(cmd);
0462                 }
0463             }
0464         }
0465     }
0466 }
0467 
0468 
0469 /** This slot is called to delete all the selected objects in the current view */
0470 void CMapClipboard::slotDelete(void)
0471 {
0472   m_mapManager->openCommandGroup(i18n("Delete Elements"));
0473   CMapView *currentView = m_mapManager->getActiveView();
0474   if (currentView)
0475   {
0476     CMapLevel *level = currentView->getCurrentlyViewedLevel();
0477 
0478     if (level)
0479     {
0480       QList<CMapElement *> lst = level->getAllElements();
0481       foreach (CMapElement *el, lst)
0482         if (el->getSelected())
0483           m_mapManager->deleteElement(el);
0484     }
0485   }
0486 
0487   m_mapManager->closeCommandGroup();
0488 }
0489 
0490 /** This slot is called when the select all menu option is selected */
0491 void CMapClipboard::slotSelectAll(void)
0492 {
0493   if (m_mapManager->getActiveView())
0494   {
0495     CMapLevel *level = m_mapManager->getActiveView()->getCurrentlyViewedLevel();
0496     QList<CMapElement *> lst = level->getAllElements();
0497     foreach (CMapElement *element, lst)
0498       element->setSelected(true);
0499 
0500     m_mapManager->levelChanged(level);
0501   }
0502 }
0503 
0504 /** This slot is called when the unselect all menu option is selected */
0505 void CMapClipboard::slotUnselectAll(void)
0506 {
0507     if (m_mapManager->getActiveView())
0508     {
0509         m_mapManager->unselectElements(m_mapManager->getActiveView()->getCurrentlyViewedLevel());
0510 
0511         m_mapManager->levelChanged(m_mapManager->getActiveView()->getCurrentlyViewedLevel());
0512     }
0513 }
0514 
0515 /** This slot is called when the invert selection menu option is called */
0516 void CMapClipboard::slotInvertSelection(void)
0517 {
0518   if (!m_mapManager->getActiveView()) return;
0519   CMapLevel *level = m_mapManager->getActiveView()->getCurrentlyViewedLevel();
0520 
0521   QList<CMapElement *> lst = level->getAllElements();
0522   foreach (CMapElement *element, lst)
0523     element->setSelected(!element->getSelected());
0524 
0525   m_mapManager->levelChanged(m_mapManager->getActiveView()->getCurrentlyViewedLevel());
0526 }
0527 
0528 #include "moc_cmapclipboard.cpp"