File indexing completed on 2024-04-28 15:35:31

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 <KLocalizedString>
0022 
0023 #include <QAction>
0024 #include <QDebug>
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     qDebug() << "CMapClipboard::CMapClipboard constructor begins";
0045 
0046     m_clipboard = nullptr;
0047     initActions();
0048     qDebug() << "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 = QString::number(group);
0124       KConfigGroup clipGroup = m_clipboard->group(grp);
0125 
0126       switch (element->getElementType())
0127       {
0128         case ROOM : {
0129                       CMapRoom *room = (CMapRoom *)element;
0130                       room->saveProperties(clipGroup);
0131                       clipGroup.deleteEntry("RoomID");
0132                       clipGroup.writeEntry("LabelPos",(int)CMapRoom::HIDE);
0133                     }
0134                     break;
0135         case TEXT : if (!((CMapText *)element)->getLinkElement())
0136                     {
0137                       element->saveProperties(clipGroup);
0138                       clipGroup.deleteEntry("TextID");
0139                     }
0140                     break;
0141         default   : break;
0142       }
0143     }
0144 
0145     // Copy all the path elements into the clipboard
0146     int pathGroup = 0;
0147 
0148     for (unsigned int idx = 0; idx < m_mapManager->getZone()->levelCount(); ++idx)
0149     {
0150       CMapLevel *level = m_mapManager->getZone()->getLevel(idx);
0151 
0152       foreach (CMapRoom *room, *level->getRoomList())
0153       {
0154         foreach (CMapPath *path, *room->getPathList())
0155         {
0156           if ((path->getSrcRoom()->getSelected() || path->getSrcRoom()->getZone()->getSelected()) &&
0157               (path->getDestRoom()->getSelected() || path->getDestRoom()->getZone()->getSelected()))
0158           { 
0159             copyPath (&pathGroup,path);
0160           }
0161         }
0162       }
0163     }
0164 
0165     // Copy all the linked text elements
0166     int linkGroup =0;
0167 
0168     foreach (CMapElement *element, lst)
0169     {
0170       if (element->getSelected() && element->getElementType()==TEXT)
0171       {
0172         CMapText *text = (CMapText *)element;
0173         CMapElement *link = text->getLinkElement();
0174         if (link)
0175         {
0176           linkGroup++;
0177           QString grp = "LINK" + QString::number(linkGroup);
0178           KConfigGroup clipGroup = m_clipboard->group(grp);
0179 
0180           text->saveProperties(clipGroup);
0181 
0182           clipGroup.writeEntry("LinkLevelNum",link->getLevel()->getNumber());
0183 
0184           clipGroup.writeEntry("LinkX",link->getX());
0185           clipGroup.writeEntry("LinkY",link->getY());
0186           clipGroup.writeEntry("LinkZone",link->getZone()->getZoneID());
0187         }
0188       }
0189     }
0190 
0191     // Copy the selected paths
0192     KConfigGroup header = m_clipboard->group("Header");
0193     header.writeEntry("Elements",group);
0194     header.writeEntry("Paths",pathGroup);
0195     header.writeEntry("Links",linkGroup);
0196   }
0197 }
0198 
0199 /** This method is used to copy a path into the clipboard */                        
0200 void CMapClipboard::copyPath(int *pathGroup,CMapPath *path)
0201 {
0202     (*pathGroup)++;
0203         QString grp = "PATH" + QString::number(*pathGroup);
0204         KConfigGroup pGroup = m_clipboard->group(grp);
0205 
0206     path->saveProperties(pGroup);
0207     pGroup.writeEntry("SrcLevelNum",path->getSrcRoom()->getLevel()->getNumber());
0208     pGroup.writeEntry("DestLevelNum",path->getDestRoom()->getLevel()->getNumber());
0209     pGroup.writeEntry("SrcX",path->getSrcRoom()->getX());
0210     pGroup.writeEntry("SrcY",path->getSrcRoom()->getY());
0211     pGroup.writeEntry("DestX",path->getDestRoom()->getX());
0212     pGroup.writeEntry("DestY",path->getDestRoom()->getY());
0213     pGroup.writeEntry("SrcZone",path->getSrcRoom()->getZone()->getZoneID());
0214     pGroup.writeEntry("DestZone",path->getDestRoom()->getZone()->getZoneID());
0215 }
0216 
0217 /** This method is called to copy the selected elements into the clipboard, then delete them */
0218 void CMapClipboard::slotCut()
0219 {
0220     slotCopy();
0221     slotDelete();
0222 }
0223 
0224 /** This method is called to paste the elements in the clipboard onto the current map */
0225 void CMapClipboard::slotPaste()
0226 {   
0227     m_mapManager->openCommandGroup("Paste");
0228     
0229     if (m_clipboard && m_mapManager->getActiveView())
0230     {
0231         pasteElements();
0232         pastePaths();
0233         pasteLinks();
0234     }
0235 
0236 
0237     m_mapManager->closeCommandGroup();
0238 }
0239 
0240 /** This method is used to paste elements that are not paths or linked text elements */
0241 void CMapClipboard::pasteElements()
0242 {
0243 
0244     // Paste the non path elements
0245 
0246     // Get the number of elements in the clipboard  
0247         KConfigGroup header = m_clipboard->group("Header");
0248     int elements = header.readEntry("Elements",0);
0249     if (elements>0)
0250     {
0251         // Interate through each element in the clipboard
0252         for (int i=1;i<=elements; i++)
0253         {
0254             // Change to the group for the current element
0255             QString grp = QString::number(i);
0256                         KConfigGroup group = m_clipboard->group(grp);
0257     
0258             // Get the level number in the zone that the element is to be insterted into
0259             int levelNum = group.readEntry("LevelNum",-5);
0260 
0261             // Get the zone that the element came from
0262             int orgZone = group.readEntry("Zone",-5);
0263             if (levelNum == -5 || orgZone == -5)
0264             {
0265                 // The level num was not found so this is not a zone copy
0266             }
0267             else
0268             {
0269                 CMapZone *zone = m_mapManager->getZone();
0270 
0271                 // Check to see if the level exists and if not create it
0272                 CMapLevel *level = nullptr;
0273                 if (levelNum >= (int)zone->levelCount())
0274                 {
0275                     level = m_mapManager->createLevel(UP);
0276                 }
0277                 else
0278                 {
0279                     level = zone->getLevel(levelNum);
0280                 }
0281 
0282                 // Update the clipboard with the new level that the element is to be pasted into
0283                 group.writeEntry("Level",level->getLevelID());
0284             }
0285 
0286             // Copy the properties to new properties the remove unwanted keys
0287             KMemConfig properties;
0288                         KConfigGroup props = properties.group("Properties");
0289             group.copyTo(&props);
0290 
0291             int x = props.readEntry("X",-5);
0292             int y = props.readEntry("Y",-5);
0293 
0294             props.writeEntry("X",x + m_mapManager->getMapData()->gridSize.width());
0295             props.writeEntry("Y",y + m_mapManager->getMapData()->gridSize.height());
0296 
0297             // Create the command used to add a new element
0298             CMapCmdElementCreate *command = new CMapCmdElementCreate(m_mapManager,i18n("Paste Element"));
0299 
0300             command->addElement(&properties,"Properties");
0301     
0302             // Execute the commmand
0303             m_mapManager->addCommand(command);
0304 
0305             // Check the created elements to see if a zone was created
0306             QList<CMapElement *> *elements = command->getElements();
0307 
0308             foreach (CMapElement *el, *elements)
0309             {
0310                 // Update the elements properties
0311                 CMapCmdElementProperties *cmd = new CMapCmdElementProperties(m_mapManager,i18n("Update Properties"),el);
0312                 cmd->setNewProperties(props);
0313                 m_mapManager->addCommand(cmd);
0314             }
0315         }
0316     }
0317 }
0318 
0319 /** This method is used to paste path elements */
0320 void CMapClipboard::pastePaths()
0321 {
0322     // Paste the path elements
0323     // Get the number of elements in the clipboard  
0324         KConfigGroup header = m_clipboard->group("Header");
0325     int paths = header.readEntry("Paths",0);
0326 
0327     if (paths>0)
0328     {
0329         // Interate through each element in the clipboard
0330         for (int i=1;i<=paths; i++)
0331         {
0332             // Change to the group for the current element
0333             QString grp = "PATH" + QString::number(i);
0334                         KConfigGroup group = m_clipboard->group(grp);
0335 
0336             int srcLevelNum = group.readEntry("SrcLevelNum",-5);
0337             int destLevelNum = group.readEntry("DestLevelNum",-5);
0338 
0339             if (srcLevelNum==-5 || destLevelNum ==-5)
0340             {
0341                 // Should never get here
0342             }
0343             else
0344             {
0345                 // Lookup witch zone the element is to be pasted into
0346                 CMapZone *zone = m_mapManager->getZone();
0347 
0348                 // Check to see if the level exists and if not create it
0349                 CMapLevel *srcLevel = zone->getLevel(srcLevelNum);
0350                 CMapLevel *destLevel = zone->getLevel(destLevelNum);
0351 
0352                 KMemConfig properties;
0353                                 KConfigGroup props = properties.group("Properties");
0354                     group.copyTo(&props);
0355 
0356                 int srcX = props.readEntry("SrcX",-5);
0357                 int srcY = props.readEntry("SrcY",-5);
0358 
0359                 srcX+=m_mapManager->getMapData()->gridSize.width();
0360                 srcY+=m_mapManager->getMapData()->gridSize.height();
0361 
0362                 int destX = props.readEntry("DestX",-5);
0363                 int destY = props.readEntry("DestY",-5);
0364 
0365                 destX+=m_mapManager->getMapData()->gridSize.width();
0366                 destY+=m_mapManager->getMapData()->gridSize.height();
0367 
0368                 // Update the clipboard with the new level that the element is to be pasted into
0369                 props.writeEntry("SrcRoom", srcLevel->findRoomAt(QPoint(srcX,srcY))->getRoomID());
0370                 props.writeEntry("DestRoom", destLevel->findRoomAt(QPoint(destX,destY))->getRoomID());
0371                 props.writeEntry("SrcLevel",srcLevel->getLevelID());
0372                 props.writeEntry("DestLevel",destLevel->getLevelID());
0373 
0374                 // Create the command used to add a new element and the execute it
0375                 CMapCmdElementCreate *command = new CMapCmdElementCreate(m_mapManager,i18n("Paste Path"));
0376                 command->addElement(&properties);
0377                 m_mapManager->addCommand(command);
0378             }
0379         }
0380     }
0381 }
0382 
0383 /** This method is used to update linked text elements with the correct properties from the clibboard */
0384 void CMapClipboard::pasteLinks()
0385 {
0386     // Update link elements with the correct properties
0387         KConfigGroup header = m_clipboard->group("Header");
0388     int links = header.readEntry("Links",0);
0389 
0390     if (links>0)
0391     {
0392         // Interate through each element in the clipboard
0393         for (int i=1;i<=links; i++)
0394         {
0395             // Change to the group for the current element
0396             QString grp = "LINK" + QString::number(i);
0397                         KConfigGroup group = m_clipboard->group(grp);
0398 
0399             int linkLevelNum = group.readEntry("LinkLevelNum",-5);
0400 
0401             if (linkLevelNum==-5)
0402             {
0403                 // Should never get here
0404             }
0405             else
0406             {
0407                 // Get the zone that the element came from
0408                 CMapZone *zone = m_mapManager->getZone();
0409 
0410                 // Check to see if the level exists and if not create it
0411                 CMapLevel *linkLevel = zone->getLevel(linkLevelNum);    
0412 
0413                 // Copy link text element properties to new properties
0414                 KMemConfig properties;
0415                                 KConfigGroup props = properties.group("Properties");
0416                     group.copyTo(&props);
0417 
0418                 // Get cordianets of text element and linked element, and adjust them for any offsets
0419                 int x = props.readEntry("LinkX",-5);
0420                 int y = props.readEntry("LinkY",-5);
0421 
0422                 x+=m_mapManager->getMapData()->gridSize.width();
0423                 y+=m_mapManager->getMapData()->gridSize.height();
0424 
0425                 int textX = props.readEntry("X",-5);
0426                 int textY = props.readEntry("Y",-5);
0427                 props.writeEntry("X",textX + m_mapManager->getMapData()->gridSize.width());
0428                 props.writeEntry("Y",textY + m_mapManager->getMapData()->gridSize.height());
0429 
0430                 // Setup the properties so that the text element will be linked to the new element
0431                 CMapElement *link = linkLevel->findElementAt(QPoint(x,y));
0432                 if (link->getElementType()==ZONE)
0433                 {
0434                     props.writeEntry("LinkedID",((CMapZone *)link)->getZoneID());
0435                 }
0436                 else
0437                 {
0438                     props.writeEntry("LinkedID",((CMapRoom *)link)->getRoomID());
0439                 }
0440                 props.writeEntry("LinkedLevel",link->getLevel()->getLevelID());
0441 
0442                 // Create the command used to add a new element
0443                 CMapCmdElementCreate *command = new CMapCmdElementCreate(m_mapManager,i18n("Paste Element"));
0444                 command->addElement(&properties,"Properties");
0445                 m_mapManager->addCommand(command);
0446 
0447                 // Check the created elements to see if a zone was created
0448                 QList<CMapElement *> *elements=command->getElements();
0449 
0450                 foreach (CMapElement *el, *elements)
0451                 {
0452                     // Update the elements properties
0453                     CMapCmdElementProperties *cmd = new CMapCmdElementProperties(m_mapManager,i18n("Update Properties"),el);
0454                     cmd->setNewProperties(props);
0455                     m_mapManager->addCommand(cmd);
0456                 }
0457             }
0458         }
0459     }
0460 }
0461 
0462 
0463 /** This slot is called to delete all the selected objects in the current view */
0464 void CMapClipboard::slotDelete(void)
0465 {
0466   m_mapManager->openCommandGroup(i18n("Delete Elements"));
0467   CMapView *currentView = m_mapManager->getActiveView();
0468   if (currentView)
0469   {
0470     CMapLevel *level = currentView->getCurrentlyViewedLevel();
0471 
0472     if (level)
0473     {
0474       QList<CMapElement *> lst = level->getAllElements();
0475       foreach (CMapElement *el, lst)
0476         if (el->getSelected())
0477           m_mapManager->deleteElement(el);
0478     }
0479   }
0480 
0481   m_mapManager->closeCommandGroup();
0482 }
0483 
0484 /** This slot is called when the select all menu option is selected */
0485 void CMapClipboard::slotSelectAll(void)
0486 {
0487   if (m_mapManager->getActiveView())
0488   {
0489     CMapLevel *level = m_mapManager->getActiveView()->getCurrentlyViewedLevel();
0490     QList<CMapElement *> lst = level->getAllElements();
0491     foreach (CMapElement *element, lst)
0492       element->setSelected(true);
0493 
0494     m_mapManager->levelChanged(level);
0495   }
0496 }
0497 
0498 /** This slot is called when the unselect all menu option is selected */
0499 void CMapClipboard::slotUnselectAll(void)
0500 {
0501     if (m_mapManager->getActiveView())
0502     {
0503         m_mapManager->unselectElements(m_mapManager->getActiveView()->getCurrentlyViewedLevel());
0504 
0505         m_mapManager->levelChanged(m_mapManager->getActiveView()->getCurrentlyViewedLevel());
0506     }
0507 }
0508 
0509 /** This slot is called when the invert selection menu option is called */
0510 void CMapClipboard::slotInvertSelection(void)
0511 {
0512   if (!m_mapManager->getActiveView()) return;
0513   CMapLevel *level = m_mapManager->getActiveView()->getCurrentlyViewedLevel();
0514 
0515   QList<CMapElement *> lst = level->getAllElements();
0516   foreach (CMapElement *element, lst)
0517     element->setSelected(!element->getSelected());
0518 
0519   m_mapManager->levelChanged(m_mapManager->getActiveView()->getCurrentlyViewedLevel());
0520 }
0521 
0522 #include "moc_cmapclipboard.cpp"