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

0001 /***************************************************************************
0002                                cmappath.cpp
0003                              -------------------
0004     begin                : Sat Mar 10 2001
0005     copyright            : (C) 2001 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 "cmappath.h"
0019 
0020 #include "cmapmanager.h"
0021 
0022 #include <kdebug.h>
0023 #include <klocale.h>
0024 #include <kconfiggroup.h>
0025 
0026 #include <qregion.h>
0027 #include <QPolygon>
0028 
0029 #include <math.h>
0030 #include <stdlib.h>
0031 
0032 #include "cmaplevel.h"
0033 #include "cmapcmdelementproperties.h"
0034 
0035 CMapPath::CMapPath(CMapManager *manager,CMapRoom *srcRoom,directionTyp srcDir,CMapRoom *destRoom,directionTyp destDir, bool twoWay) : CMapElement(manager,nullptr)
0036 {
0037   setSrcRoom(srcRoom);
0038   setDestRoom(destRoom);
0039   setSrcDir(srcDir);
0040   setDestDir(destDir);
0041   setCords();
0042   bSpecialExit = false;
0043   specialCmd = "";
0044 
0045   setLevel(srcRoom->getLevel());
0046   srcRoom->addPath(this);
0047   destRoom->getConnectingPathList()->append(this);
0048 
0049   // Check to see if there is a a path in the opsite directon, if so make this a two way path
0050   bool found = false;
0051   foreach (CMapPath *path, *destRoom->getPathList())
0052   {
0053     // FIXME_jp : Fix this for multiple special paths between the same rooms with different cmd's
0054     if (path->getDestRoom()==srcRoom &&
0055         path->getSrcDir() == destDir &&
0056         path->getDestDir() == srcDir &&
0057         path->getSpecialCmd() == "")
0058     {
0059       setOpsitePath(path);
0060       path->setOpsitePath(this);
0061       found = true;
0062     }
0063   }
0064   if (twoWay && (!found)) makeTwoWay();
0065 
0066   beforeCommand = "";
0067   afterCommand = "";
0068   done = false;
0069   opsitePath = nullptr;
0070 
0071   m_dontPaintBend=0;
0072 }
0073 
0074 CMapPath::CMapPath(CMapManager *manager,CMapRoom *srcRoom,CMapRoom *destRoom)  : CMapElement(manager,nullptr)
0075 {
0076     setSrcRoom(srcRoom);
0077     setDestRoom(destRoom);
0078     setSrcDir(NORTH);
0079     setDestDir(SOUTH);
0080 
0081     beforeCommand = "";
0082     afterCommand = "";
0083     bSpecialExit = false;
0084     specialCmd = "";
0085     done = false;
0086     opsitePath = nullptr;
0087 }
0088 
0089 CMapPath::~CMapPath()
0090 {
0091   if (opsitePath) {
0092     opsitePath->setOpsitePath(nullptr);  // needed to prevent endless looping
0093     delete opsitePath;
0094   }
0095 
0096   if (destRoom)
0097     destRoom->getConnectingPathList()->removeAll(this);
0098   if (srcRoom)
0099     srcRoom->getPathList()->removeAll(this);
0100 }
0101 
0102 void CMapPath::setDontPaintBend(int bend)
0103 {
0104     m_dontPaintBend = bend;
0105 }
0106 
0107 /** This method is used to set the cords of the path */
0108 void CMapPath::setCords(void)
0109 {
0110     QPoint pos1,pos2;
0111     CMapRoom *srcRoom = getSrcRoom();
0112     CMapRoom *destRoom = getDestRoom();
0113     directionTyp srcDir = getSrcDir();
0114     directionTyp destDir = getDestDir();
0115 
0116     QPoint start;
0117     QSize halfRoomSize;
0118 
0119     start.setX(srcRoom->getX() + (srcRoom->getWidth() /  2));
0120     start.setY(srcRoom->getY() + (srcRoom->getHeight() /  2));
0121 
0122     halfRoomSize = QSize(srcRoom->getSize().width()/2,srcRoom->getSize().height()/2);
0123     getManager()->directionToCord(srcDir,halfRoomSize,&pos1);
0124 
0125     pos1+=start;
0126 
0127     QPoint end;
0128 
0129     end.setX(destRoom->getX() + (destRoom->getWidth() /  2));
0130     end.setY(destRoom->getY() + (destRoom->getHeight() /  2));
0131     halfRoomSize = QSize(destRoom->getSize().width()/2,destRoom->getSize().height()/2);
0132 
0133     getManager()->directionToCord(destDir,halfRoomSize,&pos2);
0134 
0135     pos2+=end;
0136 
0137     QRect rect(pos1,pos2);
0138     setRect(rect);
0139         setDone(false);
0140 }
0141 
0142 /** Used to draw an arrow head */
0143 void CMapPath::drawArrow(directionTyp dir,QPainter *p,QPoint end)
0144 {
0145     int x1=0,x2=0,y1=0,y2=0;
0146     QPolygon cords(3);
0147 
0148     switch (dir)
0149     {
0150         case NORTH     : x1=end.x()-3; x2=end.x()+3; y1=end.y()-3; y2=end.y()-3; break;
0151         case SOUTH     : x1=end.x()-3; x2=end.x()+3; y1=end.y()+3; y2=end.y()+3; break;
0152         case WEST      : x1=end.x()-3; x2=end.x()-3; y1=end.y()-3; y2=end.y()+3; break;
0153         case EAST      : x1=end.x()+3; x2=end.x()+3; y1=end.y()-3; y2=end.y()+3; break;
0154         case NORTHEAST : x1=end.x(); x2=end.x()+4; y1=end.y()-4; y2=end.y(); break;
0155         case SOUTHEAST : x1=end.x(); x2=end.x()+4; y1=end.y()+4; y2=end.y(); break;
0156         case SOUTHWEST : x1=end.x(); x2=end.x()-4; y1=end.y()+4; y2=end.y(); break;
0157         case NORTHWEST : x1=end.x(); x2=end.x()-4; y1=end.y()-4; y2=end.y(); break;
0158         case UP        : break;
0159         case DOWN      : break;
0160         case SPECIAL   : break;
0161     }
0162 
0163     // Draw the arrow head to indicate the direction of the path
0164     cords.setPoint(0,end);
0165     cords.setPoint(1,x1,y1);
0166     cords.setPoint(2,x2,y2);
0167         p->drawPolygon(cords.constData(), 3, Qt::OddEvenFill);
0168 }
0169 
0170 QPoint CMapPath::getIndent(directionTyp dir,QPoint pos)
0171 {
0172     int x=0,y=0;
0173     int posx = pos.x();
0174     int posy = pos.y();
0175 
0176     switch (dir)
0177     {
0178         case NORTH     : x = posx  ; y=posy-5; break;
0179         case SOUTH     : x = posx  ; y=posy+5; break;
0180         case WEST      : x = posx-5; y=posy  ; break;
0181         case EAST      : x = posx+5; y=posy  ; break;
0182         case NORTHEAST : x = posx+5; y=posy-5; break;
0183         case SOUTHEAST : x = posx+5; y=posy+5; break;
0184         case SOUTHWEST : x = posx-5; y=posy+5; break;
0185         case NORTHWEST : x = posx-5; y=posy-5; break;
0186         case UP        : break;
0187         case DOWN      : break;
0188         case SPECIAL   : break;
0189     }
0190 
0191     return QPoint(x,y);
0192 }
0193 
0194 /** This method is used to calcualte the distance from a path segment */
0195 int CMapPath::getDistance (int x,int y,int x1,int x2,int y1,int y2)
0196 {
0197     int a = y1 - y2;
0198     int b = -(x1 - x2);
0199 
0200     int d = (int)(( (x - x2) * a + (y-y2) * b) / sqrt (a*a + b*b));
0201 
0202     return abs(d);
0203 }
0204 
0205 /** Set a pointer to the destination room */
0206 void CMapPath::setDestRoom(CMapRoom *DestRoom)
0207 {
0208     destRoom = DestRoom;
0209 }
0210 
0211 /** Set a pointer to the source room */
0212 void CMapPath::setSrcRoom(CMapRoom *SrcRoom)
0213 {
0214     srcRoom = SrcRoom;
0215 }
0216 
0217 /** Set the start and finish directrions of the path */
0218 void CMapPath::setSrcDir(directionTyp SrcDir)
0219 {
0220     srcDir = SrcDir;
0221 }
0222 
0223 void CMapPath::setDestDir(directionTyp DestDir)
0224 {
0225     destDir = DestDir;
0226 }
0227 
0228 void CMapPath::makeOneWay() {
0229   CMapPath *path = getOpsitePath();
0230   if (!path) return;
0231   path->setOpsitePath(nullptr);  // so it doesn't delete us too
0232   delete path;
0233 }
0234 
0235 void CMapPath::makeTwoWay()
0236 {
0237   if (opsitePath) return;
0238 
0239   CMapPath *newPath = new CMapPath(getManager(), destRoom, destDir, srcRoom, srcDir, false);
0240   setOpsitePath(newPath);
0241   newPath->setOpsitePath(this);
0242   if (bSpecialExit)
0243     newPath->setSpecialCmd(specialCmd);
0244 }
0245 
0246 directionTyp CMapPath::generatePath()
0247 {
0248     tempPathCords.clear();
0249 
0250     QPoint start = getLowPos();
0251         QPoint end = getHighPos();
0252 
0253         directionTyp destDir = getDestDir();
0254 
0255     QPoint indent1 = getIndent(getSrcDir(),start);
0256 
0257     QPoint indent2 = getIndent(destDir,end);
0258 
0259     tempPathCords.append(start);
0260     tempPathCords.append(indent1);
0261 
0262     for( PointList::Iterator point = bendList.begin(); point != bendList.end(); ++point )
0263     {
0264         tempPathCords.append(*point);
0265     }
0266 
0267     tempPathCords.append(indent2);
0268     tempPathCords.append(end);
0269 
0270     return destDir;
0271 }
0272 
0273 /** Used to draw the path */
0274 void CMapPath::drawPath(QPainter *p,CMapZone *zone,QPoint offset,QColor color,int editBox,QPoint editPos)
0275 {
0276     directionTyp tempDestDir = generatePath();
0277 
0278     p->setPen(color);
0279     p->setBrush(color);
0280 
0281     // If the path has not already been then draw it
0282     if (!getDone())
0283     {
0284         if (tempPathCords.count()>1)
0285         {
0286             QPoint temp = tempPathCords.at(1);
0287 
0288             int count = 0;
0289 
0290             for( PointList::Iterator point = tempPathCords.begin(); point != tempPathCords.end(); ++point )
0291             {
0292                 
0293                 if (editBox > 0 && count==editBox + 1)
0294                 {
0295                     p->drawLine(temp + offset,editPos + offset);
0296                 }
0297                 else if (editBox > 0 && count==editBox + 2)
0298                 {
0299                     p->drawLine(editPos + offset,(*point) + offset);
0300                 }
0301                 else
0302                 {
0303                     if (editBox == 0 && m_dontPaintBend == 0)
0304                     {
0305                         p->drawLine(temp + offset,(*point) + offset);
0306                     }
0307                     else
0308                     {
0309                         if (count != m_dontPaintBend+1 && count != m_dontPaintBend + 2)
0310                         {
0311                             p->drawLine(temp + offset,(*point) + offset);
0312                         }
0313                     }
0314                 }
0315                 temp = *point;
0316                 count++;
0317             }
0318         }
0319 
0320         if (getEditMode())
0321         {
0322             int count = 0;
0323             p->setPen(getManager()->getMapData()->editColor);
0324             p->setBrush(getManager()->getMapData()->editColor);
0325             for( PointList::Iterator point = tempPathCords.begin(); point != tempPathCords.end(); ++point )
0326             {
0327                 if (count>1 && count < (int)tempPathCords.count()-2)
0328                 {
0329                     if (editBox > 0 && count==editBox + 2)
0330                     {
0331                         p->drawRect(editPos.x()-3,editPos.y()-3,6,6);
0332                     }
0333                     else
0334                     {
0335                         if (editBox == 0 && m_dontPaintBend == 0)
0336                         {
0337                             p->drawRect((*point).x()-3,(*point).y()-3,6,6);
0338                         }
0339                         else
0340                         {
0341                             if (count != m_dontPaintBend+1)
0342                             {
0343                                 p->drawRect((*point).x()-3,(*point).y()-3,6,6); 
0344                             }
0345                         }
0346                     }
0347                 }
0348                 count ++;
0349             }
0350         }
0351 
0352     }
0353 
0354     p->setPen(color);
0355     p->setBrush(color);
0356 
0357     // Draw the arrow head of the path
0358     drawArrow(tempDestDir,p,tempPathCords.last() + offset);
0359 
0360     if (getDestRoom()->getZone()!=zone)
0361     {
0362         if (getOpsitePath())
0363             drawArrow(getSrcDir(),p,tempPathCords.first() + offset);
0364     }
0365 
0366     // Mark this path and the opsite (two way path) as having been drawn
0367     setDone(true);
0368 
0369     if (getOpsitePath())
0370     {
0371         getOpsitePath()->setDone(true);
0372     }
0373 }
0374 
0375 
0376 
0377 /** Used to paint the element at a given location and size
0378   * @param p The painter to paint the element to
0379   * @param pos The position to paint the elmenet
0380   * @param size The size the element should be draw
0381   * @param zone The current zone being viewed */
0382 void CMapPath::paintElementResize(QPainter *p,QPoint,QSize,CMapZone *zone)
0383 {
0384     if (srcDir == UP || srcDir == DOWN || destDir == UP || destDir == DOWN || srcDir==SPECIAL || destDir==SPECIAL) return;
0385 
0386     // Get start and end points of the path
0387     drawPath(p,zone,QPoint(0,0),getManager()->getMapData()->defaultPathColor);
0388 
0389     if (getSelected())
0390     {
0391         p->setPen(getManager()->getMapData()->selectedColor);
0392         p->setBrush(getManager()->getMapData()->selectedColor);
0393         p->drawRect(tempPathCords.first().x()-3,tempPathCords.first().y()-3,6,6);
0394         p->drawRect(tempPathCords.last().x()-3,tempPathCords.last().y()-3,6,6);
0395     }
0396 }
0397 
0398 /** Used to find out if the mouse is in the element */
0399 bool CMapPath::mouseInElement(QPoint mousePos)
0400 {
0401     if (srcDir == UP || srcDir == DOWN || srcDir==SPECIAL) return false;
0402 
0403     //FIXME_jp: Handle zone paths that have been termintated
0404     generatePath();
0405 
0406     if (tempPathCords.count()>1)
0407     {
0408         QPoint temp = tempPathCords.at(1);
0409 
0410         for( PointList::Iterator point = tempPathCords.begin(); point != tempPathCords.end(); ++point )
0411         {       
0412             QPoint pos1 = temp;
0413             QPoint pos2 = *point;
0414 
0415             QRect rect = getBoundRectOfSeg(pos1,pos2);
0416 
0417             QRegion region(rect,QRegion::Rectangle);
0418 
0419             if (region.contains(mousePos))
0420             {
0421                 int distance = getDistance(mousePos.x(),mousePos.y(),pos1.x(),pos2.x(),pos1.y(),pos2.y());
0422 
0423                 return (distance <= 5);
0424             }
0425 
0426             temp = *point;
0427         }
0428     }
0429     return false;
0430 }
0431 
0432 QRect CMapPath::getBoundRectOfSeg(QPoint pos1,QPoint pos2)
0433 {
0434     QRect rect;
0435 
0436     if (pos1.x() == pos2.x())
0437     {
0438         pos1.setX(pos1.x()-5);
0439         pos2.setX(pos2.x()+5);
0440     }
0441 
0442     if (pos1.y() == pos2.y()){
0443 
0444         pos1.setY(pos1.y()-5);
0445         pos2.setY(pos2.y()+5);
0446     }
0447 
0448     if (pos1.y()>pos2.y())
0449     {
0450         rect.setBottom(pos1.y());
0451         rect.setTop(pos2.y());
0452     }
0453     else
0454     {
0455         rect.setTop(pos1.y());
0456         rect.setBottom(pos2.y());
0457     }
0458 
0459     if (pos1.x()>pos2.x())
0460     {
0461         rect.setRight(pos1.x());
0462         rect.setLeft(pos2.x());
0463     }
0464     else
0465     {
0466         rect.setLeft(pos1.x());
0467         rect.setRight(pos2.x());
0468     }
0469 
0470 
0471     return rect;
0472 }
0473 
0474 void CMapPath::paint(QPainter *p,CMapZone *zone)
0475 {
0476     if (srcDir == UP || srcDir == DOWN || destDir == UP || destDir == DOWN || srcDir==SPECIAL || destDir==SPECIAL) return;
0477 
0478     CMapElement::paint(p,zone);
0479 }
0480 
0481 void CMapPath::resizePaint(QPoint,QPainter *,CMapZone *,int)
0482 {
0483 }
0484 
0485 void CMapPath::editPaint(QPoint pos,QPainter *p,CMapZone *zone,int editBox)
0486 {   
0487     if (srcDir == UP || srcDir == DOWN || destDir == UP || destDir == DOWN || srcDir==SPECIAL || destDir==SPECIAL) return;  
0488 
0489     setDone(false);
0490     drawPath(p,zone,QPoint (0,0),getManager()->getMapData()->defaultPathColor,editBox,pos);
0491 }
0492 
0493 
0494 void CMapPath::dragPaint(QPoint offset,QPainter *p,CMapZone *zone)
0495 {
0496     if (srcDir == UP || srcDir == DOWN || destDir == UP || destDir == DOWN || srcDir==SPECIAL || destDir==SPECIAL) return;
0497 
0498     if (getSrcRoom()->getSelected() && getDestRoom()->getSelected())
0499     {
0500         drawPath(p,zone,offset,getManager()->getMapData()->defaultPathColor);
0501     }
0502 }
0503 
0504 void CMapPath::lowerPaint(QPainter *p,CMapZone *zone)
0505 {
0506     if (srcDir == UP || srcDir == DOWN || destDir == UP || destDir == DOWN || srcDir==SPECIAL || destDir==SPECIAL) return;
0507 
0508     // Get start and end points of the path
0509     drawPath(p,zone,QPoint(-5,-5),getManager()->getMapData()->lowerPathColor);
0510 }
0511 
0512 void CMapPath::higherPaint(QPainter *p,CMapZone *zone)
0513 {
0514     if (srcDir == UP || srcDir == DOWN || destDir == UP || destDir == DOWN || srcDir==SPECIAL || destDir==SPECIAL) return;
0515 
0516     // Get start and end points of the path
0517     drawPath(p,zone,QPoint(5,5),getManager()->getMapData()->higherPathColor);
0518 }
0519 
0520 /** Used to create a deep copy of the path */
0521 CMapElement *CMapPath::copy(void)
0522 {
0523     CMapPath *path = new CMapPath(getManager(),getSrcRoom(),getSrcDir(),getDestRoom(),getDestDir(),getOpsitePath());
0524 
0525     path->setAfterCommand(getAfterCommand());
0526     path->setBeforeCommand(getBeforeCommand());
0527     path->setSpecialCmd(getSpecialCmd());
0528     path->setSpecialExit(getSpecialExit());
0529 
0530     for( PointList::Iterator bend = bendList.begin(); bend != bendList.end(); ++bend )
0531     {
0532         path->addBend(*bend);
0533     }
0534 
0535     return path;
0536 }
0537 
0538 /** Used to add a bend to the path */
0539 int CMapPath::addBend(QPoint pos)
0540 {
0541     if (bendList.contains(pos))
0542         return -1;
0543 
0544     if (bendList.count()==0)
0545     {
0546         bendList.append(pos);
0547         return bendList.count()-1;
0548     }
0549     else
0550     {
0551         int x1 = getX();
0552         int y1 = getY();
0553         int x2 = getHighX();
0554         int y2 = getHighY();
0555 
0556         QPoint pos1 = getIndent(getSrcDir(),QPoint (x1,y1));
0557 
0558         x1=pos1.x(),y1=pos1.y();
0559         int count = 0;
0560 
0561         for( PointList::Iterator point = bendList.begin(); point != bendList.end(); ++point )
0562         {
0563             x2 = (*point).x();
0564             y2 = (*point).y();
0565             if (x1 == x2)
0566             {
0567                 x1-=3;
0568                 x2+=3;
0569             }
0570 
0571             if (y1 == y2)           
0572             {
0573                 y1-=3;
0574                 y2+=3;
0575             }
0576 
0577             int x1_1 = x1 < x2 ? x1 : x2;
0578             int y1_1 = y1 < y2 ? y1 : y2;
0579             int x2_1 = x1 >= x2 ? x1 : x2;
0580             int y2_1 = y1 >= y2 ? y1 : y2;
0581 
0582             QRegion r(x1_1,y1_1,x2_1-x1_1,y2_1-y1_1);
0583 
0584             if (r.contains(pos))
0585             {
0586                 bendList.insert(count, pos);
0587                 return count;
0588             }
0589             x1 = (*point).x();
0590             y1 = (*point).y();
0591             count++;
0592         }
0593         bendList.append(pos);
0594         return bendList.count()-1;
0595     }
0596 }
0597 
0598 /** Used to add a bend to the path */
0599 void CMapPath::addBendWithUndo(QPoint pos)
0600 {
0601     if (bendList.contains(pos))
0602         return;
0603 
0604     CMapCmdElementProperties *cmdAddBend = new CMapCmdElementProperties(getManager(),i18n("Add Bend"),this);
0605     cmdAddBend->getNewProperties().writeEntry("AddBend",pos);
0606     cmdAddBend->getOrgProperties().writeEntry("DelBend",pos);
0607     getManager()->addCommand(cmdAddBend);
0608 }
0609 
0610 /** Used to move a bend to a new position */
0611 void CMapPath::moveBendWithUndo(int bend, QPoint pos)
0612 {
0613     if (bend>0 && bend-1 < (int)bendList.count())
0614     {
0615         QPoint oldPos = bendList.at(bend-1);
0616         CMapCmdElementProperties *cmdMoveBend = new CMapCmdElementProperties(getManager(),i18n("Move Bend"),this);
0617         cmdMoveBend->getNewProperties().writeEntry("MoveBendPos",pos);
0618         cmdMoveBend->getNewProperties().writeEntry("MoveBendBend",bend);
0619         cmdMoveBend->getOrgProperties().writeEntry("MoveBendPos",oldPos);   
0620         cmdMoveBend->getOrgProperties().writeEntry("MoveBendBend",bend);
0621         getManager()->addCommand(cmdMoveBend);
0622     }
0623 }
0624 
0625 /** This method is used to delete bends from a path
0626   * @param seg The path segment number to delete */
0627 void CMapPath::deletePathSegWithUndo(int seg)
0628 {
0629     QPoint bend = deletePathSeg(seg);
0630 
0631     CMapCmdElementProperties *cmdDeleteBend = new CMapCmdElementProperties(getManager(),i18n("Delete Path Segment"),this);
0632     cmdDeleteBend->getNewProperties().writeEntry("DelBend",bend);
0633     cmdDeleteBend->getOrgProperties().writeEntry("AddBend",bend);
0634     getManager()->addCommand(cmdDeleteBend);
0635 }
0636 
0637 void CMapPath::deleteBend(QPoint bend)
0638 {
0639     bendList.removeAll(bend);
0640 }
0641 
0642 /** Used to load the properties of the element from a list of properties */
0643 void CMapPath::loadProperties(KConfigGroup grp)
0644 {
0645     CMapElement::loadProperties(grp);
0646 
0647     setAfterCommand(grp.readEntry("SrcAfterCommand",getAfterCommand()));
0648     setBeforeCommand(grp.readEntry("SrcBeforeCommand",getBeforeCommand()));
0649     setSpecialCmd(grp.readEntry("SpecialCmdSrc",getSpecialCmd()));
0650     setSpecialExit(grp.readEntry("SpecialExit",getSpecialExit()));
0651     setSrcDir((directionTyp)grp.readEntry("SrcDir",(int)getSrcDir()));
0652     setDestDir((directionTyp)grp.readEntry("DestDir",(int)getDestDir()));
0653     setCords();
0654 
0655         if (grp.readEntry("PathTwoWay", getOpsitePath() != nullptr))
0656           makeTwoWay();
0657         else
0658           makeOneWay();
0659 
0660         CMapPath *opposite = getOpsitePath();
0661     if (opposite)
0662     {
0663         opposite->setAfterCommand(grp.readEntry("DestAfterCommand",opposite->getAfterCommand()));
0664         opposite->setBeforeCommand(grp.readEntry("DestBeforeCommand",opposite->getBeforeCommand()));
0665         opposite->setSrcDir((directionTyp)grp.readEntry("DestDir",(int)opposite->getSrcDir()));
0666         opposite->setDestDir((directionTyp)grp.readEntry("SrcDir",(int)opposite->getDestDir()));
0667         opposite->setSpecialCmd(grp.readEntry("SpecialCmdDest",opposite->getSpecialCmd()));
0668         opposite->setSpecialExit(grp.readEntry("SpecialExit",opposite->getSpecialExit()));
0669         opposite->setCords();
0670     }
0671 
0672     if (grp.hasKey("AddBend"))
0673     {
0674         QPoint bend(0,0);
0675         bend = grp.readEntry("AddBend",bend);
0676         addBend(bend);
0677     }
0678 
0679     if (grp.hasKey("DelBend"))
0680     {
0681         QPoint bend(0,0);
0682         bend = grp.readEntry("DelBend",bend);
0683         deleteBend(bend);
0684     }
0685 
0686     if (grp.hasKey("MoveBendBend"))
0687     {
0688         QPoint pos(0,0);
0689         pos = grp.readEntry("MoveBendPos",pos);
0690         int bend = grp.readEntry("MoveBendBend",-1);
0691         moveBend(bend,pos);
0692     }
0693 
0694     if (grp.hasKey("DeletePathSeg"))
0695     {
0696         int seg = grp.readEntry("DeletePathSeg", 0);
0697         deletePathSeg(seg);
0698     }
0699 }
0700 
0701 /** Used to save the properties of the element to a list of properties */
0702 void CMapPath::saveProperties(KConfigGroup grp)
0703 {
0704     // FIXME_jp : Make sure twoway paths are handled correctly
0705     CMapElement::saveProperties(grp);
0706 
0707     grp.writeEntry("SrcAfterCommand",getAfterCommand());
0708     grp.writeEntry("SrcBeforeCommand",getBeforeCommand());
0709     grp.writeEntry("SpecialCmdSrc",getSpecialCmd());
0710     grp.writeEntry("SpecialExit",getSpecialExit());
0711     grp.writeEntry("SrcDir",(int)getSrcDir());
0712     grp.writeEntry("DestDir",(int)getDestDir());    
0713     grp.writeEntry("SrcRoom",getSrcRoom()->getRoomID());
0714     grp.writeEntry("SrcZone",getSrcRoom()->getZone()->getZoneID());
0715     grp.writeEntry("SrcLevel",getSrcRoom()->getLevel()->getLevelID());
0716     grp.writeEntry("DestRoom",getDestRoom()->getRoomID());
0717     grp.writeEntry("DestZone",getDestRoom()->getZone()->getZoneID());
0718     grp.writeEntry("DestLevel",getDestRoom()->getLevel()->getLevelID());
0719 
0720     if (getOpsitePath())
0721     {
0722         grp.writeEntry("PathTwoWay",true);
0723         grp.writeEntry("DestAfterCommand",getOpsitePath()->getAfterCommand());
0724         grp.writeEntry("DestBeforeCommand",getOpsitePath()->getBeforeCommand());
0725         grp.writeEntry("SpecialCmdDest",getOpsitePath()->getSpecialCmd());
0726     }
0727     else
0728     {
0729         grp.writeEntry("PathTwoWay",false);
0730     }
0731 }
0732 
0733 /** Used to save the element as an XML object
0734   * @param properties The XML object to save the properties too 
0735   * @param doc The XML Document */  
0736 void CMapPath::saveQDomElement(QDomDocument *doc,QDomElement *properties)
0737 {
0738     CMapElement::saveQDomElement(doc,properties);
0739 
0740     properties->setAttribute("AfterCommand",getAfterCommand());
0741     properties->setAttribute("BeforeCommand",getBeforeCommand());
0742     properties->setAttribute("SpecialCmd",getSpecialCmd());
0743     writeBool(properties,"SpecialExit",getSpecialExit());
0744     writeInt(doc,properties,"SrcDir",(int)getSrcDir());
0745     writeInt(doc,properties,"DestDir",(int)getDestDir());
0746     writeInt(doc,properties,"SrcRoom",getSrcRoom()->getRoomID());
0747     writeInt(doc,properties,"SrcZone",getSrcRoom()->getZone()->getZoneID());
0748     writeInt(doc,properties,"SrcLevel",getSrcRoom()->getLevel()->getLevelID());
0749     writeInt(doc,properties,"DestRoom",getDestRoom()->getRoomID());
0750     writeInt(doc,properties,"DestZone",getDestRoom()->getZone()->getZoneID());
0751     writeInt(doc,properties,"DestLevel",getDestRoom()->getLevel()->getLevelID());
0752 
0753     QDomElement bendsNode = doc->createElement ("bends");
0754     properties->appendChild(bendsNode);
0755 
0756     for( PointList::Iterator bend = bendList.begin(); bend != bendList.end(); ++bend )
0757     {
0758         QDomElement bendNode = doc->createElement ("bend");
0759        
0760         writeInt(doc,&bendNode,"X",(*bend).x());
0761         writeInt(doc,&bendNode,"Y",(*bend).y());        
0762         bendsNode.appendChild(bendNode);
0763     }
0764 }
0765 
0766 /** Used to load the properties from a XML object
0767   * @param properties The XML object to load the properties from */
0768 void CMapPath::loadQDomElement(QDomElement *properties)
0769 {
0770     CMapElement::loadQDomElement(properties);
0771     setAfterCommand(properties->attribute("AfterCommand",getAfterCommand()));
0772     setBeforeCommand(properties->attribute("BeforeCommand",getAfterCommand()));
0773     setSpecialCmd(properties->attribute("SpecialCmd",getSpecialCmd()));
0774     setSpecialExit(readBool(properties,"SpecialExit",getSpecialExit()));
0775 
0776     QDomNode n = properties->namedItem("bends");
0777     if (!n.isNull())
0778     {
0779         QDomElement bendsNode = n.toElement();
0780         if (!bendsNode.isNull() )
0781         {
0782             QDomNode n1 = bendsNode.firstChild();
0783             while (!n1.isNull() )
0784             {
0785                 QDomElement bendNode = n1.toElement();
0786 
0787                 if (!bendNode.isNull() )
0788                 {
0789                     int x=readInt(&bendNode,"X",-1);
0790                     int y=readInt(&bendNode,"X",-1);
0791 
0792                     if (x!=-1 && y!=-1)
0793                     {
0794                         addBend(QPoint(x,y));
0795                     }
0796                 }
0797 
0798                 n1 = n1.nextSibling();
0799             }
0800         }
0801     }
0802 
0803     //TODO_jp : write path bends
0804 
0805 }
0806 
0807 void CMapPath::moveBy(QPoint offset)
0808 {
0809     if (getSrcRoom()->getSelected() && getDestRoom()->getSelected())
0810     {
0811         
0812         for( PointList::Iterator point = bendList.begin(); point != bendList.end(); ++point )
0813         {
0814             (*point)+=offset;
0815         }
0816     }
0817 }
0818 
0819 /** This method is used to calculate the positions of the resize handles */
0820 void CMapPath::generateResizePositions(void)
0821 {
0822     resizePos.clear();
0823     resizePos.append(QRect(tempPathCords.first().x()-3,tempPathCords.first().y()-3,7,7));
0824     resizePos.append(QRect(tempPathCords.last().x()-3,tempPathCords.last().y()-3,7,7));
0825 
0826 }
0827 
0828 /** Used to find out if the mouse is in the resize box
0829   * @param mousePos The position of the mouse pointer
0830   * @param currentZone A pointer to the current zone
0831   * @return the ID of the resize box, or 0 if not in any */
0832 int CMapPath::mouseInResize(QPoint ,CMapZone *)
0833 {
0834     return 0;
0835 }
0836 
0837 /** Used to find out if the mosuse is in the edit box of the path
0838   * @param mousePos The position of the mouse pointer
0839   * @param currentZone A pointer to the current zone
0840   * @return the ID of the edit box, or 0 if not in any */
0841 int CMapPath::mouseInEditBox(QPoint mousePos ,CMapZone *)
0842 {
0843     if (getEditMode())
0844     {
0845         int count = 1;
0846         for( PointList::Iterator point = bendList.begin(); point != bendList.end(); ++point )
0847         {
0848             QRegion r((*point).x()-3,(*point).y()-3,6,6);
0849             if (r.contains(mousePos))
0850             {
0851                 return count;
0852             }
0853             count ++;
0854         }
0855     }
0856 
0857     return 0;
0858 }
0859 
0860 /** Used to move a bend to a new position */
0861 void CMapPath::moveBend(int bend, QPoint pos)
0862 {
0863     if (bend>0 && bend-1 < (int)bendList.count())
0864     {
0865         bendList.replace(bend-1, pos);
0866         getManager()->changedElement(this);
0867     }
0868 }
0869 
0870 /** This method is used to delete bends from a path
0871   * @param seg The path segment number to delete */
0872 QPoint CMapPath::deletePathSeg(int seg)
0873 {   
0874   QPoint deletedPos;
0875 
0876   for( PointList::Iterator point = bendList.begin(); point != bendList.end(); ++point )
0877   {
0878     kDebug() << "Bend : " << (*point).x() << "," << (*point).y();   
0879   }
0880 
0881   if (seg > (int) bendList.count()) seg = bendList.count();
0882   deletedPos = bendList.at(seg - 1);
0883   return deletedPos;
0884 }
0885 
0886 /**
0887  * This method is used to find out if the mouse pointer is in a path segment.
0888  * @param mousePos The position of the mouse
0889  * @param currentZone The current zone being viewed
0890  * @return 0 if not in any segament, otherwise return the number of the segment
0891  */
0892 int CMapPath::mouseInPathSeg(QPoint mousePos,CMapZone *currentZone)
0893 {
0894     // Is this a inter zone path
0895     if (getSrcRoom()->getZone()!=currentZone || getDestRoom()->getZone()!=currentZone)
0896         return -1;
0897 
0898     if (bendList.count()==0)
0899         return -1;
0900 
0901     int count = 0;
0902     int x1=tempPathCords.first().x(),y1=tempPathCords.first().y(),x2,y2;
0903 
0904     for( PointList::Iterator point = tempPathCords.begin(); point != tempPathCords.end(); ++point )
0905     {
0906         x2 = (*point).x();
0907         y2 = (*point).y();
0908 
0909         if (count > 1 && count < (int)tempPathCords.count()-1)
0910         {
0911             int startx = x1-5;
0912             int endx = x2+5;
0913             int starty = y1-5;
0914             int endy = y2+5;
0915     
0916             QRegion r(startx,starty,endx-startx,endy-starty);
0917 
0918             if (r.contains(mousePos))
0919             {
0920 
0921                 int d = getDistance (mousePos.x(),mousePos.y(),startx,endx,starty,endy);
0922 
0923                 if (d<=5)
0924                 {
0925                     return count -1;
0926                 }
0927             }
0928         }
0929 
0930         count++;
0931 
0932         x1 = x2;
0933         y1 = y2;
0934     }
0935 
0936     return -1;
0937 }