3 #include <QGraphicsProxyWidget>
7 #include <QPrintDialog>
10 #include "branchitem.h"
12 #include "mainwindow.h"
14 #include "shortcuts.h"
15 #include "warningdialog.h"
16 #include "xlinkitem.h"
19 extern Main *mainWindow;
20 extern QString tmpVymDir;
21 extern QString clipboardDir;
22 extern QString clipboardFile;
23 extern bool clipboardEmpty;
25 extern QPrinter *printer;
27 extern QMenu* branchContextMenu;
28 extern QMenu* canvasContextMenu;
29 extern QMenu* floatimageContextMenu;
30 extern QMenu* taskContextMenu;
32 extern Switchboard switchboard;
33 extern Settings settings;
35 extern QTextStream vout;
37 ///////////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////////
39 MapEditor::MapEditor( VymModel *vm)
41 //qDebug() << "Constructor ME "<<this;
43 QString shortcutScope = tr("Map Editor","Shortcut scope");
44 mapScene= new QGraphicsScene(NULL);
45 mapScene->setBackgroundBrush (QBrush(Qt::white, Qt::SolidPattern));
47 zoomFactor=zoomFactorTarget=1;
51 model->registerEditor(this);
52 model->makeDefault(); // No changes in model so far
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 );
67 setAcceptDrops (true);
69 // Shortcuts and actions
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() ) );
78 a = new QAction( "Select lower branch",this);
79 a->setShortcut ( Qt::Key_Down );
80 a->setShortcutContext (Qt::WidgetShortcut);
82 connect( a, SIGNAL( triggered() ), this, SLOT( cursorDown() ) );
84 a = new QAction( "Select left branch", this);
85 a->setShortcut (Qt::Key_Left );
86 // a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
88 connect( a, SIGNAL( triggered() ), this, SLOT( cursorLeft() ) );
90 a = new QAction( "Select child branch", this);
91 a->setShortcut (Qt::Key_Right);
92 // a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
94 connect( a, SIGNAL( triggered() ), this, SLOT( cursorRight() ) );
96 a = new QAction( "Select first branch", this);
97 a->setShortcut (Qt::Key_Home );
98 a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
100 connect( a, SIGNAL( triggered() ), this, SLOT( cursorFirst() ) );
102 a = new QAction( "Select last branch",this);
103 a->setShortcut ( Qt::Key_End );
104 a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
106 connect( a, SIGNAL( triggered() ), this, SLOT( cursorLast() ) );
108 // Action to embed LineEdit for heading in Scene
111 a = new QAction( tr( "Edit heading","MapEditor" ), this);
112 a->setShortcut ( Qt::Key_Return ); //Edit heading
113 a->setShortcutContext (Qt::WidgetShortcut);
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);
120 connect( a, SIGNAL( triggered() ), this, SLOT( editHeading() ) );
123 selectionColor =QColor (255,255,0);
126 panningTimer=new QTimer (this);
128 connect (panningTimer, SIGNAL (timeout()), this, SLOT (panView() ));
130 // Clone actions defined in MainWindow
131 foreach (QAction* qa, mainWindow->mapEditorActions)
133 a = new QAction( this );
134 a->setShortcut( qa->shortcut() );
135 a->setShortcutContext( qa->shortcutContext() );
136 connect( a, SIGNAL( triggered() ), qa, SLOT( trigger() ) );
142 // Attributes //TODO testing only...
145 attrTable= new AttributeTable();
147 ad=attrTable->addKey (k,StringList);
151 sl <<"val 1"<<"val 2"<< "val 3";
152 ad->setValue (QVariant (sl));
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");
159 ad=attrTable->addKey (k,FreeString);
162 //attrTable->addValue ("Key B","w1");
163 //attrTable->addValue ("Key B","w2");
165 k="C - UniqueString";
166 ad=attrTable->addKey (k,UniqueString);
169 //attrTable->addKey ("Key Prio");
170 //attrTable->addValue ("Key Prio","Prio 1");
171 //attrTable->addValue ("Key Prio","Prio 2");
177 MapEditor::~MapEditor()
179 //qDebug ()<<"Destr MapEditor this="<<this;
182 VymModel* MapEditor::getModel()
187 QGraphicsScene * MapEditor::getScene()
192 void MapEditor::panView()
197 // To avoid jumping of the sceneView, only
198 // show selection, if not tmp linked
203 else if (vPan.x()>0 )
207 else if (vPan.y()>0 )
208 py=height()+vPan.y();
210 QPointF q=mapToScene (QPoint(px,py));
211 QRectF r=QRectF (q,QPointF (q.x()+1,q.y()+1));
213 // Expand view if necessary
214 setScrollBarPosTarget (r);
216 // Stop possible other animations
217 if (scrollBarPosAnimation.state()==QAbstractAnimation::Running)
218 scrollBarPosAnimation.stop();
220 // Do linear animation
221 horizontalScrollBar()->setValue(horizontalScrollBar()->value() + vPan.x() );
222 verticalScrollBar()->setValue ( verticalScrollBar()->value() + vPan.y() );
224 // Update currently moving object
229 void MapEditor::scrollTo (const QModelIndex &index)
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();
239 QRectF r=lmo->getBBox();
240 setScrollBarPosTarget (r);
246 void MapEditor::setScrollBarPosTarget (QRectF rect)
248 // Expand viewport, if rect is not contained
249 if (!sceneRect().contains (rect) )
250 setSceneRect(sceneRect().united (rect));
256 qreal width = viewport()->width();
257 qreal height = viewport()->height();
258 QRectF viewRect = matrix().mapRect(rect);
260 qreal left = horizontalScrollBar()->value();
261 qreal right = left + width;
262 qreal top = verticalScrollBar()->value();
263 qreal bottom = top + height;
265 scrollBarPosTarget=getScrollBarPos();
267 if (viewRect.left() <= left + xmargin) {
268 // need to scroll from the left
269 scrollBarPosTarget.setX(int(viewRect.left() - xmargin - 0.5));
271 if (viewRect.right() >= right - xmargin) {
272 // need to scroll from the right
273 scrollBarPosTarget.setX(int(viewRect.right() - width + xmargin + 0.5));
275 if (viewRect.top() <= top + ymargin) {
276 // need to scroll from the top
277 scrollBarPosTarget.setY(int(viewRect.top() - ymargin - 0.5));
279 if (viewRect.bottom() >= bottom - ymargin) {
280 // need to scroll from the bottom
281 scrollBarPosTarget.setY(int(viewRect.bottom() - height + ymargin + 0.5));
286 QPointF MapEditor::getScrollBarPosTarget()
288 return scrollBarPosTarget;
292 void MapEditor::setScrollBarPos(const QPointF &p)
295 horizontalScrollBar()->setValue(int(p.x()));
296 verticalScrollBar()->setValue(int(p.y()));
299 QPointF MapEditor::getScrollBarPos()
301 return QPointF (horizontalScrollBar()->value(),verticalScrollBar()->value());
302 //return scrollBarPos;
305 void MapEditor::animateScrollBars()
307 if (scrollBarPosAnimation.state()==QAbstractAnimation::Running)
308 scrollBarPosAnimation.stop();
310 if (settings.value ("/animation/use/",true).toBool() )
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();
322 setScrollBarPos (scrollBarPosTarget);
325 void MapEditor::setZoomFactorTarget (const qreal &zft)
327 zoomFactorTarget=zft;
328 if (zoomAnimation.state()==QAbstractAnimation::Running)
329 zoomAnimation.stop();
330 if (settings.value ("/animation/use/",true).toBool() )
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();
343 qreal MapEditor::getZoomFactorTarget()
345 return zoomFactorTarget;
349 void MapEditor::setZoomFactor(const qreal &zf)
355 qreal MapEditor::getZoomFactor()
360 void MapEditor::setAngleTarget (const qreal &at)
363 if (rotationAnimation.state()==QAbstractAnimation::Running)
364 rotationAnimation.stop();
365 if (settings.value ("/animation/use/",true).toBool() )
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();
375 setAngle (angleTarget);
378 qreal MapEditor::getAngleTarget()
384 void MapEditor::setAngle(const qreal &a)
390 qreal MapEditor::getAngle()
395 void MapEditor::setViewCenterTarget (
400 const QEasingCurve &easingCurve)
403 zoomFactorTarget=zft;
406 viewCenter=mapToScene(viewport()->geometry()).boundingRect().center();
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();
415 if (settings.value ("/animation/use/",true).toBool() )
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();
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();
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();
444 setAngle (angleTarget);
446 setViewCenter (viewCenterTarget);
450 void MapEditor::setViewCenterTarget ()
452 MapItem *selti=(MapItem*)(model->getSelectedItem() );
455 LinkableMapObj *lmo=selti->getLMO();
457 setViewCenterTarget (lmo->getBBox().center(), 1, 0);
461 QPointF MapEditor::getViewCenterTarget ()
463 return viewCenterTarget;
466 void MapEditor::setViewCenter (const QPointF &vc)
471 QPointF MapEditor::getViewCenter()
476 void MapEditor::updateMatrix()
478 double a = M_PI/180 * angle;
479 double sina = sin((double)a);
480 double cosa = cos((double)a);
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);
488 void MapEditor::minimizeView()
490 setSceneRect( scene()->itemsBoundingRect() );
493 void MapEditor::print()
495 QRectF totalBBox=getTotalBBox();
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
502 if (totalBBox.width()>totalBBox.height())
503 // recommend landscape
504 printer->setOrientation (QPrinter::Landscape);
506 // recommend portrait
507 printer->setOrientation (QPrinter::Portrait);
509 QPrintDialog dialog (printer, this);
510 dialog.setWindowTitle(tr("Print vym map","MapEditor"));
511 if (dialog.exec() == QDialog::Accepted)
513 QPainter pp(printer);
515 pp.setRenderHint(QPainter::Antialiasing,true);
517 // Don't print the visualisation of selection
518 model->unselectAll();
520 QRectF mapRect=totalBBox;
521 QGraphicsRectItem *frame=NULL;
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));
534 double paperAspect = (double)printer->width() / (double)printer->height();
535 double mapAspect = (double)mapRect.width() / (double)mapRect.height();
537 if (mapAspect>=paperAspect)
539 // Fit horizontally to paper width
540 //pp.setViewport(0,0, printer->width(),(int)(printer->width()/mapAspect) );
541 viewBottom=(int)(printer->width()/mapAspect);
544 // Fit vertically to paper height
545 //pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height());
546 viewBottom=printer->height();
551 // Print footer below map
553 font.setPointSize(10);
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));
561 QRectF (0,0,printer->width(),printer->height()-15),
562 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height())
565 // Viewport has paper dimension
566 if (frame) delete (frame);
573 QRectF MapEditor::getTotalBBox()
579 QImage MapEditor::getImage( QPointF &offset)
581 QRectF mapRect = getTotalBBox(); // minimized sceneRect
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 );
588 pp.setRenderHints(renderHints());
589 mapScene->render ( &pp,
591 QRectF( 0, 0, mapRect.width() + d, mapRect.height() + d ),
593 QRectF( mapRect.x() - d/2, mapRect.y() -d/2, mapRect.width() + d, mapRect.height() + d));
598 void MapEditor::setAntiAlias (bool b)
600 setRenderHint(QPainter::Antialiasing,b);
603 void MapEditor::setSmoothPixmap(bool b)
605 setRenderHint(QPainter::SmoothPixmapTransform,b);
608 void MapEditor::autoLayout()
610 // Create list with all bounding polygons
611 QList <LinkableMapObj*> mapobjects;
612 QList <ConvexPolygon> polys;
614 QList <Vector> vectors;
615 QList <Vector> orgpos;
616 QStringList headings; //FIXME-3 testing only
622 // Outer loop: Iterate until we no more changes in orientation
623 bool orientationChanged=true;
624 while (orientationChanged)
626 BranchItem *ri=model->getRootItem();
627 for (int i=0;i<ri->branchCount();++i)
629 bi=ri->getBranchNum (i);
630 bo=(BranchObj*)bi->getLMO();
633 mapobjects.append (bo);
634 p=bo->getBoundingPolygon();
637 vectors.append (QPointF(0,0));
638 orgpos.append (p.at(0));
639 headings.append (bi->getHeadingPlain());
641 for (int j=0;j<bi->branchCount();++j)
643 bi2=bi->getBranchNum (j);
644 bo=(BranchObj*)bi2->getLMO();
647 mapobjects.append (bo);
648 p=bo->getBoundingPolygon();
651 vectors.append (QPointF(0,0));
652 orgpos.append (p.at(0));
653 headings.append (bi2->getHeadingPlain());
658 // Iterate moving bounding polygons until we have no more collisions
663 for (int i=0; i<polys.size()-1; ++i)
665 for (int j=i+1; j<polys.size();++j)
667 if (polygonCollision (polys.at(i),polys.at(j), QPointF(0,0)).intersect )
670 if (debug) qDebug() << "Collision: "<<headings[i]<<" - "<<headings[j];
671 v=polys.at(j).centroid()-polys.at(i).centroid();
673 // Add random direction, if only two polygons with identical y or x
674 if (v.x()==0 || v.y()==0)
676 Vector w (cos (double((int)rand()%1000)),sin(double((int)rand()%1000)));
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();
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_
691 for (int i=0;i<vectors.size();i++)
693 //qDebug() << " v="<<vectors[i]<<" "<<headings[i];
694 if (!vectors[i].isNull() )
695 polys[i].translate (vectors[i]);
697 // if (debug) qDebug()<< "Collisions total: "<<collisions;
701 // Finally move the real objects and update
702 QList <LinkableMapObj::Orientation> orients;
703 for (int i=0;i<polys.size();i++)
705 Vector v=polys[i].at(0)-orgpos[i];
706 orients.append (mapobjects[i]->getOrientation());
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);
718 orientationChanged=false;
719 for (int i=0;i<polys.size();i++)
720 if (orients[i]!=mapobjects[i]->getOrientation())
722 orientationChanged=true;
729 //orientationChanged=false;
730 } // loop if orientation has changed
732 model->emitSelectionChanged();
735 TreeItem* MapEditor::findMapItem (QPointF p,TreeItem *exclude)
739 for (int i=0; i<model->xlinkCount(); i++ )
741 link=model->getXLinkNum(i);
744 XLinkObj *xlo=link->getXLinkObj();
745 if (xlo && xlo->isInClickBox (p))
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());
751 return link->getBeginLinkItem();
753 return link->getEndLinkItem();
758 // Search branches (and their childs, e.g. images
759 // Start with mapcenter, no images allowed at rootItem
761 BranchItem *bi=model->getRootItem()->getFirstBranch();
762 TreeItem *found=NULL;
765 found=bi->findMapItem (p, exclude);
766 if (found) return found;
768 bi=model->getRootItem()->getBranchNum(i);
773 AttributeTable* MapEditor::attributeTable()
778 void MapEditor::testFunction1()
782 void MapEditor::testFunction2()
788 void MapEditor::toggleWinter()
796 winter=new Winter (this);
797 QList <QRectF> obstacles;
799 BranchItem *cur=NULL;
800 BranchItem *prev=NULL;
801 model->nextBranch(cur,prev);
804 if (!cur->hasHiddenExportParent())
807 bo=(BranchObj*)(cur->getLMO());
808 if (bo && bo->isVisibleObj())
809 obstacles.append(bo->getBBox());
811 model->nextBranch(cur,prev);
813 winter->setObstacles(obstacles);
817 BranchItem* MapEditor::getBranchDirectAbove (BranchItem *bi)
822 if (i>0) return bi->parent()->getBranchNum(i-1);
827 BranchItem* MapEditor::getBranchAbove (BranchItem *selbi)
831 int dz=selbi->depth(); // original depth
833 if (selbi->getLMO()->getOrientation()==LinkableMapObj::LeftOfCenter)
838 // Look for branch with same parent but directly above
840 bi=getBranchDirectBelow(selbi);
842 bi=getBranchDirectAbove (selbi);
845 // direct predecessor
848 // Go towards center and look for predecessor
849 while (selbi->depth()>0)
851 selbi=(BranchItem*)(selbi->parent());
852 if (selbi->depth()==1 && invert)
853 bi=getBranchDirectBelow (selbi);
855 bi=getBranchDirectAbove (selbi);
860 while (selbi->depth()<dz)
862 // try to get back to original depth dz
863 bi=selbi->getLastBranch();
877 BranchItem* MapEditor::getBranchDirectBelow(BranchItem *bi)
882 if (i+1<bi->parent()->branchCount()) return bi->parent()->getBranchNum(i+1);
887 BranchItem* MapEditor::getBranchBelow (BranchItem *selbi)
892 int dz=selbi->depth(); // original depth
894 if (selbi->getLMO()->getOrientation()==LinkableMapObj::LeftOfCenter)
898 // Look for branch with same parent but directly below
900 bi=getBranchDirectAbove (selbi);
902 bi=getBranchDirectBelow (selbi);
908 // Go towards center and look for neighbour
909 while (selbi->depth()>0)
911 selbi=(BranchItem*)(selbi->parent());
912 if (selbi->depth()==1 && invert)
913 bi=getBranchDirectAbove (selbi);
915 bi=getBranchDirectBelow (selbi);
920 while (selbi->depth()<dz)
922 // try to get back to original depth dz
923 bi=selbi->getFirstBranch();
937 BranchItem* MapEditor::getLeftBranch (BranchItem *bi)
943 // Special case: use alternative selection index
944 BranchItem *newbi=bi->getLastSelectedBranchAlt();
948 // Try to find a mainbranch left of center
949 for (int i=0; i<bi->branchCount(); i++)
951 newbi=bi->getBranchNum(i);
952 bo=newbi->getBranchObj();
953 if (bo && bo->getOrientation()==LinkableMapObj::LeftOfCenter)
959 if (bi->getBranchObj()->getOrientation()==LinkableMapObj::RightOfCenter)
961 return (BranchItem*)(bi->parent());
964 if (bi->getType()== TreeItem::Branch )
965 return bi->getLastSelectedBranch();
970 BranchItem* MapEditor::getRightBranch(BranchItem *bi)
976 // Special case: use alternative selection index
977 BranchItem *newbi=bi->getLastSelectedBranch();
981 // Try to find a mainbranch right of center
982 for (int i=0; i<bi->branchCount(); i++)
984 newbi=bi->getBranchNum(i);
985 bo=newbi->getBranchObj();
986 if (bo && bo->getOrientation()==LinkableMapObj::RightOfCenter)
987 qDebug()<<"BI found right: "<<newbi->getHeadingPlain();
992 if (bi->getBranchObj()->getOrientation()==LinkableMapObj::LeftOfCenter)
994 return (BranchItem*)(bi->parent());
997 if (bi->getType()== TreeItem::Branch )
998 return (BranchItem*)bi->getLastSelectedBranch();
1005 void MapEditor::cursorUp()
1007 if (state == MapEditor::EditingHeading) return;
1009 BranchItem *bi=model->getSelectedBranch();
1010 if (bi) model->select (getBranchAbove(bi));
1013 void MapEditor::cursorDown()
1016 if (state == MapEditor::EditingHeading) return;
1018 BranchItem *bi=model->getSelectedBranch();
1019 if (bi) model->select (getBranchBelow(bi));
1022 void MapEditor::cursorLeft()
1024 BranchItem *bi=getLeftBranch (model->getSelectedBranch());
1025 if (bi) model->select (bi);
1028 void MapEditor::cursorRight()
1030 BranchItem *bi=getRightBranch (model->getSelectedBranch());
1031 if (bi) model->select (bi);
1034 void MapEditor::cursorFirst()
1036 model->selectFirstBranch();
1039 void MapEditor::cursorLast()
1041 model->selectLastBranch();
1045 void MapEditor::editHeading()
1047 if (state==EditingHeading)
1049 editHeadingFinished();
1053 BranchObj *bo=model->getSelectedBranchObj();
1054 BranchItem *bi=model->getSelectedBranch();
1057 VymText heading = bi->getHeading();
1058 if (heading.isRichText())
1060 mainWindow->windowShowHeadingEditor();
1063 model->setSelectionBlocked(true);
1065 lineEdit=new QLineEdit;
1066 QGraphicsProxyWidget *pw=mapScene->addWidget (lineEdit);
1067 pw->setZValue (Z_LINEEDIT);
1068 lineEdit->setCursor(Qt::IBeamCursor);
1069 lineEdit->setCursorPosition(1);
1071 QPointF tl=bo->getOrnamentsBBox().topLeft();
1072 QPointF br=tl + QPointF (230,30);
1074 lineEdit->setGeometry(r.toRect() );
1076 setScrollBarPosTarget ( r );
1079 // Set focus to MapEditor first
1080 // To avoid problems with Cursor up/down
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);
1092 void MapEditor::editHeadingFinished()
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);
1104 animateScrollBars();
1106 // Maybe reselect previous branch
1107 mainWindow->editHeadingFinished (model);
1109 //Autolayout to avoid overlapping branches with longer headings
1110 if (settings.value("/mainwindow/autoLayout/use","true")=="true")
1115 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
1117 // Lineedits are already closed by preceding
1118 // mouseEvent, we don't need to close here.
1120 QPointF p = mapToScene(e->pos());
1121 TreeItem *ti=findMapItem (p, NULL);
1124 { // MapObj was found
1127 LinkableMapObj* lmo=NULL;
1128 BranchItem* selbi=model->getSelectedBranch();
1129 if (ti) lmo=((MapItem*)ti)->getLMO();
1134 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
1135 if (foname.startsWith ("system-task"))
1136 taskContextMenu->popup (e->globalPos() );
1138 // Context Menu on branch or mapcenter
1139 branchContextMenu->popup(e->globalPos() );
1142 if (model->getSelectedImage() )
1144 // Context Menu on floatimage
1145 floatimageContextMenu->popup(e->globalPos() );
1148 if (model->getSelectedXLink() )
1149 // Context Menu on XLink
1154 { // No MapObj found, we are on the Canvas itself
1155 // Context Menu on scene
1157 // Open context menu synchronously to position new mapcenter
1158 model->setContextPos (p);
1159 canvasContextMenu->exec(e->globalPos() );
1160 model->unsetContextPos ();
1165 void MapEditor::keyPressEvent(QKeyEvent* e)
1167 if (e->key()==Qt::Key_PageUp || e->key()==Qt::Key_PageDown)
1168 // Ignore PageUP/Down to avoid scrolling with keys
1171 if (e->modifiers() & Qt::ShiftModifier)
1173 switch (mainWindow->getModMode())
1175 case Main::ModModeColor:
1176 setCursor (PickColorCursor);
1178 case Main::ModModeCopy:
1179 setCursor (CopyCursor);
1181 case Main::ModModeXLink:
1182 setCursor (XLinkCursor);
1185 setCursor (Qt::ArrowCursor);
1189 QGraphicsView::keyPressEvent(e);
1192 void MapEditor::keyReleaseEvent(QKeyEvent* e)
1194 if (!(e->modifiers() & Qt::ControlModifier))
1195 setCursor (Qt::ArrowCursor);
1198 void MapEditor::mousePressEvent(QMouseEvent* e)
1200 // Ignore right clicks or wile editing heading
1201 if (e->button() == Qt::RightButton || model->isSelectionBlocked() )
1204 QGraphicsView::mousePressEvent(e);
1208 // Check if we need to reset zoomFactor
1209 if (e->button() == Qt::MidButton && e->modifiers() & Qt::ControlModifier )
1211 setZoomFactorTarget (1);
1216 QPointF p = mapToScene(e->pos());
1217 TreeItem *ti=findMapItem (p, NULL);
1218 LinkableMapObj* lmo=NULL;
1219 if (ti) lmo=((MapItem*)ti)->getLMO();
1221 QString sysFlagName;
1222 if (lmo) sysFlagName=((BranchObj*)lmo)->getSystemFlagName(p);
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;
1232 // Check PickColor modifier (before selecting object!)
1233 if (ti && (e->modifiers() & Qt::ShiftModifier) &&
1234 mainWindow->getModMode()==Main::ModModeColor)
1236 setState (PickingColor);
1237 mainWindow->setCurrentColor (ti->getHeadingColor() );
1238 if ((e->modifiers() & Qt::ShiftModifier) && (e->modifiers() & Qt::ControlModifier) )
1239 model->colorBranch(ti->getHeadingColor());
1241 model->colorSubtree(ti->getHeadingColor());
1245 // Check vymlink modifier (before selecting object!)
1246 if (ti && sysFlagName=="system-vymLink")
1249 if (e->modifiers() & Qt::ControlModifier)
1250 mainWindow->editOpenVymLink(true);
1252 mainWindow->editOpenVymLink(false);
1256 // Select the clicked object
1257 if (ti && e->modifiers() & Qt::ControlModifier)
1258 model->selectToggle (ti);
1264 //Take care of remaining system flags _or_ modifier modes
1267 if (!sysFlagName.isEmpty())
1269 // systemFlag clicked
1270 if (sysFlagName.contains("system-url"))
1272 if (e->modifiers() & Qt::ControlModifier)
1273 mainWindow->editOpenURLTab();
1275 mainWindow->editOpenURL();
1277 else if (sysFlagName=="system-vymLink")
1279 if (e->modifiers() & Qt::ControlModifier)
1280 mainWindow->editOpenVymLink(true);
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();
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)
1298 if ((lmo->getOrientation()!=LinkableMapObj::RightOfCenter && p.x() < lmo->getBBox().left()+10) ||
1299 (lmo->getOrientation()!=LinkableMapObj::LeftOfCenter && p.x() > lmo->getBBox().right()-10) )
1301 //FIXME-4 similar code in mainwindow::updateActions
1303 QList <QAction*> alist;
1304 QList <BranchItem*> blist;
1305 for (int i=0;i<ti->xlinkCount();i++)
1307 XLinkItem *xli=ti->getXLinkItemNum(i);
1308 BranchItem *bit=xli->getPartnerBranch();
1309 if (bit) alist.append (new QAction(ti->getXLinkItemNum(i)->getPartnerBranch()->getHeadingPlain(),&menu));
1311 menu.addActions (alist);
1312 QAction *ra=menu.exec (e->globalPos() );
1314 model->select (blist.at( alist.indexOf(ra)));
1315 while (!alist.isEmpty())
1317 QAction *a=alist.takeFirst();
1326 // XLink modifier, create new XLink
1327 BranchItem* selbi = model->getSelectedBranch();
1329 mainWindow->getModMode()==Main::ModModeXLink &&
1330 (e->modifiers() & Qt::ShiftModifier))
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();
1343 // Start moving around
1346 // Left Button Move Branches
1347 if (e->button() == Qt::LeftButton )
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() );
1357 movingObj_orgRelPos=lmo->getRelPos();
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)
1367 setState (CopyingObject);
1370 model->select (selbi->getLastBranch());
1371 model->reposition();
1374 setState (MovingObject);
1376 movingObj=model->getSelectedLMO();
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();
1384 { // No lmo found, check XLinks
1387 if (ti->getType()==TreeItem::XLink)
1389 XLinkObj* xlo=(XLinkObj*) ((MapItem*)ti)->getMO() ;
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() );
1404 { // No MapObj found, we are on the scene itself
1405 // Left Button move Pos of sceneView
1406 if (e->button() == Qt::LeftButton )
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);
1421 void MapEditor::mouseMoveEvent(QMouseEvent* e)
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())));
1430 TreeItem *seli=model->getSelectedItem();
1434 mosel=((MapItem*)seli)->getMO();
1436 // Move the selected MapObj
1437 if ( mosel && (state==MovingObject || state==CopyingObject || state==EditingLink))
1441 // Check if we have to scroll
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 );
1453 pointerPos=e->pos();
1454 pointerMod=e->modifiers();
1456 } // selection && moving_obj
1458 // Draw a link from one branch to another
1459 if (state==DrawingLink)
1461 tmpLink->setEndPoint ( mapToScene (e->pos() ) );
1462 tmpLink->updateLink();
1466 if (state==MovingView && e->buttons() == Qt::LeftButton )
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
1477 void MapEditor::moveObject ()
1479 if (!panningTimer->isActive() )
1480 panningTimer->start(50);
1482 QPointF p = mapToScene(pointerPos);
1483 TreeItem *seli=model->getSelectedItem();
1484 LinkableMapObj* lmosel=NULL;
1486 lmosel=((MapItem*)seli)->getLMO();
1489 // reset cursor if we are moving and don't copy
1490 if (mainWindow->getModMode()!=Main::ModModeCopy)
1491 setCursor (Qt::ArrowCursor);
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())
1499 dsti=(BranchItem*)ti;
1506 if (seli->getType()==TreeItem::Image)
1508 FloatImageObj *fio=(FloatImageObj*)lmosel;
1509 fio->moveCenter (p.x() - movingObj_offset.x(), p.y() - movingObj_offset.y() );
1511 fio->updateLinkGeometry(); //no need for reposition, if we update link here
1512 model->emitSelectionChanged(); // position has changed
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() )
1518 // Also save the move which was done so far
1519 QString pold=qpointFToString(movingObj_orgRelPos);
1520 QString pnow=qpointFToString(fio->getRelPos());
1526 QString("Move %1 to relative position %2").arg(model->getObjectName(lmosel)).arg(pnow));
1527 model->reposition();
1529 model->relinkImage ((ImageItem*) seli,dsti);
1530 model->select (seli);
1532 } else if (seli->isBranchLikeType() )
1533 { // selection != a FloatObj
1534 if (seli->depth()==0)
1537 lmosel->move (p-movingObj_offset);
1538 if (pointerMod==Qt::ShiftModifier)
1540 // Move only mapcenter, leave its children where they are
1542 v=lmosel->getAbsPos();
1543 for (int i=0; i<seli->branchCount(); ++i)
1545 seli->getBranchObjNum(i)->setRelPos();
1546 seli->getBranchObjNum(i)->setOrientation();
1551 if (seli->depth()==1)
1554 if (!lmosel->hasParObjTmp())
1555 lmosel->move(p-movingObj_offset);
1556 lmosel->setRelPos();
1559 // d>1, move ordinary branch
1560 if (lmosel->getOrientation() == LinkableMapObj::LeftOfCenter)
1561 // Add width of bbox here, otherwise alignRelTo will cause jumping around
1563 p.x() - movingObj_offset.x(),
1564 p.y() - movingObj_offset.y() + lmosel->getTopPad() );
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();
1573 // Maybe we can relink temporary?
1576 if (pointerMod==Qt::ControlModifier)
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);
1583 lmosel->setParObjTmp (dst,p,0);
1585 lmosel->unsetParObjTmp();
1587 // reposition subbranch
1588 lmosel->reposition();
1590 QItemSelection sel=model->getSelectionModel()->selection();
1591 updateSelection(sel,sel); // position has changed
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)
1599 // Move XLink control point
1600 MapObj* mosel=((MapItem*)seli)->getMO();
1603 mosel->move( p-movingObj_offset ); // FIXME-3 Missing savestate
1604 model->setChanged();
1605 model->emitSelectionChanged();
1608 qWarning("ME::moveObject Huh? I'm confused.");
1615 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
1617 QPointF p = mapToScene(e->pos());
1618 TreeItem *seli=model->getSelectedItem();
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();
1630 // Have we been picking color?
1631 if (state==PickingColor)
1633 setCursor (Qt::ArrowCursor);
1634 // Check if we are over another branch
1637 if (e->modifiers() & Qt::ShiftModifier)
1638 model->colorBranch (mainWindow->getCurrentColor());
1640 model->colorSubtree (mainWindow->getCurrentColor());
1646 // Have we been drawing a link?
1647 if (state==DrawingLink)
1650 // Check if we are over another branch
1653 tmpLink->setEndBranch ( ((BranchItem*)dsti) );
1654 tmpLink->activate();
1655 tmpLink->updateLink();
1656 if (model->createLink (tmpLink) )
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)));
1674 // Have we been moving something?
1675 if ( seli && state==MovingObject)
1677 panningTimer->stop();
1678 if (seli->getType()==TreeItem::Image)
1680 FloatImageObj *fio=(FloatImageObj*)( ((MapItem*)seli)->getLMO());
1683 // Moved Image, we need to reposition
1684 QString pold=qpointFToString(movingObj_orgRelPos);
1685 QString pnow=qpointFToString(fio->getRelPos());
1691 QString("Move %1 to relative position %2").arg(model->getObjectName(seli)).arg(pnow));
1693 model->emitDataChanged(seli->parent()); // Parent of image has changed
1694 model->reposition();
1698 if (selbi && selbi->depth()==0)
1700 if (movingObj_orgPos != selbi->getBranchObj()->getAbsPos())
1702 QString pold=qpointFToString(movingObj_orgPos);
1703 QString pnow=qpointFToString(selbi->getBranchObj()->getAbsPos());
1710 QString("Move mapcenter %1 to position %2").arg(model->getObjectName(selbi)).arg(pnow));
1714 if (seli->isBranchLikeType() ) //(seli->getType() == TreeItem::Branch )
1715 { // A branch was moved
1716 LinkableMapObj* lmosel=NULL;
1717 lmosel=((MapItem*)seli)->getLMO();
1719 // save the position in case we link to mapcenter
1720 QPointF savePos=QPointF (lmosel->getAbsPos() );
1722 // Reset the temporary drawn link to the original one
1723 lmosel->unsetParObjTmp();
1725 // For Redo we may need to save original selection
1726 QString preSelStr=model->getSelectString(seli);
1728 if (dsti && objectMoved)
1730 // We have a destination, relink to that
1731 BranchObj* selbo=model->getSelectedBranchObj();
1733 QString preParStr=model->getSelectString (seli->parent() );
1734 QString preNum=QString::number (seli->num(),10);
1735 QString preDstParStr;
1737 if (e->modifiers() & Qt::ShiftModifier && dsti->parent() )
1739 preDstParStr=model->getSelectString (dsti->parent() );
1740 model->relinkBranch (
1742 (BranchItem*)dsti->parent(),
1743 ((BranchItem*)dsti)->num(),
1746 if (e->modifiers() & Qt::ControlModifier && dsti->parent() )
1749 preDstParStr=model->getSelectString (dsti->parent() );
1750 model->relinkBranch (
1752 (BranchItem*)dsti->parent(),
1753 ((BranchItem*)dsti)->num()+1,
1757 preDstParStr=model->getSelectString(dsti);
1758 model->relinkBranch (
1764 if (dsti->depth()==0) selbo->move (savePos);
1768 // No destination, undo temporary move
1770 if (seli->depth()==1)
1772 // The select string might be different _after_ moving around.
1773 // Therefor reposition and then use string of old selection, too
1774 model->reposition();
1776 QPointF rp(lmosel->getRelPos());
1777 if (rp != movingObj_orgRelPos)
1779 QString ps=qpointFToString(rp);
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));
1787 if (selbi->parentBranch()->getChildrenLayout() == BranchItem::FreePositioning)
1789 lmosel->setRelPos();
1790 model->reposition();
1795 // Draw the original link, before selection was moved around
1796 if (settings.value("/animation/use",true).toBool()
1798 // && distance (lmosel->getRelPos(),movingObj_orgRelPos)<3
1801 lmosel->setRelPos(); // calc relPos first for starting point
1803 model->startAnimation(
1805 lmosel->getRelPos(),
1809 model->reposition();
1813 // Finally resize scene, if needed
1819 // maybe we moved View: set old cursor
1820 setCursor (Qt::ArrowCursor);
1822 if (state!=EditingHeading) setState (Neutral); // Continue editing after double click!
1824 QGraphicsView::mouseReleaseEvent(e);
1827 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
1829 if (e->button() == Qt::LeftButton )
1831 QPointF p = mapToScene(e->pos());
1832 TreeItem *ti=findMapItem (p, NULL);
1833 LinkableMapObj *lmo;
1836 if (state==EditingHeading) editHeadingFinished();
1838 BranchItem* selbi=model->getSelectedBranch();
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
1852 void MapEditor::wheelEvent(QWheelEvent* e)
1854 if (e->modifiers() & Qt::ControlModifier && e->orientation()==Qt::Vertical)
1857 setZoomFactorTarget (zoomFactorTarget*1.15);
1859 setZoomFactorTarget (zoomFactorTarget*0.85);
1862 scrollBarPosAnimation.stop();
1863 QGraphicsView::wheelEvent (e);
1867 void MapEditor::focusOutEvent (QFocusEvent*)
1869 //qDebug()<<"ME::focusOutEvent"<<e->reason();
1870 if (state==EditingHeading) editHeadingFinished();
1873 void MapEditor::resizeEvent (QResizeEvent* e)
1875 QGraphicsView::resizeEvent( e );
1878 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
1880 //for (unsigned int i=0;event->format(i);i++) // Debug mime type
1881 // cerr << event->format(i) << endl;
1883 if (event->mimeData()->hasImage())
1884 event->acceptProposedAction();
1886 if (event->mimeData()->hasUrls())
1887 event->acceptProposedAction();
1890 void MapEditor::dragMoveEvent(QDragMoveEvent *)
1894 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
1899 void MapEditor::dropEvent(QDropEvent *event)
1901 BranchItem *selbi=model->getSelectedBranch();
1906 foreach (QString format,event->mimeData()->formats())
1907 qDebug()<< "MapEditor: Dropped format: "<<qPrintable (format);
1908 foreach (QUrl url,event->mimeData()->urls())
1910 qDebug()<< " URL-path:" <<url.path();
1911 qDebug()<< "URL-string:" <<url.toString();
1912 qDebug()<< " enc:" <<url.toEncoded();
1913 qDebug()<< " valid:" <<url.isValid();
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() << "===========================================";
1922 if (event->mimeData()->hasUrls())
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();
1929 QByteArray ba = event->mimeData()->urls().first().path().toLatin1();
1931 for (int i = 0; i < ba.count(); i++)
1932 if (ba.at(i) != 0) ba2.append(ba.at(i));
1937 BranchItem *bi = NULL;
1938 // Workaround to avoid adding empty branches
1941 if (url.startsWith("file://")) url.remove(0,7);
1943 #if defined(Q_OS_WIN32)
1944 if (url.startsWith("/")) url.remove(0,1);
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";
1955 bi = model->addNewBranch();
1959 if (url.endsWith(".vym", Qt::CaseInsensitive))
1960 model->setVymLink(url);
1964 model->setHeadingPlainText(url);
1967 model->select (bi->parent());
1973 event->acceptProposedAction();
1976 void MapEditor::setState (EditorState s)
1978 if (state!=Neutral && s!=Neutral)
1979 qWarning ()<<"MapEditor::setState switching directly from "<<state<<" to "<<s;
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;
1995 qDebug()<<"MapEditor: State "<<s<< " of "<<model->getMapName();
2000 MapEditor::EditorState MapEditor::getState()
2005 void MapEditor::updateSelection(QItemSelection nsel,QItemSelection dsel)
2007 QList <MapItem*> itemsSelected;
2008 QList <MapItem*> itemsDeselected;
2010 QItemSelection sel=model->getSelectionModel()->selection();
2011 foreach (QModelIndex ix,sel.indexes() )
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);
2020 foreach (QModelIndex ix,dsel.indexes() )
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);
2030 // Trim list of selection paths
2031 while (itemsSelected.count() < selPathList.count() )
2032 delete selPathList.takeFirst();
2035 while (itemsSelected.count() < selPathList.count() )
2036 delete selPathList.takeFirst();
2038 // Add additonal polygons
2039 QGraphicsPathItem *sp;
2040 while (itemsSelected.count() > selPathList.count() )
2042 sp = mapScene->addPath(
2044 QPen(selectionColor),
2047 selPathList.append (sp);
2051 // Reposition polygons
2052 for (int i=0; i<itemsSelected.count();++i)
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);
2062 // Reposition also LineEdit for heading during animation
2063 if (lineEdit) lineEdit->move (mo->getAbsPos().toPoint() );
2069 void MapEditor::updateData (const QModelIndex &sel)
2071 TreeItem *ti= static_cast<TreeItem*>(sel.internalPointer());
2074 qDebug() << "ME::updateData";
2077 qDebug() << " ti=NULL";
2080 qDebug() << " ti="<<ti;
2081 qDebug() << " h="<<ti->getHeadingPlain();
2084 if (ti && ti->isBranchLikeType())
2086 BranchObj *bo=(BranchObj*) ( ((MapItem*)ti)->getLMO());
2092 QList <QRectF> obstacles;
2094 BranchItem *cur=NULL;
2095 BranchItem *prev=NULL;
2096 model->nextBranch(cur,prev);
2099 if (!cur->hasHiddenExportParent())
2102 bo=(BranchObj*)(cur->getLMO());
2103 if (bo && bo->isVisibleObj())
2104 obstacles.append(bo->getBBox());
2106 model->nextBranch(cur,prev);
2108 winter->setObstacles(obstacles);
2112 void MapEditor::setSelectionColor (QColor col)
2115 selectionColor.setAlpha (220);
2116 QItemSelection sel=model->getSelectionModel()->selection();
2117 updateSelection(sel,sel);
2121 QColor MapEditor::getSelectionColor ()
2123 return selectionColor;