3 #include <q3filedialog.h>
10 #include "editxlinkdialog.h"
12 #include "exportxhtmldialog.h"
13 #include "extrainfodialog.h"
15 #include "linkablemapobj.h"
16 #include "mainwindow.h"
18 #include "texteditor.h"
19 #include "warningdialog.h"
20 #include "xml-freemind.h"
24 extern TextEditor *textEditor;
25 extern int statusbarTime;
26 extern Main *mainWindow;
27 extern QString tmpVymDir;
28 extern QString clipboardDir;
29 extern QString clipboardFile;
30 extern bool clipboardEmpty;
32 extern FlagRowObj *standardFlagsDefault;
34 extern QMenu* branchContextMenu;
35 extern QMenu* branchAddContextMenu;
36 extern QMenu* branchRemoveContextMenu;
37 extern QMenu* branchLinksContextMenu;
38 extern QMenu* branchXLinksContextMenuEdit;
39 extern QMenu* branchXLinksContextMenuFollow;
40 extern QMenu* floatimageContextMenu;
41 extern QMenu* canvasContextMenu;
44 extern Settings settings;
45 extern ImageIO imageIO;
47 extern QString vymName;
48 extern QString vymVersion;
50 extern QString iconPath;
51 extern QDir vymBaseDir;
52 extern QDir lastImageDir;
53 extern QDir lastFileDir;
55 int MapEditor::mapNum=0; // make instance
57 ///////////////////////////////////////////////////////////////////////
58 ///////////////////////////////////////////////////////////////////////
59 MapEditor::MapEditor( QWidget* parent) :
62 setObjectName ("MapEditor");
64 //cout << "Constructor ME "<<this<<endl;
68 mapScene= new QGraphicsScene(parent);
69 //mapScene= new QGraphicsScene(QRectF(0,0,width(),height()), parent);
70 mapScene->setBackgroundBrush (QBrush(Qt::white, Qt::SolidPattern));
73 model->setScene (mapScene);
74 model->setMapEditor (this);
80 defLinkColor=QColor (0,0,255);
81 defXLinkColor=QColor (180,180,180);
82 linkcolorhint=LinkableMapObj::DefaultColor;
83 linkstyle=LinkableMapObj::PolyParabel;
85 // Create bitmap cursors, platform dependant
86 HandOpenCursor=QCursor (QPixmap(iconPath+"cursorhandopen.png"),1,1);
87 PickColorCursor=QCursor ( QPixmap(iconPath+"cursorcolorpicker.png"), 5,27 );
88 CopyCursor=QCursor ( QPixmap(iconPath+"cursorcopy.png"), 1,1 );
89 XLinkCursor=QCursor ( QPixmap(iconPath+"cursorxlink.png"), 1,7 );
91 setFocusPolicy (Qt::StrongFocus);
100 xelection.setModel (model);
101 xelection.unselect();
104 defXLinkColor=QColor (230,230,230);
112 fileName=tr("unnamed");
115 stepsTotal=settings.readNumEntry("/mapeditor/stepsTotal",100);
116 undoSet.setEntry ("/history/stepsTotal",QString::number(stepsTotal));
117 mainWindow->updateHistory (undoSet);
119 // Initialize find routine
126 blockReposition=false;
127 blockSaveState=false;
131 // Create temporary files
138 setAcceptDrops (true);
143 autosaveTimer=new QTimer (this);
144 connect(autosaveTimer, SIGNAL(timeout()), this, SLOT(autosave()));
146 fileChangedTimer=new QTimer (this);
147 fileChangedTimer->start(3000);
148 connect(fileChangedTimer, SIGNAL(timeout()), this, SLOT(fileChanged()));
153 // Attributes //FIXME testing only...
156 attrTable= new AttributeTable();
158 ad=attrTable->addKey (k,StringList);
162 sl <<"val 1"<<"val 2"<< "val 3";
163 ad->setValue (QVariant (sl));
165 //attrTable->addValue ("Key A","P 1");
166 //attrTable->addValue ("Key A","P 2");
167 //attrTable->addValue ("Key A","P 3");
168 //attrTable->addValue ("Key A","P 4");
170 ad=attrTable->addKey (k,FreeString);
173 //attrTable->addValue ("Key B","w1");
174 //attrTable->addValue ("Key B","w2");
176 k="C - UniqueString";
177 ad=attrTable->addKey (k,UniqueString);
180 //attrTable->addKey ("Key Prio");
181 //attrTable->addValue ("Key Prio","Prio 1");
182 //attrTable->addValue ("Key Prio","Prio 2");
186 MapEditor::~MapEditor()
188 //cout <<"Destructor MapEditor "<<mapName.toStdString()<<endl;
189 fileChangedTimer->stop();
192 // tmpMapDir is in tmpVymDir, so it gets removed automagically when vym closes
194 //removeDir(QDir(tmpMapDir));
198 VymModel* MapEditor::getModel()
203 QGraphicsScene * MapEditor::getScene()
208 MapEditor::State MapEditor::getState()
213 void MapEditor::setStateEditHeading(bool s)
217 if (state==Idle) state=EditHeading;
223 bool MapEditor::isRepositionBlocked()
225 return blockReposition;
228 void MapEditor::setSaveStateBlocked(bool b)
233 bool MapEditor::isSelectBlocked()
235 if (state==EditHeading)
241 QString MapEditor::getName (const LinkableMapObj *lmo)
244 if (!lmo) return QString("Error: NULL has no name!");
246 if ((typeid(*lmo) == typeid(BranchObj) ||
247 typeid(*lmo) == typeid(MapCenterObj)))
250 s=(((BranchObj*)lmo)->getHeading());
251 if (s=="") s="unnamed";
252 if ((typeid(*lmo) == typeid(BranchObj) ) )
253 return QString("branch (%1)").arg(s);
254 return QString("mapcenter (%1)").arg(s);
256 if ((typeid(*lmo) == typeid(FloatImageObj) ))
257 return QString ("floatimage [%1]").arg(((FloatImageObj*)lmo)->getOriginalFilename());
258 return QString("Unknown type has no name!");
261 void MapEditor::makeTmpDirs()
263 // Create unique temporary directories
264 tmpMapDir = tmpVymDir+QString("/mapeditor-%1").arg(mapNum);
265 histPath = tmpMapDir+"/history";
270 QString MapEditor::saveToDir(const QString &tmpdir, const QString &prefix, bool writeflags, const QPointF &offset, LinkableMapObj *saveSel)
272 // tmpdir temporary directory to which data will be written
273 // prefix mapname, which will be appended to images etc.
274 // writeflags Only write flags for "real" save of map, not undo
275 // offset offset of bbox of whole map in scene.
276 // Needed for XML export
282 case LinkableMapObj::Line:
285 case LinkableMapObj::Parabel:
288 case LinkableMapObj::PolyLine:
292 ls="StylePolyParabel";
296 QString s="<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE vymmap>\n";
298 if (linkcolorhint==LinkableMapObj::HeadingColor)
299 colhint=attribut("linkColorHint","HeadingColor");
301 QString mapAttr=attribut("version",vymVersion);
303 mapAttr+= attribut("author",model->getAuthor()) +
304 attribut("comment",model->getComment()) +
305 attribut("date",model->getDate()) +
306 attribut("branchCount", QString().number(model->countBranches())) +
308 attribut("backgroundColor", mapScene->backgroundBrush().color().name() ) +
309 attribut("selectionColor", xelection.getColor().name() ) +
310 attribut("linkStyle", ls ) +
311 attribut("linkColor", defLinkColor.name() ) +
312 attribut("defXLinkColor", defXLinkColor.name() ) +
313 attribut("defXLinkWidth", QString().setNum(defXLinkWidth,10) ) +
315 s+=beginElement("vymmap",mapAttr);
318 // Find the used flags while traversing the tree
319 standardFlagsDefault->resetUsedCounter();
321 // Reset the counters before saving
322 // TODO constr. of FIO creates lots of objects, better do this in some other way...
323 FloatImageObj (mapScene).resetSaveCounter();
325 // Build xml recursivly
327 // Save complete map, if saveSel not set
328 s+=model->saveToDir(tmpdir,prefix,writeflags,offset);
331 if ( typeid (*saveSel) == typeid (MapCenterObj))
333 s+=((MapCenterObj*)saveSel)->saveToDir(tmpdir,prefix,0,offset);
334 else if ( typeid(*saveSel) == typeid(BranchObj) )
336 s+=((BranchObj*)saveSel)->saveToDir(tmpdir,prefix,offset);
339 if ( typeid(*saveSel) == typeid(FloatImageObj) )
341 s+=((FloatImageObj*)saveSel)->saveToDir(tmpdir,prefix);
345 // Save local settings
346 s+=settings.getDataXML (destPath);
349 if (!xelection.isEmpty() && !saveSel )
350 s+=valueElement("select",xelection.getSelectString());
353 s+=endElement("vymmap");
356 standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags);
360 QString MapEditor::getHistoryDir()
362 QString histName(QString("history-%1").arg(curStep));
363 return (tmpMapDir+"/"+histName);
366 void MapEditor::saveState(const SaveMode &savemode, const QString &undoSelection, const QString &undoCom, const QString &redoSelection, const QString &redoCom, const QString &comment, LinkableMapObj *saveSel)
368 sendData(redoCom); //FIXME testing
373 if (blockSaveState) return;
375 if (debug) cout << "ME::saveState() for "<<qPrintable (mapName)<<endl;
377 // Find out current undo directory
378 if (undosAvail<stepsTotal) undosAvail++;
380 if (curStep>stepsTotal) curStep=1;
382 QString backupXML="";
383 QString histDir=getHistoryDir();
384 QString bakMapPath=histDir+"/map.xml";
386 // Create histDir if not available
389 makeSubDirs (histDir);
391 // Save depending on how much needs to be saved
393 backupXML=saveToDir (histDir,mapName+"-",false, QPointF (),saveSel);
395 QString undoCommand="";
396 if (savemode==UndoCommand)
400 else if (savemode==PartOfMap )
403 undoCommand.replace ("PATH",bakMapPath);
406 if (!backupXML.isEmpty())
407 // Write XML Data to disk
408 saveStringToDisk (bakMapPath,backupXML);
410 // We would have to save all actions in a tree, to keep track of
411 // possible redos after a action. Possible, but we are too lazy: forget about redos.
414 // Write the current state to disk
415 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
416 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
417 undoSet.setEntry ("/history/curStep",QString::number(curStep));
418 undoSet.setEntry (QString("/history/step-%1/undoCommand").arg(curStep),undoCommand);
419 undoSet.setEntry (QString("/history/step-%1/undoSelection").arg(curStep),undoSelection);
420 undoSet.setEntry (QString("/history/step-%1/redoCommand").arg(curStep),redoCom);
421 undoSet.setEntry (QString("/history/step-%1/redoSelection").arg(curStep),redoSelection);
422 undoSet.setEntry (QString("/history/step-%1/comment").arg(curStep),comment);
423 undoSet.setEntry (QString("/history/version"),vymVersion);
424 undoSet.writeSettings(histPath);
428 // TODO remove after testing
429 //cout << " into="<< histPath.toStdString()<<endl;
430 cout << " stepsTotal="<<stepsTotal<<
431 ", undosAvail="<<undosAvail<<
432 ", redosAvail="<<redosAvail<<
433 ", curStep="<<curStep<<endl;
434 cout << " ---------------------------"<<endl;
435 cout << " comment="<<comment.toStdString()<<endl;
436 cout << " undoCom="<<undoCommand.toStdString()<<endl;
437 cout << " undoSel="<<undoSelection.toStdString()<<endl;
438 cout << " redoCom="<<redoCom.toStdString()<<endl;
439 cout << " redoSel="<<redoSelection.toStdString()<<endl;
440 if (saveSel) cout << " saveSel="<<qPrintable (model->getSelectString(saveSel))<<endl;
441 cout << " ---------------------------"<<endl;
444 mainWindow->updateHistory (undoSet);
450 void MapEditor::saveStateChangingPart(LinkableMapObj *undoSel, LinkableMapObj* redoSel, const QString &rc, const QString &comment)
452 // save the selected part of the map, Undo will replace part of map
453 QString undoSelection="";
455 undoSelection=model->getSelectString(undoSel);
457 qWarning ("MapEditor::saveStateChangingPart no undoSel given!");
458 QString redoSelection="";
460 redoSelection=model->getSelectString(undoSel);
462 qWarning ("MapEditor::saveStateChangingPart no redoSel given!");
465 saveState (PartOfMap,
466 undoSelection, "addMapReplace (\"PATH\")",
472 void MapEditor::saveStateRemovingPart(LinkableMapObj *redoSel, const QString &comment)
476 qWarning ("MapEditor::saveStateRemovingPart no redoSel given!");
480 QString undoSelection;
481 QString redoSelection=model->getSelectString(redoSel);
482 if (typeid(*redoSel) == typeid(BranchObj) )
484 undoSelection=model->getSelectString (redoSel->getParObj());
485 // save the selected branch of the map, Undo will insert part of map
486 saveState (PartOfMap,
487 undoSelection, QString("addMapInsert (\"PATH\",%1)").arg(((BranchObj*)redoSel)->getNum()),
488 redoSelection, "delete ()",
492 if (typeid(*redoSel) == typeid(MapCenterObj) )
494 undoSelection.clear();
495 // save the selected branch of the map, Undo will insert part of map
496 saveState (PartOfMap,
497 undoSelection, QString("addMapInsert (\"PATH\")"),
498 redoSelection, "delete ()",
505 void MapEditor::saveState(LinkableMapObj *undoSel, const QString &uc, LinkableMapObj *redoSel, const QString &rc, const QString &comment)
507 // "Normal" savestate: save commands, selections and comment
508 // so just save commands for undo and redo
509 // and use current selection
511 QString redoSelection="";
512 if (redoSel) redoSelection=model->getSelectString(redoSel);
513 QString undoSelection="";
514 if (undoSel) undoSelection=model->getSelectString(undoSel);
516 saveState (UndoCommand,
523 void MapEditor::saveState(const QString &undoSel, const QString &uc, const QString &redoSel, const QString &rc, const QString &comment)
525 // "Normal" savestate: save commands, selections and comment
526 // so just save commands for undo and redo
527 // and use current selection
528 saveState (UndoCommand,
535 void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment)
537 // "Normal" savestate applied to model (no selection needed):
538 // save commands and comment
539 saveState (UndoCommand,
547 void MapEditor::parseAtom(const QString &atom)
549 BranchObj *selb=xelection.getBranch();
555 // Split string s into command and parameters
556 parser.parseAtom (atom);
557 QString com=parser.getCommand();
560 /////////////////////////////////////////////////////////////////////
561 if (com=="addBranch")
563 if (xelection.isEmpty())
565 parser.setError (Aborted,"Nothing selected");
568 parser.setError (Aborted,"Type of selection is not a branch");
573 if (parser.checkParCount(pl))
575 if (parser.parCount()==0)
579 n=parser.parInt (ok,0);
580 if (ok ) addNewBranch (n);
584 /////////////////////////////////////////////////////////////////////
585 } else if (com=="addBranchBefore")
587 if (xelection.isEmpty())
589 parser.setError (Aborted,"Nothing selected");
592 parser.setError (Aborted,"Type of selection is not a branch");
595 if (parser.parCount()==0)
597 addNewBranchBefore ();
600 /////////////////////////////////////////////////////////////////////
601 } else if (com==QString("addMapCenter"))
603 if (parser.checkParCount(2))
605 x=parser.parDouble (ok,0);
608 y=parser.parDouble (ok,1);
609 if (ok) model->addMapCenter (QPointF(x,y));
612 /////////////////////////////////////////////////////////////////////
613 } else if (com==QString("addMapReplace"))
615 if (xelection.isEmpty())
617 parser.setError (Aborted,"Nothing selected");
620 parser.setError (Aborted,"Type of selection is not a branch");
621 } else if (parser.checkParCount(1))
623 //s=parser.parString (ok,0); // selection
624 t=parser.parString (ok,0); // path to map
625 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
626 addMapReplaceInt(model->getSelectString(selb),t);
628 /////////////////////////////////////////////////////////////////////
629 } else if (com==QString("addMapInsert"))
631 if (parser.parCount()==2)
633 if (xelection.isEmpty())
635 parser.setError (Aborted,"Nothing selected");
638 parser.setError (Aborted,"Type of selection is not a branch");
641 t=parser.parString (ok,0); // path to map
642 n=parser.parInt(ok,1); // position
643 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
644 addMapInsertInt(t,n);
646 } else if (parser.parCount ()==1)
648 t=parser.parString (ok,0); // path to map
649 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
652 /////////////////////////////////////////////////////////////////////
653 } else if (com=="clearFlags")
655 if (xelection.isEmpty() )
657 parser.setError (Aborted,"Nothing selected");
660 parser.setError (Aborted,"Type of selection is not a branch");
661 } else if (parser.checkParCount(0))
663 selb->clearStandardFlags();
664 selb->updateFlagsToolbar();
666 /////////////////////////////////////////////////////////////////////
667 } else if (com=="colorBranch")
669 if (xelection.isEmpty())
671 parser.setError (Aborted,"Nothing selected");
674 parser.setError (Aborted,"Type of selection is not a branch");
675 } else if (parser.checkParCount(1))
677 QColor c=parser.parColor (ok,0);
678 if (ok) colorBranch (c);
680 /////////////////////////////////////////////////////////////////////
681 } else if (com=="colorSubtree")
683 if (xelection.isEmpty())
685 parser.setError (Aborted,"Nothing selected");
688 parser.setError (Aborted,"Type of selection is not a branch");
689 } else if (parser.checkParCount(1))
691 QColor c=parser.parColor (ok,0);
692 if (ok) colorSubtree (c);
694 /////////////////////////////////////////////////////////////////////
695 } else if (com=="copy")
697 if (xelection.isEmpty())
699 parser.setError (Aborted,"Nothing selected");
702 parser.setError (Aborted,"Type of selection is not a branch");
703 } else if (parser.checkParCount(0))
705 //FIXME missing action for copy
707 /////////////////////////////////////////////////////////////////////
708 } else if (com=="cut")
710 if (xelection.isEmpty())
712 parser.setError (Aborted,"Nothing selected");
713 } else if ( xelection.type()!=Selection::Branch &&
714 xelection.type()!=Selection::MapCenter &&
715 xelection.type()!=Selection::FloatImage )
717 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
718 } else if (parser.checkParCount(0))
722 /////////////////////////////////////////////////////////////////////
723 } else if (com=="delete")
725 if (xelection.isEmpty())
727 parser.setError (Aborted,"Nothing selected");
729 /*else if (xelection.type() != Selection::Branch && xelection.type() != Selection::FloatImage )
731 parser.setError (Aborted,"Type of selection is wrong.");
734 else if (parser.checkParCount(0))
738 /////////////////////////////////////////////////////////////////////
739 } else if (com=="deleteKeepChilds")
741 if (xelection.isEmpty())
743 parser.setError (Aborted,"Nothing selected");
746 parser.setError (Aborted,"Type of selection is not a branch");
747 } else if (parser.checkParCount(0))
751 /////////////////////////////////////////////////////////////////////
752 } else if (com=="deleteChilds")
754 if (xelection.isEmpty())
756 parser.setError (Aborted,"Nothing selected");
759 parser.setError (Aborted,"Type of selection is not a branch");
760 } else if (parser.checkParCount(0))
764 /////////////////////////////////////////////////////////////////////
765 } else if (com=="exportASCII")
769 if (parser.parCount()>=1)
770 // Hey, we even have a filename
771 fname=parser.parString(ok,0);
774 parser.setError (Aborted,"Could not read filename");
777 exportASCII (fname,false);
779 /////////////////////////////////////////////////////////////////////
780 } else if (com=="exportImage")
784 if (parser.parCount()>=2)
785 // Hey, we even have a filename
786 fname=parser.parString(ok,0);
789 parser.setError (Aborted,"Could not read filename");
792 QString format="PNG";
793 if (parser.parCount()>=2)
795 format=parser.parString(ok,1);
797 exportImage (fname,false,format);
799 /////////////////////////////////////////////////////////////////////
800 } else if (com=="exportXHTML")
804 if (parser.parCount()>=2)
805 // Hey, we even have a filename
806 fname=parser.parString(ok,1);
809 parser.setError (Aborted,"Could not read filename");
812 exportXHTML (fname,false);
814 /////////////////////////////////////////////////////////////////////
815 } else if (com=="exportXML")
819 if (parser.parCount()>=2)
820 // Hey, we even have a filename
821 fname=parser.parString(ok,1);
824 parser.setError (Aborted,"Could not read filename");
827 exportXML (fname,false);
829 /////////////////////////////////////////////////////////////////////
830 } else if (com=="importDir")
832 if (xelection.isEmpty())
834 parser.setError (Aborted,"Nothing selected");
837 parser.setError (Aborted,"Type of selection is not a branch");
838 } else if (parser.checkParCount(1))
840 s=parser.parString(ok,0);
841 if (ok) importDirInt(s);
843 /////////////////////////////////////////////////////////////////////
844 } else if (com=="linkTo")
846 if (xelection.isEmpty())
848 parser.setError (Aborted,"Nothing selected");
851 if (parser.checkParCount(4))
853 // 0 selectstring of parent
854 // 1 num in parent (for branches)
855 // 2,3 x,y of mainbranch or mapcenter
856 s=parser.parString(ok,0);
857 LinkableMapObj *dst=model->findObjBySelect (s);
860 if (typeid(*dst) == typeid(BranchObj) )
862 // Get number in parent
863 n=parser.parInt (ok,1);
866 selb->linkTo ((BranchObj*)(dst),n);
869 } else if (typeid(*dst) == typeid(MapCenterObj) )
871 selb->linkTo ((BranchObj*)(dst),-1);
872 // Get coordinates of mainbranch
873 x=parser.parDouble(ok,2);
876 y=parser.parDouble(ok,3);
886 } else if ( xelection.type() == Selection::FloatImage)
888 if (parser.checkParCount(1))
890 // 0 selectstring of parent
891 s=parser.parString(ok,0);
892 LinkableMapObj *dst=model->findObjBySelect (s);
895 if (typeid(*dst) == typeid(BranchObj) ||
896 typeid(*dst) == typeid(MapCenterObj))
897 linkTo (model->getSelectString(dst));
899 parser.setError (Aborted,"Destination is not a branch");
902 parser.setError (Aborted,"Type of selection is not a floatimage or branch");
903 /////////////////////////////////////////////////////////////////////
904 } else if (com=="loadImage")
906 if (xelection.isEmpty())
908 parser.setError (Aborted,"Nothing selected");
911 parser.setError (Aborted,"Type of selection is not a branch");
912 } else if (parser.checkParCount(1))
914 s=parser.parString(ok,0);
915 if (ok) loadFloatImageInt (s);
917 /////////////////////////////////////////////////////////////////////
918 } else if (com=="moveBranchUp")
920 if (xelection.isEmpty() )
922 parser.setError (Aborted,"Nothing selected");
925 parser.setError (Aborted,"Type of selection is not a branch");
926 } else if (parser.checkParCount(0))
930 /////////////////////////////////////////////////////////////////////
931 } else if (com=="moveBranchDown")
933 if (xelection.isEmpty() )
935 parser.setError (Aborted,"Nothing selected");
938 parser.setError (Aborted,"Type of selection is not a branch");
939 } else if (parser.checkParCount(0))
943 /////////////////////////////////////////////////////////////////////
944 } else if (com=="move")
946 if (xelection.isEmpty() )
948 parser.setError (Aborted,"Nothing selected");
949 } else if ( xelection.type()!=Selection::Branch &&
950 xelection.type()!=Selection::MapCenter &&
951 xelection.type()!=Selection::FloatImage )
953 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
954 } else if (parser.checkParCount(2))
956 x=parser.parDouble (ok,0);
959 y=parser.parDouble (ok,1);
963 /////////////////////////////////////////////////////////////////////
964 } else if (com=="moveRel")
966 if (xelection.isEmpty() )
968 parser.setError (Aborted,"Nothing selected");
969 } else if ( xelection.type()!=Selection::Branch &&
970 xelection.type()!=Selection::MapCenter &&
971 xelection.type()!=Selection::FloatImage )
973 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
974 } else if (parser.checkParCount(2))
976 x=parser.parDouble (ok,0);
979 y=parser.parDouble (ok,1);
980 if (ok) moveRel (x,y);
983 /////////////////////////////////////////////////////////////////////
984 } else if (com=="nop")
986 /////////////////////////////////////////////////////////////////////
987 } else if (com=="paste")
989 if (xelection.isEmpty() )
991 parser.setError (Aborted,"Nothing selected");
994 parser.setError (Aborted,"Type of selection is not a branch");
995 } else if (parser.checkParCount(1))
997 n=parser.parInt (ok,0);
998 if (ok) pasteNoSave(n);
1000 /////////////////////////////////////////////////////////////////////
1001 } else if (com=="qa")
1003 if (xelection.isEmpty() )
1005 parser.setError (Aborted,"Nothing selected");
1008 parser.setError (Aborted,"Type of selection is not a branch");
1009 } else if (parser.checkParCount(4))
1012 c=parser.parString (ok,0);
1015 parser.setError (Aborted,"No comment given");
1018 s=parser.parString (ok,1);
1021 parser.setError (Aborted,"First parameter is not a string");
1024 t=parser.parString (ok,2);
1027 parser.setError (Aborted,"Condition is not a string");
1030 u=parser.parString (ok,3);
1033 parser.setError (Aborted,"Third parameter is not a string");
1038 parser.setError (Aborted,"Unknown type: "+s);
1043 parser.setError (Aborted,"Unknown operator: "+t);
1048 parser.setError (Aborted,"Type of selection is not a branch");
1051 if (selb->getHeading() == u)
1053 cout << "PASSED: " << qPrintable (c) << endl;
1056 cout << "FAILED: " << qPrintable (c) << endl;
1066 /////////////////////////////////////////////////////////////////////
1067 } else if (com=="saveImage")
1069 FloatImageObj *fio=xelection.getFloatImage();
1072 parser.setError (Aborted,"Type of selection is not an image");
1073 } else if (parser.checkParCount(2))
1075 s=parser.parString(ok,0);
1078 t=parser.parString(ok,1);
1079 if (ok) saveFloatImageInt (fio,t,s);
1082 /////////////////////////////////////////////////////////////////////
1083 } else if (com=="scroll")
1085 if (xelection.isEmpty() )
1087 parser.setError (Aborted,"Nothing selected");
1090 parser.setError (Aborted,"Type of selection is not a branch");
1091 } else if (parser.checkParCount(0))
1093 if (!scrollBranch (selb))
1094 parser.setError (Aborted,"Could not scroll branch");
1096 /////////////////////////////////////////////////////////////////////
1097 } else if (com=="select")
1099 if (parser.checkParCount(1))
1101 s=parser.parString(ok,0);
1104 /////////////////////////////////////////////////////////////////////
1105 } else if (com=="selectLastBranch")
1107 if (xelection.isEmpty() )
1109 parser.setError (Aborted,"Nothing selected");
1112 parser.setError (Aborted,"Type of selection is not a branch");
1113 } else if (parser.checkParCount(0))
1115 BranchObj *bo=selb->getLastBranch();
1117 parser.setError (Aborted,"Could not select last branch");
1121 /////////////////////////////////////////////////////////////////////
1122 } else if (com=="selectLastImage")
1124 if (xelection.isEmpty() )
1126 parser.setError (Aborted,"Nothing selected");
1129 parser.setError (Aborted,"Type of selection is not a branch");
1130 } else if (parser.checkParCount(0))
1132 FloatImageObj *fio=selb->getLastFloatImage();
1134 parser.setError (Aborted,"Could not select last image");
1138 /////////////////////////////////////////////////////////////////////
1139 } else if (com=="selectLatestAdded")
1141 if (latestSelection.isEmpty() )
1143 parser.setError (Aborted,"No latest added object");
1146 if (!select (latestSelection))
1147 parser.setError (Aborted,"Could not select latest added object "+latestSelection);
1149 /////////////////////////////////////////////////////////////////////
1150 } else if (com=="setFrameType")
1152 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1154 parser.setError (Aborted,"Type of selection does not allow setting frame type");
1156 else if (parser.checkParCount(1))
1158 s=parser.parString(ok,0);
1159 if (ok) setFrameType (s);
1161 /////////////////////////////////////////////////////////////////////
1162 } else if (com=="setFramePenColor")
1164 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1166 parser.setError (Aborted,"Type of selection does not allow setting of pen color");
1168 else if (parser.checkParCount(1))
1170 QColor c=parser.parColor(ok,0);
1171 if (ok) setFramePenColor (c);
1173 /////////////////////////////////////////////////////////////////////
1174 } else if (com=="setFrameBrushColor")
1176 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1178 parser.setError (Aborted,"Type of selection does not allow setting brush color");
1180 else if (parser.checkParCount(1))
1182 QColor c=parser.parColor(ok,0);
1183 if (ok) setFrameBrushColor (c);
1185 /////////////////////////////////////////////////////////////////////
1186 } else if (com=="setFramePadding")
1188 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1190 parser.setError (Aborted,"Type of selection does not allow setting frame padding");
1192 else if (parser.checkParCount(1))
1194 n=parser.parInt(ok,0);
1195 if (ok) setFramePadding(n);
1197 /////////////////////////////////////////////////////////////////////
1198 } else if (com=="setFrameBorderWidth")
1200 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1202 parser.setError (Aborted,"Type of selection does not allow setting frame border width");
1204 else if (parser.checkParCount(1))
1206 n=parser.parInt(ok,0);
1207 if (ok) setFrameBorderWidth (n);
1209 /////////////////////////////////////////////////////////////////////
1210 } else if (com=="setMapAuthor")
1212 if (parser.checkParCount(1))
1214 s=parser.parString(ok,0);
1215 if (ok) setMapAuthor (s);
1217 /////////////////////////////////////////////////////////////////////
1218 } else if (com=="setMapComment")
1220 if (parser.checkParCount(1))
1222 s=parser.parString(ok,0);
1223 if (ok) setMapComment(s);
1225 /////////////////////////////////////////////////////////////////////
1226 } else if (com=="setMapBackgroundColor")
1228 if (xelection.isEmpty() )
1230 parser.setError (Aborted,"Nothing selected");
1231 } else if (! xelection.getBranch() )
1233 parser.setError (Aborted,"Type of selection is not a branch");
1234 } else if (parser.checkParCount(1))
1236 QColor c=parser.parColor (ok,0);
1237 if (ok) setMapBackgroundColor (c);
1239 /////////////////////////////////////////////////////////////////////
1240 } else if (com=="setMapDefLinkColor")
1242 if (xelection.isEmpty() )
1244 parser.setError (Aborted,"Nothing selected");
1247 parser.setError (Aborted,"Type of selection is not a branch");
1248 } else if (parser.checkParCount(1))
1250 QColor c=parser.parColor (ok,0);
1251 if (ok) setMapDefLinkColor (c);
1253 /////////////////////////////////////////////////////////////////////
1254 } else if (com=="setMapLinkStyle")
1256 if (parser.checkParCount(1))
1258 s=parser.parString (ok,0);
1259 if (ok) setMapLinkStyle(s);
1261 /////////////////////////////////////////////////////////////////////
1262 } else if (com=="setHeading")
1264 if (xelection.isEmpty() )
1266 parser.setError (Aborted,"Nothing selected");
1269 parser.setError (Aborted,"Type of selection is not a branch");
1270 } else if (parser.checkParCount(1))
1272 s=parser.parString (ok,0);
1276 /////////////////////////////////////////////////////////////////////
1277 } else if (com=="setHideExport")
1279 if (xelection.isEmpty() )
1281 parser.setError (Aborted,"Nothing selected");
1282 } else if (xelection.type()!=Selection::Branch && xelection.type() != Selection::MapCenter &&xelection.type()!=Selection::FloatImage)
1284 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
1285 } else if (parser.checkParCount(1))
1287 b=parser.parBool(ok,0);
1288 if (ok) setHideExport (b);
1290 /////////////////////////////////////////////////////////////////////
1291 } else if (com=="setIncludeImagesHorizontally")
1293 if (xelection.isEmpty() )
1295 parser.setError (Aborted,"Nothing selected");
1298 parser.setError (Aborted,"Type of selection is not a branch");
1299 } else if (parser.checkParCount(1))
1301 b=parser.parBool(ok,0);
1302 if (ok) setIncludeImagesHor(b);
1304 /////////////////////////////////////////////////////////////////////
1305 } else if (com=="setIncludeImagesVertically")
1307 if (xelection.isEmpty() )
1309 parser.setError (Aborted,"Nothing selected");
1312 parser.setError (Aborted,"Type of selection is not a branch");
1313 } else if (parser.checkParCount(1))
1315 b=parser.parBool(ok,0);
1316 if (ok) setIncludeImagesVer(b);
1318 /////////////////////////////////////////////////////////////////////
1319 } else if (com=="setHideLinkUnselected")
1321 if (xelection.isEmpty() )
1323 parser.setError (Aborted,"Nothing selected");
1324 } else if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1326 parser.setError (Aborted,"Type of selection does not allow hiding the link");
1327 } else if (parser.checkParCount(1))
1329 b=parser.parBool(ok,0);
1330 if (ok) setHideLinkUnselected(b);
1332 /////////////////////////////////////////////////////////////////////
1333 } else if (com=="setSelectionColor")
1335 if (parser.checkParCount(1))
1337 QColor c=parser.parColor (ok,0);
1338 if (ok) setSelectionColorInt (c);
1340 /////////////////////////////////////////////////////////////////////
1341 } else if (com=="setURL")
1343 if (xelection.isEmpty() )
1345 parser.setError (Aborted,"Nothing selected");
1348 parser.setError (Aborted,"Type of selection is not a branch");
1349 } else if (parser.checkParCount(1))
1351 s=parser.parString (ok,0);
1354 /////////////////////////////////////////////////////////////////////
1355 } else if (com=="setVymLink")
1357 if (xelection.isEmpty() )
1359 parser.setError (Aborted,"Nothing selected");
1362 parser.setError (Aborted,"Type of selection is not a branch");
1363 } else if (parser.checkParCount(1))
1365 s=parser.parString (ok,0);
1366 if (ok) setVymLinkInt(s);
1369 /////////////////////////////////////////////////////////////////////
1370 else if (com=="setFlag")
1372 if (xelection.isEmpty() )
1374 parser.setError (Aborted,"Nothing selected");
1377 parser.setError (Aborted,"Type of selection is not a branch");
1378 } else if (parser.checkParCount(1))
1380 s=parser.parString(ok,0);
1383 selb->activateStandardFlag(s);
1384 selb->updateFlagsToolbar();
1387 /////////////////////////////////////////////////////////////////////
1388 } else if (com=="setFrameType")
1390 if (xelection.isEmpty() )
1392 parser.setError (Aborted,"Nothing selected");
1395 parser.setError (Aborted,"Type of selection is not a branch");
1396 } else if (parser.checkParCount(1))
1398 s=parser.parString(ok,0);
1402 /////////////////////////////////////////////////////////////////////
1403 } else if (com=="sortChildren")
1405 if (xelection.isEmpty() )
1407 parser.setError (Aborted,"Nothing selected");
1410 parser.setError (Aborted,"Type of selection is not a branch");
1411 } else if (parser.checkParCount(0))
1415 /////////////////////////////////////////////////////////////////////
1416 } else if (com=="toggleFlag")
1418 if (xelection.isEmpty() )
1420 parser.setError (Aborted,"Nothing selected");
1423 parser.setError (Aborted,"Type of selection is not a branch");
1424 } else if (parser.checkParCount(1))
1426 s=parser.parString(ok,0);
1429 selb->toggleStandardFlag(s);
1430 selb->updateFlagsToolbar();
1433 /////////////////////////////////////////////////////////////////////
1434 } else if (com=="unscroll")
1436 if (xelection.isEmpty() )
1438 parser.setError (Aborted,"Nothing selected");
1441 parser.setError (Aborted,"Type of selection is not a branch");
1442 } else if (parser.checkParCount(0))
1444 if (!unscrollBranch (selb))
1445 parser.setError (Aborted,"Could not unscroll branch");
1447 /////////////////////////////////////////////////////////////////////
1448 } else if (com=="unscrollChilds")
1450 if (xelection.isEmpty() )
1452 parser.setError (Aborted,"Nothing selected");
1455 parser.setError (Aborted,"Type of selection is not a branch");
1456 } else if (parser.checkParCount(0))
1460 /////////////////////////////////////////////////////////////////////
1461 } else if (com=="unsetFlag")
1463 if (xelection.isEmpty() )
1465 parser.setError (Aborted,"Nothing selected");
1468 parser.setError (Aborted,"Type of selection is not a branch");
1469 } else if (parser.checkParCount(1))
1471 s=parser.parString(ok,0);
1474 selb->deactivateStandardFlag(s);
1475 selb->updateFlagsToolbar();
1479 parser.setError (Aborted,"Unknown command");
1482 if (parser.errorLevel()==NoError)
1484 // setChanged(); FIXME should not be called e.g. for export?!
1485 model->reposition();
1489 // TODO Error handling
1490 qWarning("MapEditor::parseAtom: Error!");
1491 qWarning(parser.errorMessage());
1495 void MapEditor::runScript (QString script)
1497 parser.setScript (script);
1499 while (parser.next() )
1500 parseAtom(parser.getAtom());
1503 bool MapEditor::isDefault()
1508 bool MapEditor::hasChanged()
1513 void MapEditor::setChanged()
1517 autosaveTimer->start(settings.value("/mainwindow/autosave/ms/",300000).toInt());
1518 fileChangedTimer->start (3000);
1527 void MapEditor::closeMap()
1529 // Unselect before disabling the toolbar actions
1530 if (!xelection.isEmpty() ) xelection.unselect();
1535 // close(); FIXME needed?
1538 void MapEditor::setFilePath(QString fpath, QString destname)
1540 if (fpath.isEmpty() || fpath=="")
1547 filePath=fpath; // becomes absolute path
1548 fileName=fpath; // gets stripped of path
1549 destPath=destname; // needed for vymlinks and during load to reset fileChangedTime
1551 // If fpath is not an absolute path, complete it
1552 filePath=QDir(fpath).absPath();
1553 fileDir=filePath.left (1+filePath.findRev ("/"));
1555 // Set short name, too. Search from behind:
1556 int i=fileName.findRev("/");
1557 if (i>=0) fileName=fileName.remove (0,i+1);
1559 // Forget the .vym (or .xml) for name of map
1560 mapName=fileName.left(fileName.findRev(".",-1,true) );
1564 void MapEditor::setFilePath(QString fpath)
1566 setFilePath (fpath,fpath);
1569 QString MapEditor::getFilePath()
1574 QString MapEditor::getFileName()
1579 QString MapEditor::getMapName()
1584 QString MapEditor::getDestPath()
1589 ErrorCode MapEditor::load (QString fname, const LoadMode &lmode, const FileType &ftype)
1591 ErrorCode err=success;
1593 parseBaseHandler *handler;
1597 case VymMap: handler=new parseVYMHandler; break;
1598 case FreemindMap : handler=new parseFreemindHandler; break;
1600 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1601 "Unknown FileType in MapEditor::load()");
1605 // Save original zip state, important for inserting complete maps
1606 bool zipped_org=zipped;
1611 model->setMapEditor(this);
1612 // (map state is set later at end of load...)
1615 BranchObj *bo=xelection.getBranch();
1616 if (!bo) return aborted;
1617 if (lmode==ImportAdd)
1618 saveStateChangingPart(
1621 QString("addMapInsert (%1)").arg(fname),
1622 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1624 saveStateChangingPart(
1627 QString("addMapReplace(%1)").arg(fname),
1628 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1632 // Create temporary directory for packing
1634 QString tmpZipDir=makeTmpDir (ok,"vym-pack");
1637 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1638 tr("Couldn't create temporary directory before load\n"));
1642 // Try to unzip file
1643 err=unzipDir (tmpZipDir,fname);
1653 // Look for mapname.xml
1654 xmlfile= fname.left(fname.findRev(".",-1,true));
1655 xmlfile=xmlfile.section( '/', -1 );
1656 QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
1657 if (!mfile.exists() )
1659 // mapname.xml does not exist, well,
1660 // maybe someone renamed the mapname.vym file...
1661 // Try to find any .xml in the toplevel
1662 // directory of the .vym file
1663 QStringList flist=QDir (tmpZipDir).entryList("*.xml");
1664 if (flist.count()==1)
1666 // Only one entry, take this one
1667 xmlfile=tmpZipDir + "/"+flist.first();
1670 for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it )
1671 *it=tmpZipDir + "/" + *it;
1672 // TODO Multiple entries, load all (but only the first one into this ME)
1673 //mainWindow->fileLoadFromTmp (flist);
1674 //returnCode=1; // Silently forget this attempt to load
1675 qWarning ("MainWindow::load (fn) multimap found...");
1678 if (flist.isEmpty() )
1680 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1681 tr("Couldn't find a map (*.xml) in .vym archive.\n"));
1684 } //file doesn't exist
1686 xmlfile=mfile.name();
1689 QFile file( xmlfile);
1691 // I am paranoid: file should exist anyway
1692 // according to check in mainwindow.
1693 if (!file.exists() )
1695 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1696 tr(QString("Couldn't open map %1").arg(file.name())));
1700 bool blockSaveStateOrg=blockSaveState;
1701 blockReposition=true;
1702 blockSaveState=true;
1703 QXmlInputSource source( file);
1704 QXmlSimpleReader reader;
1705 reader.setContentHandler( handler );
1706 reader.setErrorHandler( handler );
1707 handler->setModel ( model);
1710 // We need to set the tmpDir in order to load files with rel. path
1715 tmpdir=fname.left(fname.findRev("/",-1));
1716 handler->setTmpDir (tmpdir);
1717 handler->setInputFile (file.name());
1718 handler->setLoadMode (lmode);
1719 bool ok = reader.parse( source );
1720 blockReposition=false;
1721 blockSaveState=blockSaveStateOrg;
1725 model->reposition(); // FIXME reposition the view instead...
1732 autosaveTimer->stop();
1735 // Reset timestamp to check for later updates of file
1736 fileChangedTime=QFileInfo (destPath).lastModified();
1739 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1740 tr( handler->errorProtocol() ) );
1742 // Still return "success": the map maybe at least
1743 // partially read by the parser
1748 removeDir (QDir(tmpZipDir));
1750 // Restore original zip state
1758 ErrorCode MapEditor::save (const SaveMode &savemode)
1761 QString mapFileName;
1762 QString safeFilePath;
1764 ErrorCode err=success;
1768 mapFileName=mapName+".xml";
1770 // use name given by user, even if he chooses .doc
1771 mapFileName=fileName;
1773 // Look, if we should zip the data:
1776 QMessageBox mb( vymName,
1777 tr("The map %1\ndid not use the compressed "
1778 "vym file format.\nWriting it uncompressed will also write images \n"
1779 "and flags and thus may overwrite files in the "
1780 "given directory\n\nDo you want to write the map").arg(filePath),
1781 QMessageBox::Warning,
1782 QMessageBox::Yes | QMessageBox::Default,
1784 QMessageBox::Cancel | QMessageBox::Escape);
1785 mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
1786 mb.setButtonText( QMessageBox::No, tr("uncompressed") );
1787 mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
1790 case QMessageBox::Yes:
1791 // save compressed (default file format)
1794 case QMessageBox::No:
1795 // save uncompressed
1798 case QMessageBox::Cancel:
1805 // First backup existing file, we
1806 // don't want to add to old zip archives
1810 if ( settings.value ("/mapeditor/writeBackupFile").toBool())
1812 QString backupFileName(destPath + "~");
1813 QFile backupFile(backupFileName);
1814 if (backupFile.exists() && !backupFile.remove())
1816 QMessageBox::warning(0, tr("Save Error"),
1817 tr("%1\ncould not be removed before saving").arg(backupFileName));
1819 else if (!f.rename(backupFileName))
1821 QMessageBox::warning(0, tr("Save Error"),
1822 tr("%1\ncould not be renamed before saving").arg(destPath));
1829 // Create temporary directory for packing
1831 tmpZipDir=makeTmpDir (ok,"vym-zip");
1834 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1835 tr("Couldn't create temporary directory before save\n"));
1839 // cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1840 safeFilePath=filePath;
1841 setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
1844 // Create mapName and fileDir
1845 makeSubDirs (fileDir);
1849 cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1850 cout <<"ME::save saveFilePath="<<safeFilePath.toStdString()<<endl;
1851 cout <<"ME::save destPath="<<destPath.toStdString()<<endl;
1852 cout <<"ME::save mapName="<<mapName.toStdString()<<endl;
1853 cout <<"ME::save mapFileName="<<mapFileName.toStdString()<<endl;
1857 if (savemode==CompleteMap || xelection.isEmpty())
1859 // Save complete map
1860 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),NULL);
1863 autosaveTimer->stop();
1868 if (xelection.type()==Selection::FloatImage)
1871 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),xelection.getBranch());
1872 // TODO take care of multiselections
1875 if (!saveStringToDisk(fileDir+mapFileName,saveFile))
1878 QMessageBox::critical (0,"Critical error in MapEditor::save",QString("could not save %1").arg(fileDir+mapFileName));
1884 if (err==success) err=zipDir (tmpZipDir,destPath);
1887 removeDir (QDir(tmpZipDir));
1889 // Restore original filepath outside of tmp zip dir
1890 setFilePath (safeFilePath);
1894 fileChangedTime=QFileInfo (destPath).lastModified();
1899 void MapEditor::print()
1903 printer = new QPrinter;
1904 printer->setColorMode (QPrinter::Color);
1905 printer->setPrinterName (settings.value("/mainwindow/printerName",printer->printerName()).toString());
1906 printer->setOutputFormat((QPrinter::OutputFormat)settings.value("/mainwindow/printerFormat",printer->outputFormat()).toInt());
1907 printer->setOutputFileName(settings.value("/mainwindow/printerFileName",printer->outputFileName()).toString());
1910 QRectF totalBBox=model->getTotalBBox();
1912 // Try to set orientation automagically
1913 // Note: Interpretation of generated postscript is amibiguous, if
1914 // there are problems with landscape mode, see
1915 // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html
1917 if (totalBBox.width()>totalBBox.height())
1918 // recommend landscape
1919 printer->setOrientation (QPrinter::Landscape);
1921 // recommend portrait
1922 printer->setOrientation (QPrinter::Portrait);
1924 if ( printer->setup(this) )
1925 // returns false, if printing is canceled
1927 QPainter pp(printer);
1929 pp.setRenderHint(QPainter::Antialiasing,true);
1931 // Don't print the visualisation of selection
1932 xelection.unselect();
1934 QRectF mapRect=totalBBox;
1935 QGraphicsRectItem *frame=NULL;
1939 // Print frame around map
1940 mapRect.setRect (totalBBox.x()-10, totalBBox.y()-10,
1941 totalBBox.width()+20, totalBBox.height()+20);
1942 frame=mapScene->addRect (mapRect, QPen(Qt::black),QBrush(Qt::NoBrush));
1943 frame->setZValue(0);
1948 double paperAspect = (double)printer->width() / (double)printer->height();
1949 double mapAspect = (double)mapRect.width() / (double)mapRect.height();
1951 if (mapAspect>=paperAspect)
1953 // Fit horizontally to paper width
1954 //pp.setViewport(0,0, printer->width(),(int)(printer->width()/mapAspect) );
1955 viewBottom=(int)(printer->width()/mapAspect);
1958 // Fit vertically to paper height
1959 //pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height());
1960 viewBottom=printer->height();
1965 // Print footer below map
1967 font.setPointSize(10);
1969 QRectF footerBox(0,viewBottom,printer->width(),15);
1970 pp.drawText ( footerBox,Qt::AlignLeft,"VYM - " +fileName);
1971 pp.drawText ( footerBox, Qt::AlignRight, QDate::currentDate().toString(Qt::TextDate));
1975 QRectF (0,0,printer->width(),printer->height()-15),
1976 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height())
1979 // Viewport has paper dimension
1980 if (frame) delete (frame);
1982 // Restore selection
1983 xelection.reselect();
1985 // Save settings in vymrc
1986 settings.writeEntry("/mainwindow/printerName",printer->printerName());
1987 settings.writeEntry("/mainwindow/printerFormat",printer->outputFormat());
1988 settings.writeEntry("/mainwindow/printerFileName",printer->outputFileName());
1992 void MapEditor::setAntiAlias (bool b)
1994 setRenderHint(QPainter::Antialiasing,b);
1997 void MapEditor::setSmoothPixmap(bool b)
1999 setRenderHint(QPainter::SmoothPixmapTransform,b);
2002 QPixmap MapEditor::getPixmap()
2004 QRectF mapRect=model->getTotalBBox();
2005 QPixmap pix((int)mapRect.width()+2,(int)mapRect.height()+1);
2008 pp.setRenderHints(renderHints());
2010 // Don't print the visualisation of selection
2011 xelection.unselect();
2013 mapScene->render ( &pp,
2014 QRectF(0,0,mapRect.width()+1,mapRect.height()+1),
2015 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height() ));
2017 // Restore selection
2018 xelection.reselect();
2023 void MapEditor::setHideTmpMode (HideTmpMode mode)
2026 model->setHideTmp (hidemode);
2027 model->reposition();
2031 HideTmpMode MapEditor::getHideTmpMode()
2036 void MapEditor::setExportMode (bool b)
2038 // should be called before and after exports
2039 // depending on the settings
2040 if (b && settings.value("/export/useHideExport","true")=="true")
2041 setHideTmpMode (HideExport);
2043 setHideTmpMode (HideNone);
2046 void MapEditor::exportASCII(QString fname,bool askName)
2049 ex.setModel (model);
2051 ex.setFile (mapName+".txt");
2057 //ex.addFilter ("TXT (*.txt)");
2058 ex.setDir(lastImageDir);
2059 //ex.setCaption(vymName+ " -" +tr("Export as ASCII")+" "+tr("(still experimental)"));
2064 setExportMode(true);
2066 setExportMode(false);
2070 void MapEditor::exportImage(QString fname, bool askName, QString format)
2074 fname=mapName+".png";
2081 QFileDialog *fd=new QFileDialog (this);
2082 fd->setCaption (tr("Export map as image"));
2083 fd->setDirectory (lastImageDir);
2084 fd->setFileMode(QFileDialog::AnyFile);
2085 fd->setFilters (imageIO.getFilters() );
2088 fl=fd->selectedFiles();
2090 format=imageIO.getType(fd->selectedFilter());
2094 setExportMode (true);
2095 QPixmap pix (getPixmap());
2096 pix.save(fname, format);
2097 setExportMode (false);
2100 void MapEditor::exportOOPresentation(const QString &fn, const QString &cf)
2104 ex.setModel (model);
2105 if (ex.setConfigFile(cf))
2107 setExportMode (true);
2108 ex.exportPresentation();
2109 setExportMode (false);
2113 void MapEditor::exportXHTML (const QString &dir, bool askForName)
2115 ExportXHTMLDialog dia(this);
2116 dia.setFilePath (filePath );
2117 dia.setMapName (mapName );
2119 if (dir!="") dia.setDir (dir);
2125 if (dia.exec()!=QDialog::Accepted)
2129 QDir d (dia.getDir());
2130 // Check, if warnings should be used before overwriting
2131 // the output directory
2132 if (d.exists() && d.count()>0)
2135 warn.showCancelButton (true);
2136 warn.setText(QString(
2137 "The directory %1 is not empty.\n"
2138 "Do you risk to overwrite some of its contents?").arg(d.path() ));
2139 warn.setCaption("Warning: Directory not empty");
2140 warn.setShowAgainName("mainwindow/overwrite-dir-xhtml");
2142 if (warn.exec()!=QDialog::Accepted) ok=false;
2149 exportXML (dia.getDir(),false );
2150 dia.doExport(mapName );
2151 //if (dia.hasChanged()) setChanged();
2155 void MapEditor::exportXML(QString dir, bool askForName)
2159 dir=browseDirectory(this,tr("Export XML to directory"));
2160 if (dir =="" && !reallyWriteDirectory(dir) )
2164 // Hide stuff during export, if settings want this
2165 setExportMode (true);
2167 // Create subdirectories
2170 // write to directory
2171 QString saveFile=saveToDir (dir,mapName+"-",true,model->getTotalBBox().topLeft() ,NULL);
2174 file.setName ( dir + "/"+mapName+".xml");
2175 if ( !file.open( QIODevice::WriteOnly ) )
2177 // This should neverever happen
2178 QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open %1").arg(file.name()));
2182 // Write it finally, and write in UTF8, no matter what
2183 QTextStream ts( &file );
2184 ts.setEncoding (QTextStream::UnicodeUTF8);
2188 // Now write image, too
2189 exportImage (dir+"/images/"+mapName+".png",false,"PNG");
2191 setExportMode (false);
2194 void MapEditor::clear()
2196 //cout << "ME::clear() "<<mapName.toStdString()<<endl;
2198 autosaveTimer->stop();
2199 fileChangedTimer->stop();
2203 void MapEditor::copy()
2205 LinkableMapObj *sel=xelection.single();
2208 if (redosAvail == 0)
2211 QString s=model->getSelectString(sel);
2212 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy selection to clipboard",sel );
2213 curClipboard=curStep;
2216 // Copy also to global clipboard, because we are at last step in history
2217 QString bakMapName(QString("history-%1").arg(curStep));
2218 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2219 copyDir (bakMapDir,clipboardDir );
2221 clipboardEmpty=false;
2226 void MapEditor::redo()
2228 // Can we undo at all?
2229 if (redosAvail<1) return;
2231 bool blockSaveStateOrg=blockSaveState;
2232 blockSaveState=true;
2236 if (undosAvail<stepsTotal) undosAvail++;
2238 if (curStep>stepsTotal) curStep=1;
2239 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2240 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2241 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2242 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2243 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2244 QString version=undoSet.readEntry ("/history/version");
2246 /* TODO Maybe check for version, if we save the history
2247 if (!checkVersion(version))
2248 QMessageBox::warning(0,tr("Warning"),
2249 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2252 // Find out current undo directory
2253 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2257 cout << "ME::redo() begin\n";
2258 cout << " undosAvail="<<undosAvail<<endl;
2259 cout << " redosAvail="<<redosAvail<<endl;
2260 cout << " curStep="<<curStep<<endl;
2261 cout << " ---------------------------"<<endl;
2262 cout << " comment="<<comment.toStdString()<<endl;
2263 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2264 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2265 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2266 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2267 cout << " ---------------------------"<<endl<<endl;
2270 // select object before redo
2271 if (!redoSelection.isEmpty())
2272 select (redoSelection);
2275 parseAtom (redoCommand);
2276 model->reposition();
2278 blockSaveState=blockSaveStateOrg;
2280 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2281 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2282 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2283 undoSet.writeSettings(histPath);
2285 mainWindow->updateHistory (undoSet);
2288 /* TODO remove testing
2289 cout << "ME::redo() end\n";
2290 cout << " undosAvail="<<undosAvail<<endl;
2291 cout << " redosAvail="<<redosAvail<<endl;
2292 cout << " curStep="<<curStep<<endl;
2293 cout << " ---------------------------"<<endl<<endl;
2299 bool MapEditor::isRedoAvailable()
2301 if (undoSet.readNumEntry("/history/redosAvail",0)>0)
2307 void MapEditor::undo()
2309 // Can we undo at all?
2310 if (undosAvail<1) return;
2312 mainWindow->statusMessage (tr("Autosave disabled during undo."));
2314 bool blockSaveStateOrg=blockSaveState;
2315 blockSaveState=true;
2317 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2318 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2319 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2320 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2321 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2322 QString version=undoSet.readEntry ("/history/version");
2324 /* TODO Maybe check for version, if we save the history
2325 if (!checkVersion(version))
2326 QMessageBox::warning(0,tr("Warning"),
2327 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2330 // Find out current undo directory
2331 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2333 // select object before undo
2334 select (undoSelection);
2338 cout << "ME::undo() begin\n";
2339 cout << " undosAvail="<<undosAvail<<endl;
2340 cout << " redosAvail="<<redosAvail<<endl;
2341 cout << " curStep="<<curStep<<endl;
2342 cout << " ---------------------------"<<endl;
2343 cout << " comment="<<comment.toStdString()<<endl;
2344 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2345 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2346 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2347 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2348 cout << " ---------------------------"<<endl<<endl;
2350 parseAtom (undoCommand);
2351 model->reposition();
2355 if (curStep<1) curStep=stepsTotal;
2359 blockSaveState=blockSaveStateOrg;
2360 /* TODO remove testing
2361 cout << "ME::undo() end\n";
2362 cout << " undosAvail="<<undosAvail<<endl;
2363 cout << " redosAvail="<<redosAvail<<endl;
2364 cout << " curStep="<<curStep<<endl;
2365 cout << " ---------------------------"<<endl<<endl;
2368 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2369 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2370 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2371 undoSet.writeSettings(histPath);
2373 mainWindow->updateHistory (undoSet);
2376 ensureSelectionVisible();
2379 bool MapEditor::isUndoAvailable()
2381 if (undoSet.readNumEntry("/history/undosAvail",0)>0)
2387 void MapEditor::gotoHistoryStep (int i)
2389 // Restore variables
2390 int undosAvail=undoSet.readNumEntry (QString("/history/undosAvail"));
2391 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
2393 if (i<0) i=undosAvail+redosAvail;
2395 // Clicking above current step makes us undo things
2398 for (int j=0; j<undosAvail-i; j++) undo();
2401 // Clicking below current step makes us redo things
2403 for (int j=undosAvail; j<i; j++)
2405 if (debug) cout << "ME::gotoHistoryStep redo "<<j<<"/"<<undosAvail<<" i="<<i<<endl;
2409 // And ignore clicking the current row ;-)
2412 void MapEditor::addMapReplaceInt(const QString &undoSel, const QString &path)
2414 QString pathDir=path.left(path.findRev("/"));
2420 // We need to parse saved XML data
2421 parseVYMHandler handler;
2422 QXmlInputSource source( file);
2423 QXmlSimpleReader reader;
2424 reader.setContentHandler( &handler );
2425 reader.setErrorHandler( &handler );
2426 handler.setModel ( model);
2427 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2428 if (undoSel.isEmpty())
2432 handler.setLoadMode (NewMap);
2436 handler.setLoadMode (ImportReplace);
2438 blockReposition=true;
2439 bool ok = reader.parse( source );
2440 blockReposition=false;
2443 // This should never ever happen
2444 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2445 handler.errorProtocol());
2448 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2451 bool MapEditor::addMapInsertInt (const QString &path)
2453 QString pathDir=path.left(path.findRev("/"));
2459 // We need to parse saved XML data
2460 parseVYMHandler handler;
2461 QXmlInputSource source( file);
2462 QXmlSimpleReader reader;
2463 reader.setContentHandler( &handler );
2464 reader.setErrorHandler( &handler );
2465 handler.setModel (model);
2466 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2467 handler.setLoadMode (ImportAdd);
2468 blockReposition=true;
2469 bool ok = reader.parse( source );
2470 blockReposition=false;
2471 if ( ok ) return true;
2473 // This should never ever happen
2474 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2475 handler.errorProtocol());
2477 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2481 bool MapEditor::addMapInsertInt (const QString &path, int pos)
2483 BranchObj *sel=xelection.getBranch();
2486 if (addMapInsertInt (path))
2489 if (sel->getDepth()>0)
2490 sel->getLastBranch()->linkTo (sel,pos);
2495 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2499 qWarning ("ME::addMapInsertInt nothing selected");
2503 void MapEditor::pasteNoSave(const int &n)
2505 bool old=blockSaveState;
2506 blockSaveState=true;
2507 bool zippedOrg=zipped;
2508 if (redosAvail > 0 || n!=0)
2510 // Use the "historical" buffer
2511 QString bakMapName(QString("history-%1").arg(n));
2512 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2513 load (bakMapDir+"/"+clipboardFile,ImportAdd, VymMap);
2515 // Use the global buffer
2516 load (clipboardDir+"/"+clipboardFile,ImportAdd, VymMap);
2521 void MapEditor::paste()
2523 BranchObj *sel=xelection.getBranch();
2526 saveStateChangingPart(
2529 QString ("paste (%1)").arg(curClipboard),
2530 QString("Paste to %1").arg( getName(sel))
2533 model->reposition();
2537 void MapEditor::cut()
2539 LinkableMapObj *sel=xelection.single();
2540 if ( sel && (xelection.type() == Selection::Branch ||
2541 xelection.type()==Selection::MapCenter ||
2542 xelection.type()==Selection::FloatImage))
2544 /* No savestate! savestate is called in cutNoSave
2545 saveStateChangingPart(
2549 QString("Cut %1").arg(getName(sel ))
2554 model->reposition();
2558 void MapEditor::move(const double &x, const double &y)
2560 LinkableMapObj *sel=xelection.single();
2563 QPointF ap(sel->getAbsPos());
2567 QString ps=qpointfToString(ap);
2568 QString s=xelection.getSelectString();
2571 s, "move "+qpointfToString(to),
2572 QString("Move %1 to %2").arg(getName(sel)).arg(ps));
2574 model->reposition();
2580 void MapEditor::moveRel (const double &x, const double &y)
2582 LinkableMapObj *sel=xelection.single();
2585 QPointF rp(sel->getRelPos());
2589 QString ps=qpointfToString (sel->getRelPos());
2590 QString s=model->getSelectString(sel);
2593 s, "moveRel "+qpointfToString(to),
2594 QString("Move %1 to relative position %2").arg(getName(sel)).arg(ps));
2595 ((OrnamentedObj*)sel)->move2RelPos (x,y);
2596 model->reposition();
2603 void MapEditor::moveBranchUp()
2605 BranchObj* bo=xelection.getBranch();
2609 if (!bo->canMoveBranchUp()) return;
2610 par=(BranchObj*)(bo->getParObj());
2611 BranchObj *obo=par->moveBranchUp (bo); // bo will be the one below selection
2612 saveState (model->getSelectString(bo),"moveBranchDown ()",model->getSelectString(obo),"moveBranchUp ()",QString("Move up %1").arg(getName(bo)));
2613 model->reposition();
2616 ensureSelectionVisible();
2620 void MapEditor::moveBranchDown()
2622 BranchObj* bo=xelection.getBranch();
2626 if (!bo->canMoveBranchDown()) return;
2627 par=(BranchObj*)(bo->getParObj());
2628 BranchObj *obo=par->moveBranchDown(bo); // bo will be the one above selection
2629 saveState(model->getSelectString(bo),"moveBranchUp ()",model->getSelectString(obo),"moveBranchDown ()",QString("Move down %1").arg(getName(bo)));
2630 model->reposition();
2633 ensureSelectionVisible();
2637 void MapEditor::sortChildren()
2639 BranchObj* bo=xelection.getBranch();
2642 if(bo->countBranches()>1)
2644 saveStateChangingPart(bo,bo, "sortChildren ()",QString("Sort children of %1").arg(getName(bo)));
2646 model->reposition();
2647 ensureSelectionVisible();
2652 void MapEditor::linkTo(const QString &dstString)
2654 FloatImageObj *fio=xelection.getFloatImage();
2657 BranchObj *dst=(BranchObj*)(model->findObjBySelect(dstString));
2658 if (dst && (typeid(*dst)==typeid (BranchObj) ||
2659 typeid(*dst)==typeid (MapCenterObj)))
2661 LinkableMapObj *dstPar=dst->getParObj();
2662 QString parString=model->getSelectString(dstPar);
2663 QString fioPreSelectString=model->getSelectString(fio);
2664 QString fioPreParentSelectString=model->getSelectString (fio->getParObj());
2665 ((BranchObj*)(dst))->addFloatImage (fio);
2666 xelection.unselect();
2667 ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio);
2668 fio=((BranchObj*)(dst))->getLastFloatImage();
2671 xelection.select(fio);
2673 model->getSelectString(fio),
2674 QString("linkTo (\"%1\")").arg(fioPreParentSelectString),
2676 QString ("linkTo (\"%1\")").arg(dstString),
2677 QString ("Link floatimage to %1").arg(getName(dst)));
2682 QString MapEditor::getHeading(bool &ok, QPoint &p)
2684 BranchObj *bo=xelection.getBranch();
2688 p=mapFromScene(bo->getAbsPos());
2689 return bo->getHeading();
2695 void MapEditor::setHeading(const QString &s)
2697 BranchObj *sel=xelection.getBranch();
2702 "setHeading (\""+sel->getHeading()+"\")",
2704 "setHeading (\""+s+"\")",
2705 QString("Set heading of %1 to \"%2\"").arg(getName(sel)).arg(s) );
2706 sel->setHeading(s );
2707 model->reposition();
2709 ensureSelectionVisible();
2713 void MapEditor::setHeadingInt(const QString &s)
2715 BranchObj *bo=xelection.getBranch();
2719 model->reposition();
2721 ensureSelectionVisible();
2725 void MapEditor::setVymLinkInt (const QString &s)
2727 // Internal function, no saveState needed
2728 BranchObj *bo=xelection.getBranch();
2732 model->reposition();
2735 ensureSelectionVisible();
2739 BranchObj* MapEditor::addMapCenter ()
2741 MapCenterObj *mco= model->addMapCenter(contextMenuPos);
2742 xelection.select (mco);
2744 ensureSelectionVisible();
2749 QString ("addMapCenter (%1,%2)").arg (contextMenuPos.x()).arg(contextMenuPos.y()),
2750 QString ("Adding MapCenter to (%1,%2").arg (contextMenuPos.x()).arg(contextMenuPos.y())
2755 BranchObj* MapEditor::addNewBranchInt(int num)
2757 // Depending on pos:
2758 // -3 insert in childs of parent above selection
2759 // -2 add branch to selection
2760 // -1 insert in childs of parent below selection
2761 // 0..n insert in childs of parent at pos
2762 BranchObj *newbo=NULL;
2763 BranchObj *bo=xelection.getBranch();
2768 // save scroll state. If scrolled, automatically select
2769 // new branch in order to tmp unscroll parent...
2770 newbo=bo->addBranch();
2775 bo=(BranchObj*)bo->getParObj();
2776 if (bo) newbo=bo->insertBranch(num);
2780 bo=(BranchObj*)bo->getParObj();
2781 if (bo) newbo=bo->insertBranch(num);
2783 if (!newbo) return NULL;
2788 BranchObj* MapEditor::addNewBranch(int pos)
2790 // Different meaning than num in addNewBranchInt!
2794 BranchObj *bo = xelection.getBranch();
2795 BranchObj *newbo=NULL;
2799 setCursor (Qt::ArrowCursor);
2801 newbo=addNewBranchInt (pos-2);
2809 QString ("addBranch (%1)").arg(pos),
2810 QString ("Add new branch to %1").arg(getName(bo)));
2812 model->reposition();
2814 latestSelection=model->getSelectString(newbo);
2815 // In Network mode, the client needs to know where the new branch is,
2816 // so we have to pass on this information via saveState.
2817 // TODO: Get rid of this positioning workaround
2818 QString ps=qpointfToString (newbo->getAbsPos());
2819 sendData ("selectLatestAdded ()");
2820 sendData (QString("move %1").arg(ps));
2828 BranchObj* MapEditor::addNewBranchBefore()
2830 BranchObj *newbo=NULL;
2831 BranchObj *bo = xelection.getBranch();
2832 if (bo && xelection.type()==Selection::Branch)
2833 // We accept no MapCenterObj here, so we _have_ a parent
2835 QPointF p=bo->getRelPos();
2838 BranchObj *parbo=(BranchObj*)(bo->getParObj());
2840 // add below selection
2841 newbo=parbo->insertBranch(bo->getNum()+1);
2844 newbo->move2RelPos (p);
2846 // Move selection to new branch
2847 bo->linkTo (newbo,-1);
2849 saveState (newbo, "deleteKeepChilds ()", newbo, "addBranchBefore ()",
2850 QString ("Add branch before %1").arg(getName(bo)));
2852 model->reposition();
2856 latestSelection=xelection.getSelectString();
2860 void MapEditor::deleteSelection()
2862 BranchObj *bo = xelection.getBranch();
2863 if (bo && xelection.type()==Selection::MapCenter)
2865 xelection.unselect();
2866 xelection.clear(); // Otherwise we might get a segfault when trying to reselect
2867 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2868 bo=model->removeMapCenter ((MapCenterObj*)bo);
2871 xelection.select (bo);
2872 ensureSelectionVisible();
2875 model->reposition();
2878 if (bo && xelection.type()==Selection::Branch)
2880 BranchObj* par=(BranchObj*)bo->getParObj();
2881 xelection.unselect();
2882 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2883 par->removeBranch(bo);
2884 xelection.select (par);
2885 ensureSelectionVisible();
2886 model->reposition();
2890 FloatImageObj *fio=xelection.getFloatImage();
2893 BranchObj* par=(BranchObj*)fio->getParObj();
2894 saveStateChangingPart(
2898 QString("Delete %1").arg(getName(fio))
2900 xelection.unselect();
2901 par->removeFloatImage(fio);
2902 xelection.select (par);
2903 model->reposition();
2905 ensureSelectionVisible();
2910 LinkableMapObj* MapEditor::getSelection()
2912 return xelection.single();
2915 BranchObj* MapEditor::getSelectedBranch()
2917 return xelection.getBranch();
2920 FloatImageObj* MapEditor::getSelectedFloatImage()
2922 return xelection.getFloatImage();
2925 void MapEditor::unselect()
2927 xelection.unselect();
2930 void MapEditor::reselect()
2932 xelection.reselect();
2935 bool MapEditor::select (const QString &s)
2937 if (xelection.select(s))
2940 ensureSelectionVisible();
2947 bool MapEditor::select (LinkableMapObj *lmo)
2949 if (xelection.select(lmo))
2952 ensureSelectionVisible();
2959 QString MapEditor::getSelectString()
2961 return xelection.getSelectString();
2964 void MapEditor::selectInt (LinkableMapObj *lmo)
2966 if (lmo && xelection.single()!= lmo && isSelectBlocked()==false )
2968 xelection.select(lmo);
2974 void MapEditor::selectNextBranchInt()
2976 // Increase number of branch
2977 LinkableMapObj *sel=xelection.single();
2980 QString s=xelection.getSelectString();
2986 part=s.section(",",-1);
2988 num=part.right(part.length() - 3);
2990 s=s.left (s.length() -num.length());
2993 num=QString ("%1").arg(num.toUInt()+1);
2997 // Try to select this one
2998 if (select (s)) return;
3000 // We have no direct successor,
3001 // try to increase the parental number in order to
3002 // find a successor with same depth
3004 int d=xelection.single()->getDepth();
3009 while (!found && d>0)
3011 s=s.section (",",0,d-1);
3012 // replace substring of current depth in s with "1"
3013 part=s.section(",",-1);
3015 num=part.right(part.length() - 3);
3019 // increase number of parent
3020 num=QString ("%1").arg(num.toUInt()+1);
3021 s=s.section (",",0,d-2) + ","+ typ+num;
3024 // Special case, look at orientation
3025 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
3026 num=QString ("%1").arg(num.toUInt()+1);
3028 num=QString ("%1").arg(num.toUInt()-1);
3033 // pad to oldDepth, select the first branch for each depth
3034 for (i=d;i<oldDepth;i++)
3039 if ( xelection.getBranch()->countBranches()>0)
3047 // try to select the freshly built string
3055 void MapEditor::selectPrevBranchInt()
3057 // Decrease number of branch
3058 BranchObj *bo=xelection.getBranch();
3061 QString s=xelection.getSelectString();
3067 part=s.section(",",-1);
3069 num=part.right(part.length() - 3);
3071 s=s.left (s.length() -num.length());
3073 int n=num.toInt()-1;
3076 num=QString ("%1").arg(n);
3079 // Try to select this one
3080 if (n>=0 && select (s)) return;
3082 // We have no direct precessor,
3083 // try to decrease the parental number in order to
3084 // find a precessor with same depth
3086 int d=xelection.single()->getDepth();
3091 while (!found && d>0)
3093 s=s.section (",",0,d-1);
3094 // replace substring of current depth in s with "1"
3095 part=s.section(",",-1);
3097 num=part.right(part.length() - 3);
3101 // decrease number of parent
3102 num=QString ("%1").arg(num.toInt()-1);
3103 s=s.section (",",0,d-2) + ","+ typ+num;
3106 // Special case, look at orientation
3107 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
3108 num=QString ("%1").arg(num.toInt()-1);
3110 num=QString ("%1").arg(num.toInt()+1);
3115 // pad to oldDepth, select the last branch for each depth
3116 for (i=d;i<oldDepth;i++)
3120 if ( xelection.getBranch()->countBranches()>0)
3121 s+=",bo:"+ QString ("%1").arg( xelection.getBranch()->countBranches()-1 );
3128 // try to select the freshly built string
3136 void MapEditor::selectUpperBranch()
3138 if (isSelectBlocked() ) return;
3140 BranchObj *bo=xelection.getBranch();
3141 if (bo && xelection.type()==Selection::Branch)
3143 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3144 selectPrevBranchInt();
3146 if (bo->getDepth()==1)
3147 selectNextBranchInt();
3149 selectPrevBranchInt();
3153 void MapEditor::selectLowerBranch()
3155 if (isSelectBlocked() ) return;
3157 BranchObj *bo=xelection.getBranch();
3158 if (bo && xelection.type()==Selection::Branch)
3160 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3161 selectNextBranchInt();
3163 if (bo->getDepth()==1)
3164 selectPrevBranchInt();
3166 selectNextBranchInt();
3171 void MapEditor::selectLeftBranch()
3173 if (isSelectBlocked() ) return;
3177 LinkableMapObj *sel=xelection.single();
3180 if (xelection.type()== Selection::MapCenter)
3182 par=xelection.getBranch();
3183 bo=par->getLastSelectedBranch();
3186 // Workaround for reselecting on left and right side
3187 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3188 bo=par->getLastBranch();
3191 bo=par->getLastBranch();
3192 xelection.select(bo);
3194 ensureSelectionVisible();
3200 par=(BranchObj*)(sel->getParObj());
3201 if (sel->getOrientation()==LinkableMapObj::RightOfCenter)
3203 if (xelection.type() == Selection::Branch ||
3204 xelection.type() == Selection::FloatImage)
3206 xelection.select(par);
3208 ensureSelectionVisible();
3213 if (xelection.type() == Selection::Branch )
3215 bo=xelection.getBranch()->getLastSelectedBranch();
3218 xelection.select(bo);
3220 ensureSelectionVisible();
3229 void MapEditor::selectRightBranch()
3231 if (isSelectBlocked() ) return;
3235 LinkableMapObj *sel=xelection.single();
3238 if (xelection.type()==Selection::MapCenter)
3240 par=xelection.getBranch();
3241 bo=par->getLastSelectedBranch();
3244 // Workaround for reselecting on left and right side
3245 if (bo->getOrientation()==LinkableMapObj::LeftOfCenter)
3246 bo=par->getFirstBranch();
3249 xelection.select(bo);
3251 ensureSelectionVisible();
3257 par=(BranchObj*)(xelection.single()->getParObj());
3258 if (xelection.single()->getOrientation()==LinkableMapObj::LeftOfCenter)
3260 if (xelection.type() == Selection::Branch ||
3261 xelection.type() == Selection::FloatImage)
3263 xelection.select(par);
3265 ensureSelectionVisible();
3270 if (xelection.type() == Selection::Branch)
3272 bo=xelection.getBranch()->getLastSelectedBranch();
3275 xelection.select(bo);
3277 ensureSelectionVisible();
3286 void MapEditor::selectFirstBranch()
3288 BranchObj *bo1=xelection.getBranch();
3293 par=(BranchObj*)(bo1->getParObj());
3295 bo2=par->getFirstBranch();
3297 xelection.select(bo2);
3299 ensureSelectionVisible();
3305 void MapEditor::selectLastBranch()
3307 BranchObj *bo1=xelection.getBranch();
3312 par=(BranchObj*)(bo1->getParObj());
3314 bo2=par->getLastBranch();
3317 xelection.select(bo2);
3319 ensureSelectionVisible();
3325 void MapEditor::selectMapBackgroundImage ()
3327 Q3FileDialog *fd=new Q3FileDialog( this);
3328 fd->setMode (Q3FileDialog::ExistingFile);
3329 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
3330 ImagePreview *p =new ImagePreview (fd);
3331 fd->setContentsPreviewEnabled( TRUE );
3332 fd->setContentsPreview( p, p );
3333 fd->setPreviewMode( Q3FileDialog::Contents );
3334 fd->setCaption(vymName+" - " +tr("Load background image"));
3335 fd->setDir (lastImageDir);
3338 if ( fd->exec() == QDialog::Accepted )
3340 // TODO selectMapBackgroundImg in QT4 use: lastImageDir=fd->directory();
3341 lastImageDir=QDir (fd->dirPath());
3342 setMapBackgroundImage (fd->selectedFile());
3346 void MapEditor::setMapBackgroundImage (const QString &fn) //FIXME missing savestate
3348 QColor oldcol=mapScene->backgroundBrush().color();
3352 QString ("setMapBackgroundImage (%1)").arg(oldcol.name()),
3354 QString ("setMapBackgroundImage (%1)").arg(col.name()),
3355 QString("Set background color of map to %1").arg(col.name()));
3358 brush.setTextureImage (QPixmap (fn));
3359 mapScene->setBackgroundBrush(brush);
3362 void MapEditor::selectMapBackgroundColor()
3364 QColor col = QColorDialog::getColor( mapScene->backgroundBrush().color(), this );
3365 if ( !col.isValid() ) return;
3366 setMapBackgroundColor( col );
3370 void MapEditor::setMapBackgroundColor(QColor col)
3372 QColor oldcol=mapScene->backgroundBrush().color();
3374 QString ("setMapBackgroundColor (\"%1\")").arg(oldcol.name()),
3375 QString ("setMapBackgroundColor (\"%1\")").arg(col.name()),
3376 QString("Set background color of map to %1").arg(col.name()));
3377 mapScene->setBackgroundBrush(col);
3380 QColor MapEditor::getMapBackgroundColor()
3382 return mapScene->backgroundBrush().color();
3385 QColor MapEditor::getCurrentHeadingColor()
3387 BranchObj *bo=xelection.getBranch();
3388 if (bo) return bo->getColor();
3390 QMessageBox::warning(0,tr("Warning"),tr("Can't get color of heading,\nthere's no branch selected"));
3394 void MapEditor::colorBranch (QColor c)
3396 BranchObj *bo=xelection.getBranch();
3401 QString ("colorBranch (\"%1\")").arg(bo->getColor().name()),
3403 QString ("colorBranch (\"%1\")").arg(c.name()),
3404 QString("Set color of %1 to %2").arg(getName(bo)).arg(c.name())
3406 bo->setColor(c); // color branch
3410 void MapEditor::colorSubtree (QColor c)
3412 BranchObj *bo=xelection.getBranch();
3415 saveStateChangingPart(
3418 QString ("colorSubtree (\"%1\")").arg(c.name()),
3419 QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(c.name())
3421 bo->setColorSubtree (c); // color links, color childs
3426 void MapEditor::toggleStandardFlag(QString f)
3428 BranchObj *bo=xelection.getBranch();
3432 if (bo->isSetStandardFlag(f))
3444 QString("%1 (\"%2\")").arg(u).arg(f),
3446 QString("%1 (\"%2\")").arg(r).arg(f),
3447 QString("Toggling standard flag \"%1\" of %2").arg(f).arg(getName(bo)));
3448 bo->toggleStandardFlag (f,mainWindow->useFlagGroups());
3454 BranchObj* MapEditor::findText (QString s, bool cs)
3456 QTextDocument::FindFlags flags=0;
3457 if (cs) flags=QTextDocument::FindCaseSensitively;
3460 { // Nothing found or new find process
3462 // nothing found, start again
3464 itFind=model->first();
3466 bool searching=true;
3467 bool foundNote=false;
3468 while (searching && !EOFind)
3472 // Searching in Note
3473 if (itFind->getNote().contains(s,cs))
3475 if (xelection.single()!=itFind)
3477 xelection.select(itFind);
3478 ensureSelectionVisible();
3480 if (textEditor->findText(s,flags))
3486 // Searching in Heading
3487 if (searching && itFind->getHeading().contains (s,cs) )
3489 xelection.select(itFind);
3490 ensureSelectionVisible();
3496 itFind=model->next(itFind);
3497 if (!itFind) EOFind=true;
3499 //cout <<"still searching... "<<qPrintable( itFind->getHeading())<<endl;
3502 return xelection.getBranch();
3507 void MapEditor::findReset()
3508 { // Necessary if text to find changes during a find process
3512 void MapEditor::setURL(const QString &url)
3514 BranchObj *bo=xelection.getBranch();
3517 QString oldurl=bo->getURL();
3521 QString ("setURL (\"%1\")").arg(oldurl),
3523 QString ("setURL (\"%1\")").arg(url),
3524 QString ("set URL of %1 to %2").arg(getName(bo)).arg(url)
3527 model->reposition();
3529 ensureSelectionVisible();
3533 void MapEditor::editURL()
3535 BranchObj *bo=xelection.getBranch();
3539 QString text = QInputDialog::getText(
3540 "VYM", tr("Enter URL:"), QLineEdit::Normal,
3541 bo->getURL(), &ok, this );
3543 // user entered something and pressed OK
3548 void MapEditor::editLocalURL()
3550 BranchObj *bo=xelection.getBranch();
3553 QStringList filters;
3554 filters <<"All files (*)";
3555 filters << tr("Text","Filedialog") + " (*.txt)";
3556 filters << tr("Spreadsheet","Filedialog") + " (*.odp,*.sxc)";
3557 filters << tr("Textdocument","Filedialog") +" (*.odw,*.sxw)";
3558 filters << tr("Images","Filedialog") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)";
3559 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Set URL to a local file"));
3560 fd->setFilters (filters);
3561 fd->setCaption(vymName+" - " +tr("Set URL to a local file"));
3562 fd->setDirectory (lastFileDir);
3563 if (! bo->getVymLink().isEmpty() )
3564 fd->selectFile( bo->getURL() );
3567 if ( fd->exec() == QDialog::Accepted )
3569 lastFileDir=QDir (fd->directory().path());
3570 setURL (fd->selectedFile() );
3575 QString MapEditor::getURL()
3577 BranchObj *bo=xelection.getBranch();
3579 return bo->getURL();
3584 QStringList MapEditor::getURLs()
3587 BranchObj *bo=xelection.getBranch();
3593 if (!bo->getURL().isEmpty()) urls.append( bo->getURL());
3601 void MapEditor::editHeading2URL()
3603 BranchObj *bo=xelection.getBranch();
3605 setURL (bo->getHeading());
3608 void MapEditor::editBugzilla2URL()
3610 BranchObj *bo=xelection.getBranch();
3613 QString h=bo->getHeading();
3614 QRegExp rx("^(\\d+)");
3615 if (rx.indexIn(h) !=-1)
3616 setURL ("https://bugzilla.novell.com/show_bug.cgi?id="+rx.cap(1) );
3620 void MapEditor::editFATE2URL()
3622 BranchObj *bo=xelection.getBranch();
3625 QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading();
3628 "setURL (\""+bo->getURL()+"\")",
3630 "setURL (\""+url+"\")",
3631 QString("Use heading of %1 as link to FATE").arg(getName(bo))
3638 void MapEditor::editVymLink()
3640 BranchObj *bo=xelection.getBranch();
3643 QStringList filters;
3644 filters <<"VYM map (*.vym)";
3645 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Link to another map"));
3646 fd->setFilters (filters);
3647 fd->setCaption(vymName+" - " +tr("Link to another map"));
3648 fd->setDirectory (lastFileDir);
3649 if (! bo->getVymLink().isEmpty() )
3650 fd->selectFile( bo->getVymLink() );
3654 if ( fd->exec() == QDialog::Accepted )
3656 lastFileDir=QDir (fd->directory().path());
3659 "setVymLink (\""+bo->getVymLink()+"\")",
3661 "setVymLink (\""+fd->selectedFile()+"\")",
3662 QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())
3664 setVymLinkInt (fd->selectedFile() );
3669 void MapEditor::deleteVymLink()
3671 BranchObj *bo=xelection.getBranch();
3676 "setVymLink (\""+bo->getVymLink()+"\")",
3678 "setVymLink (\"\")",
3679 QString("Unset vymlink of %1").arg(getName(bo))
3681 bo->setVymLink ("" );
3683 model->reposition();
3688 void MapEditor::setHideExport(bool b)
3690 BranchObj *bo=xelection.getBranch();
3693 bo->setHideInExport (b);
3694 QString u= b ? "false" : "true";
3695 QString r=!b ? "false" : "true";
3699 QString ("setHideExport (%1)").arg(u),
3701 QString ("setHideExport (%1)").arg(r),
3702 QString ("Set HideExport flag of %1 to %2").arg(getName(bo)).arg (r)
3705 model->reposition();
3711 void MapEditor::toggleHideExport()
3713 BranchObj *bo=xelection.getBranch();
3715 setHideExport ( !bo->hideInExport() );
3718 QString MapEditor::getVymLink()
3720 BranchObj *bo=xelection.getBranch();
3722 return bo->getVymLink();
3728 QStringList MapEditor::getVymLinks()
3731 BranchObj *bo=xelection.getBranch();
3737 if (!bo->getVymLink().isEmpty()) links.append( bo->getVymLink());
3745 void MapEditor::deleteKeepChilds()
3747 BranchObj *bo=xelection.getBranch();
3751 par=(BranchObj*)(bo->getParObj());
3753 // Don't use this on mapcenter
3756 // Check if we have childs at all to keep
3757 if (bo->countBranches()==0)
3763 QPointF p=bo->getRelPos();
3764 saveStateChangingPart(
3767 "deleteKeepChilds ()",
3768 QString("Remove %1 and keep its childs").arg(getName(bo))
3771 QString sel=model->getSelectString(bo);
3773 par->removeBranchHere(bo);
3774 model->reposition();
3776 xelection.getBranch()->move2RelPos (p);
3777 model->reposition();
3781 void MapEditor::deleteChilds()
3783 BranchObj *bo=xelection.getBranch();
3786 saveStateChangingPart(
3790 QString( "Remove childs of branch %1").arg(getName(bo))
3793 model->reposition();
3797 void MapEditor::editMapInfo()
3799 ExtraInfoDialog dia;
3800 dia.setMapName (getFileName() );
3801 dia.setAuthor (model->getAuthor() );
3802 dia.setComment(model->getComment() );
3806 stats+=tr("%1 items on map\n","Info about map").arg (mapScene->items().size(),6);
3816 if (!bo->getNote().isEmpty() ) n++;
3817 f+= bo->countFloatImages();
3819 xl+=bo->countXLinks();
3822 stats+=QString ("%1 branches\n").arg (b-1,6);
3823 stats+=QString ("%1 xLinks \n").arg (xl,6);
3824 stats+=QString ("%1 notes\n").arg (n,6);
3825 stats+=QString ("%1 images\n").arg (f,6);
3826 dia.setStats (stats);
3828 // Finally show dialog
3829 if (dia.exec() == QDialog::Accepted)
3831 setMapAuthor (dia.getAuthor() );
3832 setMapComment (dia.getComment() );
3836 void MapEditor::ensureSelectionVisible()
3838 LinkableMapObj *lmo=xelection.single();
3839 if (lmo) ensureVisible (lmo->getBBox() );
3843 void MapEditor::updateSelection()
3845 // Tell selection to update geometries
3849 void MapEditor::updateActions()
3851 // Tell mainwindow to update states of actions
3852 mainWindow->updateActions();
3853 // TODO maybe don't update if blockReposition is set
3856 void MapEditor::updateNoteFlag()
3859 BranchObj *bo=xelection.getBranch();
3862 bo->updateNoteFlag();
3863 mainWindow->updateActions();
3867 void MapEditor::setMapAuthor (const QString &s)
3870 QString ("setMapAuthor (\"%1\")").arg(model->getAuthor()),
3871 QString ("setMapAuthor (\"%1\")").arg(s),
3872 QString ("Set author of map to \"%1\"").arg(s)
3874 model->setAuthor (s);
3877 void MapEditor::setMapComment (const QString &s)
3880 QString ("setMapComment (\"%1\")").arg(model->getComment()),
3881 QString ("setMapComment (\"%1\")").arg(s),
3882 QString ("Set comment of map")
3884 model->setComment (s);
3887 void MapEditor::setMapLinkStyle (const QString & s)
3890 if (linkstyle==LinkableMapObj::Line)
3892 else if (linkstyle==LinkableMapObj::Parabel)
3893 snow="StyleParabel";
3894 else if (linkstyle==LinkableMapObj::PolyLine)
3895 snow="StylePolyLine";
3896 else if (linkstyle==LinkableMapObj::PolyParabel)
3897 snow="StyleParabel";
3900 QString("setMapLinkStyle (\"%1\")").arg(s),
3901 QString("setMapLinkStyle (\"%1\")").arg(snow),
3902 QString("Set map link style (\"%1\")").arg(s)
3906 linkstyle=LinkableMapObj::Line;
3907 else if (s=="StyleParabel")
3908 linkstyle=LinkableMapObj::Parabel;
3909 else if (s=="StylePolyLine")
3910 linkstyle=LinkableMapObj::PolyLine;
3912 linkstyle=LinkableMapObj::PolyParabel;
3919 bo->setLinkStyle(bo->getDefLinkStyle());
3922 model->reposition();
3925 LinkableMapObj::Style MapEditor::getMapLinkStyle ()
3930 void MapEditor::setMapDefLinkColor(QColor c)
3943 void MapEditor::setMapLinkColorHintInt()
3945 // called from setMapLinkColorHint(lch) or at end of parse
3955 void MapEditor::setMapLinkColorHint(LinkableMapObj::ColorHint lch)
3958 setMapLinkColorHintInt();
3961 void MapEditor::toggleMapLinkColorHint()
3963 if (linkcolorhint==LinkableMapObj::HeadingColor)
3964 linkcolorhint=LinkableMapObj::DefaultColor;
3966 linkcolorhint=LinkableMapObj::HeadingColor;
3976 LinkableMapObj::ColorHint MapEditor::getMapLinkColorHint()
3978 return linkcolorhint;
3981 QColor MapEditor::getMapDefLinkColor()
3983 return defLinkColor;
3986 void MapEditor::setMapDefXLinkColor(QColor col)
3991 QColor MapEditor::getMapDefXLinkColor()
3993 return defXLinkColor;
3996 void MapEditor::setMapDefXLinkWidth (int w)
4001 int MapEditor::getMapDefXLinkWidth()
4003 return defXLinkWidth;
4006 void MapEditor::selectMapLinkColor()
4008 QColor col = QColorDialog::getColor( defLinkColor, this );
4009 if ( !col.isValid() ) return;
4011 QString("setMapDefLinkColor (\"%1\")").arg(getMapDefLinkColor().name()),
4012 QString("setMapDefLinkColor (\"%1\")").arg(col.name()),
4013 QString("Set map link color to %1").arg(col.name())
4015 setMapDefLinkColor( col );
4018 void MapEditor::selectMapSelectionColor()
4020 QColor col = QColorDialog::getColor( defLinkColor, this );
4021 setSelectionColor (col);
4024 void MapEditor::setSelectionColorInt (QColor col)
4026 if ( !col.isValid() ) return;
4027 xelection.setColor (col);
4030 void MapEditor::setSelectionColor(QColor col)
4032 if ( !col.isValid() ) return;
4034 QString("setSelectionColor (%1)").arg(xelection.getColor().name()),
4035 QString("setSelectionColor (%1)").arg(col.name()),
4036 QString("Set color of selection box to %1").arg(col.name())
4038 setSelectionColorInt (col);
4041 QColor MapEditor::getSelectionColor()
4043 return xelection.getColor();
4046 bool MapEditor::scrollBranch(BranchObj *bo)
4050 if (bo->isScrolled()) return false;
4051 if (bo->countBranches()==0) return false;
4052 if (bo->getDepth()==0) return false;
4058 QString ("%1 ()").arg(u),
4060 QString ("%1 ()").arg(r),
4061 QString ("%1 %2").arg(r).arg(getName(bo))
4071 bool MapEditor::unscrollBranch(BranchObj *bo)
4075 if (!bo->isScrolled()) return false;
4076 if (bo->countBranches()==0) return false;
4077 if (bo->getDepth()==0) return false;
4083 QString ("%1 ()").arg(u),
4085 QString ("%1 ()").arg(r),
4086 QString ("%1 %2").arg(r).arg(getName(bo))
4096 void MapEditor::toggleScroll()
4098 BranchObj *bo=xelection.getBranch();
4099 if (xelection.type()==Selection::Branch )
4101 if (bo->isScrolled())
4102 unscrollBranch (bo);
4108 void MapEditor::unscrollChilds()
4110 BranchObj *bo=xelection.getBranch();
4116 if (bo->isScrolled()) unscrollBranch (bo);
4122 FloatImageObj* MapEditor::loadFloatImageInt (QString fn)
4124 BranchObj *bo=xelection.getBranch();
4128 bo->addFloatImage();
4129 fio=bo->getLastFloatImage();
4131 model->reposition();
4138 void MapEditor::loadFloatImage ()
4140 BranchObj *bo=xelection.getBranch();
4144 Q3FileDialog *fd=new Q3FileDialog( this);
4145 fd->setMode (Q3FileDialog::ExistingFiles);
4146 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
4147 ImagePreview *p =new ImagePreview (fd);
4148 fd->setContentsPreviewEnabled( TRUE );
4149 fd->setContentsPreview( p, p );
4150 fd->setPreviewMode( Q3FileDialog::Contents );
4151 fd->setCaption(vymName+" - " +tr("Load image"));
4152 fd->setDir (lastImageDir);
4155 if ( fd->exec() == QDialog::Accepted )
4157 // TODO loadFIO in QT4 use: lastImageDir=fd->directory();
4158 lastImageDir=QDir (fd->dirPath());
4161 for (int j=0; j<fd->selectedFiles().count(); j++)
4163 s=fd->selectedFiles().at(j);
4164 fio=loadFloatImageInt (s);
4167 (LinkableMapObj*)fio,
4170 QString ("loadImage (%1)").arg(s ),
4171 QString("Add image %1 to %2").arg(s).arg(getName(bo))
4174 // TODO loadFIO error handling
4175 qWarning ("Failed to load "+s);
4183 void MapEditor::saveFloatImageInt (FloatImageObj *fio, const QString &type, const QString &fn)
4185 fio->save (fn,type);
4188 void MapEditor::saveFloatImage ()
4190 FloatImageObj *fio=xelection.getFloatImage();
4193 QFileDialog *fd=new QFileDialog( this);
4194 fd->setFilters (imageIO.getFilters());
4195 fd->setCaption(vymName+" - " +tr("Save image"));
4196 fd->setFileMode( QFileDialog::AnyFile );
4197 fd->setDirectory (lastImageDir);
4198 // fd->setSelection (fio->getOriginalFilename());
4202 if ( fd->exec() == QDialog::Accepted && fd->selectedFiles().count()==1)
4204 fn=fd->selectedFiles().at(0);
4205 if (QFile (fn).exists() )
4207 QMessageBox mb( vymName,
4208 tr("The file %1 exists already.\n"
4209 "Do you want to overwrite it?").arg(fn),
4210 QMessageBox::Warning,
4211 QMessageBox::Yes | QMessageBox::Default,
4212 QMessageBox::Cancel | QMessageBox::Escape,
4213 QMessageBox::NoButton );
4215 mb.setButtonText( QMessageBox::Yes, tr("Overwrite") );
4216 mb.setButtonText( QMessageBox::No, tr("Cancel"));
4219 case QMessageBox::Yes:
4222 case QMessageBox::Cancel:
4229 saveFloatImageInt (fio,fd->selectedFilter(),fn );
4235 void MapEditor::setFrameType(const FrameObj::FrameType &t)
4237 BranchObj *bo=xelection.getBranch();
4240 QString s=bo->getFrameTypeName();
4241 bo->setFrameType (t);
4242 saveState (bo, QString("setFrameType (\"%1\")").arg(s),
4243 bo, QString ("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),QString ("set type of frame to %1").arg(s));
4244 model->reposition();
4249 void MapEditor::setFrameType(const QString &s)
4251 BranchObj *bo=xelection.getBranch();
4254 saveState (bo, QString("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),
4255 bo, QString ("setFrameType (\"%1\")").arg(s),QString ("set type of frame to %1").arg(s));
4256 bo->setFrameType (s);
4257 model->reposition();
4262 void MapEditor::setFramePenColor(const QColor &c)
4264 BranchObj *bo=xelection.getBranch();
4267 saveState (bo, QString("setFramePenColor (\"%1\")").arg(bo->getFramePenColor().name() ),
4268 bo, QString ("setFramePenColor (\"%1\")").arg(c.name() ),QString ("set pen color of frame to %1").arg(c.name() ));
4269 bo->setFramePenColor (c);
4273 void MapEditor::setFrameBrushColor(const QColor &c)
4275 BranchObj *bo=xelection.getBranch();
4278 saveState (bo, QString("setFrameBrushColor (\"%1\")").arg(bo->getFrameBrushColor().name() ),
4279 bo, QString ("setFrameBrushColor (\"%1\")").arg(c.name() ),QString ("set brush color of frame to %1").arg(c.name() ));
4280 bo->setFrameBrushColor (c);
4284 void MapEditor::setFramePadding (const int &i)
4286 BranchObj *bo=xelection.getBranch();
4289 saveState (bo, QString("setFramePadding (\"%1\")").arg(bo->getFramePadding() ),
4290 bo, QString ("setFramePadding (\"%1\")").arg(i),QString ("set brush color of frame to %1").arg(i));
4291 bo->setFramePadding (i);
4292 model->reposition();
4297 void MapEditor::setFrameBorderWidth(const int &i)
4299 BranchObj *bo=xelection.getBranch();
4302 saveState (bo, QString("setFrameBorderWidth (\"%1\")").arg(bo->getFrameBorderWidth() ),
4303 bo, QString ("setFrameBorderWidth (\"%1\")").arg(i),QString ("set border width of frame to %1").arg(i));
4304 bo->setFrameBorderWidth (i);
4305 model->reposition();
4310 void MapEditor::setIncludeImagesVer(bool b)
4312 BranchObj *bo=xelection.getBranch();
4315 QString u= b ? "false" : "true";
4316 QString r=!b ? "false" : "true";
4320 QString("setIncludeImagesVertically (%1)").arg(u),
4322 QString("setIncludeImagesVertically (%1)").arg(r),
4323 QString("Include images vertically in %1").arg(getName(bo))
4325 bo->setIncludeImagesVer(b);
4326 model->reposition();
4330 void MapEditor::setIncludeImagesHor(bool b)
4332 BranchObj *bo=xelection.getBranch();
4335 QString u= b ? "false" : "true";
4336 QString r=!b ? "false" : "true";
4340 QString("setIncludeImagesHorizontally (%1)").arg(u),
4342 QString("setIncludeImagesHorizontally (%1)").arg(r),
4343 QString("Include images horizontally in %1").arg(getName(bo))
4345 bo->setIncludeImagesHor(b);
4346 model->reposition();
4350 void MapEditor::setHideLinkUnselected (bool b)
4352 LinkableMapObj *sel=xelection.single();
4354 (xelection.type() == Selection::Branch ||
4355 xelection.type() == Selection::MapCenter ||
4356 xelection.type() == Selection::FloatImage ))
4358 QString u= b ? "false" : "true";
4359 QString r=!b ? "false" : "true";
4363 QString("setHideLinkUnselected (%1)").arg(u),
4365 QString("setHideLinkUnselected (%1)").arg(r),
4366 QString("Hide link of %1 if unselected").arg(getName(sel))
4368 sel->setHideLinkUnselected(b);
4372 void MapEditor::importDirInt(BranchObj *dst, QDir d)
4374 BranchObj *bo=xelection.getBranch();
4377 // Traverse directories
4378 d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
4379 QFileInfoList list = d.entryInfoList();
4382 for (int i = 0; i < list.size(); ++i)
4385 if (fi.fileName() != "." && fi.fileName() != ".." )
4388 bo=dst->getLastBranch();
4389 bo->setHeading (fi.fileName() );
4390 bo->setColor (QColor("blue"));
4392 if ( !d.cd(fi.fileName()) )
4393 QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory %1").arg(fi.fileName()));
4396 // Recursively add subdirs
4397 importDirInt (bo,d);
4403 d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
4404 list = d.entryInfoList();
4406 for (int i = 0; i < list.size(); ++i)
4410 bo=dst->getLastBranch();
4411 bo->setHeading (fi.fileName() );
4412 bo->setColor (QColor("black"));
4413 if (fi.fileName().right(4) == ".vym" )
4414 bo->setVymLink (fi.filePath());
4419 void MapEditor::importDirInt (const QString &s)
4421 BranchObj *bo=xelection.getBranch();
4424 saveStateChangingPart (bo,bo,QString ("importDir (\"%1\")").arg(s),QString("Import directory structure from %1").arg(s));
4427 importDirInt (bo,d);
4431 void MapEditor::importDir()
4433 BranchObj *bo=xelection.getBranch();
4436 QStringList filters;
4437 filters <<"VYM map (*.vym)";
4438 QFileDialog *fd=new QFileDialog( this,vymName+ " - " +tr("Choose directory structure to import"));
4439 fd->setMode (QFileDialog::DirectoryOnly);
4440 fd->setFilters (filters);
4441 fd->setCaption(vymName+" - " +tr("Choose directory structure to import"));
4445 if ( fd->exec() == QDialog::Accepted )
4447 importDirInt (fd->selectedFile() );
4448 model->reposition();
4454 void MapEditor::followXLink(int i)
4456 BranchObj *bo=xelection.getBranch();
4459 bo=bo->XLinkTargetAt(i);
4462 xelection.select(bo);
4463 ensureSelectionVisible();
4468 void MapEditor::editXLink(int i) // FIXME missing saveState
4470 BranchObj *bo=xelection.getBranch();
4473 XLinkObj *xlo=bo->XLinkAt(i);
4476 EditXLinkDialog dia;
4478 dia.setSelection(bo);
4479 if (dia.exec() == QDialog::Accepted)
4481 if (dia.useSettingsGlobal() )
4483 setMapDefXLinkColor (xlo->getColor() );
4484 setMapDefXLinkWidth (xlo->getWidth() );
4486 if (dia.deleteXLink())
4487 bo->deleteXLinkAt(i);
4493 AttributeTable* MapEditor::attributeTable()
4498 void MapEditor::testFunction1()
4500 BranchObj *bo=xelection.getBranch();
4501 if (bo) model->moveAway (bo);
4503 /* TODO Hide hidden stuff temporary, maybe add this as regular function somewhere
4504 if (hidemode==HideNone)
4506 setHideTmpMode (HideExport);
4507 mapCenter->calcBBoxSizeWithChilds();
4508 QRectF totalBBox=mapCenter->getTotalBBox();
4509 QRectF mapRect=totalBBox;
4510 QCanvasRectangle *frame=NULL;
4512 cout << " map has =("<<totalBBox.x()<<","<<totalBBox.y()<<","<<totalBBox.width()<<","<<totalBBox.height()<<")\n";
4514 mapRect.setRect (totalBBox.x(), totalBBox.y(),
4515 totalBBox.width(), totalBBox.height());
4516 frame=new QCanvasRectangle (mapRect,mapScene);
4517 frame->setBrush (QColor(white));
4518 frame->setPen (QColor(black));
4519 frame->setZValue(0);
4524 setHideTmpMode (HideNone);
4526 cout <<" hidemode="<<hidemode<<endl;
4530 void MapEditor::testFunction2()
4535 if (hidemode==HideExport)
4536 setHideTmpMode (HideNone);
4538 setHideTmpMode (HideExport);
4542 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
4544 // Lineedits are already closed by preceding
4545 // mouseEvent, we don't need to close here.
4547 QPointF p = mapToScene(e->pos());
4548 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4551 { // MapObj was found
4552 if (xelection.single() != lmo)
4554 // select the MapObj
4555 xelection.select(lmo);
4558 if (xelection.getBranch() )
4560 // Context Menu on branch or mapcenter
4562 branchContextMenu->popup(e->globalPos() );
4565 if (xelection.getFloatImage() )
4567 // Context Menu on floatimage
4569 floatimageContextMenu->popup(e->globalPos() );
4573 { // No MapObj found, we are on the Canvas itself
4574 // Context Menu on scene
4577 canvasContextMenu->popup(e->globalPos() );
4582 void MapEditor::keyPressEvent(QKeyEvent* e)
4584 if (e->modifiers() & Qt::ControlModifier)
4586 switch (mainWindow->getModMode())
4588 case Main::ModModeColor:
4589 setCursor (PickColorCursor);
4591 case Main::ModModeCopy:
4592 setCursor (CopyCursor);
4594 case Main::ModModeXLink:
4595 setCursor (XLinkCursor);
4598 setCursor (Qt::ArrowCursor);
4604 void MapEditor::keyReleaseEvent(QKeyEvent* e)
4606 if (!(e->modifiers() & Qt::ControlModifier))
4607 setCursor (Qt::ArrowCursor);
4610 void MapEditor::mousePressEvent(QMouseEvent* e)
4612 // Ignore right clicks, these will go to context menus
4613 if (e->button() == Qt::RightButton )
4619 //Ignore clicks while editing heading
4620 if (isSelectBlocked() )
4626 QPointF p = mapToScene(e->pos());
4627 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4631 //Take care of system flags _or_ modifier modes
4633 if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4634 typeid(*lmo)==typeid(MapCenterObj) ))
4636 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
4637 if (!foname.isEmpty())
4639 // systemFlag clicked
4643 if (e->state() & Qt::ControlModifier)
4644 mainWindow->editOpenURLTab();
4646 mainWindow->editOpenURL();
4648 else if (foname=="vymLink")
4650 mainWindow->editOpenVymLink();
4651 // tabWidget may change, better return now
4652 // before segfaulting...
4653 } else if (foname=="note")
4654 mainWindow->windowToggleNoteEditor();
4655 else if (foname=="hideInExport")
4662 // No system flag clicked, take care of modmodes (CTRL-Click)
4663 if (e->state() & Qt::ControlModifier)
4665 if (mainWindow->getModMode()==Main::ModModeColor)
4668 setCursor (PickColorCursor);
4671 if (mainWindow->getModMode()==Main::ModModeCopy)
4673 if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4674 typeid(*lmo)==typeid(MapCenterObj) ))
4679 if (lmo->getDepth()>0) select (lmo->getParObj() );
4681 cout << "sel 1="<<getSelectedBranch()->getHeading().toStdString()<<endl;
4682 lmo=getSelectedBranch()->getLastBranch();
4683 cout << "sel 2="<<getSelectedBranch()->getHeading().toStdString()<<endl;
4684 setCursor (Qt::ArrowCursor);
4688 if (mainWindow->getModMode()==Main::ModModeXLink)
4690 BranchObj *bo_begin=NULL;
4692 bo_begin=(BranchObj*)(lmo);
4694 if (xelection.getBranch() )
4695 bo_begin=xelection.getBranch();
4699 linkingObj_src=bo_begin;
4700 tmpXLink=new XLinkObj (mapScene);
4701 tmpXLink->setBegin (bo_begin);
4702 tmpXLink->setEnd (p);
4703 tmpXLink->setColor(defXLinkColor);
4704 tmpXLink->setWidth(defXLinkWidth);
4705 tmpXLink->updateXLink();
4706 tmpXLink->setVisibility (true);
4710 } // End of modmodes
4714 // Select the clicked object
4717 // Left Button Move Branches
4718 if (e->button() == Qt::LeftButton )
4720 //movingObj_start.setX( p.x() - selection->x() );// TODO replaced selection->lmo here
4721 //movingObj_start.setY( p.y() - selection->y() );
4722 movingObj_start.setX( p.x() - lmo->x() );
4723 movingObj_start.setY( p.y() - lmo->y() );
4724 movingObj_orgPos.setX (lmo->x() );
4725 movingObj_orgPos.setY (lmo->y() );
4726 movingObj_orgRelPos=lmo->getRelPos();
4728 // If modMode==copy, then we want to "move" the _new_ object around
4729 // then we need the offset from p to the _old_ selection, because of tmp
4731 if (mainWindow->getModMode()==Main::ModModeCopy &&
4732 e->state() & Qt::ControlModifier)
4734 BranchObj *bo=xelection.getBranch();
4738 bo->addBranch ((BranchObj*)xelection.single());
4740 xelection.select(bo->getLastBranch());
4741 model->reposition();
4746 movingObj=xelection.single();
4748 // Middle Button Toggle Scroll
4749 // (On Mac OS X this won't work, but we still have
4750 // a button in the toolbar)
4751 if (e->button() == Qt::MidButton )
4756 { // No MapObj found, we are on the scene itself
4757 // Left Button move Pos of sceneView
4758 if (e->button() == Qt::LeftButton )
4760 movingObj=NULL; // move Content not Obj
4761 movingObj_start=e->globalPos();
4762 movingCont_start=QPointF (
4763 horizontalScrollBar()->value(),
4764 verticalScrollBar()->value());
4765 movingVec=QPointF(0,0);
4766 setCursor(HandOpenCursor);
4771 void MapEditor::mouseMoveEvent(QMouseEvent* e)
4773 QPointF p = mapToScene(e->pos());
4774 LinkableMapObj *lmosel=xelection.single();
4776 // Move the selected MapObj
4777 if ( lmosel && movingObj)
4779 // reset cursor if we are moving and don't copy
4780 if (mainWindow->getModMode()!=Main::ModModeCopy)
4781 setCursor (Qt::ArrowCursor);
4783 // To avoid jumping of the sceneView, only
4784 // ensureSelectionVisible, if not tmp linked
4785 if (!lmosel->hasParObjTmp())
4786 ensureSelectionVisible ();
4788 // Now move the selection, but add relative position
4789 // (movingObj_start) where selection was chosen with
4790 // mousepointer. (This avoids flickering resp. jumping
4791 // of selection back to absPos)
4793 // Check if we could link
4794 LinkableMapObj* lmo=model->findMapObj(p, lmosel);
4797 FloatObj *fio=xelection.getFloatImage();
4800 fio->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4802 fio->updateLink(); //no need for reposition, if we update link here
4805 // Relink float to new mapcenter or branch, if shift is pressed
4806 // Only relink, if selection really has a new parent
4807 if ( (e->modifiers()==Qt::ShiftModifier) && lmo &&
4808 ( (typeid(*lmo)==typeid(BranchObj)) ||
4809 (typeid(*lmo)==typeid(MapCenterObj)) ) &&
4810 ( lmo != fio->getParObj())
4813 if (typeid(*fio) == typeid(FloatImageObj) &&
4814 ( (typeid(*lmo)==typeid(BranchObj) ||
4815 typeid(*lmo)==typeid(MapCenterObj)) ))
4818 // Also save the move which was done so far
4819 QString pold=qpointfToString(movingObj_orgRelPos);
4820 QString pnow=qpointfToString(fio->getRelPos());
4826 QString("Move %1 to relative position %2").arg(getName(fio)).arg(pnow));
4827 fio->getParObj()->requestReposition();
4828 model->reposition();
4830 linkTo (model->getSelectString(lmo));
4832 //movingObj_orgRelPos=lmosel->getRelPos();
4834 model->reposition();
4838 { // selection != a FloatObj
4839 if (lmosel->getDepth()==0)
4842 if (e->buttons()== Qt::LeftButton && e->modifiers()==Qt::ShiftModifier)
4843 ((MapCenterObj*)lmosel)->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4845 lmosel->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4846 model->updateRelPositions();
4849 if (lmosel->getDepth()==1)
4852 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4853 lmosel->setRelPos();
4856 // Move ordinary branch
4857 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4860 // Maybe we can relink temporary?
4861 if (lmo && (lmo!=lmosel) && xelection.getBranch() &&
4862 (typeid(*lmo)==typeid(BranchObj) ||
4863 typeid(*lmo)==typeid(MapCenterObj)) )
4866 if (e->modifiers()==Qt::ControlModifier)
4868 // Special case: CTRL to link below lmo
4869 lmosel->setParObjTmp (lmo,p,+1);
4871 else if (e->modifiers()==Qt::ShiftModifier)
4872 lmosel->setParObjTmp (lmo,p,-1);
4874 lmosel->setParObjTmp (lmo,p,0);
4877 lmosel->unsetParObjTmp();
4879 // reposition subbranch
4880 lmosel->reposition();
4884 } // no FloatImageObj
4888 } // selection && moving_obj
4890 // Draw a link from one branch to another
4893 tmpXLink->setEnd (p);
4894 tmpXLink->updateXLink();
4898 if (!movingObj && !pickingColor &&!drawingLink && e->buttons() == Qt::LeftButton )
4900 QPointF p=e->globalPos();
4901 movingVec.setX(-p.x() + movingObj_start.x() );
4902 movingVec.setY(-p.y() + movingObj_start.y() );
4903 horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
4904 verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
4909 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
4911 QPointF p = mapToScene(e->pos());
4912 LinkableMapObj *dst;
4913 LinkableMapObj *lmosel=xelection.single();
4914 // Have we been picking color?
4918 setCursor (Qt::ArrowCursor);
4919 // Check if we are over another branch
4920 dst=model->findMapObj(p, NULL);
4923 if (e->state() & Qt::ShiftModifier)
4924 colorBranch (((BranchObj*)dst)->getColor());
4926 colorSubtree (((BranchObj*)dst)->getColor());
4931 // Have we been drawing a link?
4935 // Check if we are over another branch
4936 dst=model->findMapObj(p, NULL);
4939 tmpXLink->setEnd ( ((BranchObj*)(dst)) );
4940 tmpXLink->updateXLink();
4941 tmpXLink->activate(); //FIXME savestate missing
4942 //saveStateComplete(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) );
4951 // Have we been moving something?
4952 if ( lmosel && movingObj )
4954 FloatImageObj *fo=xelection.getFloatImage();
4957 // Moved FloatObj. Maybe we need to reposition
4958 QString pold=qpointfToString(movingObj_orgRelPos);
4959 QString pnow=qpointfToString(fo->getRelPos());
4965 QString("Move %1 to relative position %2").arg(getName(fo)).arg(pnow));
4967 fo->getParObj()->requestReposition();
4968 model->reposition();
4971 // Check if we are over another branch, but ignore
4972 // any found LMOs, which are FloatObjs
4973 dst=model->findMapObj(mapToScene(e->pos() ), lmosel);
4975 if (dst && (typeid(*dst)!=typeid(BranchObj) && typeid(*dst)!=typeid(MapCenterObj)))
4978 BranchObj *bo=xelection.getBranch();
4979 if (bo && bo->getDepth()==0)
4981 if (movingObj_orgPos != bo->getAbsPos())
4983 QString pold=qpointfToString(movingObj_orgPos);
4984 QString pnow=qpointfToString(bo->getAbsPos());
4990 QString("Move mapcenter %1 to position %2").arg(getName(bo)).arg(pnow));
4994 if (xelection.type() == Selection::Branch )
4995 { // A branch was moved
4997 // save the position in case we link to mapcenter
4998 QPointF savePos=QPointF (lmosel->getAbsPos() );
5000 // Reset the temporary drawn link to the original one
5001 lmosel->unsetParObjTmp();
5003 // For Redo we may need to save original selection
5004 QString preSelStr=model->getSelectString(lmosel);
5009 // Don't unscroll if relinked to a scrolled parent, but
5010 // select parent instead
5011 bool selectParent=false;
5013 // We have a destination, relink to that
5015 BranchObj* bsel=xelection.getBranch();
5016 BranchObj* bdst=(BranchObj*)dst;
5018 QString preParStr=model->getSelectString (bsel->getParObj());
5019 QString preNum=QString::number (bsel->getNum(),10);
5020 QString preDstParStr;
5022 if (e->state() & Qt::ShiftModifier && dst->getParObj())
5024 preDstParStr=model->getSelectString (dst->getParObj());
5025 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum());
5027 if (e->state() & Qt::ControlModifier && dst->getParObj())
5030 preDstParStr=model->getSelectString (dst->getParObj());
5031 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum()+1);
5034 if (bdst->isScrolled()) selectParent=true;
5035 preDstParStr=model->getSelectString(dst);
5036 bsel->linkTo (bdst,-1);
5037 if (dst->getDepth()==0) bsel->move (savePos);
5039 QString postSelStr=model->getSelectString(lmosel);
5040 QString postNum=QString::number (bsel->getNum(),10);
5042 QString undoCom="linkTo (\""+
5043 preParStr+ "\"," + preNum +"," +
5044 QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")";
5046 QString redoCom="linkTo (\""+
5047 preDstParStr + "\"," + postNum + "," +
5048 QString ("%1,%2").arg(savePos.x()).arg(savePos.y())+ ")";
5053 QString("Relink %1 to %2").arg(getName(bsel)).arg(getName(dst)) );
5055 if (selectParent) select (bdst);
5057 model->reposition(); // not necessary if we undo temporary move below
5060 // No destination, undo temporary move
5062 if (lmosel->getDepth()==1)
5064 // The select string might be different _after_ moving around.
5065 // Therefor reposition and then use string of old selection, too
5066 model->reposition();
5068 QPointF rp(lmosel->getRelPos());
5069 if (rp != movingObj_orgRelPos)
5071 QString ps=qpointfToString(rp);
5073 model->getSelectString(lmosel), "moveRel "+qpointfToString(movingObj_orgRelPos),
5074 preSelStr, "moveRel "+ps,
5075 QString("Move %1 to relative position %2").arg(getName(lmosel)).arg(ps));
5079 // Draw the original link, before selection was moved around
5080 if (settings.value("/animation/use",false).toBool() && lmosel->getDepth()>1)
5082 QPointF p=bo->getParObj()->getChildPos();
5083 lmosel->setRelPos(); // calc relPos first
5084 model->startAnimation(
5085 lmosel->getRelPos(),
5086 QPointF (movingObj_orgPos.x() - p.x(), movingObj_orgPos.y() - p.y() )
5089 model->reposition();
5093 // Finally resize scene, if needed
5097 // Just make sure, that actions are still ok,e.g. the move branch up/down buttons...
5100 // maybe we moved View: set old cursor
5101 setCursor (Qt::ArrowCursor);
5105 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
5107 if (isSelectBlocked() )
5113 if (e->button() == Qt::LeftButton )
5115 QPointF p = mapToScene(e->pos());
5116 LinkableMapObj *lmo=model->findMapObj(p, NULL);
5117 if (lmo) { // MapObj was found
5118 // First select the MapObj than edit heading
5119 xelection.select(lmo);
5120 mainWindow->editHeading();
5125 void MapEditor::resizeEvent (QResizeEvent* e)
5127 QGraphicsView::resizeEvent( e );
5130 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
5132 //for (unsigned int i=0;event->format(i);i++) // Debug mime type
5133 // cerr << event->format(i) << endl;
5135 if (event->mimeData()->hasImage())
5136 event->acceptProposedAction();
5138 if (event->mimeData()->hasUrls())
5139 event->acceptProposedAction();
5142 void MapEditor::dragMoveEvent(QDragMoveEvent *)
5146 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
5151 void MapEditor::dropEvent(QDropEvent *event)
5153 BranchObj *sel=xelection.getBranch();
5157 foreach (QString format,event->mimeData()->formats())
5158 cout << "MapEditor: Dropped format: "<<qPrintable (format)<<endl;
5162 if (event->mimeData()->hasImage())
5164 QVariant imageData = event->mimeData()->imageData();
5165 addFloatImageInt (qvariant_cast<QPixmap>(imageData));
5167 if (event->mimeData()->hasUrls())
5168 uris=event->mimeData()->urls();
5176 for (int i=0; i<uris.count();i++)
5178 // Workaround to avoid adding empty branches
5179 if (!uris.at(i).toString().isEmpty())
5181 bo=sel->addBranch();
5184 s=uris.at(i).toLocalFile();
5187 QString file = QDir::fromNativeSeparators(s);
5188 heading = QFileInfo(file).baseName();
5190 if (file.endsWith(".vym", false))
5191 bo->setVymLink(file);
5193 bo->setURL(uris.at(i).toString());
5196 bo->setURL(uris.at(i).toString());
5199 if (!heading.isEmpty())
5200 bo->setHeading(heading);
5202 bo->setHeading(uris.at(i).toString());
5206 model->reposition();
5209 event->acceptProposedAction();
5213 void MapEditor::sendSelection()
5215 if (netstate!=Server) return;
5216 sendData (QString("select (\"%1\")").arg(xelection.getSelectString()) );
5219 void MapEditor::newServer()
5223 tcpServer = new QTcpServer(this);
5224 if (!tcpServer->listen(QHostAddress::Any,port)) {
5225 QMessageBox::critical(this, "vym server",
5226 QString("Unable to start the server: %1.").arg(tcpServer->errorString()));
5230 connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newClient()));
5232 cout<<"Server is running on port "<<tcpServer->serverPort()<<endl;
5235 void MapEditor::connectToServer()
5238 server="salam.suse.de";
5240 clientSocket = new QTcpSocket (this);
5241 clientSocket->abort();
5242 clientSocket->connectToHost(server ,port);
5243 connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readData()));
5244 connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
5245 this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
5247 cout<<"connected to "<<qPrintable (server)<<" port "<<port<<endl;
5252 void MapEditor::newClient()
5254 QTcpSocket *newClient = tcpServer->nextPendingConnection();
5255 connect(newClient, SIGNAL(disconnected()),
5256 newClient, SLOT(deleteLater()));
5258 cout <<"ME::newClient at "<<qPrintable( newClient->peerAddress().toString() )<<endl;
5260 clientList.append (newClient);
5264 void MapEditor::sendData(const QString &s)
5266 if (clientList.size()==0) return;
5268 // Create bytearray to send
5270 QDataStream out(&block, QIODevice::WriteOnly);
5271 out.setVersion(QDataStream::Qt_4_0);
5273 // Reserve some space for blocksize
5276 // Write sendCounter
5277 out << sendCounter++;
5282 // Go back and write blocksize so far
5283 out.device()->seek(0);
5284 quint16 bs=(quint16)(block.size() - 2*sizeof(quint16));
5288 cout << "ME::sendData bs="<<bs<<" counter="<<sendCounter<<" s="<<qPrintable(s)<<endl;
5290 for (int i=0; i<clientList.size(); ++i)
5292 //cout << "Sending \""<<qPrintable (s)<<"\" to "<<qPrintable (clientList.at(i)->peerAddress().toString())<<endl;
5293 clientList.at(i)->write (block);
5297 void MapEditor::readData ()
5299 while (clientSocket->bytesAvailable() >=(int)sizeof(quint16) )
5302 cout <<"readData bytesAvail="<<clientSocket->bytesAvailable();
5306 QDataStream in(clientSocket);
5307 in.setVersion(QDataStream::Qt_4_0);
5315 cout << " t="<<qPrintable (t)<<endl;
5321 void MapEditor::displayNetworkError(QAbstractSocket::SocketError socketError)
5323 switch (socketError) {
5324 case QAbstractSocket::RemoteHostClosedError:
5326 case QAbstractSocket::HostNotFoundError:
5327 QMessageBox::information(this, vymName +" Network client",
5328 "The host was not found. Please check the "
5329 "host name and port settings.");
5331 case QAbstractSocket::ConnectionRefusedError:
5332 QMessageBox::information(this, vymName + " Network client",
5333 "The connection was refused by the peer. "
5334 "Make sure the fortune server is running, "
5335 "and check that the host name and port "
5336 "settings are correct.");
5339 QMessageBox::information(this, vymName + " Network client",
5340 QString("The following error occurred: %1.")
5341 .arg(clientSocket->errorString()));
5345 void MapEditor::autosave()
5349 if (debug) cout <<" ME::autosave rejected, no filepath available\n";
5353 QDateTime now=QDateTime().currentDateTime();
5355 cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n";
5356 cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
5357 cout << " fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
5358 cout << " time: "<<qPrintable (now.toString())<<endl;
5359 cout << " zipped="<<zipped<<endl;
5362 // Disable autosave, while we have gone back in history
5363 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
5364 if (redosAvail>0) return;
5366 // Also disable autosave for new map without filename
5367 if (filePath.isEmpty()) return;
5370 if (mapUnsaved &&mapChanged && settings.value ("/mainwindow/autosave/use",true).toBool() )
5372 if (QFileInfo(filePath).lastModified()<=fileChangedTime)
5373 mainWindow->fileSave (this);
5376 cout <<" ME::autosave rejected, file on disk is newer than last save.\n";
5380 void MapEditor::fileChanged()
5382 // Check if file on disk has changed meanwhile
5383 if (!filePath.isEmpty())
5385 QDateTime tmod=QFileInfo (filePath).lastModified();
5386 if (tmod>fileChangedTime)
5389 /* FIXME debug message, sometimes there's a glitch in the metrics...
5390 cout << "ME::fileChanged()\n"
5391 << " last saved: "<<qPrintable (fileChangedTime.toString())<<endl
5392 << " last modififed: "<<qPrintable (tmod.toString())<<endl;
5394 // FIXME switch to current mapeditor and finish lineedits...
5395 QMessageBox mb( vymName,
5396 tr("The file of the map on disk has changed:\n\n"
5397 " %1\n\nDo you want to reload that map with the new file?").arg(filePath),
5398 QMessageBox::Question,
5400 QMessageBox::Cancel | QMessageBox::Default,
5401 QMessageBox::NoButton );
5403 mb.setButtonText( QMessageBox::Yes, tr("Reload"));
5404 mb.setButtonText( QMessageBox::No, tr("Ignore"));
5407 case QMessageBox::Yes:
5409 load (filePath,NewMap,fileType);
5410 case QMessageBox::Cancel:
5411 fileChangedTime=tmod; // allow autosave to overwrite newer file!
5419 /*TODO not needed? void MapEditor::contentsDropEvent(QDropEvent *event)
5422 } else if (event->provides("application/x-moz-file-promise-url") &&
5423 event->provides("application/x-moz-nativeimage"))
5425 // Contains url to the img src in unicode16
5426 QByteArray d = event->encodedData("application/x-moz-file-promise-url");
5427 QString url = QString((const QChar*)d.data(),d.size()/2);
5431 } else if (event->provides ("text/uri-list"))
5432 { // Uris provided e.g. by konqueror
5433 Q3UriDrag::decode (event,uris);
5434 } else if (event->provides ("_NETSCAPE_URL"))
5435 { // Uris provided by Mozilla
5436 QStringList l = QStringList::split("\n", event->encodedData("_NETSCAPE_URL"));
5439 } else if (event->provides("text/html")) {
5441 // Handels text mime types
5442 // Look like firefox allways handle text as unicode16 (2 bytes per char.)
5443 QByteArray d = event->encodedData("text/html");
5446 text = QString((const QChar*)d.data(),d.size()/2);
5450 textEditor->setText(text);
5454 } else if (event->provides("text/plain")) {
5455 QByteArray d = event->encodedData("text/plain");
5458 text = QString((const QChar*)d.data(),d.size()/2);
5462 textEditor->setText(text);
5472 bool isUnicode16(const QByteArray &d)
5474 // TODO: make more precise check for unicode 16.
5475 // Guess unicode16 if any of second bytes are zero
5476 unsigned int length = max(0,d.size()-2)/2;
5477 for (unsigned int i = 0; i<length ; i++)
5478 if (d.at(i*2+1)==0) return true;
5482 void MapEditor::addFloatImageInt (const QPixmap &img)
5484 BranchObj *bo=xelection.getBranch();
5487 FloatImageObj *fio=bo->addFloatImage();
5489 fio->setOriginalFilename("No original filename (image added by dropevent)");
5490 QString s=model->getSelectString(bo);
5491 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy dropped image to clipboard",fio );
5492 saveState (fio,"delete ()", bo,QString("paste(%1)").arg(curStep),"Pasting dropped image");
5493 model->reposition();
5500 void MapEditor::imageDataFetched(const QByteArray &a, Q3NetworkOperation * / *nop* /)
5502 if (!imageBuffer) imageBuffer = new QBuffer();
5503 if (!imageBuffer->isOpen()) {
5504 imageBuffer->open(QIODevice::WriteOnly | QIODevice::Append);
5506 imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a));
5510 void MapEditor::imageDataFinished(Q3NetworkOperation *nop)
5512 if (nop->state()==Q3NetworkProtocol::StDone) {
5513 QPixmap img(imageBuffer->buffer());
5514 addFloatImageInt (img);
5518 imageBuffer->close();
5520 imageBuffer->close();
5527 void MapEditor::fetchImage(const QString &url)
5530 urlOperator->stop();
5531 disconnect(urlOperator);
5535 urlOperator = new Q3UrlOperator(url);
5536 connect(urlOperator, SIGNAL(finished(Q3NetworkOperation *)),
5537 this, SLOT(imageDataFinished(Q3NetworkOperation*)));
5539 connect(urlOperator, SIGNAL(data(const QByteArray &, Q3NetworkOperation *)),
5540 this, SLOT(imageDataFetched(const QByteArray &, Q3NetworkOperation *)));