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("backgroundColor", mapScene->backgroundBrush().color().name() ) +
305 attribut("selectionColor", xelection.getColor().name() ) +
306 attribut("linkStyle", ls ) +
307 attribut("linkColor", defLinkColor.name() ) +
308 attribut("defXLinkColor", defXLinkColor.name() ) +
309 attribut("defXLinkWidth", QString().setNum(defXLinkWidth,10) ) +
311 s+=beginElement("vymmap",mapAttr);
314 // Find the used flags while traversing the tree
315 standardFlagsDefault->resetUsedCounter();
317 // Reset the counters before saving
318 // TODO constr. of FIO creates lots of objects, better do this in some other way...
319 FloatImageObj (mapScene).resetSaveCounter();
321 // Build xml recursivly
322 if (!saveSel || typeid (*saveSel) == typeid (MapCenterObj))
323 // Save complete map, if saveSel not set
324 s+=model->saveToDir(tmpdir,prefix,writeflags,offset);
327 if ( typeid(*saveSel) == typeid(BranchObj) )
329 s+=((BranchObj*)saveSel)->saveToDir(tmpdir,prefix,offset);
332 if ( typeid(*saveSel) == typeid(FloatImageObj) )
334 s+=((FloatImageObj*)saveSel)->saveToDir(tmpdir,prefix);
338 // Save local settings
339 s+=settings.getDataXML (destPath);
342 if (!xelection.isEmpty() && !saveSel )
343 s+=valueElement("select",xelection.getSelectString());
346 s+=endElement("vymmap");
349 standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags);
353 QString MapEditor::getHistoryDir()
355 QString histName(QString("history-%1").arg(curStep));
356 return (tmpMapDir+"/"+histName);
359 void MapEditor::saveState(const SaveMode &savemode, const QString &undoSelection, const QString &undoCom, const QString &redoSelection, const QString &redoCom, const QString &comment, LinkableMapObj *saveSel)
361 sendData(redoCom); //FIXME testing
366 if (blockSaveState) return;
368 if (debug) cout << "ME::saveState() for "<<qPrintable (mapName)<<endl;
370 // Find out current undo directory
371 if (undosAvail<stepsTotal) undosAvail++;
373 if (curStep>stepsTotal) curStep=1;
375 QString backupXML="";
376 QString histDir=getHistoryDir();
377 QString bakMapPath=histDir+"/map.xml";
379 // Create histDir if not available
382 makeSubDirs (histDir);
384 // Save depending on how much needs to be saved
386 backupXML=saveToDir (histDir,mapName+"-",false, QPointF (),saveSel);
388 QString undoCommand="";
389 if (savemode==UndoCommand)
393 else if (savemode==PartOfMap )
396 undoCommand.replace ("PATH",bakMapPath);
399 if (!backupXML.isEmpty())
400 // Write XML Data to disk
401 saveStringToDisk (bakMapPath,backupXML);
403 // We would have to save all actions in a tree, to keep track of
404 // possible redos after a action. Possible, but we are too lazy: forget about redos.
407 // Write the current state to disk
408 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
409 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
410 undoSet.setEntry ("/history/curStep",QString::number(curStep));
411 undoSet.setEntry (QString("/history/step-%1/undoCommand").arg(curStep),undoCommand);
412 undoSet.setEntry (QString("/history/step-%1/undoSelection").arg(curStep),undoSelection);
413 undoSet.setEntry (QString("/history/step-%1/redoCommand").arg(curStep),redoCom);
414 undoSet.setEntry (QString("/history/step-%1/redoSelection").arg(curStep),redoSelection);
415 undoSet.setEntry (QString("/history/step-%1/comment").arg(curStep),comment);
416 undoSet.setEntry (QString("/history/version"),vymVersion);
417 undoSet.writeSettings(histPath);
421 // TODO remove after testing
422 //cout << " into="<< histPath.toStdString()<<endl;
423 cout << " stepsTotal="<<stepsTotal<<
424 ", undosAvail="<<undosAvail<<
425 ", redosAvail="<<redosAvail<<
426 ", curStep="<<curStep<<endl;
427 cout << " ---------------------------"<<endl;
428 cout << " comment="<<comment.toStdString()<<endl;
429 cout << " undoCom="<<undoCommand.toStdString()<<endl;
430 cout << " undoSel="<<undoSelection.toStdString()<<endl;
431 cout << " redoCom="<<redoCom.toStdString()<<endl;
432 cout << " redoSel="<<redoSelection.toStdString()<<endl;
433 if (saveSel) cout << " saveSel="<<qPrintable (model->getSelectString(saveSel))<<endl;
434 cout << " ---------------------------"<<endl;
437 mainWindow->updateHistory (undoSet);
443 void MapEditor::saveStateChangingPart(LinkableMapObj *undoSel, LinkableMapObj* redoSel, const QString &rc, const QString &comment)
445 // save the selected part of the map, Undo will replace part of map
446 QString undoSelection="";
448 undoSelection=model->getSelectString(undoSel);
450 qWarning ("MapEditor::saveStateChangingPart no undoSel given!");
451 QString redoSelection="";
453 redoSelection=model->getSelectString(undoSel);
455 qWarning ("MapEditor::saveStateChangingPart no redoSel given!");
458 saveState (PartOfMap,
459 undoSelection, "addMapReplace (\"PATH\")",
465 void MapEditor::saveStateRemovingPart(LinkableMapObj *redoSel, const QString &comment)
469 qWarning ("MapEditor::saveStateRemovingPart no redoSel given!");
472 QString undoSelection=model->getSelectString (redoSel->getParObj());
473 QString redoSelection=model->getSelectString(redoSel);
474 if (typeid(*redoSel) == typeid(BranchObj) )
476 // save the selected branch of the map, Undo will insert part of map
477 saveState (PartOfMap,
478 undoSelection, QString("addMapInsert (\"PATH\",%1)").arg(((BranchObj*)redoSel)->getNum()),
479 redoSelection, "delete ()",
486 void MapEditor::saveState(LinkableMapObj *undoSel, const QString &uc, LinkableMapObj *redoSel, const QString &rc, const QString &comment)
488 // "Normal" savestate: save commands, selections and comment
489 // so just save commands for undo and redo
490 // and use current selection
492 QString redoSelection="";
493 if (redoSel) redoSelection=model->getSelectString(redoSel);
494 QString undoSelection="";
495 if (undoSel) undoSelection=model->getSelectString(undoSel);
497 saveState (UndoCommand,
504 void MapEditor::saveState(const QString &undoSel, const QString &uc, const QString &redoSel, const QString &rc, const QString &comment)
506 // "Normal" savestate: save commands, selections and comment
507 // so just save commands for undo and redo
508 // and use current selection
509 saveState (UndoCommand,
516 void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment)
518 // "Normal" savestate applied to model (no selection needed):
519 // save commands and comment
520 saveState (UndoCommand,
528 void MapEditor::parseAtom(const QString &atom)
530 BranchObj *selb=xelection.getBranch();
536 // Split string s into command and parameters
537 parser.parseAtom (atom);
538 QString com=parser.getCommand();
541 /////////////////////////////////////////////////////////////////////
542 if (com=="addBranch")
544 if (xelection.isEmpty())
546 parser.setError (Aborted,"Nothing selected");
549 parser.setError (Aborted,"Type of selection is not a branch");
554 if (parser.checkParCount(pl))
556 if (parser.parCount()==0)
560 n=parser.parInt (ok,0);
561 if (ok ) addNewBranch (n);
565 /////////////////////////////////////////////////////////////////////
566 } else if (com=="addBranchBefore")
568 if (xelection.isEmpty())
570 parser.setError (Aborted,"Nothing selected");
573 parser.setError (Aborted,"Type of selection is not a branch");
576 if (parser.parCount()==0)
578 addNewBranchBefore ();
581 /////////////////////////////////////////////////////////////////////
582 } else if (com==QString("addMapCenter"))
584 if (parser.checkParCount(2))
586 x=parser.parDouble (ok,0);
589 y=parser.parDouble (ok,1);
590 if (ok) model->addMapCenter (QPointF(x,y));
593 /////////////////////////////////////////////////////////////////////
594 } else if (com==QString("addMapReplace"))
596 if (xelection.isEmpty())
598 parser.setError (Aborted,"Nothing selected");
601 parser.setError (Aborted,"Type of selection is not a branch");
602 } else if (parser.checkParCount(1))
604 //s=parser.parString (ok,0); // selection
605 t=parser.parString (ok,0); // path to map
606 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
607 addMapReplaceInt(model->getSelectString(selb),t);
609 /////////////////////////////////////////////////////////////////////
610 } else if (com==QString("addMapInsert"))
612 if (xelection.isEmpty())
614 parser.setError (Aborted,"Nothing selected");
617 parser.setError (Aborted,"Type of selection is not a branch");
620 if (parser.checkParCount(2))
622 t=parser.parString (ok,0); // path to map
623 n=parser.parInt(ok,1); // position
624 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
625 addMapInsertInt(t,n);
628 /////////////////////////////////////////////////////////////////////
629 } else if (com=="clearFlags")
631 if (xelection.isEmpty() )
633 parser.setError (Aborted,"Nothing selected");
636 parser.setError (Aborted,"Type of selection is not a branch");
637 } else if (parser.checkParCount(0))
639 selb->clearStandardFlags();
640 selb->updateFlagsToolbar();
642 /////////////////////////////////////////////////////////////////////
643 } else if (com=="colorBranch")
645 if (xelection.isEmpty())
647 parser.setError (Aborted,"Nothing selected");
650 parser.setError (Aborted,"Type of selection is not a branch");
651 } else if (parser.checkParCount(1))
653 QColor c=parser.parColor (ok,0);
654 if (ok) colorBranch (c);
656 /////////////////////////////////////////////////////////////////////
657 } else if (com=="colorSubtree")
659 if (xelection.isEmpty())
661 parser.setError (Aborted,"Nothing selected");
664 parser.setError (Aborted,"Type of selection is not a branch");
665 } else if (parser.checkParCount(1))
667 QColor c=parser.parColor (ok,0);
668 if (ok) colorSubtree (c);
670 /////////////////////////////////////////////////////////////////////
671 } else if (com=="copy")
673 if (xelection.isEmpty())
675 parser.setError (Aborted,"Nothing selected");
678 parser.setError (Aborted,"Type of selection is not a branch");
679 } else if (parser.checkParCount(0))
681 //FIXME missing action for copy
683 /////////////////////////////////////////////////////////////////////
684 } else if (com=="cut")
686 if (xelection.isEmpty())
688 parser.setError (Aborted,"Nothing selected");
689 } else if ( xelection.type()!=Selection::Branch &&
690 xelection.type()!=Selection::MapCenter &&
691 xelection.type()!=Selection::FloatImage )
693 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
694 } else if (parser.checkParCount(0))
698 /////////////////////////////////////////////////////////////////////
699 } else if (com=="delete")
701 if (xelection.isEmpty())
703 parser.setError (Aborted,"Nothing selected");
705 /*else if (xelection.type() != Selection::Branch && xelection.type() != Selection::FloatImage )
707 parser.setError (Aborted,"Type of selection is wrong.");
710 else if (parser.checkParCount(0))
714 /////////////////////////////////////////////////////////////////////
715 } else if (com=="deleteKeepChilds")
717 if (xelection.isEmpty())
719 parser.setError (Aborted,"Nothing selected");
722 parser.setError (Aborted,"Type of selection is not a branch");
723 } else if (parser.checkParCount(0))
727 /////////////////////////////////////////////////////////////////////
728 } else if (com=="deleteChilds")
730 if (xelection.isEmpty())
732 parser.setError (Aborted,"Nothing selected");
735 parser.setError (Aborted,"Type of selection is not a branch");
736 } else if (parser.checkParCount(0))
740 /////////////////////////////////////////////////////////////////////
741 } else if (com=="exportASCII")
745 if (parser.parCount()>=1)
746 // Hey, we even have a filename
747 fname=parser.parString(ok,0);
750 parser.setError (Aborted,"Could not read filename");
753 exportASCII (fname,false);
755 /////////////////////////////////////////////////////////////////////
756 } else if (com=="exportImage")
760 if (parser.parCount()>=2)
761 // Hey, we even have a filename
762 fname=parser.parString(ok,0);
765 parser.setError (Aborted,"Could not read filename");
768 QString format="PNG";
769 if (parser.parCount()>=2)
771 format=parser.parString(ok,1);
773 exportImage (fname,false,format);
775 /////////////////////////////////////////////////////////////////////
776 } else if (com=="exportXHTML")
780 if (parser.parCount()>=2)
781 // Hey, we even have a filename
782 fname=parser.parString(ok,1);
785 parser.setError (Aborted,"Could not read filename");
788 exportXHTML (fname,false);
790 /////////////////////////////////////////////////////////////////////
791 } else if (com=="exportXML")
795 if (parser.parCount()>=2)
796 // Hey, we even have a filename
797 fname=parser.parString(ok,1);
800 parser.setError (Aborted,"Could not read filename");
803 exportXML (fname,false);
805 /////////////////////////////////////////////////////////////////////
806 } else if (com=="importDir")
808 if (xelection.isEmpty())
810 parser.setError (Aborted,"Nothing selected");
813 parser.setError (Aborted,"Type of selection is not a branch");
814 } else if (parser.checkParCount(1))
816 s=parser.parString(ok,0);
817 if (ok) importDirInt(s);
819 /////////////////////////////////////////////////////////////////////
820 } else if (com=="linkTo")
822 if (xelection.isEmpty())
824 parser.setError (Aborted,"Nothing selected");
827 if (parser.checkParCount(4))
829 // 0 selectstring of parent
830 // 1 num in parent (for branches)
831 // 2,3 x,y of mainbranch or mapcenter
832 s=parser.parString(ok,0);
833 LinkableMapObj *dst=model->findObjBySelect (s);
836 if (typeid(*dst) == typeid(BranchObj) )
838 // Get number in parent
839 n=parser.parInt (ok,1);
842 selb->linkTo ((BranchObj*)(dst),n);
845 } else if (typeid(*dst) == typeid(MapCenterObj) )
847 selb->linkTo ((BranchObj*)(dst),-1);
848 // Get coordinates of mainbranch
849 x=parser.parDouble(ok,2);
852 y=parser.parDouble(ok,3);
862 } else if ( xelection.type() == Selection::FloatImage)
864 if (parser.checkParCount(1))
866 // 0 selectstring of parent
867 s=parser.parString(ok,0);
868 LinkableMapObj *dst=model->findObjBySelect (s);
871 if (typeid(*dst) == typeid(BranchObj) ||
872 typeid(*dst) == typeid(MapCenterObj))
873 linkTo (model->getSelectString(dst));
875 parser.setError (Aborted,"Destination is not a branch");
878 parser.setError (Aborted,"Type of selection is not a floatimage or branch");
879 /////////////////////////////////////////////////////////////////////
880 } else if (com=="loadImage")
882 if (xelection.isEmpty())
884 parser.setError (Aborted,"Nothing selected");
887 parser.setError (Aborted,"Type of selection is not a branch");
888 } else if (parser.checkParCount(1))
890 s=parser.parString(ok,0);
891 if (ok) loadFloatImageInt (s);
893 /////////////////////////////////////////////////////////////////////
894 } else if (com=="moveBranchUp")
896 if (xelection.isEmpty() )
898 parser.setError (Aborted,"Nothing selected");
901 parser.setError (Aborted,"Type of selection is not a branch");
902 } else if (parser.checkParCount(0))
906 /////////////////////////////////////////////////////////////////////
907 } else if (com=="moveBranchDown")
909 if (xelection.isEmpty() )
911 parser.setError (Aborted,"Nothing selected");
914 parser.setError (Aborted,"Type of selection is not a branch");
915 } else if (parser.checkParCount(0))
919 /////////////////////////////////////////////////////////////////////
920 } else if (com=="move")
922 if (xelection.isEmpty() )
924 parser.setError (Aborted,"Nothing selected");
925 } else if ( xelection.type()!=Selection::Branch &&
926 xelection.type()!=Selection::MapCenter &&
927 xelection.type()!=Selection::FloatImage )
929 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
930 } else if (parser.checkParCount(2))
932 x=parser.parDouble (ok,0);
935 y=parser.parDouble (ok,1);
939 /////////////////////////////////////////////////////////////////////
940 } else if (com=="moveRel")
942 if (xelection.isEmpty() )
944 parser.setError (Aborted,"Nothing selected");
945 } else if ( xelection.type()!=Selection::Branch &&
946 xelection.type()!=Selection::MapCenter &&
947 xelection.type()!=Selection::FloatImage )
949 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
950 } else if (parser.checkParCount(2))
952 x=parser.parDouble (ok,0);
955 y=parser.parDouble (ok,1);
956 if (ok) moveRel (x,y);
959 /////////////////////////////////////////////////////////////////////
960 } else if (com=="nop")
962 /////////////////////////////////////////////////////////////////////
963 } else if (com=="paste")
965 if (xelection.isEmpty() )
967 parser.setError (Aborted,"Nothing selected");
970 parser.setError (Aborted,"Type of selection is not a branch");
971 } else if (parser.checkParCount(1))
973 n=parser.parInt (ok,0);
974 if (ok) pasteNoSave(n);
976 /////////////////////////////////////////////////////////////////////
977 } else if (com=="qa")
979 if (xelection.isEmpty() )
981 parser.setError (Aborted,"Nothing selected");
984 parser.setError (Aborted,"Type of selection is not a branch");
985 } else if (parser.checkParCount(4))
988 c=parser.parString (ok,0);
991 parser.setError (Aborted,"No comment given");
994 s=parser.parString (ok,1);
997 parser.setError (Aborted,"First parameter is not a string");
1000 t=parser.parString (ok,2);
1003 parser.setError (Aborted,"Condition is not a string");
1006 u=parser.parString (ok,3);
1009 parser.setError (Aborted,"Third parameter is not a string");
1014 parser.setError (Aborted,"Unknown type: "+s);
1019 parser.setError (Aborted,"Unknown operator: "+t);
1024 parser.setError (Aborted,"Type of selection is not a branch");
1027 if (selb->getHeading() == u)
1029 cout << "PASSED: " << qPrintable (c) << endl;
1032 cout << "FAILED: " << qPrintable (c) << endl;
1042 /////////////////////////////////////////////////////////////////////
1043 } else if (com=="saveImage")
1045 FloatImageObj *fio=xelection.getFloatImage();
1048 parser.setError (Aborted,"Type of selection is not an image");
1049 } else if (parser.checkParCount(2))
1051 s=parser.parString(ok,0);
1054 t=parser.parString(ok,1);
1055 if (ok) saveFloatImageInt (fio,t,s);
1058 /////////////////////////////////////////////////////////////////////
1059 } else if (com=="scroll")
1061 if (xelection.isEmpty() )
1063 parser.setError (Aborted,"Nothing selected");
1066 parser.setError (Aborted,"Type of selection is not a branch");
1067 } else if (parser.checkParCount(0))
1069 if (!scrollBranch (selb))
1070 parser.setError (Aborted,"Could not scroll branch");
1072 /////////////////////////////////////////////////////////////////////
1073 } else if (com=="select")
1075 if (parser.checkParCount(1))
1077 s=parser.parString(ok,0);
1080 /////////////////////////////////////////////////////////////////////
1081 } else if (com=="selectLastBranch")
1083 if (xelection.isEmpty() )
1085 parser.setError (Aborted,"Nothing selected");
1088 parser.setError (Aborted,"Type of selection is not a branch");
1089 } else if (parser.checkParCount(0))
1091 BranchObj *bo=selb->getLastBranch();
1093 parser.setError (Aborted,"Could not select last branch");
1097 /////////////////////////////////////////////////////////////////////
1098 } else if (com=="selectLastImage")
1100 if (xelection.isEmpty() )
1102 parser.setError (Aborted,"Nothing selected");
1105 parser.setError (Aborted,"Type of selection is not a branch");
1106 } else if (parser.checkParCount(0))
1108 FloatImageObj *fio=selb->getLastFloatImage();
1110 parser.setError (Aborted,"Could not select last image");
1114 /////////////////////////////////////////////////////////////////////
1115 } else if (com=="selectLatestAdded")
1117 if (latestSelection.isEmpty() )
1119 parser.setError (Aborted,"No latest added object");
1122 if (!select (latestSelection))
1123 parser.setError (Aborted,"Could not select latest added object "+latestSelection);
1125 /////////////////////////////////////////////////////////////////////
1126 } else if (com=="setFrameType")
1128 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1130 parser.setError (Aborted,"Type of selection does not allow setting frame type");
1132 else if (parser.checkParCount(1))
1134 s=parser.parString(ok,0);
1135 if (ok) setFrameType (s);
1137 /////////////////////////////////////////////////////////////////////
1138 } else if (com=="setFramePenColor")
1140 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1142 parser.setError (Aborted,"Type of selection does not allow setting of pen color");
1144 else if (parser.checkParCount(1))
1146 QColor c=parser.parColor(ok,0);
1147 if (ok) setFramePenColor (c);
1149 /////////////////////////////////////////////////////////////////////
1150 } else if (com=="setFrameBrushColor")
1152 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1154 parser.setError (Aborted,"Type of selection does not allow setting brush color");
1156 else if (parser.checkParCount(1))
1158 QColor c=parser.parColor(ok,0);
1159 if (ok) setFrameBrushColor (c);
1161 /////////////////////////////////////////////////////////////////////
1162 } else if (com=="setFramePadding")
1164 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1166 parser.setError (Aborted,"Type of selection does not allow setting frame padding");
1168 else if (parser.checkParCount(1))
1170 n=parser.parInt(ok,0);
1171 if (ok) setFramePadding(n);
1173 /////////////////////////////////////////////////////////////////////
1174 } else if (com=="setFrameBorderWidth")
1176 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1178 parser.setError (Aborted,"Type of selection does not allow setting frame border width");
1180 else if (parser.checkParCount(1))
1182 n=parser.parInt(ok,0);
1183 if (ok) setFrameBorderWidth (n);
1185 /////////////////////////////////////////////////////////////////////
1186 } else if (com=="setMapAuthor")
1188 if (parser.checkParCount(1))
1190 s=parser.parString(ok,0);
1191 if (ok) setMapAuthor (s);
1193 /////////////////////////////////////////////////////////////////////
1194 } else if (com=="setMapComment")
1196 if (parser.checkParCount(1))
1198 s=parser.parString(ok,0);
1199 if (ok) setMapComment(s);
1201 /////////////////////////////////////////////////////////////////////
1202 } else if (com=="setMapBackgroundColor")
1204 if (xelection.isEmpty() )
1206 parser.setError (Aborted,"Nothing selected");
1207 } else if (! xelection.getBranch() )
1209 parser.setError (Aborted,"Type of selection is not a branch");
1210 } else if (parser.checkParCount(1))
1212 QColor c=parser.parColor (ok,0);
1213 if (ok) setMapBackgroundColor (c);
1215 /////////////////////////////////////////////////////////////////////
1216 } else if (com=="setMapDefLinkColor")
1218 if (xelection.isEmpty() )
1220 parser.setError (Aborted,"Nothing selected");
1223 parser.setError (Aborted,"Type of selection is not a branch");
1224 } else if (parser.checkParCount(1))
1226 QColor c=parser.parColor (ok,0);
1227 if (ok) setMapDefLinkColor (c);
1229 /////////////////////////////////////////////////////////////////////
1230 } else if (com=="setMapLinkStyle")
1232 if (parser.checkParCount(1))
1234 s=parser.parString (ok,0);
1235 if (ok) setMapLinkStyle(s);
1237 /////////////////////////////////////////////////////////////////////
1238 } else if (com=="setHeading")
1240 if (xelection.isEmpty() )
1242 parser.setError (Aborted,"Nothing selected");
1245 parser.setError (Aborted,"Type of selection is not a branch");
1246 } else if (parser.checkParCount(1))
1248 s=parser.parString (ok,0);
1252 /////////////////////////////////////////////////////////////////////
1253 } else if (com=="setHideExport")
1255 if (xelection.isEmpty() )
1257 parser.setError (Aborted,"Nothing selected");
1258 } else if (xelection.type()!=Selection::Branch && xelection.type() != Selection::MapCenter &&xelection.type()!=Selection::FloatImage)
1260 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
1261 } else if (parser.checkParCount(1))
1263 b=parser.parBool(ok,0);
1264 if (ok) setHideExport (b);
1266 /////////////////////////////////////////////////////////////////////
1267 } else if (com=="setIncludeImagesHorizontally")
1269 if (xelection.isEmpty() )
1271 parser.setError (Aborted,"Nothing selected");
1274 parser.setError (Aborted,"Type of selection is not a branch");
1275 } else if (parser.checkParCount(1))
1277 b=parser.parBool(ok,0);
1278 if (ok) setIncludeImagesHor(b);
1280 /////////////////////////////////////////////////////////////////////
1281 } else if (com=="setIncludeImagesVertically")
1283 if (xelection.isEmpty() )
1285 parser.setError (Aborted,"Nothing selected");
1288 parser.setError (Aborted,"Type of selection is not a branch");
1289 } else if (parser.checkParCount(1))
1291 b=parser.parBool(ok,0);
1292 if (ok) setIncludeImagesVer(b);
1294 /////////////////////////////////////////////////////////////////////
1295 } else if (com=="setHideLinkUnselected")
1297 if (xelection.isEmpty() )
1299 parser.setError (Aborted,"Nothing selected");
1300 } else if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1302 parser.setError (Aborted,"Type of selection does not allow hiding the link");
1303 } else if (parser.checkParCount(1))
1305 b=parser.parBool(ok,0);
1306 if (ok) setHideLinkUnselected(b);
1308 /////////////////////////////////////////////////////////////////////
1309 } else if (com=="setSelectionColor")
1311 if (parser.checkParCount(1))
1313 QColor c=parser.parColor (ok,0);
1314 if (ok) setSelectionColorInt (c);
1316 /////////////////////////////////////////////////////////////////////
1317 } else if (com=="setURL")
1319 if (xelection.isEmpty() )
1321 parser.setError (Aborted,"Nothing selected");
1324 parser.setError (Aborted,"Type of selection is not a branch");
1325 } else if (parser.checkParCount(1))
1327 s=parser.parString (ok,0);
1330 /////////////////////////////////////////////////////////////////////
1331 } else if (com=="setVymLink")
1333 if (xelection.isEmpty() )
1335 parser.setError (Aborted,"Nothing selected");
1338 parser.setError (Aborted,"Type of selection is not a branch");
1339 } else if (parser.checkParCount(1))
1341 s=parser.parString (ok,0);
1342 if (ok) setVymLinkInt(s);
1345 /////////////////////////////////////////////////////////////////////
1346 else if (com=="setFlag")
1348 if (xelection.isEmpty() )
1350 parser.setError (Aborted,"Nothing selected");
1353 parser.setError (Aborted,"Type of selection is not a branch");
1354 } else if (parser.checkParCount(1))
1356 s=parser.parString(ok,0);
1359 selb->activateStandardFlag(s);
1360 selb->updateFlagsToolbar();
1363 /////////////////////////////////////////////////////////////////////
1364 } else if (com=="setFrameType")
1366 if (xelection.isEmpty() )
1368 parser.setError (Aborted,"Nothing selected");
1371 parser.setError (Aborted,"Type of selection is not a branch");
1372 } else if (parser.checkParCount(1))
1374 s=parser.parString(ok,0);
1378 /////////////////////////////////////////////////////////////////////
1379 } else if (com=="sortChildren")
1381 if (xelection.isEmpty() )
1383 parser.setError (Aborted,"Nothing selected");
1386 parser.setError (Aborted,"Type of selection is not a branch");
1387 } else if (parser.checkParCount(0))
1391 /////////////////////////////////////////////////////////////////////
1392 } else if (com=="toggleFlag")
1394 if (xelection.isEmpty() )
1396 parser.setError (Aborted,"Nothing selected");
1399 parser.setError (Aborted,"Type of selection is not a branch");
1400 } else if (parser.checkParCount(1))
1402 s=parser.parString(ok,0);
1405 selb->toggleStandardFlag(s);
1406 selb->updateFlagsToolbar();
1409 /////////////////////////////////////////////////////////////////////
1410 } else if (com=="unscroll")
1412 if (xelection.isEmpty() )
1414 parser.setError (Aborted,"Nothing selected");
1417 parser.setError (Aborted,"Type of selection is not a branch");
1418 } else if (parser.checkParCount(0))
1420 if (!unscrollBranch (selb))
1421 parser.setError (Aborted,"Could not unscroll branch");
1423 /////////////////////////////////////////////////////////////////////
1424 } else if (com=="unscrollChilds")
1426 if (xelection.isEmpty() )
1428 parser.setError (Aborted,"Nothing selected");
1431 parser.setError (Aborted,"Type of selection is not a branch");
1432 } else if (parser.checkParCount(0))
1436 /////////////////////////////////////////////////////////////////////
1437 } else if (com=="unsetFlag")
1439 if (xelection.isEmpty() )
1441 parser.setError (Aborted,"Nothing selected");
1444 parser.setError (Aborted,"Type of selection is not a branch");
1445 } else if (parser.checkParCount(1))
1447 s=parser.parString(ok,0);
1450 selb->deactivateStandardFlag(s);
1451 selb->updateFlagsToolbar();
1455 parser.setError (Aborted,"Unknown command");
1458 if (parser.errorLevel()==NoError)
1460 // setChanged(); FIXME should not be called e.g. for export?!
1461 model->reposition();
1465 // TODO Error handling
1466 qWarning("MapEditor::parseAtom: Error!");
1467 qWarning(parser.errorMessage());
1471 void MapEditor::runScript (QString script)
1473 parser.setScript (script);
1475 while (parser.next() )
1476 parseAtom(parser.getAtom());
1479 bool MapEditor::isDefault()
1484 bool MapEditor::hasChanged()
1489 void MapEditor::setChanged()
1493 autosaveTimer->start(settings.value("/mapeditor/autosave/ms/",300000).toInt());
1494 fileChangedTimer->start (3000);
1503 void MapEditor::closeMap()
1505 // Unselect before disabling the toolbar actions
1506 if (!xelection.isEmpty() ) xelection.unselect();
1511 // close(); FIXME needed?
1514 void MapEditor::setFilePath(QString fpath, QString destname)
1516 if (fpath.isEmpty() || fpath=="")
1523 filePath=fpath; // becomes absolute path
1524 fileName=fpath; // gets stripped of path
1525 destPath=destname; // needed for vymlinks and during load to reset fileChangedTime
1527 // If fpath is not an absolute path, complete it
1528 filePath=QDir(fpath).absPath();
1529 fileDir=filePath.left (1+filePath.findRev ("/"));
1531 // Set short name, too. Search from behind:
1532 int i=fileName.findRev("/");
1533 if (i>=0) fileName=fileName.remove (0,i+1);
1535 // Forget the .vym (or .xml) for name of map
1536 mapName=fileName.left(fileName.findRev(".",-1,true) );
1540 void MapEditor::setFilePath(QString fpath)
1542 setFilePath (fpath,fpath);
1545 QString MapEditor::getFilePath()
1550 QString MapEditor::getFileName()
1555 QString MapEditor::getMapName()
1560 QString MapEditor::getDestPath()
1565 ErrorCode MapEditor::load (QString fname, const LoadMode &lmode, const FileType &ftype)
1567 ErrorCode err=success;
1569 parseBaseHandler *handler;
1573 case VymMap: handler=new parseVYMHandler; break;
1574 case FreemindMap : handler=new parseFreemindHandler; break;
1576 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1577 "Unknown FileType in MapEditor::load()");
1581 // Save original zip state, important for inserting complete maps
1582 bool zipped_org=zipped;
1587 model->setMapEditor(this);
1588 // (map state is set later at end of load...)
1591 BranchObj *bo=xelection.getBranch();
1592 if (!bo) return aborted;
1593 if (lmode==ImportAdd)
1594 saveStateChangingPart(
1597 QString("addMapInsert (%1)").arg(fname),
1598 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1600 saveStateChangingPart(
1603 QString("addMapReplace(%1)").arg(fname),
1604 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1608 // Create temporary directory for packing
1610 QString tmpZipDir=makeTmpDir (ok,"vym-pack");
1613 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1614 tr("Couldn't create temporary directory before load\n"));
1618 // Try to unzip file
1619 err=unzipDir (tmpZipDir,fname);
1629 // Look for mapname.xml
1630 xmlfile= fname.left(fname.findRev(".",-1,true));
1631 xmlfile=xmlfile.section( '/', -1 );
1632 QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
1633 if (!mfile.exists() )
1635 // mapname.xml does not exist, well,
1636 // maybe someone renamed the mapname.vym file...
1637 // Try to find any .xml in the toplevel
1638 // directory of the .vym file
1639 QStringList flist=QDir (tmpZipDir).entryList("*.xml");
1640 if (flist.count()==1)
1642 // Only one entry, take this one
1643 xmlfile=tmpZipDir + "/"+flist.first();
1646 for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it )
1647 *it=tmpZipDir + "/" + *it;
1648 // TODO Multiple entries, load all (but only the first one into this ME)
1649 //mainWindow->fileLoadFromTmp (flist);
1650 //returnCode=1; // Silently forget this attempt to load
1651 qWarning ("MainWindow::load (fn) multimap found...");
1654 if (flist.isEmpty() )
1656 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1657 tr("Couldn't find a map (*.xml) in .vym archive.\n"));
1660 } //file doesn't exist
1662 xmlfile=mfile.name();
1665 QFile file( xmlfile);
1667 // I am paranoid: file should exist anyway
1668 // according to check in mainwindow.
1669 if (!file.exists() )
1671 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1672 tr(QString("Couldn't open map %1").arg(file.name())));
1676 bool blockSaveStateOrg=blockSaveState;
1677 blockReposition=true;
1678 blockSaveState=true;
1679 QXmlInputSource source( file);
1680 QXmlSimpleReader reader;
1681 reader.setContentHandler( handler );
1682 reader.setErrorHandler( handler );
1683 handler->setModel ( model);
1686 // We need to set the tmpDir in order to load files with rel. path
1691 tmpdir=fname.left(fname.findRev("/",-1));
1692 handler->setTmpDir (tmpdir);
1693 handler->setInputFile (file.name());
1694 handler->setLoadMode (lmode);
1695 bool ok = reader.parse( source );
1696 blockReposition=false;
1697 blockSaveState=blockSaveStateOrg;
1701 model->reposition(); // FIXME reposition the view instead...
1708 autosaveTimer->stop();
1711 // Reset timestamp to check for later updates of file
1712 fileChangedTime=QFileInfo (destPath).lastModified();
1715 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1716 tr( handler->errorProtocol() ) );
1718 // Still return "success": the map maybe at least
1719 // partially read by the parser
1724 removeDir (QDir(tmpZipDir));
1726 // Restore original zip state
1734 ErrorCode MapEditor::save (const SaveMode &savemode)
1737 QString mapFileName;
1738 QString safeFilePath;
1740 ErrorCode err=success;
1744 mapFileName=mapName+".xml";
1746 // use name given by user, even if he chooses .doc
1747 mapFileName=fileName;
1749 // Look, if we should zip the data:
1752 QMessageBox mb( vymName,
1753 tr("The map %1\ndid not use the compressed "
1754 "vym file format.\nWriting it uncompressed will also write images \n"
1755 "and flags and thus may overwrite files in the "
1756 "given directory\n\nDo you want to write the map").arg(filePath),
1757 QMessageBox::Warning,
1758 QMessageBox::Yes | QMessageBox::Default,
1760 QMessageBox::Cancel | QMessageBox::Escape);
1761 mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
1762 mb.setButtonText( QMessageBox::No, tr("uncompressed") );
1763 mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
1766 case QMessageBox::Yes:
1767 // save compressed (default file format)
1770 case QMessageBox::No:
1771 // save uncompressed
1774 case QMessageBox::Cancel:
1781 // First backup existing file, we
1782 // don't want to add to old zip archives
1786 if ( settings.value ("/mapeditor/writeBackupFile").toBool())
1788 QString backupFileName(destPath + "~");
1789 QFile backupFile(backupFileName);
1790 if (backupFile.exists() && !backupFile.remove())
1792 QMessageBox::warning(0, tr("Save Error"),
1793 tr("%1\ncould not be removed before saving").arg(backupFileName));
1795 else if (!f.rename(backupFileName))
1797 QMessageBox::warning(0, tr("Save Error"),
1798 tr("%1\ncould not be renamed before saving").arg(destPath));
1805 // Create temporary directory for packing
1807 tmpZipDir=makeTmpDir (ok,"vym-zip");
1810 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1811 tr("Couldn't create temporary directory before save\n"));
1815 // cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1816 safeFilePath=filePath;
1817 setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
1820 // Create mapName and fileDir
1821 makeSubDirs (fileDir);
1825 cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1826 cout <<"ME::save saveFilePath="<<safeFilePath.toStdString()<<endl;
1827 cout <<"ME::save destPath="<<destPath.toStdString()<<endl;
1828 cout <<"ME::save mapName="<<mapName.toStdString()<<endl;
1829 cout <<"ME::save mapFileName="<<mapFileName.toStdString()<<endl;
1833 if (savemode==CompleteMap || xelection.isEmpty())
1835 // Save complete map
1836 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),NULL);
1839 autosaveTimer->stop();
1844 if (xelection.type()==Selection::FloatImage)
1847 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),xelection.getBranch());
1848 // TODO take care of multiselections
1851 // FIXME trying to debug save problem
1852 if (saveFile.length()<1000)
1853 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));
1854 if (!saveStringToDisk(fileDir+mapFileName,saveFile))
1857 QMessageBox::critical (0,"Critical error in MapEditor::save",QString("could not sage %1").arg(fileDir+mapFileName));
1863 if (err==success) err=zipDir (tmpZipDir,destPath);
1866 removeDir (QDir(tmpZipDir));
1868 // Restore original filepath outside of tmp zip dir
1869 setFilePath (safeFilePath);
1873 fileChangedTime=QFileInfo (destPath).lastModified();
1878 void MapEditor::print()
1882 printer = new QPrinter;
1883 printer->setColorMode (QPrinter::Color);
1884 printer->setPrinterName (settings.value("/mainwindow/printerName",printer->printerName()).toString());
1885 printer->setOutputFormat((QPrinter::OutputFormat)settings.value("/mainwindow/printerFormat",printer->outputFormat()).toInt());
1886 printer->setOutputFileName(settings.value("/mainwindow/printerFileName",printer->outputFileName()).toString());
1889 QRectF totalBBox=model->getTotalBBox();
1891 // Try to set orientation automagically
1892 // Note: Interpretation of generated postscript is amibiguous, if
1893 // there are problems with landscape mode, see
1894 // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html
1896 if (totalBBox.width()>totalBBox.height())
1897 // recommend landscape
1898 printer->setOrientation (QPrinter::Landscape);
1900 // recommend portrait
1901 printer->setOrientation (QPrinter::Portrait);
1903 if ( printer->setup(this) )
1904 // returns false, if printing is canceled
1906 QPainter pp(printer);
1908 pp.setRenderHint(QPainter::Antialiasing,true);
1910 // Don't print the visualisation of selection
1911 xelection.unselect();
1913 QRectF mapRect=totalBBox;
1914 QGraphicsRectItem *frame=NULL;
1918 // Print frame around map
1919 mapRect.setRect (totalBBox.x()-10, totalBBox.y()-10,
1920 totalBBox.width()+20, totalBBox.height()+20);
1921 frame=mapScene->addRect (mapRect, QPen(Qt::black),QBrush(Qt::NoBrush));
1922 frame->setZValue(0);
1927 double paperAspect = (double)printer->width() / (double)printer->height();
1928 double mapAspect = (double)mapRect.width() / (double)mapRect.height();
1930 if (mapAspect>=paperAspect)
1932 // Fit horizontally to paper width
1933 //pp.setViewport(0,0, printer->width(),(int)(printer->width()/mapAspect) );
1934 viewBottom=(int)(printer->width()/mapAspect);
1937 // Fit vertically to paper height
1938 //pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height());
1939 viewBottom=printer->height();
1944 // Print footer below map
1946 font.setPointSize(10);
1948 QRectF footerBox(0,viewBottom,printer->width(),15);
1949 pp.drawText ( footerBox,Qt::AlignLeft,"VYM - " +fileName);
1950 pp.drawText ( footerBox, Qt::AlignRight, QDate::currentDate().toString(Qt::TextDate));
1954 QRectF (0,0,printer->width(),printer->height()-15),
1955 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height())
1958 // Viewport has paper dimension
1959 if (frame) delete (frame);
1961 // Restore selection
1962 xelection.reselect();
1964 // Save settings in vymrc
1965 settings.writeEntry("/mainwindow/printerName",printer->printerName());
1966 settings.writeEntry("/mainwindow/printerFormat",printer->outputFormat());
1967 settings.writeEntry("/mainwindow/printerFileName",printer->outputFileName());
1971 void MapEditor::setAntiAlias (bool b)
1973 setRenderHint(QPainter::Antialiasing,b);
1976 void MapEditor::setSmoothPixmap(bool b)
1978 setRenderHint(QPainter::SmoothPixmapTransform,b);
1981 QPixmap MapEditor::getPixmap()
1983 QRectF mapRect=model->getTotalBBox();
1984 QPixmap pix((int)mapRect.width()+2,(int)mapRect.height()+1);
1987 pp.setRenderHints(renderHints());
1989 // Don't print the visualisation of selection
1990 xelection.unselect();
1992 mapScene->render ( &pp,
1993 QRectF(0,0,mapRect.width()+1,mapRect.height()+1),
1994 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height() ));
1996 // Restore selection
1997 xelection.reselect();
2002 void MapEditor::setHideTmpMode (HideTmpMode mode)
2005 model->setHideTmp (hidemode);
2006 model->reposition();
2010 HideTmpMode MapEditor::getHideTmpMode()
2015 void MapEditor::setExportMode (bool b)
2017 // should be called before and after exports
2018 // depending on the settings
2019 if (b && settings.value("/export/useHideExport","true")=="true")
2020 setHideTmpMode (HideExport);
2022 setHideTmpMode (HideNone);
2025 void MapEditor::exportASCII(QString fname,bool askName)
2028 ex.setModel (model);
2030 ex.setFile (mapName+".txt");
2036 //ex.addFilter ("TXT (*.txt)");
2037 ex.setDir(lastImageDir);
2038 //ex.setCaption(vymName+ " -" +tr("Export as ASCII")+" "+tr("(still experimental)"));
2043 setExportMode(true);
2045 setExportMode(false);
2049 void MapEditor::exportImage(QString fname, bool askName, QString format)
2053 fname=mapName+".png";
2060 QFileDialog *fd=new QFileDialog (this);
2061 fd->setCaption (tr("Export map as image"));
2062 fd->setDirectory (lastImageDir);
2063 fd->setFileMode(QFileDialog::AnyFile);
2064 fd->setFilters (imageIO.getFilters() );
2067 fl=fd->selectedFiles();
2069 format=imageIO.getType(fd->selectedFilter());
2073 setExportMode (true);
2074 QPixmap pix (getPixmap());
2075 pix.save(fname, format);
2076 setExportMode (false);
2079 void MapEditor::exportOOPresentation(const QString &fn, const QString &cf)
2083 ex.setModel (model);
2084 if (ex.setConfigFile(cf))
2086 setExportMode (true);
2087 ex.exportPresentation();
2088 setExportMode (false);
2092 void MapEditor::exportXHTML (const QString &dir, bool askForName)
2094 ExportXHTMLDialog dia(this);
2095 dia.setFilePath (filePath );
2096 dia.setMapName (mapName );
2098 if (dir!="") dia.setDir (dir);
2104 if (dia.exec()!=QDialog::Accepted)
2108 QDir d (dia.getDir());
2109 // Check, if warnings should be used before overwriting
2110 // the output directory
2111 if (d.exists() && d.count()>0)
2114 warn.showCancelButton (true);
2115 warn.setText(QString(
2116 "The directory %1 is not empty.\n"
2117 "Do you risk to overwrite some of its contents?").arg(d.path() ));
2118 warn.setCaption("Warning: Directory not empty");
2119 warn.setShowAgainName("mainwindow/overwrite-dir-xhtml");
2121 if (warn.exec()!=QDialog::Accepted) ok=false;
2128 exportXML (dia.getDir(),false );
2129 dia.doExport(mapName );
2130 //if (dia.hasChanged()) setChanged();
2134 void MapEditor::exportXML(QString dir, bool askForName)
2138 dir=browseDirectory(this,tr("Export XML to directory"));
2139 if (dir =="" && !reallyWriteDirectory(dir) )
2143 // Hide stuff during export, if settings want this
2144 setExportMode (true);
2146 // Create subdirectories
2149 // write to directory
2150 QString saveFile=saveToDir (dir,mapName+"-",true,model->getTotalBBox().topLeft() ,NULL);
2153 file.setName ( dir + "/"+mapName+".xml");
2154 if ( !file.open( QIODevice::WriteOnly ) )
2156 // This should neverever happen
2157 QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open %1").arg(file.name()));
2161 // Write it finally, and write in UTF8, no matter what
2162 QTextStream ts( &file );
2163 ts.setEncoding (QTextStream::UnicodeUTF8);
2167 // Now write image, too
2168 exportImage (dir+"/images/"+mapName+".png",false,"PNG");
2170 setExportMode (false);
2173 void MapEditor::clear()
2175 //cout << "ME::clear() "<<mapName.toStdString()<<endl;
2177 autosaveTimer->stop();
2178 fileChangedTimer->stop();
2182 void MapEditor::copy()
2184 LinkableMapObj *sel=xelection.single();
2187 if (redosAvail == 0)
2190 QString s=model->getSelectString(sel);
2191 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy selection to clipboard",sel );
2192 curClipboard=curStep;
2195 // Copy also to global clipboard, because we are at last step in history
2196 QString bakMapName(QString("history-%1").arg(curStep));
2197 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2198 copyDir (bakMapDir,clipboardDir );
2200 clipboardEmpty=false;
2205 void MapEditor::redo()
2207 // Can we undo at all?
2208 if (redosAvail<1) return;
2210 bool blockSaveStateOrg=blockSaveState;
2211 blockSaveState=true;
2215 if (undosAvail<stepsTotal) undosAvail++;
2217 if (curStep>stepsTotal) curStep=1;
2218 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2219 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2220 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2221 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2222 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2223 QString version=undoSet.readEntry ("/history/version");
2225 /* TODO Maybe check for version, if we save the history
2226 if (!checkVersion(version))
2227 QMessageBox::warning(0,tr("Warning"),
2228 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2231 // Find out current undo directory
2232 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2236 cout << "ME::redo() begin\n";
2237 cout << " undosAvail="<<undosAvail<<endl;
2238 cout << " redosAvail="<<redosAvail<<endl;
2239 cout << " curStep="<<curStep<<endl;
2240 cout << " ---------------------------"<<endl;
2241 cout << " comment="<<comment.toStdString()<<endl;
2242 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2243 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2244 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2245 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2246 cout << " ---------------------------"<<endl<<endl;
2249 // select object before redo
2250 if (!redoSelection.isEmpty())
2251 select (redoSelection);
2254 parseAtom (redoCommand);
2255 model->reposition();
2257 blockSaveState=blockSaveStateOrg;
2259 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2260 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2261 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2262 undoSet.writeSettings(histPath);
2264 mainWindow->updateHistory (undoSet);
2267 /* TODO remove testing
2268 cout << "ME::redo() end\n";
2269 cout << " undosAvail="<<undosAvail<<endl;
2270 cout << " redosAvail="<<redosAvail<<endl;
2271 cout << " curStep="<<curStep<<endl;
2272 cout << " ---------------------------"<<endl<<endl;
2278 bool MapEditor::isRedoAvailable()
2280 if (undoSet.readNumEntry("/history/redosAvail",0)>0)
2286 void MapEditor::undo()
2288 // Can we undo at all?
2289 if (undosAvail<1) return;
2291 mainWindow->statusMessage (tr("Autosave disabled during undo."));
2293 bool blockSaveStateOrg=blockSaveState;
2294 blockSaveState=true;
2296 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2297 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2298 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2299 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2300 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2301 QString version=undoSet.readEntry ("/history/version");
2303 /* TODO Maybe check for version, if we save the history
2304 if (!checkVersion(version))
2305 QMessageBox::warning(0,tr("Warning"),
2306 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2309 // Find out current undo directory
2310 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2312 // select object before undo
2313 if (!undoSelection.isEmpty())
2314 select (undoSelection);
2318 cout << "ME::undo() begin\n";
2319 cout << " undosAvail="<<undosAvail<<endl;
2320 cout << " redosAvail="<<redosAvail<<endl;
2321 cout << " curStep="<<curStep<<endl;
2322 cout << " ---------------------------"<<endl;
2323 cout << " comment="<<comment.toStdString()<<endl;
2324 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2325 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2326 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2327 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2328 cout << " ---------------------------"<<endl<<endl;
2330 parseAtom (undoCommand);
2331 model->reposition();
2335 if (curStep<1) curStep=stepsTotal;
2339 blockSaveState=blockSaveStateOrg;
2340 /* TODO remove testing
2341 cout << "ME::undo() end\n";
2342 cout << " undosAvail="<<undosAvail<<endl;
2343 cout << " redosAvail="<<redosAvail<<endl;
2344 cout << " curStep="<<curStep<<endl;
2345 cout << " ---------------------------"<<endl<<endl;
2348 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2349 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2350 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2351 undoSet.writeSettings(histPath);
2353 mainWindow->updateHistory (undoSet);
2356 ensureSelectionVisible();
2359 bool MapEditor::isUndoAvailable()
2361 if (undoSet.readNumEntry("/history/undosAvail",0)>0)
2367 void MapEditor::gotoHistoryStep (int i)
2369 // Restore variables
2370 int undosAvail=undoSet.readNumEntry (QString("/history/undosAvail"));
2371 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
2373 if (i<0) i=undosAvail+redosAvail;
2375 // Clicking above current step makes us undo things
2378 for (int j=0; j<undosAvail-i; j++) undo();
2381 // Clicking below current step makes us redo things
2383 for (int j=undosAvail; j<i; j++)
2385 if (debug) cout << "ME::gotoHistoryStep redo "<<j<<"/"<<undosAvail<<" i="<<i<<endl;
2389 // And ignore clicking the current row ;-)
2392 void MapEditor::addMapReplaceInt(const QString &undoSel, const QString &path)
2394 QString pathDir=path.left(path.findRev("/"));
2400 // We need to parse saved XML data
2401 parseVYMHandler handler;
2402 QXmlInputSource source( file);
2403 QXmlSimpleReader reader;
2404 reader.setContentHandler( &handler );
2405 reader.setErrorHandler( &handler );
2406 handler.setModel ( model);
2407 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2408 if (undoSel.isEmpty())
2412 handler.setLoadMode (NewMap);
2416 handler.setLoadMode (ImportReplace);
2418 blockReposition=true;
2419 bool ok = reader.parse( source );
2420 blockReposition=false;
2423 // This should never ever happen
2424 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2425 handler.errorProtocol());
2428 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2431 void MapEditor::addMapInsertInt (const QString &path, int pos)
2433 BranchObj *sel=xelection.getBranch();
2436 QString pathDir=path.left(path.findRev("/"));
2442 // We need to parse saved XML data
2443 parseVYMHandler handler;
2444 QXmlInputSource source( file);
2445 QXmlSimpleReader reader;
2446 reader.setContentHandler( &handler );
2447 reader.setErrorHandler( &handler );
2448 handler.setModel (model);
2449 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2450 handler.setLoadMode (ImportAdd);
2451 blockReposition=true;
2452 bool ok = reader.parse( source );
2453 blockReposition=false;
2456 // This should never ever happen
2457 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2458 handler.errorProtocol());
2460 if (sel->getDepth()>0)
2461 sel->getLastBranch()->linkTo (sel,pos);
2463 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2467 void MapEditor::pasteNoSave(const int &n)
2469 bool old=blockSaveState;
2470 blockSaveState=true;
2471 bool zippedOrg=zipped;
2472 if (redosAvail > 0 || n!=0)
2474 // Use the "historical" buffer
2475 QString bakMapName(QString("history-%1").arg(n));
2476 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2477 load (bakMapDir+"/"+clipboardFile,ImportAdd, VymMap);
2479 // Use the global buffer
2480 load (clipboardDir+"/"+clipboardFile,ImportAdd, VymMap);
2485 void MapEditor::paste()
2487 BranchObj *sel=xelection.getBranch();
2490 saveStateChangingPart(
2493 QString ("paste (%1)").arg(curClipboard),
2494 QString("Paste to %1").arg( getName(sel))
2497 model->reposition();
2501 void MapEditor::cut()
2503 LinkableMapObj *sel=xelection.single();
2504 if ( sel && (xelection.type() == Selection::Branch ||
2505 xelection.type()==Selection::MapCenter ||
2506 xelection.type()==Selection::FloatImage))
2508 /* No savestate! savestate is called in cutNoSave
2509 saveStateChangingPart(
2513 QString("Cut %1").arg(getName(sel ))
2518 model->reposition();
2522 void MapEditor::move(const double &x, const double &y)
2524 LinkableMapObj *sel=xelection.single();
2527 QPointF ap(sel->getAbsPos());
2531 QString ps=qpointfToString(ap);
2532 QString s=xelection.getSelectString();
2535 s, "move "+qpointfToString(to),
2536 QString("Move %1 to %2").arg(getName(sel)).arg(ps));
2538 model->reposition();
2544 void MapEditor::moveRel (const double &x, const double &y)
2546 LinkableMapObj *sel=xelection.single();
2549 QPointF rp(sel->getRelPos());
2553 QString ps=qpointfToString (sel->getRelPos());
2554 QString s=model->getSelectString(sel);
2557 s, "moveRel "+qpointfToString(to),
2558 QString("Move %1 to relative position %2").arg(getName(sel)).arg(ps));
2559 ((OrnamentedObj*)sel)->move2RelPos (x,y);
2560 model->reposition();
2567 void MapEditor::moveBranchUp()
2569 BranchObj* bo=xelection.getBranch();
2573 if (!bo->canMoveBranchUp()) return;
2574 par=(BranchObj*)(bo->getParObj());
2575 BranchObj *obo=par->moveBranchUp (bo); // bo will be the one below selection
2576 saveState (model->getSelectString(bo),"moveBranchDown ()",model->getSelectString(obo),"moveBranchUp ()",QString("Move up %1").arg(getName(bo)));
2577 model->reposition();
2580 ensureSelectionVisible();
2584 void MapEditor::moveBranchDown()
2586 BranchObj* bo=xelection.getBranch();
2590 if (!bo->canMoveBranchDown()) return;
2591 par=(BranchObj*)(bo->getParObj());
2592 BranchObj *obo=par->moveBranchDown(bo); // bo will be the one above selection
2593 saveState(model->getSelectString(bo),"moveBranchUp ()",model->getSelectString(obo),"moveBranchDown ()",QString("Move down %1").arg(getName(bo)));
2594 model->reposition();
2597 ensureSelectionVisible();
2601 void MapEditor::sortChildren()
2603 BranchObj* bo=xelection.getBranch();
2606 if(bo->countBranches()>1)
2608 saveStateChangingPart(bo,bo, "sortChildren ()",QString("Sort children of %1").arg(getName(bo)));
2610 model->reposition();
2611 ensureSelectionVisible();
2616 void MapEditor::linkTo(const QString &dstString)
2618 FloatImageObj *fio=xelection.getFloatImage();
2621 BranchObj *dst=(BranchObj*)(model->findObjBySelect(dstString));
2622 if (dst && (typeid(*dst)==typeid (BranchObj) ||
2623 typeid(*dst)==typeid (MapCenterObj)))
2625 LinkableMapObj *dstPar=dst->getParObj();
2626 QString parString=model->getSelectString(dstPar);
2627 QString fioPreSelectString=model->getSelectString(fio);
2628 QString fioPreParentSelectString=model->getSelectString (fio->getParObj());
2629 ((BranchObj*)(dst))->addFloatImage (fio);
2630 xelection.unselect();
2631 ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio);
2632 fio=((BranchObj*)(dst))->getLastFloatImage();
2635 xelection.select(fio);
2637 model->getSelectString(fio),
2638 QString("linkTo (\"%1\")").arg(fioPreParentSelectString),
2640 QString ("linkTo (\"%1\")").arg(dstString),
2641 QString ("Link floatimage to %1").arg(getName(dst)));
2646 QString MapEditor::getHeading(bool &ok, QPoint &p)
2648 BranchObj *bo=xelection.getBranch();
2652 p=mapFromScene(bo->getAbsPos());
2653 return bo->getHeading();
2659 void MapEditor::setHeading(const QString &s)
2661 BranchObj *sel=xelection.getBranch();
2666 "setHeading (\""+sel->getHeading()+"\")",
2668 "setHeading (\""+s+"\")",
2669 QString("Set heading of %1 to \"%2\"").arg(getName(sel)).arg(s) );
2670 sel->setHeading(s );
2671 model->reposition();
2673 ensureSelectionVisible();
2677 void MapEditor::setHeadingInt(const QString &s)
2679 BranchObj *bo=xelection.getBranch();
2683 model->reposition();
2685 ensureSelectionVisible();
2689 void MapEditor::setVymLinkInt (const QString &s)
2691 // Internal function, no saveState needed
2692 BranchObj *bo=xelection.getBranch();
2696 model->reposition();
2699 ensureSelectionVisible();
2703 BranchObj* MapEditor::addMapCenter ()
2705 MapCenterObj *mco= model->addMapCenter(contextMenuPos);
2706 xelection.select (mco);
2708 ensureSelectionVisible();
2713 QString ("addMapCenter (%1,%2)").arg (contextMenuPos.x()).arg(contextMenuPos.y()),
2714 QString ("Adding MapCenter to (%1,%2").arg (contextMenuPos.x()).arg(contextMenuPos.y())
2719 BranchObj* MapEditor::addNewBranchInt(int num)
2721 // Depending on pos:
2722 // -3 insert in childs of parent above selection
2723 // -2 add branch to selection
2724 // -1 insert in childs of parent below selection
2725 // 0..n insert in childs of parent at pos
2726 BranchObj *newbo=NULL;
2727 BranchObj *bo=xelection.getBranch();
2732 // save scroll state. If scrolled, automatically select
2733 // new branch in order to tmp unscroll parent...
2734 newbo=bo->addBranch();
2739 bo=(BranchObj*)bo->getParObj();
2740 if (bo) newbo=bo->insertBranch(num);
2744 bo=(BranchObj*)bo->getParObj();
2745 if (bo) newbo=bo->insertBranch(num);
2747 if (!newbo) return NULL;
2752 BranchObj* MapEditor::addNewBranch(int pos)
2754 // Different meaning than num in addNewBranchInt!
2758 BranchObj *bo = xelection.getBranch();
2759 BranchObj *newbo=NULL;
2763 setCursor (Qt::ArrowCursor);
2765 newbo=addNewBranchInt (pos-2);
2773 QString ("addBranch (%1)").arg(pos),
2774 QString ("Add new branch to %1").arg(getName(bo)));
2776 model->reposition();
2778 latestSelection=model->getSelectString(newbo);
2779 // In Network mode, the client needs to know where the new branch is,
2780 // so we have to pass on this information via saveState.
2781 // TODO: Get rid of this positioning workaround
2782 QString ps=qpointfToString (newbo->getAbsPos());
2783 sendData ("selectLatestAdded ()");
2784 sendData (QString("move %1").arg(ps));
2792 BranchObj* MapEditor::addNewBranchBefore()
2794 BranchObj *newbo=NULL;
2795 BranchObj *bo = xelection.getBranch();
2796 if (bo && xelection.type()==Selection::Branch)
2797 // We accept no MapCenterObj here, so we _have_ a parent
2799 QPointF p=bo->getRelPos();
2802 BranchObj *parbo=(BranchObj*)(bo->getParObj());
2804 // add below selection
2805 newbo=parbo->insertBranch(bo->getNum()+1);
2808 newbo->move2RelPos (p);
2810 // Move selection to new branch
2811 bo->linkTo (newbo,-1);
2813 saveState (newbo, "deleteKeepChilds ()", newbo, "addBranchBefore ()",
2814 QString ("Add branch before %1").arg(getName(bo)));
2816 model->reposition();
2820 latestSelection=xelection.getSelectString();
2824 void MapEditor::deleteSelection()
2826 BranchObj *bo = xelection.getBranch();
2827 if (bo && xelection.type()==Selection::MapCenter)
2829 // BranchObj* par=(BranchObj*)(bo->getParObj());
2830 xelection.unselect();
2831 /* FIXME Note: does saveStateRemovingPart work for MCO? (No parent!)
2832 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2834 bo=model->removeMapCenter ((MapCenterObj*)bo);
2837 xelection.select (bo);
2838 ensureSelectionVisible();
2841 model->reposition();
2844 if (bo && xelection.type()==Selection::Branch)
2846 BranchObj* par=(BranchObj*)bo->getParObj();
2847 xelection.unselect();
2848 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2849 par->removeBranch(bo);
2850 xelection.select (par);
2851 ensureSelectionVisible();
2852 model->reposition();
2853 // xelection.update();
2857 FloatImageObj *fio=xelection.getFloatImage();
2860 BranchObj* par=(BranchObj*)fio->getParObj();
2861 saveStateChangingPart(
2865 QString("Delete %1").arg(getName(fio))
2867 xelection.unselect();
2868 par->removeFloatImage(fio);
2869 xelection.select (par);
2870 model->reposition();
2872 ensureSelectionVisible();
2877 LinkableMapObj* MapEditor::getSelection()
2879 return xelection.single();
2882 BranchObj* MapEditor::getSelectedBranch()
2884 return xelection.getBranch();
2887 FloatImageObj* MapEditor::getSelectedFloatImage()
2889 return xelection.getFloatImage();
2892 void MapEditor::unselect()
2894 xelection.unselect();
2897 void MapEditor::reselect()
2899 xelection.reselect();
2902 bool MapEditor::select (const QString &s)
2904 if (xelection.select(s))
2907 ensureSelectionVisible();
2914 bool MapEditor::select (LinkableMapObj *lmo)
2916 if (xelection.select(lmo))
2919 ensureSelectionVisible();
2926 QString MapEditor::getSelectString()
2928 return xelection.getSelectString();
2931 void MapEditor::selectInt (LinkableMapObj *lmo)
2933 if (lmo && xelection.single()!= lmo && isSelectBlocked()==false )
2935 xelection.select(lmo);
2941 void MapEditor::selectNextBranchInt()
2943 // Increase number of branch
2944 LinkableMapObj *sel=xelection.single();
2947 QString s=xelection.getSelectString();
2953 part=s.section(",",-1);
2955 num=part.right(part.length() - 3);
2957 s=s.left (s.length() -num.length());
2960 num=QString ("%1").arg(num.toUInt()+1);
2964 // Try to select this one
2965 if (select (s)) return;
2967 // We have no direct successor,
2968 // try to increase the parental number in order to
2969 // find a successor with same depth
2971 int d=xelection.single()->getDepth();
2976 while (!found && d>0)
2978 s=s.section (",",0,d-1);
2979 // replace substring of current depth in s with "1"
2980 part=s.section(",",-1);
2982 num=part.right(part.length() - 3);
2986 // increase number of parent
2987 num=QString ("%1").arg(num.toUInt()+1);
2988 s=s.section (",",0,d-2) + ","+ typ+num;
2991 // Special case, look at orientation
2992 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
2993 num=QString ("%1").arg(num.toUInt()+1);
2995 num=QString ("%1").arg(num.toUInt()-1);
3000 // pad to oldDepth, select the first branch for each depth
3001 for (i=d;i<oldDepth;i++)
3006 if ( xelection.getBranch()->countBranches()>0)
3014 // try to select the freshly built string
3022 void MapEditor::selectPrevBranchInt()
3024 // Decrease number of branch
3025 BranchObj *bo=xelection.getBranch();
3028 QString s=xelection.getSelectString();
3034 part=s.section(",",-1);
3036 num=part.right(part.length() - 3);
3038 s=s.left (s.length() -num.length());
3040 int n=num.toInt()-1;
3043 num=QString ("%1").arg(n);
3046 // Try to select this one
3047 if (n>=0 && select (s)) return;
3049 // We have no direct precessor,
3050 // try to decrease the parental number in order to
3051 // find a precessor with same depth
3053 int d=xelection.single()->getDepth();
3058 while (!found && d>0)
3060 s=s.section (",",0,d-1);
3061 // replace substring of current depth in s with "1"
3062 part=s.section(",",-1);
3064 num=part.right(part.length() - 3);
3068 // decrease number of parent
3069 num=QString ("%1").arg(num.toInt()-1);
3070 s=s.section (",",0,d-2) + ","+ typ+num;
3073 // Special case, look at orientation
3074 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
3075 num=QString ("%1").arg(num.toInt()-1);
3077 num=QString ("%1").arg(num.toInt()+1);
3082 // pad to oldDepth, select the last branch for each depth
3083 for (i=d;i<oldDepth;i++)
3087 if ( xelection.getBranch()->countBranches()>0)
3088 s+=",bo:"+ QString ("%1").arg( xelection.getBranch()->countBranches()-1 );
3095 // try to select the freshly built string
3103 void MapEditor::selectUpperBranch()
3105 if (isSelectBlocked() ) return;
3107 BranchObj *bo=xelection.getBranch();
3108 if (bo && xelection.type()==Selection::Branch)
3110 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3111 selectPrevBranchInt();
3113 if (bo->getDepth()==1)
3114 selectNextBranchInt();
3116 selectPrevBranchInt();
3120 void MapEditor::selectLowerBranch()
3122 if (isSelectBlocked() ) return;
3124 BranchObj *bo=xelection.getBranch();
3125 if (bo && xelection.type()==Selection::Branch)
3127 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3128 selectNextBranchInt();
3130 if (bo->getDepth()==1)
3131 selectPrevBranchInt();
3133 selectNextBranchInt();
3138 void MapEditor::selectLeftBranch()
3140 if (isSelectBlocked() ) return;
3144 LinkableMapObj *sel=xelection.single();
3147 if (xelection.type()== Selection::MapCenter)
3149 par=xelection.getBranch();
3150 bo=par->getLastSelectedBranch();
3153 // Workaround for reselecting on left and right side
3154 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3155 bo=par->getLastBranch();
3158 bo=par->getLastBranch();
3159 xelection.select(bo);
3161 ensureSelectionVisible();
3167 par=(BranchObj*)(sel->getParObj());
3168 if (sel->getOrientation()==LinkableMapObj::RightOfCenter)
3170 if (xelection.type() == Selection::Branch ||
3171 xelection.type() == Selection::FloatImage)
3173 xelection.select(par);
3175 ensureSelectionVisible();
3180 if (xelection.type() == Selection::Branch )
3182 bo=xelection.getBranch()->getLastSelectedBranch();
3185 xelection.select(bo);
3187 ensureSelectionVisible();
3196 void MapEditor::selectRightBranch()
3198 if (isSelectBlocked() ) return;
3202 LinkableMapObj *sel=xelection.single();
3205 if (xelection.type()==Selection::MapCenter)
3207 par=xelection.getBranch();
3208 bo=par->getLastSelectedBranch();
3211 // Workaround for reselecting on left and right side
3212 if (bo->getOrientation()==LinkableMapObj::LeftOfCenter)
3213 bo=par->getFirstBranch();
3216 xelection.select(bo);
3218 ensureSelectionVisible();
3224 par=(BranchObj*)(xelection.single()->getParObj());
3225 if (xelection.single()->getOrientation()==LinkableMapObj::LeftOfCenter)
3227 if (xelection.type() == Selection::Branch ||
3228 xelection.type() == Selection::FloatImage)
3230 xelection.select(par);
3232 ensureSelectionVisible();
3237 if (xelection.type() == Selection::Branch)
3239 bo=xelection.getBranch()->getLastSelectedBranch();
3242 xelection.select(bo);
3244 ensureSelectionVisible();
3253 void MapEditor::selectFirstBranch()
3255 BranchObj *bo1=xelection.getBranch();
3260 par=(BranchObj*)(bo1->getParObj());
3262 bo2=par->getFirstBranch();
3264 xelection.select(bo2);
3266 ensureSelectionVisible();
3272 void MapEditor::selectLastBranch()
3274 BranchObj *bo1=xelection.getBranch();
3279 par=(BranchObj*)(bo1->getParObj());
3281 bo2=par->getLastBranch();
3284 xelection.select(bo2);
3286 ensureSelectionVisible();
3292 void MapEditor::selectMapBackgroundImage ()
3294 Q3FileDialog *fd=new Q3FileDialog( this);
3295 fd->setMode (Q3FileDialog::ExistingFile);
3296 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
3297 ImagePreview *p =new ImagePreview (fd);
3298 fd->setContentsPreviewEnabled( TRUE );
3299 fd->setContentsPreview( p, p );
3300 fd->setPreviewMode( Q3FileDialog::Contents );
3301 fd->setCaption(vymName+" - " +tr("Load background image"));
3302 fd->setDir (lastImageDir);
3305 if ( fd->exec() == QDialog::Accepted )
3307 // TODO selectMapBackgroundImg in QT4 use: lastImageDir=fd->directory();
3308 lastImageDir=QDir (fd->dirPath());
3309 setMapBackgroundImage (fd->selectedFile());
3313 void MapEditor::setMapBackgroundImage (const QString &fn) //FIXME missing savestate
3315 QColor oldcol=mapScene->backgroundBrush().color();
3319 QString ("setMapBackgroundImage (%1)").arg(oldcol.name()),
3321 QString ("setMapBackgroundImage (%1)").arg(col.name()),
3322 QString("Set background color of map to %1").arg(col.name()));
3325 brush.setTextureImage (QPixmap (fn));
3326 mapScene->setBackgroundBrush(brush);
3329 void MapEditor::selectMapBackgroundColor()
3331 QColor col = QColorDialog::getColor( mapScene->backgroundBrush().color(), this );
3332 if ( !col.isValid() ) return;
3333 setMapBackgroundColor( col );
3337 void MapEditor::setMapBackgroundColor(QColor col)
3339 QColor oldcol=mapScene->backgroundBrush().color();
3341 QString ("setMapBackgroundColor (\"%1\")").arg(oldcol.name()),
3342 QString ("setMapBackgroundColor (\"%1\")").arg(col.name()),
3343 QString("Set background color of map to %1").arg(col.name()));
3344 mapScene->setBackgroundBrush(col);
3347 QColor MapEditor::getMapBackgroundColor()
3349 return mapScene->backgroundBrush().color();
3352 QColor MapEditor::getCurrentHeadingColor()
3354 BranchObj *bo=xelection.getBranch();
3355 if (bo) return bo->getColor();
3357 QMessageBox::warning(0,tr("Warning"),tr("Can't get color of heading,\nthere's no branch selected"));
3361 void MapEditor::colorBranch (QColor c)
3363 BranchObj *bo=xelection.getBranch();
3368 QString ("colorBranch (\"%1\")").arg(bo->getColor().name()),
3370 QString ("colorBranch (\"%1\")").arg(c.name()),
3371 QString("Set color of %1 to %2").arg(getName(bo)).arg(c.name())
3373 bo->setColor(c); // color branch
3377 void MapEditor::colorSubtree (QColor c)
3379 BranchObj *bo=xelection.getBranch();
3382 saveStateChangingPart(
3385 QString ("colorSubtree (\"%1\")").arg(c.name()),
3386 QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(c.name())
3388 bo->setColorSubtree (c); // color links, color childs
3393 void MapEditor::toggleStandardFlag(QString f)
3395 BranchObj *bo=xelection.getBranch();
3399 if (bo->isSetStandardFlag(f))
3411 QString("%1 (\"%2\")").arg(u).arg(f),
3413 QString("%1 (\"%2\")").arg(r).arg(f),
3414 QString("Toggling standard flag \"%1\" of %2").arg(f).arg(getName(bo)));
3415 bo->toggleStandardFlag (f,mainWindow->useFlagGroups());
3421 BranchObj* MapEditor::findText (QString s, bool cs)
3423 QTextDocument::FindFlags flags=0;
3424 if (cs) flags=QTextDocument::FindCaseSensitively;
3427 { // Nothing found or new find process
3429 // nothing found, start again
3431 itFind=model->first();
3433 bool searching=true;
3434 bool foundNote=false;
3435 while (searching && !EOFind)
3439 // Searching in Note
3440 if (itFind->getNote().contains(s,cs))
3442 if (xelection.single()!=itFind)
3444 xelection.select(itFind);
3445 ensureSelectionVisible();
3447 if (textEditor->findText(s,flags))
3453 // Searching in Heading
3454 if (searching && itFind->getHeading().contains (s,cs) )
3456 xelection.select(itFind);
3457 ensureSelectionVisible();
3463 itFind=model->next(itFind);
3464 if (!itFind) EOFind=true;
3466 //cout <<"still searching... "<<qPrintable( itFind->getHeading())<<endl;
3469 return xelection.getBranch();
3474 void MapEditor::findReset()
3475 { // Necessary if text to find changes during a find process
3479 void MapEditor::setURL(const QString &url)
3481 BranchObj *bo=xelection.getBranch();
3484 QString oldurl=bo->getURL();
3488 QString ("setURL (\"%1\")").arg(oldurl),
3490 QString ("setURL (\"%1\")").arg(url),
3491 QString ("set URL of %1 to %2").arg(getName(bo)).arg(url)
3494 model->reposition();
3496 ensureSelectionVisible();
3500 void MapEditor::editURL()
3502 BranchObj *bo=xelection.getBranch();
3506 QString text = QInputDialog::getText(
3507 "VYM", tr("Enter URL:"), QLineEdit::Normal,
3508 bo->getURL(), &ok, this );
3510 // user entered something and pressed OK
3515 void MapEditor::editLocalURL()
3517 BranchObj *bo=xelection.getBranch();
3520 QStringList filters;
3521 filters <<"All files (*)";
3522 filters << tr("Text","Filedialog") + " (*.txt)";
3523 filters << tr("Spreadsheet","Filedialog") + " (*.odp,*.sxc)";
3524 filters << tr("Textdocument","Filedialog") +" (*.odw,*.sxw)";
3525 filters << tr("Images","Filedialog") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)";
3526 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Set URL to a local file"));
3527 fd->setFilters (filters);
3528 fd->setCaption(vymName+" - " +tr("Set URL to a local file"));
3529 fd->setDirectory (lastFileDir);
3530 if (! bo->getVymLink().isEmpty() )
3531 fd->selectFile( bo->getURL() );
3534 if ( fd->exec() == QDialog::Accepted )
3536 lastFileDir=QDir (fd->directory().path());
3537 setURL (fd->selectedFile() );
3542 QString MapEditor::getURL()
3544 BranchObj *bo=xelection.getBranch();
3546 return bo->getURL();
3551 QStringList MapEditor::getURLs()
3554 BranchObj *bo=xelection.getBranch();
3560 if (!bo->getURL().isEmpty()) urls.append( bo->getURL());
3568 void MapEditor::editHeading2URL()
3570 BranchObj *bo=xelection.getBranch();
3572 setURL (bo->getHeading());
3575 void MapEditor::editBugzilla2URL()
3577 BranchObj *bo=xelection.getBranch();
3580 QString url= "https://bugzilla.novell.com/show_bug.cgi?id="+bo->getHeading();
3585 void MapEditor::editFATE2URL()
3587 BranchObj *bo=xelection.getBranch();
3590 QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading();
3593 "setURL (\""+bo->getURL()+"\")",
3595 "setURL (\""+url+"\")",
3596 QString("Use heading of %1 as link to FATE").arg(getName(bo))
3603 void MapEditor::editVymLink()
3605 BranchObj *bo=xelection.getBranch();
3608 QStringList filters;
3609 filters <<"VYM map (*.vym)";
3610 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Link to another map"));
3611 fd->setFilters (filters);
3612 fd->setCaption(vymName+" - " +tr("Link to another map"));
3613 fd->setDirectory (lastFileDir);
3614 if (! bo->getVymLink().isEmpty() )
3615 fd->selectFile( bo->getVymLink() );
3619 if ( fd->exec() == QDialog::Accepted )
3621 lastFileDir=QDir (fd->directory().path());
3624 "setVymLink (\""+bo->getVymLink()+"\")",
3626 "setVymLink (\""+fd->selectedFile()+"\")",
3627 QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())
3629 setVymLinkInt (fd->selectedFile() );
3634 void MapEditor::deleteVymLink()
3636 BranchObj *bo=xelection.getBranch();
3641 "setVymLink (\""+bo->getVymLink()+"\")",
3643 "setVymLink (\"\")",
3644 QString("Unset vymlink of %1").arg(getName(bo))
3646 bo->setVymLink ("" );
3648 model->reposition();
3653 void MapEditor::setHideExport(bool b)
3655 BranchObj *bo=xelection.getBranch();
3658 bo->setHideInExport (b);
3659 QString u= b ? "false" : "true";
3660 QString r=!b ? "false" : "true";
3664 QString ("setHideExport (%1)").arg(u),
3666 QString ("setHideExport (%1)").arg(r),
3667 QString ("Set HideExport flag of %1 to %2").arg(getName(bo)).arg (r)
3670 model->reposition();
3676 void MapEditor::toggleHideExport()
3678 BranchObj *bo=xelection.getBranch();
3680 setHideExport ( !bo->hideInExport() );
3683 QString MapEditor::getVymLink()
3685 BranchObj *bo=xelection.getBranch();
3687 return bo->getVymLink();
3693 QStringList MapEditor::getVymLinks()
3696 BranchObj *bo=xelection.getBranch();
3702 if (!bo->getVymLink().isEmpty()) links.append( bo->getVymLink());
3710 void MapEditor::deleteKeepChilds()
3712 BranchObj *bo=xelection.getBranch();
3716 par=(BranchObj*)(bo->getParObj());
3718 // Don't use this on mapcenter
3721 // Check if we have childs at all to keep
3722 if (bo->countBranches()==0)
3728 QPointF p=bo->getRelPos();
3729 saveStateChangingPart(
3732 "deleteKeepChilds ()",
3733 QString("Remove %1 and keep its childs").arg(getName(bo))
3736 QString sel=model->getSelectString(bo);
3738 par->removeBranchHere(bo);
3739 model->reposition();
3741 xelection.getBranch()->move2RelPos (p);
3742 model->reposition();
3746 void MapEditor::deleteChilds()
3748 BranchObj *bo=xelection.getBranch();
3751 saveStateChangingPart(
3755 QString( "Remove childs of branch %1").arg(getName(bo))
3758 model->reposition();
3762 void MapEditor::editMapInfo()
3764 ExtraInfoDialog dia;
3765 dia.setMapName (getFileName() );
3766 dia.setAuthor (model->getAuthor() );
3767 dia.setComment(model->getComment() );
3771 stats+=tr("%1 items on map\n","Info about map").arg (mapScene->items().size(),6);
3781 if (!bo->getNote().isEmpty() ) n++;
3782 f+= bo->countFloatImages();
3784 xl+=bo->countXLinks();
3787 stats+=QString ("%1 branches\n").arg (b-1,6);
3788 stats+=QString ("%1 xLinks \n").arg (xl,6);
3789 stats+=QString ("%1 notes\n").arg (n,6);
3790 stats+=QString ("%1 images\n").arg (f,6);
3791 dia.setStats (stats);
3793 // Finally show dialog
3794 if (dia.exec() == QDialog::Accepted)
3796 setMapAuthor (dia.getAuthor() );
3797 setMapComment (dia.getComment() );
3801 void MapEditor::ensureSelectionVisible()
3803 LinkableMapObj *lmo=xelection.single();
3804 if (lmo) ensureVisible (lmo->getBBox() );
3808 void MapEditor::updateSelection()
3810 // Tell selection to update geometries
3814 void MapEditor::updateActions()
3816 // Tell mainwindow to update states of actions
3817 mainWindow->updateActions();
3818 // TODO maybe don't update if blockReposition is set
3821 void MapEditor::updateNoteFlag()
3824 BranchObj *bo=xelection.getBranch();
3827 bo->updateNoteFlag();
3828 mainWindow->updateActions();
3832 void MapEditor::setMapAuthor (const QString &s)
3835 QString ("setMapAuthor (\"%1\")").arg(model->getAuthor()),
3836 QString ("setMapAuthor (\"%1\")").arg(s),
3837 QString ("Set author of map to \"%1\"").arg(s)
3839 model->setAuthor (s);
3842 void MapEditor::setMapComment (const QString &s)
3845 QString ("setMapComment (\"%1\")").arg(model->getComment()),
3846 QString ("setMapComment (\"%1\")").arg(s),
3847 QString ("Set comment of map")
3849 model->setComment (s);
3852 void MapEditor::setMapLinkStyle (const QString & s)
3855 if (linkstyle==LinkableMapObj::Line)
3857 else if (linkstyle==LinkableMapObj::Parabel)
3858 snow="StyleParabel";
3859 else if (linkstyle==LinkableMapObj::PolyLine)
3860 snow="StylePolyLine";
3861 else if (linkstyle==LinkableMapObj::PolyParabel)
3862 snow="StyleParabel";
3865 QString("setMapLinkStyle (\"%1\")").arg(s),
3866 QString("setMapLinkStyle (\"%1\")").arg(snow),
3867 QString("Set map link style (\"%1\")").arg(s)
3871 linkstyle=LinkableMapObj::Line;
3872 else if (s=="StyleParabel")
3873 linkstyle=LinkableMapObj::Parabel;
3874 else if (s=="StylePolyLine")
3875 linkstyle=LinkableMapObj::PolyLine;
3877 linkstyle=LinkableMapObj::PolyParabel;
3884 bo->setLinkStyle(bo->getDefLinkStyle());
3887 model->reposition();
3890 LinkableMapObj::Style MapEditor::getMapLinkStyle ()
3895 void MapEditor::setMapDefLinkColor(QColor c)
3908 void MapEditor::setMapLinkColorHintInt()
3910 // called from setMapLinkColorHint(lch) or at end of parse
3920 void MapEditor::setMapLinkColorHint(LinkableMapObj::ColorHint lch)
3923 setMapLinkColorHintInt();
3926 void MapEditor::toggleMapLinkColorHint()
3928 if (linkcolorhint==LinkableMapObj::HeadingColor)
3929 linkcolorhint=LinkableMapObj::DefaultColor;
3931 linkcolorhint=LinkableMapObj::HeadingColor;
3941 LinkableMapObj::ColorHint MapEditor::getMapLinkColorHint()
3943 return linkcolorhint;
3946 QColor MapEditor::getMapDefLinkColor()
3948 return defLinkColor;
3951 void MapEditor::setMapDefXLinkColor(QColor col)
3956 QColor MapEditor::getMapDefXLinkColor()
3958 return defXLinkColor;
3961 void MapEditor::setMapDefXLinkWidth (int w)
3966 int MapEditor::getMapDefXLinkWidth()
3968 return defXLinkWidth;
3971 void MapEditor::selectMapLinkColor()
3973 QColor col = QColorDialog::getColor( defLinkColor, this );
3974 if ( !col.isValid() ) return;
3976 QString("setMapDefLinkColor (\"%1\")").arg(getMapDefLinkColor().name()),
3977 QString("setMapDefLinkColor (\"%1\")").arg(col.name()),
3978 QString("Set map link color to %1").arg(col.name())
3980 setMapDefLinkColor( col );
3983 void MapEditor::selectMapSelectionColor()
3985 QColor col = QColorDialog::getColor( defLinkColor, this );
3986 setSelectionColor (col);
3989 void MapEditor::setSelectionColorInt (QColor col)
3991 if ( !col.isValid() ) return;
3992 xelection.setColor (col);
3995 void MapEditor::setSelectionColor(QColor col)
3997 if ( !col.isValid() ) return;
3999 QString("setSelectionColor (%1)").arg(xelection.getColor().name()),
4000 QString("setSelectionColor (%1)").arg(col.name()),
4001 QString("Set color of selection box to %1").arg(col.name())
4003 setSelectionColorInt (col);
4006 QColor MapEditor::getSelectionColor()
4008 return xelection.getColor();
4011 bool MapEditor::scrollBranch(BranchObj *bo)
4015 if (bo->isScrolled()) return false;
4016 if (bo->countBranches()==0) return false;
4017 if (bo->getDepth()==0) return false;
4023 QString ("%1 ()").arg(u),
4025 QString ("%1 ()").arg(r),
4026 QString ("%1 %2").arg(r).arg(getName(bo))
4036 bool MapEditor::unscrollBranch(BranchObj *bo)
4040 if (!bo->isScrolled()) return false;
4041 if (bo->countBranches()==0) return false;
4042 if (bo->getDepth()==0) return false;
4048 QString ("%1 ()").arg(u),
4050 QString ("%1 ()").arg(r),
4051 QString ("%1 %2").arg(r).arg(getName(bo))
4061 void MapEditor::toggleScroll()
4063 BranchObj *bo=xelection.getBranch();
4064 if (xelection.type()==Selection::Branch )
4066 if (bo->isScrolled())
4067 unscrollBranch (bo);
4073 void MapEditor::unscrollChilds()
4075 BranchObj *bo=xelection.getBranch();
4081 if (bo->isScrolled()) unscrollBranch (bo);
4087 FloatImageObj* MapEditor::loadFloatImageInt (QString fn)
4089 BranchObj *bo=xelection.getBranch();
4093 bo->addFloatImage();
4094 fio=bo->getLastFloatImage();
4096 model->reposition();
4103 void MapEditor::loadFloatImage ()
4105 BranchObj *bo=xelection.getBranch();
4109 Q3FileDialog *fd=new Q3FileDialog( this);
4110 fd->setMode (Q3FileDialog::ExistingFiles);
4111 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
4112 ImagePreview *p =new ImagePreview (fd);
4113 fd->setContentsPreviewEnabled( TRUE );
4114 fd->setContentsPreview( p, p );
4115 fd->setPreviewMode( Q3FileDialog::Contents );
4116 fd->setCaption(vymName+" - " +tr("Load image"));
4117 fd->setDir (lastImageDir);
4120 if ( fd->exec() == QDialog::Accepted )
4122 // TODO loadFIO in QT4 use: lastImageDir=fd->directory();
4123 lastImageDir=QDir (fd->dirPath());
4126 for (int j=0; j<fd->selectedFiles().count(); j++)
4128 s=fd->selectedFiles().at(j);
4129 fio=loadFloatImageInt (s);
4132 (LinkableMapObj*)fio,
4135 QString ("loadImage (%1)").arg(s ),
4136 QString("Add image %1 to %2").arg(s).arg(getName(bo))
4139 // TODO loadFIO error handling
4140 qWarning ("Failed to load "+s);
4148 void MapEditor::saveFloatImageInt (FloatImageObj *fio, const QString &type, const QString &fn)
4150 fio->save (fn,type);
4153 void MapEditor::saveFloatImage ()
4155 FloatImageObj *fio=xelection.getFloatImage();
4158 QFileDialog *fd=new QFileDialog( this);
4159 fd->setFilters (imageIO.getFilters());
4160 fd->setCaption(vymName+" - " +tr("Save image"));
4161 fd->setFileMode( QFileDialog::AnyFile );
4162 fd->setDirectory (lastImageDir);
4163 // fd->setSelection (fio->getOriginalFilename());
4167 if ( fd->exec() == QDialog::Accepted && fd->selectedFiles().count()==1)
4169 fn=fd->selectedFiles().at(0);
4170 if (QFile (fn).exists() )
4172 QMessageBox mb( vymName,
4173 tr("The file %1 exists already.\n"
4174 "Do you want to overwrite it?").arg(fn),
4175 QMessageBox::Warning,
4176 QMessageBox::Yes | QMessageBox::Default,
4177 QMessageBox::Cancel | QMessageBox::Escape,
4178 QMessageBox::NoButton );
4180 mb.setButtonText( QMessageBox::Yes, tr("Overwrite") );
4181 mb.setButtonText( QMessageBox::No, tr("Cancel"));
4184 case QMessageBox::Yes:
4187 case QMessageBox::Cancel:
4194 saveFloatImageInt (fio,fd->selectedFilter(),fn );
4200 void MapEditor::setFrameType(const FrameObj::FrameType &t)
4202 BranchObj *bo=xelection.getBranch();
4205 QString s=bo->getFrameTypeName();
4206 bo->setFrameType (t);
4207 saveState (bo, QString("setFrameType (\"%1\")").arg(s),
4208 bo, QString ("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),QString ("set type of frame to %1").arg(s));
4209 model->reposition();
4214 void MapEditor::setFrameType(const QString &s)
4216 BranchObj *bo=xelection.getBranch();
4219 saveState (bo, QString("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),
4220 bo, QString ("setFrameType (\"%1\")").arg(s),QString ("set type of frame to %1").arg(s));
4221 bo->setFrameType (s);
4222 model->reposition();
4227 void MapEditor::setFramePenColor(const QColor &c)
4229 BranchObj *bo=xelection.getBranch();
4232 saveState (bo, QString("setFramePenColor (\"%1\")").arg(bo->getFramePenColor().name() ),
4233 bo, QString ("setFramePenColor (\"%1\")").arg(c.name() ),QString ("set pen color of frame to %1").arg(c.name() ));
4234 bo->setFramePenColor (c);
4238 void MapEditor::setFrameBrushColor(const QColor &c)
4240 BranchObj *bo=xelection.getBranch();
4243 saveState (bo, QString("setFrameBrushColor (\"%1\")").arg(bo->getFrameBrushColor().name() ),
4244 bo, QString ("setFrameBrushColor (\"%1\")").arg(c.name() ),QString ("set brush color of frame to %1").arg(c.name() ));
4245 bo->setFrameBrushColor (c);
4249 void MapEditor::setFramePadding (const int &i)
4251 BranchObj *bo=xelection.getBranch();
4254 saveState (bo, QString("setFramePadding (\"%1\")").arg(bo->getFramePadding() ),
4255 bo, QString ("setFramePadding (\"%1\")").arg(i),QString ("set brush color of frame to %1").arg(i));
4256 bo->setFramePadding (i);
4257 model->reposition();
4262 void MapEditor::setFrameBorderWidth(const int &i)
4264 BranchObj *bo=xelection.getBranch();
4267 saveState (bo, QString("setFrameBorderWidth (\"%1\")").arg(bo->getFrameBorderWidth() ),
4268 bo, QString ("setFrameBorderWidth (\"%1\")").arg(i),QString ("set border width of frame to %1").arg(i));
4269 bo->setFrameBorderWidth (i);
4270 model->reposition();
4275 void MapEditor::setIncludeImagesVer(bool b)
4277 BranchObj *bo=xelection.getBranch();
4280 QString u= b ? "false" : "true";
4281 QString r=!b ? "false" : "true";
4285 QString("setIncludeImagesVertically (%1)").arg(u),
4287 QString("setIncludeImagesVertically (%1)").arg(r),
4288 QString("Include images vertically in %1").arg(getName(bo))
4290 bo->setIncludeImagesVer(b);
4291 model->reposition();
4295 void MapEditor::setIncludeImagesHor(bool b)
4297 BranchObj *bo=xelection.getBranch();
4300 QString u= b ? "false" : "true";
4301 QString r=!b ? "false" : "true";
4305 QString("setIncludeImagesHorizontally (%1)").arg(u),
4307 QString("setIncludeImagesHorizontally (%1)").arg(r),
4308 QString("Include images horizontally in %1").arg(getName(bo))
4310 bo->setIncludeImagesHor(b);
4311 model->reposition();
4315 void MapEditor::setHideLinkUnselected (bool b)
4317 LinkableMapObj *sel=xelection.single();
4319 (xelection.type() == Selection::Branch ||
4320 xelection.type() == Selection::MapCenter ||
4321 xelection.type() == Selection::FloatImage ))
4323 QString u= b ? "false" : "true";
4324 QString r=!b ? "false" : "true";
4328 QString("setHideLinkUnselected (%1)").arg(u),
4330 QString("setHideLinkUnselected (%1)").arg(r),
4331 QString("Hide link of %1 if unselected").arg(getName(sel))
4333 sel->setHideLinkUnselected(b);
4337 void MapEditor::importDirInt(BranchObj *dst, QDir d)
4339 BranchObj *bo=xelection.getBranch();
4342 // Traverse directories
4343 d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
4344 QFileInfoList list = d.entryInfoList();
4347 for (int i = 0; i < list.size(); ++i)
4350 if (fi.fileName() != "." && fi.fileName() != ".." )
4353 bo=dst->getLastBranch();
4354 bo->setHeading (fi.fileName() );
4355 bo->setColor (QColor("blue"));
4357 if ( !d.cd(fi.fileName()) )
4358 QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory %1").arg(fi.fileName()));
4361 // Recursively add subdirs
4362 importDirInt (bo,d);
4368 d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
4369 list = d.entryInfoList();
4371 for (int i = 0; i < list.size(); ++i)
4375 bo=dst->getLastBranch();
4376 bo->setHeading (fi.fileName() );
4377 bo->setColor (QColor("black"));
4378 if (fi.fileName().right(4) == ".vym" )
4379 bo->setVymLink (fi.filePath());
4384 void MapEditor::importDirInt (const QString &s)
4386 BranchObj *bo=xelection.getBranch();
4389 saveStateChangingPart (bo,bo,QString ("importDir (\"%1\")").arg(s),QString("Import directory structure from %1").arg(s));
4392 importDirInt (bo,d);
4396 void MapEditor::importDir()
4398 BranchObj *bo=xelection.getBranch();
4401 QStringList filters;
4402 filters <<"VYM map (*.vym)";
4403 QFileDialog *fd=new QFileDialog( this,vymName+ " - " +tr("Choose directory structure to import"));
4404 fd->setMode (QFileDialog::DirectoryOnly);
4405 fd->setFilters (filters);
4406 fd->setCaption(vymName+" - " +tr("Choose directory structure to import"));
4410 if ( fd->exec() == QDialog::Accepted )
4412 importDirInt (fd->selectedFile() );
4413 model->reposition();
4419 void MapEditor::followXLink(int i)
4421 BranchObj *bo=xelection.getBranch();
4424 bo=bo->XLinkTargetAt(i);
4427 xelection.select(bo);
4428 ensureSelectionVisible();
4433 void MapEditor::editXLink(int i) // FIXME missing saveState
4435 BranchObj *bo=xelection.getBranch();
4438 XLinkObj *xlo=bo->XLinkAt(i);
4441 EditXLinkDialog dia;
4443 dia.setSelection(bo);
4444 if (dia.exec() == QDialog::Accepted)
4446 if (dia.useSettingsGlobal() )
4448 setMapDefXLinkColor (xlo->getColor() );
4449 setMapDefXLinkWidth (xlo->getWidth() );
4451 if (dia.deleteXLink())
4452 bo->deleteXLinkAt(i);
4458 AttributeTable* MapEditor::attributeTable()
4463 void MapEditor::testFunction1()
4465 BranchObj *bo=xelection.getBranch();
4466 if (bo) model->moveAway (bo);
4468 /* TODO Hide hidden stuff temporary, maybe add this as regular function somewhere
4469 if (hidemode==HideNone)
4471 setHideTmpMode (HideExport);
4472 mapCenter->calcBBoxSizeWithChilds();
4473 QRectF totalBBox=mapCenter->getTotalBBox();
4474 QRectF mapRect=totalBBox;
4475 QCanvasRectangle *frame=NULL;
4477 cout << " map has =("<<totalBBox.x()<<","<<totalBBox.y()<<","<<totalBBox.width()<<","<<totalBBox.height()<<")\n";
4479 mapRect.setRect (totalBBox.x(), totalBBox.y(),
4480 totalBBox.width(), totalBBox.height());
4481 frame=new QCanvasRectangle (mapRect,mapScene);
4482 frame->setBrush (QColor(white));
4483 frame->setPen (QColor(black));
4484 frame->setZValue(0);
4489 setHideTmpMode (HideNone);
4491 cout <<" hidemode="<<hidemode<<endl;
4495 void MapEditor::testFunction2()
4500 if (hidemode==HideExport)
4501 setHideTmpMode (HideNone);
4503 setHideTmpMode (HideExport);
4507 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
4509 // Lineedits are already closed by preceding
4510 // mouseEvent, we don't need to close here.
4512 QPointF p = mapToScene(e->pos());
4513 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4516 { // MapObj was found
4517 if (xelection.single() != lmo)
4519 // select the MapObj
4520 xelection.select(lmo);
4523 if (xelection.getBranch() )
4525 // Context Menu on branch or mapcenter
4527 branchContextMenu->popup(e->globalPos() );
4530 if (xelection.getFloatImage() )
4532 // Context Menu on floatimage
4534 floatimageContextMenu->popup(e->globalPos() );
4538 { // No MapObj found, we are on the Canvas itself
4539 // Context Menu on scene
4542 canvasContextMenu->popup(e->globalPos() );
4547 void MapEditor::keyPressEvent(QKeyEvent* e)
4549 if (e->modifiers() & Qt::ControlModifier)
4551 switch (mainWindow->getModMode())
4553 case Main::ModModeColor:
4554 setCursor (PickColorCursor);
4556 case Main::ModModeCopy:
4557 setCursor (CopyCursor);
4559 case Main::ModModeXLink:
4560 setCursor (XLinkCursor);
4563 setCursor (Qt::ArrowCursor);
4569 void MapEditor::keyReleaseEvent(QKeyEvent* e)
4571 if (!(e->modifiers() & Qt::ControlModifier))
4572 setCursor (Qt::ArrowCursor);
4575 void MapEditor::mousePressEvent(QMouseEvent* e)
4577 // Ignore right clicks, these will go to context menus
4578 if (e->button() == Qt::RightButton )
4584 //Ignore clicks while editing heading
4585 if (isSelectBlocked() )
4591 QPointF p = mapToScene(e->pos());
4592 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4596 //Take care of system flags _or_ modifier modes
4598 if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4599 typeid(*lmo)==typeid(MapCenterObj) ))
4601 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
4602 if (!foname.isEmpty())
4604 // systemFlag clicked
4608 if (e->state() & Qt::ControlModifier)
4609 mainWindow->editOpenURLTab();
4611 mainWindow->editOpenURL();
4613 else if (foname=="vymLink")
4615 mainWindow->editOpenVymLink();
4616 // tabWidget may change, better return now
4617 // before segfaulting...
4618 } else if (foname=="note")
4619 mainWindow->windowToggleNoteEditor();
4620 else if (foname=="hideInExport")
4627 // No system flag clicked, take care of modmodes (CTRL-Click)
4628 if (e->state() & Qt::ControlModifier)
4630 if (mainWindow->getModMode()==Main::ModModeColor)
4633 setCursor (PickColorCursor);
4636 if (mainWindow->getModMode()==Main::ModModeXLink)
4638 BranchObj *bo_begin=NULL;
4640 bo_begin=(BranchObj*)(lmo);
4642 if (xelection.getBranch() )
4643 bo_begin=xelection.getBranch();
4647 linkingObj_src=bo_begin;
4648 tmpXLink=new XLinkObj (mapScene);
4649 tmpXLink->setBegin (bo_begin);
4650 tmpXLink->setEnd (p);
4651 tmpXLink->setColor(defXLinkColor);
4652 tmpXLink->setWidth(defXLinkWidth);
4653 tmpXLink->updateXLink();
4654 tmpXLink->setVisibility (true);
4658 } // End of modmodes
4662 // Select the clicked object
4665 // Left Button Move Branches
4666 if (e->button() == Qt::LeftButton )
4668 //movingObj_start.setX( p.x() - selection->x() );// TODO replaced selection->lmo here
4669 //movingObj_start.setY( p.y() - selection->y() );
4670 movingObj_start.setX( p.x() - lmo->x() );
4671 movingObj_start.setY( p.y() - lmo->y() );
4672 movingObj_orgPos.setX (lmo->x() );
4673 movingObj_orgPos.setY (lmo->y() );
4674 movingObj_orgRelPos=lmo->getRelPos();
4676 // If modMode==copy, then we want to "move" the _new_ object around
4677 // then we need the offset from p to the _old_ selection, because of tmp
4678 if (mainWindow->getModMode()==Main::ModModeCopy &&
4679 e->state() & Qt::ControlModifier)
4681 BranchObj *bo=xelection.getBranch();
4685 bo->addBranch ((BranchObj*)xelection.single());
4687 xelection.select(bo->getLastBranch());
4688 model->reposition();
4692 movingObj=xelection.single();
4694 // Middle Button Toggle Scroll
4695 // (On Mac OS X this won't work, but we still have
4696 // a button in the toolbar)
4697 if (e->button() == Qt::MidButton )
4702 { // No MapObj found, we are on the scene itself
4703 // Left Button move Pos of sceneView
4704 if (e->button() == Qt::LeftButton )
4706 movingObj=NULL; // move Content not Obj
4707 movingObj_start=e->globalPos();
4708 movingCont_start=QPointF (
4709 horizontalScrollBar()->value(),
4710 verticalScrollBar()->value());
4711 movingVec=QPointF(0,0);
4712 setCursor(HandOpenCursor);
4717 void MapEditor::mouseMoveEvent(QMouseEvent* e)
4719 QPointF p = mapToScene(e->pos());
4720 LinkableMapObj *lmosel=xelection.single();
4722 // Move the selected MapObj
4723 if ( lmosel && movingObj)
4725 // reset cursor if we are moving and don't copy
4726 if (mainWindow->getModMode()!=Main::ModModeCopy)
4727 setCursor (Qt::ArrowCursor);
4729 // To avoid jumping of the sceneView, only
4730 // ensureSelectionVisible, if not tmp linked
4731 if (!lmosel->hasParObjTmp())
4732 ensureSelectionVisible ();
4734 // Now move the selection, but add relative position
4735 // (movingObj_start) where selection was chosen with
4736 // mousepointer. (This avoids flickering resp. jumping
4737 // of selection back to absPos)
4739 // Check if we could link
4740 LinkableMapObj* lmo=model->findMapObj(p, lmosel);
4743 FloatObj *fio=xelection.getFloatImage();
4746 fio->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4748 fio->updateLink(); //no need for reposition, if we update link here
4751 // Relink float to new mapcenter or branch, if shift is pressed
4752 // Only relink, if selection really has a new parent
4753 if ( (e->modifiers()==Qt::ShiftModifier) && lmo &&
4754 ( (typeid(*lmo)==typeid(BranchObj)) ||
4755 (typeid(*lmo)==typeid(MapCenterObj)) ) &&
4756 ( lmo != fio->getParObj())
4759 if (typeid(*fio) == typeid(FloatImageObj) &&
4760 ( (typeid(*lmo)==typeid(BranchObj) ||
4761 typeid(*lmo)==typeid(MapCenterObj)) ))
4764 // Also save the move which was done so far
4765 QString pold=qpointfToString(movingObj_orgRelPos);
4766 QString pnow=qpointfToString(fio->getRelPos());
4772 QString("Move %1 to relative position %2").arg(getName(fio)).arg(pnow));
4773 fio->getParObj()->requestReposition();
4774 model->reposition();
4776 linkTo (model->getSelectString(lmo));
4778 //movingObj_orgRelPos=lmosel->getRelPos();
4780 model->reposition();
4784 { // selection != a FloatObj
4785 if (lmosel->getDepth()==0)
4788 if (e->buttons()== Qt::LeftButton && e->modifiers()==Qt::ShiftModifier)
4789 ((MapCenterObj*)lmosel)->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4791 lmosel->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4792 model->updateRelPositions();
4795 if (lmosel->getDepth()==1)
4798 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4799 lmosel->setRelPos();
4802 // Move ordinary branch
4803 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4806 // Maybe we can relink temporary?
4807 if (lmo && (lmo!=lmosel) && xelection.getBranch() &&
4808 (typeid(*lmo)==typeid(BranchObj) ||
4809 typeid(*lmo)==typeid(MapCenterObj)) )
4812 if (e->modifiers()==Qt::ControlModifier)
4814 // Special case: CTRL to link below lmo
4815 lmosel->setParObjTmp (lmo,p,+1);
4817 else if (e->modifiers()==Qt::ShiftModifier)
4818 lmosel->setParObjTmp (lmo,p,-1);
4820 lmosel->setParObjTmp (lmo,p,0);
4823 lmosel->unsetParObjTmp();
4825 // reposition subbranch
4826 lmosel->reposition();
4830 } // no FloatImageObj
4834 } // selection && moving_obj
4836 // Draw a link from one branch to another
4839 tmpXLink->setEnd (p);
4840 tmpXLink->updateXLink();
4844 if (!movingObj && !pickingColor &&!drawingLink && e->buttons() == Qt::LeftButton )
4846 QPointF p=e->globalPos();
4847 movingVec.setX(-p.x() + movingObj_start.x() );
4848 movingVec.setY(-p.y() + movingObj_start.y() );
4849 horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
4850 verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
4855 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
4857 QPointF p = mapToScene(e->pos());
4858 LinkableMapObj *dst;
4859 LinkableMapObj *lmosel=xelection.single();
4860 // Have we been picking color?
4864 setCursor (Qt::ArrowCursor);
4865 // Check if we are over another branch
4866 dst=model->findMapObj(p, NULL);
4869 if (e->state() & Qt::ShiftModifier)
4870 colorBranch (((BranchObj*)dst)->getColor());
4872 colorSubtree (((BranchObj*)dst)->getColor());
4877 // Have we been drawing a link?
4881 // Check if we are over another branch
4882 dst=model->findMapObj(p, NULL);
4885 tmpXLink->setEnd ( ((BranchObj*)(dst)) );
4886 tmpXLink->updateXLink();
4887 tmpXLink->activate(); //FIXME savestate missing
4888 //saveStateComplete(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) );
4897 // Have we been moving something?
4898 if ( lmosel && movingObj )
4900 FloatImageObj *fo=xelection.getFloatImage();
4903 // Moved FloatObj. Maybe we need to reposition
4904 QString pold=qpointfToString(movingObj_orgRelPos);
4905 QString pnow=qpointfToString(fo->getRelPos());
4911 QString("Move %1 to relative position %2").arg(getName(fo)).arg(pnow));
4913 fo->getParObj()->requestReposition();
4914 model->reposition();
4917 // Check if we are over another branch, but ignore
4918 // any found LMOs, which are FloatObjs
4919 dst=model->findMapObj(mapToScene(e->pos() ), lmosel);
4921 if (dst && (typeid(*dst)!=typeid(BranchObj) && typeid(*dst)!=typeid(MapCenterObj)))
4924 BranchObj *bo=xelection.getBranch();
4925 if (bo && bo->getDepth()==0)
4927 if (movingObj_orgPos != bo->getAbsPos())
4929 QString pold=qpointfToString(movingObj_orgPos);
4930 QString pnow=qpointfToString(bo->getAbsPos());
4936 QString("Move mapcenter %1 to position %2").arg(getName(bo)).arg(pnow));
4940 if (xelection.type() == Selection::Branch )
4941 { // A branch was moved
4943 // save the position in case we link to mapcenter
4944 QPointF savePos=QPointF (lmosel->getAbsPos() );
4946 // Reset the temporary drawn link to the original one
4947 lmosel->unsetParObjTmp();
4949 // For Redo we may need to save original selection
4950 QString preSelStr=model->getSelectString(lmosel);
4955 // We have a destination, relink to that
4957 BranchObj* bsel=xelection.getBranch();
4958 BranchObj* bdst=(BranchObj*)dst;
4960 QString preParStr=model->getSelectString (bsel->getParObj());
4961 QString preNum=QString::number (bsel->getNum(),10);
4962 QString preDstParStr;
4964 if (e->state() & Qt::ShiftModifier && dst->getParObj())
4966 preDstParStr=model->getSelectString (dst->getParObj());
4967 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum());
4969 if (e->state() & Qt::ControlModifier && dst->getParObj())
4972 preDstParStr=model->getSelectString (dst->getParObj());
4973 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum()+1);
4976 preDstParStr=model->getSelectString(dst);
4977 bsel->linkTo (bdst,-1);
4978 if (dst->getDepth()==0) bsel->move (savePos);
4980 QString postSelStr=model->getSelectString(lmosel);
4981 QString postNum=QString::number (bsel->getNum(),10);
4983 QString undoCom="linkTo (\""+
4984 preParStr+ "\"," + preNum +"," +
4985 QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")";
4987 QString redoCom="linkTo (\""+
4988 preDstParStr + "\"," + postNum + "," +
4989 QString ("%1,%2").arg(savePos.x()).arg(savePos.y())+ ")";
4994 QString("Relink %1 to %2").arg(getName(bsel)).arg(getName(dst)) );
4996 model->reposition(); // not necessary if we undo temporary move below
4999 // No destination, undo temporary move
5001 if (lmosel->getDepth()==1)
5003 // The select string might be different _after_ moving around.
5004 // Therefor reposition and then use string of old selection, too
5005 model->reposition();
5007 QPointF rp(lmosel->getRelPos());
5008 if (rp != movingObj_orgRelPos)
5010 QString ps=qpointfToString(rp);
5012 model->getSelectString(lmosel), "moveRel "+qpointfToString(movingObj_orgRelPos),
5013 preSelStr, "moveRel "+ps,
5014 QString("Move %1 to relative position %2").arg(getName(lmosel)).arg(ps));
5018 // Draw the original link, before selection was moved around
5019 if (settings.value("/animation/use",false).toBool() && lmosel->getDepth()>1)
5021 QPointF p=bo->getParObj()->getChildPos();
5022 lmosel->setRelPos(); // calc relPos first
5023 model->startAnimation(
5024 lmosel->getRelPos(),
5025 QPointF (movingObj_orgPos.x() - p.x(), movingObj_orgPos.y() - p.y() )
5028 model->reposition();
5032 // Finally resize scene, if needed
5036 // Just make sure, that actions are still ok,e.g. the move branch up/down buttons...
5039 // maybe we moved View: set old cursor
5040 setCursor (Qt::ArrowCursor);
5044 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
5046 if (isSelectBlocked() )
5052 if (e->button() == Qt::LeftButton )
5054 QPointF p = mapToScene(e->pos());
5055 LinkableMapObj *lmo=model->findMapObj(p, NULL);
5056 if (lmo) { // MapObj was found
5057 // First select the MapObj than edit heading
5058 xelection.select(lmo);
5059 mainWindow->editHeading();
5064 void MapEditor::resizeEvent (QResizeEvent* e)
5066 QGraphicsView::resizeEvent( e );
5069 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
5071 //for (unsigned int i=0;event->format(i);i++) // Debug mime type
5072 // cerr << event->format(i) << endl;
5074 if (event->mimeData()->hasImage())
5075 event->acceptProposedAction();
5077 if (event->mimeData()->hasUrls())
5078 event->acceptProposedAction();
5081 void MapEditor::dragMoveEvent(QDragMoveEvent *)
5085 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
5090 void MapEditor::dropEvent(QDropEvent *event)
5092 BranchObj *sel=xelection.getBranch();
5096 foreach (QString format,event->mimeData()->formats())
5097 cout << "MapEditor: Dropped format: "<<qPrintable (format)<<endl;
5101 if (event->mimeData()->hasImage())
5103 QVariant imageData = event->mimeData()->imageData();
5104 addFloatImageInt (qvariant_cast<QPixmap>(imageData));
5106 if (event->mimeData()->hasUrls())
5107 uris=event->mimeData()->urls();
5115 for (int i=0; i<uris.count();i++)
5117 // Workaround to avoid adding empty branches
5118 if (!uris.at(i).toString().isEmpty())
5120 bo=sel->addBranch();
5123 s=uris.at(i).toLocalFile();
5126 QString file = QDir::fromNativeSeparators(s);
5127 heading = QFileInfo(file).baseName();
5129 if (file.endsWith(".vym", false))
5130 bo->setVymLink(file);
5132 bo->setURL(uris.at(i).toString());
5135 bo->setURL(uris.at(i).toString());
5138 if (!heading.isEmpty())
5139 bo->setHeading(heading);
5141 bo->setHeading(uris.at(i).toString());
5145 model->reposition();
5148 event->acceptProposedAction();
5152 void MapEditor::sendSelection()
5154 if (netstate!=Server) return;
5155 sendData (QString("select (\"%1\")").arg(xelection.getSelectString()) );
5158 void MapEditor::newServer()
5162 tcpServer = new QTcpServer(this);
5163 if (!tcpServer->listen(QHostAddress::Any,port)) {
5164 QMessageBox::critical(this, "vym server",
5165 QString("Unable to start the server: %1.").arg(tcpServer->errorString()));
5169 connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newClient()));
5171 cout<<"Server is running on port "<<tcpServer->serverPort()<<endl;
5174 void MapEditor::connectToServer()
5177 server="salam.suse.de";
5179 clientSocket = new QTcpSocket (this);
5180 clientSocket->abort();
5181 clientSocket->connectToHost(server ,port);
5182 connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readData()));
5183 connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
5184 this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
5186 cout<<"connected to "<<qPrintable (server)<<" port "<<port<<endl;
5191 void MapEditor::newClient()
5193 QTcpSocket *newClient = tcpServer->nextPendingConnection();
5194 connect(newClient, SIGNAL(disconnected()),
5195 newClient, SLOT(deleteLater()));
5197 cout <<"ME::newClient at "<<qPrintable( newClient->peerAddress().toString() )<<endl;
5199 clientList.append (newClient);
5203 void MapEditor::sendData(const QString &s)
5205 if (clientList.size()==0) return;
5207 // Create bytearray to send
5209 QDataStream out(&block, QIODevice::WriteOnly);
5210 out.setVersion(QDataStream::Qt_4_0);
5212 // Reserve some space for blocksize
5215 // Write sendCounter
5216 out << sendCounter++;
5221 // Go back and write blocksize so far
5222 out.device()->seek(0);
5223 quint16 bs=(quint16)(block.size() - 2*sizeof(quint16));
5227 cout << "ME::sendData bs="<<bs<<" counter="<<sendCounter<<" s="<<qPrintable(s)<<endl;
5229 for (int i=0; i<clientList.size(); ++i)
5231 //cout << "Sending \""<<qPrintable (s)<<"\" to "<<qPrintable (clientList.at(i)->peerAddress().toString())<<endl;
5232 clientList.at(i)->write (block);
5236 void MapEditor::readData ()
5238 while (clientSocket->bytesAvailable() >=(int)sizeof(quint16) )
5241 cout <<"readData bytesAvail="<<clientSocket->bytesAvailable();
5245 QDataStream in(clientSocket);
5246 in.setVersion(QDataStream::Qt_4_0);
5254 cout << " t="<<qPrintable (t)<<endl;
5260 void MapEditor::displayNetworkError(QAbstractSocket::SocketError socketError)
5262 switch (socketError) {
5263 case QAbstractSocket::RemoteHostClosedError:
5265 case QAbstractSocket::HostNotFoundError:
5266 QMessageBox::information(this, vymName +" Network client",
5267 "The host was not found. Please check the "
5268 "host name and port settings.");
5270 case QAbstractSocket::ConnectionRefusedError:
5271 QMessageBox::information(this, vymName + " Network client",
5272 "The connection was refused by the peer. "
5273 "Make sure the fortune server is running, "
5274 "and check that the host name and port "
5275 "settings are correct.");
5278 QMessageBox::information(this, vymName + " Network client",
5279 QString("The following error occurred: %1.")
5280 .arg(clientSocket->errorString()));
5284 void MapEditor::autosave()
5286 QDateTime now=QDateTime().currentDateTime();
5288 cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n";
5289 cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
5290 cout << " fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
5291 cout << " time: "<<qPrintable (now.toString())<<endl;
5292 cout << " zipped="<<zipped<<endl;
5294 // Disable autosave, while we have gone back in history
5295 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
5296 if (redosAvail>0) return;
5298 // Also disable autosave for new map without filename
5299 if (filePath.isEmpty()) return;
5302 if (mapUnsaved &&mapChanged && settings.value ("/mapeditor/autosave/use",true).toBool() )
5304 if (QFileInfo(filePath).lastModified()<=fileChangedTime)
5305 mainWindow->fileSave (this);
5308 cout <<" ME::autosave rejected, file on disk is newer than last save.\n";
5312 void MapEditor::fileChanged()
5314 // Check if file on disk has changed meanwhile
5315 if (!filePath.isEmpty())
5317 QDateTime tmod=QFileInfo (filePath).lastModified();
5318 if (tmod>fileChangedTime)
5321 /* FIXME debug message, sometimes there's a glitch in the metrics...
5322 cout << "ME::fileChanged()\n"
5323 << " last saved: "<<qPrintable (fileChangedTime.toString())<<endl
5324 << " last modififed: "<<qPrintable (tmod.toString())<<endl;
5326 // FIXME switch to current mapeditor and finish lineedits...
5327 QMessageBox mb( vymName,
5328 tr("The file of the map on disk has changed:\n\n"
5329 " %1\n\nDo you want to reload that map with the new file?").arg(filePath),
5330 QMessageBox::Question,
5332 QMessageBox::Cancel | QMessageBox::Default,
5333 QMessageBox::NoButton );
5335 mb.setButtonText( QMessageBox::Yes, tr("Reload"));
5336 mb.setButtonText( QMessageBox::No, tr("Ignore"));
5339 case QMessageBox::Yes:
5341 load (filePath,NewMap,fileType);
5342 case QMessageBox::Cancel:
5343 fileChangedTime=tmod; // allow autosave to overwrite newer file!
5351 /*TODO not needed? void MapEditor::contentsDropEvent(QDropEvent *event)
5354 } else if (event->provides("application/x-moz-file-promise-url") &&
5355 event->provides("application/x-moz-nativeimage"))
5357 // Contains url to the img src in unicode16
5358 QByteArray d = event->encodedData("application/x-moz-file-promise-url");
5359 QString url = QString((const QChar*)d.data(),d.size()/2);
5363 } else if (event->provides ("text/uri-list"))
5364 { // Uris provided e.g. by konqueror
5365 Q3UriDrag::decode (event,uris);
5366 } else if (event->provides ("_NETSCAPE_URL"))
5367 { // Uris provided by Mozilla
5368 QStringList l = QStringList::split("\n", event->encodedData("_NETSCAPE_URL"));
5371 } else if (event->provides("text/html")) {
5373 // Handels text mime types
5374 // Look like firefox allways handle text as unicode16 (2 bytes per char.)
5375 QByteArray d = event->encodedData("text/html");
5378 text = QString((const QChar*)d.data(),d.size()/2);
5382 textEditor->setText(text);
5386 } else if (event->provides("text/plain")) {
5387 QByteArray d = event->encodedData("text/plain");
5390 text = QString((const QChar*)d.data(),d.size()/2);
5394 textEditor->setText(text);
5404 bool isUnicode16(const QByteArray &d)
5406 // TODO: make more precise check for unicode 16.
5407 // Guess unicode16 if any of second bytes are zero
5408 unsigned int length = max(0,d.size()-2)/2;
5409 for (unsigned int i = 0; i<length ; i++)
5410 if (d.at(i*2+1)==0) return true;
5414 void MapEditor::addFloatImageInt (const QPixmap &img)
5416 BranchObj *bo=xelection.getBranch();
5419 FloatImageObj *fio=bo->addFloatImage();
5421 fio->setOriginalFilename("No original filename (image added by dropevent)");
5422 QString s=model->getSelectString(bo);
5423 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy dropped image to clipboard",fio );
5424 saveState (fio,"delete ()", bo,QString("paste(%1)").arg(curStep),"Pasting dropped image");
5425 model->reposition();
5432 void MapEditor::imageDataFetched(const QByteArray &a, Q3NetworkOperation * / *nop* /)
5434 if (!imageBuffer) imageBuffer = new QBuffer();
5435 if (!imageBuffer->isOpen()) {
5436 imageBuffer->open(QIODevice::WriteOnly | QIODevice::Append);
5438 imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a));
5442 void MapEditor::imageDataFinished(Q3NetworkOperation *nop)
5444 if (nop->state()==Q3NetworkProtocol::StDone) {
5445 QPixmap img(imageBuffer->buffer());
5446 addFloatImageInt (img);
5450 imageBuffer->close();
5452 imageBuffer->close();
5459 void MapEditor::fetchImage(const QString &url)
5462 urlOperator->stop();
5463 disconnect(urlOperator);
5467 urlOperator = new Q3UrlOperator(url);
5468 connect(urlOperator, SIGNAL(finished(Q3NetworkOperation *)),
5469 this, SLOT(imageDataFinished(Q3NetworkOperation*)));
5471 connect(urlOperator, SIGNAL(data(const QByteArray &, Q3NetworkOperation *)),
5472 this, SLOT(imageDataFetched(const QByteArray &, Q3NetworkOperation *)));