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("branchCount", QString().number(model->countBranches())) +
306 attribut("backgroundColor", mapScene->backgroundBrush().color().name() ) +
307 attribut("selectionColor", xelection.getColor().name() ) +
308 attribut("linkStyle", ls ) +
309 attribut("linkColor", defLinkColor.name() ) +
310 attribut("defXLinkColor", defXLinkColor.name() ) +
311 attribut("defXLinkWidth", QString().setNum(defXLinkWidth,10) ) +
313 s+=beginElement("vymmap",mapAttr);
316 // Find the used flags while traversing the tree
317 standardFlagsDefault->resetUsedCounter();
319 // Reset the counters before saving
320 // TODO constr. of FIO creates lots of objects, better do this in some other way...
321 FloatImageObj (mapScene).resetSaveCounter();
323 // Build xml recursivly
324 if (!saveSel || typeid (*saveSel) == typeid (MapCenterObj))
325 // Save complete map, if saveSel not set
326 s+=model->saveToDir(tmpdir,prefix,writeflags,offset);
329 if ( typeid(*saveSel) == typeid(BranchObj) )
331 s+=((BranchObj*)saveSel)->saveToDir(tmpdir,prefix,offset);
334 if ( typeid(*saveSel) == typeid(FloatImageObj) )
336 s+=((FloatImageObj*)saveSel)->saveToDir(tmpdir,prefix);
340 // Save local settings
341 s+=settings.getDataXML (destPath);
344 if (!xelection.isEmpty() && !saveSel )
345 s+=valueElement("select",xelection.getSelectString());
348 s+=endElement("vymmap");
351 standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags);
355 QString MapEditor::getHistoryDir()
357 QString histName(QString("history-%1").arg(curStep));
358 return (tmpMapDir+"/"+histName);
361 void MapEditor::saveState(const SaveMode &savemode, const QString &undoSelection, const QString &undoCom, const QString &redoSelection, const QString &redoCom, const QString &comment, LinkableMapObj *saveSel)
363 sendData(redoCom); //FIXME testing
368 if (blockSaveState) return;
370 if (debug) cout << "ME::saveState() for "<<qPrintable (mapName)<<endl;
372 // Find out current undo directory
373 if (undosAvail<stepsTotal) undosAvail++;
375 if (curStep>stepsTotal) curStep=1;
377 QString backupXML="";
378 QString histDir=getHistoryDir();
379 QString bakMapPath=histDir+"/map.xml";
381 // Create histDir if not available
384 makeSubDirs (histDir);
386 // Save depending on how much needs to be saved
388 backupXML=saveToDir (histDir,mapName+"-",false, QPointF (),saveSel);
390 QString undoCommand="";
391 if (savemode==UndoCommand)
395 else if (savemode==PartOfMap )
398 undoCommand.replace ("PATH",bakMapPath);
401 if (!backupXML.isEmpty())
402 // Write XML Data to disk
403 saveStringToDisk (bakMapPath,backupXML);
405 // We would have to save all actions in a tree, to keep track of
406 // possible redos after a action. Possible, but we are too lazy: forget about redos.
409 // Write the current state to disk
410 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
411 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
412 undoSet.setEntry ("/history/curStep",QString::number(curStep));
413 undoSet.setEntry (QString("/history/step-%1/undoCommand").arg(curStep),undoCommand);
414 undoSet.setEntry (QString("/history/step-%1/undoSelection").arg(curStep),undoSelection);
415 undoSet.setEntry (QString("/history/step-%1/redoCommand").arg(curStep),redoCom);
416 undoSet.setEntry (QString("/history/step-%1/redoSelection").arg(curStep),redoSelection);
417 undoSet.setEntry (QString("/history/step-%1/comment").arg(curStep),comment);
418 undoSet.setEntry (QString("/history/version"),vymVersion);
419 undoSet.writeSettings(histPath);
423 // TODO remove after testing
424 //cout << " into="<< histPath.toStdString()<<endl;
425 cout << " stepsTotal="<<stepsTotal<<
426 ", undosAvail="<<undosAvail<<
427 ", redosAvail="<<redosAvail<<
428 ", curStep="<<curStep<<endl;
429 cout << " ---------------------------"<<endl;
430 cout << " comment="<<comment.toStdString()<<endl;
431 cout << " undoCom="<<undoCommand.toStdString()<<endl;
432 cout << " undoSel="<<undoSelection.toStdString()<<endl;
433 cout << " redoCom="<<redoCom.toStdString()<<endl;
434 cout << " redoSel="<<redoSelection.toStdString()<<endl;
435 if (saveSel) cout << " saveSel="<<qPrintable (model->getSelectString(saveSel))<<endl;
436 cout << " ---------------------------"<<endl;
439 mainWindow->updateHistory (undoSet);
445 void MapEditor::saveStateChangingPart(LinkableMapObj *undoSel, LinkableMapObj* redoSel, const QString &rc, const QString &comment)
447 // save the selected part of the map, Undo will replace part of map
448 QString undoSelection="";
450 undoSelection=model->getSelectString(undoSel);
452 qWarning ("MapEditor::saveStateChangingPart no undoSel given!");
453 QString redoSelection="";
455 redoSelection=model->getSelectString(undoSel);
457 qWarning ("MapEditor::saveStateChangingPart no redoSel given!");
460 saveState (PartOfMap,
461 undoSelection, "addMapReplace (\"PATH\")",
467 void MapEditor::saveStateRemovingPart(LinkableMapObj *redoSel, const QString &comment)
471 qWarning ("MapEditor::saveStateRemovingPart no redoSel given!");
474 QString undoSelection=model->getSelectString (redoSel->getParObj());
475 QString redoSelection=model->getSelectString(redoSel);
476 if (typeid(*redoSel) == typeid(BranchObj) )
478 // save the selected branch of the map, Undo will insert part of map
479 saveState (PartOfMap,
480 undoSelection, QString("addMapInsert (\"PATH\",%1)").arg(((BranchObj*)redoSel)->getNum()),
481 redoSelection, "delete ()",
488 void MapEditor::saveState(LinkableMapObj *undoSel, const QString &uc, LinkableMapObj *redoSel, const QString &rc, const QString &comment)
490 // "Normal" savestate: save commands, selections and comment
491 // so just save commands for undo and redo
492 // and use current selection
494 QString redoSelection="";
495 if (redoSel) redoSelection=model->getSelectString(redoSel);
496 QString undoSelection="";
497 if (undoSel) undoSelection=model->getSelectString(undoSel);
499 saveState (UndoCommand,
506 void MapEditor::saveState(const QString &undoSel, const QString &uc, const QString &redoSel, const QString &rc, const QString &comment)
508 // "Normal" savestate: save commands, selections and comment
509 // so just save commands for undo and redo
510 // and use current selection
511 saveState (UndoCommand,
518 void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment)
520 // "Normal" savestate applied to model (no selection needed):
521 // save commands and comment
522 saveState (UndoCommand,
530 void MapEditor::parseAtom(const QString &atom)
532 BranchObj *selb=xelection.getBranch();
538 // Split string s into command and parameters
539 parser.parseAtom (atom);
540 QString com=parser.getCommand();
543 /////////////////////////////////////////////////////////////////////
544 if (com=="addBranch")
546 if (xelection.isEmpty())
548 parser.setError (Aborted,"Nothing selected");
551 parser.setError (Aborted,"Type of selection is not a branch");
556 if (parser.checkParCount(pl))
558 if (parser.parCount()==0)
562 n=parser.parInt (ok,0);
563 if (ok ) addNewBranch (n);
567 /////////////////////////////////////////////////////////////////////
568 } else if (com=="addBranchBefore")
570 if (xelection.isEmpty())
572 parser.setError (Aborted,"Nothing selected");
575 parser.setError (Aborted,"Type of selection is not a branch");
578 if (parser.parCount()==0)
580 addNewBranchBefore ();
583 /////////////////////////////////////////////////////////////////////
584 } else if (com==QString("addMapCenter"))
586 if (parser.checkParCount(2))
588 x=parser.parDouble (ok,0);
591 y=parser.parDouble (ok,1);
592 if (ok) model->addMapCenter (QPointF(x,y));
595 /////////////////////////////////////////////////////////////////////
596 } else if (com==QString("addMapReplace"))
598 if (xelection.isEmpty())
600 parser.setError (Aborted,"Nothing selected");
603 parser.setError (Aborted,"Type of selection is not a branch");
604 } else if (parser.checkParCount(1))
606 //s=parser.parString (ok,0); // selection
607 t=parser.parString (ok,0); // path to map
608 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
609 addMapReplaceInt(model->getSelectString(selb),t);
611 /////////////////////////////////////////////////////////////////////
612 } else if (com==QString("addMapInsert"))
614 if (xelection.isEmpty())
616 parser.setError (Aborted,"Nothing selected");
619 parser.setError (Aborted,"Type of selection is not a branch");
622 if (parser.checkParCount(2))
624 t=parser.parString (ok,0); // path to map
625 n=parser.parInt(ok,1); // position
626 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
627 addMapInsertInt(t,n);
630 /////////////////////////////////////////////////////////////////////
631 } else if (com=="clearFlags")
633 if (xelection.isEmpty() )
635 parser.setError (Aborted,"Nothing selected");
638 parser.setError (Aborted,"Type of selection is not a branch");
639 } else if (parser.checkParCount(0))
641 selb->clearStandardFlags();
642 selb->updateFlagsToolbar();
644 /////////////////////////////////////////////////////////////////////
645 } else if (com=="colorBranch")
647 if (xelection.isEmpty())
649 parser.setError (Aborted,"Nothing selected");
652 parser.setError (Aborted,"Type of selection is not a branch");
653 } else if (parser.checkParCount(1))
655 QColor c=parser.parColor (ok,0);
656 if (ok) colorBranch (c);
658 /////////////////////////////////////////////////////////////////////
659 } else if (com=="colorSubtree")
661 if (xelection.isEmpty())
663 parser.setError (Aborted,"Nothing selected");
666 parser.setError (Aborted,"Type of selection is not a branch");
667 } else if (parser.checkParCount(1))
669 QColor c=parser.parColor (ok,0);
670 if (ok) colorSubtree (c);
672 /////////////////////////////////////////////////////////////////////
673 } else if (com=="copy")
675 if (xelection.isEmpty())
677 parser.setError (Aborted,"Nothing selected");
680 parser.setError (Aborted,"Type of selection is not a branch");
681 } else if (parser.checkParCount(0))
683 //FIXME missing action for copy
685 /////////////////////////////////////////////////////////////////////
686 } else if (com=="cut")
688 if (xelection.isEmpty())
690 parser.setError (Aborted,"Nothing selected");
691 } else if ( xelection.type()!=Selection::Branch &&
692 xelection.type()!=Selection::MapCenter &&
693 xelection.type()!=Selection::FloatImage )
695 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
696 } else if (parser.checkParCount(0))
700 /////////////////////////////////////////////////////////////////////
701 } else if (com=="delete")
703 if (xelection.isEmpty())
705 parser.setError (Aborted,"Nothing selected");
707 /*else if (xelection.type() != Selection::Branch && xelection.type() != Selection::FloatImage )
709 parser.setError (Aborted,"Type of selection is wrong.");
712 else if (parser.checkParCount(0))
716 /////////////////////////////////////////////////////////////////////
717 } else if (com=="deleteKeepChilds")
719 if (xelection.isEmpty())
721 parser.setError (Aborted,"Nothing selected");
724 parser.setError (Aborted,"Type of selection is not a branch");
725 } else if (parser.checkParCount(0))
729 /////////////////////////////////////////////////////////////////////
730 } else if (com=="deleteChilds")
732 if (xelection.isEmpty())
734 parser.setError (Aborted,"Nothing selected");
737 parser.setError (Aborted,"Type of selection is not a branch");
738 } else if (parser.checkParCount(0))
742 /////////////////////////////////////////////////////////////////////
743 } else if (com=="exportASCII")
747 if (parser.parCount()>=1)
748 // Hey, we even have a filename
749 fname=parser.parString(ok,0);
752 parser.setError (Aborted,"Could not read filename");
755 exportASCII (fname,false);
757 /////////////////////////////////////////////////////////////////////
758 } else if (com=="exportImage")
762 if (parser.parCount()>=2)
763 // Hey, we even have a filename
764 fname=parser.parString(ok,0);
767 parser.setError (Aborted,"Could not read filename");
770 QString format="PNG";
771 if (parser.parCount()>=2)
773 format=parser.parString(ok,1);
775 exportImage (fname,false,format);
777 /////////////////////////////////////////////////////////////////////
778 } else if (com=="exportXHTML")
782 if (parser.parCount()>=2)
783 // Hey, we even have a filename
784 fname=parser.parString(ok,1);
787 parser.setError (Aborted,"Could not read filename");
790 exportXHTML (fname,false);
792 /////////////////////////////////////////////////////////////////////
793 } else if (com=="exportXML")
797 if (parser.parCount()>=2)
798 // Hey, we even have a filename
799 fname=parser.parString(ok,1);
802 parser.setError (Aborted,"Could not read filename");
805 exportXML (fname,false);
807 /////////////////////////////////////////////////////////////////////
808 } else if (com=="importDir")
810 if (xelection.isEmpty())
812 parser.setError (Aborted,"Nothing selected");
815 parser.setError (Aborted,"Type of selection is not a branch");
816 } else if (parser.checkParCount(1))
818 s=parser.parString(ok,0);
819 if (ok) importDirInt(s);
821 /////////////////////////////////////////////////////////////////////
822 } else if (com=="linkTo")
824 if (xelection.isEmpty())
826 parser.setError (Aborted,"Nothing selected");
829 if (parser.checkParCount(4))
831 // 0 selectstring of parent
832 // 1 num in parent (for branches)
833 // 2,3 x,y of mainbranch or mapcenter
834 s=parser.parString(ok,0);
835 LinkableMapObj *dst=model->findObjBySelect (s);
838 if (typeid(*dst) == typeid(BranchObj) )
840 // Get number in parent
841 n=parser.parInt (ok,1);
844 selb->linkTo ((BranchObj*)(dst),n);
847 } else if (typeid(*dst) == typeid(MapCenterObj) )
849 selb->linkTo ((BranchObj*)(dst),-1);
850 // Get coordinates of mainbranch
851 x=parser.parDouble(ok,2);
854 y=parser.parDouble(ok,3);
864 } else if ( xelection.type() == Selection::FloatImage)
866 if (parser.checkParCount(1))
868 // 0 selectstring of parent
869 s=parser.parString(ok,0);
870 LinkableMapObj *dst=model->findObjBySelect (s);
873 if (typeid(*dst) == typeid(BranchObj) ||
874 typeid(*dst) == typeid(MapCenterObj))
875 linkTo (model->getSelectString(dst));
877 parser.setError (Aborted,"Destination is not a branch");
880 parser.setError (Aborted,"Type of selection is not a floatimage or branch");
881 /////////////////////////////////////////////////////////////////////
882 } else if (com=="loadImage")
884 if (xelection.isEmpty())
886 parser.setError (Aborted,"Nothing selected");
889 parser.setError (Aborted,"Type of selection is not a branch");
890 } else if (parser.checkParCount(1))
892 s=parser.parString(ok,0);
893 if (ok) loadFloatImageInt (s);
895 /////////////////////////////////////////////////////////////////////
896 } else if (com=="moveBranchUp")
898 if (xelection.isEmpty() )
900 parser.setError (Aborted,"Nothing selected");
903 parser.setError (Aborted,"Type of selection is not a branch");
904 } else if (parser.checkParCount(0))
908 /////////////////////////////////////////////////////////////////////
909 } else if (com=="moveBranchDown")
911 if (xelection.isEmpty() )
913 parser.setError (Aborted,"Nothing selected");
916 parser.setError (Aborted,"Type of selection is not a branch");
917 } else if (parser.checkParCount(0))
921 /////////////////////////////////////////////////////////////////////
922 } else if (com=="move")
924 if (xelection.isEmpty() )
926 parser.setError (Aborted,"Nothing selected");
927 } else if ( xelection.type()!=Selection::Branch &&
928 xelection.type()!=Selection::MapCenter &&
929 xelection.type()!=Selection::FloatImage )
931 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
932 } else if (parser.checkParCount(2))
934 x=parser.parDouble (ok,0);
937 y=parser.parDouble (ok,1);
941 /////////////////////////////////////////////////////////////////////
942 } else if (com=="moveRel")
944 if (xelection.isEmpty() )
946 parser.setError (Aborted,"Nothing selected");
947 } else if ( xelection.type()!=Selection::Branch &&
948 xelection.type()!=Selection::MapCenter &&
949 xelection.type()!=Selection::FloatImage )
951 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
952 } else if (parser.checkParCount(2))
954 x=parser.parDouble (ok,0);
957 y=parser.parDouble (ok,1);
958 if (ok) moveRel (x,y);
961 /////////////////////////////////////////////////////////////////////
962 } else if (com=="nop")
964 /////////////////////////////////////////////////////////////////////
965 } else if (com=="paste")
967 if (xelection.isEmpty() )
969 parser.setError (Aborted,"Nothing selected");
972 parser.setError (Aborted,"Type of selection is not a branch");
973 } else if (parser.checkParCount(1))
975 n=parser.parInt (ok,0);
976 if (ok) pasteNoSave(n);
978 /////////////////////////////////////////////////////////////////////
979 } else if (com=="qa")
981 if (xelection.isEmpty() )
983 parser.setError (Aborted,"Nothing selected");
986 parser.setError (Aborted,"Type of selection is not a branch");
987 } else if (parser.checkParCount(4))
990 c=parser.parString (ok,0);
993 parser.setError (Aborted,"No comment given");
996 s=parser.parString (ok,1);
999 parser.setError (Aborted,"First parameter is not a string");
1002 t=parser.parString (ok,2);
1005 parser.setError (Aborted,"Condition is not a string");
1008 u=parser.parString (ok,3);
1011 parser.setError (Aborted,"Third parameter is not a string");
1016 parser.setError (Aborted,"Unknown type: "+s);
1021 parser.setError (Aborted,"Unknown operator: "+t);
1026 parser.setError (Aborted,"Type of selection is not a branch");
1029 if (selb->getHeading() == u)
1031 cout << "PASSED: " << qPrintable (c) << endl;
1034 cout << "FAILED: " << qPrintable (c) << endl;
1044 /////////////////////////////////////////////////////////////////////
1045 } else if (com=="saveImage")
1047 FloatImageObj *fio=xelection.getFloatImage();
1050 parser.setError (Aborted,"Type of selection is not an image");
1051 } else if (parser.checkParCount(2))
1053 s=parser.parString(ok,0);
1056 t=parser.parString(ok,1);
1057 if (ok) saveFloatImageInt (fio,t,s);
1060 /////////////////////////////////////////////////////////////////////
1061 } else if (com=="scroll")
1063 if (xelection.isEmpty() )
1065 parser.setError (Aborted,"Nothing selected");
1068 parser.setError (Aborted,"Type of selection is not a branch");
1069 } else if (parser.checkParCount(0))
1071 if (!scrollBranch (selb))
1072 parser.setError (Aborted,"Could not scroll branch");
1074 /////////////////////////////////////////////////////////////////////
1075 } else if (com=="select")
1077 if (parser.checkParCount(1))
1079 s=parser.parString(ok,0);
1082 /////////////////////////////////////////////////////////////////////
1083 } else if (com=="selectLastBranch")
1085 if (xelection.isEmpty() )
1087 parser.setError (Aborted,"Nothing selected");
1090 parser.setError (Aborted,"Type of selection is not a branch");
1091 } else if (parser.checkParCount(0))
1093 BranchObj *bo=selb->getLastBranch();
1095 parser.setError (Aborted,"Could not select last branch");
1099 /////////////////////////////////////////////////////////////////////
1100 } else if (com=="selectLastImage")
1102 if (xelection.isEmpty() )
1104 parser.setError (Aborted,"Nothing selected");
1107 parser.setError (Aborted,"Type of selection is not a branch");
1108 } else if (parser.checkParCount(0))
1110 FloatImageObj *fio=selb->getLastFloatImage();
1112 parser.setError (Aborted,"Could not select last image");
1116 /////////////////////////////////////////////////////////////////////
1117 } else if (com=="selectLatestAdded")
1119 if (latestSelection.isEmpty() )
1121 parser.setError (Aborted,"No latest added object");
1124 if (!select (latestSelection))
1125 parser.setError (Aborted,"Could not select latest added object "+latestSelection);
1127 /////////////////////////////////////////////////////////////////////
1128 } else if (com=="setFrameType")
1130 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1132 parser.setError (Aborted,"Type of selection does not allow setting frame type");
1134 else if (parser.checkParCount(1))
1136 s=parser.parString(ok,0);
1137 if (ok) setFrameType (s);
1139 /////////////////////////////////////////////////////////////////////
1140 } else if (com=="setFramePenColor")
1142 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1144 parser.setError (Aborted,"Type of selection does not allow setting of pen color");
1146 else if (parser.checkParCount(1))
1148 QColor c=parser.parColor(ok,0);
1149 if (ok) setFramePenColor (c);
1151 /////////////////////////////////////////////////////////////////////
1152 } else if (com=="setFrameBrushColor")
1154 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1156 parser.setError (Aborted,"Type of selection does not allow setting brush color");
1158 else if (parser.checkParCount(1))
1160 QColor c=parser.parColor(ok,0);
1161 if (ok) setFrameBrushColor (c);
1163 /////////////////////////////////////////////////////////////////////
1164 } else if (com=="setFramePadding")
1166 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1168 parser.setError (Aborted,"Type of selection does not allow setting frame padding");
1170 else if (parser.checkParCount(1))
1172 n=parser.parInt(ok,0);
1173 if (ok) setFramePadding(n);
1175 /////////////////////////////////////////////////////////////////////
1176 } else if (com=="setFrameBorderWidth")
1178 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1180 parser.setError (Aborted,"Type of selection does not allow setting frame border width");
1182 else if (parser.checkParCount(1))
1184 n=parser.parInt(ok,0);
1185 if (ok) setFrameBorderWidth (n);
1187 /////////////////////////////////////////////////////////////////////
1188 } else if (com=="setMapAuthor")
1190 if (parser.checkParCount(1))
1192 s=parser.parString(ok,0);
1193 if (ok) setMapAuthor (s);
1195 /////////////////////////////////////////////////////////////////////
1196 } else if (com=="setMapComment")
1198 if (parser.checkParCount(1))
1200 s=parser.parString(ok,0);
1201 if (ok) setMapComment(s);
1203 /////////////////////////////////////////////////////////////////////
1204 } else if (com=="setMapBackgroundColor")
1206 if (xelection.isEmpty() )
1208 parser.setError (Aborted,"Nothing selected");
1209 } else if (! xelection.getBranch() )
1211 parser.setError (Aborted,"Type of selection is not a branch");
1212 } else if (parser.checkParCount(1))
1214 QColor c=parser.parColor (ok,0);
1215 if (ok) setMapBackgroundColor (c);
1217 /////////////////////////////////////////////////////////////////////
1218 } else if (com=="setMapDefLinkColor")
1220 if (xelection.isEmpty() )
1222 parser.setError (Aborted,"Nothing selected");
1225 parser.setError (Aborted,"Type of selection is not a branch");
1226 } else if (parser.checkParCount(1))
1228 QColor c=parser.parColor (ok,0);
1229 if (ok) setMapDefLinkColor (c);
1231 /////////////////////////////////////////////////////////////////////
1232 } else if (com=="setMapLinkStyle")
1234 if (parser.checkParCount(1))
1236 s=parser.parString (ok,0);
1237 if (ok) setMapLinkStyle(s);
1239 /////////////////////////////////////////////////////////////////////
1240 } else if (com=="setHeading")
1242 if (xelection.isEmpty() )
1244 parser.setError (Aborted,"Nothing selected");
1247 parser.setError (Aborted,"Type of selection is not a branch");
1248 } else if (parser.checkParCount(1))
1250 s=parser.parString (ok,0);
1254 /////////////////////////////////////////////////////////////////////
1255 } else if (com=="setHideExport")
1257 if (xelection.isEmpty() )
1259 parser.setError (Aborted,"Nothing selected");
1260 } else if (xelection.type()!=Selection::Branch && xelection.type() != Selection::MapCenter &&xelection.type()!=Selection::FloatImage)
1262 parser.setError (Aborted,"Type of selection is not a branch or floatimage");
1263 } else if (parser.checkParCount(1))
1265 b=parser.parBool(ok,0);
1266 if (ok) setHideExport (b);
1268 /////////////////////////////////////////////////////////////////////
1269 } else if (com=="setIncludeImagesHorizontally")
1271 if (xelection.isEmpty() )
1273 parser.setError (Aborted,"Nothing selected");
1276 parser.setError (Aborted,"Type of selection is not a branch");
1277 } else if (parser.checkParCount(1))
1279 b=parser.parBool(ok,0);
1280 if (ok) setIncludeImagesHor(b);
1282 /////////////////////////////////////////////////////////////////////
1283 } else if (com=="setIncludeImagesVertically")
1285 if (xelection.isEmpty() )
1287 parser.setError (Aborted,"Nothing selected");
1290 parser.setError (Aborted,"Type of selection is not a branch");
1291 } else if (parser.checkParCount(1))
1293 b=parser.parBool(ok,0);
1294 if (ok) setIncludeImagesVer(b);
1296 /////////////////////////////////////////////////////////////////////
1297 } else if (com=="setHideLinkUnselected")
1299 if (xelection.isEmpty() )
1301 parser.setError (Aborted,"Nothing selected");
1302 } else if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1304 parser.setError (Aborted,"Type of selection does not allow hiding the link");
1305 } else if (parser.checkParCount(1))
1307 b=parser.parBool(ok,0);
1308 if (ok) setHideLinkUnselected(b);
1310 /////////////////////////////////////////////////////////////////////
1311 } else if (com=="setSelectionColor")
1313 if (parser.checkParCount(1))
1315 QColor c=parser.parColor (ok,0);
1316 if (ok) setSelectionColorInt (c);
1318 /////////////////////////////////////////////////////////////////////
1319 } else if (com=="setURL")
1321 if (xelection.isEmpty() )
1323 parser.setError (Aborted,"Nothing selected");
1326 parser.setError (Aborted,"Type of selection is not a branch");
1327 } else if (parser.checkParCount(1))
1329 s=parser.parString (ok,0);
1332 /////////////////////////////////////////////////////////////////////
1333 } else if (com=="setVymLink")
1335 if (xelection.isEmpty() )
1337 parser.setError (Aborted,"Nothing selected");
1340 parser.setError (Aborted,"Type of selection is not a branch");
1341 } else if (parser.checkParCount(1))
1343 s=parser.parString (ok,0);
1344 if (ok) setVymLinkInt(s);
1347 /////////////////////////////////////////////////////////////////////
1348 else if (com=="setFlag")
1350 if (xelection.isEmpty() )
1352 parser.setError (Aborted,"Nothing selected");
1355 parser.setError (Aborted,"Type of selection is not a branch");
1356 } else if (parser.checkParCount(1))
1358 s=parser.parString(ok,0);
1361 selb->activateStandardFlag(s);
1362 selb->updateFlagsToolbar();
1365 /////////////////////////////////////////////////////////////////////
1366 } else if (com=="setFrameType")
1368 if (xelection.isEmpty() )
1370 parser.setError (Aborted,"Nothing selected");
1373 parser.setError (Aborted,"Type of selection is not a branch");
1374 } else if (parser.checkParCount(1))
1376 s=parser.parString(ok,0);
1380 /////////////////////////////////////////////////////////////////////
1381 } else if (com=="sortChildren")
1383 if (xelection.isEmpty() )
1385 parser.setError (Aborted,"Nothing selected");
1388 parser.setError (Aborted,"Type of selection is not a branch");
1389 } else if (parser.checkParCount(0))
1393 /////////////////////////////////////////////////////////////////////
1394 } else if (com=="toggleFlag")
1396 if (xelection.isEmpty() )
1398 parser.setError (Aborted,"Nothing selected");
1401 parser.setError (Aborted,"Type of selection is not a branch");
1402 } else if (parser.checkParCount(1))
1404 s=parser.parString(ok,0);
1407 selb->toggleStandardFlag(s);
1408 selb->updateFlagsToolbar();
1411 /////////////////////////////////////////////////////////////////////
1412 } else if (com=="unscroll")
1414 if (xelection.isEmpty() )
1416 parser.setError (Aborted,"Nothing selected");
1419 parser.setError (Aborted,"Type of selection is not a branch");
1420 } else if (parser.checkParCount(0))
1422 if (!unscrollBranch (selb))
1423 parser.setError (Aborted,"Could not unscroll branch");
1425 /////////////////////////////////////////////////////////////////////
1426 } else if (com=="unscrollChilds")
1428 if (xelection.isEmpty() )
1430 parser.setError (Aborted,"Nothing selected");
1433 parser.setError (Aborted,"Type of selection is not a branch");
1434 } else if (parser.checkParCount(0))
1438 /////////////////////////////////////////////////////////////////////
1439 } else if (com=="unsetFlag")
1441 if (xelection.isEmpty() )
1443 parser.setError (Aborted,"Nothing selected");
1446 parser.setError (Aborted,"Type of selection is not a branch");
1447 } else if (parser.checkParCount(1))
1449 s=parser.parString(ok,0);
1452 selb->deactivateStandardFlag(s);
1453 selb->updateFlagsToolbar();
1457 parser.setError (Aborted,"Unknown command");
1460 if (parser.errorLevel()==NoError)
1462 // setChanged(); FIXME should not be called e.g. for export?!
1463 model->reposition();
1467 // TODO Error handling
1468 qWarning("MapEditor::parseAtom: Error!");
1469 qWarning(parser.errorMessage());
1473 void MapEditor::runScript (QString script)
1475 parser.setScript (script);
1477 while (parser.next() )
1478 parseAtom(parser.getAtom());
1481 bool MapEditor::isDefault()
1486 bool MapEditor::hasChanged()
1491 void MapEditor::setChanged()
1495 autosaveTimer->start(settings.value("/mainwindow/autosave/ms/",300000).toInt());
1496 fileChangedTimer->start (3000);
1505 void MapEditor::closeMap()
1507 // Unselect before disabling the toolbar actions
1508 if (!xelection.isEmpty() ) xelection.unselect();
1513 // close(); FIXME needed?
1516 void MapEditor::setFilePath(QString fpath, QString destname)
1518 if (fpath.isEmpty() || fpath=="")
1525 filePath=fpath; // becomes absolute path
1526 fileName=fpath; // gets stripped of path
1527 destPath=destname; // needed for vymlinks and during load to reset fileChangedTime
1529 // If fpath is not an absolute path, complete it
1530 filePath=QDir(fpath).absPath();
1531 fileDir=filePath.left (1+filePath.findRev ("/"));
1533 // Set short name, too. Search from behind:
1534 int i=fileName.findRev("/");
1535 if (i>=0) fileName=fileName.remove (0,i+1);
1537 // Forget the .vym (or .xml) for name of map
1538 mapName=fileName.left(fileName.findRev(".",-1,true) );
1542 void MapEditor::setFilePath(QString fpath)
1544 setFilePath (fpath,fpath);
1547 QString MapEditor::getFilePath()
1552 QString MapEditor::getFileName()
1557 QString MapEditor::getMapName()
1562 QString MapEditor::getDestPath()
1567 ErrorCode MapEditor::load (QString fname, const LoadMode &lmode, const FileType &ftype)
1569 ErrorCode err=success;
1571 parseBaseHandler *handler;
1575 case VymMap: handler=new parseVYMHandler; break;
1576 case FreemindMap : handler=new parseFreemindHandler; break;
1578 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1579 "Unknown FileType in MapEditor::load()");
1583 // Save original zip state, important for inserting complete maps
1584 bool zipped_org=zipped;
1589 model->setMapEditor(this);
1590 // (map state is set later at end of load...)
1593 BranchObj *bo=xelection.getBranch();
1594 if (!bo) return aborted;
1595 if (lmode==ImportAdd)
1596 saveStateChangingPart(
1599 QString("addMapInsert (%1)").arg(fname),
1600 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1602 saveStateChangingPart(
1605 QString("addMapReplace(%1)").arg(fname),
1606 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1610 // Create temporary directory for packing
1612 QString tmpZipDir=makeTmpDir (ok,"vym-pack");
1615 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1616 tr("Couldn't create temporary directory before load\n"));
1620 // Try to unzip file
1621 err=unzipDir (tmpZipDir,fname);
1631 // Look for mapname.xml
1632 xmlfile= fname.left(fname.findRev(".",-1,true));
1633 xmlfile=xmlfile.section( '/', -1 );
1634 QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
1635 if (!mfile.exists() )
1637 // mapname.xml does not exist, well,
1638 // maybe someone renamed the mapname.vym file...
1639 // Try to find any .xml in the toplevel
1640 // directory of the .vym file
1641 QStringList flist=QDir (tmpZipDir).entryList("*.xml");
1642 if (flist.count()==1)
1644 // Only one entry, take this one
1645 xmlfile=tmpZipDir + "/"+flist.first();
1648 for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it )
1649 *it=tmpZipDir + "/" + *it;
1650 // TODO Multiple entries, load all (but only the first one into this ME)
1651 //mainWindow->fileLoadFromTmp (flist);
1652 //returnCode=1; // Silently forget this attempt to load
1653 qWarning ("MainWindow::load (fn) multimap found...");
1656 if (flist.isEmpty() )
1658 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1659 tr("Couldn't find a map (*.xml) in .vym archive.\n"));
1662 } //file doesn't exist
1664 xmlfile=mfile.name();
1667 QFile file( xmlfile);
1669 // I am paranoid: file should exist anyway
1670 // according to check in mainwindow.
1671 if (!file.exists() )
1673 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1674 tr(QString("Couldn't open map %1").arg(file.name())));
1678 bool blockSaveStateOrg=blockSaveState;
1679 blockReposition=true;
1680 blockSaveState=true;
1681 QXmlInputSource source( file);
1682 QXmlSimpleReader reader;
1683 reader.setContentHandler( handler );
1684 reader.setErrorHandler( handler );
1685 handler->setModel ( model);
1688 // We need to set the tmpDir in order to load files with rel. path
1693 tmpdir=fname.left(fname.findRev("/",-1));
1694 handler->setTmpDir (tmpdir);
1695 handler->setInputFile (file.name());
1696 handler->setLoadMode (lmode);
1697 bool ok = reader.parse( source );
1698 blockReposition=false;
1699 blockSaveState=blockSaveStateOrg;
1703 model->reposition(); // FIXME reposition the view instead...
1710 autosaveTimer->stop();
1713 // Reset timestamp to check for later updates of file
1714 fileChangedTime=QFileInfo (destPath).lastModified();
1717 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1718 tr( handler->errorProtocol() ) );
1720 // Still return "success": the map maybe at least
1721 // partially read by the parser
1726 removeDir (QDir(tmpZipDir));
1728 // Restore original zip state
1736 ErrorCode MapEditor::save (const SaveMode &savemode)
1739 QString mapFileName;
1740 QString safeFilePath;
1742 ErrorCode err=success;
1746 mapFileName=mapName+".xml";
1748 // use name given by user, even if he chooses .doc
1749 mapFileName=fileName;
1751 // Look, if we should zip the data:
1754 QMessageBox mb( vymName,
1755 tr("The map %1\ndid not use the compressed "
1756 "vym file format.\nWriting it uncompressed will also write images \n"
1757 "and flags and thus may overwrite files in the "
1758 "given directory\n\nDo you want to write the map").arg(filePath),
1759 QMessageBox::Warning,
1760 QMessageBox::Yes | QMessageBox::Default,
1762 QMessageBox::Cancel | QMessageBox::Escape);
1763 mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
1764 mb.setButtonText( QMessageBox::No, tr("uncompressed") );
1765 mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
1768 case QMessageBox::Yes:
1769 // save compressed (default file format)
1772 case QMessageBox::No:
1773 // save uncompressed
1776 case QMessageBox::Cancel:
1783 // First backup existing file, we
1784 // don't want to add to old zip archives
1788 if ( settings.value ("/mapeditor/writeBackupFile").toBool())
1790 QString backupFileName(destPath + "~");
1791 QFile backupFile(backupFileName);
1792 if (backupFile.exists() && !backupFile.remove())
1794 QMessageBox::warning(0, tr("Save Error"),
1795 tr("%1\ncould not be removed before saving").arg(backupFileName));
1797 else if (!f.rename(backupFileName))
1799 QMessageBox::warning(0, tr("Save Error"),
1800 tr("%1\ncould not be renamed before saving").arg(destPath));
1807 // Create temporary directory for packing
1809 tmpZipDir=makeTmpDir (ok,"vym-zip");
1812 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1813 tr("Couldn't create temporary directory before save\n"));
1817 // cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1818 safeFilePath=filePath;
1819 setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
1822 // Create mapName and fileDir
1823 makeSubDirs (fileDir);
1827 cout <<"ME::save filePath="<<filePath.toStdString()<<endl;
1828 cout <<"ME::save saveFilePath="<<safeFilePath.toStdString()<<endl;
1829 cout <<"ME::save destPath="<<destPath.toStdString()<<endl;
1830 cout <<"ME::save mapName="<<mapName.toStdString()<<endl;
1831 cout <<"ME::save mapFileName="<<mapFileName.toStdString()<<endl;
1835 if (savemode==CompleteMap || xelection.isEmpty())
1837 // Save complete map
1838 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),NULL);
1841 autosaveTimer->stop();
1846 if (xelection.type()==Selection::FloatImage)
1849 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),xelection.getBranch());
1850 // TODO take care of multiselections
1853 // FIXME trying to debug save problem
1854 if (saveFile.length()<1000)
1855 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));
1856 if (!saveStringToDisk(fileDir+mapFileName,saveFile))
1859 QMessageBox::critical (0,"Critical error in MapEditor::save",QString("could not save %1").arg(fileDir+mapFileName));
1865 if (err==success) err=zipDir (tmpZipDir,destPath);
1868 removeDir (QDir(tmpZipDir));
1870 // Restore original filepath outside of tmp zip dir
1871 setFilePath (safeFilePath);
1875 fileChangedTime=QFileInfo (destPath).lastModified();
1880 void MapEditor::print()
1884 printer = new QPrinter;
1885 printer->setColorMode (QPrinter::Color);
1886 printer->setPrinterName (settings.value("/mainwindow/printerName",printer->printerName()).toString());
1887 printer->setOutputFormat((QPrinter::OutputFormat)settings.value("/mainwindow/printerFormat",printer->outputFormat()).toInt());
1888 printer->setOutputFileName(settings.value("/mainwindow/printerFileName",printer->outputFileName()).toString());
1891 QRectF totalBBox=model->getTotalBBox();
1893 // Try to set orientation automagically
1894 // Note: Interpretation of generated postscript is amibiguous, if
1895 // there are problems with landscape mode, see
1896 // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html
1898 if (totalBBox.width()>totalBBox.height())
1899 // recommend landscape
1900 printer->setOrientation (QPrinter::Landscape);
1902 // recommend portrait
1903 printer->setOrientation (QPrinter::Portrait);
1905 if ( printer->setup(this) )
1906 // returns false, if printing is canceled
1908 QPainter pp(printer);
1910 pp.setRenderHint(QPainter::Antialiasing,true);
1912 // Don't print the visualisation of selection
1913 xelection.unselect();
1915 QRectF mapRect=totalBBox;
1916 QGraphicsRectItem *frame=NULL;
1920 // Print frame around map
1921 mapRect.setRect (totalBBox.x()-10, totalBBox.y()-10,
1922 totalBBox.width()+20, totalBBox.height()+20);
1923 frame=mapScene->addRect (mapRect, QPen(Qt::black),QBrush(Qt::NoBrush));
1924 frame->setZValue(0);
1929 double paperAspect = (double)printer->width() / (double)printer->height();
1930 double mapAspect = (double)mapRect.width() / (double)mapRect.height();
1932 if (mapAspect>=paperAspect)
1934 // Fit horizontally to paper width
1935 //pp.setViewport(0,0, printer->width(),(int)(printer->width()/mapAspect) );
1936 viewBottom=(int)(printer->width()/mapAspect);
1939 // Fit vertically to paper height
1940 //pp.setViewport(0,0,(int)(printer->height()*mapAspect),printer->height());
1941 viewBottom=printer->height();
1946 // Print footer below map
1948 font.setPointSize(10);
1950 QRectF footerBox(0,viewBottom,printer->width(),15);
1951 pp.drawText ( footerBox,Qt::AlignLeft,"VYM - " +fileName);
1952 pp.drawText ( footerBox, Qt::AlignRight, QDate::currentDate().toString(Qt::TextDate));
1956 QRectF (0,0,printer->width(),printer->height()-15),
1957 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height())
1960 // Viewport has paper dimension
1961 if (frame) delete (frame);
1963 // Restore selection
1964 xelection.reselect();
1966 // Save settings in vymrc
1967 settings.writeEntry("/mainwindow/printerName",printer->printerName());
1968 settings.writeEntry("/mainwindow/printerFormat",printer->outputFormat());
1969 settings.writeEntry("/mainwindow/printerFileName",printer->outputFileName());
1973 void MapEditor::setAntiAlias (bool b)
1975 setRenderHint(QPainter::Antialiasing,b);
1978 void MapEditor::setSmoothPixmap(bool b)
1980 setRenderHint(QPainter::SmoothPixmapTransform,b);
1983 QPixmap MapEditor::getPixmap()
1985 QRectF mapRect=model->getTotalBBox();
1986 QPixmap pix((int)mapRect.width()+2,(int)mapRect.height()+1);
1989 pp.setRenderHints(renderHints());
1991 // Don't print the visualisation of selection
1992 xelection.unselect();
1994 mapScene->render ( &pp,
1995 QRectF(0,0,mapRect.width()+1,mapRect.height()+1),
1996 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height() ));
1998 // Restore selection
1999 xelection.reselect();
2004 void MapEditor::setHideTmpMode (HideTmpMode mode)
2007 model->setHideTmp (hidemode);
2008 model->reposition();
2012 HideTmpMode MapEditor::getHideTmpMode()
2017 void MapEditor::setExportMode (bool b)
2019 // should be called before and after exports
2020 // depending on the settings
2021 if (b && settings.value("/export/useHideExport","true")=="true")
2022 setHideTmpMode (HideExport);
2024 setHideTmpMode (HideNone);
2027 void MapEditor::exportASCII(QString fname,bool askName)
2030 ex.setModel (model);
2032 ex.setFile (mapName+".txt");
2038 //ex.addFilter ("TXT (*.txt)");
2039 ex.setDir(lastImageDir);
2040 //ex.setCaption(vymName+ " -" +tr("Export as ASCII")+" "+tr("(still experimental)"));
2045 setExportMode(true);
2047 setExportMode(false);
2051 void MapEditor::exportImage(QString fname, bool askName, QString format)
2055 fname=mapName+".png";
2062 QFileDialog *fd=new QFileDialog (this);
2063 fd->setCaption (tr("Export map as image"));
2064 fd->setDirectory (lastImageDir);
2065 fd->setFileMode(QFileDialog::AnyFile);
2066 fd->setFilters (imageIO.getFilters() );
2069 fl=fd->selectedFiles();
2071 format=imageIO.getType(fd->selectedFilter());
2075 setExportMode (true);
2076 QPixmap pix (getPixmap());
2077 pix.save(fname, format);
2078 setExportMode (false);
2081 void MapEditor::exportOOPresentation(const QString &fn, const QString &cf)
2085 ex.setModel (model);
2086 if (ex.setConfigFile(cf))
2088 setExportMode (true);
2089 ex.exportPresentation();
2090 setExportMode (false);
2094 void MapEditor::exportXHTML (const QString &dir, bool askForName)
2096 ExportXHTMLDialog dia(this);
2097 dia.setFilePath (filePath );
2098 dia.setMapName (mapName );
2100 if (dir!="") dia.setDir (dir);
2106 if (dia.exec()!=QDialog::Accepted)
2110 QDir d (dia.getDir());
2111 // Check, if warnings should be used before overwriting
2112 // the output directory
2113 if (d.exists() && d.count()>0)
2116 warn.showCancelButton (true);
2117 warn.setText(QString(
2118 "The directory %1 is not empty.\n"
2119 "Do you risk to overwrite some of its contents?").arg(d.path() ));
2120 warn.setCaption("Warning: Directory not empty");
2121 warn.setShowAgainName("mainwindow/overwrite-dir-xhtml");
2123 if (warn.exec()!=QDialog::Accepted) ok=false;
2130 exportXML (dia.getDir(),false );
2131 dia.doExport(mapName );
2132 //if (dia.hasChanged()) setChanged();
2136 void MapEditor::exportXML(QString dir, bool askForName)
2140 dir=browseDirectory(this,tr("Export XML to directory"));
2141 if (dir =="" && !reallyWriteDirectory(dir) )
2145 // Hide stuff during export, if settings want this
2146 setExportMode (true);
2148 // Create subdirectories
2151 // write to directory
2152 QString saveFile=saveToDir (dir,mapName+"-",true,model->getTotalBBox().topLeft() ,NULL);
2155 file.setName ( dir + "/"+mapName+".xml");
2156 if ( !file.open( QIODevice::WriteOnly ) )
2158 // This should neverever happen
2159 QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open %1").arg(file.name()));
2163 // Write it finally, and write in UTF8, no matter what
2164 QTextStream ts( &file );
2165 ts.setEncoding (QTextStream::UnicodeUTF8);
2169 // Now write image, too
2170 exportImage (dir+"/images/"+mapName+".png",false,"PNG");
2172 setExportMode (false);
2175 void MapEditor::clear()
2177 //cout << "ME::clear() "<<mapName.toStdString()<<endl;
2179 autosaveTimer->stop();
2180 fileChangedTimer->stop();
2184 void MapEditor::copy()
2186 LinkableMapObj *sel=xelection.single();
2189 if (redosAvail == 0)
2192 QString s=model->getSelectString(sel);
2193 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy selection to clipboard",sel );
2194 curClipboard=curStep;
2197 // Copy also to global clipboard, because we are at last step in history
2198 QString bakMapName(QString("history-%1").arg(curStep));
2199 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2200 copyDir (bakMapDir,clipboardDir );
2202 clipboardEmpty=false;
2207 void MapEditor::redo()
2209 // Can we undo at all?
2210 if (redosAvail<1) return;
2212 bool blockSaveStateOrg=blockSaveState;
2213 blockSaveState=true;
2217 if (undosAvail<stepsTotal) undosAvail++;
2219 if (curStep>stepsTotal) curStep=1;
2220 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2221 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2222 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2223 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2224 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2225 QString version=undoSet.readEntry ("/history/version");
2227 /* TODO Maybe check for version, if we save the history
2228 if (!checkVersion(version))
2229 QMessageBox::warning(0,tr("Warning"),
2230 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2233 // Find out current undo directory
2234 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2238 cout << "ME::redo() begin\n";
2239 cout << " undosAvail="<<undosAvail<<endl;
2240 cout << " redosAvail="<<redosAvail<<endl;
2241 cout << " curStep="<<curStep<<endl;
2242 cout << " ---------------------------"<<endl;
2243 cout << " comment="<<comment.toStdString()<<endl;
2244 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2245 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2246 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2247 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2248 cout << " ---------------------------"<<endl<<endl;
2251 // select object before redo
2252 if (!redoSelection.isEmpty())
2253 select (redoSelection);
2256 parseAtom (redoCommand);
2257 model->reposition();
2259 blockSaveState=blockSaveStateOrg;
2261 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2262 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2263 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2264 undoSet.writeSettings(histPath);
2266 mainWindow->updateHistory (undoSet);
2269 /* TODO remove testing
2270 cout << "ME::redo() end\n";
2271 cout << " undosAvail="<<undosAvail<<endl;
2272 cout << " redosAvail="<<redosAvail<<endl;
2273 cout << " curStep="<<curStep<<endl;
2274 cout << " ---------------------------"<<endl<<endl;
2280 bool MapEditor::isRedoAvailable()
2282 if (undoSet.readNumEntry("/history/redosAvail",0)>0)
2288 void MapEditor::undo()
2290 // Can we undo at all?
2291 if (undosAvail<1) return;
2293 mainWindow->statusMessage (tr("Autosave disabled during undo."));
2295 bool blockSaveStateOrg=blockSaveState;
2296 blockSaveState=true;
2298 QString undoCommand= undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2299 QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2300 QString redoCommand= undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2301 QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2302 QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2303 QString version=undoSet.readEntry ("/history/version");
2305 /* TODO Maybe check for version, if we save the history
2306 if (!checkVersion(version))
2307 QMessageBox::warning(0,tr("Warning"),
2308 tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2311 // Find out current undo directory
2312 QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2314 // select object before undo
2315 if (!undoSelection.isEmpty())
2316 select (undoSelection);
2320 cout << "ME::undo() begin\n";
2321 cout << " undosAvail="<<undosAvail<<endl;
2322 cout << " redosAvail="<<redosAvail<<endl;
2323 cout << " curStep="<<curStep<<endl;
2324 cout << " ---------------------------"<<endl;
2325 cout << " comment="<<comment.toStdString()<<endl;
2326 cout << " undoCom="<<undoCommand.toStdString()<<endl;
2327 cout << " undoSel="<<undoSelection.toStdString()<<endl;
2328 cout << " redoCom="<<redoCommand.toStdString()<<endl;
2329 cout << " redoSel="<<redoSelection.toStdString()<<endl;
2330 cout << " ---------------------------"<<endl<<endl;
2332 parseAtom (undoCommand);
2333 model->reposition();
2337 if (curStep<1) curStep=stepsTotal;
2341 blockSaveState=blockSaveStateOrg;
2342 /* TODO remove testing
2343 cout << "ME::undo() end\n";
2344 cout << " undosAvail="<<undosAvail<<endl;
2345 cout << " redosAvail="<<redosAvail<<endl;
2346 cout << " curStep="<<curStep<<endl;
2347 cout << " ---------------------------"<<endl<<endl;
2350 undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2351 undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2352 undoSet.setEntry ("/history/curStep",QString::number(curStep));
2353 undoSet.writeSettings(histPath);
2355 mainWindow->updateHistory (undoSet);
2358 ensureSelectionVisible();
2361 bool MapEditor::isUndoAvailable()
2363 if (undoSet.readNumEntry("/history/undosAvail",0)>0)
2369 void MapEditor::gotoHistoryStep (int i)
2371 // Restore variables
2372 int undosAvail=undoSet.readNumEntry (QString("/history/undosAvail"));
2373 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
2375 if (i<0) i=undosAvail+redosAvail;
2377 // Clicking above current step makes us undo things
2380 for (int j=0; j<undosAvail-i; j++) undo();
2383 // Clicking below current step makes us redo things
2385 for (int j=undosAvail; j<i; j++)
2387 if (debug) cout << "ME::gotoHistoryStep redo "<<j<<"/"<<undosAvail<<" i="<<i<<endl;
2391 // And ignore clicking the current row ;-)
2394 void MapEditor::addMapReplaceInt(const QString &undoSel, const QString &path)
2396 QString pathDir=path.left(path.findRev("/"));
2402 // We need to parse saved XML data
2403 parseVYMHandler handler;
2404 QXmlInputSource source( file);
2405 QXmlSimpleReader reader;
2406 reader.setContentHandler( &handler );
2407 reader.setErrorHandler( &handler );
2408 handler.setModel ( model);
2409 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2410 if (undoSel.isEmpty())
2414 handler.setLoadMode (NewMap);
2418 handler.setLoadMode (ImportReplace);
2420 blockReposition=true;
2421 bool ok = reader.parse( source );
2422 blockReposition=false;
2425 // This should never ever happen
2426 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2427 handler.errorProtocol());
2430 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2433 void MapEditor::addMapInsertInt (const QString &path, int pos)
2435 BranchObj *sel=xelection.getBranch();
2438 QString pathDir=path.left(path.findRev("/"));
2444 // We need to parse saved XML data
2445 parseVYMHandler handler;
2446 QXmlInputSource source( file);
2447 QXmlSimpleReader reader;
2448 reader.setContentHandler( &handler );
2449 reader.setErrorHandler( &handler );
2450 handler.setModel (model);
2451 handler.setTmpDir ( pathDir ); // needed to load files with rel. path
2452 handler.setLoadMode (ImportAdd);
2453 blockReposition=true;
2454 bool ok = reader.parse( source );
2455 blockReposition=false;
2458 // This should never ever happen
2459 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2460 handler.errorProtocol());
2462 if (sel->getDepth()>0)
2463 sel->getLastBranch()->linkTo (sel,pos);
2465 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2469 void MapEditor::pasteNoSave(const int &n)
2471 bool old=blockSaveState;
2472 blockSaveState=true;
2473 bool zippedOrg=zipped;
2474 if (redosAvail > 0 || n!=0)
2476 // Use the "historical" buffer
2477 QString bakMapName(QString("history-%1").arg(n));
2478 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2479 load (bakMapDir+"/"+clipboardFile,ImportAdd, VymMap);
2481 // Use the global buffer
2482 load (clipboardDir+"/"+clipboardFile,ImportAdd, VymMap);
2487 void MapEditor::paste()
2489 BranchObj *sel=xelection.getBranch();
2492 saveStateChangingPart(
2495 QString ("paste (%1)").arg(curClipboard),
2496 QString("Paste to %1").arg( getName(sel))
2499 model->reposition();
2503 void MapEditor::cut()
2505 LinkableMapObj *sel=xelection.single();
2506 if ( sel && (xelection.type() == Selection::Branch ||
2507 xelection.type()==Selection::MapCenter ||
2508 xelection.type()==Selection::FloatImage))
2510 /* No savestate! savestate is called in cutNoSave
2511 saveStateChangingPart(
2515 QString("Cut %1").arg(getName(sel ))
2520 model->reposition();
2524 void MapEditor::move(const double &x, const double &y)
2526 LinkableMapObj *sel=xelection.single();
2529 QPointF ap(sel->getAbsPos());
2533 QString ps=qpointfToString(ap);
2534 QString s=xelection.getSelectString();
2537 s, "move "+qpointfToString(to),
2538 QString("Move %1 to %2").arg(getName(sel)).arg(ps));
2540 model->reposition();
2546 void MapEditor::moveRel (const double &x, const double &y)
2548 LinkableMapObj *sel=xelection.single();
2551 QPointF rp(sel->getRelPos());
2555 QString ps=qpointfToString (sel->getRelPos());
2556 QString s=model->getSelectString(sel);
2559 s, "moveRel "+qpointfToString(to),
2560 QString("Move %1 to relative position %2").arg(getName(sel)).arg(ps));
2561 ((OrnamentedObj*)sel)->move2RelPos (x,y);
2562 model->reposition();
2569 void MapEditor::moveBranchUp()
2571 BranchObj* bo=xelection.getBranch();
2575 if (!bo->canMoveBranchUp()) return;
2576 par=(BranchObj*)(bo->getParObj());
2577 BranchObj *obo=par->moveBranchUp (bo); // bo will be the one below selection
2578 saveState (model->getSelectString(bo),"moveBranchDown ()",model->getSelectString(obo),"moveBranchUp ()",QString("Move up %1").arg(getName(bo)));
2579 model->reposition();
2582 ensureSelectionVisible();
2586 void MapEditor::moveBranchDown()
2588 BranchObj* bo=xelection.getBranch();
2592 if (!bo->canMoveBranchDown()) return;
2593 par=(BranchObj*)(bo->getParObj());
2594 BranchObj *obo=par->moveBranchDown(bo); // bo will be the one above selection
2595 saveState(model->getSelectString(bo),"moveBranchUp ()",model->getSelectString(obo),"moveBranchDown ()",QString("Move down %1").arg(getName(bo)));
2596 model->reposition();
2599 ensureSelectionVisible();
2603 void MapEditor::sortChildren()
2605 BranchObj* bo=xelection.getBranch();
2608 if(bo->countBranches()>1)
2610 saveStateChangingPart(bo,bo, "sortChildren ()",QString("Sort children of %1").arg(getName(bo)));
2612 model->reposition();
2613 ensureSelectionVisible();
2618 void MapEditor::linkTo(const QString &dstString)
2620 FloatImageObj *fio=xelection.getFloatImage();
2623 BranchObj *dst=(BranchObj*)(model->findObjBySelect(dstString));
2624 if (dst && (typeid(*dst)==typeid (BranchObj) ||
2625 typeid(*dst)==typeid (MapCenterObj)))
2627 LinkableMapObj *dstPar=dst->getParObj();
2628 QString parString=model->getSelectString(dstPar);
2629 QString fioPreSelectString=model->getSelectString(fio);
2630 QString fioPreParentSelectString=model->getSelectString (fio->getParObj());
2631 ((BranchObj*)(dst))->addFloatImage (fio);
2632 xelection.unselect();
2633 ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio);
2634 fio=((BranchObj*)(dst))->getLastFloatImage();
2637 xelection.select(fio);
2639 model->getSelectString(fio),
2640 QString("linkTo (\"%1\")").arg(fioPreParentSelectString),
2642 QString ("linkTo (\"%1\")").arg(dstString),
2643 QString ("Link floatimage to %1").arg(getName(dst)));
2648 QString MapEditor::getHeading(bool &ok, QPoint &p)
2650 BranchObj *bo=xelection.getBranch();
2654 p=mapFromScene(bo->getAbsPos());
2655 return bo->getHeading();
2661 void MapEditor::setHeading(const QString &s)
2663 BranchObj *sel=xelection.getBranch();
2668 "setHeading (\""+sel->getHeading()+"\")",
2670 "setHeading (\""+s+"\")",
2671 QString("Set heading of %1 to \"%2\"").arg(getName(sel)).arg(s) );
2672 sel->setHeading(s );
2673 model->reposition();
2675 ensureSelectionVisible();
2679 void MapEditor::setHeadingInt(const QString &s)
2681 BranchObj *bo=xelection.getBranch();
2685 model->reposition();
2687 ensureSelectionVisible();
2691 void MapEditor::setVymLinkInt (const QString &s)
2693 // Internal function, no saveState needed
2694 BranchObj *bo=xelection.getBranch();
2698 model->reposition();
2701 ensureSelectionVisible();
2705 BranchObj* MapEditor::addMapCenter ()
2707 MapCenterObj *mco= model->addMapCenter(contextMenuPos);
2708 xelection.select (mco);
2710 ensureSelectionVisible();
2715 QString ("addMapCenter (%1,%2)").arg (contextMenuPos.x()).arg(contextMenuPos.y()),
2716 QString ("Adding MapCenter to (%1,%2").arg (contextMenuPos.x()).arg(contextMenuPos.y())
2721 BranchObj* MapEditor::addNewBranchInt(int num)
2723 // Depending on pos:
2724 // -3 insert in childs of parent above selection
2725 // -2 add branch to selection
2726 // -1 insert in childs of parent below selection
2727 // 0..n insert in childs of parent at pos
2728 BranchObj *newbo=NULL;
2729 BranchObj *bo=xelection.getBranch();
2734 // save scroll state. If scrolled, automatically select
2735 // new branch in order to tmp unscroll parent...
2736 newbo=bo->addBranch();
2741 bo=(BranchObj*)bo->getParObj();
2742 if (bo) newbo=bo->insertBranch(num);
2746 bo=(BranchObj*)bo->getParObj();
2747 if (bo) newbo=bo->insertBranch(num);
2749 if (!newbo) return NULL;
2754 BranchObj* MapEditor::addNewBranch(int pos)
2756 // Different meaning than num in addNewBranchInt!
2760 BranchObj *bo = xelection.getBranch();
2761 BranchObj *newbo=NULL;
2765 setCursor (Qt::ArrowCursor);
2767 newbo=addNewBranchInt (pos-2);
2775 QString ("addBranch (%1)").arg(pos),
2776 QString ("Add new branch to %1").arg(getName(bo)));
2778 model->reposition();
2780 latestSelection=model->getSelectString(newbo);
2781 // In Network mode, the client needs to know where the new branch is,
2782 // so we have to pass on this information via saveState.
2783 // TODO: Get rid of this positioning workaround
2784 QString ps=qpointfToString (newbo->getAbsPos());
2785 sendData ("selectLatestAdded ()");
2786 sendData (QString("move %1").arg(ps));
2794 BranchObj* MapEditor::addNewBranchBefore()
2796 BranchObj *newbo=NULL;
2797 BranchObj *bo = xelection.getBranch();
2798 if (bo && xelection.type()==Selection::Branch)
2799 // We accept no MapCenterObj here, so we _have_ a parent
2801 QPointF p=bo->getRelPos();
2804 BranchObj *parbo=(BranchObj*)(bo->getParObj());
2806 // add below selection
2807 newbo=parbo->insertBranch(bo->getNum()+1);
2810 newbo->move2RelPos (p);
2812 // Move selection to new branch
2813 bo->linkTo (newbo,-1);
2815 saveState (newbo, "deleteKeepChilds ()", newbo, "addBranchBefore ()",
2816 QString ("Add branch before %1").arg(getName(bo)));
2818 model->reposition();
2822 latestSelection=xelection.getSelectString();
2826 void MapEditor::deleteSelection()
2828 BranchObj *bo = xelection.getBranch();
2829 if (bo && xelection.type()==Selection::MapCenter)
2831 // BranchObj* par=(BranchObj*)(bo->getParObj());
2832 xelection.unselect();
2833 /* FIXME Note: does saveStateRemovingPart work for MCO? (No parent!)
2834 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2836 bo=model->removeMapCenter ((MapCenterObj*)bo);
2839 xelection.select (bo);
2840 ensureSelectionVisible();
2843 model->reposition();
2846 if (bo && xelection.type()==Selection::Branch)
2848 BranchObj* par=(BranchObj*)bo->getParObj();
2849 xelection.unselect();
2850 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2851 par->removeBranch(bo);
2852 xelection.select (par);
2853 ensureSelectionVisible();
2854 model->reposition();
2855 // xelection.update();
2859 FloatImageObj *fio=xelection.getFloatImage();
2862 BranchObj* par=(BranchObj*)fio->getParObj();
2863 saveStateChangingPart(
2867 QString("Delete %1").arg(getName(fio))
2869 xelection.unselect();
2870 par->removeFloatImage(fio);
2871 xelection.select (par);
2872 model->reposition();
2874 ensureSelectionVisible();
2879 LinkableMapObj* MapEditor::getSelection()
2881 return xelection.single();
2884 BranchObj* MapEditor::getSelectedBranch()
2886 return xelection.getBranch();
2889 FloatImageObj* MapEditor::getSelectedFloatImage()
2891 return xelection.getFloatImage();
2894 void MapEditor::unselect()
2896 xelection.unselect();
2899 void MapEditor::reselect()
2901 xelection.reselect();
2904 bool MapEditor::select (const QString &s)
2906 if (xelection.select(s))
2909 ensureSelectionVisible();
2916 bool MapEditor::select (LinkableMapObj *lmo)
2918 if (xelection.select(lmo))
2921 ensureSelectionVisible();
2928 QString MapEditor::getSelectString()
2930 return xelection.getSelectString();
2933 void MapEditor::selectInt (LinkableMapObj *lmo)
2935 if (lmo && xelection.single()!= lmo && isSelectBlocked()==false )
2937 xelection.select(lmo);
2943 void MapEditor::selectNextBranchInt()
2945 // Increase number of branch
2946 LinkableMapObj *sel=xelection.single();
2949 QString s=xelection.getSelectString();
2955 part=s.section(",",-1);
2957 num=part.right(part.length() - 3);
2959 s=s.left (s.length() -num.length());
2962 num=QString ("%1").arg(num.toUInt()+1);
2966 // Try to select this one
2967 if (select (s)) return;
2969 // We have no direct successor,
2970 // try to increase the parental number in order to
2971 // find a successor with same depth
2973 int d=xelection.single()->getDepth();
2978 while (!found && d>0)
2980 s=s.section (",",0,d-1);
2981 // replace substring of current depth in s with "1"
2982 part=s.section(",",-1);
2984 num=part.right(part.length() - 3);
2988 // increase number of parent
2989 num=QString ("%1").arg(num.toUInt()+1);
2990 s=s.section (",",0,d-2) + ","+ typ+num;
2993 // Special case, look at orientation
2994 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
2995 num=QString ("%1").arg(num.toUInt()+1);
2997 num=QString ("%1").arg(num.toUInt()-1);
3002 // pad to oldDepth, select the first branch for each depth
3003 for (i=d;i<oldDepth;i++)
3008 if ( xelection.getBranch()->countBranches()>0)
3016 // try to select the freshly built string
3024 void MapEditor::selectPrevBranchInt()
3026 // Decrease number of branch
3027 BranchObj *bo=xelection.getBranch();
3030 QString s=xelection.getSelectString();
3036 part=s.section(",",-1);
3038 num=part.right(part.length() - 3);
3040 s=s.left (s.length() -num.length());
3042 int n=num.toInt()-1;
3045 num=QString ("%1").arg(n);
3048 // Try to select this one
3049 if (n>=0 && select (s)) return;
3051 // We have no direct precessor,
3052 // try to decrease the parental number in order to
3053 // find a precessor with same depth
3055 int d=xelection.single()->getDepth();
3060 while (!found && d>0)
3062 s=s.section (",",0,d-1);
3063 // replace substring of current depth in s with "1"
3064 part=s.section(",",-1);
3066 num=part.right(part.length() - 3);
3070 // decrease number of parent
3071 num=QString ("%1").arg(num.toInt()-1);
3072 s=s.section (",",0,d-2) + ","+ typ+num;
3075 // Special case, look at orientation
3076 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
3077 num=QString ("%1").arg(num.toInt()-1);
3079 num=QString ("%1").arg(num.toInt()+1);
3084 // pad to oldDepth, select the last branch for each depth
3085 for (i=d;i<oldDepth;i++)
3089 if ( xelection.getBranch()->countBranches()>0)
3090 s+=",bo:"+ QString ("%1").arg( xelection.getBranch()->countBranches()-1 );
3097 // try to select the freshly built string
3105 void MapEditor::selectUpperBranch()
3107 if (isSelectBlocked() ) return;
3109 BranchObj *bo=xelection.getBranch();
3110 if (bo && xelection.type()==Selection::Branch)
3112 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3113 selectPrevBranchInt();
3115 if (bo->getDepth()==1)
3116 selectNextBranchInt();
3118 selectPrevBranchInt();
3122 void MapEditor::selectLowerBranch()
3124 if (isSelectBlocked() ) return;
3126 BranchObj *bo=xelection.getBranch();
3127 if (bo && xelection.type()==Selection::Branch)
3129 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3130 selectNextBranchInt();
3132 if (bo->getDepth()==1)
3133 selectPrevBranchInt();
3135 selectNextBranchInt();
3140 void MapEditor::selectLeftBranch()
3142 if (isSelectBlocked() ) return;
3146 LinkableMapObj *sel=xelection.single();
3149 if (xelection.type()== Selection::MapCenter)
3151 par=xelection.getBranch();
3152 bo=par->getLastSelectedBranch();
3155 // Workaround for reselecting on left and right side
3156 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3157 bo=par->getLastBranch();
3160 bo=par->getLastBranch();
3161 xelection.select(bo);
3163 ensureSelectionVisible();
3169 par=(BranchObj*)(sel->getParObj());
3170 if (sel->getOrientation()==LinkableMapObj::RightOfCenter)
3172 if (xelection.type() == Selection::Branch ||
3173 xelection.type() == Selection::FloatImage)
3175 xelection.select(par);
3177 ensureSelectionVisible();
3182 if (xelection.type() == Selection::Branch )
3184 bo=xelection.getBranch()->getLastSelectedBranch();
3187 xelection.select(bo);
3189 ensureSelectionVisible();
3198 void MapEditor::selectRightBranch()
3200 if (isSelectBlocked() ) return;
3204 LinkableMapObj *sel=xelection.single();
3207 if (xelection.type()==Selection::MapCenter)
3209 par=xelection.getBranch();
3210 bo=par->getLastSelectedBranch();
3213 // Workaround for reselecting on left and right side
3214 if (bo->getOrientation()==LinkableMapObj::LeftOfCenter)
3215 bo=par->getFirstBranch();
3218 xelection.select(bo);
3220 ensureSelectionVisible();
3226 par=(BranchObj*)(xelection.single()->getParObj());
3227 if (xelection.single()->getOrientation()==LinkableMapObj::LeftOfCenter)
3229 if (xelection.type() == Selection::Branch ||
3230 xelection.type() == Selection::FloatImage)
3232 xelection.select(par);
3234 ensureSelectionVisible();
3239 if (xelection.type() == Selection::Branch)
3241 bo=xelection.getBranch()->getLastSelectedBranch();
3244 xelection.select(bo);
3246 ensureSelectionVisible();
3255 void MapEditor::selectFirstBranch()
3257 BranchObj *bo1=xelection.getBranch();
3262 par=(BranchObj*)(bo1->getParObj());
3264 bo2=par->getFirstBranch();
3266 xelection.select(bo2);
3268 ensureSelectionVisible();
3274 void MapEditor::selectLastBranch()
3276 BranchObj *bo1=xelection.getBranch();
3281 par=(BranchObj*)(bo1->getParObj());
3283 bo2=par->getLastBranch();
3286 xelection.select(bo2);
3288 ensureSelectionVisible();
3294 void MapEditor::selectMapBackgroundImage ()
3296 Q3FileDialog *fd=new Q3FileDialog( this);
3297 fd->setMode (Q3FileDialog::ExistingFile);
3298 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
3299 ImagePreview *p =new ImagePreview (fd);
3300 fd->setContentsPreviewEnabled( TRUE );
3301 fd->setContentsPreview( p, p );
3302 fd->setPreviewMode( Q3FileDialog::Contents );
3303 fd->setCaption(vymName+" - " +tr("Load background image"));
3304 fd->setDir (lastImageDir);
3307 if ( fd->exec() == QDialog::Accepted )
3309 // TODO selectMapBackgroundImg in QT4 use: lastImageDir=fd->directory();
3310 lastImageDir=QDir (fd->dirPath());
3311 setMapBackgroundImage (fd->selectedFile());
3315 void MapEditor::setMapBackgroundImage (const QString &fn) //FIXME missing savestate
3317 QColor oldcol=mapScene->backgroundBrush().color();
3321 QString ("setMapBackgroundImage (%1)").arg(oldcol.name()),
3323 QString ("setMapBackgroundImage (%1)").arg(col.name()),
3324 QString("Set background color of map to %1").arg(col.name()));
3327 brush.setTextureImage (QPixmap (fn));
3328 mapScene->setBackgroundBrush(brush);
3331 void MapEditor::selectMapBackgroundColor()
3333 QColor col = QColorDialog::getColor( mapScene->backgroundBrush().color(), this );
3334 if ( !col.isValid() ) return;
3335 setMapBackgroundColor( col );
3339 void MapEditor::setMapBackgroundColor(QColor col)
3341 QColor oldcol=mapScene->backgroundBrush().color();
3343 QString ("setMapBackgroundColor (\"%1\")").arg(oldcol.name()),
3344 QString ("setMapBackgroundColor (\"%1\")").arg(col.name()),
3345 QString("Set background color of map to %1").arg(col.name()));
3346 mapScene->setBackgroundBrush(col);
3349 QColor MapEditor::getMapBackgroundColor()
3351 return mapScene->backgroundBrush().color();
3354 QColor MapEditor::getCurrentHeadingColor()
3356 BranchObj *bo=xelection.getBranch();
3357 if (bo) return bo->getColor();
3359 QMessageBox::warning(0,tr("Warning"),tr("Can't get color of heading,\nthere's no branch selected"));
3363 void MapEditor::colorBranch (QColor c)
3365 BranchObj *bo=xelection.getBranch();
3370 QString ("colorBranch (\"%1\")").arg(bo->getColor().name()),
3372 QString ("colorBranch (\"%1\")").arg(c.name()),
3373 QString("Set color of %1 to %2").arg(getName(bo)).arg(c.name())
3375 bo->setColor(c); // color branch
3379 void MapEditor::colorSubtree (QColor c)
3381 BranchObj *bo=xelection.getBranch();
3384 saveStateChangingPart(
3387 QString ("colorSubtree (\"%1\")").arg(c.name()),
3388 QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(c.name())
3390 bo->setColorSubtree (c); // color links, color childs
3395 void MapEditor::toggleStandardFlag(QString f)
3397 BranchObj *bo=xelection.getBranch();
3401 if (bo->isSetStandardFlag(f))
3413 QString("%1 (\"%2\")").arg(u).arg(f),
3415 QString("%1 (\"%2\")").arg(r).arg(f),
3416 QString("Toggling standard flag \"%1\" of %2").arg(f).arg(getName(bo)));
3417 bo->toggleStandardFlag (f,mainWindow->useFlagGroups());
3423 BranchObj* MapEditor::findText (QString s, bool cs)
3425 QTextDocument::FindFlags flags=0;
3426 if (cs) flags=QTextDocument::FindCaseSensitively;
3429 { // Nothing found or new find process
3431 // nothing found, start again
3433 itFind=model->first();
3435 bool searching=true;
3436 bool foundNote=false;
3437 while (searching && !EOFind)
3441 // Searching in Note
3442 if (itFind->getNote().contains(s,cs))
3444 if (xelection.single()!=itFind)
3446 xelection.select(itFind);
3447 ensureSelectionVisible();
3449 if (textEditor->findText(s,flags))
3455 // Searching in Heading
3456 if (searching && itFind->getHeading().contains (s,cs) )
3458 xelection.select(itFind);
3459 ensureSelectionVisible();
3465 itFind=model->next(itFind);
3466 if (!itFind) EOFind=true;
3468 //cout <<"still searching... "<<qPrintable( itFind->getHeading())<<endl;
3471 return xelection.getBranch();
3476 void MapEditor::findReset()
3477 { // Necessary if text to find changes during a find process
3481 void MapEditor::setURL(const QString &url)
3483 BranchObj *bo=xelection.getBranch();
3486 QString oldurl=bo->getURL();
3490 QString ("setURL (\"%1\")").arg(oldurl),
3492 QString ("setURL (\"%1\")").arg(url),
3493 QString ("set URL of %1 to %2").arg(getName(bo)).arg(url)
3496 model->reposition();
3498 ensureSelectionVisible();
3502 void MapEditor::editURL()
3504 BranchObj *bo=xelection.getBranch();
3508 QString text = QInputDialog::getText(
3509 "VYM", tr("Enter URL:"), QLineEdit::Normal,
3510 bo->getURL(), &ok, this );
3512 // user entered something and pressed OK
3517 void MapEditor::editLocalURL()
3519 BranchObj *bo=xelection.getBranch();
3522 QStringList filters;
3523 filters <<"All files (*)";
3524 filters << tr("Text","Filedialog") + " (*.txt)";
3525 filters << tr("Spreadsheet","Filedialog") + " (*.odp,*.sxc)";
3526 filters << tr("Textdocument","Filedialog") +" (*.odw,*.sxw)";
3527 filters << tr("Images","Filedialog") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)";
3528 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Set URL to a local file"));
3529 fd->setFilters (filters);
3530 fd->setCaption(vymName+" - " +tr("Set URL to a local file"));
3531 fd->setDirectory (lastFileDir);
3532 if (! bo->getVymLink().isEmpty() )
3533 fd->selectFile( bo->getURL() );
3536 if ( fd->exec() == QDialog::Accepted )
3538 lastFileDir=QDir (fd->directory().path());
3539 setURL (fd->selectedFile() );
3544 QString MapEditor::getURL()
3546 BranchObj *bo=xelection.getBranch();
3548 return bo->getURL();
3553 QStringList MapEditor::getURLs()
3556 BranchObj *bo=xelection.getBranch();
3562 if (!bo->getURL().isEmpty()) urls.append( bo->getURL());
3570 void MapEditor::editHeading2URL()
3572 BranchObj *bo=xelection.getBranch();
3574 setURL (bo->getHeading());
3577 void MapEditor::editBugzilla2URL()
3579 BranchObj *bo=xelection.getBranch();
3582 QString url= "https://bugzilla.novell.com/show_bug.cgi?id="+bo->getHeading();
3587 void MapEditor::editFATE2URL()
3589 BranchObj *bo=xelection.getBranch();
3592 QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading();
3595 "setURL (\""+bo->getURL()+"\")",
3597 "setURL (\""+url+"\")",
3598 QString("Use heading of %1 as link to FATE").arg(getName(bo))
3605 void MapEditor::editVymLink()
3607 BranchObj *bo=xelection.getBranch();
3610 QStringList filters;
3611 filters <<"VYM map (*.vym)";
3612 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Link to another map"));
3613 fd->setFilters (filters);
3614 fd->setCaption(vymName+" - " +tr("Link to another map"));
3615 fd->setDirectory (lastFileDir);
3616 if (! bo->getVymLink().isEmpty() )
3617 fd->selectFile( bo->getVymLink() );
3621 if ( fd->exec() == QDialog::Accepted )
3623 lastFileDir=QDir (fd->directory().path());
3626 "setVymLink (\""+bo->getVymLink()+"\")",
3628 "setVymLink (\""+fd->selectedFile()+"\")",
3629 QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())
3631 setVymLinkInt (fd->selectedFile() );
3636 void MapEditor::deleteVymLink()
3638 BranchObj *bo=xelection.getBranch();
3643 "setVymLink (\""+bo->getVymLink()+"\")",
3645 "setVymLink (\"\")",
3646 QString("Unset vymlink of %1").arg(getName(bo))
3648 bo->setVymLink ("" );
3650 model->reposition();
3655 void MapEditor::setHideExport(bool b)
3657 BranchObj *bo=xelection.getBranch();
3660 bo->setHideInExport (b);
3661 QString u= b ? "false" : "true";
3662 QString r=!b ? "false" : "true";
3666 QString ("setHideExport (%1)").arg(u),
3668 QString ("setHideExport (%1)").arg(r),
3669 QString ("Set HideExport flag of %1 to %2").arg(getName(bo)).arg (r)
3672 model->reposition();
3678 void MapEditor::toggleHideExport()
3680 BranchObj *bo=xelection.getBranch();
3682 setHideExport ( !bo->hideInExport() );
3685 QString MapEditor::getVymLink()
3687 BranchObj *bo=xelection.getBranch();
3689 return bo->getVymLink();
3695 QStringList MapEditor::getVymLinks()
3698 BranchObj *bo=xelection.getBranch();
3704 if (!bo->getVymLink().isEmpty()) links.append( bo->getVymLink());
3712 void MapEditor::deleteKeepChilds()
3714 BranchObj *bo=xelection.getBranch();
3718 par=(BranchObj*)(bo->getParObj());
3720 // Don't use this on mapcenter
3723 // Check if we have childs at all to keep
3724 if (bo->countBranches()==0)
3730 QPointF p=bo->getRelPos();
3731 saveStateChangingPart(
3734 "deleteKeepChilds ()",
3735 QString("Remove %1 and keep its childs").arg(getName(bo))
3738 QString sel=model->getSelectString(bo);
3740 par->removeBranchHere(bo);
3741 model->reposition();
3743 xelection.getBranch()->move2RelPos (p);
3744 model->reposition();
3748 void MapEditor::deleteChilds()
3750 BranchObj *bo=xelection.getBranch();
3753 saveStateChangingPart(
3757 QString( "Remove childs of branch %1").arg(getName(bo))
3760 model->reposition();
3764 void MapEditor::editMapInfo()
3766 ExtraInfoDialog dia;
3767 dia.setMapName (getFileName() );
3768 dia.setAuthor (model->getAuthor() );
3769 dia.setComment(model->getComment() );
3773 stats+=tr("%1 items on map\n","Info about map").arg (mapScene->items().size(),6);
3783 if (!bo->getNote().isEmpty() ) n++;
3784 f+= bo->countFloatImages();
3786 xl+=bo->countXLinks();
3789 stats+=QString ("%1 branches\n").arg (b-1,6);
3790 stats+=QString ("%1 xLinks \n").arg (xl,6);
3791 stats+=QString ("%1 notes\n").arg (n,6);
3792 stats+=QString ("%1 images\n").arg (f,6);
3793 dia.setStats (stats);
3795 // Finally show dialog
3796 if (dia.exec() == QDialog::Accepted)
3798 setMapAuthor (dia.getAuthor() );
3799 setMapComment (dia.getComment() );
3803 void MapEditor::ensureSelectionVisible()
3805 LinkableMapObj *lmo=xelection.single();
3806 if (lmo) ensureVisible (lmo->getBBox() );
3810 void MapEditor::updateSelection()
3812 // Tell selection to update geometries
3816 void MapEditor::updateActions()
3818 // Tell mainwindow to update states of actions
3819 mainWindow->updateActions();
3820 // TODO maybe don't update if blockReposition is set
3823 void MapEditor::updateNoteFlag()
3826 BranchObj *bo=xelection.getBranch();
3829 bo->updateNoteFlag();
3830 mainWindow->updateActions();
3834 void MapEditor::setMapAuthor (const QString &s)
3837 QString ("setMapAuthor (\"%1\")").arg(model->getAuthor()),
3838 QString ("setMapAuthor (\"%1\")").arg(s),
3839 QString ("Set author of map to \"%1\"").arg(s)
3841 model->setAuthor (s);
3844 void MapEditor::setMapComment (const QString &s)
3847 QString ("setMapComment (\"%1\")").arg(model->getComment()),
3848 QString ("setMapComment (\"%1\")").arg(s),
3849 QString ("Set comment of map")
3851 model->setComment (s);
3854 void MapEditor::setMapLinkStyle (const QString & s)
3857 if (linkstyle==LinkableMapObj::Line)
3859 else if (linkstyle==LinkableMapObj::Parabel)
3860 snow="StyleParabel";
3861 else if (linkstyle==LinkableMapObj::PolyLine)
3862 snow="StylePolyLine";
3863 else if (linkstyle==LinkableMapObj::PolyParabel)
3864 snow="StyleParabel";
3867 QString("setMapLinkStyle (\"%1\")").arg(s),
3868 QString("setMapLinkStyle (\"%1\")").arg(snow),
3869 QString("Set map link style (\"%1\")").arg(s)
3873 linkstyle=LinkableMapObj::Line;
3874 else if (s=="StyleParabel")
3875 linkstyle=LinkableMapObj::Parabel;
3876 else if (s=="StylePolyLine")
3877 linkstyle=LinkableMapObj::PolyLine;
3879 linkstyle=LinkableMapObj::PolyParabel;
3886 bo->setLinkStyle(bo->getDefLinkStyle());
3889 model->reposition();
3892 LinkableMapObj::Style MapEditor::getMapLinkStyle ()
3897 void MapEditor::setMapDefLinkColor(QColor c)
3910 void MapEditor::setMapLinkColorHintInt()
3912 // called from setMapLinkColorHint(lch) or at end of parse
3922 void MapEditor::setMapLinkColorHint(LinkableMapObj::ColorHint lch)
3925 setMapLinkColorHintInt();
3928 void MapEditor::toggleMapLinkColorHint()
3930 if (linkcolorhint==LinkableMapObj::HeadingColor)
3931 linkcolorhint=LinkableMapObj::DefaultColor;
3933 linkcolorhint=LinkableMapObj::HeadingColor;
3943 LinkableMapObj::ColorHint MapEditor::getMapLinkColorHint()
3945 return linkcolorhint;
3948 QColor MapEditor::getMapDefLinkColor()
3950 return defLinkColor;
3953 void MapEditor::setMapDefXLinkColor(QColor col)
3958 QColor MapEditor::getMapDefXLinkColor()
3960 return defXLinkColor;
3963 void MapEditor::setMapDefXLinkWidth (int w)
3968 int MapEditor::getMapDefXLinkWidth()
3970 return defXLinkWidth;
3973 void MapEditor::selectMapLinkColor()
3975 QColor col = QColorDialog::getColor( defLinkColor, this );
3976 if ( !col.isValid() ) return;
3978 QString("setMapDefLinkColor (\"%1\")").arg(getMapDefLinkColor().name()),
3979 QString("setMapDefLinkColor (\"%1\")").arg(col.name()),
3980 QString("Set map link color to %1").arg(col.name())
3982 setMapDefLinkColor( col );
3985 void MapEditor::selectMapSelectionColor()
3987 QColor col = QColorDialog::getColor( defLinkColor, this );
3988 setSelectionColor (col);
3991 void MapEditor::setSelectionColorInt (QColor col)
3993 if ( !col.isValid() ) return;
3994 xelection.setColor (col);
3997 void MapEditor::setSelectionColor(QColor col)
3999 if ( !col.isValid() ) return;
4001 QString("setSelectionColor (%1)").arg(xelection.getColor().name()),
4002 QString("setSelectionColor (%1)").arg(col.name()),
4003 QString("Set color of selection box to %1").arg(col.name())
4005 setSelectionColorInt (col);
4008 QColor MapEditor::getSelectionColor()
4010 return xelection.getColor();
4013 bool MapEditor::scrollBranch(BranchObj *bo)
4017 if (bo->isScrolled()) return false;
4018 if (bo->countBranches()==0) return false;
4019 if (bo->getDepth()==0) return false;
4025 QString ("%1 ()").arg(u),
4027 QString ("%1 ()").arg(r),
4028 QString ("%1 %2").arg(r).arg(getName(bo))
4038 bool MapEditor::unscrollBranch(BranchObj *bo)
4042 if (!bo->isScrolled()) return false;
4043 if (bo->countBranches()==0) return false;
4044 if (bo->getDepth()==0) return false;
4050 QString ("%1 ()").arg(u),
4052 QString ("%1 ()").arg(r),
4053 QString ("%1 %2").arg(r).arg(getName(bo))
4063 void MapEditor::toggleScroll()
4065 BranchObj *bo=xelection.getBranch();
4066 if (xelection.type()==Selection::Branch )
4068 if (bo->isScrolled())
4069 unscrollBranch (bo);
4075 void MapEditor::unscrollChilds()
4077 BranchObj *bo=xelection.getBranch();
4083 if (bo->isScrolled()) unscrollBranch (bo);
4089 FloatImageObj* MapEditor::loadFloatImageInt (QString fn)
4091 BranchObj *bo=xelection.getBranch();
4095 bo->addFloatImage();
4096 fio=bo->getLastFloatImage();
4098 model->reposition();
4105 void MapEditor::loadFloatImage ()
4107 BranchObj *bo=xelection.getBranch();
4111 Q3FileDialog *fd=new Q3FileDialog( this);
4112 fd->setMode (Q3FileDialog::ExistingFiles);
4113 fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
4114 ImagePreview *p =new ImagePreview (fd);
4115 fd->setContentsPreviewEnabled( TRUE );
4116 fd->setContentsPreview( p, p );
4117 fd->setPreviewMode( Q3FileDialog::Contents );
4118 fd->setCaption(vymName+" - " +tr("Load image"));
4119 fd->setDir (lastImageDir);
4122 if ( fd->exec() == QDialog::Accepted )
4124 // TODO loadFIO in QT4 use: lastImageDir=fd->directory();
4125 lastImageDir=QDir (fd->dirPath());
4128 for (int j=0; j<fd->selectedFiles().count(); j++)
4130 s=fd->selectedFiles().at(j);
4131 fio=loadFloatImageInt (s);
4134 (LinkableMapObj*)fio,
4137 QString ("loadImage (%1)").arg(s ),
4138 QString("Add image %1 to %2").arg(s).arg(getName(bo))
4141 // TODO loadFIO error handling
4142 qWarning ("Failed to load "+s);
4150 void MapEditor::saveFloatImageInt (FloatImageObj *fio, const QString &type, const QString &fn)
4152 fio->save (fn,type);
4155 void MapEditor::saveFloatImage ()
4157 FloatImageObj *fio=xelection.getFloatImage();
4160 QFileDialog *fd=new QFileDialog( this);
4161 fd->setFilters (imageIO.getFilters());
4162 fd->setCaption(vymName+" - " +tr("Save image"));
4163 fd->setFileMode( QFileDialog::AnyFile );
4164 fd->setDirectory (lastImageDir);
4165 // fd->setSelection (fio->getOriginalFilename());
4169 if ( fd->exec() == QDialog::Accepted && fd->selectedFiles().count()==1)
4171 fn=fd->selectedFiles().at(0);
4172 if (QFile (fn).exists() )
4174 QMessageBox mb( vymName,
4175 tr("The file %1 exists already.\n"
4176 "Do you want to overwrite it?").arg(fn),
4177 QMessageBox::Warning,
4178 QMessageBox::Yes | QMessageBox::Default,
4179 QMessageBox::Cancel | QMessageBox::Escape,
4180 QMessageBox::NoButton );
4182 mb.setButtonText( QMessageBox::Yes, tr("Overwrite") );
4183 mb.setButtonText( QMessageBox::No, tr("Cancel"));
4186 case QMessageBox::Yes:
4189 case QMessageBox::Cancel:
4196 saveFloatImageInt (fio,fd->selectedFilter(),fn );
4202 void MapEditor::setFrameType(const FrameObj::FrameType &t)
4204 BranchObj *bo=xelection.getBranch();
4207 QString s=bo->getFrameTypeName();
4208 bo->setFrameType (t);
4209 saveState (bo, QString("setFrameType (\"%1\")").arg(s),
4210 bo, QString ("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),QString ("set type of frame to %1").arg(s));
4211 model->reposition();
4216 void MapEditor::setFrameType(const QString &s)
4218 BranchObj *bo=xelection.getBranch();
4221 saveState (bo, QString("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),
4222 bo, QString ("setFrameType (\"%1\")").arg(s),QString ("set type of frame to %1").arg(s));
4223 bo->setFrameType (s);
4224 model->reposition();
4229 void MapEditor::setFramePenColor(const QColor &c)
4231 BranchObj *bo=xelection.getBranch();
4234 saveState (bo, QString("setFramePenColor (\"%1\")").arg(bo->getFramePenColor().name() ),
4235 bo, QString ("setFramePenColor (\"%1\")").arg(c.name() ),QString ("set pen color of frame to %1").arg(c.name() ));
4236 bo->setFramePenColor (c);
4240 void MapEditor::setFrameBrushColor(const QColor &c)
4242 BranchObj *bo=xelection.getBranch();
4245 saveState (bo, QString("setFrameBrushColor (\"%1\")").arg(bo->getFrameBrushColor().name() ),
4246 bo, QString ("setFrameBrushColor (\"%1\")").arg(c.name() ),QString ("set brush color of frame to %1").arg(c.name() ));
4247 bo->setFrameBrushColor (c);
4251 void MapEditor::setFramePadding (const int &i)
4253 BranchObj *bo=xelection.getBranch();
4256 saveState (bo, QString("setFramePadding (\"%1\")").arg(bo->getFramePadding() ),
4257 bo, QString ("setFramePadding (\"%1\")").arg(i),QString ("set brush color of frame to %1").arg(i));
4258 bo->setFramePadding (i);
4259 model->reposition();
4264 void MapEditor::setFrameBorderWidth(const int &i)
4266 BranchObj *bo=xelection.getBranch();
4269 saveState (bo, QString("setFrameBorderWidth (\"%1\")").arg(bo->getFrameBorderWidth() ),
4270 bo, QString ("setFrameBorderWidth (\"%1\")").arg(i),QString ("set border width of frame to %1").arg(i));
4271 bo->setFrameBorderWidth (i);
4272 model->reposition();
4277 void MapEditor::setIncludeImagesVer(bool b)
4279 BranchObj *bo=xelection.getBranch();
4282 QString u= b ? "false" : "true";
4283 QString r=!b ? "false" : "true";
4287 QString("setIncludeImagesVertically (%1)").arg(u),
4289 QString("setIncludeImagesVertically (%1)").arg(r),
4290 QString("Include images vertically in %1").arg(getName(bo))
4292 bo->setIncludeImagesVer(b);
4293 model->reposition();
4297 void MapEditor::setIncludeImagesHor(bool b)
4299 BranchObj *bo=xelection.getBranch();
4302 QString u= b ? "false" : "true";
4303 QString r=!b ? "false" : "true";
4307 QString("setIncludeImagesHorizontally (%1)").arg(u),
4309 QString("setIncludeImagesHorizontally (%1)").arg(r),
4310 QString("Include images horizontally in %1").arg(getName(bo))
4312 bo->setIncludeImagesHor(b);
4313 model->reposition();
4317 void MapEditor::setHideLinkUnselected (bool b)
4319 LinkableMapObj *sel=xelection.single();
4321 (xelection.type() == Selection::Branch ||
4322 xelection.type() == Selection::MapCenter ||
4323 xelection.type() == Selection::FloatImage ))
4325 QString u= b ? "false" : "true";
4326 QString r=!b ? "false" : "true";
4330 QString("setHideLinkUnselected (%1)").arg(u),
4332 QString("setHideLinkUnselected (%1)").arg(r),
4333 QString("Hide link of %1 if unselected").arg(getName(sel))
4335 sel->setHideLinkUnselected(b);
4339 void MapEditor::importDirInt(BranchObj *dst, QDir d)
4341 BranchObj *bo=xelection.getBranch();
4344 // Traverse directories
4345 d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
4346 QFileInfoList list = d.entryInfoList();
4349 for (int i = 0; i < list.size(); ++i)
4352 if (fi.fileName() != "." && fi.fileName() != ".." )
4355 bo=dst->getLastBranch();
4356 bo->setHeading (fi.fileName() );
4357 bo->setColor (QColor("blue"));
4359 if ( !d.cd(fi.fileName()) )
4360 QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory %1").arg(fi.fileName()));
4363 // Recursively add subdirs
4364 importDirInt (bo,d);
4370 d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
4371 list = d.entryInfoList();
4373 for (int i = 0; i < list.size(); ++i)
4377 bo=dst->getLastBranch();
4378 bo->setHeading (fi.fileName() );
4379 bo->setColor (QColor("black"));
4380 if (fi.fileName().right(4) == ".vym" )
4381 bo->setVymLink (fi.filePath());
4386 void MapEditor::importDirInt (const QString &s)
4388 BranchObj *bo=xelection.getBranch();
4391 saveStateChangingPart (bo,bo,QString ("importDir (\"%1\")").arg(s),QString("Import directory structure from %1").arg(s));
4394 importDirInt (bo,d);
4398 void MapEditor::importDir()
4400 BranchObj *bo=xelection.getBranch();
4403 QStringList filters;
4404 filters <<"VYM map (*.vym)";
4405 QFileDialog *fd=new QFileDialog( this,vymName+ " - " +tr("Choose directory structure to import"));
4406 fd->setMode (QFileDialog::DirectoryOnly);
4407 fd->setFilters (filters);
4408 fd->setCaption(vymName+" - " +tr("Choose directory structure to import"));
4412 if ( fd->exec() == QDialog::Accepted )
4414 importDirInt (fd->selectedFile() );
4415 model->reposition();
4421 void MapEditor::followXLink(int i)
4423 BranchObj *bo=xelection.getBranch();
4426 bo=bo->XLinkTargetAt(i);
4429 xelection.select(bo);
4430 ensureSelectionVisible();
4435 void MapEditor::editXLink(int i) // FIXME missing saveState
4437 BranchObj *bo=xelection.getBranch();
4440 XLinkObj *xlo=bo->XLinkAt(i);
4443 EditXLinkDialog dia;
4445 dia.setSelection(bo);
4446 if (dia.exec() == QDialog::Accepted)
4448 if (dia.useSettingsGlobal() )
4450 setMapDefXLinkColor (xlo->getColor() );
4451 setMapDefXLinkWidth (xlo->getWidth() );
4453 if (dia.deleteXLink())
4454 bo->deleteXLinkAt(i);
4460 AttributeTable* MapEditor::attributeTable()
4465 void MapEditor::testFunction1()
4467 BranchObj *bo=xelection.getBranch();
4468 if (bo) model->moveAway (bo);
4470 /* TODO Hide hidden stuff temporary, maybe add this as regular function somewhere
4471 if (hidemode==HideNone)
4473 setHideTmpMode (HideExport);
4474 mapCenter->calcBBoxSizeWithChilds();
4475 QRectF totalBBox=mapCenter->getTotalBBox();
4476 QRectF mapRect=totalBBox;
4477 QCanvasRectangle *frame=NULL;
4479 cout << " map has =("<<totalBBox.x()<<","<<totalBBox.y()<<","<<totalBBox.width()<<","<<totalBBox.height()<<")\n";
4481 mapRect.setRect (totalBBox.x(), totalBBox.y(),
4482 totalBBox.width(), totalBBox.height());
4483 frame=new QCanvasRectangle (mapRect,mapScene);
4484 frame->setBrush (QColor(white));
4485 frame->setPen (QColor(black));
4486 frame->setZValue(0);
4491 setHideTmpMode (HideNone);
4493 cout <<" hidemode="<<hidemode<<endl;
4497 void MapEditor::testFunction2()
4502 if (hidemode==HideExport)
4503 setHideTmpMode (HideNone);
4505 setHideTmpMode (HideExport);
4509 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
4511 // Lineedits are already closed by preceding
4512 // mouseEvent, we don't need to close here.
4514 QPointF p = mapToScene(e->pos());
4515 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4518 { // MapObj was found
4519 if (xelection.single() != lmo)
4521 // select the MapObj
4522 xelection.select(lmo);
4525 if (xelection.getBranch() )
4527 // Context Menu on branch or mapcenter
4529 branchContextMenu->popup(e->globalPos() );
4532 if (xelection.getFloatImage() )
4534 // Context Menu on floatimage
4536 floatimageContextMenu->popup(e->globalPos() );
4540 { // No MapObj found, we are on the Canvas itself
4541 // Context Menu on scene
4544 canvasContextMenu->popup(e->globalPos() );
4549 void MapEditor::keyPressEvent(QKeyEvent* e)
4551 if (e->modifiers() & Qt::ControlModifier)
4553 switch (mainWindow->getModMode())
4555 case Main::ModModeColor:
4556 setCursor (PickColorCursor);
4558 case Main::ModModeCopy:
4559 setCursor (CopyCursor);
4561 case Main::ModModeXLink:
4562 setCursor (XLinkCursor);
4565 setCursor (Qt::ArrowCursor);
4571 void MapEditor::keyReleaseEvent(QKeyEvent* e)
4573 if (!(e->modifiers() & Qt::ControlModifier))
4574 setCursor (Qt::ArrowCursor);
4577 void MapEditor::mousePressEvent(QMouseEvent* e)
4579 // Ignore right clicks, these will go to context menus
4580 if (e->button() == Qt::RightButton )
4586 //Ignore clicks while editing heading
4587 if (isSelectBlocked() )
4593 QPointF p = mapToScene(e->pos());
4594 LinkableMapObj* lmo=model->findMapObj(p, NULL);
4598 //Take care of system flags _or_ modifier modes
4600 if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4601 typeid(*lmo)==typeid(MapCenterObj) ))
4603 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
4604 if (!foname.isEmpty())
4606 // systemFlag clicked
4610 if (e->state() & Qt::ControlModifier)
4611 mainWindow->editOpenURLTab();
4613 mainWindow->editOpenURL();
4615 else if (foname=="vymLink")
4617 mainWindow->editOpenVymLink();
4618 // tabWidget may change, better return now
4619 // before segfaulting...
4620 } else if (foname=="note")
4621 mainWindow->windowToggleNoteEditor();
4622 else if (foname=="hideInExport")
4629 // No system flag clicked, take care of modmodes (CTRL-Click)
4630 if (e->state() & Qt::ControlModifier)
4632 if (mainWindow->getModMode()==Main::ModModeColor)
4635 setCursor (PickColorCursor);
4638 if (mainWindow->getModMode()==Main::ModModeCopy)
4640 if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4641 typeid(*lmo)==typeid(MapCenterObj) ))
4646 if (lmo->getDepth()>0) select (lmo->getParObj() );
4648 cout << "sel 1="<<getSelectedBranch()->getHeading().toStdString()<<endl;
4649 lmo=getSelectedBranch()->getLastBranch();
4650 cout << "sel 2="<<getSelectedBranch()->getHeading().toStdString()<<endl;
4651 setCursor (Qt::ArrowCursor);
4655 if (mainWindow->getModMode()==Main::ModModeXLink)
4657 BranchObj *bo_begin=NULL;
4659 bo_begin=(BranchObj*)(lmo);
4661 if (xelection.getBranch() )
4662 bo_begin=xelection.getBranch();
4666 linkingObj_src=bo_begin;
4667 tmpXLink=new XLinkObj (mapScene);
4668 tmpXLink->setBegin (bo_begin);
4669 tmpXLink->setEnd (p);
4670 tmpXLink->setColor(defXLinkColor);
4671 tmpXLink->setWidth(defXLinkWidth);
4672 tmpXLink->updateXLink();
4673 tmpXLink->setVisibility (true);
4677 } // End of modmodes
4681 // Select the clicked object
4684 // Left Button Move Branches
4685 if (e->button() == Qt::LeftButton )
4687 //movingObj_start.setX( p.x() - selection->x() );// TODO replaced selection->lmo here
4688 //movingObj_start.setY( p.y() - selection->y() );
4689 movingObj_start.setX( p.x() - lmo->x() );
4690 movingObj_start.setY( p.y() - lmo->y() );
4691 movingObj_orgPos.setX (lmo->x() );
4692 movingObj_orgPos.setY (lmo->y() );
4693 movingObj_orgRelPos=lmo->getRelPos();
4695 // If modMode==copy, then we want to "move" the _new_ object around
4696 // then we need the offset from p to the _old_ selection, because of tmp
4698 if (mainWindow->getModMode()==Main::ModModeCopy &&
4699 e->state() & Qt::ControlModifier)
4701 BranchObj *bo=xelection.getBranch();
4705 bo->addBranch ((BranchObj*)xelection.single());
4707 xelection.select(bo->getLastBranch());
4708 model->reposition();
4713 movingObj=xelection.single();
4715 // Middle Button Toggle Scroll
4716 // (On Mac OS X this won't work, but we still have
4717 // a button in the toolbar)
4718 if (e->button() == Qt::MidButton )
4723 { // No MapObj found, we are on the scene itself
4724 // Left Button move Pos of sceneView
4725 if (e->button() == Qt::LeftButton )
4727 movingObj=NULL; // move Content not Obj
4728 movingObj_start=e->globalPos();
4729 movingCont_start=QPointF (
4730 horizontalScrollBar()->value(),
4731 verticalScrollBar()->value());
4732 movingVec=QPointF(0,0);
4733 setCursor(HandOpenCursor);
4738 void MapEditor::mouseMoveEvent(QMouseEvent* e)
4740 QPointF p = mapToScene(e->pos());
4741 LinkableMapObj *lmosel=xelection.single();
4743 // Move the selected MapObj
4744 if ( lmosel && movingObj)
4746 // reset cursor if we are moving and don't copy
4747 if (mainWindow->getModMode()!=Main::ModModeCopy)
4748 setCursor (Qt::ArrowCursor);
4750 // To avoid jumping of the sceneView, only
4751 // ensureSelectionVisible, if not tmp linked
4752 if (!lmosel->hasParObjTmp())
4753 ensureSelectionVisible ();
4755 // Now move the selection, but add relative position
4756 // (movingObj_start) where selection was chosen with
4757 // mousepointer. (This avoids flickering resp. jumping
4758 // of selection back to absPos)
4760 // Check if we could link
4761 LinkableMapObj* lmo=model->findMapObj(p, lmosel);
4764 FloatObj *fio=xelection.getFloatImage();
4767 fio->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4769 fio->updateLink(); //no need for reposition, if we update link here
4772 // Relink float to new mapcenter or branch, if shift is pressed
4773 // Only relink, if selection really has a new parent
4774 if ( (e->modifiers()==Qt::ShiftModifier) && lmo &&
4775 ( (typeid(*lmo)==typeid(BranchObj)) ||
4776 (typeid(*lmo)==typeid(MapCenterObj)) ) &&
4777 ( lmo != fio->getParObj())
4780 if (typeid(*fio) == typeid(FloatImageObj) &&
4781 ( (typeid(*lmo)==typeid(BranchObj) ||
4782 typeid(*lmo)==typeid(MapCenterObj)) ))
4785 // Also save the move which was done so far
4786 QString pold=qpointfToString(movingObj_orgRelPos);
4787 QString pnow=qpointfToString(fio->getRelPos());
4793 QString("Move %1 to relative position %2").arg(getName(fio)).arg(pnow));
4794 fio->getParObj()->requestReposition();
4795 model->reposition();
4797 linkTo (model->getSelectString(lmo));
4799 //movingObj_orgRelPos=lmosel->getRelPos();
4801 model->reposition();
4805 { // selection != a FloatObj
4806 if (lmosel->getDepth()==0)
4809 if (e->buttons()== Qt::LeftButton && e->modifiers()==Qt::ShiftModifier)
4810 ((MapCenterObj*)lmosel)->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4812 lmosel->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4813 model->updateRelPositions();
4816 if (lmosel->getDepth()==1)
4819 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4820 lmosel->setRelPos();
4823 // Move ordinary branch
4824 lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );
4827 // Maybe we can relink temporary?
4828 if (lmo && (lmo!=lmosel) && xelection.getBranch() &&
4829 (typeid(*lmo)==typeid(BranchObj) ||
4830 typeid(*lmo)==typeid(MapCenterObj)) )
4833 if (e->modifiers()==Qt::ControlModifier)
4835 // Special case: CTRL to link below lmo
4836 lmosel->setParObjTmp (lmo,p,+1);
4838 else if (e->modifiers()==Qt::ShiftModifier)
4839 lmosel->setParObjTmp (lmo,p,-1);
4841 lmosel->setParObjTmp (lmo,p,0);
4844 lmosel->unsetParObjTmp();
4846 // reposition subbranch
4847 lmosel->reposition();
4851 } // no FloatImageObj
4855 } // selection && moving_obj
4857 // Draw a link from one branch to another
4860 tmpXLink->setEnd (p);
4861 tmpXLink->updateXLink();
4865 if (!movingObj && !pickingColor &&!drawingLink && e->buttons() == Qt::LeftButton )
4867 QPointF p=e->globalPos();
4868 movingVec.setX(-p.x() + movingObj_start.x() );
4869 movingVec.setY(-p.y() + movingObj_start.y() );
4870 horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
4871 verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
4876 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
4878 QPointF p = mapToScene(e->pos());
4879 LinkableMapObj *dst;
4880 LinkableMapObj *lmosel=xelection.single();
4881 // Have we been picking color?
4885 setCursor (Qt::ArrowCursor);
4886 // Check if we are over another branch
4887 dst=model->findMapObj(p, NULL);
4890 if (e->state() & Qt::ShiftModifier)
4891 colorBranch (((BranchObj*)dst)->getColor());
4893 colorSubtree (((BranchObj*)dst)->getColor());
4898 // Have we been drawing a link?
4902 // Check if we are over another branch
4903 dst=model->findMapObj(p, NULL);
4906 tmpXLink->setEnd ( ((BranchObj*)(dst)) );
4907 tmpXLink->updateXLink();
4908 tmpXLink->activate(); //FIXME savestate missing
4909 //saveStateComplete(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) );
4918 // Have we been moving something?
4919 if ( lmosel && movingObj )
4921 FloatImageObj *fo=xelection.getFloatImage();
4924 // Moved FloatObj. Maybe we need to reposition
4925 QString pold=qpointfToString(movingObj_orgRelPos);
4926 QString pnow=qpointfToString(fo->getRelPos());
4932 QString("Move %1 to relative position %2").arg(getName(fo)).arg(pnow));
4934 fo->getParObj()->requestReposition();
4935 model->reposition();
4938 // Check if we are over another branch, but ignore
4939 // any found LMOs, which are FloatObjs
4940 dst=model->findMapObj(mapToScene(e->pos() ), lmosel);
4942 if (dst && (typeid(*dst)!=typeid(BranchObj) && typeid(*dst)!=typeid(MapCenterObj)))
4945 BranchObj *bo=xelection.getBranch();
4946 if (bo && bo->getDepth()==0)
4948 if (movingObj_orgPos != bo->getAbsPos())
4950 QString pold=qpointfToString(movingObj_orgPos);
4951 QString pnow=qpointfToString(bo->getAbsPos());
4957 QString("Move mapcenter %1 to position %2").arg(getName(bo)).arg(pnow));
4961 if (xelection.type() == Selection::Branch )
4962 { // A branch was moved
4964 // save the position in case we link to mapcenter
4965 QPointF savePos=QPointF (lmosel->getAbsPos() );
4967 // Reset the temporary drawn link to the original one
4968 lmosel->unsetParObjTmp();
4970 // For Redo we may need to save original selection
4971 QString preSelStr=model->getSelectString(lmosel);
4976 // Don't unscroll if relinked to a scrolled parent, but
4977 // select parent instead
4978 bool selectParent=false;
4980 // We have a destination, relink to that
4982 BranchObj* bsel=xelection.getBranch();
4983 BranchObj* bdst=(BranchObj*)dst;
4985 QString preParStr=model->getSelectString (bsel->getParObj());
4986 QString preNum=QString::number (bsel->getNum(),10);
4987 QString preDstParStr;
4989 if (e->state() & Qt::ShiftModifier && dst->getParObj())
4991 preDstParStr=model->getSelectString (dst->getParObj());
4992 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum());
4994 if (e->state() & Qt::ControlModifier && dst->getParObj())
4997 preDstParStr=model->getSelectString (dst->getParObj());
4998 bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum()+1);
5001 if (bdst->isScrolled()) selectParent=true;
5002 preDstParStr=model->getSelectString(dst);
5003 bsel->linkTo (bdst,-1);
5004 if (dst->getDepth()==0) bsel->move (savePos);
5006 QString postSelStr=model->getSelectString(lmosel);
5007 QString postNum=QString::number (bsel->getNum(),10);
5009 QString undoCom="linkTo (\""+
5010 preParStr+ "\"," + preNum +"," +
5011 QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")";
5013 QString redoCom="linkTo (\""+
5014 preDstParStr + "\"," + postNum + "," +
5015 QString ("%1,%2").arg(savePos.x()).arg(savePos.y())+ ")";
5020 QString("Relink %1 to %2").arg(getName(bsel)).arg(getName(dst)) );
5022 if (selectParent) select (bdst);
5024 model->reposition(); // not necessary if we undo temporary move below
5027 // No destination, undo temporary move
5029 if (lmosel->getDepth()==1)
5031 // The select string might be different _after_ moving around.
5032 // Therefor reposition and then use string of old selection, too
5033 model->reposition();
5035 QPointF rp(lmosel->getRelPos());
5036 if (rp != movingObj_orgRelPos)
5038 QString ps=qpointfToString(rp);
5040 model->getSelectString(lmosel), "moveRel "+qpointfToString(movingObj_orgRelPos),
5041 preSelStr, "moveRel "+ps,
5042 QString("Move %1 to relative position %2").arg(getName(lmosel)).arg(ps));
5046 // Draw the original link, before selection was moved around
5047 if (settings.value("/animation/use",false).toBool() && lmosel->getDepth()>1)
5049 QPointF p=bo->getParObj()->getChildPos();
5050 lmosel->setRelPos(); // calc relPos first
5051 model->startAnimation(
5052 lmosel->getRelPos(),
5053 QPointF (movingObj_orgPos.x() - p.x(), movingObj_orgPos.y() - p.y() )
5056 model->reposition();
5060 // Finally resize scene, if needed
5064 // Just make sure, that actions are still ok,e.g. the move branch up/down buttons...
5067 // maybe we moved View: set old cursor
5068 setCursor (Qt::ArrowCursor);
5072 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
5074 if (isSelectBlocked() )
5080 if (e->button() == Qt::LeftButton )
5082 QPointF p = mapToScene(e->pos());
5083 LinkableMapObj *lmo=model->findMapObj(p, NULL);
5084 if (lmo) { // MapObj was found
5085 // First select the MapObj than edit heading
5086 xelection.select(lmo);
5087 mainWindow->editHeading();
5092 void MapEditor::resizeEvent (QResizeEvent* e)
5094 QGraphicsView::resizeEvent( e );
5097 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
5099 //for (unsigned int i=0;event->format(i);i++) // Debug mime type
5100 // cerr << event->format(i) << endl;
5102 if (event->mimeData()->hasImage())
5103 event->acceptProposedAction();
5105 if (event->mimeData()->hasUrls())
5106 event->acceptProposedAction();
5109 void MapEditor::dragMoveEvent(QDragMoveEvent *)
5113 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
5118 void MapEditor::dropEvent(QDropEvent *event)
5120 BranchObj *sel=xelection.getBranch();
5124 foreach (QString format,event->mimeData()->formats())
5125 cout << "MapEditor: Dropped format: "<<qPrintable (format)<<endl;
5129 if (event->mimeData()->hasImage())
5131 QVariant imageData = event->mimeData()->imageData();
5132 addFloatImageInt (qvariant_cast<QPixmap>(imageData));
5134 if (event->mimeData()->hasUrls())
5135 uris=event->mimeData()->urls();
5143 for (int i=0; i<uris.count();i++)
5145 // Workaround to avoid adding empty branches
5146 if (!uris.at(i).toString().isEmpty())
5148 bo=sel->addBranch();
5151 s=uris.at(i).toLocalFile();
5154 QString file = QDir::fromNativeSeparators(s);
5155 heading = QFileInfo(file).baseName();
5157 if (file.endsWith(".vym", false))
5158 bo->setVymLink(file);
5160 bo->setURL(uris.at(i).toString());
5163 bo->setURL(uris.at(i).toString());
5166 if (!heading.isEmpty())
5167 bo->setHeading(heading);
5169 bo->setHeading(uris.at(i).toString());
5173 model->reposition();
5176 event->acceptProposedAction();
5180 void MapEditor::sendSelection()
5182 if (netstate!=Server) return;
5183 sendData (QString("select (\"%1\")").arg(xelection.getSelectString()) );
5186 void MapEditor::newServer()
5190 tcpServer = new QTcpServer(this);
5191 if (!tcpServer->listen(QHostAddress::Any,port)) {
5192 QMessageBox::critical(this, "vym server",
5193 QString("Unable to start the server: %1.").arg(tcpServer->errorString()));
5197 connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newClient()));
5199 cout<<"Server is running on port "<<tcpServer->serverPort()<<endl;
5202 void MapEditor::connectToServer()
5205 server="salam.suse.de";
5207 clientSocket = new QTcpSocket (this);
5208 clientSocket->abort();
5209 clientSocket->connectToHost(server ,port);
5210 connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readData()));
5211 connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
5212 this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
5214 cout<<"connected to "<<qPrintable (server)<<" port "<<port<<endl;
5219 void MapEditor::newClient()
5221 QTcpSocket *newClient = tcpServer->nextPendingConnection();
5222 connect(newClient, SIGNAL(disconnected()),
5223 newClient, SLOT(deleteLater()));
5225 cout <<"ME::newClient at "<<qPrintable( newClient->peerAddress().toString() )<<endl;
5227 clientList.append (newClient);
5231 void MapEditor::sendData(const QString &s)
5233 if (clientList.size()==0) return;
5235 // Create bytearray to send
5237 QDataStream out(&block, QIODevice::WriteOnly);
5238 out.setVersion(QDataStream::Qt_4_0);
5240 // Reserve some space for blocksize
5243 // Write sendCounter
5244 out << sendCounter++;
5249 // Go back and write blocksize so far
5250 out.device()->seek(0);
5251 quint16 bs=(quint16)(block.size() - 2*sizeof(quint16));
5255 cout << "ME::sendData bs="<<bs<<" counter="<<sendCounter<<" s="<<qPrintable(s)<<endl;
5257 for (int i=0; i<clientList.size(); ++i)
5259 //cout << "Sending \""<<qPrintable (s)<<"\" to "<<qPrintable (clientList.at(i)->peerAddress().toString())<<endl;
5260 clientList.at(i)->write (block);
5264 void MapEditor::readData ()
5266 while (clientSocket->bytesAvailable() >=(int)sizeof(quint16) )
5269 cout <<"readData bytesAvail="<<clientSocket->bytesAvailable();
5273 QDataStream in(clientSocket);
5274 in.setVersion(QDataStream::Qt_4_0);
5282 cout << " t="<<qPrintable (t)<<endl;
5288 void MapEditor::displayNetworkError(QAbstractSocket::SocketError socketError)
5290 switch (socketError) {
5291 case QAbstractSocket::RemoteHostClosedError:
5293 case QAbstractSocket::HostNotFoundError:
5294 QMessageBox::information(this, vymName +" Network client",
5295 "The host was not found. Please check the "
5296 "host name and port settings.");
5298 case QAbstractSocket::ConnectionRefusedError:
5299 QMessageBox::information(this, vymName + " Network client",
5300 "The connection was refused by the peer. "
5301 "Make sure the fortune server is running, "
5302 "and check that the host name and port "
5303 "settings are correct.");
5306 QMessageBox::information(this, vymName + " Network client",
5307 QString("The following error occurred: %1.")
5308 .arg(clientSocket->errorString()));
5312 void MapEditor::autosave()
5316 if (debug) cout <<" ME::autosave rejected, no filepath available\n";
5320 QDateTime now=QDateTime().currentDateTime();
5322 cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n";
5323 cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
5324 cout << " fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
5325 cout << " time: "<<qPrintable (now.toString())<<endl;
5326 cout << " zipped="<<zipped<<endl;
5329 // Disable autosave, while we have gone back in history
5330 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
5331 if (redosAvail>0) return;
5333 // Also disable autosave for new map without filename
5334 if (filePath.isEmpty()) return;
5337 if (mapUnsaved &&mapChanged && settings.value ("/mainwindow/autosave/use",true).toBool() )
5339 if (QFileInfo(filePath).lastModified()<=fileChangedTime)
5340 mainWindow->fileSave (this);
5343 cout <<" ME::autosave rejected, file on disk is newer than last save.\n";
5347 void MapEditor::fileChanged()
5349 // Check if file on disk has changed meanwhile
5350 if (!filePath.isEmpty())
5352 QDateTime tmod=QFileInfo (filePath).lastModified();
5353 if (tmod>fileChangedTime)
5356 /* FIXME debug message, sometimes there's a glitch in the metrics...
5357 cout << "ME::fileChanged()\n"
5358 << " last saved: "<<qPrintable (fileChangedTime.toString())<<endl
5359 << " last modififed: "<<qPrintable (tmod.toString())<<endl;
5361 // FIXME switch to current mapeditor and finish lineedits...
5362 QMessageBox mb( vymName,
5363 tr("The file of the map on disk has changed:\n\n"
5364 " %1\n\nDo you want to reload that map with the new file?").arg(filePath),
5365 QMessageBox::Question,
5367 QMessageBox::Cancel | QMessageBox::Default,
5368 QMessageBox::NoButton );
5370 mb.setButtonText( QMessageBox::Yes, tr("Reload"));
5371 mb.setButtonText( QMessageBox::No, tr("Ignore"));
5374 case QMessageBox::Yes:
5376 load (filePath,NewMap,fileType);
5377 case QMessageBox::Cancel:
5378 fileChangedTime=tmod; // allow autosave to overwrite newer file!
5386 /*TODO not needed? void MapEditor::contentsDropEvent(QDropEvent *event)
5389 } else if (event->provides("application/x-moz-file-promise-url") &&
5390 event->provides("application/x-moz-nativeimage"))
5392 // Contains url to the img src in unicode16
5393 QByteArray d = event->encodedData("application/x-moz-file-promise-url");
5394 QString url = QString((const QChar*)d.data(),d.size()/2);
5398 } else if (event->provides ("text/uri-list"))
5399 { // Uris provided e.g. by konqueror
5400 Q3UriDrag::decode (event,uris);
5401 } else if (event->provides ("_NETSCAPE_URL"))
5402 { // Uris provided by Mozilla
5403 QStringList l = QStringList::split("\n", event->encodedData("_NETSCAPE_URL"));
5406 } else if (event->provides("text/html")) {
5408 // Handels text mime types
5409 // Look like firefox allways handle text as unicode16 (2 bytes per char.)
5410 QByteArray d = event->encodedData("text/html");
5413 text = QString((const QChar*)d.data(),d.size()/2);
5417 textEditor->setText(text);
5421 } else if (event->provides("text/plain")) {
5422 QByteArray d = event->encodedData("text/plain");
5425 text = QString((const QChar*)d.data(),d.size()/2);
5429 textEditor->setText(text);
5439 bool isUnicode16(const QByteArray &d)
5441 // TODO: make more precise check for unicode 16.
5442 // Guess unicode16 if any of second bytes are zero
5443 unsigned int length = max(0,d.size()-2)/2;
5444 for (unsigned int i = 0; i<length ; i++)
5445 if (d.at(i*2+1)==0) return true;
5449 void MapEditor::addFloatImageInt (const QPixmap &img)
5451 BranchObj *bo=xelection.getBranch();
5454 FloatImageObj *fio=bo->addFloatImage();
5456 fio->setOriginalFilename("No original filename (image added by dropevent)");
5457 QString s=model->getSelectString(bo);
5458 saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy dropped image to clipboard",fio );
5459 saveState (fio,"delete ()", bo,QString("paste(%1)").arg(curStep),"Pasting dropped image");
5460 model->reposition();
5467 void MapEditor::imageDataFetched(const QByteArray &a, Q3NetworkOperation * / *nop* /)
5469 if (!imageBuffer) imageBuffer = new QBuffer();
5470 if (!imageBuffer->isOpen()) {
5471 imageBuffer->open(QIODevice::WriteOnly | QIODevice::Append);
5473 imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a));
5477 void MapEditor::imageDataFinished(Q3NetworkOperation *nop)
5479 if (nop->state()==Q3NetworkProtocol::StDone) {
5480 QPixmap img(imageBuffer->buffer());
5481 addFloatImageInt (img);
5485 imageBuffer->close();
5487 imageBuffer->close();
5494 void MapEditor::fetchImage(const QString &url)
5497 urlOperator->stop();
5498 disconnect(urlOperator);
5502 urlOperator = new Q3UrlOperator(url);
5503 connect(urlOperator, SIGNAL(finished(Q3NetworkOperation *)),
5504 this, SLOT(imageDataFinished(Q3NetworkOperation*)));
5506 connect(urlOperator, SIGNAL(data(const QByteArray &, Q3NetworkOperation *)),
5507 this, SLOT(imageDataFetched(const QByteArray &, Q3NetworkOperation *)));