3 #include <q3filedialog.h>
10 #include "editxlinkdialog.h"
12 #include "exportxhtmldialog.h"
13 #include "extrainfodialog.h"
15 #include "linkablemapobj.h"
16 #include "mainwindow.h"
18 #include "texteditor.h"
19 #include "warningdialog.h"
20 #include "xml-freemind.h"
24 extern TextEditor *textEditor;
25 extern int statusbarTime;
26 extern Main *mainWindow;
27 extern QString tmpVymDir;
28 extern QString clipboardDir;
29 extern QString clipboardFile;
30 extern bool clipboardEmpty;
32 extern FlagRowObj *standardFlagsDefault;
34 extern QMenu* branchContextMenu;
35 extern QMenu* branchAddContextMenu;
36 extern QMenu* branchRemoveContextMenu;
37 extern QMenu* branchLinksContextMenu;
38 extern QMenu* branchXLinksContextMenuEdit;
39 extern QMenu* branchXLinksContextMenuFollow;
40 extern QMenu* floatimageContextMenu;
41 extern QMenu* canvasContextMenu;
44 extern Settings settings;
45 extern ImageIO imageIO;
47 extern QString vymName;
48 extern QString vymVersion;
50 extern QString iconPath;
51 extern QDir vymBaseDir;
52 extern QDir lastImageDir;
53 extern QDir lastFileDir;
55 int MapEditor::mapNum=0; // make instance
57 ///////////////////////////////////////////////////////////////////////
58 ///////////////////////////////////////////////////////////////////////
59 MapEditor::MapEditor( QWidget* parent) :
62 setObjectName ("MapEditor");
64 //cout << "Constructor ME "<<this<<endl;
68 mapScene= new QGraphicsScene(parent);
69 //mapScene= new QGraphicsScene(QRectF(0,0,width(),height()), parent);
70 mapScene->setBackgroundBrush (QBrush(Qt::white, Qt::SolidPattern));
73 model->setScene (mapScene);
74 model->setMapEditor (this);
80 defLinkColor=QColor (0,0,255);
81 defXLinkColor=QColor (180,180,180);
82 linkcolorhint=LinkableMapObj::DefaultColor;
83 linkstyle=LinkableMapObj::PolyParabel;
85 // Create bitmap cursors, platform dependant
86 HandOpenCursor=QCursor (QPixmap(iconPath+"cursorhandopen.png"),1,1);
87 PickColorCursor=QCursor ( QPixmap(iconPath+"cursorcolorpicker.png"), 5,27 );
88 CopyCursor=QCursor ( QPixmap(iconPath+"cursorcopy.png"), 1,1 );
89 XLinkCursor=QCursor ( QPixmap(iconPath+"cursorxlink.png"), 1,7 );
91 setFocusPolicy (Qt::StrongFocus);
100 xelection.setModel (model);
101 xelection.unselect();
104 defXLinkColor=QColor (230,230,230);
112 fileName=tr("unnamed");
115 stepsTotal=settings.readNumEntry("/mapeditor/stepsTotal",100);
116 undoSet.setEntry ("/history/stepsTotal",QString::number(stepsTotal));
117 mainWindow->updateHistory (undoSet);
119 // Initialize find routine
126 blockReposition=false;
127 blockSaveState=false;
131 // Create temporary files
138 setAcceptDrops (true);
143 autosaveTimer=new QTimer (this);
144 connect(autosaveTimer, SIGNAL(timeout()), this, SLOT(autosave()));
146 fileChangedTimer=new QTimer (this);
147 fileChangedTimer->start(3000);
148 connect(fileChangedTimer, SIGNAL(timeout()), this, SLOT(fileChanged()));
153 // Attributes //FIXME testing only...
156 attrTable= new AttributeTable();
158 ad=attrTable->addKey (k,StringList);
162 sl <<"val 1"<<"val 2"<< "val 3";
163 ad->setValue (QVariant (sl));
165 //attrTable->addValue ("Key A","P 1");
166 //attrTable->addValue ("Key A","P 2");
167 //attrTable->addValue ("Key A","P 3");
168 //attrTable->addValue ("Key A","P 4");
170 ad=attrTable->addKey (k,FreeString);
173 //attrTable->addValue ("Key B","w1");
174 //attrTable->addValue ("Key B","w2");
176 k="C - UniqueString";
177 ad=attrTable->addKey (k,UniqueString);
180 //attrTable->addKey ("Key Prio");
181 //attrTable->addValue ("Key Prio","Prio 1");
182 //attrTable->addValue ("Key Prio","Prio 2");
186 MapEditor::~MapEditor()
188 //cout <<"Destructor MapEditor "<<mapName.toStdString()<<endl;
189 fileChangedTimer->stop();
192 // tmpMapDir is in tmpVymDir, so it gets removed automagically when vym closes
194 //removeDir(QDir(tmpMapDir));
198 VymModel* MapEditor::getModel()
203 QGraphicsScene * MapEditor::getScene()
208 MapEditor::State MapEditor::getState()
213 void MapEditor::setStateEditHeading(bool s)
217 if (state==Idle) state=EditHeading;
223 bool MapEditor::isRepositionBlocked()
225 return blockReposition;
228 void MapEditor::setSaveStateBlocked(bool b)
233 bool MapEditor::isSelectBlocked()
235 if (state==EditHeading)
241 QString MapEditor::getName (const LinkableMapObj *lmo)
244 if (!lmo) return QString("Error: NULL has no name!");
246 if ((typeid(*lmo) == typeid(BranchObj) ||
247 typeid(*lmo) == typeid(MapCenterObj)))
250 s=(((BranchObj*)lmo)->getHeading());
251 if (s=="") s="unnamed";
252 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("date",model->getDate()) +
305 attribut("countBranches", QString().number(model->countBranches())) +
307 attribut("backgroundColor", mapScene->backgroundBrush().color().name() ) +
308 attribut("selectionColor", xelection.getColor().name() ) +
309 attribut("linkStyle", ls ) +
310 attribut("linkColor", defLinkColor.name() ) +
311 attribut("defXLinkColor", defXLinkColor.name() ) +
312 attribut("defXLinkWidth", QString().setNum(defXLinkWidth,10) ) +
314 s+=beginElement("vymmap",mapAttr);
317 // Find the used flags while traversing the tree
318 standardFlagsDefault->resetUsedCounter();
320 // Reset the counters before saving
321 // TODO constr. of FIO creates lots of objects, better do this in some other way...
322 FloatImageObj (mapScene).resetSaveCounter();
324 // Build xml recursivly
325 if (!saveSel || typeid (*saveSel) == typeid (MapCenterObj))
326 // Save complete map, if saveSel not set
327 s+=model->saveToDir(tmpdir,prefix,writeflags,offset);
330 if ( typeid(*saveSel) == typeid(BranchObj) )
332 s+=((BranchObj*)saveSel)->saveToDir(tmpdir,prefix,offset);
335 if ( typeid(*saveSel) == typeid(FloatImageObj) )
337 s+=((FloatImageObj*)saveSel)->saveToDir(tmpdir,prefix);
341 // Save local settings
342 s+=settings.getDataXML (destPath);
345 if (!xelection.isEmpty() && !saveSel )
346 s+=valueElement("select",xelection.getSelectString());
349 s+=endElement("vymmap");
352 standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags);
356 QString MapEditor::getHistoryDir()
358 QString histName(QString("history-%1").arg(curStep));
359 return (tmpMapDir+"/"+histName);
362 void MapEditor::saveState(const SaveMode &savemode, const QString &undoSelection, const QString &undoCom, const QString &redoSelection, const QString &redoCom, const QString &comment, LinkableMapObj *saveSel)
364 sendData(redoCom); //FIXME testing
369 if (blockSaveState) return;
371 if (debug) cout << "ME::saveState() for "<<qPrintable (mapName)<<endl;
373 // Find out current undo directory
374 if (undosAvail<stepsTotal) undosAvail++;
376 if (curStep>stepsTotal) curStep=1;
378 QString backupXML="";
379 QString histDir=getHistoryDir();
380 QString bakMapPath=histDir+"/map.xml";
382 // Create histDir if not available
385 makeSubDirs (histDir);
387 // Save depending on how much needs to be saved
389 backupXML=saveToDir (histDir,mapName+"-",false, QPointF (),saveSel);
391 QString undoCommand="";
392 if (savemode==UndoCommand)
396 else if (savemode==PartOfMap )
399 undoCommand.replace ("PATH",bakMapPath);
402 if (!backupXML.isEmpty())
403 // Write XML Data to disk
404 saveStringToDisk (bakMapPath,backupXML);
406 // We would have to save all actions in a tree, to keep track of
407 // possible redos after a action. Possible, but we are too lazy: forget about redos.
410 // Write the current state to disk
411 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
412 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
413 undoSet.setEntry ("/history/curStep",QString::number(curStep));
414 undoSet.setEntry (QString("/history/step-%1/undoCommand").arg(curStep),undoCommand);
415 undoSet.setEntry (QString("/history/step-%1/undoSelection").arg(curStep),undoSelection);
416 undoSet.setEntry (QString("/history/step-%1/redoCommand").arg(curStep),redoCom);
417 undoSet.setEntry (QString("/history/step-%1/redoSelection").arg(curStep),redoSelection);
418 undoSet.setEntry (QString("/history/step-%1/comment").arg(curStep),comment);
419 undoSet.setEntry (QString("/history/version"),vymVersion);
420 undoSet.writeSettings(histPath);
424 // TODO remove after testing
425 //cout << " into="<< histPath.toStdString()<<endl;
426 cout << " stepsTotal="<<stepsTotal<<
427 ", undosAvail="<<undosAvail<<
428 ", redosAvail="<<redosAvail<<
429 ", curStep="<<curStep<<endl;
430 cout << " ---------------------------"<<endl;
431 cout << " comment="<<comment.toStdString()<<endl;
432 cout << " undoCom="<<undoCommand.toStdString()<<endl;
433 cout << " undoSel="<<undoSelection.toStdString()<<endl;
434 cout << " redoCom="<<redoCom.toStdString()<<endl;
435 cout << " redoSel="<<redoSelection.toStdString()<<endl;
436 if (saveSel) cout << " saveSel="<<qPrintable (model->getSelectString(saveSel))<<endl;
437 cout << " ---------------------------"<<endl;
440 mainWindow->updateHistory (undoSet);
446 void MapEditor::saveStateChangingPart(LinkableMapObj *undoSel, LinkableMapObj* redoSel, const QString &rc, const QString &comment)
448 // save the selected part of the map, Undo will replace part of map
449 QString undoSelection="";
451 undoSelection=model->getSelectString(undoSel);
453 qWarning ("MapEditor::saveStateChangingPart no undoSel given!");
454 QString redoSelection="";
456 redoSelection=model->getSelectString(undoSel);
458 qWarning ("MapEditor::saveStateChangingPart no redoSel given!");
461 saveState (PartOfMap,
462 undoSelection, "addMapReplace (\"PATH\")",
468 void MapEditor::saveStateRemovingPart(LinkableMapObj *redoSel, const QString &comment)
472 qWarning ("MapEditor::saveStateRemovingPart no redoSel given!");
475 QString undoSelection=model->getSelectString (redoSel->getParObj());
476 QString redoSelection=model->getSelectString(redoSel);
477 if (typeid(*redoSel) == typeid(BranchObj) )
479 // save the selected branch of the map, Undo will insert part of map
480 saveState (PartOfMap,
481 undoSelection, QString("addMapInsert (\"PATH\",%1)").arg(((BranchObj*)redoSel)->getNum()),
482 redoSelection, "delete ()",
489 void MapEditor::saveState(LinkableMapObj *undoSel, const QString &uc, LinkableMapObj *redoSel, const QString &rc, const QString &comment)
491 // "Normal" savestate: save commands, selections and comment
492 // so just save commands for undo and redo
493 // and use current selection
495 QString redoSelection="";
496 if (redoSel) redoSelection=model->getSelectString(redoSel);
497 QString undoSelection="";
498 if (undoSel) undoSelection=model->getSelectString(undoSel);
500 saveState (UndoCommand,
507 void MapEditor::saveState(const QString &undoSel, const QString &uc, const QString &redoSel, const QString &rc, const QString &comment)
509 // "Normal" savestate: save commands, selections and comment
510 // so just save commands for undo and redo
511 // and use current selection
512 saveState (UndoCommand,
519 void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment)
521 // "Normal" savestate applied to model (no selection needed):
522 // save commands and comment
523 saveState (UndoCommand,
531 void MapEditor::parseAtom(const QString &atom)
533 BranchObj *selb=xelection.getBranch();
539 // Split string s into command and parameters
540 parser.parseAtom (atom);
541 QString com=parser.getCommand();
544 /////////////////////////////////////////////////////////////////////
545 if (com=="addBranch")
547 if (xelection.isEmpty())
549 parser.setError (Aborted,"Nothing selected");
552 parser.setError (Aborted,"Type of selection is not a branch");
557 if (parser.checkParCount(pl))
559 if (parser.parCount()==0)
563 n=parser.parInt (ok,0);
564 if (ok ) addNewBranch (n);
568 /////////////////////////////////////////////////////////////////////
569 } else if (com=="addBranchBefore")
571 if (xelection.isEmpty())
573 parser.setError (Aborted,"Nothing selected");
576 parser.setError (Aborted,"Type of selection is not a branch");
579 if (parser.parCount()==0)
581 addNewBranchBefore ();
584 /////////////////////////////////////////////////////////////////////
585 } else if (com==QString("addMapCenter"))
587 if (parser.checkParCount(2))
589 x=parser.parDouble (ok,0);
592 y=parser.parDouble (ok,1);
593 if (ok) model->addMapCenter (QPointF(x,y));
596 /////////////////////////////////////////////////////////////////////
597 } else if (com==QString("addMapReplace"))
599 if (xelection.isEmpty())
601 parser.setError (Aborted,"Nothing selected");
604 parser.setError (Aborted,"Type of selection is not a branch");
605 } else if (parser.checkParCount(1))
607 //s=parser.parString (ok,0); // selection
608 t=parser.parString (ok,0); // path to map
609 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
610 addMapReplaceInt(model->getSelectString(selb),t);
612 /////////////////////////////////////////////////////////////////////
613 } else if (com==QString("addMapInsert"))
615 if (xelection.isEmpty())
617 parser.setError (Aborted,"Nothing selected");
620 parser.setError (Aborted,"Type of selection is not a branch");
623 if (parser.checkParCount(2))
625 t=parser.parString (ok,0); // path to map
626 n=parser.parInt(ok,1); // position
627 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
628 addMapInsertInt(t,n);
631 /////////////////////////////////////////////////////////////////////
632 } else if (com=="clearFlags")
634 if (xelection.isEmpty() )
636 parser.setError (Aborted,"Nothing selected");
639 parser.setError (Aborted,"Type of selection is not a branch");
640 } else if (parser.checkParCount(0))
642 selb->clearStandardFlags();
643 selb->updateFlagsToolbar();
645 /////////////////////////////////////////////////////////////////////
646 } else if (com=="colorBranch")
648 if (xelection.isEmpty())
650 parser.setError (Aborted,"Nothing selected");
653 parser.setError (Aborted,"Type of selection is not a branch");
654 } else if (parser.checkParCount(1))
656 QColor c=parser.parColor (ok,0);
657 if (ok) colorBranch (c);
659 /////////////////////////////////////////////////////////////////////
660 } else if (com=="colorSubtree")
662 if (xelection.isEmpty())
664 parser.setError (Aborted,"Nothing selected");
667 parser.setError (Aborted,"Type of selection is not a branch");
668 } else if (parser.checkParCount(1))
670 QColor c=parser.parColor (ok,0);
671 if (ok) colorSubtree (c);
673 /////////////////////////////////////////////////////////////////////
674 } else if (com=="copy")
676 if (xelection.isEmpty())
678 parser.setError (Aborted,"Nothing selected");
681 parser.setError (Aborted,"Type of selection is not a branch");
682 } else if (parser.checkParCount(0))
684 //FIXME missing action for copy
686 /////////////////////////////////////////////////////////////////////
687 } else if (com=="cut")
689 if (xelection.isEmpty())
691 parser.setError (Aborted,"Nothing selected");
692 } else if ( xelection.type()!=Selection::Branch &&
693 xelection.type()!=Selection::MapCenter &&
694 xelection.type()!=Selection::FloatImage )
696 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
697 } else if (parser.checkParCount(0))
701 /////////////////////////////////////////////////////////////////////
702 } else if (com=="delete")
704 if (xelection.isEmpty())
706 parser.setError (Aborted,"Nothing selected");
708 /*else if (xelection.type() != Selection::Branch && xelection.type() != Selection::FloatImage )
710 parser.setError (Aborted,"Type of selection is wrong.");
713 else if (parser.checkParCount(0))
717 /////////////////////////////////////////////////////////////////////
718 } else if (com=="deleteKeepChilds")
720 if (xelection.isEmpty())
722 parser.setError (Aborted,"Nothing selected");
725 parser.setError (Aborted,"Type of selection is not a branch");
726 } else if (parser.checkParCount(0))
730 /////////////////////////////////////////////////////////////////////
731 } else if (com=="deleteChilds")
733 if (xelection.isEmpty())
735 parser.setError (Aborted,"Nothing selected");
738 parser.setError (Aborted,"Type of selection is not a branch");
739 } else if (parser.checkParCount(0))
743 /////////////////////////////////////////////////////////////////////
744 } else if (com=="exportASCII")
748 if (parser.parCount()>=1)
749 // Hey, we even have a filename
750 fname=parser.parString(ok,0);
753 parser.setError (Aborted,"Could not read filename");
756 exportASCII (fname,false);
758 /////////////////////////////////////////////////////////////////////
759 } else if (com=="exportImage")
763 if (parser.parCount()>=2)
764 // Hey, we even have a filename
765 fname=parser.parString(ok,0);
768 parser.setError (Aborted,"Could not read filename");
771 QString format="PNG";
772 if (parser.parCount()>=2)
774 format=parser.parString(ok,1);
776 exportImage (fname,false,format);
778 /////////////////////////////////////////////////////////////////////
779 } else if (com=="exportXHTML")
783 if (parser.parCount()>=2)
784 // Hey, we even have a filename
785 fname=parser.parString(ok,1);
788 parser.setError (Aborted,"Could not read filename");
791 exportXHTML (fname,false);
793 /////////////////////////////////////////////////////////////////////
794 } else if (com=="exportXML")
798 if (parser.parCount()>=2)
799 // Hey, we even have a filename
800 fname=parser.parString(ok,1);
803 parser.setError (Aborted,"Could not read filename");
806 exportXML (fname,false);
808 /////////////////////////////////////////////////////////////////////
809 } else if (com=="importDir")
811 if (xelection.isEmpty())
813 parser.setError (Aborted,"Nothing selected");
816 parser.setError (Aborted,"Type of selection is not a branch");
817 } else if (parser.checkParCount(1))
819 s=parser.parString(ok,0);
820 if (ok) importDirInt(s);
822 /////////////////////////////////////////////////////////////////////
823 } else if (com=="linkTo")
825 if (xelection.isEmpty())
827 parser.setError (Aborted,"Nothing selected");
830 if (parser.checkParCount(4))
832 // 0 selectstring of parent
833 // 1 num in parent (for branches)
834 // 2,3 x,y of mainbranch or mapcenter
835 s=parser.parString(ok,0);
836 LinkableMapObj *dst=model->findObjBySelect (s);
839 if (typeid(*dst) == typeid(BranchObj) )
841 // Get number in parent
842 n=parser.parInt (ok,1);
845 selb->linkTo ((BranchObj*)(dst),n);
848 } else if (typeid(*dst) == typeid(MapCenterObj) )
850 selb->linkTo ((BranchObj*)(dst),-1);
851 // Get coordinates of mainbranch
852 x=parser.parDouble(ok,2);
855 y=parser.parDouble(ok,3);
865 } else if ( xelection.type() == Selection::FloatImage)
867 if (parser.checkParCount(1))
869 // 0 selectstring of parent
870 s=parser.parString(ok,0);
871 LinkableMapObj *dst=model->findObjBySelect (s);
874 if (typeid(*dst) == typeid(BranchObj) ||
875 typeid(*dst) == typeid(MapCenterObj))
876 linkTo (model->getSelectString(dst));
878 parser.setError (Aborted,"Destination is not a branch");
881 parser.setError (Aborted,"Type of selection is not a floatimage or branch");
882 /////////////////////////////////////////////////////////////////////
883 } else if (com=="loadImage")
885 if (xelection.isEmpty())
887 parser.setError (Aborted,"Nothing selected");
890 parser.setError (Aborted,"Type of selection is not a branch");
891 } else if (parser.checkParCount(1))
893 s=parser.parString(ok,0);
894 if (ok) loadFloatImageInt (s);
896 /////////////////////////////////////////////////////////////////////
897 } else if (com=="moveBranchUp")
899 if (xelection.isEmpty() )
901 parser.setError (Aborted,"Nothing selected");
904 parser.setError (Aborted,"Type of selection is not a branch");
905 } else if (parser.checkParCount(0))
909 /////////////////////////////////////////////////////////////////////
910 } else if (com=="moveBranchDown")
912 if (xelection.isEmpty() )
914 parser.setError (Aborted,"Nothing selected");
917 parser.setError (Aborted,"Type of selection is not a branch");
918 } else if (parser.checkParCount(0))
922 /////////////////////////////////////////////////////////////////////
923 } else if (com=="move")
925 if (xelection.isEmpty() )
927 parser.setError (Aborted,"Nothing selected");
928 } else if ( xelection.type()!=Selection::Branch &&
929 xelection.type()!=Selection::MapCenter &&
930 xelection.type()!=Selection::FloatImage )
932 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
933 } else if (parser.checkParCount(2))
935 x=parser.parDouble (ok,0);
938 y=parser.parDouble (ok,1);
942 /////////////////////////////////////////////////////////////////////
943 } else if (com=="moveRel")
945 if (xelection.isEmpty() )
947 parser.setError (Aborted,"Nothing selected");
948 } else if ( xelection.type()!=Selection::Branch &&
949 xelection.type()!=Selection::MapCenter &&
950 xelection.type()!=Selection::FloatImage )
952 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
953 } else if (parser.checkParCount(2))
955 x=parser.parDouble (ok,0);
958 y=parser.parDouble (ok,1);
959 if (ok) moveRel (x,y);
962 /////////////////////////////////////////////////////////////////////
963 } else if (com=="nop")
965 /////////////////////////////////////////////////////////////////////
966 } else if (com=="paste")
968 if (xelection.isEmpty() )
970 parser.setError (Aborted,"Nothing selected");
973 parser.setError (Aborted,"Type of selection is not a branch");
974 } else if (parser.checkParCount(1))
976 n=parser.parInt (ok,0);
977 if (ok) pasteNoSave(n);
979 /////////////////////////////////////////////////////////////////////
980 } else if (com=="qa")
982 if (xelection.isEmpty() )
984 parser.setError (Aborted,"Nothing selected");
987 parser.setError (Aborted,"Type of selection is not a branch");
988 } else if (parser.checkParCount(4))
991 c=parser.parString (ok,0);
994 parser.setError (Aborted,"No comment given");
997 s=parser.parString (ok,1);
1000 parser.setError (Aborted,"First parameter is not a string");
1003 t=parser.parString (ok,2);
1006 parser.setError (Aborted,"Condition is not a string");
1009 u=parser.parString (ok,3);
1012 parser.setError (Aborted,"Third parameter is not a string");
1017 parser.setError (Aborted,"Unknown type: "+s);
1022 parser.setError (Aborted,"Unknown operator: "+t);
1027 parser.setError (Aborted,"Type of selection is not a branch");
1030 if (selb->getHeading() == u)
1032 cout << "PASSED: " << qPrintable (c) << endl;
1035 cout << "FAILED: " << qPrintable (c) << endl;
1045 /////////////////////////////////////////////////////////////////////
1046 } else if (com=="saveImage")
1048 FloatImageObj *fio=xelection.getFloatImage();
1051 parser.setError (Aborted,"Type of selection is not an image");
1052 } else if (parser.checkParCount(2))
1054 s=parser.parString(ok,0);
1057 t=parser.parString(ok,1);
1058 if (ok) saveFloatImageInt (fio,t,s);
1061 /////////////////////////////////////////////////////////////////////
1062 } else if (com=="scroll")
1064 if (xelection.isEmpty() )
1066 parser.setError (Aborted,"Nothing selected");
1069 parser.setError (Aborted,"Type of selection is not a branch");
1070 } else if (parser.checkParCount(0))
1072 if (!scrollBranch (selb))
1073 parser.setError (Aborted,"Could not scroll branch");
1075 /////////////////////////////////////////////////////////////////////
1076 } else if (com=="select")
1078 if (parser.checkParCount(1))
1080 s=parser.parString(ok,0);
1083 /////////////////////////////////////////////////////////////////////
1084 } else if (com=="selectLastBranch")
1086 if (xelection.isEmpty() )
1088 parser.setError (Aborted,"Nothing selected");
1091 parser.setError (Aborted,"Type of selection is not a branch");
1092 } else if (parser.checkParCount(0))
1094 BranchObj *bo=selb->getLastBranch();
1096 parser.setError (Aborted,"Could not select last branch");
1100 /////////////////////////////////////////////////////////////////////
1101 } else if (com=="selectLastImage")
1103 if (xelection.isEmpty() )
1105 parser.setError (Aborted,"Nothing selected");
1108 parser.setError (Aborted,"Type of selection is not a branch");
1109 } else if (parser.checkParCount(0))
1111 FloatImageObj *fio=selb->getLastFloatImage();
1113 parser.setError (Aborted,"Could not select last image");
1117 /////////////////////////////////////////////////////////////////////
1118 } else if (com=="selectLatestAdded")
1120 if (latestSelection.isEmpty() )
1122 parser.setError (Aborted,"No latest added object");
1125 if (!select (latestSelection))
1126 parser.setError (Aborted,"Could not select latest added object "+latestSelection);
1128 /////////////////////////////////////////////////////////////////////
1129 } else if (com=="setFrameType")
1131 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1133 parser.setError (Aborted,"Type of selection does not allow setting frame type");
1135 else if (parser.checkParCount(1))
1137 s=parser.parString(ok,0);
1138 if (ok) setFrameType (s);
1140 /////////////////////////////////////////////////////////////////////
1141 } else if (com=="setFramePenColor")
1143 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1145 parser.setError (Aborted,"Type of selection does not allow setting of pen color");
1147 else if (parser.checkParCount(1))
1149 QColor c=parser.parColor(ok,0);
1150 if (ok) setFramePenColor (c);
1152 /////////////////////////////////////////////////////////////////////
1153 } else if (com=="setFrameBrushColor")
1155 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1157 parser.setError (Aborted,"Type of selection does not allow setting brush color");
1159 else if (parser.checkParCount(1))
1161 QColor c=parser.parColor(ok,0);
1162 if (ok) setFrameBrushColor (c);
1164 /////////////////////////////////////////////////////////////////////
1165 } else if (com=="setFramePadding")
1167 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1169 parser.setError (Aborted,"Type of selection does not allow setting frame padding");
1171 else if (parser.checkParCount(1))
1173 n=parser.parInt(ok,0);
1174 if (ok) setFramePadding(n);
1176 /////////////////////////////////////////////////////////////////////
1177 } else if (com=="setFrameBorderWidth")
1179 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1181 parser.setError (Aborted,"Type of selection does not allow setting frame border width");
1183 else if (parser.checkParCount(1))
1185 n=parser.parInt(ok,0);
1186 if (ok) setFrameBorderWidth (n);
1188 /////////////////////////////////////////////////////////////////////
1189 } else if (com=="setMapAuthor")
1191 if (parser.checkParCount(1))
1193 s=parser.parString(ok,0);
1194 if (ok) setMapAuthor (s);
1196 /////////////////////////////////////////////////////////////////////
1197 } else if (com=="setMapComment")
1199 if (parser.checkParCount(1))
1201 s=parser.parString(ok,0);
1202 if (ok) setMapComment(s);
1204 /////////////////////////////////////////////////////////////////////
1205 } else if (com=="setMapBackgroundColor")
1207 if (xelection.isEmpty() )
1209 parser.setError (Aborted,"Nothing selected");
1210 } else if (! xelection.getBranch() )
1212 parser.setError (Aborted,"Type of selection is not a branch");
1213 } else if (parser.checkParCount(1))
1215 QColor c=parser.parColor (ok,0);
1216 if (ok) setMapBackgroundColor (c);
1218 /////////////////////////////////////////////////////////////////////
1219 } else if (com=="setMapDefLinkColor")
1221 if (xelection.isEmpty() )
1223 parser.setError (Aborted,"Nothing selected");
1226 parser.setError (Aborted,"Type of selection is not a branch");
1227 } else if (parser.checkParCount(1))
1229 QColor c=parser.parColor (ok,0);
1230 if (ok) setMapDefLinkColor (c);
1232 /////////////////////////////////////////////////////////////////////
1233 } else if (com=="setMapLinkStyle")
1235 if (parser.checkParCount(1))
1237 s=parser.parString (ok,0);
1238 if (ok) setMapLinkStyle(s);
1240 /////////////////////////////////////////////////////////////////////
1241 } else if (com=="setHeading")
1243 if (xelection.isEmpty() )
1245 parser.setError (Aborted,"Nothing selected");
1248 parser.setError (Aborted,"Type of selection is not a branch");
1249 } else if (parser.checkParCount(1))
1251 s=parser.parString (ok,0);
1255 /////////////////////////////////////////////////////////////////////
1256 } else if (com=="setHideExport")
1258 if (xelection.isEmpty() )
1260 parser.setError (Aborted,"Nothing selected");
1261 } else if (xelection.type()!=Selection::Branch && xelection.type() != Selection::MapCenter &&xelection.type()!=Selection::FloatImage)
1263 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
1264 } else if (parser.checkParCount(1))
1266 b=parser.parBool(ok,0);
1267 if (ok) setHideExport (b);
1269 /////////////////////////////////////////////////////////////////////
1270 } else if (com=="setIncludeImagesHorizontally")
1272 if (xelection.isEmpty() )
1274 parser.setError (Aborted,"Nothing selected");
1277 parser.setError (Aborted,"Type of selection is not a branch");
1278 } else if (parser.checkParCount(1))
1280 b=parser.parBool(ok,0);
1281 if (ok) setIncludeImagesHor(b);
1283 /////////////////////////////////////////////////////////////////////
1284 } else if (com=="setIncludeImagesVertically")
1286 if (xelection.isEmpty() )
1288 parser.setError (Aborted,"Nothing selected");
1291 parser.setError (Aborted,"Type of selection is not a branch");
1292 } else if (parser.checkParCount(1))
1294 b=parser.parBool(ok,0);
1295 if (ok) setIncludeImagesVer(b);
1297 /////////////////////////////////////////////////////////////////////
1298 } else if (com=="setHideLinkUnselected")
1300 if (xelection.isEmpty() )
1302 parser.setError (Aborted,"Nothing selected");
1303 } else if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1305 parser.setError (Aborted,"Type of selection does not allow hiding the link");
1306 } else if (parser.checkParCount(1))
1308 b=parser.parBool(ok,0);
1309 if (ok) setHideLinkUnselected(b);
1311 /////////////////////////////////////////////////////////////////////
1312 } else if (com=="setSelectionColor")
1314 if (parser.checkParCount(1))
1316 QColor c=parser.parColor (ok,0);
1317 if (ok) setSelectionColorInt (c);
1319 /////////////////////////////////////////////////////////////////////
1320 } else if (com=="setURL")
1322 if (xelection.isEmpty() )
1324 parser.setError (Aborted,"Nothing selected");
1327 parser.setError (Aborted,"Type of selection is not a branch");
1328 } else if (parser.checkParCount(1))
1330 s=parser.parString (ok,0);
1333 /////////////////////////////////////////////////////////////////////
1334 } else if (com=="setVymLink")
1336 if (xelection.isEmpty() )
1338 parser.setError (Aborted,"Nothing selected");
1341 parser.setError (Aborted,"Type of selection is not a branch");
1342 } else if (parser.checkParCount(1))
1344 s=parser.parString (ok,0);
1345 if (ok) setVymLinkInt(s);
1348 /////////////////////////////////////////////////////////////////////
1349 else if (com=="setFlag")
1351 if (xelection.isEmpty() )
1353 parser.setError (Aborted,"Nothing selected");
1356 parser.setError (Aborted,"Type of selection is not a branch");
1357 } else if (parser.checkParCount(1))
1359 s=parser.parString(ok,0);
1362 selb->activateStandardFlag(s);
1363 selb->updateFlagsToolbar();
1366 /////////////////////////////////////////////////////////////////////
1367 } else if (com=="setFrameType")
1369 if (xelection.isEmpty() )
1371 parser.setError (Aborted,"Nothing selected");
1374 parser.setError (Aborted,"Type of selection is not a branch");
1375 } else if (parser.checkParCount(1))
1377 s=parser.parString(ok,0);
1381 /////////////////////////////////////////////////////////////////////
1382 } else if (com=="sortChildren")
1384 if (xelection.isEmpty() )
1386 parser.setError (Aborted,"Nothing selected");
1389 parser.setError (Aborted,"Type of selection is not a branch");
1390 } else if (parser.checkParCount(0))
1394 /////////////////////////////////////////////////////////////////////
1395 } else if (com=="toggleFlag")
1397 if (xelection.isEmpty() )
1399 parser.setError (Aborted,"Nothing selected");
1402 parser.setError (Aborted,"Type of selection is not a branch");
1403 } else if (parser.checkParCount(1))
1405 s=parser.parString(ok,0);
1408 selb->toggleStandardFlag(s);
1409 selb->updateFlagsToolbar();
1412 /////////////////////////////////////////////////////////////////////
1413 } else if (com=="unscroll")
1415 if (xelection.isEmpty() )
1417 parser.setError (Aborted,"Nothing selected");
1420 parser.setError (Aborted,"Type of selection is not a branch");
1421 } else if (parser.checkParCount(0))
1423 if (!unscrollBranch (selb))
1424 parser.setError (Aborted,"Could not unscroll branch");
1426 /////////////////////////////////////////////////////////////////////
1427 } else if (com=="unscrollChilds")
1429 if (xelection.isEmpty() )
1431 parser.setError (Aborted,"Nothing selected");
1434 parser.setError (Aborted,"Type of selection is not a branch");
1435 } else if (parser.checkParCount(0))
1439 /////////////////////////////////////////////////////////////////////
1440 } else if (com=="unsetFlag")
1442 if (xelection.isEmpty() )
1444 parser.setError (Aborted,"Nothing selected");
1447 parser.setError (Aborted,"Type of selection is not a branch");
1448 } else if (parser.checkParCount(1))
1450 s=parser.parString(ok,0);
1453 selb->deactivateStandardFlag(s);
1454 selb->updateFlagsToolbar();
1458 parser.setError (Aborted,"Unknown command");
1461 if (parser.errorLevel()==NoError)
1463 // setChanged(); FIXME should not be called e.g. for export?!
1464 model->reposition();
1468 // TODO Error handling
1469 qWarning("MapEditor::parseAtom: Error!");
1470 qWarning(parser.errorMessage());
1474 void MapEditor::runScript (QString script)
1476 parser.setScript (script);
1478 while (parser.next() )
1479 parseAtom(parser.getAtom());
1482 bool MapEditor::isDefault()
1487 bool MapEditor::hasChanged()
1492 void MapEditor::setChanged()
1496 autosaveTimer->start(settings.value("/mapeditor/autosave/ms/",300000).toInt());
1497 fileChangedTimer->start (3000);
1506 void MapEditor::closeMap()
1508 // Unselect before disabling the toolbar actions
1509 if (!xelection.isEmpty() ) xelection.unselect();
1514 // close(); FIXME needed?
1517 void MapEditor::setFilePath(QString fpath, QString destname)
1519 if (fpath.isEmpty() || fpath=="")
1526 filePath=fpath; // becomes absolute path
1527 fileName=fpath; // gets stripped of path
1528 destPath=destname; // needed for vymlinks and during load to reset fileChangedTime
1530 // If fpath is not an absolute path, complete it
1531 filePath=QDir(fpath).absPath();
1532 fileDir=filePath.left (1+filePath.findRev ("/"));
1534 // Set short name, too. Search from behind:
1535 int i=fileName.findRev("/");
1536 if (i>=0) fileName=fileName.remove (0,i+1);
1538 // Forget the .vym (or .xml) for name of map
1539 mapName=fileName.left(fileName.findRev(".",-1,true) );
1543 void MapEditor::setFilePath(QString fpath)
1545 setFilePath (fpath,fpath);
1548 QString MapEditor::getFilePath()
1553 QString MapEditor::getFileName()
1558 QString MapEditor::getMapName()
1563 QString MapEditor::getDestPath()
1568 ErrorCode MapEditor::load (QString fname, const LoadMode &lmode, const FileType &ftype)
1570 ErrorCode err=success;
1572 parseBaseHandler *handler;
1576 case VymMap: handler=new parseVYMHandler; break;
1577 case FreemindMap : handler=new parseFreemindHandler; break;
1579 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1580 "Unknown FileType in MapEditor::load()");
1584 // Save original zip state, important for inserting complete maps
1585 bool zipped_org=zipped;
1590 model->setMapEditor(this);
1591 // (map state is set later at end of load...)
1594 BranchObj *bo=xelection.getBranch();
1595 if (!bo) return aborted;
1596 if (lmode==ImportAdd)
1597 saveStateChangingPart(
1600 QString("addMapInsert (%1)").arg(fname),
1601 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1603 saveStateChangingPart(
1606 QString("addMapReplace(%1)").arg(fname),
1607 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1611 // Create temporary directory for packing
1613 QString tmpZipDir=makeTmpDir (ok,"vym-pack");
1616 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1617 tr("Couldn't create temporary directory before load\n"));
1621 // Try to unzip file
1622 err=unzipDir (tmpZipDir,fname);
1632 // Look for mapname.xml
1633 xmlfile= fname.left(fname.findRev(".",-1,true));
1634 xmlfile=xmlfile.section( '/', -1 );
1635 QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
1636 if (!mfile.exists() )
1638 // mapname.xml does not exist, well,
1639 // maybe someone renamed the mapname.vym file...
1640 // Try to find any .xml in the toplevel
1641 // directory of the .vym file
1642 QStringList flist=QDir (tmpZipDir).entryList("*.xml");
1643 if (flist.count()==1)
1645 // Only one entry, take this one
1646 xmlfile=tmpZipDir + "/"+flist.first();
1649 for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it )
1650 *it=tmpZipDir + "/" + *it;
1651 // TODO Multiple entries, load all (but only the first one into this ME)
1652 //mainWindow->fileLoadFromTmp (flist);
1653 //returnCode=1; // Silently forget this attempt to load
1654 qWarning ("MainWindow::load (fn) multimap found...");
1657 if (flist.isEmpty() )
1659 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1660 tr("Couldn't find a map (*.xml) in .vym archive.\n"));
1663 } //file doesn't exist
1665 xmlfile=mfile.name();
1668 QFile file( xmlfile);
1670 // I am paranoid: file should exist anyway
1671 // according to check in mainwindow.
1672 if (!file.exists() )
1674 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1675 tr(QString("Couldn't open map %1").arg(file.name())));
1679 bool blockSaveStateOrg=blockSaveState;
1680 blockReposition=true;
1681 blockSaveState=true;
1682 QXmlInputSource source( file);
1683 QXmlSimpleReader reader;
1684 reader.setContentHandler( handler );
1685 reader.setErrorHandler( handler );
1686 handler->setModel ( model);
1689 // We need to set the tmpDir in order to load files with rel. path
1694 tmpdir=fname.left(fname.findRev("/",-1));
1695 handler->setTmpDir (tmpdir);
1696 handler->setInputFile (file.name());
1697 handler->setLoadMode (lmode);
1698 bool ok = reader.parse( source );
1699 blockReposition=false;
1700 blockSaveState=blockSaveStateOrg;
1704 model->reposition(); // FIXME reposition the view instead...
1711 autosaveTimer->stop();
1714 // Reset timestamp to check for later updates of file
1715 fileChangedTime=QFileInfo (destPath).lastModified();
1718 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1719 tr( handler->errorProtocol() ) );
1721 // Still return "success": the map maybe at least
1722 // partially read by the parser
1727 removeDir (QDir(tmpZipDir));
1729 // Restore original zip state
1737 ErrorCode MapEditor::save (const SaveMode &savemode)
1740 QString mapFileName;
1741 QString safeFilePath;
1743 ErrorCode err=success;
1747 mapFileName=mapName+".xml";
1749 // use name given by user, even if he chooses .doc
1750 mapFileName=fileName;
1752 // Look, if we should zip the data:
1755 QMessageBox mb( vymName,
1756 tr("The map %1\ndid not use the compressed "
1757 "vym file format.\nWriting it uncompressed will also write images \n"
1758 "and flags and thus may overwrite files in the "
1759 "given directory\n\nDo you want to write the map").arg(filePath),
1760 QMessageBox::Warning,
1761 QMessageBox::Yes | QMessageBox::Default,
1763 QMessageBox::Cancel | QMessageBox::Escape);
1764 mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
1765 mb.setButtonText( QMessageBox::No, tr("uncompressed") );
1766 mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
1769 case QMessageBox::Yes:
1770 // save compressed (default file format)
1773 case QMessageBox::No:
1774 // save uncompressed
1777 case QMessageBox::Cancel:
1784 // First backup existing file, we
1785 // don't want to add to old zip archives
1789 if ( settings.value ("/mapeditor/writeBackupFile").toBool())
1791 QString backupFileName(destPath + "~");
1792 QFile backupFile(backupFileName);
1793 if (backupFile.exists() && !backupFile.remove())
1795 QMessageBox::warning(0, tr("Save Error"),
1796 tr("%1\ncould not be removed before saving").arg(backupFileName));
1798 else if (!f.rename(backupFileName))
1800 QMessageBox::warning(0, tr("Save Error"),
1801 tr("%1\ncould not be renamed before saving").arg(destPath));
1808 // Create temporary directory for packing
1810 tmpZipDir=makeTmpDir (ok,"vym-zip");
1813 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1814 tr("Couldn't create temporary directory before save\n"));
1818 // cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1819 safeFilePath=filePath;
1820 setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
1823 // Create mapName and fileDir
1824 makeSubDirs (fileDir);
1828 cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1829 cout <<"ME::save saveFilePath="<<safeFilePath.toStdString()<<endl;
1830 cout <<"ME::save destPath="<<destPath.toStdString()<<endl;
1831 cout <<"ME::save mapName="<<mapName.toStdString()<<endl;
1832 cout <<"ME::save mapFileName="<<mapFileName.toStdString()<<endl;
1836 if (savemode==CompleteMap || xelection.isEmpty())
1838 // Save complete map
1839 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),NULL);
1842 autosaveTimer->stop();
1847 if (xelection.type()==Selection::FloatImage)
1850 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),xelection.getBranch());
1851 // TODO take care of multiselections
1854 // FIXME trying to debug save problem
1855 if (saveFile.length()<1000)
1856 QMessageBox::critical (0,"Critical error in MapEditor::save",QString("saveFile is too small, try make a backup NOW\nof your original file\nbefore vym writes to\"%1\":\n%2").arg(mapName).arg(saveFile));
1857 if (!saveStringToDisk(fileDir+mapFileName,saveFile))
1860 QMessageBox::critical (0,"Critical error in MapEditor::save",QString("could not save %1").arg(fileDir+mapFileName));
1866 if (err==success) err=zipDir (tmpZipDir,destPath);
1869 removeDir (QDir(tmpZipDir));
1871 // Restore original filepath outside of tmp zip dir
1872 setFilePath (safeFilePath);
1876 fileChangedTime=QFileInfo (destPath).lastModified();
1881 void MapEditor::print()
1885 printer = new QPrinter;
1886 printer->setColorMode (QPrinter::Color);
1887 printer->setPrinterName (settings.value("/mainwindow/printerName",printer->printerName()).toString());
1888 printer->setOutputFormat((QPrinter::OutputFormat)settings.value("/mainwindow/printerFormat",printer->outputFormat()).toInt());
1889 printer->setOutputFileName(settings.value("/mainwindow/printerFileName",printer->outputFileName()).toString());
1892 QRectF totalBBox=model->getTotalBBox();
1894 // Try to set orientation automagically
1895 // Note: Interpretation of generated postscript is amibiguous, if
1896 // there are problems with landscape mode, see
1897 // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html
1899 if (totalBBox.width()>totalBBox.height())
1900 // recommend landscape
1901 printer->setOrientation (QPrinter::Landscape);
1903 // recommend portrait
1904 printer->setOrientation (QPrinter::Portrait);
1906 if ( printer->setup(this) )
1907 // returns false, if printing is canceled
1909 QPainter pp(printer);
1911 pp.setRenderHint(QPainter::Antialiasing,true);
1913 // Don't print the visualisation of selection
1914 xelection.unselect();
1916 QRectF mapRect=totalBBox;
1917 QGraphicsRectItem *frame=NULL;
1921 // Print frame around map
1922 mapRect.setRect (totalBBox.x()-10, totalBBox.y()-10,
1923 totalBBox.width()+20, totalBBox.height()+20);
1924 frame=mapScene->addRect (mapRect, QPen(Qt::black),QBrush(Qt::NoBrush));
1925 frame->setZValue(0);
1930 double paperAspect = (double)printer->width() / (double)printer->height();
1931 double mapAspect = (double)mapRect.width() / (double)mapRect.height();
1933 if (mapAspect>=paperAspect)
1935 // Fit horizontally to paper width
1936 //pp.setViewport(0,0, printer->width(),(int)(printer->width()/mapAspect) );
1937 viewBottom=(int)(printer->width()/mapAspect);
1940 // Fit vertically to paper height
1941 //pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height());
1942 viewBottom=printer->height();
1947 // Print footer below map
1949 font.setPointSize(10);
1951 QRectF footerBox(0,viewBottom,printer->width(),15);
1952 pp.drawText ( footerBox,Qt::AlignLeft,"VYM - " +fileName);
1953 pp.drawText ( footerBox, Qt::AlignRight, QDate::currentDate().toString(Qt::TextDate));
1957 QRectF (0,0,printer->width(),printer->height()-15),
1958 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height())
1961 // Viewport has paper dimension
1962 if (frame) delete (frame);
1964 // Restore selection
1965 xelection.reselect();
1967 // Save settings in vymrc
1968 settings.writeEntry("/mainwindow/printerName",printer->printerName());
1969 settings.writeEntry("/mainwindow/printerFormat",printer->outputFormat());
1970 settings.writeEntry("/mainwindow/printerFileName",printer->outputFileName());
1974 void MapEditor::setAntiAlias (bool b)
1976 setRenderHint(QPainter::Antialiasing,b);
1979 void MapEditor::setSmoothPixmap(bool b)
1981 setRenderHint(QPainter::SmoothPixmapTransform,b);
1984 QPixmap MapEditor::getPixmap()
1986 QRectF mapRect=model->getTotalBBox();
1987 QPixmap pix((int)mapRect.width()+2,(int)mapRect.height()+1);
1990 pp.setRenderHints(renderHints());
1992 // Don't print the visualisation of selection
1993 xelection.unselect();
1995 mapScene->render ( &pp,
1996 QRectF(0,0,mapRect.width()+1,mapRect.height()+1),
1997 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height() ));
1999 // Restore selection
2000 xelection.reselect();
2005 void MapEditor::setHideTmpMode (HideTmpMode mode)
2008 model->setHideTmp (hidemode);
2009 model->reposition();
2013 HideTmpMode MapEditor::getHideTmpMode()
2018 void MapEditor::setExportMode (bool b)
2020 // should be called before and after exports
2021 // depending on the settings
2022 if (b && settings.value("/export/useHideExport","true")=="true")
2023 setHideTmpMode (HideExport);
2025 setHideTmpMode (HideNone);
2028 void MapEditor::exportASCII(QString fname,bool askName)
2031 ex.setModel (model);
2033 ex.setFile (mapName+".txt");
2039 //ex.addFilter ("TXT (*.txt)");
2040 ex.setDir(lastImageDir);
2041 //ex.setCaption(vymName+ " -" +tr("Export as ASCII")+" "+tr("(still experimental)"));
2046 setExportMode(true);
2048 setExportMode(false);
2052 void MapEditor::exportImage(QString fname, bool askName, QString format)
2056 fname=mapName+".png";
2063 QFileDialog *fd=new QFileDialog (this);
2064 fd->setCaption (tr("Export map as image"));
2065 fd->setDirectory (lastImageDir);
2066 fd->setFileMode(QFileDialog::AnyFile);
2067 fd->setFilters (imageIO.getFilters() );
2070 fl=fd->selectedFiles();
2072 format=imageIO.getType(fd->selectedFilter());
2076 setExportMode (true);
2077 QPixmap pix (getPixmap());
2078 pix.save(fname, format);
2079 setExportMode (false);
2082 void MapEditor::exportOOPresentation(const QString &fn, const QString &cf)
2086 ex.setModel (model);
2087 if (ex.setConfigFile(cf))
2089 setExportMode (true);
2090 ex.exportPresentation();
2091 setExportMode (false);
2095 void MapEditor::exportXHTML (const QString &dir, bool askForName)
2097 ExportXHTMLDialog dia(this);
2098 dia.setFilePath (filePath );
2099 dia.setMapName (mapName );
2101 if (dir!="") dia.setDir (dir);
2107 if (dia.exec()!=QDialog::Accepted)
2111 QDir d (dia.getDir());
2112 // Check, if warnings should be used before overwriting
2113 // the output directory
2114 if (d.exists() && d.count()>0)
2117 warn.showCancelButton (true);
2118 warn.setText(QString(
2119 "The directory %1 is not empty.\n"
2120 "Do you risk to overwrite some of its contents?").arg(d.path() ));
2121 warn.setCaption("Warning: Directory not empty");
2122 warn.setShowAgainName("mainwindow/overwrite-dir-xhtml");
2124 if (warn.exec()!=QDialog::Accepted) ok=false;
2131 exportXML (dia.getDir(),false );
2132 dia.doExport(mapName );
2133 //if (dia.hasChanged()) setChanged();
2137 void MapEditor::exportXML(QString dir, bool askForName)
2141 dir=browseDirectory(this,tr("Export XML to directory"));
2142 if (dir =="" && !reallyWriteDirectory(dir) )
2146 // Hide stuff during export, if settings want this
2147 setExportMode (true);
2149 // Create subdirectories
2152 // write to directory
2153 QString saveFile=saveToDir (dir,mapName+"-",true,model->getTotalBBox().topLeft() ,NULL);
2156 file.setName ( dir + "/"+mapName+".xml");
2157 if ( !file.open( QIODevice::WriteOnly ) )
2159 // This should neverever happen
2160 QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open %1").arg(file.name()));
2164 // Write it finally, and write in UTF8, no matter what
2165 QTextStream ts( &file );
2166 ts.setEncoding (QTextStream::UnicodeUTF8);
2170 // Now write image, too
2171 exportImage (dir+"/images/"+mapName+".png",false,"PNG");
2173 setExportMode (false);
2176 void MapEditor::clear()
2178 //cout << "ME::clear() "<<mapName.toStdString()<<endl;
2180 autosaveTimer->stop();
2181 fileChangedTimer->stop();
2185 void MapEditor::copy()
2187 LinkableMapObj *sel=xelection.single();
2190 if (redosAvail == 0)
2193 QString s=model->getSelectString(sel);
2194 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy selection to clipboard",sel );
2195 curClipboard=curStep;
2198 // Copy also to global clipboard, because we are at last step in history
2199 QString bakMapName(QString("history-%1").arg(curStep));
2200 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2201 copyDir (bakMapDir,clipboardDir );
2203 clipboardEmpty=false;
2208 void MapEditor::redo()
2210 // Can we undo at all?
2211 if (redosAvail<1) return;
2213 bool blockSaveStateOrg=blockSaveState;
2214 blockSaveState=true;
2218 if (undosAvail<stepsTotal) undosAvail++;
2220 if (curStep>stepsTotal) curStep=1;
2221 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2222 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2223 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2224 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2225 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2226 QString version=undoSet.readEntry ("/history/version");
2228 /* TODO Maybe check for version, if we save the history
2229 if (!checkVersion(version))
2230 QMessageBox::warning(0,tr("Warning"),
2231 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2234 // Find out current undo directory
2235 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2239 cout << "ME::redo() begin\n";
2240 cout << " undosAvail="<<undosAvail<<endl;
2241 cout << " redosAvail="<<redosAvail<<endl;
2242 cout << " curStep="<<curStep<<endl;
2243 cout << " ---------------------------"<<endl;
2244 cout << " comment="<<comment.toStdString()<<endl;
2245 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2246 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2247 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2248 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2249 cout << " ---------------------------"<<endl<<endl;
2252 // select object before redo
2253 if (!redoSelection.isEmpty())
2254 select (redoSelection);
2257 parseAtom (redoCommand);
2258 model->reposition();
2260 blockSaveState=blockSaveStateOrg;
2262 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2263 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2264 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2265 undoSet.writeSettings(histPath);
2267 mainWindow->updateHistory (undoSet);
2270 /* TODO remove testing
2271 cout << "ME::redo() end\n";
2272 cout << " undosAvail="<<undosAvail<<endl;
2273 cout << " redosAvail="<<redosAvail<<endl;
2274 cout << " curStep="<<curStep<<endl;
2275 cout << " ---------------------------"<<endl<<endl;
2281 bool MapEditor::isRedoAvailable()
2283 if (undoSet.readNumEntry("/history/redosAvail",0)>0)
2289 void MapEditor::undo()
2291 // Can we undo at all?
2292 if (undosAvail<1) return;
2294 mainWindow->statusMessage (tr("Autosave disabled during undo."));
2296 bool blockSaveStateOrg=blockSaveState;
2297 blockSaveState=true;
2299 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2300 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2301 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2302 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2303 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2304 QString version=undoSet.readEntry ("/history/version");
2306 /* TODO Maybe check for version, if we save the history
2307 if (!checkVersion(version))
2308 QMessageBox::warning(0,tr("Warning"),
2309 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2312 // Find out current undo directory
2313 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2315 // select object before undo
2316 if (!undoSelection.isEmpty())
2317 select (undoSelection);
2321 cout << "ME::undo() begin\n";
2322 cout << " undosAvail="<<undosAvail<<endl;
2323 cout << " redosAvail="<<redosAvail<<endl;
2324 cout << " curStep="<<curStep<<endl;
2325 cout << " ---------------------------"<<endl;
2326 cout << " comment="<<comment.toStdString()<<endl;
2327 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2328 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2329 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2330 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2331 cout << " ---------------------------"<<endl<<endl;
2333 parseAtom (undoCommand);
2334 model->reposition();
2338 if (curStep<1) curStep=stepsTotal;
2342 blockSaveState=blockSaveStateOrg;
2343 /* TODO remove testing
2344 cout << "ME::undo() end\n";
2345 cout << " undosAvail="<<undosAvail<<endl;
2346 cout << " redosAvail="<<redosAvail<<endl;
2347 cout << " curStep="<<curStep<<endl;
2348 cout << " ---------------------------"<<endl<<endl;
2351 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2352 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2353 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2354 undoSet.writeSettings(histPath);
2356 mainWindow->updateHistory (undoSet);
2359 ensureSelectionVisible();
2362 bool MapEditor::isUndoAvailable()
2364 if (undoSet.readNumEntry("/history/undosAvail",0)>0)
2370 void MapEditor::gotoHistoryStep (int i)
2372 // Restore variables
2373 int undosAvail=undoSet.readNumEntry (QString("/history/undosAvail"));
2374 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
2376 if (i<0) i=undosAvail+redosAvail;
2378 // Clicking above current step makes us undo things
2381 for (int j=0; j<undosAvail-i; j++) undo();
2384 // Clicking below current step makes us redo things
2386 for (int j=undosAvail; j<i; j++)
2388 if (debug) cout << "ME::gotoHistoryStep redo "<<j<<"/"<<undosAvail<<" i="<<i<<endl;
2392 // And ignore clicking the current row ;-)
2395 void MapEditor::addMapReplaceInt(const QString &undoSel, const QString &path)
2397 QString pathDir=path.left(path.findRev("/"));
2403 // We need to parse saved XML data
2404 parseVYMHandler handler;
2405 QXmlInputSource source( file);
2406 QXmlSimpleReader reader;
2407 reader.setContentHandler( &handler );
2408 reader.setErrorHandler( &handler );
2409 handler.setModel ( model);
2410 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2411 if (undoSel.isEmpty())
2415 handler.setLoadMode (NewMap);
2419 handler.setLoadMode (ImportReplace);
2421 blockReposition=true;
2422 bool ok = reader.parse( source );
2423 blockReposition=false;
2426 // This should never ever happen
2427 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2428 handler.errorProtocol());
2431 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2434 void MapEditor::addMapInsertInt (const QString &path, int pos)
2436 BranchObj *sel=xelection.getBranch();
2439 QString pathDir=path.left(path.findRev("/"));
2445 // We need to parse saved XML data
2446 parseVYMHandler handler;
2447 QXmlInputSource source( file);
2448 QXmlSimpleReader reader;
2449 reader.setContentHandler( &handler );
2450 reader.setErrorHandler( &handler );
2451 handler.setModel (model);
2452 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2453 handler.setLoadMode (ImportAdd);
2454 blockReposition=true;
2455 bool ok = reader.parse( source );
2456 blockReposition=false;
2459 // This should never ever happen
2460 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2461 handler.errorProtocol());
2463 if (sel->getDepth()>0)
2464 sel->getLastBranch()->linkTo (sel,pos);
2466 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2470 void MapEditor::pasteNoSave(const int &n)
2472 bool old=blockSaveState;
2473 blockSaveState=true;
2474 bool zippedOrg=zipped;
2475 if (redosAvail > 0 || n!=0)
2477 // Use the "historical" buffer
2478 QString bakMapName(QString("history-%1").arg(n));
2479 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2480 load (bakMapDir+"/"+clipboardFile,ImportAdd, VymMap);
2482 // Use the global buffer
2483 load (clipboardDir+"/"+clipboardFile,ImportAdd, VymMap);
2488 void MapEditor::paste()
2490 BranchObj *sel=xelection.getBranch();
2493 saveStateChangingPart(
2496 QString ("paste (%1)").arg(curClipboard),
2497 QString("Paste to %1").arg( getName(sel))
2500 model->reposition();
2504 void MapEditor::cut()
2506 LinkableMapObj *sel=xelection.single();
2507 if ( sel && (xelection.type() == Selection::Branch ||
2508 xelection.type()==Selection::MapCenter ||
2509 xelection.type()==Selection::FloatImage))
2511 /* No savestate! savestate is called in cutNoSave
2512 saveStateChangingPart(
2516 QString("Cut %1").arg(getName(sel ))
2521 model->reposition();
2525 void MapEditor::move(const double &x, const double &y)
2527 LinkableMapObj *sel=xelection.single();
2530 QPointF ap(sel->getAbsPos());
2534 QString ps=qpointfToString(ap);
2535 QString s=xelection.getSelectString();
2538 s, "move "+qpointfToString(to),
2539 QString("Move %1 to %2").arg(getName(sel)).arg(ps));
2541 model->reposition();
2547 void MapEditor::moveRel (const double &x, const double &y)
2549 LinkableMapObj *sel=xelection.single();
2552 QPointF rp(sel->getRelPos());
2556 QString ps=qpointfToString (sel->getRelPos());
2557 QString s=model->getSelectString(sel);
2560 s, "moveRel "+qpointfToString(to),
2561 QString("Move %1 to relative position %2").arg(getName(sel)).arg(ps));
2562 ((OrnamentedObj*)sel)->move2RelPos (x,y);
2563 model->reposition();
2570 void MapEditor::moveBranchUp()
2572 BranchObj* bo=xelection.getBranch();
2576 if (!bo->canMoveBranchUp()) return;
2577 par=(BranchObj*)(bo->getParObj());
2578 BranchObj *obo=par->moveBranchUp (bo); // bo will be the one below selection
2579 saveState (model->getSelectString(bo),"moveBranchDown ()",model->getSelectString(obo),"moveBranchUp ()",QString("Move up %1").arg(getName(bo)));
2580 model->reposition();
2583 ensureSelectionVisible();
2587 void MapEditor::moveBranchDown()
2589 BranchObj* bo=xelection.getBranch();
2593 if (!bo->canMoveBranchDown()) return;
2594 par=(BranchObj*)(bo->getParObj());
2595 BranchObj *obo=par->moveBranchDown(bo); // bo will be the one above selection
2596 saveState(model->getSelectString(bo),"moveBranchUp ()",model->getSelectString(obo),"moveBranchDown ()",QString("Move down %1").arg(getName(bo)));
2597 model->reposition();
2600 ensureSelectionVisible();
2604 void MapEditor::sortChildren()
2606 BranchObj* bo=xelection.getBranch();
2609 if(bo->countBranches()>1)
2611 saveStateChangingPart(bo,bo, "sortChildren ()",QString("Sort children of %1").arg(getName(bo)));
2613 model->reposition();
2614 ensureSelectionVisible();
2619 void MapEditor::linkTo(const QString &dstString)
2621 FloatImageObj *fio=xelection.getFloatImage();
2624 BranchObj *dst=(BranchObj*)(model->findObjBySelect(dstString));
2625 if (dst && (typeid(*dst)==typeid (BranchObj) ||
2626 typeid(*dst)==typeid (MapCenterObj)))
2628 LinkableMapObj *dstPar=dst->getParObj();
2629 QString parString=model->getSelectString(dstPar);
2630 QString fioPreSelectString=model->getSelectString(fio);
2631 QString fioPreParentSelectString=model->getSelectString (fio->getParObj());
2632 ((BranchObj*)(dst))->addFloatImage (fio);
2633 xelection.unselect();
2634 ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio);
2635 fio=((BranchObj*)(dst))->getLastFloatImage();
2638 xelection.select(fio);
2640 model->getSelectString(fio),
2641 QString("linkTo (\"%1\")").arg(fioPreParentSelectString),
2643 QString ("linkTo (\"%1\")").arg(dstString),
2644 QString ("Link floatimage to %1").arg(getName(dst)));
2649 QString MapEditor::getHeading(bool &ok, QPoint &p)
2651 BranchObj *bo=xelection.getBranch();
2655 p=mapFromScene(bo->getAbsPos());
2656 return bo->getHeading();
2662 void MapEditor::setHeading(const QString &s)
2664 BranchObj *sel=xelection.getBranch();
2669 "setHeading (\""+sel->getHeading()+"\")",
2671 "setHeading (\""+s+"\")",
2672 QString("Set heading of %1 to \"%2\"").arg(getName(sel)).arg(s) );
2673 sel->setHeading(s );
2674 model->reposition();
2676 ensureSelectionVisible();
2680 void MapEditor::setHeadingInt(const QString &s)
2682 BranchObj *bo=xelection.getBranch();
2686 model->reposition();
2688 ensureSelectionVisible();
2692 void MapEditor::setVymLinkInt (const QString &s)
2694 // Internal function, no saveState needed
2695 BranchObj *bo=xelection.getBranch();
2699 model->reposition();
2702 ensureSelectionVisible();
2706 BranchObj* MapEditor::addMapCenter ()
2708 MapCenterObj *mco= model->addMapCenter(contextMenuPos);
2709 xelection.select (mco);
2711 ensureSelectionVisible();
2716 QString ("addMapCenter (%1,%2)").arg (contextMenuPos.x()).arg(contextMenuPos.y()),
2717 QString ("Adding MapCenter to (%1,%2").arg (contextMenuPos.x()).arg(contextMenuPos.y())
2722 BranchObj* MapEditor::addNewBranchInt(int num)
2724 // Depending on pos:
2725 // -3 insert in childs of parent above selection
2726 // -2 add branch to selection
2727 // -1 insert in childs of parent below selection
2728 // 0..n insert in childs of parent at pos
2729 BranchObj *newbo=NULL;
2730 BranchObj *bo=xelection.getBranch();
2735 // save scroll state. If scrolled, automatically select
2736 // new branch in order to tmp unscroll parent...
2737 newbo=bo->addBranch();
2742 bo=(BranchObj*)bo->getParObj();
2743 if (bo) newbo=bo->insertBranch(num);
2747 bo=(BranchObj*)bo->getParObj();
2748 if (bo) newbo=bo->insertBranch(num);
2750 if (!newbo) return NULL;
2755 BranchObj* MapEditor::addNewBranch(int pos)
2757 // Different meaning than num in addNewBranchInt!
2761 BranchObj *bo = xelection.getBranch();
2762 BranchObj *newbo=NULL;
2766 setCursor (Qt::ArrowCursor);
2768 newbo=addNewBranchInt (pos-2);
2776 QString ("addBranch (%1)").arg(pos),
2777 QString ("Add new branch to %1").arg(getName(bo)));
2779 model->reposition();
2781 latestSelection=model->getSelectString(newbo);
2782 // In Network mode, the client needs to know where the new branch is,
2783 // so we have to pass on this information via saveState.
2784 // TODO: Get rid of this positioning workaround
2785 QString ps=qpointfToString (newbo->getAbsPos());
2786 sendData ("selectLatestAdded ()");
2787 sendData (QString("move %1").arg(ps));
2795 BranchObj* MapEditor::addNewBranchBefore()
2797 BranchObj *newbo=NULL;
2798 BranchObj *bo = xelection.getBranch();
2799 if (bo && xelection.type()==Selection::Branch)
2800 // We accept no MapCenterObj here, so we _have_ a parent
2802 QPointF p=bo->getRelPos();
2805 BranchObj *parbo=(BranchObj*)(bo->getParObj());
2807 // add below selection
2808 newbo=parbo->insertBranch(bo->getNum()+1);
2811 newbo->move2RelPos (p);
2813 // Move selection to new branch
2814 bo->linkTo (newbo,-1);
2816 saveState (newbo, "deleteKeepChilds ()", newbo, "addBranchBefore ()",
2817 QString ("Add branch before %1").arg(getName(bo)));
2819 model->reposition();
2823 latestSelection=xelection.getSelectString();
2827 void MapEditor::deleteSelection()
2829 BranchObj *bo = xelection.getBranch();
2830 if (bo && xelection.type()==Selection::MapCenter)
2832 // BranchObj* par=(BranchObj*)(bo->getParObj());
2833 xelection.unselect();
2834 /* FIXME Note: does saveStateRemovingPart work for MCO? (No parent!)
2835 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2837 bo=model->removeMapCenter ((MapCenterObj*)bo);
2840 xelection.select (bo);
2841 ensureSelectionVisible();
2844 model->reposition();
2847 if (bo && xelection.type()==Selection::Branch)
2849 BranchObj* par=(BranchObj*)bo->getParObj();
2850 xelection.unselect();
2851 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2852 par->removeBranch(bo);
2853 xelection.select (par);
2854 ensureSelectionVisible();
2855 model->reposition();
2856 // xelection.update();
2860 FloatImageObj *fio=xelection.getFloatImage();
2863 BranchObj* par=(BranchObj*)fio->getParObj();
2864 saveStateChangingPart(
2868 QString("Delete %1").arg(getName(fio))
2870 xelection.unselect();
2871 par->removeFloatImage(fio);
2872 xelection.select (par);
2873 model->reposition();
2875 ensureSelectionVisible();
2880 LinkableMapObj* MapEditor::getSelection()
2882 return xelection.single();
2885 BranchObj* MapEditor::getSelectedBranch()
2887 return xelection.getBranch();
2890 FloatImageObj* MapEditor::getSelectedFloatImage()
2892 return xelection.getFloatImage();
2895 void MapEditor::unselect()
2897 xelection.unselect();
2900 void MapEditor::reselect()
2902 xelection.reselect();
2905 bool MapEditor::select (const QString &s)
2907 if (xelection.select(s))
2910 ensureSelectionVisible();
2917 bool MapEditor::select (LinkableMapObj *lmo)
2919 if (xelection.select(lmo))
2922 ensureSelectionVisible();
2929 QString MapEditor::getSelectString()
2931 return xelection.getSelectString();
2934 void MapEditor::selectInt (LinkableMapObj *lmo)
2936 if (lmo && xelection.single()!= lmo && isSelectBlocked()==false )
2938 xelection.select(lmo);
2944 void MapEditor::selectNextBranchInt()
2946 // Increase number of branch
2947 LinkableMapObj *sel=xelection.single();
2950 QString s=xelection.getSelectString();
2956 part=s.section(",",-1);
2958 num=part.right(part.length() - 3);
2960 s=s.left (s.length() -num.length());
2963 num=QString ("%1").arg(num.toUInt()+1);
2967 // Try to select this one
2968 if (select (s)) return;
2970 // We have no direct successor,
2971 // try to increase the parental number in order to
2972 // find a successor with same depth
2974 int d=xelection.single()->getDepth();
2979 while (!found && d>0)
2981 s=s.section (",",0,d-1);
2982 // replace substring of current depth in s with "1"
2983 part=s.section(",",-1);
2985 num=part.right(part.length() - 3);
2989 // increase number of parent
2990 num=QString ("%1").arg(num.toUInt()+1);
2991 s=s.section (",",0,d-2) + ","+ typ+num;
2994 // Special case, look at orientation
2995 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
2996 num=QString ("%1").arg(num.toUInt()+1);
2998 num=QString ("%1").arg(num.toUInt()-1);
3003 // pad to oldDepth, select the first branch for each depth
3004 for (i=d;i<oldDepth;i++)
3009 if ( xelection.getBranch()->countBranches()>0)
3017 // try to select the freshly built string
3025 void MapEditor::selectPrevBranchInt()
3027 // Decrease number of branch
3028 BranchObj *bo=xelection.getBranch();
3031 QString s=xelection.getSelectString();
3037 part=s.section(",",-1);
3039 num=part.right(part.length() - 3);
3041 s=s.left (s.length() -num.length());
3043 int n=num.toInt()-1;
3046 num=QString ("%1").arg(n);
3049 // Try to select this one
3050 if (n>=0 && select (s)) return;
3052 // We have no direct precessor,
3053 // try to decrease the parental number in order to
3054 // find a precessor with same depth
3056 int d=xelection.single()->getDepth();
3061 while (!found && d>0)
3063 s=s.section (",",0,d-1);
3064 // replace substring of current depth in s with "1"
3065 part=s.section(",",-1);
3067 num=part.right(part.length() - 3);
3071 // decrease number of parent
3072 num=QString ("%1").arg(num.toInt()-1);
3073 s=s.section (",",0,d-2) + ","+ typ+num;
3076 // Special case, look at orientation
3077 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
3078 num=QString ("%1").arg(num.toInt()-1);
3080 num=QString ("%1").arg(num.toInt()+1);
3085 // pad to oldDepth, select the last branch for each depth
3086 for (i=d;i<oldDepth;i++)
3090 if ( xelection.getBranch()->countBranches()>0)
3091 s+=",bo:"+ QString ("%1").arg( xelection.getBranch()->countBranches()-1 );
3098 // try to select the freshly built string
3106 void MapEditor::selectUpperBranch()
3108 if (isSelectBlocked() ) return;
3110 BranchObj *bo=xelection.getBranch();
3111 if (bo && xelection.type()==Selection::Branch)
3113 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3114 selectPrevBranchInt();
3116 if (bo->getDepth()==1)
3117 selectNextBranchInt();
3119 selectPrevBranchInt();
3123 void MapEditor::selectLowerBranch()
3125 if (isSelectBlocked() ) return;
3127 BranchObj *bo=xelection.getBranch();
3128 if (bo && xelection.type()==Selection::Branch)
3130 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3131 selectNextBranchInt();
3133 if (bo->getDepth()==1)
3134 selectPrevBranchInt();
3136 selectNextBranchInt();
3141 void MapEditor::selectLeftBranch()
3143 if (isSelectBlocked() ) return;
3147 LinkableMapObj *sel=xelection.single();
3150 if (xelection.type()== Selection::MapCenter)
3152 par=xelection.getBranch();
3153 bo=par->getLastSelectedBranch();
3156 // Workaround for reselecting on left and right side
3157 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3158 bo=par->getLastBranch();
3161 bo=par->getLastBranch();
3162 xelection.select(bo);
3164 ensureSelectionVisible();
3170 par=(BranchObj*)(sel->getParObj());
3171 if (sel->getOrientation()==LinkableMapObj::RightOfCenter)
3173 if (xelection.type() == Selection::Branch ||
3174 xelection.type() == Selection::FloatImage)
3176 xelection.select(par);
3178 ensureSelectionVisible();
3183 if (xelection.type() == Selection::Branch )
3185 bo=xelection.getBranch()->getLastSelectedBranch();
3188 xelection.select(bo);
3190 ensureSelectionVisible();
3199 void MapEditor::selectRightBranch()
3201 if (isSelectBlocked() ) return;
3205 LinkableMapObj *sel=xelection.single();
3208 if (xelection.type()==Selection::MapCenter)
3210 par=xelection.getBranch();
3211 bo=par->getLastSelectedBranch();
3214 // Workaround for reselecting on left and right side
3215 if (bo->getOrientation()==LinkableMapObj::LeftOfCenter)
3216 bo=par->getFirstBranch();
3219 xelection.select(bo);
3221 ensureSelectionVisible();
3227 par=(BranchObj*)(xelection.single()->getParObj());
3228 if (xelection.single()->getOrientation()==LinkableMapObj::LeftOfCenter)
3230 if (xelection.type() == Selection::Branch ||
3231 xelection.type() == Selection::FloatImage)
3233 xelection.select(par);
3235 ensureSelectionVisible();
3240 if (xelection.type() == Selection::Branch)
3242 bo=xelection.getBranch()->getLastSelectedBranch();
3245 xelection.select(bo);
3247 ensureSelectionVisible();
3256 void MapEditor::selectFirstBranch()
3258 BranchObj *bo1=xelection.getBranch();
3263 par=(BranchObj*)(bo1->getParObj());
3265 bo2=par->getFirstBranch();
3267 xelection.select(bo2);
3269 ensureSelectionVisible();
3275 void MapEditor::selectLastBranch()
3277 BranchObj *bo1=xelection.getBranch();
3282 par=(BranchObj*)(bo1->getParObj());
3284 bo2=par->getLastBranch();
3287 xelection.select(bo2);
3289 ensureSelectionVisible();
3295 void MapEditor::selectMapBackgroundImage ()
3297 Q3FileDialog *fd=new Q3FileDialog( this);
3298 fd->setMode (Q3FileDialog::ExistingFile);
3299 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
3300 ImagePreview *p =new ImagePreview (fd);
3301 fd->setContentsPreviewEnabled( TRUE );
3302 fd->setContentsPreview( p, p );
3303 fd->setPreviewMode( Q3FileDialog::Contents );
3304 fd->setCaption(vymName+" - " +tr("Load background image"));
3305 fd->setDir (lastImageDir);
3308 if ( fd->exec() == QDialog::Accepted )
3310 // TODO selectMapBackgroundImg in QT4 use: lastImageDir=fd->directory();
3311 lastImageDir=QDir (fd->dirPath());
3312 setMapBackgroundImage (fd->selectedFile());
3316 void MapEditor::setMapBackgroundImage (const QString &fn) //FIXME missing savestate
3318 QColor oldcol=mapScene->backgroundBrush().color();
3322 QString ("setMapBackgroundImage (%1)").arg(oldcol.name()),
3324 QString ("setMapBackgroundImage (%1)").arg(col.name()),
3325 QString("Set background color of map to %1").arg(col.name()));
3328 brush.setTextureImage (QPixmap (fn));
3329 mapScene->setBackgroundBrush(brush);
3332 void MapEditor::selectMapBackgroundColor()
3334 QColor col = QColorDialog::getColor( mapScene->backgroundBrush().color(), this );
3335 if ( !col.isValid() ) return;
3336 setMapBackgroundColor( col );
3340 void MapEditor::setMapBackgroundColor(QColor col)
3342 QColor oldcol=mapScene->backgroundBrush().color();
3344 QString ("setMapBackgroundColor (\"%1\")").arg(oldcol.name()),
3345 QString ("setMapBackgroundColor (\"%1\")").arg(col.name()),
3346 QString("Set background color of map to %1").arg(col.name()));
3347 mapScene->setBackgroundBrush(col);
3350 QColor MapEditor::getMapBackgroundColor()
3352 return mapScene->backgroundBrush().color();
3355 QColor MapEditor::getCurrentHeadingColor()
3357 BranchObj *bo=xelection.getBranch();
3358 if (bo) return bo->getColor();
3360 QMessageBox::warning(0,tr("Warning"),tr("Can't get color of heading,\nthere's no branch selected"));
3364 void MapEditor::colorBranch (QColor c)
3366 BranchObj *bo=xelection.getBranch();
3371 QString ("colorBranch (\"%1\")").arg(bo->getColor().name()),
3373 QString ("colorBranch (\"%1\")").arg(c.name()),
3374 QString("Set color of %1 to %2").arg(getName(bo)).arg(c.name())
3376 bo->setColor(c); // color branch
3380 void MapEditor::colorSubtree (QColor c)
3382 BranchObj *bo=xelection.getBranch();
3385 saveStateChangingPart(
3388 QString ("colorSubtree (\"%1\")").arg(c.name()),
3389 QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(c.name())
3391 bo->setColorSubtree (c); // color links, color childs
3396 void MapEditor::toggleStandardFlag(QString f)
3398 BranchObj *bo=xelection.getBranch();
3402 if (bo->isSetStandardFlag(f))
3414 QString("%1 (\"%2\")").arg(u).arg(f),
3416 QString("%1 (\"%2\")").arg(r).arg(f),
3417 QString("Toggling standard flag \"%1\" of %2").arg(f).arg(getName(bo)));
3418 bo->toggleStandardFlag (f,mainWindow->useFlagGroups());
3424 BranchObj* MapEditor::findText (QString s, bool cs)
3426 QTextDocument::FindFlags flags=0;
3427 if (cs) flags=QTextDocument::FindCaseSensitively;
3430 { // Nothing found or new find process
3432 // nothing found, start again
3434 itFind=model->first();
3436 bool searching=true;
3437 bool foundNote=false;
3438 while (searching && !EOFind)
3442 // Searching in Note
3443 if (itFind->getNote().contains(s,cs))
3445 if (xelection.single()!=itFind)
3447 xelection.select(itFind);
3448 ensureSelectionVisible();
3450 if (textEditor->findText(s,flags))
3456 // Searching in Heading
3457 if (searching && itFind->getHeading().contains (s,cs) )
3459 xelection.select(itFind);
3460 ensureSelectionVisible();
3466 itFind=model->next(itFind);
3467 if (!itFind) EOFind=true;
3469 //cout <<"still searching... "<<qPrintable( itFind->getHeading())<<endl;
3472 return xelection.getBranch();
3477 void MapEditor::findReset()
3478 { // Necessary if text to find changes during a find process
3482 void MapEditor::setURL(const QString &url)
3484 BranchObj *bo=xelection.getBranch();
3487 QString oldurl=bo->getURL();
3491 QString ("setURL (\"%1\")").arg(oldurl),
3493 QString ("setURL (\"%1\")").arg(url),
3494 QString ("set URL of %1 to %2").arg(getName(bo)).arg(url)
3497 model->reposition();
3499 ensureSelectionVisible();
3503 void MapEditor::editURL()
3505 BranchObj *bo=xelection.getBranch();
3509 QString text = QInputDialog::getText(
3510 "VYM", tr("Enter URL:"), QLineEdit::Normal,
3511 bo->getURL(), &ok, this );
3513 // user entered something and pressed OK
3518 void MapEditor::editLocalURL()
3520 BranchObj *bo=xelection.getBranch();
3523 QStringList filters;
3524 filters <<"All files (*)";
3525 filters << tr("Text","Filedialog") + " (*.txt)";
3526 filters << tr("Spreadsheet","Filedialog") + " (*.odp,*.sxc)";
3527 filters << tr("Textdocument","Filedialog") +" (*.odw,*.sxw)";
3528 filters << tr("Images","Filedialog") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)";
3529 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Set URL to a local file"));
3530 fd->setFilters (filters);
3531 fd->setCaption(vymName+" - " +tr("Set URL to a local file"));
3532 fd->setDirectory (lastFileDir);
3533 if (! bo->getVymLink().isEmpty() )
3534 fd->selectFile( bo->getURL() );
3537 if ( fd->exec() == QDialog::Accepted )
3539 lastFileDir=QDir (fd->directory().path());
3540 setURL (fd->selectedFile() );
3545 QString MapEditor::getURL()
3547 BranchObj *bo=xelection.getBranch();
3549 return bo->getURL();
3554 QStringList MapEditor::getURLs()
3557 BranchObj *bo=xelection.getBranch();
3563 if (!bo->getURL().isEmpty()) urls.append( bo->getURL());
3571 void MapEditor::editHeading2URL()
3573 BranchObj *bo=xelection.getBranch();
3575 setURL (bo->getHeading());
3578 void MapEditor::editBugzilla2URL()
3580 BranchObj *bo=xelection.getBranch();
3583 QString url= "https://bugzilla.novell.com/show_bug.cgi?id="+bo->getHeading();
3588 void MapEditor::editFATE2URL()
3590 BranchObj *bo=xelection.getBranch();
3593 QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading();
3596 "setURL (\""+bo->getURL()+"\")",
3598 "setURL (\""+url+"\")",
3599 QString("Use heading of %1 as link to FATE").arg(getName(bo))
3606 void MapEditor::editVymLink()
3608 BranchObj *bo=xelection.getBranch();
3611 QStringList filters;
3612 filters <<"VYM map (*.vym)";
3613 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Link to another map"));
3614 fd->setFilters (filters);
3615 fd->setCaption(vymName+" - " +tr("Link to another map"));
3616 fd->setDirectory (lastFileDir);
3617 if (! bo->getVymLink().isEmpty() )
3618 fd->selectFile( bo->getVymLink() );
3622 if ( fd->exec() == QDialog::Accepted )
3624 lastFileDir=QDir (fd->directory().path());
3627 "setVymLink (\""+bo->getVymLink()+"\")",
3629 "setVymLink (\""+fd->selectedFile()+"\")",
3630 QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())
3632 setVymLinkInt (fd->selectedFile() );
3637 void MapEditor::deleteVymLink()
3639 BranchObj *bo=xelection.getBranch();
3644 "setVymLink (\""+bo->getVymLink()+"\")",
3646 "setVymLink (\"\")",
3647 QString("Unset vymlink of %1").arg(getName(bo))
3649 bo->setVymLink ("" );
3651 model->reposition();
3656 void MapEditor::setHideExport(bool b)
3658 BranchObj *bo=xelection.getBranch();
3661 bo->setHideInExport (b);
3662 QString u= b ? "false" : "true";
3663 QString r=!b ? "false" : "true";
3667 QString ("setHideExport (%1)").arg(u),
3669 QString ("setHideExport (%1)").arg(r),
3670 QString ("Set HideExport flag of %1 to %2").arg(getName(bo)).arg (r)
3673 model->reposition();
3679 void MapEditor::toggleHideExport()
3681 BranchObj *bo=xelection.getBranch();
3683 setHideExport ( !bo->hideInExport() );
3686 QString MapEditor::getVymLink()
3688 BranchObj *bo=xelection.getBranch();
3690 return bo->getVymLink();
3696 QStringList MapEditor::getVymLinks()
3699 BranchObj *bo=xelection.getBranch();
3705 if (!bo->getVymLink().isEmpty()) links.append( bo->getVymLink());
3713 void MapEditor::deleteKeepChilds()
3715 BranchObj *bo=xelection.getBranch();
3719 par=(BranchObj*)(bo->getParObj());
3721 // Don't use this on mapcenter
3724 // Check if we have childs at all to keep
3725 if (bo->countBranches()==0)
3731 QPointF p=bo->getRelPos();
3732 saveStateChangingPart(
3735 "deleteKeepChilds ()",
3736 QString("Remove %1 and keep its childs").arg(getName(bo))
3739 QString sel=model->getSelectString(bo);
3741 par->removeBranchHere(bo);
3742 model->reposition();
3744 xelection.getBranch()->move2RelPos (p);
3745 model->reposition();
3749 void MapEditor::deleteChilds()
3751 BranchObj *bo=xelection.getBranch();
3754 saveStateChangingPart(
3758 QString( "Remove childs of branch %1").arg(getName(bo))
3761 model->reposition();
3765 void MapEditor::editMapInfo()
3767 ExtraInfoDialog dia;
3768 dia.setMapName (getFileName() );
3769 dia.setAuthor (model->getAuthor() );
3770 dia.setComment(model->getComment() );
3774 stats+=tr("%1 items on map\n","Info about map").arg (mapScene->items().size(),6);
3784 if (!bo->getNote().isEmpty() ) n++;
3785 f+= bo->countFloatImages();
3787 xl+=bo->countXLinks();
3790 stats+=QString ("%1 branches\n").arg (b-1,6);
3791 stats+=QString ("%1 xLinks \n").arg (xl,6);
3792 stats+=QString ("%1 notes\n").arg (n,6);
3793 stats+=QString ("%1 images\n").arg (f,6);
3794 dia.setStats (stats);
3796 // Finally show dialog
3797 if (dia.exec() == QDialog::Accepted)
3799 setMapAuthor (dia.getAuthor() );
3800 setMapComment (dia.getComment() );
3804 void MapEditor::ensureSelectionVisible()
3806 LinkableMapObj *lmo=xelection.single();
3807 if (lmo) ensureVisible (lmo->getBBox() );
3811 void MapEditor::updateSelection()
3813 // Tell selection to update geometries
3817 void MapEditor::updateActions()
3819 // Tell mainwindow to update states of actions
3820 mainWindow->updateActions();
3821 // TODO maybe don't update if blockReposition is set
3824 void MapEditor::updateNoteFlag()
3827 BranchObj *bo=xelection.getBranch();
3830 bo->updateNoteFlag();
3831 mainWindow->updateActions();
3835 void MapEditor::setMapAuthor (const QString &s)
3838 QString ("setMapAuthor (\"%1\")").arg(model->getAuthor()),
3839 QString ("setMapAuthor (\"%1\")").arg(s),
3840 QString ("Set author of map to \"%1\"").arg(s)
3842 model->setAuthor (s);
3845 void MapEditor::setMapComment (const QString &s)
3848 QString ("setMapComment (\"%1\")").arg(model->getComment()),
3849 QString ("setMapComment (\"%1\")").arg(s),
3850 QString ("Set comment of map")
3852 model->setComment (s);
3855 void MapEditor::setMapLinkStyle (const QString & s)
3858 if (linkstyle==LinkableMapObj::Line)
3860 else if (linkstyle==LinkableMapObj::Parabel)
3861 snow="StyleParabel";
3862 else if (linkstyle==LinkableMapObj::PolyLine)
3863 snow="StylePolyLine";
3864 else if (linkstyle==LinkableMapObj::PolyParabel)
3865 snow="StyleParabel";
3868 QString("setMapLinkStyle (\"%1\")").arg(s),
3869 QString("setMapLinkStyle (\"%1\")").arg(snow),
3870 QString("Set map link style (\"%1\")").arg(s)
3874 linkstyle=LinkableMapObj::Line;
3875 else if (s=="StyleParabel")
3876 linkstyle=LinkableMapObj::Parabel;
3877 else if (s=="StylePolyLine")
3878 linkstyle=LinkableMapObj::PolyLine;
3880 linkstyle=LinkableMapObj::PolyParabel;
3887 bo->setLinkStyle(bo->getDefLinkStyle());
3890 model->reposition();
3893 LinkableMapObj::Style MapEditor::getMapLinkStyle ()
3898 void MapEditor::setMapDefLinkColor(QColor c)
3911 void MapEditor::setMapLinkColorHintInt()
3913 // called from setMapLinkColorHint(lch) or at end of parse
3923 void MapEditor::setMapLinkColorHint(LinkableMapObj::ColorHint lch)
3926 setMapLinkColorHintInt();
3929 void MapEditor::toggleMapLinkColorHint()
3931 if (linkcolorhint==LinkableMapObj::HeadingColor)
3932 linkcolorhint=LinkableMapObj::DefaultColor;
3934 linkcolorhint=LinkableMapObj::HeadingColor;
3944 LinkableMapObj::ColorHint MapEditor::getMapLinkColorHint()
3946 return linkcolorhint;
3949 QColor MapEditor::getMapDefLinkColor()
3951 return defLinkColor;
3954 void MapEditor::setMapDefXLinkColor(QColor col)
3959 QColor MapEditor::getMapDefXLinkColor()
3961 return defXLinkColor;
3964 void MapEditor::setMapDefXLinkWidth (int w)
3969 int MapEditor::getMapDefXLinkWidth()
3971 return defXLinkWidth;
3974 void MapEditor::selectMapLinkColor()
3976 QColor col = QColorDialog::getColor( defLinkColor, this );
3977 if ( !col.isValid() ) return;
3979 QString("setMapDefLinkColor (\"%1\")").arg(getMapDefLinkColor().name()),
3980 QString("setMapDefLinkColor (\"%1\")").arg(col.name()),
3981 QString("Set map link color to %1").arg(col.name())
3983 setMapDefLinkColor( col );
3986 void MapEditor::selectMapSelectionColor()
3988 QColor col = QColorDialog::getColor( defLinkColor, this );
3989 setSelectionColor (col);
3992 void MapEditor::setSelectionColorInt (QColor col)
3994 if ( !col.isValid() ) return;
3995 xelection.setColor (col);
3998 void MapEditor::setSelectionColor(QColor col)
4000 if ( !col.isValid() ) return;
4002 QString("setSelectionColor (%1)").arg(xelection.getColor().name()),
4003 QString("setSelectionColor (%1)").arg(col.name()),
4004 QString("Set color of selection box to %1").arg(col.name())
4006 setSelectionColorInt (col);
4009 QColor MapEditor::getSelectionColor()
4011 return xelection.getColor();
4014 bool MapEditor::scrollBranch(BranchObj *bo)
4018 if (bo->isScrolled()) return false;
4019 if (bo->countBranches()==0) return false;
4020 if (bo->getDepth()==0) return false;
4026 QString ("%1 ()").arg(u),
4028 QString ("%1 ()").arg(r),
4029 QString ("%1 %2").arg(r).arg(getName(bo))
4039 bool MapEditor::unscrollBranch(BranchObj *bo)
4043 if (!bo->isScrolled()) return false;
4044 if (bo->countBranches()==0) return false;
4045 if (bo->getDepth()==0) return false;
4051 QString ("%1 ()").arg(u),
4053 QString ("%1 ()").arg(r),
4054 QString ("%1 %2").arg(r).arg(getName(bo))
4064 void MapEditor::toggleScroll()
4066 BranchObj *bo=xelection.getBranch();
4067 if (xelection.type()==Selection::Branch )
4069 if (bo->isScrolled())
4070 unscrollBranch (bo);
4076 void MapEditor::unscrollChilds()
4078 BranchObj *bo=xelection.getBranch();
4084 if (bo->isScrolled()) unscrollBranch (bo);
4090 FloatImageObj* MapEditor::loadFloatImageInt (QString fn)
4092 BranchObj *bo=xelection.getBranch();
4096 bo->addFloatImage();
4097 fio=bo->getLastFloatImage();
4099 model->reposition();
4106 void MapEditor::loadFloatImage ()
4108 BranchObj *bo=xelection.getBranch();
4112 Q3FileDialog *fd=new Q3FileDialog( this);
4113 fd->setMode (Q3FileDialog::ExistingFiles);
4114 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
4115 ImagePreview *p =new ImagePreview (fd);
4116 fd->setContentsPreviewEnabled( TRUE );
4117 fd->setContentsPreview( p, p );
4118 fd->setPreviewMode( Q3FileDialog::Contents );
4119 fd->setCaption(vymName+" - " +tr("Load image"));
4120 fd->setDir (lastImageDir);
4123 if ( fd->exec() == QDialog::Accepted )
4125 // TODO loadFIO in QT4 use: lastImageDir=fd->directory();
4126 lastImageDir=QDir (fd->dirPath());
4129 for (int j=0; j<fd->selectedFiles().count(); j++)
4131 s=fd->selectedFiles().at(j);
4132 fio=loadFloatImageInt (s);
4135 (LinkableMapObj*)fio,
4138 QString ("loadImage (%1)").arg(s ),
4139 QString("Add image %1 to %2").arg(s).arg(getName(bo))
4142 // TODO loadFIO error handling
4143 qWarning ("Failed to load "+s);
4151 void MapEditor::saveFloatImageInt (FloatImageObj *fio, const QString &type, const QString &fn)
4153 fio->save (fn,type);
4156 void MapEditor::saveFloatImage ()
4158 FloatImageObj *fio=xelection.getFloatImage();
4161 QFileDialog *fd=new QFileDialog( this);
4162 fd->setFilters (imageIO.getFilters());
4163 fd->setCaption(vymName+" - " +tr("Save image"));
4164 fd->setFileMode( QFileDialog::AnyFile );
4165 fd->setDirectory (lastImageDir);
4166 // fd->setSelection (fio->getOriginalFilename());
4170 if ( fd->exec() == QDialog::Accepted && fd->selectedFiles().count()==1)
4172 fn=fd->selectedFiles().at(0);
4173 if (QFile (fn).exists() )
4175 QMessageBox mb( vymName,
4176 tr("The file %1 exists already.\n"
4177 "Do you want to overwrite it?").arg(fn),
4178 QMessageBox::Warning,
4179 QMessageBox::Yes | QMessageBox::Default,
4180 QMessageBox::Cancel | QMessageBox::Escape,
4181 QMessageBox::NoButton );
4183 mb.setButtonText( QMessageBox::Yes, tr("Overwrite") );
4184 mb.setButtonText( QMessageBox::No, tr("Cancel"));
4187 case QMessageBox::Yes:
4190 case QMessageBox::Cancel:
4197 saveFloatImageInt (fio,fd->selectedFilter(),fn );
4203 void MapEditor::setFrameType(const FrameObj::FrameType &t)
4205 BranchObj *bo=xelection.getBranch();
4208 QString s=bo->getFrameTypeName();
4209 bo->setFrameType (t);
4210 saveState (bo, QString("setFrameType (\"%1\")").arg(s),
4211 bo, QString ("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),QString ("set type of frame to %1").arg(s));
4212 model->reposition();
4217 void MapEditor::setFrameType(const QString &s)
4219 BranchObj *bo=xelection.getBranch();
4222 saveState (bo, QString("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),
4223 bo, QString ("setFrameType (\"%1\")").arg(s),QString ("set type of frame to %1").arg(s));
4224 bo->setFrameType (s);
4225 model->reposition();
4230 void MapEditor::setFramePenColor(const QColor &c)
4232 BranchObj *bo=xelection.getBranch();
4235 saveState (bo, QString("setFramePenColor (\"%1\")").arg(bo->getFramePenColor().name() ),
4236 bo, QString ("setFramePenColor (\"%1\")").arg(c.name() ),QString ("set pen color of frame to %1").arg(c.name() ));
4237 bo->setFramePenColor (c);
4241 void MapEditor::setFrameBrushColor(const QColor &c)
4243 BranchObj *bo=xelection.getBranch();
4246 saveState (bo, QString("setFrameBrushColor (\"%1\")").arg(bo->getFrameBrushColor().name() ),
4247 bo, QString ("setFrameBrushColor (\"%1\")").arg(c.name() ),QString ("set brush color of frame to %1").arg(c.name() ));
4248 bo->setFrameBrushColor (c);
4252 void MapEditor::setFramePadding (const int &i)
4254 BranchObj *bo=xelection.getBranch();
4257 saveState (bo, QString("setFramePadding (\"%1\")").arg(bo->getFramePadding() ),
4258 bo, QString ("setFramePadding (\"%1\")").arg(i),QString ("set brush color of frame to %1").arg(i));
4259 bo->setFramePadding (i);
4260 model->reposition();
4265 void MapEditor::setFrameBorderWidth(const int &i)
4267 BranchObj *bo=xelection.getBranch();
4270 saveState (bo, QString("setFrameBorderWidth (\"%1\")").arg(bo->getFrameBorderWidth() ),
4271 bo, QString ("setFrameBorderWidth (\"%1\")").arg(i),QString ("set border width of frame to %1").arg(i));
4272 bo->setFrameBorderWidth (i);
4273 model->reposition();
4278 void MapEditor::setIncludeImagesVer(bool b)
4280 BranchObj *bo=xelection.getBranch();
4283 QString u= b ? "false" : "true";
4284 QString r=!b ? "false" : "true";
4288 QString("setIncludeImagesVertically (%1)").arg(u),
4290 QString("setIncludeImagesVertically (%1)").arg(r),
4291 QString("Include images vertically in %1").arg(getName(bo))
4293 bo->setIncludeImagesVer(b);
4294 model->reposition();
4298 void MapEditor::setIncludeImagesHor(bool b)
4300 BranchObj *bo=xelection.getBranch();
4303 QString u= b ? "false" : "true";
4304 QString r=!b ? "false" : "true";
4308 QString("setIncludeImagesHorizontally (%1)").arg(u),
4310 QString("setIncludeImagesHorizontally (%1)").arg(r),
4311 QString("Include images horizontally in %1").arg(getName(bo))
4313 bo->setIncludeImagesHor(b);
4314 model->reposition();
4318 void MapEditor::setHideLinkUnselected (bool b)
4320 LinkableMapObj *sel=xelection.single();
4322 (xelection.type() == Selection::Branch ||
4323 xelection.type() == Selection::MapCenter ||
4324 xelection.type() == Selection::FloatImage ))
4326 QString u= b ? "false" : "true";
4327 QString r=!b ? "false" : "true";
4331 QString("setHideLinkUnselected (%1)").arg(u),
4333 QString("setHideLinkUnselected (%1)").arg(r),
4334 QString("Hide link of %1 if unselected").arg(getName(sel))
4336 sel->setHideLinkUnselected(b);
4340 void MapEditor::importDirInt(BranchObj *dst, QDir d)
4342 BranchObj *bo=xelection.getBranch();
4345 // Traverse directories
4346 d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
4347 QFileInfoList list = d.entryInfoList();
4350 for (int i = 0; i < list.size(); ++i)
4353 if (fi.fileName() != "." && fi.fileName() != ".." )
4356 bo=dst->getLastBranch();
4357 bo->setHeading (fi.fileName() );
4358 bo->setColor (QColor("blue"));
4360 if ( !d.cd(fi.fileName()) )
4361 QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory %1").arg(fi.fileName()));
4364 // Recursively add subdirs
4365 importDirInt (bo,d);
4371 d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
4372 list = d.entryInfoList();
4374 for (int i = 0; i < list.size(); ++i)
4378 bo=dst->getLastBranch();
4379 bo->setHeading (fi.fileName() );
4380 bo->setColor (QColor("black"));
4381 if (fi.fileName().right(4) == ".vym" )
4382 bo->setVymLink (fi.filePath());
4387 void MapEditor::importDirInt (const QString &s)
4389 BranchObj *bo=xelection.getBranch();
4392 saveStateChangingPart (bo,bo,QString ("importDir (\"%1\")").arg(s),QString("Import directory structure from %1").arg(s));
4395 importDirInt (bo,d);
4399 void MapEditor::importDir()
4401 BranchObj *bo=xelection.getBranch();
4404 QStringList filters;
4405 filters <<"VYM map (*.vym)";
4406 QFileDialog *fd=new QFileDialog( this,vymName+ " - " +tr("Choose directory structure to import"));
4407 fd->setMode (QFileDialog::DirectoryOnly);
4408 fd->setFilters (filters);
4409 fd->setCaption(vymName+" - " +tr("Choose directory structure to import"));
4413 if ( fd->exec() == QDialog::Accepted )
4415 importDirInt (fd->selectedFile() );
4416 model->reposition();
4422 void MapEditor::followXLink(int i)
4424 BranchObj *bo=xelection.getBranch();
4427 bo=bo->XLinkTargetAt(i);
4430 xelection.select(bo);
4431 ensureSelectionVisible();
4436 void MapEditor::editXLink(int i) // FIXME missing saveState
4438 BranchObj *bo=xelection.getBranch();
4441 XLinkObj *xlo=bo->XLinkAt(i);
4444 EditXLinkDialog dia;
4446 dia.setSelection(bo);
4447 if (dia.exec() == QDialog::Accepted)
4449 if (dia.useSettingsGlobal() )
4451 setMapDefXLinkColor (xlo->getColor() );
4452 setMapDefXLinkWidth (xlo->getWidth() );
4454 if (dia.deleteXLink())
4455 bo->deleteXLinkAt(i);
4461 AttributeTable* MapEditor::attributeTable()
4466 void MapEditor::testFunction1()
4468 BranchObj *bo=xelection.getBranch();
4469 if (bo) model->moveAway (bo);
4471 /* TODO Hide hidden stuff temporary, maybe add this as regular function somewhere
4472 if (hidemode==HideNone)
4474 setHideTmpMode (HideExport);
4475 mapCenter->calcBBoxSizeWithChilds();
4476 QRectF totalBBox=mapCenter->getTotalBBox();
4477 QRectF mapRect=totalBBox;
4478 QCanvasRectangle *frame=NULL;
4480 cout << " map has =("<<totalBBox.x()<<","<<totalBBox.y()<<","<<totalBBox.width()<<","<<totalBBox.height()<<")\n";
4482 mapRect.setRect (totalBBox.x(), totalBBox.y(),
4483 totalBBox.width(), totalBBox.height());
4484 frame=new QCanvasRectangle (mapRect,mapScene);
4485 frame->setBrush (QColor(white));
4486 frame->setPen (QColor(black));
4487 frame->setZValue(0);
4492 setHideTmpMode (HideNone);
4494 cout <<" hidemode="<<hidemode<<endl;
4498 void MapEditor::testFunction2()
4503 if (hidemode==HideExport)
4504 setHideTmpMode (HideNone);
4506 setHideTmpMode (HideExport);
4510 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
4512 // Lineedits are already closed by preceding
4513 // mouseEvent, we don't need to close here.
4515 QPointF p = mapToScene(e->pos());
4516 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4519 { // MapObj was found
4520 if (xelection.single() != lmo)
4522 // select the MapObj
4523 xelection.select(lmo);
4526 if (xelection.getBranch() )
4528 // Context Menu on branch or mapcenter
4530 branchContextMenu->popup(e->globalPos() );
4533 if (xelection.getFloatImage() )
4535 // Context Menu on floatimage
4537 floatimageContextMenu->popup(e->globalPos() );
4541 { // No MapObj found, we are on the Canvas itself
4542 // Context Menu on scene
4545 canvasContextMenu->popup(e->globalPos() );
4550 void MapEditor::keyPressEvent(QKeyEvent* e)
4552 if (e->modifiers() & Qt::ControlModifier)
4554 switch (mainWindow->getModMode())
4556 case Main::ModModeColor:
4557 setCursor (PickColorCursor);
4559 case Main::ModModeCopy:
4560 setCursor (CopyCursor);
4562 case Main::ModModeXLink:
4563 setCursor (XLinkCursor);
4566 setCursor (Qt::ArrowCursor);
4572 void MapEditor::keyReleaseEvent(QKeyEvent* e)
4574 if (!(e->modifiers() & Qt::ControlModifier))
4575 setCursor (Qt::ArrowCursor);
4578 void MapEditor::mousePressEvent(QMouseEvent* e)
4580 // Ignore right clicks, these will go to context menus
4581 if (e->button() == Qt::RightButton )
4587 //Ignore clicks while editing heading
4588 if (isSelectBlocked() )
4594 QPointF p = mapToScene(e->pos());
4595 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4599 //Take care of system flags _or_ modifier modes
4601 if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4602 typeid(*lmo)==typeid(MapCenterObj) ))
4604 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
4605 if (!foname.isEmpty())
4607 // systemFlag clicked
4611 if (e->state() & Qt::ControlModifier)
4612 mainWindow->editOpenURLTab();
4614 mainWindow->editOpenURL();
4616 else if (foname=="vymLink")
4618 mainWindow->editOpenVymLink();
4619 // tabWidget may change, better return now
4620 // before segfaulting...
4621 } else if (foname=="note")
4622 mainWindow->windowToggleNoteEditor();
4623 else if (foname=="hideInExport")
4630 // No system flag clicked, take care of modmodes (CTRL-Click)
4631 if (e->state() & Qt::ControlModifier)
4633 if (mainWindow->getModMode()==Main::ModModeColor)
4636 setCursor (PickColorCursor);
4639 if (mainWindow->getModMode()==Main::ModModeXLink)
4641 BranchObj *bo_begin=NULL;
4643 bo_begin=(BranchObj*)(lmo);
4645 if (xelection.getBranch() )
4646 bo_begin=xelection.getBranch();
4650 linkingObj_src=bo_begin;
4651 tmpXLink=new XLinkObj (mapScene);
4652 tmpXLink->setBegin (bo_begin);
4653 tmpXLink->setEnd (p);
4654 tmpXLink->setColor(defXLinkColor);
4655 tmpXLink->setWidth(defXLinkWidth);
4656 tmpXLink->updateXLink();
4657 tmpXLink->setVisibility (true);
4661 } // End of modmodes
4665 // Select the clicked object
4668 // Left Button Move Branches
4669 if (e->button() == Qt::LeftButton )
4671 //movingObj_start.setX( p.x() - selection->x() );// TODO replaced selection->lmo here
4672 //movingObj_start.setY( p.y() - selection->y() );
4673 movingObj_start.setX( p.x() - lmo->x() );
4674 movingObj_start.setY( p.y() - lmo->y() );
4675 movingObj_orgPos.setX (lmo->x() );
4676 movingObj_orgPos.setY (lmo->y() );
4677 movingObj_orgRelPos=lmo->getRelPos();
4679 // If modMode==copy, then we want to "move" the _new_ object around
4680 // then we need the offset from p to the _old_ selection, because of tmp
4681 if (mainWindow->getModMode()==Main::ModModeCopy &&
4682 e->state() & Qt::ControlModifier)
4684 BranchObj *bo=xelection.getBranch();
4688 bo->addBranch ((BranchObj*)xelection.single());
4690 xelection.select(bo->getLastBranch());
4691 model->reposition();
4695 movingObj=xelection.single();
4697 // Middle Button Toggle Scroll
4698 // (On Mac OS X this won't work, but we still have
4699 // a button in the toolbar)
4700 if (e->button() == Qt::MidButton )
4705 { // No MapObj found, we are on the scene itself
4706 // Left Button move Pos of sceneView
4707 if (e->button() == Qt::LeftButton )
4709 movingObj=NULL; // move Content not Obj
4710 movingObj_start=e->globalPos();
4711 movingCont_start=QPointF (
4712 horizontalScrollBar()->value(),
4713 verticalScrollBar()->value());
4714 movingVec=QPointF(0,0);
4715 setCursor(HandOpenCursor);
4720 void MapEditor::mouseMoveEvent(QMouseEvent* e)
4722 QPointF p = mapToScene(e->pos());
4723 LinkableMapObj *lmosel=xelection.single();
4725 // Move the selected MapObj
4726 if ( lmosel && movingObj)
4728 // reset cursor if we are moving and don't copy
4729 if (mainWindow->getModMode()!=Main::ModModeCopy)
4730 setCursor (Qt::ArrowCursor);
4732 // To avoid jumping of the sceneView, only
4733 // ensureSelectionVisible, if not tmp linked
4734 if (!lmosel->hasParObjTmp())
4735 ensureSelectionVisible ();
4737 // Now move the selection, but add relative position
4738 // (movingObj_start) where selection was chosen with
4739 // mousepointer. (This avoids flickering resp. jumping
4740 // of selection back to absPos)
4742 // Check if we could link
4743 LinkableMapObj* lmo=model->findMapObj(p, lmosel);
4746 FloatObj *fio=xelection.getFloatImage();
4749 fio->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4751 fio->updateLink(); //no need for reposition, if we update link here
4754 // Relink float to new mapcenter or branch, if shift is pressed
4755 // Only relink, if selection really has a new parent
4756 if ( (e->modifiers()==Qt::ShiftModifier) && lmo &&
4757 ( (typeid(*lmo)==typeid(BranchObj)) ||
4758 (typeid(*lmo)==typeid(MapCenterObj)) ) &&
4759 ( lmo != fio->getParObj())
4762 if (typeid(*fio) == typeid(FloatImageObj) &&
4763 ( (typeid(*lmo)==typeid(BranchObj) ||
4764 typeid(*lmo)==typeid(MapCenterObj)) ))
4767 // Also save the move which was done so far
4768 QString pold=qpointfToString(movingObj_orgRelPos);
4769 QString pnow=qpointfToString(fio->getRelPos());
4775 QString("Move %1 to relative position %2").arg(getName(fio)).arg(pnow));
4776 fio->getParObj()->requestReposition();
4777 model->reposition();
4779 linkTo (model->getSelectString(lmo));
4781 //movingObj_orgRelPos=lmosel->getRelPos();
4783 model->reposition();
4787 { // selection != a FloatObj
4788 if (lmosel->getDepth()==0)
4791 if (e->buttons()== Qt::LeftButton && e->modifiers()==Qt::ShiftModifier)
4792 ((MapCenterObj*)lmosel)->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4794 lmosel->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4795 model->updateRelPositions();
4798 if (lmosel->getDepth()==1)
4801 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4802 lmosel->setRelPos();
4805 // Move ordinary branch
4806 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4809 // Maybe we can relink temporary?
4810 if (lmo && (lmo!=lmosel) && xelection.getBranch() &&
4811 (typeid(*lmo)==typeid(BranchObj) ||
4812 typeid(*lmo)==typeid(MapCenterObj)) )
4815 if (e->modifiers()==Qt::ControlModifier)
4817 // Special case: CTRL to link below lmo
4818 lmosel->setParObjTmp (lmo,p,+1);
4820 else if (e->modifiers()==Qt::ShiftModifier)
4821 lmosel->setParObjTmp (lmo,p,-1);
4823 lmosel->setParObjTmp (lmo,p,0);
4826 lmosel->unsetParObjTmp();
4828 // reposition subbranch
4829 lmosel->reposition();
4833 } // no FloatImageObj
4837 } // selection && moving_obj
4839 // Draw a link from one branch to another
4842 tmpXLink->setEnd (p);
4843 tmpXLink->updateXLink();
4847 if (!movingObj && !pickingColor &&!drawingLink && e->buttons() == Qt::LeftButton )
4849 QPointF p=e->globalPos();
4850 movingVec.setX(-p.x() + movingObj_start.x() );
4851 movingVec.setY(-p.y() + movingObj_start.y() );
4852 horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
4853 verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
4858 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
4860 QPointF p = mapToScene(e->pos());
4861 LinkableMapObj *dst;
4862 LinkableMapObj *lmosel=xelection.single();
4863 // Have we been picking color?
4867 setCursor (Qt::ArrowCursor);
4868 // Check if we are over another branch
4869 dst=model->findMapObj(p, NULL);
4872 if (e->state() & Qt::ShiftModifier)
4873 colorBranch (((BranchObj*)dst)->getColor());
4875 colorSubtree (((BranchObj*)dst)->getColor());
4880 // Have we been drawing a link?
4884 // Check if we are over another branch
4885 dst=model->findMapObj(p, NULL);
4888 tmpXLink->setEnd ( ((BranchObj*)(dst)) );
4889 tmpXLink->updateXLink();
4890 tmpXLink->activate(); //FIXME savestate missing
4891 //saveStateComplete(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) );
4900 // Have we been moving something?
4901 if ( lmosel && movingObj )
4903 FloatImageObj *fo=xelection.getFloatImage();
4906 // Moved FloatObj. Maybe we need to reposition
4907 QString pold=qpointfToString(movingObj_orgRelPos);
4908 QString pnow=qpointfToString(fo->getRelPos());
4914 QString("Move %1 to relative position %2").arg(getName(fo)).arg(pnow));
4916 fo->getParObj()->requestReposition();
4917 model->reposition();
4920 // Check if we are over another branch, but ignore
4921 // any found LMOs, which are FloatObjs
4922 dst=model->findMapObj(mapToScene(e->pos() ), lmosel);
4924 if (dst && (typeid(*dst)!=typeid(BranchObj) && typeid(*dst)!=typeid(MapCenterObj)))
4927 BranchObj *bo=xelection.getBranch();
4928 if (bo && bo->getDepth()==0)
4930 if (movingObj_orgPos != bo->getAbsPos())
4932 QString pold=qpointfToString(movingObj_orgPos);
4933 QString pnow=qpointfToString(bo->getAbsPos());
4939 QString("Move mapcenter %1 to position %2").arg(getName(bo)).arg(pnow));
4943 if (xelection.type() == Selection::Branch )
4944 { // A branch was moved
4946 // save the position in case we link to mapcenter
4947 QPointF savePos=QPointF (lmosel->getAbsPos() );
4949 // Reset the temporary drawn link to the original one
4950 lmosel->unsetParObjTmp();
4952 // For Redo we may need to save original selection
4953 QString preSelStr=model->getSelectString(lmosel);
4958 // We have a destination, relink to that
4960 BranchObj* bsel=xelection.getBranch();
4961 BranchObj* bdst=(BranchObj*)dst;
4963 QString preParStr=model->getSelectString (bsel->getParObj());
4964 QString preNum=QString::number (bsel->getNum(),10);
4965 QString preDstParStr;
4967 if (e->state() & Qt::ShiftModifier && dst->getParObj())
4969 preDstParStr=model->getSelectString (dst->getParObj());
4970 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum());
4972 if (e->state() & Qt::ControlModifier && dst->getParObj())
4975 preDstParStr=model->getSelectString (dst->getParObj());
4976 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum()+1);
4979 preDstParStr=model->getSelectString(dst);
4980 bsel->linkTo (bdst,-1);
4981 if (dst->getDepth()==0) bsel->move (savePos);
4983 QString postSelStr=model->getSelectString(lmosel);
4984 QString postNum=QString::number (bsel->getNum(),10);
4986 QString undoCom="linkTo (\""+
4987 preParStr+ "\"," + preNum +"," +
4988 QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")";
4990 QString redoCom="linkTo (\""+
4991 preDstParStr + "\"," + postNum + "," +
4992 QString ("%1,%2").arg(savePos.x()).arg(savePos.y())+ ")";
4997 QString("Relink %1 to %2").arg(getName(bsel)).arg(getName(dst)) );
4999 model->reposition(); // not necessary if we undo temporary move below
5002 // No destination, undo temporary move
5004 if (lmosel->getDepth()==1)
5006 // The select string might be different _after_ moving around.
5007 // Therefor reposition and then use string of old selection, too
5008 model->reposition();
5010 QPointF rp(lmosel->getRelPos());
5011 if (rp != movingObj_orgRelPos)
5013 QString ps=qpointfToString(rp);
5015 model->getSelectString(lmosel), "moveRel "+qpointfToString(movingObj_orgRelPos),
5016 preSelStr, "moveRel "+ps,
5017 QString("Move %1 to relative position %2").arg(getName(lmosel)).arg(ps));
5021 // Draw the original link, before selection was moved around
5022 if (settings.value("/animation/use",false).toBool() && lmosel->getDepth()>1)
5024 QPointF p=bo->getParObj()->getChildPos();
5025 lmosel->setRelPos(); // calc relPos first
5026 model->startAnimation(
5027 lmosel->getRelPos(),
5028 QPointF (movingObj_orgPos.x() - p.x(), movingObj_orgPos.y() - p.y() )
5031 model->reposition();
5035 // Finally resize scene, if needed
5039 // Just make sure, that actions are still ok,e.g. the move branch up/down buttons...
5042 // maybe we moved View: set old cursor
5043 setCursor (Qt::ArrowCursor);
5047 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
5049 if (isSelectBlocked() )
5055 if (e->button() == Qt::LeftButton )
5057 QPointF p = mapToScene(e->pos());
5058 LinkableMapObj *lmo=model->findMapObj(p, NULL);
5059 if (lmo) { // MapObj was found
5060 // First select the MapObj than edit heading
5061 xelection.select(lmo);
5062 mainWindow->editHeading();
5067 void MapEditor::resizeEvent (QResizeEvent* e)
5069 QGraphicsView::resizeEvent( e );
5072 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
5074 //for (unsigned int i=0;event->format(i);i++) // Debug mime type
5075 // cerr << event->format(i) << endl;
5077 if (event->mimeData()->hasImage())
5078 event->acceptProposedAction();
5080 if (event->mimeData()->hasUrls())
5081 event->acceptProposedAction();
5084 void MapEditor::dragMoveEvent(QDragMoveEvent *)
5088 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
5093 void MapEditor::dropEvent(QDropEvent *event)
5095 BranchObj *sel=xelection.getBranch();
5099 foreach (QString format,event->mimeData()->formats())
5100 cout << "MapEditor: Dropped format: "<<qPrintable (format)<<endl;
5104 if (event->mimeData()->hasImage())
5106 QVariant imageData = event->mimeData()->imageData();
5107 addFloatImageInt (qvariant_cast<QPixmap>(imageData));
5109 if (event->mimeData()->hasUrls())
5110 uris=event->mimeData()->urls();
5118 for (int i=0; i<uris.count();i++)
5120 // Workaround to avoid adding empty branches
5121 if (!uris.at(i).toString().isEmpty())
5123 bo=sel->addBranch();
5126 s=uris.at(i).toLocalFile();
5129 QString file = QDir::fromNativeSeparators(s);
5130 heading = QFileInfo(file).baseName();
5132 if (file.endsWith(".vym", false))
5133 bo->setVymLink(file);
5135 bo->setURL(uris.at(i).toString());
5138 bo->setURL(uris.at(i).toString());
5141 if (!heading.isEmpty())
5142 bo->setHeading(heading);
5144 bo->setHeading(uris.at(i).toString());
5148 model->reposition();
5151 event->acceptProposedAction();
5155 void MapEditor::sendSelection()
5157 if (netstate!=Server) return;
5158 sendData (QString("select (\"%1\")").arg(xelection.getSelectString()) );
5161 void MapEditor::newServer()
5165 tcpServer = new QTcpServer(this);
5166 if (!tcpServer->listen(QHostAddress::Any,port)) {
5167 QMessageBox::critical(this, "vym server",
5168 QString("Unable to start the server: %1.").arg(tcpServer->errorString()));
5172 connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newClient()));
5174 cout<<"Server is running on port "<<tcpServer->serverPort()<<endl;
5177 void MapEditor::connectToServer()
5180 server="salam.suse.de";
5182 clientSocket = new QTcpSocket (this);
5183 clientSocket->abort();
5184 clientSocket->connectToHost(server ,port);
5185 connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readData()));
5186 connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
5187 this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
5189 cout<<"connected to "<<qPrintable (server)<<" port "<<port<<endl;
5194 void MapEditor::newClient()
5196 QTcpSocket *newClient = tcpServer->nextPendingConnection();
5197 connect(newClient, SIGNAL(disconnected()),
5198 newClient, SLOT(deleteLater()));
5200 cout <<"ME::newClient at "<<qPrintable( newClient->peerAddress().toString() )<<endl;
5202 clientList.append (newClient);
5206 void MapEditor::sendData(const QString &s)
5208 if (clientList.size()==0) return;
5210 // Create bytearray to send
5212 QDataStream out(&block, QIODevice::WriteOnly);
5213 out.setVersion(QDataStream::Qt_4_0);
5215 // Reserve some space for blocksize
5218 // Write sendCounter
5219 out << sendCounter++;
5224 // Go back and write blocksize so far
5225 out.device()->seek(0);
5226 quint16 bs=(quint16)(block.size() - 2*sizeof(quint16));
5230 cout << "ME::sendData bs="<<bs<<" counter="<<sendCounter<<" s="<<qPrintable(s)<<endl;
5232 for (int i=0; i<clientList.size(); ++i)
5234 //cout << "Sending \""<<qPrintable (s)<<"\" to "<<qPrintable (clientList.at(i)->peerAddress().toString())<<endl;
5235 clientList.at(i)->write (block);
5239 void MapEditor::readData ()
5241 while (clientSocket->bytesAvailable() >=(int)sizeof(quint16) )
5244 cout <<"readData bytesAvail="<<clientSocket->bytesAvailable();
5248 QDataStream in(clientSocket);
5249 in.setVersion(QDataStream::Qt_4_0);
5257 cout << " t="<<qPrintable (t)<<endl;
5263 void MapEditor::displayNetworkError(QAbstractSocket::SocketError socketError)
5265 switch (socketError) {
5266 case QAbstractSocket::RemoteHostClosedError:
5268 case QAbstractSocket::HostNotFoundError:
5269 QMessageBox::information(this, vymName +" Network client",
5270 "The host was not found. Please check the "
5271 "host name and port settings.");
5273 case QAbstractSocket::ConnectionRefusedError:
5274 QMessageBox::information(this, vymName + " Network client",
5275 "The connection was refused by the peer. "
5276 "Make sure the fortune server is running, "
5277 "and check that the host name and port "
5278 "settings are correct.");
5281 QMessageBox::information(this, vymName + " Network client",
5282 QString("The following error occurred: %1.")
5283 .arg(clientSocket->errorString()));
5287 void MapEditor::autosave()
5291 if (debug) cout <<" ME::autosave rejected, no filepath available\n";
5295 QDateTime now=QDateTime().currentDateTime();
5297 cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n";
5298 cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
5299 cout << " fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
5300 cout << " time: "<<qPrintable (now.toString())<<endl;
5301 cout << " zipped="<<zipped<<endl;
5304 // Disable autosave, while we have gone back in history
5305 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
5306 if (redosAvail>0) return;
5308 // Also disable autosave for new map without filename
5309 if (filePath.isEmpty()) return;
5312 if (mapUnsaved &&mapChanged && settings.value ("/mapeditor/autosave/use",true).toBool() )
5314 if (QFileInfo(filePath).lastModified()<=fileChangedTime)
5315 mainWindow->fileSave (this);
5318 cout <<" ME::autosave rejected, file on disk is newer than last save.\n";
5322 void MapEditor::fileChanged()
5324 // Check if file on disk has changed meanwhile
5325 if (!filePath.isEmpty())
5327 QDateTime tmod=QFileInfo (filePath).lastModified();
5328 if (tmod>fileChangedTime)
5331 /* FIXME debug message, sometimes there's a glitch in the metrics...
5332 cout << "ME::fileChanged()\n"
5333 << " last saved: "<<qPrintable (fileChangedTime.toString())<<endl
5334 << " last modififed: "<<qPrintable (tmod.toString())<<endl;
5336 // FIXME switch to current mapeditor and finish lineedits...
5337 QMessageBox mb( vymName,
5338 tr("The file of the map on disk has changed:\n\n"
5339 " %1\n\nDo you want to reload that map with the new file?").arg(filePath),
5340 QMessageBox::Question,
5342 QMessageBox::Cancel | QMessageBox::Default,
5343 QMessageBox::NoButton );
5345 mb.setButtonText( QMessageBox::Yes, tr("Reload"));
5346 mb.setButtonText( QMessageBox::No, tr("Ignore"));
5349 case QMessageBox::Yes:
5351 load (filePath,NewMap,fileType);
5352 case QMessageBox::Cancel:
5353 fileChangedTime=tmod; // allow autosave to overwrite newer file!
5361 /*TODO not needed? void MapEditor::contentsDropEvent(QDropEvent *event)
5364 } else if (event->provides("application/x-moz-file-promise-url") &&
5365 event->provides("application/x-moz-nativeimage"))
5367 // Contains url to the img src in unicode16
5368 QByteArray d = event->encodedData("application/x-moz-file-promise-url");
5369 QString url = QString((const QChar*)d.data(),d.size()/2);
5373 } else if (event->provides ("text/uri-list"))
5374 { // Uris provided e.g. by konqueror
5375 Q3UriDrag::decode (event,uris);
5376 } else if (event->provides ("_NETSCAPE_URL"))
5377 { // Uris provided by Mozilla
5378 QStringList l = QStringList::split("\n", event->encodedData("_NETSCAPE_URL"));
5381 } else if (event->provides("text/html")) {
5383 // Handels text mime types
5384 // Look like firefox allways handle text as unicode16 (2 bytes per char.)
5385 QByteArray d = event->encodedData("text/html");
5388 text = QString((const QChar*)d.data(),d.size()/2);
5392 textEditor->setText(text);
5396 } else if (event->provides("text/plain")) {
5397 QByteArray d = event->encodedData("text/plain");
5400 text = QString((const QChar*)d.data(),d.size()/2);
5404 textEditor->setText(text);
5414 bool isUnicode16(const QByteArray &d)
5416 // TODO: make more precise check for unicode 16.
5417 // Guess unicode16 if any of second bytes are zero
5418 unsigned int length = max(0,d.size()-2)/2;
5419 for (unsigned int i = 0; i<length ; i++)
5420 if (d.at(i*2+1)==0) return true;
5424 void MapEditor::addFloatImageInt (const QPixmap &img)
5426 BranchObj *bo=xelection.getBranch();
5429 FloatImageObj *fio=bo->addFloatImage();
5431 fio->setOriginalFilename("No original filename (image added by dropevent)");
5432 QString s=model->getSelectString(bo);
5433 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy dropped image to clipboard",fio );
5434 saveState (fio,"delete ()", bo,QString("paste(%1)").arg(curStep),"Pasting dropped image");
5435 model->reposition();
5442 void MapEditor::imageDataFetched(const QByteArray &a, Q3NetworkOperation * / *nop* /)
5444 if (!imageBuffer) imageBuffer = new QBuffer();
5445 if (!imageBuffer->isOpen()) {
5446 imageBuffer->open(QIODevice::WriteOnly | QIODevice::Append);
5448 imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a));
5452 void MapEditor::imageDataFinished(Q3NetworkOperation *nop)
5454 if (nop->state()==Q3NetworkProtocol::StDone) {
5455 QPixmap img(imageBuffer->buffer());
5456 addFloatImageInt (img);
5460 imageBuffer->close();
5462 imageBuffer->close();
5469 void MapEditor::fetchImage(const QString &url)
5472 urlOperator->stop();
5473 disconnect(urlOperator);
5477 urlOperator = new Q3UrlOperator(url);
5478 connect(urlOperator, SIGNAL(finished(Q3NetworkOperation *)),
5479 this, SLOT(imageDataFinished(Q3NetworkOperation*)));
5481 connect(urlOperator, SIGNAL(data(const QByteArray &, Q3NetworkOperation *)),
5482 this, SLOT(imageDataFetched(const QByteArray &, Q3NetworkOperation *)));