]> git.sven.stormbind.net Git - sven/vym.git/blob - mapeditor.cpp
8f6491074e08477d3ce5072518d825312d64cccd
[sven/vym.git] / mapeditor.cpp
1 #include "mapeditor.h"
2
3 #include <QGraphicsProxyWidget>
4 #include <QMenuBar>
5 #include <QObject>
6 #include <QPrinter>
7 #include <QPrintDialog>
8 #include <QScrollBar>
9
10 #include "branchitem.h"
11 #include "geometry.h"
12 #include "mainwindow.h"
13 #include "misc.h"
14 #include "shortcuts.h"
15 #include "warningdialog.h"
16 #include "xlinkitem.h"
17
18
19 extern Main *mainWindow;
20 extern QString tmpVymDir;
21 extern QString clipboardDir;
22 extern QString clipboardFile;
23 extern bool clipboardEmpty;
24 extern bool debug;
25 extern QPrinter *printer;
26
27 extern QMenu* branchContextMenu;
28 extern QMenu* canvasContextMenu;
29 extern QMenu* floatimageContextMenu;
30 extern QMenu* taskContextMenu;
31
32 extern Switchboard switchboard;
33 extern Settings settings;
34
35 extern QTextStream vout;
36
37 ///////////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////////
39 MapEditor::MapEditor( VymModel *vm)     
40 {
41     //qDebug() << "Constructor ME "<<this;
42
43     QString shortcutScope = tr("Map Editor","Shortcut scope");
44     mapScene= new QGraphicsScene(NULL);
45     mapScene->setBackgroundBrush (QBrush(Qt::white, Qt::SolidPattern));
46
47     zoomFactor=zoomFactorTarget=1;
48     angle=angleTarget=0;
49
50     model=vm;
51     model->registerEditor(this);
52     model->makeDefault();   // No changes in model so far
53
54     setScene (mapScene);
55
56     // Create bitmap cursors, platform dependant
57     HandOpenCursor=QCursor (QPixmap(":/cursorhandopen.png"),1,1);       
58     PickColorCursor=QCursor ( QPixmap(":/cursorcolorpicker.png"), 5,27 ); 
59     CopyCursor=QCursor ( QPixmap(":/cursorcopy.png"), 1,1 ); 
60     XLinkCursor=QCursor ( QPixmap(":/cursorxlink.png"), 1,7 ); 
61
62     editingBO=NULL;
63
64     printFrame=true;
65     printFooter=true;
66
67     setAcceptDrops (true);  
68
69     // Shortcuts and actions
70     QAction *a;
71
72     a = new QAction("Select upper branch", this);
73     a->setShortcut (Qt::Key_Up );
74     a->setShortcutContext (Qt::WidgetShortcut);
75     connect( a, SIGNAL( triggered() ), this, SLOT( cursorUp() ) );
76     addAction (a);
77
78     a = new QAction( "Select lower branch",this);
79     a->setShortcut ( Qt::Key_Down );
80     a->setShortcutContext (Qt::WidgetShortcut);
81     addAction (a);
82     connect( a, SIGNAL( triggered() ), this, SLOT( cursorDown() ) );
83
84     a = new QAction( "Select left branch", this);
85     a->setShortcut (Qt::Key_Left );
86 //  a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
87     addAction (a);
88     connect( a, SIGNAL( triggered() ), this, SLOT( cursorLeft() ) );
89
90     a = new QAction( "Select child branch", this);
91     a->setShortcut (Qt::Key_Right);
92 //  a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
93     addAction (a);
94     connect( a, SIGNAL( triggered() ), this, SLOT( cursorRight() ) );
95
96     a = new QAction(  "Select first branch", this);
97     a->setShortcut (Qt::Key_Home );
98     a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
99     addAction (a);
100     connect( a, SIGNAL( triggered() ), this, SLOT( cursorFirst() ) );
101
102     a = new QAction( "Select last branch",this);
103     a->setShortcut ( Qt::Key_End );
104     a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
105     addAction (a);
106     connect( a, SIGNAL( triggered() ), this, SLOT( cursorLast() ) );
107
108     // Action to embed LineEdit for heading in Scene
109     lineEdit=NULL;
110
111     a = new QAction( tr( "Edit heading","MapEditor" ), this);
112     a->setShortcut ( Qt::Key_Return );                  //Edit heading
113     a->setShortcutContext (Qt::WidgetShortcut);
114     addAction (a);
115     connect( a, SIGNAL( triggered() ), this, SLOT( editHeading() ) );
116     a = new QAction( tr( "Edit heading","MapEditor" ), this);
117     a->setShortcut ( Qt::Key_Enter);                    //Edit heading
118     a->setShortcutContext (Qt::WidgetShortcut);
119     addAction (a);
120     connect( a, SIGNAL( triggered() ), this, SLOT( editHeading() ) );
121
122     // Selections
123     selectionColor =QColor (255,255,0);
124     
125     // Panning 
126     panningTimer=new QTimer (this);
127     vPan=QPointF();
128     connect (panningTimer, SIGNAL (timeout()), this, SLOT (panView() ));
129
130     // Clone actions defined in MainWindow
131     foreach (QAction* qa, mainWindow->mapEditorActions)
132     {
133         a = new QAction( this );
134         a->setShortcut( qa->shortcut() );
135         a->setShortcutContext( qa->shortcutContext() );
136         connect( a, SIGNAL( triggered() ), qa, SLOT( trigger() ) );
137         addAction(a);
138     }
139
140     setState (Neutral);
141
142     // Attributes   //TODO  testing only...
143     QString k;
144     AttributeDef *ad;
145     attrTable= new AttributeTable();
146     k="A - StringList";
147     ad=attrTable->addKey (k,StringList);
148     if (ad)
149     {
150         QStringList sl;
151         sl <<"val 1"<<"val 2"<< "val 3";
152         ad->setValue (QVariant (sl));
153     }
154     //attrTable->addValue ("Key A","P 1");
155     //attrTable->addValue ("Key A","P 2");
156     //attrTable->addValue ("Key A","P 3");
157     //attrTable->addValue ("Key A","P 4");
158     k="B - FreeString";
159     ad=attrTable->addKey (k,FreeString);
160     if (ad)
161     {
162         //attrTable->addValue ("Key B","w1");
163         //attrTable->addValue ("Key B","w2");
164     }
165     k="C - UniqueString";
166     ad=attrTable->addKey (k,UniqueString);
167     if (ad)
168     {
169     //attrTable->addKey ("Key Prio");
170     //attrTable->addValue ("Key Prio","Prio 1");
171     //attrTable->addValue ("Key Prio","Prio 2");
172     }
173
174     winter=NULL;
175 }
176
177 MapEditor::~MapEditor()
178 {
179     //qDebug ()<<"Destr MapEditor this="<<this;
180 }
181
182 VymModel* MapEditor::getModel()
183 {
184     return model;
185 }
186
187 QGraphicsScene * MapEditor::getScene()
188 {
189     return mapScene;
190 }
191
192 void MapEditor::panView()
193 {
194     if (!vPan.isNull() ) 
195     {
196         // Scroll if needed
197         // To avoid jumping of the sceneView, only 
198         // show selection, if not tmp linked
199         qreal px=0;
200         qreal py=0;
201         if (vPan.x()<0) 
202             px=vPan.x();
203         else if (vPan.x()>0 )
204             px=width()+vPan.x();
205         if (vPan.y()<0) 
206             py=vPan.y();
207         else if (vPan.y()>0 ) 
208             py=height()+vPan.y();
209
210         QPointF q=mapToScene (QPoint(px,py));
211         QRectF r=QRectF (q,QPointF (q.x()+1,q.y()+1));
212
213         // Expand view if necessary
214         setScrollBarPosTarget (r);
215
216         // Stop possible other animations
217         if (scrollBarPosAnimation.state()==QAbstractAnimation::Running)
218             scrollBarPosAnimation.stop();
219
220         // Do linear animation
221         horizontalScrollBar()->setValue(horizontalScrollBar()->value() + vPan.x() );
222         verticalScrollBar()->setValue  (  verticalScrollBar()->value() + vPan.y() );
223
224         // Update currently moving object
225         moveObject ();
226     }
227 }
228
229 void MapEditor::scrollTo (const QModelIndex &index) 
230 {
231     if (index.isValid())
232     {
233         LinkableMapObj* lmo=NULL;
234         TreeItem *ti= static_cast<TreeItem*>(index.internalPointer());
235         if (ti->getType()==TreeItem::Image ||ti->isBranchLikeType() )
236             lmo=((MapItem*)ti)->getLMO();
237         if (lmo) 
238         {
239             QRectF r=lmo->getBBox();
240             setScrollBarPosTarget (r);
241             animateScrollBars();
242         }   
243     }
244 }
245
246 void MapEditor::setScrollBarPosTarget (QRectF rect)
247 {
248     // Expand viewport, if rect is not contained
249     if (!sceneRect().contains (rect) )
250         setSceneRect(sceneRect().united (rect));
251
252     int xmargin=0;
253     int ymargin=0;
254
255     // Prepare scrolling
256     qreal width = viewport()->width();
257     qreal height = viewport()->height();
258     QRectF viewRect = matrix().mapRect(rect);
259
260     qreal left = horizontalScrollBar()->value();
261     qreal right = left + width;
262     qreal top = verticalScrollBar()->value();
263     qreal bottom = top + height;
264
265     scrollBarPosTarget=getScrollBarPos();
266
267     if (viewRect.left() <= left + xmargin) {
268         // need to scroll from the left
269         scrollBarPosTarget.setX(int(viewRect.left() - xmargin - 0.5));
270     }
271     if (viewRect.right() >= right - xmargin) {
272         // need to scroll from the right
273         scrollBarPosTarget.setX(int(viewRect.right() - width + xmargin + 0.5));
274     }
275     if (viewRect.top() <= top + ymargin) {
276         // need to scroll from the top
277         scrollBarPosTarget.setY(int(viewRect.top() - ymargin - 0.5));
278     }
279     if (viewRect.bottom() >= bottom - ymargin) {
280         // need to scroll from the bottom
281         scrollBarPosTarget.setY(int(viewRect.bottom() - height + ymargin + 0.5));
282     }
283
284 }
285
286 QPointF MapEditor::getScrollBarPosTarget()
287 {
288     return scrollBarPosTarget;
289 }
290
291
292 void MapEditor::setScrollBarPos(const QPointF &p)
293 {
294     scrollBarPos=p;
295     horizontalScrollBar()->setValue(int(p.x()));
296     verticalScrollBar()->setValue(int(p.y()));
297 }
298
299 QPointF MapEditor::getScrollBarPos()
300 {
301     return QPointF (horizontalScrollBar()->value(),verticalScrollBar()->value());
302     //return scrollBarPos;
303 }
304
305 void MapEditor::animateScrollBars()
306 {
307     if (scrollBarPosAnimation.state()==QAbstractAnimation::Running)
308         scrollBarPosAnimation.stop();
309     
310     if (settings.value ("/animation/use/",true).toBool() )
311     {
312         scrollBarPosAnimation.setTargetObject (this);
313         scrollBarPosAnimation.setPropertyName ("scrollBarPos");
314         scrollBarPosAnimation.setDuration(settings.value("/animation/duration/scrollbar",2000).toInt() );
315         scrollBarPosAnimation.setEasingCurve ( QEasingCurve::OutQuint);
316         scrollBarPosAnimation.setStartValue(
317             QPointF (horizontalScrollBar()->value() ,
318                      verticalScrollBar()->value() ) );
319         scrollBarPosAnimation.setEndValue(scrollBarPosTarget);
320         scrollBarPosAnimation.start();
321     } else
322         setScrollBarPos (scrollBarPosTarget);
323 }
324
325 void MapEditor::setZoomFactorTarget (const qreal &zft)
326 {
327     zoomFactorTarget=zft;
328     if (zoomAnimation.state()==QAbstractAnimation::Running)
329         zoomAnimation.stop();
330     if (settings.value ("/animation/use/",true).toBool() )
331     {
332         zoomAnimation.setTargetObject (this);
333         zoomAnimation.setPropertyName ("zoomFactor");
334         zoomAnimation.setDuration(settings.value("/animation/duration/zoom",2000).toInt() );
335         zoomAnimation.setEasingCurve ( QEasingCurve::OutQuint);
336         zoomAnimation.setStartValue(zoomFactor);
337         zoomAnimation.setEndValue(zft);
338         zoomAnimation.start();
339     } else
340         setZoomFactor (zft);
341 }
342
343 qreal MapEditor::getZoomFactorTarget()
344 {
345     return zoomFactorTarget;
346 }
347
348
349 void MapEditor::setZoomFactor(const qreal &zf)
350 {
351     zoomFactor=zf;
352     updateMatrix();
353 }
354
355 qreal MapEditor::getZoomFactor()
356 {
357     return zoomFactor;
358 }
359
360 void MapEditor::setAngleTarget (const qreal &at)
361 {
362     angleTarget=at;
363     if (rotationAnimation.state()==QAbstractAnimation::Running)
364         rotationAnimation.stop();
365     if (settings.value ("/animation/use/",true).toBool() )
366     {
367         rotationAnimation.setTargetObject (this);
368         rotationAnimation.setPropertyName ("angle");
369         rotationAnimation.setDuration(settings.value("/animation/duration/rotation",2000).toInt() );
370         rotationAnimation.setEasingCurve ( QEasingCurve::OutQuint);
371         rotationAnimation.setStartValue(angle);
372         rotationAnimation.setEndValue(at);
373         rotationAnimation.start();
374     } else
375         setAngle (angleTarget);
376 }
377
378 qreal MapEditor::getAngleTarget()
379 {
380     return angleTarget;
381 }
382
383
384 void MapEditor::setAngle(const qreal &a)
385 {
386     angle=a;
387     updateMatrix();
388 }
389
390 qreal MapEditor::getAngle()
391 {
392     return angle;
393 }
394
395 void MapEditor::setViewCenterTarget (
396     const QPointF &p, 
397     const qreal &zft, 
398     const qreal &at,
399     const int duration,
400     const QEasingCurve &easingCurve)
401 {
402     viewCenterTarget=p;
403     zoomFactorTarget=zft;
404     angleTarget=at;
405
406     viewCenter=mapToScene(viewport()->geometry()).boundingRect().center();
407
408     if (viewCenterAnimation.state()==QAbstractAnimation::Running)
409         viewCenterAnimation.stop();
410     if (rotationAnimation.state()==QAbstractAnimation::Running)
411         rotationAnimation.stop();
412     if (zoomAnimation.state()==QAbstractAnimation::Running)
413         zoomAnimation.stop();
414     
415     if (settings.value ("/animation/use/",true).toBool() )
416     {
417         viewCenterAnimation.setTargetObject (this);
418         viewCenterAnimation.setPropertyName ("viewCenter");
419         viewCenterAnimation.setDuration(
420             settings.value("/animation/duration/scrollbar",duration).toInt() );
421         viewCenterAnimation.setEasingCurve (easingCurve );
422         viewCenterAnimation.setStartValue( viewCenter );
423         viewCenterAnimation.setEndValue(viewCenterTarget);
424         viewCenterAnimation.start();
425
426         rotationAnimation.setTargetObject (this);
427         rotationAnimation.setPropertyName ("angle");
428         rotationAnimation.setDuration(settings.value("/animation/duration/rotation",duration).toInt() );
429         rotationAnimation.setEasingCurve ( easingCurve );
430         rotationAnimation.setStartValue(angle);
431         rotationAnimation.setEndValue(angleTarget);
432         rotationAnimation.start();
433
434         zoomAnimation.setTargetObject (this);
435         zoomAnimation.setPropertyName ("zoomFactor");
436         zoomAnimation.setDuration(settings.value("/animation/duration/zoom",duration).toInt() );
437         zoomAnimation.setEasingCurve ( easingCurve );
438         zoomAnimation.setStartValue(zoomFactor);
439         zoomAnimation.setEndValue(zoomFactorTarget);
440         zoomAnimation.start();
441
442     } else
443     {
444         setAngle (angleTarget);
445         setZoomFactor (zft);
446         setViewCenter (viewCenterTarget);
447     }
448 }
449
450 void MapEditor::setViewCenterTarget ()
451 {
452     MapItem *selti=(MapItem*)(model->getSelectedItem() );
453     if (selti)
454     {
455         LinkableMapObj *lmo=selti->getLMO();
456         if (lmo)
457             setViewCenterTarget (lmo->getBBox().center(), 1, 0);
458     }
459 }
460
461 QPointF MapEditor::getViewCenterTarget ()
462 {
463     return viewCenterTarget;
464 }
465
466 void MapEditor::setViewCenter (const QPointF &vc)
467 {
468     centerOn (vc);
469 }
470
471 QPointF MapEditor::getViewCenter()
472 {
473     return viewCenter;
474 }
475
476 void MapEditor::updateMatrix()
477 {
478     double a    = M_PI/180 * angle;
479     double sina = sin((double)a);
480     double cosa = cos((double)a);
481
482     QMatrix zm(zoomFactor, 0, 0, zoomFactor, 0, 0);
483     //QMatrix translationMatrix(1, 0, 0, 1, 50.0, 50.0);
484     QMatrix rm(cosa, sina, -sina, cosa, 0, 0);
485     setMatrix (zm * rm);
486 }
487
488 void MapEditor::minimizeView()
489 {
490     setSceneRect( scene()->itemsBoundingRect() );
491 }
492
493 void MapEditor::print()
494 {
495     QRectF totalBBox=getTotalBBox();
496
497     // Try to set orientation automagically
498     // Note: Interpretation of generated postscript is amibiguous, if 
499     // there are problems with landscape mode, see
500     // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html
501
502     if (totalBBox.width()>totalBBox.height())
503         // recommend landscape
504         printer->setOrientation (QPrinter::Landscape);
505     else    
506         // recommend portrait
507         printer->setOrientation (QPrinter::Portrait);
508
509     QPrintDialog dialog (printer, this);
510     dialog.setWindowTitle(tr("Print vym map","MapEditor")); 
511     if (dialog.exec() == QDialog::Accepted)
512     {
513         QPainter pp(printer);
514
515         pp.setRenderHint(QPainter::Antialiasing,true);
516
517         // Don't print the visualisation of selection
518         model->unselectAll();
519
520         QRectF mapRect=totalBBox;
521         QGraphicsRectItem *frame=NULL;
522
523         if (printFrame) 
524         {
525             // Print frame around map
526             mapRect.setRect (totalBBox.x()-10, totalBBox.y()-10, 
527                 totalBBox.width()+20, totalBBox.height()+20);
528             frame=mapScene->addRect (mapRect, QPen(Qt::black),QBrush(Qt::NoBrush));
529             frame->setZValue(0);
530             frame->show();    
531         }       
532
533
534         double paperAspect = (double)printer->width()   / (double)printer->height();
535         double   mapAspect = (double)mapRect.width() / (double)mapRect.height();
536         int viewBottom;
537         if (mapAspect>=paperAspect)
538         {
539             // Fit horizontally to paper width
540             //pp.setViewport(0,0, printer->width(),(int)(printer->width()/mapAspect) ); 
541             viewBottom=(int)(printer->width()/mapAspect);   
542         }   else
543         {
544             // Fit vertically to paper height
545             //pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height()); 
546             viewBottom=printer->height();   
547         }   
548         
549         if (printFooter) 
550         {
551             // Print footer below map
552             QFont font;     
553             font.setPointSize(10);
554             pp.setFont (font);
555             QRectF footerBox(0,viewBottom,printer->width(),15);
556             pp.drawText ( footerBox,Qt::AlignLeft,"VYM - " +model->getFileName());
557             pp.drawText ( footerBox, Qt::AlignRight, QDate::currentDate().toString(Qt::TextDate));
558         }
559         mapScene->render (
560             &pp, 
561             QRectF (0,0,printer->width(),printer->height()-15),
562             QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height())
563         );
564         
565         // Viewport has paper dimension
566         if (frame)  delete (frame);
567
568         // Restore selection
569         model->reselect();
570     }
571 }
572
573 QRectF MapEditor::getTotalBBox()  
574 {                                   
575     minimizeView();
576     return sceneRect();
577 }
578
579 QImage MapEditor::getImage( QPointF &offset) 
580 {
581     QRectF mapRect = getTotalBBox();   // minimized sceneRect
582     
583     int d = 10; // border
584     offset = QPointF( mapRect.x() -d/2, mapRect.y() - d/2 );
585     QImage pix( mapRect.width() + d, mapRect.height() + d, QImage::Format_RGB32 );
586
587     QPainter pp (&pix);
588     pp.setRenderHints(renderHints());
589     mapScene->render ( &pp, 
590         // Destination:
591         QRectF( 0, 0, mapRect.width() + d, mapRect.height() + d ),   
592         // Source in scene:
593         QRectF( mapRect.x() - d/2, mapRect.y() -d/2, mapRect.width() + d, mapRect.height() + d));
594     return pix;
595 }
596
597
598 void MapEditor::setAntiAlias (bool b)
599 {
600     setRenderHint(QPainter::Antialiasing,b);
601 }
602
603 void MapEditor::setSmoothPixmap(bool b)
604 {
605     setRenderHint(QPainter::SmoothPixmapTransform,b);
606 }
607
608 void MapEditor::autoLayout()
609 {
610     // Create list with all bounding polygons
611     QList <LinkableMapObj*> mapobjects;
612     QList <ConvexPolygon> polys; 
613     ConvexPolygon p;
614     QList <Vector> vectors;
615     QList <Vector> orgpos;
616     QStringList headings;   //FIXME-3 testing only
617     Vector v;
618     BranchItem *bi;
619     BranchItem *bi2;
620     BranchObj *bo;
621
622     // Outer loop: Iterate until we no more changes in orientation 
623     bool orientationChanged=true;
624     while (orientationChanged)
625     {
626         BranchItem *ri=model->getRootItem();
627         for (int i=0;i<ri->branchCount();++i)
628         {
629             bi=ri->getBranchNum (i);
630             bo=(BranchObj*)bi->getLMO();
631             if (bo)
632             {
633                 mapobjects.append (bo);
634                 p=bo->getBoundingPolygon();
635                 p.calcCentroid();
636                 polys.append(p);
637                 vectors.append (QPointF(0,0));
638                 orgpos.append (p.at(0));
639         headings.append (bi->getHeadingPlain());
640             }
641             for (int j=0;j<bi->branchCount();++j)
642             {
643                 bi2=bi->getBranchNum (j);
644                 bo=(BranchObj*)bi2->getLMO();
645                 if (bo)
646                 {
647                     mapobjects.append (bo);
648                     p=bo->getBoundingPolygon();
649                     p.calcCentroid();
650                     polys.append(p);
651                     vectors.append (QPointF(0,0));
652                     orgpos.append (p.at(0));
653             headings.append (bi2->getHeadingPlain());
654                 }   
655             }
656         }
657
658         // Iterate moving bounding polygons until we have no more collisions
659         int collisions=1;
660         while (collisions>0)
661         {
662             collisions=0;
663             for (int i=0; i<polys.size()-1; ++i)
664             {
665                 for (int j=i+1; j<polys.size();++j)
666                 {
667                     if (polygonCollision (polys.at(i),polys.at(j), QPointF(0,0)).intersect )
668                     {
669                         collisions++;
670                         if (debug) qDebug() << "Collision: "<<headings[i]<<" - "<<headings[j];
671                         v=polys.at(j).centroid()-polys.at(i).centroid();
672                         v.normalize();
673                         // Add random direction, if only two polygons with identical y or x
674                         if (v.x()==0 || v.y()==0) 
675                         {
676                             Vector w (cos (double((int)rand()%1000)),sin(double((int)rand()%1000)));
677                             w.normalize();
678                             v=v+w;
679                         }
680                         
681                         // Scale translation vector by area of polygons
682                         vectors[j]=v*10000/polys.at(j).weight();        
683                         vectors[i]=v*10000/polys.at(i).weight();        
684                         vectors[i].invert();
685                         //FIXME-3 outer loop, "i" get's changed several times...
686                         // Better not move away from centroid of 2 colliding polys, 
687                         // but from centroid of _all_
688                     }  
689                 }
690             }
691             for (int i=0;i<vectors.size();i++)
692             {
693                 //qDebug() << " v="<<vectors[i]<<" "<<headings[i];
694                 if (!vectors[i].isNull() )
695                 polys[i].translate (vectors[i]);
696             }
697         // if (debug) qDebug()<< "Collisions total: "<<collisions;
698         // collisions=0;
699         }   
700
701         // Finally move the real objects and update 
702         QList <LinkableMapObj::Orientation> orients;
703         for (int i=0;i<polys.size();i++)
704         {
705             Vector v=polys[i].at(0)-orgpos[i];
706             orients.append (mapobjects[i]->getOrientation());
707             if (!v.isNull())
708             {
709                 if (debug) qDebug()<<" Moving "<<polys.at(i).weight()<<" "<<mapobjects[i]->getAbsPos()<<" -> "<<mapobjects[i]->getAbsPos() + v<<"  "<<headings[i];
710                 //mapobjects[i]->moveBy(v.x(),v.y() );
711                 //mapobjects[i]->setRelPos();
712                 model->startAnimation ((BranchObj*)mapobjects[i], v);
713                 if (debug) qDebug()<<i<< " Weight: "<<polys.at(i).weight()<<" "<<v<<" "<<headings.at(i);
714             }
715         }   
716         /*
717         model->reposition();    
718         orientationChanged=false;
719         for (int i=0;i<polys.size();i++)
720             if (orients[i]!=mapobjects[i]->getOrientation())
721             {
722                 orientationChanged=true;
723                 break;
724             }
725         */
726     
727         break;
728
729         //orientationChanged=false;
730     } // loop if orientation has changed
731
732     model->emitSelectionChanged();
733 }
734
735 TreeItem* MapEditor::findMapItem (QPointF p,TreeItem *exclude)
736 {
737     // Search XLinks
738     Link *link;
739     for (int i=0; i<model->xlinkCount(); i++ )
740     {
741         link=model->getXLinkNum(i);
742         if (link)
743         {
744             XLinkObj *xlo=link->getXLinkObj();
745             if (xlo && xlo->isInClickBox (p)) 
746             {
747                 // Found XLink, now return the nearest XLinkItem of p
748                 qreal d0=Geometry::distance(p, xlo->getBeginPos());
749                 qreal d1=Geometry::distance(p, xlo->getEndPos());
750                 if (d0>d1)
751                     return link->getBeginLinkItem();
752                 else
753                     return link->getEndLinkItem();
754             }
755         }
756     }
757
758     // Search branches (and their childs, e.g. images
759     // Start with mapcenter, no images allowed at rootItem
760     int i=0;
761     BranchItem *bi=model->getRootItem()->getFirstBranch();
762     TreeItem *found=NULL;
763     while (bi)
764     {
765         found=bi->findMapItem (p, exclude);
766         if (found) return found;
767         i++;
768         bi=model->getRootItem()->getBranchNum(i);
769     }
770     return NULL;
771 }
772
773 AttributeTable* MapEditor::attributeTable()
774 {
775     return attrTable;
776 }
777
778 void MapEditor::testFunction1()
779 {
780 }
781     
782 void MapEditor::testFunction2()
783 {
784     autoLayout();
785 }
786
787 #include "winter.h"
788 void MapEditor::toggleWinter()
789 {
790     if (winter)
791     {
792         delete winter;
793         winter=NULL;
794     } else
795     {
796         winter=new Winter (this);
797         QList <QRectF> obstacles;
798         BranchObj *bo;
799         BranchItem *cur=NULL;
800         BranchItem *prev=NULL;
801         model->nextBranch(cur,prev);
802         while (cur) 
803         {
804             if (!cur->hasHiddenExportParent())
805             {
806                 // Branches
807                 bo=(BranchObj*)(cur->getLMO());
808                 if (bo && bo->isVisibleObj())
809                     obstacles.append(bo->getBBox());
810             }
811             model->nextBranch(cur,prev);
812         }
813         winter->setObstacles(obstacles);
814     }
815 }
816     
817 BranchItem* MapEditor::getBranchDirectAbove (BranchItem *bi)
818 {
819     if (bi)
820     {
821         int i=bi->num();
822         if (i>0) return bi->parent()->getBranchNum(i-1);
823     }
824     return NULL;
825 }
826
827 BranchItem* MapEditor::getBranchAbove (BranchItem *selbi)
828 {
829     if (selbi)
830     {
831         int dz=selbi->depth();  // original depth
832         bool invert=false;
833         if (selbi->getLMO()->getOrientation()==LinkableMapObj::LeftOfCenter)
834             invert=true;
835
836         BranchItem *bi;
837
838         // Look for branch with same parent but directly above
839         if (dz==1 && invert)
840             bi=getBranchDirectBelow(selbi);
841         else
842             bi=getBranchDirectAbove (selbi);
843
844         if (bi) 
845             // direct predecessor
846             return bi;
847
848         // Go towards center and look for predecessor
849         while (selbi->depth()>0)
850         {
851             selbi=(BranchItem*)(selbi->parent());
852             if (selbi->depth()==1 && invert)
853                 bi=getBranchDirectBelow (selbi);
854             else
855                 bi=getBranchDirectAbove (selbi);
856             if (bi)
857             {
858                 // turn 
859                 selbi=bi;
860                 while (selbi->depth()<dz)
861                 {
862                     // try to get back to original depth dz
863                     bi=selbi->getLastBranch();
864                     if (!bi) 
865                     {
866                         return selbi;
867                     }
868                     selbi=bi;
869                 }
870                 return selbi;
871             }
872         }
873     }
874     return NULL;
875 }
876
877 BranchItem* MapEditor::getBranchDirectBelow(BranchItem *bi)
878 {
879     if (bi)
880     {
881         int i=bi->num();
882         if (i+1<bi->parent()->branchCount()) return bi->parent()->getBranchNum(i+1);
883     }
884     return NULL;
885 }
886
887 BranchItem* MapEditor::getBranchBelow (BranchItem *selbi)
888 {
889     if (selbi)
890     {
891         BranchItem *bi;
892         int dz=selbi->depth();  // original depth
893         bool invert=false;
894         if (selbi->getLMO()->getOrientation()==LinkableMapObj::LeftOfCenter)
895             invert=true;
896
897
898         // Look for branch with same parent but directly below
899         if (dz==1 && invert)
900             bi=getBranchDirectAbove (selbi);
901         else
902             bi=getBranchDirectBelow (selbi);
903         if (bi) 
904             // direct successor
905             return bi;
906
907
908         // Go towards center and look for neighbour
909         while (selbi->depth()>0)
910         {
911             selbi=(BranchItem*)(selbi->parent());
912             if (selbi->depth()==1 && invert)
913                 bi=getBranchDirectAbove (selbi);
914             else
915                 bi=getBranchDirectBelow (selbi);
916             if (bi)
917             {
918                 // turn 
919                 selbi=bi;
920                 while (selbi->depth()<dz)
921                 {
922                     // try to get back to original depth dz
923                     bi=selbi->getFirstBranch();
924                     if (!bi) 
925                     {
926                         return selbi;
927                     }
928                     selbi=bi;
929                 }
930                 return selbi;
931             }
932         }
933     }
934     return NULL;
935 }
936
937 BranchItem* MapEditor::getLeftBranch (BranchItem *bi)  
938 {
939     if (bi)
940     {
941         if (bi->depth()==0)
942         { 
943             // Special case: use alternative selection index
944             BranchItem *newbi=bi->getLastSelectedBranchAlt();  
945             if (!newbi)
946             {
947                 BranchObj *bo;
948                 // Try to find a mainbranch left of center
949                 for (int i=0; i<bi->branchCount(); i++)
950                 {
951                     newbi=bi->getBranchNum(i);
952                     bo=newbi->getBranchObj();
953                     if (bo && bo->getOrientation()==LinkableMapObj::LeftOfCenter)
954                         break;
955                 }
956             }
957             return newbi;
958         }
959         if (bi->getBranchObj()->getOrientation()==LinkableMapObj::RightOfCenter)    
960             // right of center
961             return (BranchItem*)(bi->parent());
962         else
963             // left of center
964             if (bi->getType()== TreeItem::Branch )
965                 return bi->getLastSelectedBranch();
966     }
967     return NULL;
968 }
969
970 BranchItem* MapEditor::getRightBranch(BranchItem *bi)
971 {
972     if (bi)
973     {
974         if (bi->depth()==0)
975         {
976             // Special case: use alternative selection index
977             BranchItem *newbi=bi->getLastSelectedBranch();  
978             if (!newbi)
979             {
980                 BranchObj *bo;
981                 // Try to find a mainbranch right of center
982                 for (int i=0; i<bi->branchCount(); i++)
983                 {
984                     newbi=bi->getBranchNum(i);
985                     bo=newbi->getBranchObj();
986                     if (bo && bo->getOrientation()==LinkableMapObj::RightOfCenter)
987             qDebug()<<"BI found right: "<<newbi->getHeadingPlain();
988                 }
989             }
990             return newbi;
991         }
992         if (bi->getBranchObj()->getOrientation()==LinkableMapObj::LeftOfCenter) 
993             // left of center
994             return (BranchItem*)(bi->parent());
995         else
996             // right of center
997             if (bi->getType()== TreeItem::Branch )
998                 return (BranchItem*)bi->getLastSelectedBranch();
999     }
1000     return NULL;
1001 }
1002
1003
1004
1005 void MapEditor::cursorUp()
1006 {
1007     if (state == MapEditor::EditingHeading) return;
1008
1009     BranchItem *bi=model->getSelectedBranch();
1010     if (bi) model->select (getBranchAbove(bi));
1011 }
1012
1013 void MapEditor::cursorDown()    
1014
1015 {
1016     if (state == MapEditor::EditingHeading) return;
1017
1018     BranchItem *bi=model->getSelectedBranch();
1019     if (bi) model->select (getBranchBelow(bi));
1020 }
1021
1022 void MapEditor::cursorLeft()
1023 {
1024     BranchItem *bi=getLeftBranch (model->getSelectedBranch());
1025     if (bi) model->select (bi);
1026 }
1027
1028 void MapEditor::cursorRight()   
1029 {
1030     BranchItem *bi=getRightBranch (model->getSelectedBranch());
1031     if (bi) model->select (bi);
1032 }
1033
1034 void MapEditor::cursorFirst()   
1035 {
1036     model->selectFirstBranch();
1037 }
1038
1039 void MapEditor::cursorLast()    
1040 {
1041     model->selectLastBranch();
1042 }
1043
1044
1045 void MapEditor::editHeading()
1046 {
1047     if (state==EditingHeading)
1048     {
1049         editHeadingFinished();
1050         return;
1051     }
1052
1053     BranchObj *bo=model->getSelectedBranchObj();
1054     BranchItem *bi=model->getSelectedBranch();
1055     if (bo && bo)
1056     {
1057         VymText heading = bi->getHeading();
1058         if (heading.isRichText())
1059         {
1060             mainWindow->windowShowHeadingEditor();
1061             return;
1062         }
1063         model->setSelectionBlocked(true);
1064
1065         lineEdit=new QLineEdit;
1066         QGraphicsProxyWidget *pw=mapScene->addWidget (lineEdit);
1067         pw->setZValue (Z_LINEEDIT);
1068         lineEdit->setCursor(Qt::IBeamCursor);
1069         lineEdit->setCursorPosition(1);
1070
1071         QPointF tl=bo->getOrnamentsBBox().topLeft();
1072         QPointF br=tl + QPointF (230,30);
1073         QRectF r (tl, br);
1074         lineEdit->setGeometry(r.toRect() );
1075
1076         setScrollBarPosTarget ( r );
1077         scene()->update();
1078
1079         // Set focus to MapEditor first
1080         // To avoid problems with Cursor up/down
1081         setFocus();
1082
1083         animateScrollBars();
1084         lineEdit->setText (heading.getTextASCII() );
1085         lineEdit->setFocus();
1086         lineEdit->selectAll();  // Hack to enable cursor in lineEdit
1087         lineEdit->deselect();   // probably a Qt bug...
1088         setState (EditingHeading);
1089     }
1090 }
1091
1092 void MapEditor::editHeadingFinished()
1093 {
1094     setState (Neutral);
1095     //lineEdit->releaseKeyboard();
1096     lineEdit->clearFocus();
1097     QString s=lineEdit->text();
1098     s.replace (QRegExp ("\\n")," ");    // Don't paste newline chars
1099     model->setHeadingPlainText (s);
1100     model->setSelectionBlocked(false);
1101     delete (lineEdit);
1102     lineEdit=NULL;
1103
1104     animateScrollBars();
1105
1106     // Maybe reselect previous branch 
1107     mainWindow->editHeadingFinished (model);
1108
1109     //Autolayout to avoid overlapping branches with longer headings
1110     if (settings.value("/mainwindow/autoLayout/use","true")=="true")
1111         autoLayout();
1112 }
1113
1114
1115 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
1116 {
1117     // Lineedits are already closed by preceding
1118     // mouseEvent, we don't need to close here.
1119
1120     QPointF p = mapToScene(e->pos());
1121     TreeItem *ti=findMapItem (p, NULL); 
1122     
1123     if (ti) 
1124     {   // MapObj was found
1125         model->select (ti);
1126
1127         LinkableMapObj* lmo=NULL;
1128         BranchItem* selbi=model->getSelectedBranch();
1129         if (ti) lmo=((MapItem*)ti)->getLMO();
1130
1131         // Context Menu 
1132         if (lmo && selbi )
1133         {
1134             QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
1135             if (foname.startsWith ("system-task")) 
1136                 taskContextMenu->popup (e->globalPos() );
1137             else        
1138                 // Context Menu on branch or mapcenter
1139                 branchContextMenu->popup(e->globalPos() );
1140         } else
1141         {
1142             if (model->getSelectedImage() )
1143             {
1144                 // Context Menu on floatimage
1145                 floatimageContextMenu->popup(e->globalPos() );
1146             } else
1147             {
1148                 if (model->getSelectedXLink() )
1149                     // Context Menu on XLink
1150                     model->editXLink();
1151             }
1152         }   
1153     } else 
1154     { // No MapObj found, we are on the Canvas itself
1155         // Context Menu on scene
1156         
1157         // Open context menu synchronously to position new mapcenter
1158         model->setContextPos (p);
1159         canvasContextMenu->exec(e->globalPos() );
1160         model->unsetContextPos ();
1161     } 
1162     e->accept();
1163 }
1164
1165 void MapEditor::keyPressEvent(QKeyEvent* e)
1166 {
1167     if (e->key()==Qt::Key_PageUp || e->key()==Qt::Key_PageDown)
1168         // Ignore PageUP/Down to avoid scrolling with keys
1169         return;
1170
1171     if (e->modifiers() & Qt::ShiftModifier)
1172     {
1173         switch (mainWindow->getModMode())
1174         {
1175             case Main::ModModeColor: 
1176                 setCursor (PickColorCursor);
1177                 break;
1178             case Main::ModModeCopy: 
1179                 setCursor (CopyCursor);
1180                 break;
1181             case Main::ModModeXLink: 
1182                 setCursor (XLinkCursor);
1183                 break;
1184             default :
1185                 setCursor (Qt::ArrowCursor);
1186                 break;
1187         } 
1188     }   
1189     QGraphicsView::keyPressEvent(e); 
1190 }
1191
1192 void MapEditor::keyReleaseEvent(QKeyEvent* e)
1193 {
1194     if (!(e->modifiers() & Qt::ControlModifier))
1195         setCursor (Qt::ArrowCursor);
1196 }
1197
1198 void MapEditor::mousePressEvent(QMouseEvent* e) 
1199 {
1200     // Ignore right clicks or wile editing heading
1201     if (e->button() == Qt::RightButton || model->isSelectionBlocked() )
1202     {
1203         e->ignore();
1204         QGraphicsView::mousePressEvent(e);
1205         return;
1206     }
1207
1208     // Check if we need to reset zoomFactor
1209     if (e->button() == Qt::MidButton && e->modifiers() & Qt::ControlModifier )
1210     {
1211         setZoomFactorTarget (1);
1212         setAngleTarget (0);
1213         return;
1214     }
1215
1216     QPointF p = mapToScene(e->pos());
1217     TreeItem *ti=findMapItem (p, NULL);
1218     LinkableMapObj* lmo=NULL;
1219     if (ti) lmo=((MapItem*)ti)->getLMO();
1220
1221     QString sysFlagName;
1222     if (lmo) sysFlagName=((BranchObj*)lmo)->getSystemFlagName(p);
1223     
1224     /*
1225     qDebug() << "ME::mouse pressed\n";
1226     qDebug() << "  lmo="<<lmo;
1227     qDebug() << "   ti="<<ti;
1228     if (ti) qDebug() << "   ti="<<ti->getHeading();
1229     qDebug() << " flag="<<sysFlagName;
1230     */
1231     
1232     // Check PickColor modifier (before selecting object!) 
1233     if (ti && (e->modifiers() & Qt::ShiftModifier) &&
1234         mainWindow->getModMode()==Main::ModModeColor)
1235     {
1236         setState (PickingColor);
1237         mainWindow->setCurrentColor (ti->getHeadingColor() );
1238         if ((e->modifiers() & Qt::ShiftModifier) && (e->modifiers() & Qt::ControlModifier) )
1239             model->colorBranch(ti->getHeadingColor());
1240         else    
1241             model->colorSubtree(ti->getHeadingColor());
1242         return;
1243     }   
1244
1245     // Check vymlink  modifier (before selecting object!) 
1246     if (ti && sysFlagName=="system-vymLink")
1247     {
1248         model->select(ti);
1249         if (e->modifiers() & Qt::ControlModifier)
1250             mainWindow->editOpenVymLink(true);
1251         else
1252             mainWindow->editOpenVymLink(false);
1253         return;
1254     }
1255     
1256     // Select the clicked object 
1257     if (ti && e->modifiers() & Qt::ControlModifier)
1258         model->selectToggle (ti);
1259     else
1260         model->select (ti);
1261
1262     e->accept();
1263
1264     //Take care of  remaining system flags _or_ modifier modes
1265     if (lmo )
1266     {
1267         if (!sysFlagName.isEmpty())
1268         {
1269             // systemFlag clicked
1270             if (sysFlagName.contains("system-url")) 
1271             {
1272                 if (e->modifiers() & Qt::ControlModifier)
1273                     mainWindow->editOpenURLTab();
1274                 else    
1275                     mainWindow->editOpenURL();
1276             }   
1277             else if (sysFlagName=="system-vymLink")
1278             {
1279                 if (e->modifiers() & Qt::ControlModifier)
1280                     mainWindow->editOpenVymLink(true);
1281                 else
1282                     mainWindow->editOpenVymLink(false);
1283                 // tabWidget may change, better return now
1284                 // before segfaulting...
1285             } else if (sysFlagName=="system-note")      
1286                 mainWindow->windowToggleNoteEditor();
1287             else if (sysFlagName=="hideInExport")           
1288                 model->toggleHideExport();
1289             else if (sysFlagName.startsWith("system-task-") )
1290                 model->cycleTaskStatus();
1291             return; 
1292         } else
1293         {
1294             // Take care of xLink: Open context menu with targets
1295             // if clicked near to begin of xlink
1296             if (ti->xlinkCount()>0 && ti->getType() != TreeItem::MapCenter && lmo->getBBox().width()>30)
1297             {
1298                 if ((lmo->getOrientation()!=LinkableMapObj::RightOfCenter && p.x() < lmo->getBBox().left()+10)  ||
1299                     (lmo->getOrientation()!=LinkableMapObj::LeftOfCenter && p.x() > lmo->getBBox().right()-10) ) 
1300                 {
1301                     //FIXME-4 similar code in mainwindow::updateActions
1302                     QMenu menu;
1303                     QList <QAction*> alist;
1304                     QList <BranchItem*> blist;
1305                     for (int i=0;i<ti->xlinkCount();i++)
1306                     {
1307                         XLinkItem *xli=ti->getXLinkItemNum(i);
1308                         BranchItem *bit=xli->getPartnerBranch();
1309                         if (bit) alist.append (new QAction(ti->getXLinkItemNum(i)->getPartnerBranch()->getHeadingPlain(),&menu));
1310                     }   
1311                     menu.addActions (alist);    
1312                     QAction *ra=menu.exec (e->globalPos() );
1313                     if (ra)
1314                         model->select (blist.at( alist.indexOf(ra)));
1315                     while (!alist.isEmpty())
1316                     {
1317                         QAction *a=alist.takeFirst();
1318                         delete a;
1319                     }   
1320                     return;
1321                 }   
1322             }
1323         }
1324     }   
1325
1326     // XLink modifier, create new XLink 
1327     BranchItem* selbi = model->getSelectedBranch();
1328     if (selbi &&
1329         mainWindow->getModMode()==Main::ModModeXLink &&
1330         (e->modifiers() & Qt::ShiftModifier))
1331     {   
1332         setState (DrawingLink);
1333         tmpLink=new Link (model);
1334         tmpLink->setBeginBranch (selbi);
1335         tmpLink->createMapObj();
1336         tmpLink->setStyleBegin("None");
1337         tmpLink->setStyleEnd("None");
1338         tmpLink->setEndPoint ( mapToScene (e->pos() ) );
1339         tmpLink->updateLink();
1340         return;
1341     }
1342
1343     // Start moving around
1344     if (lmo) 
1345     {   
1346         // Left Button      Move Branches
1347         if (e->button() == Qt::LeftButton )
1348         {
1349             // No system flag clicked, take care of moving copymodes or simply moving
1350             movingObj_offset.setX( p.x() - lmo->x() );  
1351             movingObj_offset.setY( p.y() - lmo->y() );  
1352             movingObj_orgPos.setX (lmo->x() );
1353             movingObj_orgPos.setY (lmo->y() );
1354             if (ti->depth()>0)
1355             {
1356                 lmo->setRelPos();   
1357                 movingObj_orgRelPos=lmo->getRelPos();
1358             }
1359
1360             // If modMode==copy, then we want to "move" the _new_ object around
1361             // then we need the offset from p to the _old_ selection, because of tmp
1362             if (mainWindow->getModMode()==Main::ModModeCopy &&
1363                 e->modifiers() & Qt::ShiftModifier)
1364             {
1365                 if (selbi)
1366                 {
1367                     setState (CopyingObject);
1368                     model->copy();
1369                     model->paste();
1370                     model->select (selbi->getLastBranch());
1371                     model->reposition();
1372                 }
1373             } else
1374                 setState (MovingObject);
1375
1376             movingObj=model->getSelectedLMO();  
1377         } else
1378             // Middle Button    Toggle Scroll
1379             // (On Mac OS X this won't work, but we still have 
1380             // a button in the toolbar)
1381             if (e->button() == Qt::MidButton )
1382                 model->toggleScroll();
1383     } else 
1384     {   // No lmo found, check XLinks
1385         if (ti)
1386         {
1387             if (ti->getType()==TreeItem::XLink)
1388             {
1389                 XLinkObj* xlo=(XLinkObj*) ((MapItem*)ti)->getMO() ;
1390                 if (xlo)
1391                 {
1392                     setState (EditingLink);
1393                     int i=xlo->ctrlPointInClickBox(p);
1394                     if (i>=0) xlo->setSelection (i);
1395                     movingObj_offset.setX( p.x() - xlo->x() );  
1396                     movingObj_offset.setY( p.y() - xlo->y() );  
1397                     movingObj_orgPos.setX (xlo->x() );
1398                     movingObj_orgPos.setY (xlo->y() );
1399
1400                 }
1401             }
1402         }
1403         else    
1404         { // No MapObj found, we are on the scene itself
1405             // Left Button          move Pos of sceneView
1406             if (e->button() == Qt::LeftButton )
1407             {
1408                 setState (MovingView);
1409                 movingObj=NULL; // move Content not Obj
1410                 movingObj_offset=e->globalPos();
1411                 movingCont_start=QPointF (
1412                     horizontalScrollBar()->value(),
1413                     verticalScrollBar()->value());
1414                 movingVec=QPointF(0,0);
1415                 setCursor(HandOpenCursor);
1416             } 
1417         } 
1418     }
1419 }
1420
1421 void MapEditor::mouseMoveEvent(QMouseEvent* e)  
1422 {
1423     // Show mouse position for debugging in statusBar
1424     if (debug && e->modifiers() & Qt::ControlModifier )
1425         mainWindow->statusMessage(
1426             QString("ME::mousePressEvent  Scene: %1  widget: %2").
1427             arg(qpointFToString(mapToScene (e->pos()))).
1428             arg(qpointFToString(e->pos())));
1429
1430     TreeItem *seli=model->getSelectedItem();
1431
1432     MapObj* mosel=NULL;    
1433     if (seli )
1434         mosel=((MapItem*)seli)->getMO();
1435
1436     // Move the selected MapObj
1437     if ( mosel && (state==MovingObject || state==CopyingObject || state==EditingLink)) 
1438     {   
1439         int margin=50;
1440
1441         // Check if we have to scroll
1442         vPan.setX(0);
1443         vPan.setY(0);
1444         if (e->y() >=0 && e->y() <= margin)
1445             vPan.setY( e->y() - margin );
1446         else if ( e->y() <= height() && e->y() > height()-margin )
1447             vPan.setY(e->y() - height() + margin );
1448         if ( e->x() >=0 && e->x() <= margin)
1449             vPan.setX( e->x() - margin );
1450         else if ( e->x() <= width() && e->x() > width()-margin )
1451             vPan.setX(e->x() - width() + margin );
1452
1453         pointerPos=e->pos();
1454         pointerMod=e->modifiers();
1455         moveObject ();
1456     } // selection && moving_obj
1457         
1458     // Draw a link from one branch to another
1459     if (state==DrawingLink)
1460     {
1461         tmpLink->setEndPoint ( mapToScene (e->pos() ) );
1462         tmpLink->updateLink();
1463     }    
1464     
1465     // Move sceneView 
1466     if (state==MovingView && e->buttons() == Qt::LeftButton ) 
1467     {
1468         QPointF p=e->globalPos();
1469         movingVec.setX(-p.x() + movingObj_offset.x() );
1470         movingVec.setY(-p.y() + movingObj_offset.y() );
1471         horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
1472         verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
1473         scrollBarPosAnimation.stop();   // Avoid flickering
1474     }
1475 }
1476
1477 void MapEditor::moveObject ()   
1478 {
1479     if (!panningTimer->isActive() )
1480         panningTimer->start(50);
1481
1482     QPointF p = mapToScene(pointerPos);
1483     TreeItem *seli=model->getSelectedItem();
1484     LinkableMapObj* lmosel=NULL;    
1485     if (seli)
1486         lmosel=((MapItem*)seli)->getLMO();
1487
1488     objectMoved=true;
1489     // reset cursor if we are moving and don't copy
1490     if (mainWindow->getModMode()!=Main::ModModeCopy)
1491         setCursor (Qt::ArrowCursor);
1492
1493     // Check if we could link 
1494     TreeItem *ti=findMapItem (p, seli);
1495     BranchItem *dsti=NULL;
1496     LinkableMapObj* dst=NULL;
1497     if (ti && ti!=seli && ti->isBranchLikeType())
1498     {
1499         dsti=(BranchItem*)ti;
1500         dst=dsti->getLMO(); 
1501     } else
1502         dsti=NULL;
1503     
1504     if (lmosel)
1505     {
1506         if (seli->getType()==TreeItem::Image)
1507         {
1508             FloatImageObj *fio=(FloatImageObj*)lmosel;
1509             fio->moveCenter   (p.x() - movingObj_offset.x(), p.y() - movingObj_offset.y() );    
1510             fio->setRelPos();
1511             fio->updateLinkGeometry(); //no need for reposition, if we update link here
1512             model->emitSelectionChanged();  // position has changed
1513
1514             // Relink float to new mapcenter or branch, if shift is pressed 
1515             // Only relink, if selection really has a new parent
1516             if ( pointerMod==Qt::ShiftModifier && dsti &&  dsti != seli->parent()  )
1517             {
1518                 // Also save the move which was done so far
1519                 QString pold=qpointFToString(movingObj_orgRelPos);
1520                 QString pnow=qpointFToString(fio->getRelPos());
1521                 model->saveState(
1522                     seli,
1523                     "moveRel "+pold,
1524                     seli,
1525                     "moveRel "+pnow,
1526                     QString("Move %1 to relative position %2").arg(model->getObjectName(lmosel)).arg(pnow));
1527                 model->reposition();
1528
1529                 model->relinkImage ((ImageItem*) seli,dsti);
1530                 model->select (seli);
1531             }
1532         } else  if (seli->isBranchLikeType() )
1533         {   // selection != a FloatObj  
1534             if (seli->depth()==0)       
1535             {
1536                 // Move mapcenter
1537                 lmosel->move   (p-movingObj_offset);    
1538                 if (pointerMod==Qt::ShiftModifier) 
1539                 {
1540                     // Move only mapcenter, leave its children where they are
1541                     QPointF v;
1542                     v=lmosel->getAbsPos();
1543                     for (int i=0; i<seli->branchCount(); ++i)
1544                     {
1545                         seli->getBranchObjNum(i)->setRelPos();
1546                         seli->getBranchObjNum(i)->setOrientation();
1547                     }
1548                 } 
1549             } else
1550             {   
1551                 if (seli->depth()==1)
1552                 {
1553                     // Move mainbranch
1554                     if (!lmosel->hasParObjTmp())
1555                         lmosel->move(p-movingObj_offset);       
1556                     lmosel->setRelPos();
1557                 } else
1558                 {
1559                     // d>1, move ordinary branch
1560                     if (lmosel->getOrientation() == LinkableMapObj::LeftOfCenter)
1561                         // Add width of bbox here, otherwise alignRelTo will cause jumping around
1562                         lmosel->move(
1563                             p.x()  - movingObj_offset.x(), 
1564                             p.y()  - movingObj_offset.y() + lmosel->getTopPad() );          
1565                     else    
1566                         lmosel->move(p.x() - movingObj_offset.x(), p.y() - movingObj_offset.y() - lmosel->getTopPad());
1567                     BranchItem *selbi = ((BranchItem*)seli);
1568                     if ( selbi->parentBranch()->getChildrenLayout() == BranchItem::FreePositioning) lmosel->setRelPos();
1569                 } 
1570
1571             } // depth>0
1572
1573             // Maybe we can relink temporary?
1574             if (dsti)
1575             {
1576                 if (pointerMod==Qt::ControlModifier)
1577                 {
1578                     // Special case: CTRL to link below dst
1579                     lmosel->setParObjTmp (dst,p,+1);
1580                 } else if (pointerMod==Qt::ShiftModifier)
1581                     lmosel->setParObjTmp (dst,p,-1);
1582                 else
1583                     lmosel->setParObjTmp (dst,p,0);
1584             } else  
1585                 lmosel->unsetParObjTmp();
1586
1587             // reposition subbranch
1588             lmosel->reposition();
1589
1590             QItemSelection sel=model->getSelectionModel()->selection();
1591             updateSelection(sel,sel);   // position has changed
1592
1593             // In winter mode shake snow from heading
1594             if (winter) model->emitDataChanged(seli);
1595         } // Moving branchLikeType 
1596     } // End of lmosel!=NULL
1597     else if (seli && seli->getType()==TreeItem::XLink)
1598     {
1599         // Move XLink control point
1600         MapObj* mosel=((MapItem*)seli)->getMO();
1601         if (mosel) 
1602         {
1603             mosel->move( p-movingObj_offset );  // FIXME-3 Missing savestate 
1604             model->setChanged();
1605             model->emitSelectionChanged();
1606         }
1607     } else
1608         qWarning("ME::moveObject  Huh? I'm confused.");
1609
1610     scene()->update();
1611
1612     return;
1613 }
1614
1615 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
1616 {
1617     QPointF p = mapToScene(e->pos());
1618     TreeItem *seli=model->getSelectedItem();
1619
1620     TreeItem *dsti=NULL;
1621     if (seli) dsti=findMapItem(p, seli);
1622     LinkableMapObj* dst=NULL;
1623     BranchItem *selbi=model->getSelectedBranch();
1624     if (dsti && dsti->isBranchLikeType ()) 
1625         dst=((MapItem*)dsti)->getLMO(); 
1626     else
1627         dsti=NULL;
1628
1629
1630     // Have we been picking color?
1631     if (state==PickingColor)
1632     {
1633         setCursor (Qt::ArrowCursor);
1634         // Check if we are over another branch
1635         if (dst) 
1636         {   
1637             if (e->modifiers() & Qt::ShiftModifier)
1638                 model->colorBranch (mainWindow->getCurrentColor());
1639             else    
1640                 model->colorSubtree (mainWindow->getCurrentColor());
1641         } 
1642         setState (Neutral);
1643         return;
1644     }
1645
1646     // Have we been drawing a link?
1647     if (state==DrawingLink)     
1648     {
1649         setState (Neutral);
1650         // Check if we are over another branch
1651         if (dsti)
1652         {   
1653             tmpLink->setEndBranch ( ((BranchItem*)dsti) );
1654             tmpLink->activate();
1655             tmpLink->updateLink();
1656             if (model->createLink (tmpLink) )
1657             {
1658                 model->saveState(       
1659                     tmpLink->getBeginLinkItem(),"delete ()",
1660                     seli,QString("addXLink (\"%1\",\"%2\",%3,\"%4\")")
1661                         .arg(model->getSelectString(tmpLink->getBeginBranch()))
1662                         .arg(model->getSelectString(tmpLink->getEndBranch()))
1663                         .arg(tmpLink->getPen().width())
1664                         .arg(tmpLink->getPen().color().name()),
1665                     QString("Adding Link from %1 to %2").arg(model->getObjectName(seli)).arg(model->getObjectName (dsti)));     
1666                 return;
1667             }
1668         } 
1669         delete (tmpLink);
1670         tmpLink=NULL;
1671         return;
1672     }
1673     
1674     // Have we been moving something?
1675     if ( seli && state==MovingObject) 
1676     {   
1677         panningTimer->stop();
1678         if (seli->getType()==TreeItem::Image)
1679         {
1680             FloatImageObj *fio=(FloatImageObj*)( ((MapItem*)seli)->getLMO());
1681             if(fio)
1682             {
1683                 // Moved Image, we need to reposition
1684                 QString pold=qpointFToString(movingObj_orgRelPos);
1685                 QString pnow=qpointFToString(fio->getRelPos());
1686                 model->saveState(
1687                     seli,
1688                     "moveRel " + pold,
1689                     seli,
1690                     "moveRel " + pnow,
1691                     QString("Move %1 to relative position %2").arg(model->getObjectName(seli)).arg(pnow));
1692
1693                 model->emitDataChanged(seli->parent()); // Parent of image has changed
1694                 model->reposition();
1695             }   
1696         }
1697
1698         if (selbi && selbi->depth()==0)
1699         {   
1700             if (movingObj_orgPos != selbi->getBranchObj()->getAbsPos()) 
1701             {
1702                 QString pold=qpointFToString(movingObj_orgPos);
1703                 QString pnow=qpointFToString(selbi->getBranchObj()->getAbsPos());       
1704
1705                 model->saveState(
1706                     selbi,
1707                     "move "+pold,
1708                     selbi,
1709                     "move "+pnow,
1710                     QString("Move mapcenter %1 to position %2").arg(model->getObjectName(selbi)).arg(pnow));
1711             }
1712         }
1713     
1714         if (seli->isBranchLikeType() ) //(seli->getType() == TreeItem::Branch )
1715         {   // A branch was moved
1716             LinkableMapObj* lmosel=NULL;        
1717             lmosel=((MapItem*)seli)->getLMO();
1718                 
1719             // save the position in case we link to mapcenter
1720             QPointF savePos=QPointF (lmosel->getAbsPos()  );
1721
1722             // Reset the temporary drawn link to the original one
1723             lmosel->unsetParObjTmp();
1724
1725             // For Redo we may need to save original selection
1726             QString preSelStr=model->getSelectString(seli);
1727
1728             if (dsti && objectMoved)
1729             {
1730                 // We have a destination, relink to that
1731                 BranchObj* selbo=model->getSelectedBranchObj();
1732
1733                 QString preParStr=model->getSelectString (seli->parent() );
1734                 QString preNum=QString::number (seli->num(),10);
1735                 QString preDstParStr;
1736
1737                 if (e->modifiers() & Qt::ShiftModifier && dsti->parent() )
1738                 {   // Link above dst   
1739                     preDstParStr=model->getSelectString (dsti->parent() );
1740                     model->relinkBranch (
1741                         (BranchItem*)seli,
1742                         (BranchItem*)dsti->parent(),
1743                         ((BranchItem*)dsti)->num(),
1744                         true);
1745                 } else 
1746                 if (e->modifiers() & Qt::ControlModifier && dsti->parent() )
1747                 {
1748                     // Link below dst   
1749                     preDstParStr=model->getSelectString (dsti->parent() );
1750                     model->relinkBranch (
1751                         (BranchItem*)seli,
1752                         (BranchItem*)dsti->parent(),
1753                         ((BranchItem*)dsti)->num()+1,
1754                         true);
1755                 } else  
1756                 {   // Append to dst
1757                     preDstParStr=model->getSelectString(dsti);
1758                     model->relinkBranch (
1759                         (BranchItem*)seli,
1760                         (BranchItem*)dsti,
1761                         -1,
1762                         true,
1763                         movingObj_orgPos);
1764                     if (dsti->depth()==0) selbo->move (savePos);
1765                 } 
1766             } else
1767             {
1768                 // No destination, undo  temporary move 
1769
1770                 if (seli->depth()==1)
1771                 {
1772                     // The select string might be different _after_ moving around.
1773                     // Therefor reposition and then use string of old selection, too
1774                     model->reposition();
1775
1776                     QPointF rp(lmosel->getRelPos());
1777                     if (rp != movingObj_orgRelPos)
1778                     {
1779                         QString ps=qpointFToString(rp);
1780                         model->saveState(
1781                             model->getSelectString(lmosel), "moveRel "+qpointFToString(movingObj_orgRelPos), 
1782                             preSelStr, "moveRel "+ps, 
1783                             QString("Move %1 to relative position %2").arg(model->getObjectName(lmosel)).arg(ps));
1784                     }
1785                 }
1786
1787         if (selbi->parentBranch()->getChildrenLayout() == BranchItem::FreePositioning)
1788         {
1789             lmosel->setRelPos();
1790             model->reposition();
1791         }else
1792         {
1793
1794
1795             // Draw the original link, before selection was moved around
1796             if (settings.value("/animation/use",true).toBool()
1797                     && seli->depth()>1
1798                     //              && distance (lmosel->getRelPos(),movingObj_orgRelPos)<3
1799                     )
1800             {
1801                 lmosel->setRelPos();    // calc relPos first for starting point
1802
1803                 model->startAnimation(
1804                             (BranchObj*)lmosel,
1805                             lmosel->getRelPos(),
1806                             movingObj_orgRelPos
1807                             );
1808             } else
1809                 model->reposition();
1810         }
1811         }
1812     }
1813         // Finally resize scene, if needed
1814         scene()->update();
1815         movingObj=NULL;     
1816         objectMoved=false;
1817         vPan=QPoint ();
1818     } else 
1819         // maybe we moved View: set old cursor
1820         setCursor (Qt::ArrowCursor);
1821
1822     if (state!=EditingHeading) setState (Neutral);   // Continue editing after double click!
1823
1824     QGraphicsView::mouseReleaseEvent(e);
1825 }
1826
1827 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
1828 {
1829     if (e->button() == Qt::LeftButton )
1830     {
1831         QPointF p = mapToScene(e->pos());
1832         TreeItem *ti=findMapItem (p, NULL);
1833         LinkableMapObj *lmo;
1834         if (ti) 
1835         {   
1836             if (state==EditingHeading) editHeadingFinished();
1837             model->select (ti);
1838             BranchItem* selbi=model->getSelectedBranch();
1839             if (selbi)
1840             {
1841                 lmo=((MapItem*)ti)->getLMO();
1842                 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
1843                 if (!foname.isEmpty()) return;  // Don't edit heading when double clicking system flag
1844
1845             }
1846             e->accept();
1847             editHeading();
1848         }
1849     }
1850 }
1851
1852 void MapEditor::wheelEvent(QWheelEvent* e)
1853 {
1854     if (e->modifiers() & Qt::ControlModifier && e->orientation()==Qt::Vertical)
1855     {
1856         if (e->delta()>0)
1857             setZoomFactorTarget (zoomFactorTarget*1.15);
1858         else    
1859             setZoomFactorTarget (zoomFactorTarget*0.85);
1860     } else      
1861     {
1862         scrollBarPosAnimation.stop();
1863         QGraphicsView::wheelEvent (e);
1864     }
1865 }
1866
1867 void MapEditor::focusOutEvent (QFocusEvent*)
1868 {
1869     //qDebug()<<"ME::focusOutEvent"<<e->reason();
1870     if (state==EditingHeading) editHeadingFinished();
1871 }
1872
1873 void MapEditor::resizeEvent (QResizeEvent* e)
1874 {
1875     QGraphicsView::resizeEvent( e );
1876 }
1877
1878 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
1879 {
1880     //for (unsigned int i=0;event->format(i);i++) // Debug mime type
1881     //  cerr << event->format(i) << endl;
1882
1883     if (event->mimeData()->hasImage())
1884         event->acceptProposedAction();
1885     else    
1886         if (event->mimeData()->hasUrls())
1887             event->acceptProposedAction();
1888 }
1889
1890 void MapEditor::dragMoveEvent(QDragMoveEvent *)
1891 {
1892 }
1893
1894 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
1895 {
1896     event->accept();
1897 }
1898
1899 void MapEditor::dropEvent(QDropEvent *event)
1900 {
1901     BranchItem *selbi=model->getSelectedBranch();
1902     if (selbi)
1903     {
1904         if (debug)
1905         {
1906             foreach (QString format,event->mimeData()->formats())
1907                 qDebug()<< "MapEditor: Dropped format: "<<qPrintable (format);
1908             foreach (QUrl url,event->mimeData()->urls())
1909             {
1910                 qDebug()<< "  URL-path:" <<url.path();
1911                 qDebug()<< "URL-string:" <<url.toString();
1912                 qDebug()<< "       enc:" <<url.toEncoded();
1913                 qDebug()<< "     valid:" <<url.isValid();
1914             }
1915             qDebug()    << "============== mimeData ===================";
1916             qDebug()    << "has-img : " << event->mimeData()->hasImage();
1917             qDebug()    << "has-urls: " << event->mimeData()->hasUrls();
1918             qDebug()    << "    text: " << event->mimeData()->text();
1919             qDebug()    << "===========================================";
1920         }
1921
1922         if (event->mimeData()->hasUrls())
1923         {
1924             // Try text representation first, which works on windows, but in 
1925             // Linux only for https, not local images
1926             QString url = event->mimeData()->text();
1927             if (url.isEmpty() )
1928             {
1929                 QByteArray ba = event->mimeData()->urls().first().path().toLatin1();
1930                 QByteArray ba2;
1931                 for (int i = 0; i < ba.count(); i++)
1932                     if (ba.at(i) != 0) ba2.append(ba.at(i));
1933                 url = ba2;
1934             }
1935
1936
1937             BranchItem *bi = NULL;
1938             // Workaround to avoid adding empty branches
1939             if (!url.isEmpty())
1940             {
1941                 if (url.startsWith("file://")) url.remove(0,7);
1942
1943 #if defined(Q_OS_WIN32)
1944                 if (url.startsWith("/")) url.remove(0,1);
1945 #endif
1946                 if (isImage (url))
1947                 {
1948                     if (debug) qDebug() << "dropped url seems to be image: " << url;
1949                     // Image, try to download or set image from local file
1950                     //model->downloadImage (url);
1951                     model->loadImage(bi, url);
1952                     if (debug) qDebug() << "finished loading image";
1953                 } else
1954                 {
1955                     bi = model->addNewBranch();
1956                     if (bi)
1957                     {
1958                         model->select(bi);
1959                         if (url.endsWith(".vym", Qt::CaseInsensitive))
1960                             model->setVymLink(url);
1961                         else
1962                         {
1963                             model->setURL(url);
1964                             model->setHeadingPlainText(url);
1965                         }
1966
1967                         model->select (bi->parent());
1968                     }
1969                 }
1970             }
1971         }
1972     }
1973     event->acceptProposedAction();
1974 }
1975
1976 void MapEditor::setState (EditorState s)
1977 {
1978     if (state!=Neutral && s!=Neutral)
1979         qWarning ()<<"MapEditor::setState  switching directly from "<<state<<" to "<<s;
1980     state=s;
1981     /* if (debug)
1982     {
1983         QString s;
1984         switch (state)
1985         {
1986         case Neutral: s="Neutral";break;
1987         case EditingHeading: s="EditingHeading";break;
1988         case EditingLink: s="EditingLink";break;
1989         case MovingObject: s="MovingObject";break;
1990         case MovingView: s="MovingView";break;
1991         case PickingColor: s="PickingColor";break;
1992         case CopyingObject: s="CopyingObject";break;
1993         case DrawingLink: s="DrawingLink";break;
1994         }
1995         qDebug()<<"MapEditor: State "<<s<< " of "<<model->getMapName();
1996     }
1997     */
1998 }
1999
2000 MapEditor::EditorState MapEditor::getState()
2001 {
2002     return state;
2003 }
2004
2005 void MapEditor::updateSelection(QItemSelection nsel,QItemSelection dsel)        
2006 {
2007     QList <MapItem*> itemsSelected;
2008     QList <MapItem*> itemsDeselected;
2009
2010     QItemSelection sel=model->getSelectionModel()->selection();
2011     foreach (QModelIndex ix,sel.indexes() )
2012     {
2013         MapItem *mi= static_cast<MapItem*>(ix.internalPointer());
2014         if (mi->isBranchLikeType() 
2015             ||mi->getType()==TreeItem::Image 
2016             ||mi->getType()==TreeItem::XLink)
2017             if (!itemsSelected.contains(mi)) 
2018                 itemsSelected.append (mi);
2019     }
2020     foreach (QModelIndex ix,dsel.indexes() )
2021     {
2022         MapItem *mi= static_cast<MapItem*>(ix.internalPointer());
2023         if (mi->isBranchLikeType() 
2024             ||mi->getType()==TreeItem::Image 
2025             ||mi->getType()==TreeItem::XLink)
2026             if (!itemsDeselected.contains(mi)) 
2027                 itemsDeselected.append (mi);
2028     }
2029
2030     // Trim list of selection paths 
2031     while (itemsSelected.count() < selPathList.count() )
2032         delete selPathList.takeFirst();
2033
2034     // Reduce polygons
2035     while (itemsSelected.count() < selPathList.count() )
2036         delete selPathList.takeFirst();
2037
2038     // Add additonal polygons
2039     QGraphicsPathItem *sp;
2040     while (itemsSelected.count() > selPathList.count() )
2041     {
2042         sp = mapScene->addPath(
2043             QPainterPath(), 
2044             QPen(selectionColor),
2045             selectionColor);
2046         sp->show();
2047         selPathList.append (sp);
2048     }
2049
2050
2051     // Reposition polygons 
2052     for (int i=0; i<itemsSelected.count();++i)
2053     {
2054         MapObj *mo=itemsSelected.at(i)->getMO();
2055         sp=selPathList.at(i);
2056         sp->setPath (mo->getClickPath() );
2057         sp->setPen (selectionColor);    
2058         sp->setBrush (selectionColor);  
2059         sp->setParentItem (mo); 
2060         sp->setZValue (dZ_SELBOX);
2061
2062         // Reposition also LineEdit for heading during animation
2063         if (lineEdit) lineEdit->move (mo->getAbsPos().toPoint() );
2064     }
2065
2066     scene()->update();  
2067 }
2068
2069 void MapEditor::updateData (const QModelIndex &sel)
2070 {
2071     TreeItem *ti= static_cast<TreeItem*>(sel.internalPointer());
2072
2073 /* testing
2074     qDebug() << "ME::updateData";
2075     if (!ti) 
2076     {
2077         qDebug() << "  ti=NULL";
2078         return;
2079     }
2080     qDebug() << "  ti="<<ti;
2081     qDebug() << "  h="<<ti->getHeadingPlain();
2082 */
2083     
2084     if (ti && ti->isBranchLikeType())
2085     {
2086         BranchObj *bo=(BranchObj*) ( ((MapItem*)ti)->getLMO());
2087         bo->updateData();
2088     }
2089
2090     if (winter)
2091     {
2092         QList <QRectF> obstacles;
2093         BranchObj *bo;
2094         BranchItem *cur=NULL;
2095         BranchItem *prev=NULL;
2096         model->nextBranch(cur,prev);
2097         while (cur) 
2098         {
2099             if (!cur->hasHiddenExportParent())
2100             {
2101                 // Branches
2102                 bo=(BranchObj*)(cur->getLMO());
2103                 if (bo && bo->isVisibleObj())
2104                     obstacles.append(bo->getBBox());
2105             }
2106             model->nextBranch(cur,prev);
2107         }
2108         winter->setObstacles(obstacles);
2109     }
2110 }
2111
2112 void MapEditor::setSelectionColor (QColor col)
2113 {
2114     selectionColor=col;
2115     selectionColor.setAlpha (220);
2116     QItemSelection sel=model->getSelectionModel()->selection();
2117     updateSelection(sel,sel);
2118 }
2119
2120
2121 QColor MapEditor::getSelectionColor ()
2122 {
2123     return selectionColor;
2124 }
2125
2126