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\n";
189 autosaveTimer->stop();
190 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 return QString("branch (%1)").arg(s);
254 if ((typeid(*lmo) == typeid(FloatImageObj) ))
255 return QString ("floatimage [%1]").arg(((FloatImageObj*)lmo)->getOriginalFilename());
256 return QString("Unknown type has no name!");
259 void MapEditor::makeTmpDirs()
261 // Create unique temporary directories
262 tmpMapDir = tmpVymDir+QString("/mapeditor-%1").arg(mapNum);
263 histPath = tmpMapDir+"/history";
268 QString MapEditor::saveToDir(const QString &tmpdir, const QString &prefix, bool writeflags, const QPointF &offset, LinkableMapObj *saveSel)
270 // tmpdir temporary directory to which data will be written
271 // prefix mapname, which will be appended to images etc.
272 // writeflags Only write flags for "real" save of map, not undo
273 // offset offset of bbox of whole map in scene.
274 // Needed for XML export
280 case LinkableMapObj::Line:
283 case LinkableMapObj::Parabel:
286 case LinkableMapObj::PolyLine:
290 ls="StylePolyParabel";
294 QString s="<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE vymmap>\n";
296 if (linkcolorhint==LinkableMapObj::HeadingColor)
297 colhint=attribut("linkColorHint","HeadingColor");
299 QString mapAttr=attribut("version",vymVersion);
301 mapAttr+= attribut("author",model->getAuthor()) +
302 attribut("comment",model->getComment()) +
303 attribut("date",model->getDate()) +
304 attribut("backgroundColor", mapScene->backgroundBrush().color().name() ) +
305 attribut("selectionColor", xelection.getColor().name() ) +
306 attribut("linkStyle", ls ) +
307 attribut("linkColor", defLinkColor.name() ) +
308 attribut("defXLinkColor", defXLinkColor.name() ) +
309 attribut("defXLinkWidth", QString().setNum(defXLinkWidth,10) ) +
311 s+=beginElement("vymmap",mapAttr);
314 // Find the used flags while traversing the tree
315 standardFlagsDefault->resetUsedCounter();
317 // Reset the counters before saving
318 // TODO constr. of FIO creates lots of objects, better do this in some other way...
319 FloatImageObj (mapScene).resetSaveCounter();
321 // Build xml recursivly
322 if (!saveSel || typeid (*saveSel) == typeid (MapCenterObj))
323 // Save complete map, if saveSel not set
324 s+=model->saveToDir(tmpdir,prefix,writeflags,offset);
327 if ( typeid(*saveSel) == typeid(BranchObj) )
329 s+=((BranchObj*)(saveSel))->saveToDir(tmpdir,prefix,offset);
330 else if ( typeid(*saveSel) == typeid(FloatImageObj) )
332 s+=((FloatImageObj*)(saveSel))->saveToDir(tmpdir,prefix);
335 // Save local settings
336 s+=settings.getDataXML (destPath);
339 if (!xelection.isEmpty() && !saveSel )
340 s+=valueElement("select",xelection.getSelectString());
343 s+=endElement("vymmap");
346 standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags);
350 QString MapEditor::getHistoryDir()
352 QString histName(QString("history-%1").arg(curStep));
353 return (tmpMapDir+"/"+histName);
356 void MapEditor::saveState(const SaveMode &savemode, const QString &undoSelection, const QString &undoCom, const QString &redoSelection, const QString &redoCom, const QString &comment, LinkableMapObj *saveSel)
358 sendData(redoCom); //FIXME testing
363 if (blockSaveState) return;
365 if (debug) cout << "ME::saveState() for "<<qPrintable (mapName)<<endl;
367 // Find out current undo directory
368 if (undosAvail<stepsTotal) undosAvail++;
370 if (curStep>stepsTotal) curStep=1;
372 QString backupXML="";
373 QString histDir=getHistoryDir();
374 QString bakMapPath=histDir+"/map.xml";
376 // Create histDir if not available
379 makeSubDirs (histDir);
381 // Save depending on how much needs to be saved
383 backupXML=saveToDir (histDir,mapName+"-",false, QPointF (),saveSel);
385 QString undoCommand="";
386 if (savemode==UndoCommand)
390 else if (savemode==PartOfMap )
393 undoCommand.replace ("PATH",bakMapPath);
396 if (!backupXML.isEmpty())
397 // Write XML Data to disk
398 saveStringToDisk (bakMapPath,backupXML);
400 // We would have to save all actions in a tree, to keep track of
401 // possible redos after a action. Possible, but we are too lazy: forget about redos.
404 // Write the current state to disk
405 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
406 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
407 undoSet.setEntry ("/history/curStep",QString::number(curStep));
408 undoSet.setEntry (QString("/history/step-%1/undoCommand").arg(curStep),undoCommand);
409 undoSet.setEntry (QString("/history/step-%1/undoSelection").arg(curStep),undoSelection);
410 undoSet.setEntry (QString("/history/step-%1/redoCommand").arg(curStep),redoCom);
411 undoSet.setEntry (QString("/history/step-%1/redoSelection").arg(curStep),redoSelection);
412 undoSet.setEntry (QString("/history/step-%1/comment").arg(curStep),comment);
413 undoSet.setEntry (QString("/history/version"),vymVersion);
414 undoSet.writeSettings(histPath);
418 // TODO remove after testing
419 //cout << " into="<< histPath.toStdString()<<endl;
420 cout << " stepsTotal="<<stepsTotal<<
421 ", undosAvail="<<undosAvail<<
422 ", redosAvail="<<redosAvail<<
423 ", curStep="<<curStep<<endl;
424 cout << " ---------------------------"<<endl;
425 cout << " comment="<<comment.toStdString()<<endl;
426 cout << " undoCom="<<undoCommand.toStdString()<<endl;
427 cout << " undoSel="<<undoSelection.toStdString()<<endl;
428 cout << " redoCom="<<redoCom.toStdString()<<endl;
429 cout << " redoSel="<<redoSelection.toStdString()<<endl;
430 if (saveSel) cout << " saveSel="<<qPrintable (model->getSelectString(saveSel))<<endl;
431 cout << " ---------------------------"<<endl;
434 mainWindow->updateHistory (undoSet);
440 void MapEditor::saveStateChangingPart(LinkableMapObj *undoSel, LinkableMapObj* redoSel, const QString &rc, const QString &comment)
442 // save the selected part of the map, Undo will replace part of map
443 QString undoSelection="";
445 undoSelection=model->getSelectString(undoSel);
447 qWarning ("MapEditor::saveStateChangingPart no undoSel given!");
448 QString redoSelection="";
450 redoSelection=model->getSelectString(undoSel);
452 qWarning ("MapEditor::saveStateChangingPart no redoSel given!");
455 saveState (PartOfMap,
456 undoSelection, "addMapReplace (\"PATH\")",
462 void MapEditor::saveStateRemovingPart(LinkableMapObj *redoSel, const QString &comment)
466 qWarning ("MapEditor::saveStateRemovingPart no redoSel given!");
469 QString undoSelection=model->getSelectString (redoSel->getParObj());
470 QString redoSelection=model->getSelectString(redoSel);
471 if (typeid(*redoSel) == typeid(BranchObj) )
473 // save the selected branch of the map, Undo will insert part of map
474 saveState (PartOfMap,
475 undoSelection, QString("addMapInsert (\"PATH\",%1)").arg(((BranchObj*)redoSel)->getNum()),
476 redoSelection, "delete ()",
483 void MapEditor::saveState(LinkableMapObj *undoSel, const QString &uc, LinkableMapObj *redoSel, const QString &rc, const QString &comment)
485 // "Normal" savestate: save commands, selections and comment
486 // so just save commands for undo and redo
487 // and use current selection
489 QString redoSelection="";
490 if (redoSel) redoSelection=model->getSelectString(redoSel);
491 QString undoSelection="";
492 if (undoSel) undoSelection=model->getSelectString(undoSel);
494 saveState (UndoCommand,
501 void MapEditor::saveState(const QString &undoSel, const QString &uc, const QString &redoSel, const QString &rc, const QString &comment)
503 // "Normal" savestate: save commands, selections and comment
504 // so just save commands for undo and redo
505 // and use current selection
506 saveState (UndoCommand,
513 void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment)
515 // "Normal" savestate applied to model (no selection needed):
516 // save commands and comment
517 saveState (UndoCommand,
525 void MapEditor::parseAtom(const QString &atom)
527 BranchObj *selb=xelection.getBranch();
533 // Split string s into command and parameters
534 parser.parseAtom (atom);
535 QString com=parser.getCommand();
538 /////////////////////////////////////////////////////////////////////
539 if (com=="addBranch")
541 if (xelection.isEmpty())
543 parser.setError (Aborted,"Nothing selected");
546 parser.setError (Aborted,"Type of selection is not a branch");
551 if (parser.checkParCount(pl))
553 if (parser.parCount()==0)
557 n=parser.parInt (ok,0);
558 if (ok ) addNewBranch (n);
562 /////////////////////////////////////////////////////////////////////
563 } else if (com=="addBranchBefore")
565 if (xelection.isEmpty())
567 parser.setError (Aborted,"Nothing selected");
570 parser.setError (Aborted,"Type of selection is not a branch");
573 if (parser.parCount()==0)
575 addNewBranchBefore ();
578 /////////////////////////////////////////////////////////////////////
579 } else if (com==QString("addMapCenter"))
581 if (parser.checkParCount(2))
583 x=parser.parDouble (ok,0);
586 y=parser.parDouble (ok,1);
587 if (ok) model->addMapCenter (QPointF(x,y));
590 /////////////////////////////////////////////////////////////////////
591 } else if (com==QString("addMapReplace"))
593 if (xelection.isEmpty())
595 parser.setError (Aborted,"Nothing selected");
598 parser.setError (Aborted,"Type of selection is not a branch");
599 } else if (parser.checkParCount(1))
601 //s=parser.parString (ok,0); // selection
602 t=parser.parString (ok,0); // path to map
603 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
604 addMapReplaceInt(model->getSelectString(selb),t);
606 /////////////////////////////////////////////////////////////////////
607 } else if (com==QString("addMapInsert"))
609 if (xelection.isEmpty())
611 parser.setError (Aborted,"Nothing selected");
614 parser.setError (Aborted,"Type of selection is not a branch");
617 if (parser.checkParCount(2))
619 t=parser.parString (ok,0); // path to map
620 n=parser.parInt(ok,1); // position
621 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
622 addMapInsertInt(t,n);
625 /////////////////////////////////////////////////////////////////////
626 } else if (com=="clearFlags")
628 if (xelection.isEmpty() )
630 parser.setError (Aborted,"Nothing selected");
633 parser.setError (Aborted,"Type of selection is not a branch");
634 } else if (parser.checkParCount(0))
636 selb->clearStandardFlags();
637 selb->updateFlagsToolbar();
639 /////////////////////////////////////////////////////////////////////
640 } else if (com=="colorBranch")
642 if (xelection.isEmpty())
644 parser.setError (Aborted,"Nothing selected");
647 parser.setError (Aborted,"Type of selection is not a branch");
648 } else if (parser.checkParCount(1))
650 QColor c=parser.parColor (ok,0);
651 if (ok) colorBranch (c);
653 /////////////////////////////////////////////////////////////////////
654 } else if (com=="colorSubtree")
656 if (xelection.isEmpty())
658 parser.setError (Aborted,"Nothing selected");
661 parser.setError (Aborted,"Type of selection is not a branch");
662 } else if (parser.checkParCount(1))
664 QColor c=parser.parColor (ok,0);
665 if (ok) colorSubtree (c);
667 /////////////////////////////////////////////////////////////////////
668 } else if (com=="copy")
670 if (xelection.isEmpty())
672 parser.setError (Aborted,"Nothing selected");
675 parser.setError (Aborted,"Type of selection is not a branch");
676 } else if (parser.checkParCount(0))
678 //FIXME missing action for copy
680 /////////////////////////////////////////////////////////////////////
681 } else if (com=="cut")
683 if (xelection.isEmpty())
685 parser.setError (Aborted,"Nothing selected");
686 } else if ( xelection.type()!=Selection::Branch &&
687 xelection.type()!=Selection::MapCenter &&
688 xelection.type()!=Selection::FloatImage )
690 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
691 } else if (parser.checkParCount(0))
695 /////////////////////////////////////////////////////////////////////
696 } else if (com=="delete")
698 if (xelection.isEmpty())
700 parser.setError (Aborted,"Nothing selected");
702 /*else if (xelection.type() != Selection::Branch && xelection.type() != Selection::FloatImage )
704 parser.setError (Aborted,"Type of selection is wrong.");
707 else if (parser.checkParCount(0))
711 /////////////////////////////////////////////////////////////////////
712 } else if (com=="deleteKeepChilds")
714 if (xelection.isEmpty())
716 parser.setError (Aborted,"Nothing selected");
719 parser.setError (Aborted,"Type of selection is not a branch");
720 } else if (parser.checkParCount(0))
724 /////////////////////////////////////////////////////////////////////
725 } else if (com=="deleteChilds")
727 if (xelection.isEmpty())
729 parser.setError (Aborted,"Nothing selected");
732 parser.setError (Aborted,"Type of selection is not a branch");
733 } else if (parser.checkParCount(0))
737 /////////////////////////////////////////////////////////////////////
738 } else if (com=="exportASCII")
742 if (parser.parCount()>=1)
743 // Hey, we even have a filename
744 fname=parser.parString(ok,0);
747 parser.setError (Aborted,"Could not read filename");
750 exportASCII (fname,false);
752 /////////////////////////////////////////////////////////////////////
753 } else if (com=="exportImage")
757 if (parser.parCount()>=2)
758 // Hey, we even have a filename
759 fname=parser.parString(ok,0);
762 parser.setError (Aborted,"Could not read filename");
765 QString format="PNG";
766 if (parser.parCount()>=2)
768 format=parser.parString(ok,1);
770 exportImage (fname,false,format);
772 /////////////////////////////////////////////////////////////////////
773 } else if (com=="exportXHTML")
777 if (parser.parCount()>=2)
778 // Hey, we even have a filename
779 fname=parser.parString(ok,1);
782 parser.setError (Aborted,"Could not read filename");
785 exportXHTML (fname,false);
787 /////////////////////////////////////////////////////////////////////
788 } else if (com=="exportXML")
792 if (parser.parCount()>=2)
793 // Hey, we even have a filename
794 fname=parser.parString(ok,1);
797 parser.setError (Aborted,"Could not read filename");
800 exportXML (fname,false);
802 /////////////////////////////////////////////////////////////////////
803 } else if (com=="importDir")
805 if (xelection.isEmpty())
807 parser.setError (Aborted,"Nothing selected");
810 parser.setError (Aborted,"Type of selection is not a branch");
811 } else if (parser.checkParCount(1))
813 s=parser.parString(ok,0);
814 if (ok) importDirInt(s);
816 /////////////////////////////////////////////////////////////////////
817 } else if (com=="linkTo")
819 if (xelection.isEmpty())
821 parser.setError (Aborted,"Nothing selected");
824 if (parser.checkParCount(4))
826 // 0 selectstring of parent
827 // 1 num in parent (for branches)
828 // 2,3 x,y of mainbranch or mapcenter
829 s=parser.parString(ok,0);
830 LinkableMapObj *dst=model->findObjBySelect (s);
833 if (typeid(*dst) == typeid(BranchObj) )
835 // Get number in parent
836 n=parser.parInt (ok,1);
839 selb->linkTo ((BranchObj*)(dst),n);
842 } else if (typeid(*dst) == typeid(MapCenterObj) )
844 selb->linkTo ((BranchObj*)(dst),-1);
845 // Get coordinates of mainbranch
846 x=parser.parDouble(ok,2);
849 y=parser.parDouble(ok,3);
859 } else if ( xelection.type() == Selection::FloatImage)
861 if (parser.checkParCount(1))
863 // 0 selectstring of parent
864 s=parser.parString(ok,0);
865 LinkableMapObj *dst=model->findObjBySelect (s);
868 if (typeid(*dst) == typeid(BranchObj) ||
869 typeid(*dst) == typeid(MapCenterObj))
870 linkTo (model->getSelectString(dst));
872 parser.setError (Aborted,"Destination is not a branch");
875 parser.setError (Aborted,"Type of selection is not a floatimage or branch");
876 /////////////////////////////////////////////////////////////////////
877 } else if (com=="loadImage")
879 if (xelection.isEmpty())
881 parser.setError (Aborted,"Nothing selected");
884 parser.setError (Aborted,"Type of selection is not a branch");
885 } else if (parser.checkParCount(1))
887 s=parser.parString(ok,0);
888 if (ok) loadFloatImageInt (s);
890 /////////////////////////////////////////////////////////////////////
891 } else if (com=="moveBranchUp")
893 if (xelection.isEmpty() )
895 parser.setError (Aborted,"Nothing selected");
898 parser.setError (Aborted,"Type of selection is not a branch");
899 } else if (parser.checkParCount(0))
903 /////////////////////////////////////////////////////////////////////
904 } else if (com=="moveBranchDown")
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(0))
916 /////////////////////////////////////////////////////////////////////
917 } else if (com=="move")
919 if (xelection.isEmpty() )
921 parser.setError (Aborted,"Nothing selected");
922 } else if ( xelection.type()!=Selection::Branch &&
923 xelection.type()!=Selection::MapCenter &&
924 xelection.type()!=Selection::FloatImage )
926 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
927 } else if (parser.checkParCount(2))
929 x=parser.parDouble (ok,0);
932 y=parser.parDouble (ok,1);
936 /////////////////////////////////////////////////////////////////////
937 } else if (com=="moveRel")
939 if (xelection.isEmpty() )
941 parser.setError (Aborted,"Nothing selected");
942 } else if ( xelection.type()!=Selection::Branch &&
943 xelection.type()!=Selection::MapCenter &&
944 xelection.type()!=Selection::FloatImage )
946 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
947 } else if (parser.checkParCount(2))
949 x=parser.parDouble (ok,0);
952 y=parser.parDouble (ok,1);
953 if (ok) moveRel (x,y);
956 /////////////////////////////////////////////////////////////////////
957 } else if (com=="nop")
959 /////////////////////////////////////////////////////////////////////
960 } else if (com=="paste")
962 if (xelection.isEmpty() )
964 parser.setError (Aborted,"Nothing selected");
967 parser.setError (Aborted,"Type of selection is not a branch");
968 } else if (parser.checkParCount(1))
970 n=parser.parInt (ok,0);
971 if (ok) pasteNoSave(n);
973 /////////////////////////////////////////////////////////////////////
974 } else if (com=="qa")
976 if (xelection.isEmpty() )
978 parser.setError (Aborted,"Nothing selected");
981 parser.setError (Aborted,"Type of selection is not a branch");
982 } else if (parser.checkParCount(4))
985 c=parser.parString (ok,0);
988 parser.setError (Aborted,"No comment given");
991 s=parser.parString (ok,1);
994 parser.setError (Aborted,"First parameter is not a string");
997 t=parser.parString (ok,2);
1000 parser.setError (Aborted,"Condition is not a string");
1003 u=parser.parString (ok,3);
1006 parser.setError (Aborted,"Third parameter is not a string");
1011 parser.setError (Aborted,"Unknown type: "+s);
1016 parser.setError (Aborted,"Unknown operator: "+t);
1021 parser.setError (Aborted,"Type of selection is not a branch");
1024 if (selb->getHeading() == u)
1026 cout << "PASSED: " << qPrintable (c) << endl;
1029 cout << "FAILED: " << qPrintable (c) << endl;
1039 /////////////////////////////////////////////////////////////////////
1040 } else if (com=="saveImage")
1042 FloatImageObj *fio=xelection.getFloatImage();
1045 parser.setError (Aborted,"Type of selection is not an image");
1046 } else if (parser.checkParCount(2))
1048 s=parser.parString(ok,0);
1051 t=parser.parString(ok,1);
1052 if (ok) saveFloatImageInt (fio,t,s);
1055 /////////////////////////////////////////////////////////////////////
1056 } else if (com=="scroll")
1058 if (xelection.isEmpty() )
1060 parser.setError (Aborted,"Nothing selected");
1063 parser.setError (Aborted,"Type of selection is not a branch");
1064 } else if (parser.checkParCount(0))
1066 if (!scrollBranch (selb))
1067 parser.setError (Aborted,"Could not scroll branch");
1069 /////////////////////////////////////////////////////////////////////
1070 } else if (com=="select")
1072 if (parser.checkParCount(1))
1074 s=parser.parString(ok,0);
1077 /////////////////////////////////////////////////////////////////////
1078 } else if (com=="selectLastBranch")
1080 if (xelection.isEmpty() )
1082 parser.setError (Aborted,"Nothing selected");
1085 parser.setError (Aborted,"Type of selection is not a branch");
1086 } else if (parser.checkParCount(0))
1088 BranchObj *bo=selb->getLastBranch();
1090 parser.setError (Aborted,"Could not select last branch");
1094 /////////////////////////////////////////////////////////////////////
1095 } else if (com=="selectLastImage")
1097 if (xelection.isEmpty() )
1099 parser.setError (Aborted,"Nothing selected");
1102 parser.setError (Aborted,"Type of selection is not a branch");
1103 } else if (parser.checkParCount(0))
1105 FloatImageObj *fio=selb->getLastFloatImage();
1107 parser.setError (Aborted,"Could not select last image");
1111 /////////////////////////////////////////////////////////////////////
1112 } else if (com=="selectLatestAdded")
1114 if (latestSelection.isEmpty() )
1116 parser.setError (Aborted,"No latest added object");
1119 if (!select (latestSelection))
1120 parser.setError (Aborted,"Could not select latest added object "+latestSelection);
1122 /////////////////////////////////////////////////////////////////////
1123 } else if (com=="setFrameType")
1125 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1127 parser.setError (Aborted,"Type of selection does not allow setting frame type");
1129 else if (parser.checkParCount(1))
1131 s=parser.parString(ok,0);
1132 if (ok) setFrameType (s);
1134 /////////////////////////////////////////////////////////////////////
1135 } else if (com=="setFramePenColor")
1137 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1139 parser.setError (Aborted,"Type of selection does not allow setting of pen color");
1141 else if (parser.checkParCount(1))
1143 QColor c=parser.parColor(ok,0);
1144 if (ok) setFramePenColor (c);
1146 /////////////////////////////////////////////////////////////////////
1147 } else if (com=="setFrameBrushColor")
1149 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1151 parser.setError (Aborted,"Type of selection does not allow setting brush color");
1153 else if (parser.checkParCount(1))
1155 QColor c=parser.parColor(ok,0);
1156 if (ok) setFrameBrushColor (c);
1158 /////////////////////////////////////////////////////////////////////
1159 } else if (com=="setFramePadding")
1161 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1163 parser.setError (Aborted,"Type of selection does not allow setting frame padding");
1165 else if (parser.checkParCount(1))
1167 n=parser.parInt(ok,0);
1168 if (ok) setFramePadding(n);
1170 /////////////////////////////////////////////////////////////////////
1171 } else if (com=="setFrameBorderWidth")
1173 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1175 parser.setError (Aborted,"Type of selection does not allow setting frame border width");
1177 else if (parser.checkParCount(1))
1179 n=parser.parInt(ok,0);
1180 if (ok) setFrameBorderWidth (n);
1182 /////////////////////////////////////////////////////////////////////
1183 } else if (com=="setMapAuthor")
1185 if (parser.checkParCount(1))
1187 s=parser.parString(ok,0);
1188 if (ok) setMapAuthor (s);
1190 /////////////////////////////////////////////////////////////////////
1191 } else if (com=="setMapComment")
1193 if (parser.checkParCount(1))
1195 s=parser.parString(ok,0);
1196 if (ok) setMapComment(s);
1198 /////////////////////////////////////////////////////////////////////
1199 } else if (com=="setMapBackgroundColor")
1201 if (xelection.isEmpty() )
1203 parser.setError (Aborted,"Nothing selected");
1204 } else if (! xelection.getBranch() )
1206 parser.setError (Aborted,"Type of selection is not a branch");
1207 } else if (parser.checkParCount(1))
1209 QColor c=parser.parColor (ok,0);
1210 if (ok) setMapBackgroundColor (c);
1212 /////////////////////////////////////////////////////////////////////
1213 } else if (com=="setMapDefLinkColor")
1215 if (xelection.isEmpty() )
1217 parser.setError (Aborted,"Nothing selected");
1220 parser.setError (Aborted,"Type of selection is not a branch");
1221 } else if (parser.checkParCount(1))
1223 QColor c=parser.parColor (ok,0);
1224 if (ok) setMapDefLinkColor (c);
1226 /////////////////////////////////////////////////////////////////////
1227 } else if (com=="setMapLinkStyle")
1229 if (parser.checkParCount(1))
1231 s=parser.parString (ok,0);
1232 if (ok) setMapLinkStyle(s);
1234 /////////////////////////////////////////////////////////////////////
1235 } else if (com=="setHeading")
1237 if (xelection.isEmpty() )
1239 parser.setError (Aborted,"Nothing selected");
1242 parser.setError (Aborted,"Type of selection is not a branch");
1243 } else if (parser.checkParCount(1))
1245 s=parser.parString (ok,0);
1249 /////////////////////////////////////////////////////////////////////
1250 } else if (com=="setHideExport")
1252 if (xelection.isEmpty() )
1254 parser.setError (Aborted,"Nothing selected");
1255 } else if (xelection.type()!=Selection::Branch && xelection.type() != Selection::MapCenter &&xelection.type()!=Selection::FloatImage)
1257 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
1258 } else if (parser.checkParCount(1))
1260 b=parser.parBool(ok,0);
1261 if (ok) setHideExport (b);
1263 /////////////////////////////////////////////////////////////////////
1264 } else if (com=="setIncludeImagesHorizontally")
1266 if (xelection.isEmpty() )
1268 parser.setError (Aborted,"Nothing selected");
1271 parser.setError (Aborted,"Type of selection is not a branch");
1272 } else if (parser.checkParCount(1))
1274 b=parser.parBool(ok,0);
1275 if (ok) setIncludeImagesHor(b);
1277 /////////////////////////////////////////////////////////////////////
1278 } else if (com=="setIncludeImagesVertically")
1280 if (xelection.isEmpty() )
1282 parser.setError (Aborted,"Nothing selected");
1285 parser.setError (Aborted,"Type of selection is not a branch");
1286 } else if (parser.checkParCount(1))
1288 b=parser.parBool(ok,0);
1289 if (ok) setIncludeImagesVer(b);
1291 /////////////////////////////////////////////////////////////////////
1292 } else if (com=="setHideLinkUnselected")
1294 if (xelection.isEmpty() )
1296 parser.setError (Aborted,"Nothing selected");
1297 } else if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1299 parser.setError (Aborted,"Type of selection does not allow hiding the link");
1300 } else if (parser.checkParCount(1))
1302 b=parser.parBool(ok,0);
1303 if (ok) setHideLinkUnselected(b);
1305 /////////////////////////////////////////////////////////////////////
1306 } else if (com=="setSelectionColor")
1308 if (parser.checkParCount(1))
1310 QColor c=parser.parColor (ok,0);
1311 if (ok) setSelectionColorInt (c);
1313 /////////////////////////////////////////////////////////////////////
1314 } else if (com=="setURL")
1316 if (xelection.isEmpty() )
1318 parser.setError (Aborted,"Nothing selected");
1321 parser.setError (Aborted,"Type of selection is not a branch");
1322 } else if (parser.checkParCount(1))
1324 s=parser.parString (ok,0);
1327 /////////////////////////////////////////////////////////////////////
1328 } else if (com=="setVymLink")
1330 if (xelection.isEmpty() )
1332 parser.setError (Aborted,"Nothing selected");
1335 parser.setError (Aborted,"Type of selection is not a branch");
1336 } else if (parser.checkParCount(1))
1338 s=parser.parString (ok,0);
1339 if (ok) setVymLinkInt(s);
1342 /////////////////////////////////////////////////////////////////////
1343 else if (com=="setFlag")
1345 if (xelection.isEmpty() )
1347 parser.setError (Aborted,"Nothing selected");
1350 parser.setError (Aborted,"Type of selection is not a branch");
1351 } else if (parser.checkParCount(1))
1353 s=parser.parString(ok,0);
1356 selb->activateStandardFlag(s);
1357 selb->updateFlagsToolbar();
1360 /////////////////////////////////////////////////////////////////////
1361 } else if (com=="setFrameType")
1363 if (xelection.isEmpty() )
1365 parser.setError (Aborted,"Nothing selected");
1368 parser.setError (Aborted,"Type of selection is not a branch");
1369 } else if (parser.checkParCount(1))
1371 s=parser.parString(ok,0);
1375 /////////////////////////////////////////////////////////////////////
1376 } else if (com=="sortChildren")
1378 if (xelection.isEmpty() )
1380 parser.setError (Aborted,"Nothing selected");
1383 parser.setError (Aborted,"Type of selection is not a branch");
1384 } else if (parser.checkParCount(0))
1388 /////////////////////////////////////////////////////////////////////
1389 } else if (com=="toggleFlag")
1391 if (xelection.isEmpty() )
1393 parser.setError (Aborted,"Nothing selected");
1396 parser.setError (Aborted,"Type of selection is not a branch");
1397 } else if (parser.checkParCount(1))
1399 s=parser.parString(ok,0);
1402 selb->toggleStandardFlag(s);
1403 selb->updateFlagsToolbar();
1406 /////////////////////////////////////////////////////////////////////
1407 } else if (com=="unscroll")
1409 if (xelection.isEmpty() )
1411 parser.setError (Aborted,"Nothing selected");
1414 parser.setError (Aborted,"Type of selection is not a branch");
1415 } else if (parser.checkParCount(0))
1417 if (!unscrollBranch (selb))
1418 parser.setError (Aborted,"Could not unscroll branch");
1420 /////////////////////////////////////////////////////////////////////
1421 } else if (com=="unscrollChilds")
1423 if (xelection.isEmpty() )
1425 parser.setError (Aborted,"Nothing selected");
1428 parser.setError (Aborted,"Type of selection is not a branch");
1429 } else if (parser.checkParCount(0))
1433 /////////////////////////////////////////////////////////////////////
1434 } else if (com=="unsetFlag")
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(1))
1444 s=parser.parString(ok,0);
1447 selb->deactivateStandardFlag(s);
1448 selb->updateFlagsToolbar();
1452 parser.setError (Aborted,"Unknown command");
1455 if (parser.errorLevel()==NoError)
1457 // setChanged(); FIXME should not be called e.g. for export?!
1458 model->reposition();
1462 // TODO Error handling
1463 qWarning("MapEditor::parseAtom: Error!");
1464 qWarning(parser.errorMessage());
1468 void MapEditor::runScript (QString script)
1470 parser.setScript (script);
1472 while (parser.next() )
1473 parseAtom(parser.getAtom());
1476 bool MapEditor::isDefault()
1481 bool MapEditor::hasChanged()
1486 void MapEditor::setChanged()
1489 autosaveTimer->start(settings.value("/mapeditor/autosave/ms/",300000).toInt());
1497 void MapEditor::closeMap()
1499 // Unselect before disabling the toolbar actions
1500 if (!xelection.isEmpty() ) xelection.unselect();
1505 // close(); FIXME needed?
1508 void MapEditor::setFilePath(QString fpath, QString destname)
1510 if (fpath.isEmpty() || fpath=="")
1517 filePath=fpath; // becomes absolute path
1518 fileName=fpath; // gets stripped of path
1519 destPath=destname; // needed for vymlinks and during load to reset fileChangedTime
1521 // If fpath is not an absolute path, complete it
1522 filePath=QDir(fpath).absPath();
1523 fileDir=filePath.left (1+filePath.findRev ("/"));
1525 // Set short name, too. Search from behind:
1526 int i=fileName.findRev("/");
1527 if (i>=0) fileName=fileName.remove (0,i+1);
1529 // Forget the .vym (or .xml) for name of map
1530 mapName=fileName.left(fileName.findRev(".",-1,true) );
1534 void MapEditor::setFilePath(QString fpath)
1536 setFilePath (fpath,fpath);
1539 QString MapEditor::getFilePath()
1544 QString MapEditor::getFileName()
1549 QString MapEditor::getMapName()
1554 QString MapEditor::getDestPath()
1559 ErrorCode MapEditor::load (QString fname, const LoadMode &lmode, const FileType &ftype)
1561 ErrorCode err=success;
1563 parseBaseHandler *handler;
1567 case VymMap: handler=new parseVYMHandler; break;
1568 case FreemindMap : handler=new parseFreemindHandler; break;
1570 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1571 "Unknown FileType in MapEditor::load()");
1575 // Save original zip state, important for inserting complete maps
1576 bool zipped_org=zipped;
1581 model->setMapEditor(this);
1582 // (map state is set later at end of load...)
1585 BranchObj *bo=xelection.getBranch();
1586 if (!bo) return aborted;
1587 if (lmode==ImportAdd)
1588 saveStateChangingPart(
1591 QString("addMapInsert (%1)").arg(fname),
1592 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1594 saveStateChangingPart(
1597 QString("addMapReplace(%1)").arg(fname),
1598 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1602 // Create temporary directory for packing
1604 QString tmpZipDir=makeTmpDir (ok,"vym-pack");
1607 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1608 tr("Couldn't create temporary directory before load\n"));
1612 // Try to unzip file
1613 err=unzipDir (tmpZipDir,fname);
1623 // Look for mapname.xml
1624 xmlfile= fname.left(fname.findRev(".",-1,true));
1625 xmlfile=xmlfile.section( '/', -1 );
1626 QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
1627 if (!mfile.exists() )
1629 // mapname.xml does not exist, well,
1630 // maybe someone renamed the mapname.vym file...
1631 // Try to find any .xml in the toplevel
1632 // directory of the .vym file
1633 QStringList flist=QDir (tmpZipDir).entryList("*.xml");
1634 if (flist.count()==1)
1636 // Only one entry, take this one
1637 xmlfile=tmpZipDir + "/"+flist.first();
1640 for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it )
1641 *it=tmpZipDir + "/" + *it;
1642 // TODO Multiple entries, load all (but only the first one into this ME)
1643 //mainWindow->fileLoadFromTmp (flist);
1644 //returnCode=1; // Silently forget this attempt to load
1645 qWarning ("MainWindow::load (fn) multimap found...");
1648 if (flist.isEmpty() )
1650 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1651 tr("Couldn't find a map (*.xml) in .vym archive.\n"));
1654 } //file doesn't exist
1656 xmlfile=mfile.name();
1659 QFile file( xmlfile);
1661 // I am paranoid: file should exist anyway
1662 // according to check in mainwindow.
1663 if (!file.exists() )
1665 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1666 tr(QString("Couldn't open map %1").arg(file.name())));
1670 bool blockSaveStateOrg=blockSaveState;
1671 blockReposition=true;
1672 blockSaveState=true;
1673 QXmlInputSource source( file);
1674 QXmlSimpleReader reader;
1675 reader.setContentHandler( handler );
1676 reader.setErrorHandler( handler );
1677 handler->setModel ( model);
1680 // We need to set the tmpDir in order to load files with rel. path
1685 tmpdir=fname.left(fname.findRev("/",-1));
1686 handler->setTmpDir (tmpdir);
1687 handler->setInputFile (file.name());
1688 handler->setLoadMode (lmode);
1689 bool ok = reader.parse( source );
1690 blockReposition=false;
1691 blockSaveState=blockSaveStateOrg;
1695 model->reposition(); // FIXME reposition the view instead...
1702 autosaveTimer->stop();
1705 // Reset timestamp to check for later updates of file
1706 fileChangedTime=QFileInfo (destPath).lastModified();
1709 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1710 tr( handler->errorProtocol() ) );
1712 // Still return "success": the map maybe at least
1713 // partially read by the parser
1718 removeDir (QDir(tmpZipDir));
1720 // Restore original zip state
1728 ErrorCode MapEditor::save (const SaveMode &savemode)
1731 QString mapFileName;
1732 QString safeFilePath;
1734 ErrorCode err=success;
1738 mapFileName=mapName+".xml";
1740 // use name given by user, even if he chooses .doc
1741 mapFileName=fileName;
1743 // Look, if we should zip the data:
1746 QMessageBox mb( vymName,
1747 tr("The map %1\ndid not use the compressed "
1748 "vym file format.\nWriting it uncompressed will also write images \n"
1749 "and flags and thus may overwrite files in the "
1750 "given directory\n\nDo you want to write the map").arg(filePath),
1751 QMessageBox::Warning,
1752 QMessageBox::Yes | QMessageBox::Default,
1754 QMessageBox::Cancel | QMessageBox::Escape);
1755 mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
1756 mb.setButtonText( QMessageBox::No, tr("uncompressed") );
1757 mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
1760 case QMessageBox::Yes:
1761 // save compressed (default file format)
1764 case QMessageBox::No:
1765 // save uncompressed
1768 case QMessageBox::Cancel:
1775 // First backup existing file, we
1776 // don't want to add to old zip archives
1780 if ( settings.value ("/mapeditor/writeBackupFile").toBool())
1782 QString backupFileName(destPath + "~");
1783 QFile backupFile(backupFileName);
1784 if (backupFile.exists() && !backupFile.remove())
1786 QMessageBox::warning(0, tr("Save Error"),
1787 tr("%1\ncould not be removed before saving").arg(backupFileName));
1789 else if (!f.rename(backupFileName))
1791 QMessageBox::warning(0, tr("Save Error"),
1792 tr("%1\ncould not be renamed before saving").arg(destPath));
1799 // Create temporary directory for packing
1801 tmpZipDir=makeTmpDir (ok,"vym-zip");
1804 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1805 tr("Couldn't create temporary directory before save\n"));
1809 // cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1810 safeFilePath=filePath;
1811 setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
1814 // Create mapName and fileDir
1815 makeSubDirs (fileDir);
1819 cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1820 cout <<"ME::save saveFilePath="<<safeFilePath.toStdString()<<endl;
1821 cout <<"ME::save destPath="<<destPath.toStdString()<<endl;
1822 cout <<"ME::save mapName="<<mapName.toStdString()<<endl;
1823 cout <<"ME::save mapFileName="<<mapFileName.toStdString()<<endl;
1827 if (savemode==CompleteMap || xelection.isEmpty())
1829 // Save complete map
1830 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),NULL);
1833 autosaveTimer->stop();
1838 if (xelection.type()==Selection::FloatImage)
1841 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),xelection.getBranch());
1842 // TODO take care of multiselections
1845 if (!saveStringToDisk(fileDir+mapFileName,saveFile))
1848 qWarning ("ME::saveStringToDisk failed!");
1854 if (err==success) err=zipDir (tmpZipDir,destPath);
1857 removeDir (QDir(tmpZipDir));
1859 // Restore original filepath outside of tmp zip dir
1860 setFilePath (safeFilePath);
1864 fileChangedTime=QFileInfo (destPath).lastModified();
1869 void MapEditor::print()
1873 printer = new QPrinter;
1874 printer->setColorMode (QPrinter::Color);
1875 printer->setPrinterName (settings.value("/mainwindow/printerName",printer->printerName()).toString());
1876 printer->setOutputFormat((QPrinter::OutputFormat)settings.value("/mainwindow/printerFormat",printer->outputFormat()).toInt());
1877 printer->setOutputFileName(settings.value("/mainwindow/printerFileName",printer->outputFileName()).toString());
1880 QRectF totalBBox=model->getTotalBBox();
1882 // Try to set orientation automagically
1883 // Note: Interpretation of generated postscript is amibiguous, if
1884 // there are problems with landscape mode, see
1885 // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html
1887 if (totalBBox.width()>totalBBox.height())
1888 // recommend landscape
1889 printer->setOrientation (QPrinter::Landscape);
1891 // recommend portrait
1892 printer->setOrientation (QPrinter::Portrait);
1894 if ( printer->setup(this) )
1895 // returns false, if printing is canceled
1897 QPainter pp(printer);
1899 pp.setRenderHint(QPainter::Antialiasing,true);
1901 // Don't print the visualisation of selection
1902 xelection.unselect();
1904 QRectF mapRect=totalBBox;
1905 QGraphicsRectItem *frame=NULL;
1909 // Print frame around map
1910 mapRect.setRect (totalBBox.x()-10, totalBBox.y()-10,
1911 totalBBox.width()+20, totalBBox.height()+20);
1912 frame=mapScene->addRect (mapRect, QPen(Qt::black),QBrush(Qt::NoBrush));
1913 frame->setZValue(0);
1918 double paperAspect = (double)printer->width() / (double)printer->height();
1919 double mapAspect = (double)mapRect.width() / (double)mapRect.height();
1921 if (mapAspect>=paperAspect)
1923 // Fit horizontally to paper width
1924 //pp.setViewport(0,0, printer->width(),(int)(printer->width()/mapAspect) );
1925 viewBottom=(int)(printer->width()/mapAspect);
1928 // Fit vertically to paper height
1929 //pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height());
1930 viewBottom=printer->height();
1935 // Print footer below map
1937 font.setPointSize(10);
1939 QRectF footerBox(0,viewBottom,printer->width(),15);
1940 pp.drawText ( footerBox,Qt::AlignLeft,"VYM - " +fileName);
1941 pp.drawText ( footerBox, Qt::AlignRight, QDate::currentDate().toString(Qt::TextDate));
1945 QRectF (0,0,printer->width(),printer->height()-15),
1946 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height())
1949 // Viewport has paper dimension
1950 if (frame) delete (frame);
1952 // Restore selection
1953 xelection.reselect();
1955 // Save settings in vymrc
1956 settings.writeEntry("/mainwindow/printerName",printer->printerName());
1957 settings.writeEntry("/mainwindow/printerFormat",printer->outputFormat());
1958 settings.writeEntry("/mainwindow/printerFileName",printer->outputFileName());
1962 void MapEditor::setAntiAlias (bool b)
1964 setRenderHint(QPainter::Antialiasing,b);
1967 void MapEditor::setSmoothPixmap(bool b)
1969 setRenderHint(QPainter::SmoothPixmapTransform,b);
1972 QPixmap MapEditor::getPixmap()
1974 QRectF mapRect=model->getTotalBBox();
1975 QPixmap pix((int)mapRect.width()+2,(int)mapRect.height()+1);
1978 pp.setRenderHints(renderHints());
1980 // Don't print the visualisation of selection
1981 xelection.unselect();
1983 mapScene->render ( &pp,
1984 QRectF(0,0,mapRect.width()+1,mapRect.height()+1),
1985 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height() ));
1987 // Restore selection
1988 xelection.reselect();
1993 void MapEditor::setHideTmpMode (HideTmpMode mode)
1996 model->setHideTmp (hidemode);
1997 model->reposition();
2001 HideTmpMode MapEditor::getHideTmpMode()
2006 void MapEditor::setExportMode (bool b)
2008 // should be called before and after exports
2009 // depending on the settings
2010 if (b && settings.value("/export/useHideExport","true")=="true")
2011 setHideTmpMode (HideExport);
2013 setHideTmpMode (HideNone);
2016 void MapEditor::exportASCII(QString fname,bool askName)
2019 ex.setModel (model);
2021 ex.setFile (mapName+".txt");
2027 //ex.addFilter ("TXT (*.txt)");
2028 ex.setDir(lastImageDir);
2029 //ex.setCaption(vymName+ " -" +tr("Export as ASCII")+" "+tr("(still experimental)"));
2034 setExportMode(true);
2036 setExportMode(false);
2040 void MapEditor::exportImage(QString fname, bool askName, QString format)
2044 fname=mapName+".png";
2051 QFileDialog *fd=new QFileDialog (this);
2052 fd->setCaption (tr("Export map as image"));
2053 fd->setDirectory (lastImageDir);
2054 fd->setFileMode(QFileDialog::AnyFile);
2055 fd->setFilters (imageIO.getFilters() );
2058 fl=fd->selectedFiles();
2060 format=imageIO.getType(fd->selectedFilter());
2064 setExportMode (true);
2065 QPixmap pix (getPixmap());
2066 pix.save(fname, format);
2067 setExportMode (false);
2070 void MapEditor::exportOOPresentation(const QString &fn, const QString &cf)
2074 ex.setModel (model);
2075 if (ex.setConfigFile(cf))
2077 setExportMode (true);
2078 ex.exportPresentation();
2079 setExportMode (false);
2083 void MapEditor::exportXHTML (const QString &dir, bool askForName)
2085 ExportXHTMLDialog dia(this);
2086 dia.setFilePath (filePath );
2087 dia.setMapName (mapName );
2089 if (dir!="") dia.setDir (dir);
2095 if (dia.exec()!=QDialog::Accepted)
2099 QDir d (dia.getDir());
2100 // Check, if warnings should be used before overwriting
2101 // the output directory
2102 if (d.exists() && d.count()>0)
2105 warn.showCancelButton (true);
2106 warn.setText(QString(
2107 "The directory %1 is not empty.\n"
2108 "Do you risk to overwrite some of its contents?").arg(d.path() ));
2109 warn.setCaption("Warning: Directory not empty");
2110 warn.setShowAgainName("mainwindow/overwrite-dir-xhtml");
2112 if (warn.exec()!=QDialog::Accepted) ok=false;
2119 exportXML (dia.getDir(),false );
2120 dia.doExport(mapName );
2121 //if (dia.hasChanged()) setChanged();
2125 void MapEditor::exportXML(QString dir, bool askForName)
2129 dir=browseDirectory(this,tr("Export XML to directory"));
2130 if (dir =="" && !reallyWriteDirectory(dir) )
2134 // Hide stuff during export, if settings want this
2135 setExportMode (true);
2137 // Create subdirectories
2140 // write to directory
2141 QString saveFile=saveToDir (dir,mapName+"-",true,model->getTotalBBox().topLeft() ,NULL);
2144 file.setName ( dir + "/"+mapName+".xml");
2145 if ( !file.open( QIODevice::WriteOnly ) )
2147 // This should neverever happen
2148 QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open %1").arg(file.name()));
2152 // Write it finally, and write in UTF8, no matter what
2153 QTextStream ts( &file );
2154 ts.setEncoding (QTextStream::UnicodeUTF8);
2158 // Now write image, too
2159 exportImage (dir+"/images/"+mapName+".png",false,"PNG");
2161 setExportMode (false);
2164 void MapEditor::clear()
2166 xelection.unselect();
2170 void MapEditor::copy()
2172 LinkableMapObj *sel=xelection.single();
2175 if (redosAvail == 0)
2178 QString s=model->getSelectString(sel);
2179 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy selection to clipboard",sel );
2180 curClipboard=curStep;
2183 // Copy also to global clipboard, because we are at last step in history
2184 QString bakMapName(QString("history-%1").arg(curStep));
2185 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2186 copyDir (bakMapDir,clipboardDir );
2188 clipboardEmpty=false;
2193 void MapEditor::redo()
2195 // Can we undo at all?
2196 if (redosAvail<1) return;
2198 bool blockSaveStateOrg=blockSaveState;
2199 blockSaveState=true;
2203 if (undosAvail<stepsTotal) undosAvail++;
2205 if (curStep>stepsTotal) curStep=1;
2206 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2207 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2208 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2209 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2210 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2211 QString version=undoSet.readEntry ("/history/version");
2213 /* TODO Maybe check for version, if we save the history
2214 if (!checkVersion(version))
2215 QMessageBox::warning(0,tr("Warning"),
2216 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2219 // Find out current undo directory
2220 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2224 cout << "ME::redo() begin\n";
2225 cout << " undosAvail="<<undosAvail<<endl;
2226 cout << " redosAvail="<<redosAvail<<endl;
2227 cout << " curStep="<<curStep<<endl;
2228 cout << " ---------------------------"<<endl;
2229 cout << " comment="<<comment.toStdString()<<endl;
2230 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2231 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2232 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2233 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2234 cout << " ---------------------------"<<endl<<endl;
2237 // select object before redo
2238 if (!redoSelection.isEmpty())
2239 select (redoSelection);
2242 parseAtom (redoCommand);
2243 model->reposition();
2245 blockSaveState=blockSaveStateOrg;
2247 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2248 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2249 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2250 undoSet.writeSettings(histPath);
2252 mainWindow->updateHistory (undoSet);
2255 /* TODO remove testing
2256 cout << "ME::redo() end\n";
2257 cout << " undosAvail="<<undosAvail<<endl;
2258 cout << " redosAvail="<<redosAvail<<endl;
2259 cout << " curStep="<<curStep<<endl;
2260 cout << " ---------------------------"<<endl<<endl;
2266 bool MapEditor::isRedoAvailable()
2268 if (undoSet.readNumEntry("/history/redosAvail",0)>0)
2274 void MapEditor::undo()
2276 // Can we undo at all?
2277 if (undosAvail<1) return;
2279 mainWindow->statusMessage (tr("Autosave disabled during undo."));
2281 bool blockSaveStateOrg=blockSaveState;
2282 blockSaveState=true;
2284 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2285 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2286 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2287 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2288 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2289 QString version=undoSet.readEntry ("/history/version");
2291 /* TODO Maybe check for version, if we save the history
2292 if (!checkVersion(version))
2293 QMessageBox::warning(0,tr("Warning"),
2294 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2297 // Find out current undo directory
2298 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2300 // select object before undo
2301 if (!undoSelection.isEmpty())
2302 select (undoSelection);
2306 cout << "ME::undo() begin\n";
2307 cout << " undosAvail="<<undosAvail<<endl;
2308 cout << " redosAvail="<<redosAvail<<endl;
2309 cout << " curStep="<<curStep<<endl;
2310 cout << " ---------------------------"<<endl;
2311 cout << " comment="<<comment.toStdString()<<endl;
2312 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2313 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2314 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2315 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2316 cout << " ---------------------------"<<endl<<endl;
2318 parseAtom (undoCommand);
2319 model->reposition();
2323 if (curStep<1) curStep=stepsTotal;
2327 blockSaveState=blockSaveStateOrg;
2328 /* TODO remove testing
2329 cout << "ME::undo() end\n";
2330 cout << " undosAvail="<<undosAvail<<endl;
2331 cout << " redosAvail="<<redosAvail<<endl;
2332 cout << " curStep="<<curStep<<endl;
2333 cout << " ---------------------------"<<endl<<endl;
2336 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2337 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2338 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2339 undoSet.writeSettings(histPath);
2341 mainWindow->updateHistory (undoSet);
2344 ensureSelectionVisible();
2347 bool MapEditor::isUndoAvailable()
2349 if (undoSet.readNumEntry("/history/undosAvail",0)>0)
2355 void MapEditor::gotoHistoryStep (int i)
2357 // Restore variables
2358 int undosAvail=undoSet.readNumEntry (QString("/history/undosAvail"));
2359 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
2361 if (i<0) i=undosAvail+redosAvail;
2363 // Clicking above current step makes us undo things
2366 for (int j=0; j<undosAvail-i; j++) undo();
2369 // Clicking below current step makes us redo things
2371 for (int j=undosAvail; j<i; j++)
2373 if (debug) cout << "ME::gotoHistoryStep redo "<<j<<"/"<<undosAvail<<" i="<<i<<endl;
2377 // And ignore clicking the current row ;-)
2380 void MapEditor::addMapReplaceInt(const QString &undoSel, const QString &path)
2382 QString pathDir=path.left(path.findRev("/"));
2388 // We need to parse saved XML data
2389 parseVYMHandler handler;
2390 QXmlInputSource source( file);
2391 QXmlSimpleReader reader;
2392 reader.setContentHandler( &handler );
2393 reader.setErrorHandler( &handler );
2394 handler.setModel ( model);
2395 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2396 if (undoSel.isEmpty())
2400 handler.setLoadMode (NewMap);
2404 handler.setLoadMode (ImportReplace);
2406 blockReposition=true;
2407 bool ok = reader.parse( source );
2408 blockReposition=false;
2411 // This should never ever happen
2412 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2413 handler.errorProtocol());
2416 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2419 void MapEditor::addMapInsertInt (const QString &path, int pos)
2421 BranchObj *sel=xelection.getBranch();
2424 QString pathDir=path.left(path.findRev("/"));
2430 // We need to parse saved XML data
2431 parseVYMHandler handler;
2432 QXmlInputSource source( file);
2433 QXmlSimpleReader reader;
2434 reader.setContentHandler( &handler );
2435 reader.setErrorHandler( &handler );
2436 handler.setModel (model);
2437 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2438 handler.setLoadMode (ImportAdd);
2439 blockReposition=true;
2440 bool ok = reader.parse( source );
2441 blockReposition=false;
2444 // This should never ever happen
2445 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2446 handler.errorProtocol());
2448 if (sel->getDepth()>0)
2449 sel->getLastBranch()->linkTo (sel,pos);
2451 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2455 void MapEditor::pasteNoSave(const int &n)
2457 bool old=blockSaveState;
2458 blockSaveState=true;
2459 bool zippedOrg=zipped;
2460 if (redosAvail > 0 || n!=0)
2462 // Use the "historical" buffer
2463 QString bakMapName(QString("history-%1").arg(n));
2464 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2465 load (bakMapDir+"/"+clipboardFile,ImportAdd, VymMap);
2467 // Use the global buffer
2468 load (clipboardDir+"/"+clipboardFile,ImportAdd, VymMap);
2473 void MapEditor::paste()
2475 BranchObj *sel=xelection.getBranch();
2478 saveStateChangingPart(
2481 QString ("paste (%1)").arg(curClipboard),
2482 QString("Paste to %1").arg( getName(sel))
2485 model->reposition();
2489 void MapEditor::cut()
2491 LinkableMapObj *sel=xelection.single();
2492 if ( sel && (xelection.type() == Selection::Branch ||
2493 xelection.type()==Selection::MapCenter ||
2494 xelection.type()==Selection::FloatImage))
2496 /* No savestate! savestate is called in cutNoSave
2497 saveStateChangingPart(
2501 QString("Cut %1").arg(getName(sel ))
2506 model->reposition();
2510 void MapEditor::move(const double &x, const double &y)
2512 LinkableMapObj *sel=xelection.single();
2515 QPointF ap(sel->getAbsPos());
2519 QString ps=qpointfToString(ap);
2520 QString s=xelection.getSelectString();
2523 s, "move "+qpointfToString(to),
2524 QString("Move %1 to %2").arg(getName(sel)).arg(ps));
2526 model->reposition();
2532 void MapEditor::moveRel (const double &x, const double &y)
2534 LinkableMapObj *sel=xelection.single();
2537 QPointF rp(sel->getRelPos());
2541 QString ps=qpointfToString (sel->getRelPos());
2542 QString s=model->getSelectString(sel);
2545 s, "moveRel "+qpointfToString(to),
2546 QString("Move %1 to relative position %2").arg(getName(sel)).arg(ps));
2547 ((OrnamentedObj*)sel)->move2RelPos (x,y);
2548 model->reposition();
2555 void MapEditor::moveBranchUp()
2557 BranchObj* bo=xelection.getBranch();
2561 if (!bo->canMoveBranchUp()) return;
2562 par=(BranchObj*)(bo->getParObj());
2563 BranchObj *obo=par->moveBranchUp (bo); // bo will be the one below selection
2564 saveState (model->getSelectString(bo),"moveBranchDown ()",model->getSelectString(obo),"moveBranchUp ()",QString("Move up %1").arg(getName(bo)));
2565 model->reposition();
2568 ensureSelectionVisible();
2572 void MapEditor::moveBranchDown()
2574 BranchObj* bo=xelection.getBranch();
2578 if (!bo->canMoveBranchDown()) return;
2579 par=(BranchObj*)(bo->getParObj());
2580 BranchObj *obo=par->moveBranchDown(bo); // bo will be the one above selection
2581 saveState(model->getSelectString(bo),"moveBranchUp ()",model->getSelectString(obo),"moveBranchDown ()",QString("Move down %1").arg(getName(bo)));
2582 model->reposition();
2585 ensureSelectionVisible();
2589 void MapEditor::sortChildren()
2591 BranchObj* bo=xelection.getBranch();
2594 if(bo->countBranches()>1)
2596 saveStateChangingPart(bo,bo, "sortChildren ()",QString("Sort children of %1").arg(getName(bo)));
2598 model->reposition();
2599 ensureSelectionVisible();
2604 void MapEditor::linkTo(const QString &dstString)
2606 FloatImageObj *fio=xelection.getFloatImage();
2609 BranchObj *dst=(BranchObj*)(model->findObjBySelect(dstString));
2610 if (dst && (typeid(*dst)==typeid (BranchObj) ||
2611 typeid(*dst)==typeid (MapCenterObj)))
2613 LinkableMapObj *dstPar=dst->getParObj();
2614 QString parString=model->getSelectString(dstPar);
2615 QString fioPreSelectString=model->getSelectString(fio);
2616 QString fioPreParentSelectString=model->getSelectString (fio->getParObj());
2617 ((BranchObj*)(dst))->addFloatImage (fio);
2618 xelection.unselect();
2619 ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio);
2620 fio=((BranchObj*)(dst))->getLastFloatImage();
2623 xelection.select(fio);
2625 model->getSelectString(fio),
2626 QString("linkTo (\"%1\")").arg(fioPreParentSelectString),
2628 QString ("linkTo (\"%1\")").arg(dstString),
2629 QString ("Link floatimage to %1").arg(getName(dst)));
2634 QString MapEditor::getHeading(bool &ok, QPoint &p)
2636 BranchObj *bo=xelection.getBranch();
2640 p=mapFromScene(bo->getAbsPos());
2641 return bo->getHeading();
2647 void MapEditor::setHeading(const QString &s)
2649 BranchObj *sel=xelection.getBranch();
2654 "setHeading (\""+sel->getHeading()+"\")",
2656 "setHeading (\""+s+"\")",
2657 QString("Set heading of %1 to \"%2\"").arg(getName(sel)).arg(s) );
2658 sel->setHeading(s );
2659 model->reposition();
2661 ensureSelectionVisible();
2665 void MapEditor::setHeadingInt(const QString &s)
2667 BranchObj *bo=xelection.getBranch();
2671 model->reposition();
2673 ensureSelectionVisible();
2677 void MapEditor::setVymLinkInt (const QString &s)
2679 // Internal function, no saveState needed
2680 BranchObj *bo=xelection.getBranch();
2684 model->reposition();
2687 ensureSelectionVisible();
2691 BranchObj* MapEditor::addMapCenter ()
2693 MapCenterObj *mco= model->addMapCenter(contextMenuPos);
2694 xelection.select (mco);
2696 ensureSelectionVisible();
2701 QString ("addMapCenter (%1,%2)").arg (contextMenuPos.x()).arg(contextMenuPos.y()),
2702 QString ("Adding MapCenter to (%1,%2").arg (contextMenuPos.x()).arg(contextMenuPos.y())
2707 BranchObj* MapEditor::addNewBranchInt(int num)
2709 // Depending on pos:
2710 // -3 insert in childs of parent above selection
2711 // -2 add branch to selection
2712 // -1 insert in childs of parent below selection
2713 // 0..n insert in childs of parent at pos
2714 BranchObj *newbo=NULL;
2715 BranchObj *bo=xelection.getBranch();
2720 // save scroll state. If scrolled, automatically select
2721 // new branch in order to tmp unscroll parent...
2722 newbo=bo->addBranch();
2727 bo=(BranchObj*)bo->getParObj();
2728 if (bo) newbo=bo->insertBranch(num);
2732 bo=(BranchObj*)bo->getParObj();
2733 if (bo) newbo=bo->insertBranch(num);
2735 if (!newbo) return NULL;
2740 BranchObj* MapEditor::addNewBranch(int pos)
2742 // Different meaning than num in addNewBranchInt!
2746 BranchObj *bo = xelection.getBranch();
2747 BranchObj *newbo=NULL;
2751 setCursor (Qt::ArrowCursor);
2753 newbo=addNewBranchInt (pos-2);
2761 QString ("addBranch (%1)").arg(pos),
2762 QString ("Add new branch to %1").arg(getName(bo)));
2764 model->reposition();
2766 latestSelection=model->getSelectString(newbo);
2767 // In Network mode, the client needs to know where the new branch is,
2768 // so we have to pass on this information via saveState.
2769 // TODO: Get rid of this positioning workaround
2770 QString ps=qpointfToString (newbo->getAbsPos());
2771 sendData ("selectLatestAdded ()");
2772 sendData (QString("move %1").arg(ps));
2780 BranchObj* MapEditor::addNewBranchBefore()
2782 BranchObj *newbo=NULL;
2783 BranchObj *bo = xelection.getBranch();
2784 if (bo && xelection.type()==Selection::Branch)
2785 // We accept no MapCenterObj here, so we _have_ a parent
2787 QPointF p=bo->getRelPos();
2790 BranchObj *parbo=(BranchObj*)(bo->getParObj());
2792 // add below selection
2793 newbo=parbo->insertBranch(bo->getNum()+1);
2796 newbo->move2RelPos (p);
2798 // Move selection to new branch
2799 bo->linkTo (newbo,-1);
2801 saveState (newbo, "deleteKeepChilds ()", newbo, "addBranchBefore ()",
2802 QString ("Add branch before %1").arg(getName(bo)));
2804 model->reposition();
2808 latestSelection=xelection.getSelectString();
2812 void MapEditor::deleteSelection()
2814 BranchObj *bo = xelection.getBranch();
2815 if (bo && xelection.type()==Selection::MapCenter)
2817 // BranchObj* par=(BranchObj*)(bo->getParObj());
2818 xelection.unselect();
2819 /* FIXME Note: does saveStateRemovingPart work for MCO? (No parent!)
2820 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2822 bo=model->removeMapCenter ((MapCenterObj*)bo);
2825 xelection.select (bo);
2826 ensureSelectionVisible();
2829 model->reposition();
2832 if (bo && xelection.type()==Selection::Branch)
2834 BranchObj* par=(BranchObj*)bo->getParObj();
2835 xelection.unselect();
2836 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2837 par->removeBranch(bo);
2838 xelection.select (par);
2839 ensureSelectionVisible();
2840 model->reposition();
2841 // xelection.update();
2845 FloatImageObj *fio=xelection.getFloatImage();
2848 BranchObj* par=(BranchObj*)fio->getParObj();
2849 saveStateChangingPart(
2853 QString("Delete %1").arg(getName(fio))
2855 xelection.unselect();
2856 par->removeFloatImage(fio);
2857 xelection.select (par);
2858 model->reposition();
2860 ensureSelectionVisible();
2865 LinkableMapObj* MapEditor::getSelection()
2867 return xelection.single();
2870 BranchObj* MapEditor::getSelectedBranch()
2872 return xelection.getBranch();
2875 FloatImageObj* MapEditor::getSelectedFloatImage()
2877 return xelection.getFloatImage();
2880 void MapEditor::unselect()
2882 xelection.unselect();
2885 void MapEditor::reselect()
2887 xelection.reselect();
2890 bool MapEditor::select (const QString &s)
2892 if (xelection.select(s))
2895 ensureSelectionVisible();
2902 bool MapEditor::select (LinkableMapObj *lmo)
2904 if (xelection.select(lmo))
2907 ensureSelectionVisible();
2914 QString MapEditor::getSelectString()
2916 return xelection.getSelectString();
2919 void MapEditor::selectInt (LinkableMapObj *lmo)
2921 if (lmo && xelection.single()!= lmo && isSelectBlocked()==false )
2923 xelection.select(lmo);
2929 void MapEditor::selectNextBranchInt()
2931 // Increase number of branch
2932 LinkableMapObj *sel=xelection.single();
2935 QString s=xelection.getSelectString();
2941 part=s.section(",",-1);
2943 num=part.right(part.length() - 3);
2945 s=s.left (s.length() -num.length());
2948 num=QString ("%1").arg(num.toUInt()+1);
2952 // Try to select this one
2953 if (select (s)) return;
2955 // We have no direct successor,
2956 // try to increase the parental number in order to
2957 // find a successor with same depth
2959 int d=xelection.single()->getDepth();
2964 while (!found && d>0)
2966 s=s.section (",",0,d-1);
2967 // replace substring of current depth in s with "1"
2968 part=s.section(",",-1);
2970 num=part.right(part.length() - 3);
2974 // increase number of parent
2975 num=QString ("%1").arg(num.toUInt()+1);
2976 s=s.section (",",0,d-2) + ","+ typ+num;
2979 // Special case, look at orientation
2980 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
2981 num=QString ("%1").arg(num.toUInt()+1);
2983 num=QString ("%1").arg(num.toUInt()-1);
2988 // pad to oldDepth, select the first branch for each depth
2989 for (i=d;i<oldDepth;i++)
2994 if ( xelection.getBranch()->countBranches()>0)
3002 // try to select the freshly built string
3010 void MapEditor::selectPrevBranchInt()
3012 // Decrease number of branch
3013 BranchObj *bo=xelection.getBranch();
3016 QString s=xelection.getSelectString();
3022 part=s.section(",",-1);
3024 num=part.right(part.length() - 3);
3026 s=s.left (s.length() -num.length());
3028 int n=num.toInt()-1;
3031 num=QString ("%1").arg(n);
3034 // Try to select this one
3035 if (n>=0 && select (s)) return;
3037 // We have no direct precessor,
3038 // try to decrease the parental number in order to
3039 // find a precessor with same depth
3041 int d=xelection.single()->getDepth();
3046 while (!found && d>0)
3048 s=s.section (",",0,d-1);
3049 // replace substring of current depth in s with "1"
3050 part=s.section(",",-1);
3052 num=part.right(part.length() - 3);
3056 // decrease number of parent
3057 num=QString ("%1").arg(num.toInt()-1);
3058 s=s.section (",",0,d-2) + ","+ typ+num;
3061 // Special case, look at orientation
3062 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
3063 num=QString ("%1").arg(num.toInt()-1);
3065 num=QString ("%1").arg(num.toInt()+1);
3070 // pad to oldDepth, select the last branch for each depth
3071 for (i=d;i<oldDepth;i++)
3075 if ( xelection.getBranch()->countBranches()>0)
3076 s+=",bo:"+ QString ("%1").arg( xelection.getBranch()->countBranches()-1 );
3083 // try to select the freshly built string
3091 void MapEditor::selectUpperBranch()
3093 if (isSelectBlocked() ) return;
3095 BranchObj *bo=xelection.getBranch();
3096 if (bo && xelection.type()==Selection::Branch)
3098 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3099 selectPrevBranchInt();
3101 if (bo->getDepth()==1)
3102 selectNextBranchInt();
3104 selectPrevBranchInt();
3108 void MapEditor::selectLowerBranch()
3110 if (isSelectBlocked() ) return;
3112 BranchObj *bo=xelection.getBranch();
3113 if (bo && xelection.type()==Selection::Branch)
3115 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3116 selectNextBranchInt();
3118 if (bo->getDepth()==1)
3119 selectPrevBranchInt();
3121 selectNextBranchInt();
3126 void MapEditor::selectLeftBranch()
3128 if (isSelectBlocked() ) return;
3132 LinkableMapObj *sel=xelection.single();
3135 if (xelection.type()== Selection::MapCenter)
3137 par=xelection.getBranch();
3138 bo=par->getLastSelectedBranch();
3141 // Workaround for reselecting on left and right side
3142 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3143 bo=par->getLastBranch();
3146 bo=par->getLastBranch();
3147 xelection.select(bo);
3149 ensureSelectionVisible();
3155 par=(BranchObj*)(sel->getParObj());
3156 if (sel->getOrientation()==LinkableMapObj::RightOfCenter)
3158 if (xelection.type() == Selection::Branch ||
3159 xelection.type() == Selection::FloatImage)
3161 xelection.select(par);
3163 ensureSelectionVisible();
3168 if (xelection.type() == Selection::Branch )
3170 bo=xelection.getBranch()->getLastSelectedBranch();
3173 xelection.select(bo);
3175 ensureSelectionVisible();
3184 void MapEditor::selectRightBranch()
3186 if (isSelectBlocked() ) return;
3190 LinkableMapObj *sel=xelection.single();
3193 if (xelection.type()==Selection::MapCenter)
3195 par=xelection.getBranch();
3196 bo=par->getLastSelectedBranch();
3199 // Workaround for reselecting on left and right side
3200 if (bo->getOrientation()==LinkableMapObj::LeftOfCenter)
3201 bo=par->getFirstBranch();
3204 xelection.select(bo);
3206 ensureSelectionVisible();
3212 par=(BranchObj*)(xelection.single()->getParObj());
3213 if (xelection.single()->getOrientation()==LinkableMapObj::LeftOfCenter)
3215 if (xelection.type() == Selection::Branch ||
3216 xelection.type() == Selection::FloatImage)
3218 xelection.select(par);
3220 ensureSelectionVisible();
3225 if (xelection.type() == Selection::Branch)
3227 bo=xelection.getBranch()->getLastSelectedBranch();
3230 xelection.select(bo);
3232 ensureSelectionVisible();
3241 void MapEditor::selectFirstBranch()
3243 BranchObj *bo1=xelection.getBranch();
3248 par=(BranchObj*)(bo1->getParObj());
3250 bo2=par->getFirstBranch();
3252 xelection.select(bo2);
3254 ensureSelectionVisible();
3260 void MapEditor::selectLastBranch()
3262 BranchObj *bo1=xelection.getBranch();
3267 par=(BranchObj*)(bo1->getParObj());
3269 bo2=par->getLastBranch();
3272 xelection.select(bo2);
3274 ensureSelectionVisible();
3280 void MapEditor::selectMapBackgroundImage ()
3282 Q3FileDialog *fd=new Q3FileDialog( this);
3283 fd->setMode (Q3FileDialog::ExistingFile);
3284 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
3285 ImagePreview *p =new ImagePreview (fd);
3286 fd->setContentsPreviewEnabled( TRUE );
3287 fd->setContentsPreview( p, p );
3288 fd->setPreviewMode( Q3FileDialog::Contents );
3289 fd->setCaption(vymName+" - " +tr("Load background image"));
3290 fd->setDir (lastImageDir);
3293 if ( fd->exec() == QDialog::Accepted )
3295 // TODO selectMapBackgroundImg in QT4 use: lastImageDir=fd->directory();
3296 lastImageDir=QDir (fd->dirPath());
3297 setMapBackgroundImage (fd->selectedFile());
3301 void MapEditor::setMapBackgroundImage (const QString &fn) //FIXME missing savestate
3303 QColor oldcol=mapScene->backgroundBrush().color();
3307 QString ("setMapBackgroundImage (%1)").arg(oldcol.name()),
3309 QString ("setMapBackgroundImage (%1)").arg(col.name()),
3310 QString("Set background color of map to %1").arg(col.name()));
3313 brush.setTextureImage (QPixmap (fn));
3314 mapScene->setBackgroundBrush(brush);
3317 void MapEditor::selectMapBackgroundColor()
3319 QColor col = QColorDialog::getColor( mapScene->backgroundBrush().color(), this );
3320 if ( !col.isValid() ) return;
3321 setMapBackgroundColor( col );
3325 void MapEditor::setMapBackgroundColor(QColor col)
3327 QColor oldcol=mapScene->backgroundBrush().color();
3329 QString ("setMapBackgroundColor (\"%1\")").arg(oldcol.name()),
3330 QString ("setMapBackgroundColor (\"%1\")").arg(col.name()),
3331 QString("Set background color of map to %1").arg(col.name()));
3332 mapScene->setBackgroundBrush(col);
3335 QColor MapEditor::getMapBackgroundColor()
3337 return mapScene->backgroundBrush().color();
3340 QColor MapEditor::getCurrentHeadingColor()
3342 BranchObj *bo=xelection.getBranch();
3343 if (bo) return bo->getColor();
3345 QMessageBox::warning(0,tr("Warning"),tr("Can't get color of heading,\nthere's no branch selected"));
3349 void MapEditor::colorBranch (QColor c)
3351 BranchObj *bo=xelection.getBranch();
3356 QString ("colorBranch (\"%1\")").arg(bo->getColor().name()),
3358 QString ("colorBranch (\"%1\")").arg(c.name()),
3359 QString("Set color of %1 to %2").arg(getName(bo)).arg(c.name())
3361 bo->setColor(c); // color branch
3365 void MapEditor::colorSubtree (QColor c)
3367 BranchObj *bo=xelection.getBranch();
3370 saveStateChangingPart(
3373 QString ("colorSubtree (\"%1\")").arg(c.name()),
3374 QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(c.name())
3376 bo->setColorSubtree (c); // color links, color childs
3381 void MapEditor::toggleStandardFlag(QString f)
3383 BranchObj *bo=xelection.getBranch();
3387 if (bo->isSetStandardFlag(f))
3399 QString("%1 (\"%2\")").arg(u).arg(f),
3401 QString("%1 (\"%2\")").arg(r).arg(f),
3402 QString("Toggling standard flag \"%1\" of %2").arg(f).arg(getName(bo)));
3403 bo->toggleStandardFlag (f,mainWindow->useFlagGroups());
3409 BranchObj* MapEditor::findText (QString s, bool cs)
3411 QTextDocument::FindFlags flags=0;
3412 if (cs) flags=QTextDocument::FindCaseSensitively;
3415 { // Nothing found or new find process
3417 // nothing found, start again
3419 itFind=model->first();
3421 bool searching=true;
3422 bool foundNote=false;
3423 while (searching && !EOFind)
3427 // Searching in Note
3428 if (itFind->getNote().contains(s,cs))
3430 if (xelection.single()!=itFind)
3432 xelection.select(itFind);
3433 ensureSelectionVisible();
3435 if (textEditor->findText(s,flags))
3441 // Searching in Heading
3442 if (searching && itFind->getHeading().contains (s,cs) )
3444 xelection.select(itFind);
3445 ensureSelectionVisible();
3451 itFind=model->next(itFind);
3452 if (!itFind) EOFind=true;
3454 //cout <<"still searching... "<<qPrintable( itFind->getHeading())<<endl;
3457 return xelection.getBranch();
3462 void MapEditor::findReset()
3463 { // Necessary if text to find changes during a find process
3467 void MapEditor::setURL(const QString &url)
3469 BranchObj *bo=xelection.getBranch();
3472 QString oldurl=bo->getURL();
3476 QString ("setURL (\"%1\")").arg(oldurl),
3478 QString ("setURL (\"%1\")").arg(url),
3479 QString ("set URL of %1 to %2").arg(getName(bo)).arg(url)
3482 model->reposition();
3484 ensureSelectionVisible();
3488 void MapEditor::editURL()
3490 BranchObj *bo=xelection.getBranch();
3494 QString text = QInputDialog::getText(
3495 "VYM", tr("Enter URL:"), QLineEdit::Normal,
3496 bo->getURL(), &ok, this );
3498 // user entered something and pressed OK
3503 void MapEditor::editLocalURL()
3505 BranchObj *bo=xelection.getBranch();
3508 QStringList filters;
3509 filters <<"All files (*)";
3510 filters << tr("Text","Filedialog") + " (*.txt)";
3511 filters << tr("Spreadsheet","Filedialog") + " (*.odp,*.sxc)";
3512 filters << tr("Textdocument","Filedialog") +" (*.odw,*.sxw)";
3513 filters << tr("Images","Filedialog") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)";
3514 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Set URL to a local file"));
3515 fd->setFilters (filters);
3516 fd->setCaption(vymName+" - " +tr("Set URL to a local file"));
3517 fd->setDirectory (lastFileDir);
3518 if (! bo->getVymLink().isEmpty() )
3519 fd->selectFile( bo->getURL() );
3522 if ( fd->exec() == QDialog::Accepted )
3524 lastFileDir=QDir (fd->directory().path());
3525 setURL (fd->selectedFile() );
3530 QString MapEditor::getURL()
3532 BranchObj *bo=xelection.getBranch();
3534 return bo->getURL();
3539 QStringList MapEditor::getURLs()
3542 BranchObj *bo=xelection.getBranch();
3548 if (!bo->getURL().isEmpty()) urls.append( bo->getURL());
3556 void MapEditor::editHeading2URL()
3558 BranchObj *bo=xelection.getBranch();
3560 setURL (bo->getHeading());
3563 void MapEditor::editBugzilla2URL()
3565 BranchObj *bo=xelection.getBranch();
3568 QString url= "https://bugzilla.novell.com/show_bug.cgi?id="+bo->getHeading();
3573 void MapEditor::editFATE2URL()
3575 BranchObj *bo=xelection.getBranch();
3578 QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading();
3581 "setURL (\""+bo->getURL()+"\")",
3583 "setURL (\""+url+"\")",
3584 QString("Use heading of %1 as link to FATE").arg(getName(bo))
3591 void MapEditor::editVymLink()
3593 BranchObj *bo=xelection.getBranch();
3596 QStringList filters;
3597 filters <<"VYM map (*.vym)";
3598 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Link to another map"));
3599 fd->setFilters (filters);
3600 fd->setCaption(vymName+" - " +tr("Link to another map"));
3601 fd->setDirectory (lastFileDir);
3602 if (! bo->getVymLink().isEmpty() )
3603 fd->selectFile( bo->getVymLink() );
3607 if ( fd->exec() == QDialog::Accepted )
3609 lastFileDir=QDir (fd->directory().path());
3612 "setVymLink (\""+bo->getVymLink()+"\")",
3614 "setVymLink (\""+fd->selectedFile()+"\")",
3615 QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())
3617 setVymLinkInt (fd->selectedFile() );
3622 void MapEditor::deleteVymLink()
3624 BranchObj *bo=xelection.getBranch();
3629 "setVymLink (\""+bo->getVymLink()+"\")",
3631 "setVymLink (\"\")",
3632 QString("Unset vymlink of %1").arg(getName(bo))
3634 bo->setVymLink ("" );
3636 model->reposition();
3641 void MapEditor::setHideExport(bool b)
3643 BranchObj *bo=xelection.getBranch();
3646 bo->setHideInExport (b);
3647 QString u= b ? "false" : "true";
3648 QString r=!b ? "false" : "true";
3652 QString ("setHideExport (%1)").arg(u),
3654 QString ("setHideExport (%1)").arg(r),
3655 QString ("Set HideExport flag of %1 to %2").arg(getName(bo)).arg (r)
3658 model->reposition();
3664 void MapEditor::toggleHideExport()
3666 BranchObj *bo=xelection.getBranch();
3668 setHideExport ( !bo->hideInExport() );
3671 QString MapEditor::getVymLink()
3673 BranchObj *bo=xelection.getBranch();
3675 return bo->getVymLink();
3681 QStringList MapEditor::getVymLinks()
3684 BranchObj *bo=xelection.getBranch();
3690 if (!bo->getVymLink().isEmpty()) links.append( bo->getVymLink());
3698 void MapEditor::deleteKeepChilds()
3700 BranchObj *bo=xelection.getBranch();
3704 par=(BranchObj*)(bo->getParObj());
3706 // Don't use this on mapcenter
3709 // Check if we have childs at all to keep
3710 if (bo->countBranches()==0)
3716 QPointF p=bo->getRelPos();
3717 saveStateChangingPart(
3720 "deleteKeepChilds ()",
3721 QString("Remove %1 and keep its childs").arg(getName(bo))
3724 QString sel=model->getSelectString(bo);
3726 par->removeBranchHere(bo);
3727 model->reposition();
3729 xelection.getBranch()->move2RelPos (p);
3730 model->reposition();
3734 void MapEditor::deleteChilds()
3736 BranchObj *bo=xelection.getBranch();
3739 saveStateChangingPart(
3743 QString( "Remove childs of branch %1").arg(getName(bo))
3746 model->reposition();
3750 void MapEditor::editMapInfo()
3752 ExtraInfoDialog dia;
3753 dia.setMapName (getFileName() );
3754 dia.setAuthor (model->getAuthor() );
3755 dia.setComment(model->getComment() );
3759 stats+=tr("%1 items on map\n","Info about map").arg (mapScene->items().size(),6);
3769 if (!bo->getNote().isEmpty() ) n++;
3770 f+= bo->countFloatImages();
3772 xl+=bo->countXLinks();
3775 stats+=QString ("%1 branches\n").arg (b-1,6);
3776 stats+=QString ("%1 xLinks \n").arg (xl,6);
3777 stats+=QString ("%1 notes\n").arg (n,6);
3778 stats+=QString ("%1 images\n").arg (f,6);
3779 dia.setStats (stats);
3781 // Finally show dialog
3782 if (dia.exec() == QDialog::Accepted)
3784 setMapAuthor (dia.getAuthor() );
3785 setMapComment (dia.getComment() );
3789 void MapEditor::ensureSelectionVisible()
3791 LinkableMapObj *lmo=xelection.single();
3792 if (lmo) ensureVisible (lmo->getBBox() );
3796 void MapEditor::updateSelection()
3798 // Tell selection to update geometries
3802 void MapEditor::updateActions()
3804 // Tell mainwindow to update states of actions
3805 mainWindow->updateActions();
3806 // TODO maybe don't update if blockReposition is set
3809 void MapEditor::updateNoteFlag()
3812 BranchObj *bo=xelection.getBranch();
3815 bo->updateNoteFlag();
3816 mainWindow->updateActions();
3820 void MapEditor::setMapAuthor (const QString &s)
3823 QString ("setMapAuthor (\"%1\")").arg(model->getAuthor()),
3824 QString ("setMapAuthor (\"%1\")").arg(s),
3825 QString ("Set author of map to \"%1\"").arg(s)
3827 model->setAuthor (s);
3830 void MapEditor::setMapComment (const QString &s)
3833 QString ("setMapComment (\"%1\")").arg(model->getComment()),
3834 QString ("setMapComment (\"%1\")").arg(s),
3835 QString ("Set comment of map")
3837 model->setComment (s);
3840 void MapEditor::setMapLinkStyle (const QString & s)
3843 if (linkstyle==LinkableMapObj::Line)
3845 else if (linkstyle==LinkableMapObj::Parabel)
3846 snow="StyleParabel";
3847 else if (linkstyle==LinkableMapObj::PolyLine)
3848 snow="StylePolyLine";
3849 else if (linkstyle==LinkableMapObj::PolyParabel)
3850 snow="StyleParabel";
3853 QString("setMapLinkStyle (\"%1\")").arg(s),
3854 QString("setMapLinkStyle (\"%1\")").arg(snow),
3855 QString("Set map link style (\"%1\")").arg(s)
3859 linkstyle=LinkableMapObj::Line;
3860 else if (s=="StyleParabel")
3861 linkstyle=LinkableMapObj::Parabel;
3862 else if (s=="StylePolyLine")
3863 linkstyle=LinkableMapObj::PolyLine;
3865 linkstyle=LinkableMapObj::PolyParabel;
3872 bo->setLinkStyle(bo->getDefLinkStyle());
3875 model->reposition();
3878 LinkableMapObj::Style MapEditor::getMapLinkStyle ()
3883 void MapEditor::setMapDefLinkColor(QColor c)
3896 void MapEditor::setMapLinkColorHintInt()
3898 // called from setMapLinkColorHint(lch) or at end of parse
3908 void MapEditor::setMapLinkColorHint(LinkableMapObj::ColorHint lch)
3911 setMapLinkColorHintInt();
3914 void MapEditor::toggleMapLinkColorHint()
3916 if (linkcolorhint==LinkableMapObj::HeadingColor)
3917 linkcolorhint=LinkableMapObj::DefaultColor;
3919 linkcolorhint=LinkableMapObj::HeadingColor;
3929 LinkableMapObj::ColorHint MapEditor::getMapLinkColorHint()
3931 return linkcolorhint;
3934 QColor MapEditor::getMapDefLinkColor()
3936 return defLinkColor;
3939 void MapEditor::setMapDefXLinkColor(QColor col)
3944 QColor MapEditor::getMapDefXLinkColor()
3946 return defXLinkColor;
3949 void MapEditor::setMapDefXLinkWidth (int w)
3954 int MapEditor::getMapDefXLinkWidth()
3956 return defXLinkWidth;
3959 void MapEditor::selectMapLinkColor()
3961 QColor col = QColorDialog::getColor( defLinkColor, this );
3962 if ( !col.isValid() ) return;
3964 QString("setMapDefLinkColor (\"%1\")").arg(getMapDefLinkColor().name()),
3965 QString("setMapDefLinkColor (\"%1\")").arg(col.name()),
3966 QString("Set map link color to %1").arg(col.name())
3968 setMapDefLinkColor( col );
3971 void MapEditor::selectMapSelectionColor()
3973 QColor col = QColorDialog::getColor( defLinkColor, this );
3974 setSelectionColor (col);
3977 void MapEditor::setSelectionColorInt (QColor col)
3979 if ( !col.isValid() ) return;
3980 xelection.setColor (col);
3983 void MapEditor::setSelectionColor(QColor col)
3985 if ( !col.isValid() ) return;
3987 QString("setSelectionColor (%1)").arg(xelection.getColor().name()),
3988 QString("setSelectionColor (%1)").arg(col.name()),
3989 QString("Set color of selection box to %1").arg(col.name())
3991 setSelectionColorInt (col);
3994 QColor MapEditor::getSelectionColor()
3996 return xelection.getColor();
3999 bool MapEditor::scrollBranch(BranchObj *bo)
4003 if (bo->isScrolled()) return false;
4004 if (bo->countBranches()==0) return false;
4005 if (bo->getDepth()==0) return false;
4011 QString ("%1 ()").arg(u),
4013 QString ("%1 ()").arg(r),
4014 QString ("%1 %2").arg(r).arg(getName(bo))
4024 bool MapEditor::unscrollBranch(BranchObj *bo)
4028 if (!bo->isScrolled()) return false;
4029 if (bo->countBranches()==0) return false;
4030 if (bo->getDepth()==0) return false;
4036 QString ("%1 ()").arg(u),
4038 QString ("%1 ()").arg(r),
4039 QString ("%1 %2").arg(r).arg(getName(bo))
4049 void MapEditor::toggleScroll()
4051 BranchObj *bo=xelection.getBranch();
4052 if (xelection.type()==Selection::Branch )
4054 if (bo->isScrolled())
4055 unscrollBranch (bo);
4061 void MapEditor::unscrollChilds()
4063 BranchObj *bo=xelection.getBranch();
4069 if (bo->isScrolled()) unscrollBranch (bo);
4075 FloatImageObj* MapEditor::loadFloatImageInt (QString fn)
4077 BranchObj *bo=xelection.getBranch();
4081 bo->addFloatImage();
4082 fio=bo->getLastFloatImage();
4084 model->reposition();
4091 void MapEditor::loadFloatImage ()
4093 BranchObj *bo=xelection.getBranch();
4097 Q3FileDialog *fd=new Q3FileDialog( this);
4098 fd->setMode (Q3FileDialog::ExistingFiles);
4099 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
4100 ImagePreview *p =new ImagePreview (fd);
4101 fd->setContentsPreviewEnabled( TRUE );
4102 fd->setContentsPreview( p, p );
4103 fd->setPreviewMode( Q3FileDialog::Contents );
4104 fd->setCaption(vymName+" - " +tr("Load image"));
4105 fd->setDir (lastImageDir);
4108 if ( fd->exec() == QDialog::Accepted )
4110 // TODO loadFIO in QT4 use: lastImageDir=fd->directory();
4111 lastImageDir=QDir (fd->dirPath());
4114 for (int j=0; j<fd->selectedFiles().count(); j++)
4116 s=fd->selectedFiles().at(j);
4117 fio=loadFloatImageInt (s);
4120 (LinkableMapObj*)fio,
4123 QString ("loadImage (%1)").arg(s ),
4124 QString("Add image %1 to %2").arg(s).arg(getName(bo))
4127 // TODO loadFIO error handling
4128 qWarning ("Failed to load "+s);
4136 void MapEditor::saveFloatImageInt (FloatImageObj *fio, const QString &type, const QString &fn)
4138 fio->save (fn,type);
4141 void MapEditor::saveFloatImage ()
4143 FloatImageObj *fio=xelection.getFloatImage();
4146 QFileDialog *fd=new QFileDialog( this);
4147 fd->setFilters (imageIO.getFilters());
4148 fd->setCaption(vymName+" - " +tr("Save image"));
4149 fd->setFileMode( QFileDialog::AnyFile );
4150 fd->setDirectory (lastImageDir);
4151 // fd->setSelection (fio->getOriginalFilename());
4155 if ( fd->exec() == QDialog::Accepted && fd->selectedFiles().count()==1)
4157 fn=fd->selectedFiles().at(0);
4158 if (QFile (fn).exists() )
4160 QMessageBox mb( vymName,
4161 tr("The file %1 exists already.\n"
4162 "Do you want to overwrite it?").arg(fn),
4163 QMessageBox::Warning,
4164 QMessageBox::Yes | QMessageBox::Default,
4165 QMessageBox::Cancel | QMessageBox::Escape,
4166 QMessageBox::NoButton );
4168 mb.setButtonText( QMessageBox::Yes, tr("Overwrite") );
4169 mb.setButtonText( QMessageBox::No, tr("Cancel"));
4172 case QMessageBox::Yes:
4175 case QMessageBox::Cancel:
4182 saveFloatImageInt (fio,fd->selectedFilter(),fn );
4188 void MapEditor::setFrameType(const FrameObj::FrameType &t)
4190 BranchObj *bo=xelection.getBranch();
4193 QString s=bo->getFrameTypeName();
4194 bo->setFrameType (t);
4195 saveState (bo, QString("setFrameType (\"%1\")").arg(s),
4196 bo, QString ("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),QString ("set type of frame to %1").arg(s));
4197 model->reposition();
4202 void MapEditor::setFrameType(const QString &s)
4204 BranchObj *bo=xelection.getBranch();
4207 saveState (bo, QString("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),
4208 bo, QString ("setFrameType (\"%1\")").arg(s),QString ("set type of frame to %1").arg(s));
4209 bo->setFrameType (s);
4210 model->reposition();
4215 void MapEditor::setFramePenColor(const QColor &c)
4217 BranchObj *bo=xelection.getBranch();
4220 saveState (bo, QString("setFramePenColor (\"%1\")").arg(bo->getFramePenColor().name() ),
4221 bo, QString ("setFramePenColor (\"%1\")").arg(c.name() ),QString ("set pen color of frame to %1").arg(c.name() ));
4222 bo->setFramePenColor (c);
4226 void MapEditor::setFrameBrushColor(const QColor &c)
4228 BranchObj *bo=xelection.getBranch();
4231 saveState (bo, QString("setFrameBrushColor (\"%1\")").arg(bo->getFrameBrushColor().name() ),
4232 bo, QString ("setFrameBrushColor (\"%1\")").arg(c.name() ),QString ("set brush color of frame to %1").arg(c.name() ));
4233 bo->setFrameBrushColor (c);
4237 void MapEditor::setFramePadding (const int &i)
4239 BranchObj *bo=xelection.getBranch();
4242 saveState (bo, QString("setFramePadding (\"%1\")").arg(bo->getFramePadding() ),
4243 bo, QString ("setFramePadding (\"%1\")").arg(i),QString ("set brush color of frame to %1").arg(i));
4244 bo->setFramePadding (i);
4245 model->reposition();
4250 void MapEditor::setFrameBorderWidth(const int &i)
4252 BranchObj *bo=xelection.getBranch();
4255 saveState (bo, QString("setFrameBorderWidth (\"%1\")").arg(bo->getFrameBorderWidth() ),
4256 bo, QString ("setFrameBorderWidth (\"%1\")").arg(i),QString ("set border width of frame to %1").arg(i));
4257 bo->setFrameBorderWidth (i);
4258 model->reposition();
4263 void MapEditor::setIncludeImagesVer(bool b)
4265 BranchObj *bo=xelection.getBranch();
4268 QString u= b ? "false" : "true";
4269 QString r=!b ? "false" : "true";
4273 QString("setIncludeImagesVertically (%1)").arg(u),
4275 QString("setIncludeImagesVertically (%1)").arg(r),
4276 QString("Include images vertically in %1").arg(getName(bo))
4278 bo->setIncludeImagesVer(b);
4279 model->reposition();
4283 void MapEditor::setIncludeImagesHor(bool b)
4285 BranchObj *bo=xelection.getBranch();
4288 QString u= b ? "false" : "true";
4289 QString r=!b ? "false" : "true";
4293 QString("setIncludeImagesHorizontally (%1)").arg(u),
4295 QString("setIncludeImagesHorizontally (%1)").arg(r),
4296 QString("Include images horizontally in %1").arg(getName(bo))
4298 bo->setIncludeImagesHor(b);
4299 model->reposition();
4303 void MapEditor::setHideLinkUnselected (bool b)
4305 LinkableMapObj *sel=xelection.single();
4307 (xelection.type() == Selection::Branch ||
4308 xelection.type() == Selection::MapCenter ||
4309 xelection.type() == Selection::FloatImage ))
4311 QString u= b ? "false" : "true";
4312 QString r=!b ? "false" : "true";
4316 QString("setHideLinkUnselected (%1)").arg(u),
4318 QString("setHideLinkUnselected (%1)").arg(r),
4319 QString("Hide link of %1 if unselected").arg(getName(sel))
4321 sel->setHideLinkUnselected(b);
4325 void MapEditor::importDirInt(BranchObj *dst, QDir d)
4327 BranchObj *bo=xelection.getBranch();
4330 // Traverse directories
4331 d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
4332 QFileInfoList list = d.entryInfoList();
4335 for (int i = 0; i < list.size(); ++i)
4338 if (fi.fileName() != "." && fi.fileName() != ".." )
4341 bo=dst->getLastBranch();
4342 bo->setHeading (fi.fileName() );
4343 bo->setColor (QColor("blue"));
4345 if ( !d.cd(fi.fileName()) )
4346 QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory %1").arg(fi.fileName()));
4349 // Recursively add subdirs
4350 importDirInt (bo,d);
4356 d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
4357 list = d.entryInfoList();
4359 for (int i = 0; i < list.size(); ++i)
4363 bo=dst->getLastBranch();
4364 bo->setHeading (fi.fileName() );
4365 bo->setColor (QColor("black"));
4366 if (fi.fileName().right(4) == ".vym" )
4367 bo->setVymLink (fi.filePath());
4372 void MapEditor::importDirInt (const QString &s)
4374 BranchObj *bo=xelection.getBranch();
4377 saveStateChangingPart (bo,bo,QString ("importDir (\"%1\")").arg(s),QString("Import directory structure from %1").arg(s));
4380 importDirInt (bo,d);
4384 void MapEditor::importDir()
4386 BranchObj *bo=xelection.getBranch();
4389 QStringList filters;
4390 filters <<"VYM map (*.vym)";
4391 QFileDialog *fd=new QFileDialog( this,vymName+ " - " +tr("Choose directory structure to import"));
4392 fd->setMode (QFileDialog::DirectoryOnly);
4393 fd->setFilters (filters);
4394 fd->setCaption(vymName+" - " +tr("Choose directory structure to import"));
4398 if ( fd->exec() == QDialog::Accepted )
4400 importDirInt (fd->selectedFile() );
4401 model->reposition();
4407 void MapEditor::followXLink(int i)
4409 BranchObj *bo=xelection.getBranch();
4412 bo=bo->XLinkTargetAt(i);
4415 xelection.select(bo);
4416 ensureSelectionVisible();
4421 void MapEditor::editXLink(int i) // FIXME missing saveState
4423 BranchObj *bo=xelection.getBranch();
4426 XLinkObj *xlo=bo->XLinkAt(i);
4429 EditXLinkDialog dia;
4431 dia.setSelection(bo);
4432 if (dia.exec() == QDialog::Accepted)
4434 if (dia.useSettingsGlobal() )
4436 setMapDefXLinkColor (xlo->getColor() );
4437 setMapDefXLinkWidth (xlo->getWidth() );
4439 if (dia.deleteXLink())
4440 bo->deleteXLinkAt(i);
4446 AttributeTable* MapEditor::attributeTable()
4451 void MapEditor::testFunction1()
4453 BranchObj *bo=xelection.getBranch();
4454 if (bo) model->moveAway (bo);
4456 /* TODO Hide hidden stuff temporary, maybe add this as regular function somewhere
4457 if (hidemode==HideNone)
4459 setHideTmpMode (HideExport);
4460 mapCenter->calcBBoxSizeWithChilds();
4461 QRectF totalBBox=mapCenter->getTotalBBox();
4462 QRectF mapRect=totalBBox;
4463 QCanvasRectangle *frame=NULL;
4465 cout << " map has =("<<totalBBox.x()<<","<<totalBBox.y()<<","<<totalBBox.width()<<","<<totalBBox.height()<<")\n";
4467 mapRect.setRect (totalBBox.x(), totalBBox.y(),
4468 totalBBox.width(), totalBBox.height());
4469 frame=new QCanvasRectangle (mapRect,mapScene);
4470 frame->setBrush (QColor(white));
4471 frame->setPen (QColor(black));
4472 frame->setZValue(0);
4477 setHideTmpMode (HideNone);
4479 cout <<" hidemode="<<hidemode<<endl;
4483 void MapEditor::testFunction2()
4488 if (hidemode==HideExport)
4489 setHideTmpMode (HideNone);
4491 setHideTmpMode (HideExport);
4495 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
4497 // Lineedits are already closed by preceding
4498 // mouseEvent, we don't need to close here.
4500 QPointF p = mapToScene(e->pos());
4501 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4504 { // MapObj was found
4505 if (xelection.single() != lmo)
4507 // select the MapObj
4508 xelection.select(lmo);
4511 if (xelection.getBranch() )
4513 // Context Menu on branch or mapcenter
4515 branchContextMenu->popup(e->globalPos() );
4518 if (xelection.getFloatImage() )
4520 // Context Menu on floatimage
4522 floatimageContextMenu->popup(e->globalPos() );
4526 { // No MapObj found, we are on the Canvas itself
4527 // Context Menu on scene
4530 canvasContextMenu->popup(e->globalPos() );
4535 void MapEditor::keyPressEvent(QKeyEvent* e)
4537 if (e->modifiers() & Qt::ControlModifier)
4539 switch (mainWindow->getModMode())
4541 case Main::ModModeColor:
4542 setCursor (PickColorCursor);
4544 case Main::ModModeCopy:
4545 setCursor (CopyCursor);
4547 case Main::ModModeXLink:
4548 setCursor (XLinkCursor);
4551 setCursor (Qt::ArrowCursor);
4557 void MapEditor::keyReleaseEvent(QKeyEvent* e)
4559 if (!(e->modifiers() & Qt::ControlModifier))
4560 setCursor (Qt::ArrowCursor);
4563 void MapEditor::mousePressEvent(QMouseEvent* e)
4565 // Ignore right clicks, these will go to context menus
4566 if (e->button() == Qt::RightButton )
4572 //Ignore clicks while editing heading
4573 if (isSelectBlocked() )
4579 QPointF p = mapToScene(e->pos());
4580 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4584 //Take care of system flags _or_ modifier modes
4586 if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4587 typeid(*lmo)==typeid(MapCenterObj) ))
4589 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
4590 if (!foname.isEmpty())
4592 // systemFlag clicked
4596 if (e->state() & Qt::ControlModifier)
4597 mainWindow->editOpenURLTab();
4599 mainWindow->editOpenURL();
4601 else if (foname=="vymLink")
4603 mainWindow->editOpenVymLink();
4604 // tabWidget may change, better return now
4605 // before segfaulting...
4606 } else if (foname=="note")
4607 mainWindow->windowToggleNoteEditor();
4608 else if (foname=="hideInExport")
4615 // No system flag clicked, take care of modmodes (CTRL-Click)
4616 if (e->state() & Qt::ControlModifier)
4618 if (mainWindow->getModMode()==Main::ModModeColor)
4621 setCursor (PickColorCursor);
4624 if (mainWindow->getModMode()==Main::ModModeXLink)
4626 BranchObj *bo_begin=NULL;
4628 bo_begin=(BranchObj*)(lmo);
4630 if (xelection.getBranch() )
4631 bo_begin=xelection.getBranch();
4635 linkingObj_src=bo_begin;
4636 tmpXLink=new XLinkObj (mapScene);
4637 tmpXLink->setBegin (bo_begin);
4638 tmpXLink->setEnd (p);
4639 tmpXLink->setColor(defXLinkColor);
4640 tmpXLink->setWidth(defXLinkWidth);
4641 tmpXLink->updateXLink();
4642 tmpXLink->setVisibility (true);
4646 } // End of modmodes
4650 // Select the clicked object
4653 // Left Button Move Branches
4654 if (e->button() == Qt::LeftButton )
4656 //movingObj_start.setX( p.x() - selection->x() );// TODO replaced selection->lmo here
4657 //movingObj_start.setY( p.y() - selection->y() );
4658 movingObj_start.setX( p.x() - lmo->x() );
4659 movingObj_start.setY( p.y() - lmo->y() );
4660 movingObj_orgPos.setX (lmo->x() );
4661 movingObj_orgPos.setY (lmo->y() );
4662 movingObj_orgRelPos=lmo->getRelPos();
4664 // If modMode==copy, then we want to "move" the _new_ object around
4665 // then we need the offset from p to the _old_ selection, because of tmp
4666 if (mainWindow->getModMode()==Main::ModModeCopy &&
4667 e->state() & Qt::ControlModifier)
4669 BranchObj *bo=xelection.getBranch();
4673 bo->addBranch ((BranchObj*)xelection.single());
4675 xelection.select(bo->getLastBranch());
4676 model->reposition();
4680 movingObj=xelection.single();
4682 // Middle Button Toggle Scroll
4683 // (On Mac OS X this won't work, but we still have
4684 // a button in the toolbar)
4685 if (e->button() == Qt::MidButton )
4690 { // No MapObj found, we are on the scene itself
4691 // Left Button move Pos of sceneView
4692 if (e->button() == Qt::LeftButton )
4694 movingObj=NULL; // move Content not Obj
4695 movingObj_start=e->globalPos();
4696 movingCont_start=QPointF (
4697 horizontalScrollBar()->value(),
4698 verticalScrollBar()->value());
4699 movingVec=QPointF(0,0);
4700 setCursor(HandOpenCursor);
4705 void MapEditor::mouseMoveEvent(QMouseEvent* e)
4707 QPointF p = mapToScene(e->pos());
4708 LinkableMapObj *lmosel=xelection.single();
4710 // Move the selected MapObj
4711 if ( lmosel && movingObj)
4713 // reset cursor if we are moving and don't copy
4714 if (mainWindow->getModMode()!=Main::ModModeCopy)
4715 setCursor (Qt::ArrowCursor);
4717 // To avoid jumping of the sceneView, only
4718 // ensureSelectionVisible, if not tmp linked
4719 if (!lmosel->hasParObjTmp())
4720 ensureSelectionVisible ();
4722 // Now move the selection, but add relative position
4723 // (movingObj_start) where selection was chosen with
4724 // mousepointer. (This avoids flickering resp. jumping
4725 // of selection back to absPos)
4727 // Check if we could link
4728 LinkableMapObj* lmo=model->findMapObj(p, lmosel);
4731 FloatObj *fio=xelection.getFloatImage();
4734 fio->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4736 fio->updateLink(); //no need for reposition, if we update link here
4739 // Relink float to new mapcenter or branch, if shift is pressed
4740 // Only relink, if selection really has a new parent
4741 if ( (e->modifiers()==Qt::ShiftModifier) && lmo &&
4742 ( (typeid(*lmo)==typeid(BranchObj)) ||
4743 (typeid(*lmo)==typeid(MapCenterObj)) ) &&
4744 ( lmo != fio->getParObj())
4747 if (typeid(*fio) == typeid(FloatImageObj) &&
4748 ( (typeid(*lmo)==typeid(BranchObj) ||
4749 typeid(*lmo)==typeid(MapCenterObj)) ))
4752 // Also save the move which was done so far
4753 QString pold=qpointfToString(movingObj_orgRelPos);
4754 QString pnow=qpointfToString(fio->getRelPos());
4760 QString("Move %1 to relative position %2").arg(getName(fio)).arg(pnow));
4761 fio->getParObj()->requestReposition();
4762 model->reposition();
4764 linkTo (model->getSelectString(lmo));
4766 //movingObj_orgRelPos=lmosel->getRelPos();
4768 model->reposition();
4772 { // selection != a FloatObj
4773 if (lmosel->getDepth()==0)
4776 if (e->buttons()== Qt::LeftButton && e->modifiers()==Qt::ShiftModifier)
4777 ((MapCenterObj*)lmosel)->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4779 lmosel->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4780 model->updateRelPositions();
4783 if (lmosel->getDepth()==1)
4786 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4787 lmosel->setRelPos();
4790 // Move ordinary branch
4791 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4794 // Maybe we can relink temporary?
4795 if (lmo && (lmo!=lmosel) && xelection.getBranch() &&
4796 (typeid(*lmo)==typeid(BranchObj) ||
4797 typeid(*lmo)==typeid(MapCenterObj)) )
4800 if (e->modifiers()==Qt::ControlModifier)
4802 // Special case: CTRL to link below lmo
4803 lmosel->setParObjTmp (lmo,p,+1);
4805 else if (e->modifiers()==Qt::ShiftModifier)
4806 lmosel->setParObjTmp (lmo,p,-1);
4808 lmosel->setParObjTmp (lmo,p,0);
4811 lmosel->unsetParObjTmp();
4813 // reposition subbranch
4814 lmosel->reposition();
4818 } // no FloatImageObj
4822 } // selection && moving_obj
4824 // Draw a link from one branch to another
4827 tmpXLink->setEnd (p);
4828 tmpXLink->updateXLink();
4832 if (!movingObj && !pickingColor &&!drawingLink && e->buttons() == Qt::LeftButton )
4834 QPointF p=e->globalPos();
4835 movingVec.setX(-p.x() + movingObj_start.x() );
4836 movingVec.setY(-p.y() + movingObj_start.y() );
4837 horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
4838 verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
4843 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
4845 QPointF p = mapToScene(e->pos());
4846 LinkableMapObj *dst;
4847 LinkableMapObj *lmosel=xelection.single();
4848 // Have we been picking color?
4852 setCursor (Qt::ArrowCursor);
4853 // Check if we are over another branch
4854 dst=model->findMapObj(p, NULL);
4857 if (e->state() & Qt::ShiftModifier)
4858 colorBranch (((BranchObj*)dst)->getColor());
4860 colorSubtree (((BranchObj*)dst)->getColor());
4865 // Have we been drawing a link?
4869 // Check if we are over another branch
4870 dst=model->findMapObj(p, NULL);
4873 tmpXLink->setEnd ( ((BranchObj*)(dst)) );
4874 tmpXLink->updateXLink();
4875 tmpXLink->activate(); //FIXME savestate missing
4876 //saveStateComplete(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) );
4885 // Have we been moving something?
4886 if ( lmosel && movingObj )
4888 FloatImageObj *fo=xelection.getFloatImage();
4891 // Moved FloatObj. Maybe we need to reposition
4892 QString pold=qpointfToString(movingObj_orgRelPos);
4893 QString pnow=qpointfToString(fo->getRelPos());
4899 QString("Move %1 to relative position %2").arg(getName(fo)).arg(pnow));
4901 fo->getParObj()->requestReposition();
4902 model->reposition();
4905 // Check if we are over another branch, but ignore
4906 // any found LMOs, which are FloatObjs
4907 dst=model->findMapObj(mapToScene(e->pos() ), lmosel);
4909 if (dst && (typeid(*dst)!=typeid(BranchObj) && typeid(*dst)!=typeid(MapCenterObj)))
4912 BranchObj *bo=xelection.getBranch();
4913 if (bo && bo->getDepth()==0)
4915 if (movingObj_orgPos != bo->getAbsPos())
4917 QString pold=qpointfToString(movingObj_orgPos);
4918 QString pnow=qpointfToString(bo->getAbsPos());
4924 QString("Move mapcenter %1 to position %2").arg(getName(bo)).arg(pnow));
4928 if (xelection.type() == Selection::Branch )
4929 { // A branch was moved
4931 // save the position in case we link to mapcenter
4932 QPointF savePos=QPointF (lmosel->getAbsPos() );
4934 // Reset the temporary drawn link to the original one
4935 lmosel->unsetParObjTmp();
4937 // For Redo we may need to save original selection
4938 QString preSelStr=model->getSelectString(lmosel);
4943 // We have a destination, relink to that
4945 BranchObj* bsel=xelection.getBranch();
4946 BranchObj* bdst=(BranchObj*)dst;
4948 QString preParStr=model->getSelectString (bsel->getParObj());
4949 QString preNum=QString::number (bsel->getNum(),10);
4950 QString preDstParStr;
4952 if (e->state() & Qt::ShiftModifier && dst->getParObj())
4954 preDstParStr=model->getSelectString (dst->getParObj());
4955 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum());
4957 if (e->state() & Qt::ControlModifier && dst->getParObj())
4960 preDstParStr=model->getSelectString (dst->getParObj());
4961 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum()+1);
4964 preDstParStr=model->getSelectString(dst);
4965 bsel->linkTo (bdst,-1);
4966 if (dst->getDepth()==0) bsel->move (savePos);
4968 QString postSelStr=model->getSelectString(lmosel);
4969 QString postNum=QString::number (bsel->getNum(),10);
4971 QString undoCom="linkTo (\""+
4972 preParStr+ "\"," + preNum +"," +
4973 QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")";
4975 QString redoCom="linkTo (\""+
4976 preDstParStr + "\"," + postNum + "," +
4977 QString ("%1,%2").arg(savePos.x()).arg(savePos.y())+ ")";
4982 QString("Relink %1 to %2").arg(getName(bsel)).arg(getName(dst)) );
4984 model->reposition(); // not necessary if we undo temporary move below
4987 // No destination, undo temporary move
4989 if (lmosel->getDepth()==1)
4991 // The select string might be different _after_ moving around.
4992 // Therefor reposition and then use string of old selection, too
4993 model->reposition();
4995 QPointF rp(lmosel->getRelPos());
4996 if (rp != movingObj_orgRelPos)
4998 QString ps=qpointfToString(rp);
5000 model->getSelectString(lmosel), "moveRel "+qpointfToString(movingObj_orgRelPos),
5001 preSelStr, "moveRel "+ps,
5002 QString("Move %1 to relative position %2").arg(getName(lmosel)).arg(ps));
5006 // Draw the original link, before selection was moved around
5007 if (settings.value("/animation/use",false).toBool() && lmosel->getDepth()>1)
5009 QPointF p=bo->getParObj()->getChildPos();
5010 lmosel->setRelPos(); // calc relPos first
5011 model->startAnimation(
5012 lmosel->getRelPos(),
5013 QPointF (movingObj_orgPos.x() - p.x(), movingObj_orgPos.y() - p.y() )
5016 model->reposition();
5020 // Finally resize scene, if needed
5024 // Just make sure, that actions are still ok,e.g. the move branch up/down buttons...
5027 // maybe we moved View: set old cursor
5028 setCursor (Qt::ArrowCursor);
5032 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
5034 if (isSelectBlocked() )
5040 if (e->button() == Qt::LeftButton )
5042 QPointF p = mapToScene(e->pos());
5043 LinkableMapObj *lmo=model->findMapObj(p, NULL);
5044 if (lmo) { // MapObj was found
5045 // First select the MapObj than edit heading
5046 xelection.select(lmo);
5047 mainWindow->editHeading();
5052 void MapEditor::resizeEvent (QResizeEvent* e)
5054 QGraphicsView::resizeEvent( e );
5057 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
5059 //for (unsigned int i=0;event->format(i);i++) // Debug mime type
5060 // cerr << event->format(i) << endl;
5062 if (event->mimeData()->hasImage())
5063 event->acceptProposedAction();
5065 if (event->mimeData()->hasUrls())
5066 event->acceptProposedAction();
5069 void MapEditor::dragMoveEvent(QDragMoveEvent *)
5073 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
5078 void MapEditor::dropEvent(QDropEvent *event)
5080 BranchObj *sel=xelection.getBranch();
5084 foreach (QString format,event->mimeData()->formats())
5085 cout << "MapEditor: Dropped format: "<<qPrintable (format)<<endl;
5089 if (event->mimeData()->hasImage())
5091 QVariant imageData = event->mimeData()->imageData();
5092 addFloatImageInt (qvariant_cast<QPixmap>(imageData));
5094 if (event->mimeData()->hasUrls())
5095 uris=event->mimeData()->urls();
5103 for (int i=0; i<uris.count();i++)
5105 // Workaround to avoid adding empty branches
5106 if (!uris.at(i).toString().isEmpty())
5108 bo=sel->addBranch();
5111 s=uris.at(i).toLocalFile();
5114 QString file = QDir::fromNativeSeparators(s);
5115 heading = QFileInfo(file).baseName();
5117 if (file.endsWith(".vym", false))
5118 bo->setVymLink(file);
5120 bo->setURL(uris.at(i).toString());
5123 bo->setURL(uris.at(i).toString());
5126 if (!heading.isEmpty())
5127 bo->setHeading(heading);
5129 bo->setHeading(uris.at(i).toString());
5133 model->reposition();
5136 event->acceptProposedAction();
5140 void MapEditor::sendSelection()
5142 if (netstate!=Server) return;
5143 sendData (QString("select (\"%1\")").arg(xelection.getSelectString()) );
5146 void MapEditor::newServer()
5150 tcpServer = new QTcpServer(this);
5151 if (!tcpServer->listen(QHostAddress::Any,port)) {
5152 QMessageBox::critical(this, "vym server",
5153 QString("Unable to start the server: %1.").arg(tcpServer->errorString()));
5157 connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newClient()));
5159 cout<<"Server is running on port "<<tcpServer->serverPort()<<endl;
5162 void MapEditor::connectToServer()
5165 server="salam.suse.de";
5167 clientSocket = new QTcpSocket (this);
5168 clientSocket->abort();
5169 clientSocket->connectToHost(server ,port);
5170 connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readData()));
5171 connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
5172 this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
5174 cout<<"connected to "<<qPrintable (server)<<" port "<<port<<endl;
5179 void MapEditor::newClient()
5181 QTcpSocket *newClient = tcpServer->nextPendingConnection();
5182 connect(newClient, SIGNAL(disconnected()),
5183 newClient, SLOT(deleteLater()));
5185 cout <<"ME::newClient at "<<qPrintable( newClient->peerAddress().toString() )<<endl;
5187 clientList.append (newClient);
5191 void MapEditor::sendData(const QString &s)
5193 if (clientList.size()==0) return;
5195 // Create bytearray to send
5197 QDataStream out(&block, QIODevice::WriteOnly);
5198 out.setVersion(QDataStream::Qt_4_0);
5200 // Reserve some space for blocksize
5203 // Write sendCounter
5204 out << sendCounter++;
5209 // Go back and write blocksize so far
5210 out.device()->seek(0);
5211 quint16 bs=(quint16)(block.size() - 2*sizeof(quint16));
5215 cout << "ME::sendData bs="<<bs<<" counter="<<sendCounter<<" s="<<qPrintable(s)<<endl;
5217 for (int i=0; i<clientList.size(); ++i)
5219 //cout << "Sending \""<<qPrintable (s)<<"\" to "<<qPrintable (clientList.at(i)->peerAddress().toString())<<endl;
5220 clientList.at(i)->write (block);
5224 void MapEditor::readData ()
5226 while (clientSocket->bytesAvailable() >=(int)sizeof(quint16) )
5229 cout <<"readData bytesAvail="<<clientSocket->bytesAvailable();
5233 QDataStream in(clientSocket);
5234 in.setVersion(QDataStream::Qt_4_0);
5242 cout << " t="<<qPrintable (t)<<endl;
5248 void MapEditor::displayNetworkError(QAbstractSocket::SocketError socketError)
5250 switch (socketError) {
5251 case QAbstractSocket::RemoteHostClosedError:
5253 case QAbstractSocket::HostNotFoundError:
5254 QMessageBox::information(this, vymName +" Network client",
5255 "The host was not found. Please check the "
5256 "host name and port settings.");
5258 case QAbstractSocket::ConnectionRefusedError:
5259 QMessageBox::information(this, vymName + " Network client",
5260 "The connection was refused by the peer. "
5261 "Make sure the fortune server is running, "
5262 "and check that the host name and port "
5263 "settings are correct.");
5266 QMessageBox::information(this, vymName + " Network client",
5267 QString("The following error occurred: %1.")
5268 .arg(clientSocket->errorString()));
5272 void MapEditor::autosave()
5274 QDateTime now=QDateTime().currentDateTime();
5276 cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n";
5277 cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
5278 cout << " fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
5279 cout << " time: "<<qPrintable (now.toString())<<endl;
5280 cout << " zipped="<<zipped<<endl;
5282 // Disable autosave, while we have gone back in history
5283 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
5284 if (redosAvail>0) return;
5286 // Also disable autosave for new map without filename
5287 if (filePath.isEmpty()) return;
5290 if (mapUnsaved &&mapChanged && settings.value ("/mapeditor/autosave/use",true).toBool() )
5292 if (QFileInfo(filePath).lastModified()<=fileChangedTime)
5293 mainWindow->fileSave (this);
5296 cout <<" ME::autosave rejected, file on disk is newer than last save.\n";
5301 void MapEditor::fileChanged()
5303 // Check if file on disk has changed meanwhile
5304 if (!filePath.isEmpty())
5306 QDateTime tmod=QFileInfo (filePath).lastModified();
5307 if (tmod>fileChangedTime)
5310 /* FIXME debug message, sometimes there's a glitch in the metrics...
5311 cout << "ME::fileChanged()\n"
5312 << " last saved: "<<qPrintable (fileChangedTime.toString())<<endl
5313 << " last modififed: "<<qPrintable (tmod.toString())<<endl;
5315 // FIXME switch to current mapeditor and finish lineedits...
5316 QMessageBox mb( vymName,
5317 tr("The file of the map on disk has changed:\n\n"
5318 " %1\n\nDo you want to reload that map with the new file?").arg(filePath),
5319 QMessageBox::Question,
5321 QMessageBox::Cancel | QMessageBox::Default,
5322 QMessageBox::NoButton );
5324 mb.setButtonText( QMessageBox::Yes, tr("Reload"));
5325 mb.setButtonText( QMessageBox::No, tr("Ignore"));
5328 case QMessageBox::Yes:
5330 load (filePath,NewMap,fileType);
5331 case QMessageBox::Cancel:
5332 fileChangedTime=tmod; // allow autosave to overwrite newer file!
5340 /*TODO not needed? void MapEditor::contentsDropEvent(QDropEvent *event)
5343 } else if (event->provides("application/x-moz-file-promise-url") &&
5344 event->provides("application/x-moz-nativeimage"))
5346 // Contains url to the img src in unicode16
5347 QByteArray d = event->encodedData("application/x-moz-file-promise-url");
5348 QString url = QString((const QChar*)d.data(),d.size()/2);
5352 } else if (event->provides ("text/uri-list"))
5353 { // Uris provided e.g. by konqueror
5354 Q3UriDrag::decode (event,uris);
5355 } else if (event->provides ("_NETSCAPE_URL"))
5356 { // Uris provided by Mozilla
5357 QStringList l = QStringList::split("\n", event->encodedData("_NETSCAPE_URL"));
5360 } else if (event->provides("text/html")) {
5362 // Handels text mime types
5363 // Look like firefox allways handle text as unicode16 (2 bytes per char.)
5364 QByteArray d = event->encodedData("text/html");
5367 text = QString((const QChar*)d.data(),d.size()/2);
5371 textEditor->setText(text);
5375 } else if (event->provides("text/plain")) {
5376 QByteArray d = event->encodedData("text/plain");
5379 text = QString((const QChar*)d.data(),d.size()/2);
5383 textEditor->setText(text);
5393 bool isUnicode16(const QByteArray &d)
5395 // TODO: make more precise check for unicode 16.
5396 // Guess unicode16 if any of second bytes are zero
5397 unsigned int length = max(0,d.size()-2)/2;
5398 for (unsigned int i = 0; i<length ; i++)
5399 if (d.at(i*2+1)==0) return true;
5403 void MapEditor::addFloatImageInt (const QPixmap &img)
5405 BranchObj *bo=xelection.getBranch();
5408 FloatImageObj *fio=bo->addFloatImage();
5410 fio->setOriginalFilename("No original filename (image added by dropevent)");
5411 QString s=model->getSelectString(bo);
5412 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy dropped image to clipboard",fio );
5413 saveState (fio,"delete ()", bo,QString("paste(%1)").arg(curStep),"Pasting dropped image");
5414 model->reposition();
5421 void MapEditor::imageDataFetched(const QByteArray &a, Q3NetworkOperation * / *nop* /)
5423 if (!imageBuffer) imageBuffer = new QBuffer();
5424 if (!imageBuffer->isOpen()) {
5425 imageBuffer->open(QIODevice::WriteOnly | QIODevice::Append);
5427 imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a));
5431 void MapEditor::imageDataFinished(Q3NetworkOperation *nop)
5433 if (nop->state()==Q3NetworkProtocol::StDone) {
5434 QPixmap img(imageBuffer->buffer());
5435 addFloatImageInt (img);
5439 imageBuffer->close();
5441 imageBuffer->close();
5448 void MapEditor::fetchImage(const QString &url)
5451 urlOperator->stop();
5452 disconnect(urlOperator);
5456 urlOperator = new Q3UrlOperator(url);
5457 connect(urlOperator, SIGNAL(finished(Q3NetworkOperation *)),
5458 this, SLOT(imageDataFinished(Q3NetworkOperation*)));
5460 connect(urlOperator, SIGNAL(data(const QByteArray &, Q3NetworkOperation *)),
5461 this, SLOT(imageDataFetched(const QByteArray &, Q3NetworkOperation *)));