initial import
[vym] / mapeditor.cpp
1 #include "mapeditor.h"
2
3 //#include <q3filedialog.h>
4
5 #include <iostream>
6 #include <cstdlib>
7 #include <typeinfo>
8
9 #include "parser.h"
10 #include "editxlinkdialog.h"
11 #include "exports.h"
12 #include "exportxhtmldialog.h"
13 #include "extrainfodialog.h"
14 #include "file.h"
15 #include "linkablemapobj.h"
16 #include "mainwindow.h"
17 #include "misc.h"
18 #include "texteditor.h"
19 #include "warningdialog.h"
20 #include "xml-freemind.h"
21 #include "xml-vym.h"
22
23
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;
31 extern bool debug;
32 extern FlagRowObj *standardFlagsDefault;
33
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;
42
43
44 extern Settings settings;
45 extern ImageIO imageIO;
46
47 extern QString vymName;
48 extern QString vymVersion;
49
50 extern QString iconPath;
51 extern QDir vymBaseDir;
52 extern QDir lastImageDir;
53 extern QDir lastFileDir;
54
55 int MapEditor::mapNum=0;        // make instance
56
57 ///////////////////////////////////////////////////////////////////////
58 ///////////////////////////////////////////////////////////////////////
59 MapEditor::MapEditor( QWidget* parent) :
60   QGraphicsView(parent)  
61 {
62         setObjectName ("MapEditor");
63
64         //cout << "Constructor ME "<<this<<endl;
65         mapNum++;
66
67
68         mapScene= new QGraphicsScene(parent);
69         //mapScene= new QGraphicsScene(QRectF(0,0,width(),height()), parent);
70         mapScene->setBackgroundBrush (QBrush(Qt::white, Qt::SolidPattern));
71
72         model=new VymModel();
73         model->setScene (mapScene);
74         model->setMapEditor (this);
75
76     setScene (mapScene);
77
78     printer=NULL;
79
80         defLinkColor=QColor (0,0,255);
81         defXLinkColor=QColor (180,180,180);
82         linkcolorhint=LinkableMapObj::DefaultColor;
83         linkstyle=LinkableMapObj::PolyParabel;
84
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 ); 
90
91         setFocusPolicy (Qt::StrongFocus);
92
93         pickingColor=false;
94         drawingLink=false;
95         copyingObj=false;
96
97     editingBO=NULL;
98     movingObj=NULL;
99
100         xelection.setModel (model);
101         xelection.unselect();
102
103         defXLinkWidth=1;
104         defXLinkColor=QColor (230,230,230);
105
106     mapChanged=false;
107         mapDefault=true;
108         mapUnsaved=false;
109         
110         zipped=true;
111         filePath="";
112         fileName=tr("unnamed");
113         mapName="";
114
115         stepsTotal=settings.readNumEntry("/mapeditor/stepsTotal",100);
116         undoSet.setEntry ("/history/stepsTotal",QString::number(stepsTotal));
117         mainWindow->updateHistory (undoSet);
118         
119         // Initialize find routine
120         itFind=NULL;                            
121         EOFind=false;
122
123         printFrame=true;
124         printFooter=true;
125
126         blockReposition=false;
127         blockSaveState=false;
128
129         hidemode=HideNone;
130
131         // Create temporary files
132         makeTmpDirs();
133
134         curStep=0;
135         redosAvail=0;
136         undosAvail=0;
137
138         setAcceptDrops (true);  
139
140         model->reposition();
141
142         // autosave
143         autosaveTimer=new QTimer (this);
144         connect(autosaveTimer, SIGNAL(timeout()), this, SLOT(autosave()));
145
146         fileChangedTimer=new QTimer (this);
147         fileChangedTimer->start(3000);
148         connect(fileChangedTimer, SIGNAL(timeout()), this, SLOT(fileChanged()));
149
150         // Network
151         netstate=Offline;
152
153         // Attributes   //FIXME testing only...
154         QString k;
155         AttributeDef *ad;
156         attrTable= new AttributeTable();
157         k="A - StringList";
158         ad=attrTable->addKey (k,StringList);
159         if (ad)
160         {
161                 QStringList sl;
162                 sl <<"val 1"<<"val 2"<< "val 3";
163                 ad->setValue (QVariant (sl));
164         }
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");
169         k="B - FreeString";
170         ad=attrTable->addKey (k,FreeString);
171         if (ad)
172         {
173                 //attrTable->addValue ("Key B","w1");
174                 //attrTable->addValue ("Key B","w2");
175         }
176         k="C - UniqueString";
177         ad=attrTable->addKey (k,UniqueString);
178         if (ad)
179         {
180         //attrTable->addKey ("Key Prio");
181         //attrTable->addValue ("Key Prio","Prio 1");
182         //attrTable->addValue ("Key Prio","Prio 2");
183         }
184 }
185
186 MapEditor::~MapEditor()
187 {
188         //cout <<"Destructor MapEditor\n";
189         autosaveTimer->stop();
190         fileChangedTimer->stop();
191
192         // tmpMapDir is in tmpVymDir, so it gets removed automagically when vym closes
193         
194         //removeDir(QDir(tmpMapDir));
195         delete (model);
196 }
197
198 VymModel* MapEditor::getModel()
199 {
200     return model;
201 }
202
203 QGraphicsScene * MapEditor::getScene()
204 {
205     return mapScene;
206 }
207
208 MapEditor::State MapEditor::getState()
209 {
210     return state;
211 }
212
213 void MapEditor::setStateEditHeading(bool s)
214 {
215         if (s)
216         {
217                 if (state==Idle) state=EditHeading;
218         }
219         else    
220                 state=Idle;
221 }
222
223 bool MapEditor::isRepositionBlocked()
224 {
225         return blockReposition;
226 }
227
228 void MapEditor::setSaveStateBlocked(bool b)
229 {
230         blockSaveState=b;
231 }
232
233 bool MapEditor::isSelectBlocked()
234 {
235         if (state==EditHeading)
236                 return true;
237         else
238                 return false; 
239 }
240
241 QString MapEditor::getName (const LinkableMapObj *lmo)
242 {
243         QString s;
244         if (!lmo) return QString("Error: NULL has no name!");
245
246         if ((typeid(*lmo) == typeid(BranchObj) ||
247                                       typeid(*lmo) == typeid(MapCenterObj))) 
248         {
249                 
250                 s=(((BranchObj*)lmo)->getHeading());
251                 if (s=="") s="unnamed";
252                 return QString("branch (%1)").arg(s);
253         }       
254         if ((typeid(*lmo) == typeid(FloatImageObj) ))
255                 return QString ("floatimage [%1]").arg(((FloatImageObj*)lmo)->getOriginalFilename());
256         return QString("Unknown type has no name!");
257 }
258
259 void MapEditor::makeTmpDirs()
260 {
261         // Create unique temporary directories
262         tmpMapDir = tmpVymDir+QString("/mapeditor-%1").arg(mapNum);
263         histPath = tmpMapDir+"/history";
264         QDir d;
265         d.mkdir (tmpMapDir);
266 }
267
268 QString MapEditor::saveToDir(const QString &tmpdir, const QString &prefix, bool writeflags, const QPointF &offset, LinkableMapObj *saveSel)
269 {
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
275         
276         // Save Header
277         QString ls;
278         switch (linkstyle)
279         {
280                 case LinkableMapObj::Line: 
281                         ls="StyleLine";
282                         break;
283                 case LinkableMapObj::Parabel:
284                         ls="StyleParabel";
285                         break;
286                 case LinkableMapObj::PolyLine:  
287                         ls="StylePolyLine";
288                         break;
289                 default:
290                         ls="StylePolyParabel";
291                         break;
292         }       
293
294         QString s="<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE vymmap>\n";
295         QString colhint="";
296         if (linkcolorhint==LinkableMapObj::HeadingColor) 
297                 colhint=attribut("linkColorHint","HeadingColor");
298
299         QString mapAttr=attribut("version",vymVersion);
300         if (!saveSel)
301                 mapAttr+= attribut("author",model->getAuthor()) +
302                                   attribut("comment",model->getComment()) +
303                               attribut("date",model->getDate()) +
304                           attribut("backgroundColor", mapScene->backgroundBrush().color().name() ) +
305                           attribut("selectionColor", xelection.getColor().name() ) +
306                           attribut("linkStyle", ls ) +
307                           attribut("linkColor", defLinkColor.name() ) +
308                           attribut("defXLinkColor", defXLinkColor.name() ) +
309                           attribut("defXLinkWidth", QString().setNum(defXLinkWidth,10) ) +
310                           colhint; 
311         s+=beginElement("vymmap",mapAttr);
312         incIndent();
313
314         // Find the used flags while traversing the tree
315         standardFlagsDefault->resetUsedCounter();
316         
317         // Reset the counters before saving
318         // TODO constr. of FIO creates lots of objects, better do this in some other way...
319         FloatImageObj (mapScene).resetSaveCounter();
320
321         // Build xml recursivly
322         if (!saveSel || typeid (*saveSel) == typeid (MapCenterObj))
323                 // Save complete map, if saveSel not set
324                 s+=model->saveToDir(tmpdir,prefix,writeflags,offset);
325         else
326         {
327                 if ( typeid(*saveSel) == typeid(BranchObj) )
328                         // Save Subtree
329                         s+=((BranchObj*)(saveSel))->saveToDir(tmpdir,prefix,offset);
330                 else if ( typeid(*saveSel) == typeid(FloatImageObj) )
331                         // Save image
332                         s+=((FloatImageObj*)(saveSel))->saveToDir(tmpdir,prefix);
333         }
334
335         // Save local settings
336         s+=settings.getDataXML (destPath);
337
338         // Save selection
339         if (!xelection.isEmpty() && !saveSel ) 
340                 s+=valueElement("select",xelection.getSelectString());
341
342         decIndent();
343         s+=endElement("vymmap");
344
345         if (writeflags)
346                 standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags);
347         return s;
348 }
349
350 QString MapEditor::getHistoryDir()
351 {
352         QString histName(QString("history-%1").arg(curStep));
353         return (tmpMapDir+"/"+histName);
354 }
355
356 void MapEditor::saveState(const SaveMode &savemode, const QString &undoSelection, const QString &undoCom, const QString &redoSelection, const QString &redoCom, const QString &comment, LinkableMapObj *saveSel)
357 {
358         sendData(redoCom);      //FIXME testing
359
360         // Main saveState
361
362
363         if (blockSaveState) return;
364
365         if (debug) cout << "ME::saveState() for  "<<qPrintable (mapName)<<endl;
366         
367         // Find out current undo directory
368         if (undosAvail<stepsTotal) undosAvail++;
369         curStep++;
370         if (curStep>stepsTotal) curStep=1;
371         
372         QString backupXML="";
373         QString histDir=getHistoryDir();
374         QString bakMapPath=histDir+"/map.xml";
375
376         // Create histDir if not available
377         QDir d(histDir);
378         if (!d.exists()) 
379                 makeSubDirs (histDir);
380
381         // Save depending on how much needs to be saved 
382         if (saveSel)
383                 backupXML=saveToDir (histDir,mapName+"-",false, QPointF (),saveSel);
384                 
385         QString undoCommand="";
386         if (savemode==UndoCommand)
387         {
388                 undoCommand=undoCom;
389         }       
390         else if (savemode==PartOfMap )
391         {
392                 undoCommand=undoCom;
393                 undoCommand.replace ("PATH",bakMapPath);
394         }
395
396         if (!backupXML.isEmpty())
397                 // Write XML Data to disk
398                 saveStringToDisk (bakMapPath,backupXML);
399
400         // We would have to save all actions in a tree, to keep track of 
401         // possible redos after a action. Possible, but we are too lazy: forget about redos.
402         redosAvail=0;
403
404         // Write the current state to disk
405         undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
406         undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
407         undoSet.setEntry ("/history/curStep",QString::number(curStep));
408         undoSet.setEntry (QString("/history/step-%1/undoCommand").arg(curStep),undoCommand);
409         undoSet.setEntry (QString("/history/step-%1/undoSelection").arg(curStep),undoSelection);
410         undoSet.setEntry (QString("/history/step-%1/redoCommand").arg(curStep),redoCom);
411         undoSet.setEntry (QString("/history/step-%1/redoSelection").arg(curStep),redoSelection);
412         undoSet.setEntry (QString("/history/step-%1/comment").arg(curStep),comment);
413         undoSet.setEntry (QString("/history/version"),vymVersion);
414         undoSet.writeSettings(histPath);
415
416         if (debug)
417         {
418                 // TODO remove after testing
419                 //cout << "          into="<< histPath.toStdString()<<endl;
420                 cout << "    stepsTotal="<<stepsTotal<<
421                 ", undosAvail="<<undosAvail<<
422                 ", redosAvail="<<redosAvail<<
423                 ", curStep="<<curStep<<endl;
424                 cout << "    ---------------------------"<<endl;
425                 cout << "    comment="<<comment.toStdString()<<endl;
426                 cout << "    undoCom="<<undoCommand.toStdString()<<endl;
427                 cout << "    undoSel="<<undoSelection.toStdString()<<endl;
428                 cout << "    redoCom="<<redoCom.toStdString()<<endl;
429                 cout << "    redoSel="<<redoSelection.toStdString()<<endl;
430                 if (saveSel) cout << "    saveSel="<<qPrintable (model->getSelectString(saveSel))<<endl;
431                 cout << "    ---------------------------"<<endl;
432         }
433
434         mainWindow->updateHistory (undoSet);
435         setChanged();
436         updateActions();
437 }
438
439
440 void MapEditor::saveStateChangingPart(LinkableMapObj *undoSel, LinkableMapObj* redoSel, const QString &rc, const QString &comment)
441 {
442         // save the selected part of the map, Undo will replace part of map 
443         QString undoSelection="";
444         if (undoSel)
445                 undoSelection=model->getSelectString(undoSel);
446         else
447                 qWarning ("MapEditor::saveStateChangingPart  no undoSel given!");
448         QString redoSelection="";
449         if (redoSel)
450                 redoSelection=model->getSelectString(undoSel);
451         else
452                 qWarning ("MapEditor::saveStateChangingPart  no redoSel given!");
453                 
454
455         saveState (PartOfMap,
456                 undoSelection, "addMapReplace (\"PATH\")",
457                 redoSelection, rc, 
458                 comment, 
459                 undoSel);
460 }
461
462 void MapEditor::saveStateRemovingPart(LinkableMapObj *redoSel, const QString &comment)
463 {
464         if (!redoSel)
465         {
466                 qWarning ("MapEditor::saveStateRemovingPart  no redoSel given!");
467                 return;
468         }
469         QString undoSelection=model->getSelectString (redoSel->getParObj());
470         QString redoSelection=model->getSelectString(redoSel);
471         if (typeid(*redoSel) == typeid(BranchObj)  ) 
472         {
473                 // save the selected branch of the map, Undo will insert part of map 
474                 saveState (PartOfMap,
475                         undoSelection, QString("addMapInsert (\"PATH\",%1)").arg(((BranchObj*)redoSel)->getNum()),
476                         redoSelection, "delete ()", 
477                         comment, 
478                         redoSel);
479         }
480 }
481
482
483 void MapEditor::saveState(LinkableMapObj *undoSel, const QString &uc, LinkableMapObj *redoSel, const QString &rc, const QString &comment) 
484 {
485         // "Normal" savestate: save commands, selections and comment
486         // so just save commands for undo and redo
487         // and use current selection
488
489         QString redoSelection="";
490         if (redoSel) redoSelection=model->getSelectString(redoSel);
491         QString undoSelection="";
492         if (undoSel) undoSelection=model->getSelectString(undoSel);
493
494         saveState (UndoCommand,
495                 undoSelection, uc,
496                 redoSelection, rc, 
497                 comment, 
498                 NULL);
499 }
500
501 void MapEditor::saveState(const QString &undoSel, const QString &uc, const QString &redoSel, const QString &rc, const QString &comment) 
502 {
503         // "Normal" savestate: save commands, selections and comment
504         // so just save commands for undo and redo
505         // and use current selection
506         saveState (UndoCommand,
507                 undoSel, uc,
508                 redoSel, rc, 
509                 comment, 
510                 NULL);
511 }
512
513 void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment) 
514 {
515         // "Normal" savestate applied to model (no selection needed): 
516         // save commands  and comment
517         saveState (UndoCommand,
518                 NULL, uc,
519                 NULL, rc, 
520                 comment, 
521                 NULL);
522 }
523
524                 
525 void MapEditor::parseAtom(const QString &atom)
526 {
527         BranchObj *selb=xelection.getBranch();
528         QString s,t;
529         double x,y;
530         int n;
531         bool b,ok;
532
533         // Split string s into command and parameters
534         parser.parseAtom (atom);
535         QString com=parser.getCommand();
536         
537         // External commands
538         /////////////////////////////////////////////////////////////////////
539         if (com=="addBranch")
540         {
541                 if (xelection.isEmpty())
542                 {
543                         parser.setError (Aborted,"Nothing selected");
544                 } else if (! selb )
545                 {                                 
546                         parser.setError (Aborted,"Type of selection is not a branch");
547                 } else 
548                 {       
549                         QList <int> pl;
550                         pl << 0 <<1;
551                         if (parser.checkParCount(pl))
552                         {
553                                 if (parser.parCount()==0)
554                                         addNewBranch (0);
555                                 else
556                                 {
557                                         n=parser.parInt (ok,0);
558                                         if (ok ) addNewBranch (n);
559                                 }
560                         }
561                 }
562         /////////////////////////////////////////////////////////////////////
563         } else if (com=="addBranchBefore")
564         {
565                 if (xelection.isEmpty())
566                 {
567                         parser.setError (Aborted,"Nothing selected");
568                 } else if (! selb )
569                 {                                 
570                         parser.setError (Aborted,"Type of selection is not a branch");
571                 } else 
572                 {       
573                         if (parser.parCount()==0)
574                         {
575                                 addNewBranchBefore ();
576                         }       
577                 }
578         /////////////////////////////////////////////////////////////////////
579         } else if (com==QString("addMapCenter"))
580         {
581                 if (parser.checkParCount(2))
582                 {
583                         x=parser.parDouble (ok,0);
584                         if (ok)
585                         {
586                                 y=parser.parDouble (ok,1);
587                                 if (ok) model->addMapCenter (QPointF(x,y));
588                         }
589                 }       
590         /////////////////////////////////////////////////////////////////////
591         } else if (com==QString("addMapReplace"))
592         {
593                 if (xelection.isEmpty())
594                 {
595                         parser.setError (Aborted,"Nothing selected");
596                 } else if (! selb )
597                 {                                 
598                         parser.setError (Aborted,"Type of selection is not a branch");
599                 } else if (parser.checkParCount(1))
600                 {
601                         //s=parser.parString (ok,0);    // selection
602                         t=parser.parString (ok,0);      // path to map
603                         if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
604                         addMapReplaceInt(model->getSelectString(selb),t);       
605                 }
606         /////////////////////////////////////////////////////////////////////
607         } else if (com==QString("addMapInsert"))
608         {
609                 if (xelection.isEmpty())
610                 {
611                         parser.setError (Aborted,"Nothing selected");
612                 } else if (! selb )
613                 {                                 
614                         parser.setError (Aborted,"Type of selection is not a branch");
615                 } else 
616                 {       
617                         if (parser.checkParCount(2))
618                         {
619                                 t=parser.parString (ok,0);      // path to map
620                                 n=parser.parInt(ok,1);          // position
621                                 if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
622                                 addMapInsertInt(t,n);   
623                         }
624                 }
625         /////////////////////////////////////////////////////////////////////
626         } else if (com=="clearFlags")
627         {
628                 if (xelection.isEmpty() )
629                 {
630                         parser.setError (Aborted,"Nothing selected");
631                 } else if (! selb )
632                 {                                 
633                         parser.setError (Aborted,"Type of selection is not a branch");
634                 } else if (parser.checkParCount(0))
635                 {
636                         selb->clearStandardFlags();     
637                         selb->updateFlagsToolbar();
638                 }
639         /////////////////////////////////////////////////////////////////////
640         } else if (com=="colorBranch")
641         {
642                 if (xelection.isEmpty())
643                 {
644                         parser.setError (Aborted,"Nothing selected");
645                 } else if (! selb )
646                 {                                 
647                         parser.setError (Aborted,"Type of selection is not a branch");
648                 } else if (parser.checkParCount(1))
649                 {       
650                         QColor c=parser.parColor (ok,0);
651                         if (ok) colorBranch (c);
652                 }       
653         /////////////////////////////////////////////////////////////////////
654         } else if (com=="colorSubtree")
655         {
656                 if (xelection.isEmpty())
657                 {
658                         parser.setError (Aborted,"Nothing selected");
659                 } else if (! selb )
660                 {                                 
661                         parser.setError (Aborted,"Type of selection is not a branch");
662                 } else if (parser.checkParCount(1))
663                 {       
664                         QColor c=parser.parColor (ok,0);
665                         if (ok) colorSubtree (c);
666                 }       
667         /////////////////////////////////////////////////////////////////////
668         } else if (com=="copy")
669         {
670                 if (xelection.isEmpty())
671                 {
672                         parser.setError (Aborted,"Nothing selected");
673                 } else if (! selb )
674                 {                                 
675                         parser.setError (Aborted,"Type of selection is not a branch");
676                 } else if (parser.checkParCount(0))
677                 {       
678                         //FIXME missing action for copy
679                 }       
680         /////////////////////////////////////////////////////////////////////
681         } else if (com=="cut")
682         {
683                 if (xelection.isEmpty())
684                 {
685                         parser.setError (Aborted,"Nothing selected");
686                 } else if ( xelection.type()!=Selection::Branch  && 
687                                         xelection.type()!=Selection::MapCenter  &&
688                                         xelection.type()!=Selection::FloatImage )
689                 {                                 
690                         parser.setError (Aborted,"Type of selection is not a branch or floatimage");
691                 } else if (parser.checkParCount(0))
692                 {       
693                         cut();
694                 }       
695         /////////////////////////////////////////////////////////////////////
696         } else if (com=="delete")
697         {
698                 if (xelection.isEmpty())
699                 {
700                         parser.setError (Aborted,"Nothing selected");
701                 } 
702                 /*else if (xelection.type() != Selection::Branch && xelection.type() != Selection::FloatImage )
703                 {
704                         parser.setError (Aborted,"Type of selection is wrong.");
705                 } 
706                 */
707                 else if (parser.checkParCount(0))
708                 {       
709                         deleteSelection();
710                 }       
711         /////////////////////////////////////////////////////////////////////
712         } else if (com=="deleteKeepChilds")
713         {
714                 if (xelection.isEmpty())
715                 {
716                         parser.setError (Aborted,"Nothing selected");
717                 } else if (! selb )
718                 {
719                         parser.setError (Aborted,"Type of selection is not a branch");
720                 } else if (parser.checkParCount(0))
721                 {       
722                         deleteKeepChilds();
723                 }       
724         /////////////////////////////////////////////////////////////////////
725         } else if (com=="deleteChilds")
726         {
727                 if (xelection.isEmpty())
728                 {
729                         parser.setError (Aborted,"Nothing selected");
730                 } else if (! selb)
731                 {
732                         parser.setError (Aborted,"Type of selection is not a branch");
733                 } else if (parser.checkParCount(0))
734                 {       
735                         deleteChilds();
736                 }       
737         /////////////////////////////////////////////////////////////////////
738         } else if (com=="exportASCII")
739         {
740                 QString fname="";
741                 ok=true;
742                 if (parser.parCount()>=1)
743                         // Hey, we even have a filename
744                         fname=parser.parString(ok,0); 
745                 if (!ok)
746                 {
747                         parser.setError (Aborted,"Could not read filename");
748                 } else
749                 {
750                                 exportASCII (fname,false);
751                 }
752         /////////////////////////////////////////////////////////////////////
753         } else if (com=="exportImage")
754         {
755                 QString fname="";
756                 ok=true;
757                 if (parser.parCount()>=2)
758                         // Hey, we even have a filename
759                         fname=parser.parString(ok,0); 
760                 if (!ok)
761                 {
762                         parser.setError (Aborted,"Could not read filename");
763                 } else
764                 {
765                         QString format="PNG";
766                         if (parser.parCount()>=2)
767                         {
768                                 format=parser.parString(ok,1);
769                         }
770                         exportImage (fname,false,format);
771                 }
772         /////////////////////////////////////////////////////////////////////
773         } else if (com=="exportXHTML")
774         {
775                 QString fname="";
776                 ok=true;
777                 if (parser.parCount()>=2)
778                         // Hey, we even have a filename
779                         fname=parser.parString(ok,1); 
780                 if (!ok)
781                 {
782                         parser.setError (Aborted,"Could not read filename");
783                 } else
784                 {
785                         exportXHTML (fname,false);
786                 }
787         /////////////////////////////////////////////////////////////////////
788         } else if (com=="exportXML")
789         {
790                 QString fname="";
791                 ok=true;
792                 if (parser.parCount()>=2)
793                         // Hey, we even have a filename
794                         fname=parser.parString(ok,1); 
795                 if (!ok)
796                 {
797                         parser.setError (Aborted,"Could not read filename");
798                 } else
799                 {
800                         exportXML (fname,false);
801                 }
802         /////////////////////////////////////////////////////////////////////
803         } else if (com=="importDir")
804         {
805                 if (xelection.isEmpty())
806                 {
807                         parser.setError (Aborted,"Nothing selected");
808                 } else if (! selb )
809                 {                                 
810                         parser.setError (Aborted,"Type of selection is not a branch");
811                 } else if (parser.checkParCount(1))
812                 {
813                         s=parser.parString(ok,0);
814                         if (ok) importDirInt(s);
815                 }       
816         /////////////////////////////////////////////////////////////////////
817         } else if (com=="linkTo")
818         {
819                 if (xelection.isEmpty())
820                 {
821                         parser.setError (Aborted,"Nothing selected");
822                 } else if ( selb)
823                 {
824                         if (parser.checkParCount(4))
825                         {
826                                 // 0    selectstring of parent
827                                 // 1    num in parent (for branches)
828                                 // 2,3  x,y of mainbranch or mapcenter
829                                 s=parser.parString(ok,0);
830                                 LinkableMapObj *dst=model->findObjBySelect (s);
831                                 if (dst)
832                                 {       
833                                         if (typeid(*dst) == typeid(BranchObj) ) 
834                                         {
835                                                 // Get number in parent
836                                                 n=parser.parInt (ok,1);
837                                                 if (ok)
838                                                 {
839                                                         selb->linkTo ((BranchObj*)(dst),n);
840                                                         xelection.update();
841                                                 }       
842                                         } else if (typeid(*dst) == typeid(MapCenterObj) ) 
843                                         {
844                                                 selb->linkTo ((BranchObj*)(dst),-1);
845                                                 // Get coordinates of mainbranch
846                                                 x=parser.parDouble(ok,2);
847                                                 if (ok)
848                                                 {
849                                                         y=parser.parDouble(ok,3);
850                                                         if (ok) 
851                                                         {
852                                                                 selb->move (x,y);
853                                                                 xelection.update();
854                                                         }
855                                                 }
856                                         }       
857                                 }       
858                         }       
859                 } else if ( xelection.type() == Selection::FloatImage) 
860                 {
861                         if (parser.checkParCount(1))
862                         {
863                                 // 0    selectstring of parent
864                                 s=parser.parString(ok,0);
865                                 LinkableMapObj *dst=model->findObjBySelect (s);
866                                 if (dst)
867                                 {       
868                                         if (typeid(*dst) == typeid(BranchObj) ||
869                                                 typeid(*dst) == typeid(MapCenterObj)) 
870                                                 linkTo (model->getSelectString(dst));
871                                 } else  
872                                         parser.setError (Aborted,"Destination is not a branch");
873                         }               
874                 } else
875                         parser.setError (Aborted,"Type of selection is not a floatimage or branch");
876         /////////////////////////////////////////////////////////////////////
877         } else if (com=="loadImage")
878         {
879                 if (xelection.isEmpty())
880                 {
881                         parser.setError (Aborted,"Nothing selected");
882                 } else if (! selb )
883                 {                                 
884                         parser.setError (Aborted,"Type of selection is not a branch");
885                 } else if (parser.checkParCount(1))
886                 {
887                         s=parser.parString(ok,0);
888                         if (ok) loadFloatImageInt (s);
889                 }       
890         /////////////////////////////////////////////////////////////////////
891         } else if (com=="moveBranchUp")
892         {
893                 if (xelection.isEmpty() )
894                 {
895                         parser.setError (Aborted,"Nothing selected");
896                 } else if (! selb )
897                 {                                 
898                         parser.setError (Aborted,"Type of selection is not a branch");
899                 } else if (parser.checkParCount(0))
900                 {
901                         moveBranchUp();
902                 }       
903         /////////////////////////////////////////////////////////////////////
904         } else if (com=="moveBranchDown")
905         {
906                 if (xelection.isEmpty() )
907                 {
908                         parser.setError (Aborted,"Nothing selected");
909                 } else if (! selb )
910                 {                                 
911                         parser.setError (Aborted,"Type of selection is not a branch");
912                 } else if (parser.checkParCount(0))
913                 {
914                         moveBranchDown();
915                 }       
916         /////////////////////////////////////////////////////////////////////
917         } else if (com=="move")
918         {
919                 if (xelection.isEmpty() )
920                 {
921                         parser.setError (Aborted,"Nothing selected");
922                 } else if ( xelection.type()!=Selection::Branch  && 
923                                         xelection.type()!=Selection::MapCenter  &&
924                                         xelection.type()!=Selection::FloatImage )
925                 {                                 
926                         parser.setError (Aborted,"Type of selection is not a branch or floatimage");
927                 } else if (parser.checkParCount(2))
928                 {       
929                         x=parser.parDouble (ok,0);
930                         if (ok)
931                         {
932                                 y=parser.parDouble (ok,1);
933                                 if (ok) move (x,y);
934                         }
935                 }       
936         /////////////////////////////////////////////////////////////////////
937         } else if (com=="moveRel")
938         {
939                 if (xelection.isEmpty() )
940                 {
941                         parser.setError (Aborted,"Nothing selected");
942                 } else if ( xelection.type()!=Selection::Branch  && 
943                                         xelection.type()!=Selection::MapCenter  &&
944                                         xelection.type()!=Selection::FloatImage )
945                 {                                 
946                         parser.setError (Aborted,"Type of selection is not a branch or floatimage");
947                 } else if (parser.checkParCount(2))
948                 {       
949                         x=parser.parDouble (ok,0);
950                         if (ok)
951                         {
952                                 y=parser.parDouble (ok,1);
953                                 if (ok) moveRel (x,y);
954                         }
955                 }       
956         /////////////////////////////////////////////////////////////////////
957         } else if (com=="nop")
958         {
959         /////////////////////////////////////////////////////////////////////
960         } else if (com=="paste")
961         {
962                 if (xelection.isEmpty() )
963                 {
964                         parser.setError (Aborted,"Nothing selected");
965                 } else if (! selb )
966                 {                                 
967                         parser.setError (Aborted,"Type of selection is not a branch");
968                 } else if (parser.checkParCount(1))
969                 {       
970                         n=parser.parInt (ok,0);
971                         if (ok) pasteNoSave(n);
972                 }       
973         /////////////////////////////////////////////////////////////////////
974         } else if (com=="qa")
975         {
976                 if (xelection.isEmpty() )
977                 {
978                         parser.setError (Aborted,"Nothing selected");
979                 } else if (! selb )
980                 {                                 
981                         parser.setError (Aborted,"Type of selection is not a branch");
982                 } else if (parser.checkParCount(4))
983                 {       
984                         QString c,u;
985                         c=parser.parString (ok,0);
986                         if (!ok)
987                         {
988                                 parser.setError (Aborted,"No comment given");
989                         } else
990                         {
991                                 s=parser.parString (ok,1);
992                                 if (!ok)
993                                 {
994                                         parser.setError (Aborted,"First parameter is not a string");
995                                 } else
996                                 {
997                                         t=parser.parString (ok,2);
998                                         if (!ok)
999                                         {
1000                                                 parser.setError (Aborted,"Condition is not a string");
1001                                         } else
1002                                         {
1003                                                 u=parser.parString (ok,3);
1004                                                 if (!ok)
1005                                                 {
1006                                                         parser.setError (Aborted,"Third parameter is not a string");
1007                                                 } else
1008                                                 {
1009                                                         if (s!="heading")
1010                                                         {
1011                                                                 parser.setError (Aborted,"Unknown type: "+s);
1012                                                         } else
1013                                                         {
1014                                                                 if (! (t=="eq") ) 
1015                                                                 {
1016                                                                         parser.setError (Aborted,"Unknown operator: "+t);
1017                                                                 } else
1018                                                                 {
1019                                                                         if (! selb    )
1020                                                                         {
1021                                                                                 parser.setError (Aborted,"Type of selection is not a branch");
1022                                                                         } else
1023                                                                         {
1024                                                                                 if (selb->getHeading() == u)
1025                                                                                 {
1026                                                                                         cout << "PASSED: " << qPrintable (c)  << endl;
1027                                                                                 } else
1028                                                                                 {
1029                                                                                         cout << "FAILED: " << qPrintable (c)  << endl;
1030                                                                                 }
1031                                                                         }
1032                                                                 }
1033                                                         }
1034                                                 } 
1035                                         } 
1036                                 } 
1037                         }
1038                 }       
1039         /////////////////////////////////////////////////////////////////////
1040         } else if (com=="saveImage")
1041         {
1042                 FloatImageObj *fio=xelection.getFloatImage();
1043                 if (!fio)
1044                 {
1045                         parser.setError (Aborted,"Type of selection is not an image");
1046                 } else if (parser.checkParCount(2))
1047                 {
1048                         s=parser.parString(ok,0);
1049                         if (ok)
1050                         {
1051                                 t=parser.parString(ok,1);
1052                                 if (ok) saveFloatImageInt (fio,t,s);
1053                         }
1054                 }       
1055         /////////////////////////////////////////////////////////////////////
1056         } else if (com=="scroll")
1057         {
1058                 if (xelection.isEmpty() )
1059                 {
1060                         parser.setError (Aborted,"Nothing selected");
1061                 } else if (! selb )
1062                 {                                 
1063                         parser.setError (Aborted,"Type of selection is not a branch");
1064                 } else if (parser.checkParCount(0))
1065                 {       
1066                         if (!scrollBranch (selb))       
1067                                 parser.setError (Aborted,"Could not scroll branch");
1068                 }       
1069         /////////////////////////////////////////////////////////////////////
1070         } else if (com=="select")
1071         {
1072                 if (parser.checkParCount(1))
1073                 {
1074                         s=parser.parString(ok,0);
1075                         if (ok) select (s);
1076                 }       
1077         /////////////////////////////////////////////////////////////////////
1078         } else if (com=="selectLastBranch")
1079         {
1080                 if (xelection.isEmpty() )
1081                 {
1082                         parser.setError (Aborted,"Nothing selected");
1083                 } else if (! selb )
1084                 {                                 
1085                         parser.setError (Aborted,"Type of selection is not a branch");
1086                 } else if (parser.checkParCount(0))
1087                 {       
1088                         BranchObj *bo=selb->getLastBranch();
1089                         if (!bo)
1090                                 parser.setError (Aborted,"Could not select last branch");
1091                         selectInt (bo); 
1092                                 
1093                 }       
1094         /////////////////////////////////////////////////////////////////////
1095         } else if (com=="selectLastImage")
1096         {
1097                 if (xelection.isEmpty() )
1098                 {
1099                         parser.setError (Aborted,"Nothing selected");
1100                 } else if (! selb )
1101                 {                                 
1102                         parser.setError (Aborted,"Type of selection is not a branch");
1103                 } else if (parser.checkParCount(0))
1104                 {       
1105                         FloatImageObj *fio=selb->getLastFloatImage();
1106                         if (!fio)
1107                                 parser.setError (Aborted,"Could not select last image");
1108                         selectInt (fio);        
1109                                 
1110                 }       
1111         /////////////////////////////////////////////////////////////////////
1112         } else if (com=="selectLatestAdded")
1113         {
1114                 if (latestSelection.isEmpty() )
1115                 {
1116                         parser.setError (Aborted,"No latest added object");
1117                 } else
1118                 {       
1119                         if (!select (latestSelection))
1120                                 parser.setError (Aborted,"Could not select latest added object "+latestSelection);
1121                 }       
1122         /////////////////////////////////////////////////////////////////////
1123         } else if (com=="setFrameType")
1124         {
1125                 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1126                 {
1127                         parser.setError (Aborted,"Type of selection does not allow setting frame type");
1128                 }
1129                 else if (parser.checkParCount(1))
1130                 {
1131                         s=parser.parString(ok,0);
1132                         if (ok) setFrameType (s);
1133                 }       
1134         /////////////////////////////////////////////////////////////////////
1135         } else if (com=="setFramePenColor")
1136         {
1137                 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1138                 {
1139                         parser.setError (Aborted,"Type of selection does not allow setting of pen color");
1140                 }
1141                 else if (parser.checkParCount(1))
1142                 {
1143                         QColor c=parser.parColor(ok,0);
1144                         if (ok) setFramePenColor (c);
1145                 }       
1146         /////////////////////////////////////////////////////////////////////
1147         } else if (com=="setFrameBrushColor")
1148         {
1149                 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1150                 {
1151                         parser.setError (Aborted,"Type of selection does not allow setting brush color");
1152                 }
1153                 else if (parser.checkParCount(1))
1154                 {
1155                         QColor c=parser.parColor(ok,0);
1156                         if (ok) setFrameBrushColor (c);
1157                 }       
1158         /////////////////////////////////////////////////////////////////////
1159         } else if (com=="setFramePadding")
1160         {
1161                 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1162                 {
1163                         parser.setError (Aborted,"Type of selection does not allow setting frame padding");
1164                 }
1165                 else if (parser.checkParCount(1))
1166                 {
1167                         n=parser.parInt(ok,0);
1168                         if (ok) setFramePadding(n);
1169                 }       
1170         /////////////////////////////////////////////////////////////////////
1171         } else if (com=="setFrameBorderWidth")
1172         {
1173                 if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1174                 {
1175                         parser.setError (Aborted,"Type of selection does not allow setting frame border width");
1176                 }
1177                 else if (parser.checkParCount(1))
1178                 {
1179                         n=parser.parInt(ok,0);
1180                         if (ok) setFrameBorderWidth (n);
1181                 }       
1182         /////////////////////////////////////////////////////////////////////
1183         } else if (com=="setMapAuthor")
1184         {
1185                 if (parser.checkParCount(1))
1186                 {
1187                         s=parser.parString(ok,0);
1188                         if (ok) setMapAuthor (s);
1189                 }       
1190         /////////////////////////////////////////////////////////////////////
1191         } else if (com=="setMapComment")
1192         {
1193                 if (parser.checkParCount(1))
1194                 {
1195                         s=parser.parString(ok,0);
1196                         if (ok) setMapComment(s);
1197                 }       
1198         /////////////////////////////////////////////////////////////////////
1199         } else if (com=="setMapBackgroundColor")
1200         {
1201                 if (xelection.isEmpty() )
1202                 {
1203                         parser.setError (Aborted,"Nothing selected");
1204                 } else if (! xelection.getBranch() )
1205                 {                                 
1206                         parser.setError (Aborted,"Type of selection is not a branch");
1207                 } else if (parser.checkParCount(1))
1208                 {
1209                         QColor c=parser.parColor (ok,0);
1210                         if (ok) setMapBackgroundColor (c);
1211                 }       
1212         /////////////////////////////////////////////////////////////////////
1213         } else if (com=="setMapDefLinkColor")
1214         {
1215                 if (xelection.isEmpty() )
1216                 {
1217                         parser.setError (Aborted,"Nothing selected");
1218                 } else if (! selb )
1219                 {                                 
1220                         parser.setError (Aborted,"Type of selection is not a branch");
1221                 } else if (parser.checkParCount(1))
1222                 {
1223                         QColor c=parser.parColor (ok,0);
1224                         if (ok) setMapDefLinkColor (c);
1225                 }       
1226         /////////////////////////////////////////////////////////////////////
1227         } else if (com=="setMapLinkStyle")
1228         {
1229                 if (parser.checkParCount(1))
1230                 {
1231                         s=parser.parString (ok,0);
1232                         if (ok) setMapLinkStyle(s);
1233                 }       
1234         /////////////////////////////////////////////////////////////////////
1235         } else if (com=="setHeading")
1236         {
1237                 if (xelection.isEmpty() )
1238                 {
1239                         parser.setError (Aborted,"Nothing selected");
1240                 } else if (! selb )
1241                 {                                 
1242                         parser.setError (Aborted,"Type of selection is not a branch");
1243                 } else if (parser.checkParCount(1))
1244                 {
1245                         s=parser.parString (ok,0);
1246                         if (ok) 
1247                                 setHeading (s);
1248                 }       
1249         /////////////////////////////////////////////////////////////////////
1250         } else if (com=="setHideExport")
1251         {
1252                 if (xelection.isEmpty() )
1253                 {
1254                         parser.setError (Aborted,"Nothing selected");
1255                 } else if (xelection.type()!=Selection::Branch && xelection.type() != Selection::MapCenter &&xelection.type()!=Selection::FloatImage)
1256                 {                                 
1257                         parser.setError (Aborted,"Type of selection is not a branch or floatimage");
1258                 } else if (parser.checkParCount(1))
1259                 {
1260                         b=parser.parBool(ok,0);
1261                         if (ok) setHideExport (b);
1262                 }
1263         /////////////////////////////////////////////////////////////////////
1264         } else if (com=="setIncludeImagesHorizontally")
1265         { 
1266                 if (xelection.isEmpty() )
1267                 {
1268                         parser.setError (Aborted,"Nothing selected");
1269                 } else if (! selb)
1270                 {                                 
1271                         parser.setError (Aborted,"Type of selection is not a branch");
1272                 } else if (parser.checkParCount(1))
1273                 {
1274                         b=parser.parBool(ok,0);
1275                         if (ok) setIncludeImagesHor(b);
1276                 }
1277         /////////////////////////////////////////////////////////////////////
1278         } else if (com=="setIncludeImagesVertically")
1279         {
1280                 if (xelection.isEmpty() )
1281                 {
1282                         parser.setError (Aborted,"Nothing selected");
1283                 } else if (! selb)
1284                 {                                 
1285                         parser.setError (Aborted,"Type of selection is not a branch");
1286                 } else if (parser.checkParCount(1))
1287                 {
1288                         b=parser.parBool(ok,0);
1289                         if (ok) setIncludeImagesVer(b);
1290                 }
1291         /////////////////////////////////////////////////////////////////////
1292         } else if (com=="setHideLinkUnselected")
1293         {
1294                 if (xelection.isEmpty() )
1295                 {
1296                         parser.setError (Aborted,"Nothing selected");
1297                 } else if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
1298                 {                                 
1299                         parser.setError (Aborted,"Type of selection does not allow hiding the link");
1300                 } else if (parser.checkParCount(1))
1301                 {
1302                         b=parser.parBool(ok,0);
1303                         if (ok) setHideLinkUnselected(b);
1304                 }
1305         /////////////////////////////////////////////////////////////////////
1306         } else if (com=="setSelectionColor")
1307         {
1308                 if (parser.checkParCount(1))
1309                 {
1310                         QColor c=parser.parColor (ok,0);
1311                         if (ok) setSelectionColorInt (c);
1312                 }       
1313         /////////////////////////////////////////////////////////////////////
1314         } else if (com=="setURL")
1315         {
1316                 if (xelection.isEmpty() )
1317                 {
1318                         parser.setError (Aborted,"Nothing selected");
1319                 } else if (! selb )
1320                 {                                 
1321                         parser.setError (Aborted,"Type of selection is not a branch");
1322                 } else if (parser.checkParCount(1))
1323                 {
1324                         s=parser.parString (ok,0);
1325                         if (ok) setURL(s);
1326                 }       
1327         /////////////////////////////////////////////////////////////////////
1328         } else if (com=="setVymLink")
1329         {
1330                 if (xelection.isEmpty() )
1331                 {
1332                         parser.setError (Aborted,"Nothing selected");
1333                 } else if (! selb )
1334                 {                                 
1335                         parser.setError (Aborted,"Type of selection is not a branch");
1336                 } else if (parser.checkParCount(1))
1337                 {
1338                         s=parser.parString (ok,0);
1339                         if (ok) setVymLinkInt(s);
1340                 }       
1341         }
1342         /////////////////////////////////////////////////////////////////////
1343         else if (com=="setFlag")
1344         {
1345                 if (xelection.isEmpty() )
1346                 {
1347                         parser.setError (Aborted,"Nothing selected");
1348                 } else if (! selb )
1349                 {                                 
1350                         parser.setError (Aborted,"Type of selection is not a branch");
1351                 } else if (parser.checkParCount(1))
1352                 {
1353                         s=parser.parString(ok,0);
1354                         if (ok) 
1355                         {
1356                                 selb->activateStandardFlag(s);
1357                                 selb->updateFlagsToolbar();
1358                         }       
1359                 }
1360         /////////////////////////////////////////////////////////////////////
1361         } else if (com=="setFrameType")
1362         {
1363                 if (xelection.isEmpty() )
1364                 {
1365                         parser.setError (Aborted,"Nothing selected");
1366                 } else if (! selb )
1367                 {                                 
1368                         parser.setError (Aborted,"Type of selection is not a branch");
1369                 } else if (parser.checkParCount(1))
1370                 {
1371                         s=parser.parString(ok,0);
1372                         if (ok) 
1373                                 setFrameType (s);
1374                 }
1375         /////////////////////////////////////////////////////////////////////
1376         } else if (com=="sortChildren")
1377         {
1378                 if (xelection.isEmpty() )
1379                 {
1380                         parser.setError (Aborted,"Nothing selected");
1381                 } else if (! selb )
1382                 {                                 
1383                         parser.setError (Aborted,"Type of selection is not a branch");
1384                 } else if (parser.checkParCount(0))
1385                 {
1386                         sortChildren();
1387                 }
1388         /////////////////////////////////////////////////////////////////////
1389         } else if (com=="toggleFlag")
1390         {
1391                 if (xelection.isEmpty() )
1392                 {
1393                         parser.setError (Aborted,"Nothing selected");
1394                 } else if (! selb )
1395                 {                                 
1396                         parser.setError (Aborted,"Type of selection is not a branch");
1397                 } else if (parser.checkParCount(1))
1398                 {
1399                         s=parser.parString(ok,0);
1400                         if (ok) 
1401                         {
1402                                 selb->toggleStandardFlag(s);    
1403                                 selb->updateFlagsToolbar();
1404                         }       
1405                 }
1406         /////////////////////////////////////////////////////////////////////
1407         } else if (com=="unscroll")
1408         {
1409                 if (xelection.isEmpty() )
1410                 {
1411                         parser.setError (Aborted,"Nothing selected");
1412                 } else if (! selb )
1413                 {                                 
1414                         parser.setError (Aborted,"Type of selection is not a branch");
1415                 } else if (parser.checkParCount(0))
1416                 {       
1417                         if (!unscrollBranch (selb))     
1418                                 parser.setError (Aborted,"Could not unscroll branch");
1419                 }       
1420         /////////////////////////////////////////////////////////////////////
1421         } else if (com=="unscrollChilds")
1422         {
1423                 if (xelection.isEmpty() )
1424                 {
1425                         parser.setError (Aborted,"Nothing selected");
1426                 } else if (! selb )
1427                 {                                 
1428                         parser.setError (Aborted,"Type of selection is not a branch");
1429                 } else if (parser.checkParCount(0))
1430                 {       
1431                         unscrollChilds ();
1432                 }       
1433         /////////////////////////////////////////////////////////////////////
1434         } else if (com=="unsetFlag")
1435         {
1436                 if (xelection.isEmpty() )
1437                 {
1438                         parser.setError (Aborted,"Nothing selected");
1439                 } else if (! selb )
1440                 {                                 
1441                         parser.setError (Aborted,"Type of selection is not a branch");
1442                 } else if (parser.checkParCount(1))
1443                 {
1444                         s=parser.parString(ok,0);
1445                         if (ok) 
1446                         {
1447                                 selb->deactivateStandardFlag(s);
1448                                 selb->updateFlagsToolbar();
1449                         }       
1450                 }
1451         } else
1452                 parser.setError (Aborted,"Unknown command");
1453
1454         // Any errors?
1455         if (parser.errorLevel()==NoError)
1456         {
1457                 // setChanged();  FIXME should not be called e.g. for export?!
1458                 model->reposition();
1459         }       
1460         else    
1461         {
1462                 // TODO Error handling
1463                 qWarning("MapEditor::parseAtom: Error!");
1464                 qWarning(parser.errorMessage());
1465         } 
1466 }
1467
1468 void MapEditor::runScript (QString script)
1469 {
1470         parser.setScript (script);
1471         parser.runScript();
1472         while (parser.next() ) 
1473                 parseAtom(parser.getAtom());
1474 }
1475
1476 bool MapEditor::isDefault()
1477 {
1478     return mapDefault;
1479 }
1480
1481 bool MapEditor::hasChanged()
1482 {
1483     return mapChanged;
1484 }
1485
1486 void MapEditor::setChanged()
1487 {
1488         if (!mapChanged)
1489                 autosaveTimer->start(settings.value("/mapeditor/autosave/ms/",300000).toInt());
1490         mapChanged=true;
1491         mapDefault=false;
1492         mapUnsaved=true;
1493         findReset();
1494
1495 }
1496
1497 void MapEditor::closeMap()
1498 {
1499         // Unselect before disabling the toolbar actions
1500         if (!xelection.isEmpty() ) xelection.unselect();
1501         xelection.clear();
1502         updateActions();
1503
1504     clear();
1505         // close();  FIXME needed?
1506 }
1507
1508 void MapEditor::setFilePath(QString fpath, QString destname)
1509 {
1510         if (fpath.isEmpty() || fpath=="")
1511         {
1512                 filePath="";
1513                 fileName="";
1514                 destPath="";
1515         } else
1516         {
1517                 filePath=fpath;         // becomes absolute path
1518                 fileName=fpath;         // gets stripped of path
1519                 destPath=destname;      // needed for vymlinks and during load to reset fileChangedTime
1520
1521                 // If fpath is not an absolute path, complete it
1522                 filePath=QDir(fpath).absPath();
1523                 fileDir=filePath.left (1+filePath.findRev ("/"));
1524
1525                 // Set short name, too. Search from behind:
1526                 int i=fileName.findRev("/");
1527                 if (i>=0) fileName=fileName.remove (0,i+1);
1528
1529                 // Forget the .vym (or .xml) for name of map
1530                 mapName=fileName.left(fileName.findRev(".",-1,true) );
1531         }
1532 }
1533
1534 void MapEditor::setFilePath(QString fpath)
1535 {
1536         setFilePath (fpath,fpath);
1537 }
1538
1539 QString MapEditor::getFilePath()
1540 {
1541         return filePath;
1542 }
1543
1544 QString MapEditor::getFileName()
1545 {
1546         return fileName;
1547 }
1548
1549 QString MapEditor::getMapName()
1550 {
1551         return mapName;
1552 }
1553
1554 QString MapEditor::getDestPath()
1555 {
1556         return destPath;
1557 }
1558
1559 ErrorCode MapEditor::load (QString fname, const LoadMode &lmode, const FileType &ftype)
1560 {
1561         ErrorCode err=success;
1562
1563         parseBaseHandler *handler;
1564         fileType=ftype;
1565         switch (fileType)
1566         {
1567                 case VymMap: handler=new parseVYMHandler; break;
1568                 case FreemindMap : handler=new parseFreemindHandler; break;
1569                 default: 
1570                         QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1571                                    "Unknown FileType in MapEditor::load()");
1572                 return aborted; 
1573         }
1574         if (lmode==NewMap)
1575         {
1576                 xelection.clear();
1577                 model->setMapEditor(this);
1578                 // (map state is set later at end of load...)
1579         } else
1580         {
1581                 BranchObj *bo=xelection.getBranch();
1582                 if (!bo) return aborted;
1583                 if (lmode==ImportAdd)
1584                         saveStateChangingPart(
1585                                 bo,
1586                                 bo,
1587                                 QString("addMapInsert (%1)").arg(fname),
1588                                 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1589                 else    
1590                         saveStateChangingPart(
1591                                 bo,
1592                                 bo,
1593                                 QString("addMapReplace(%1)").arg(fname),
1594                                 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1595         }       
1596     
1597
1598         // Create temporary directory for packing
1599         bool ok;
1600         QString tmpZipDir=makeTmpDir (ok,"vym-pack");
1601         if (!ok)
1602         {
1603                 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1604                    tr("Couldn't create temporary directory before load\n"));
1605                 return aborted; 
1606         }
1607
1608         // Try to unzip file
1609         err=unzipDir (tmpZipDir,fname);
1610         QString xmlfile;
1611         if (err==nozip)
1612         {
1613                 xmlfile=fname;
1614                 zipped=false;
1615         } else
1616         {
1617                 zipped=true;
1618                 
1619                 // Look for mapname.xml
1620                 xmlfile= fname.left(fname.findRev(".",-1,true));
1621                 xmlfile=xmlfile.section( '/', -1 );
1622                 QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
1623                 if (!mfile.exists() )
1624                 {
1625                         // mapname.xml does not exist, well, 
1626                         // maybe someone renamed the mapname.vym file...
1627                         // Try to find any .xml in the toplevel 
1628                         // directory of the .vym file
1629                         QStringList flist=QDir (tmpZipDir).entryList("*.xml");
1630                         if (flist.count()==1) 
1631                         {
1632                                 // Only one entry, take this one
1633                                 xmlfile=tmpZipDir + "/"+flist.first();
1634                         } else
1635                         {
1636                                 for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it ) 
1637                                         *it=tmpZipDir + "/" + *it;
1638                                 // TODO Multiple entries, load all (but only the first one into this ME)
1639                                 //mainWindow->fileLoadFromTmp (flist);
1640                                 //returnCode=1; // Silently forget this attempt to load
1641                                 qWarning ("MainWindow::load (fn)  multimap found...");
1642                         }       
1643                                 
1644                         if (flist.isEmpty() )
1645                         {
1646                                 QMessageBox::critical( 0, tr( "Critical Load Error" ),
1647                                                    tr("Couldn't find a map (*.xml) in .vym archive.\n"));
1648                                 err=aborted;                               
1649                         }       
1650                 } //file doesn't exist  
1651                 else
1652                         xmlfile=mfile.name();
1653         }
1654
1655         QFile file( xmlfile);
1656
1657         // I am paranoid: file should exist anyway
1658         // according to check in mainwindow.
1659         if (!file.exists() )
1660         {
1661                 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1662                                    tr(QString("Couldn't open map %1").arg(file.name())));
1663                 err=aborted;    
1664         } else
1665         {
1666                 bool blockSaveStateOrg=blockSaveState;
1667                 blockReposition=true;
1668                 blockSaveState=true;
1669                 QXmlInputSource source( file);
1670                 QXmlSimpleReader reader;
1671                 reader.setContentHandler( handler );
1672                 reader.setErrorHandler( handler );
1673                 handler->setModel ( model);
1674
1675
1676                 // We need to set the tmpDir in order  to load files with rel. path
1677                 QString tmpdir;
1678                 if (zipped)
1679                         tmpdir=tmpZipDir;
1680                 else
1681                         tmpdir=fname.left(fname.findRev("/",-1));       
1682                 handler->setTmpDir (tmpdir);
1683                 handler->setInputFile (file.name());
1684                 handler->setLoadMode (lmode);
1685                 bool ok = reader.parse( source );
1686                 blockReposition=false;
1687                 blockSaveState=blockSaveStateOrg;
1688                 file.close();
1689                 if ( ok ) 
1690                 {
1691                         model->reposition();    // FIXME reposition the view instead...
1692                         xelection.update();
1693                         if (lmode==NewMap)
1694                         {
1695                                 mapDefault=false;
1696                                 mapChanged=false;
1697                                 mapUnsaved=false;
1698                                 autosaveTimer->stop();
1699                         }
1700
1701                         // Reset timestamp to check for later updates of file
1702                         fileChangedTime=QFileInfo (destPath).lastModified();
1703                 } else 
1704                 {
1705                         QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1706                                            tr( handler->errorProtocol() ) );
1707                         // returnCode=1;        
1708                         // Still return "success": the map maybe at least
1709                         // partially read by the parser
1710                 }       
1711         }       
1712
1713         // Delete tmpZipDir
1714         removeDir (QDir(tmpZipDir));
1715
1716         updateActions();
1717
1718         return err;
1719 }
1720
1721 ErrorCode MapEditor::save (const SaveMode &savemode)
1722 {
1723         QString tmpZipDir;
1724         QString mapFileName;
1725         QString safeFilePath;
1726
1727         ErrorCode err=success;
1728
1729         if (zipped)
1730                 // save as .xml
1731                 mapFileName=mapName+".xml";
1732         else
1733                 // use name given by user, even if he chooses .doc
1734                 mapFileName=fileName;
1735
1736         // Look, if we should zip the data:
1737         if (!zipped)
1738         {
1739                 QMessageBox mb( vymName,
1740                         tr("The map %1\ndid not use the compressed "
1741                         "vym file format.\nWriting it uncompressed will also write images \n"
1742                         "and flags and thus may overwrite files in the "
1743                         "given directory\n\nDo you want to write the map").arg(filePath),
1744                         QMessageBox::Warning,
1745                         QMessageBox::Yes | QMessageBox::Default,
1746                         QMessageBox::No ,
1747                         QMessageBox::Cancel | QMessageBox::Escape);
1748                 mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
1749                 mb.setButtonText( QMessageBox::No, tr("uncompressed") );
1750                 mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
1751                 switch( mb.exec() ) 
1752                 {
1753                         case QMessageBox::Yes:
1754                                 // save compressed (default file format)
1755                                 zipped=true;
1756                                 break;
1757                         case QMessageBox::No:
1758                                 // save uncompressed
1759                                 zipped=false;
1760                                 break;
1761                         case QMessageBox::Cancel:
1762                                 // do nothing
1763                                 return aborted;
1764                                 break;
1765                 }
1766         }
1767
1768         // First backup existing file, we 
1769         // don't want to add to old zip archives
1770         QFile f(destPath);
1771         if (f.exists())
1772         {
1773                 if ( settings.value ("/mapeditor/writeBackupFile").toBool())
1774                 {
1775                         QString backupFileName(destPath + "~");
1776                         QFile backupFile(backupFileName);
1777                         if (backupFile.exists() && !backupFile.remove())
1778                         {
1779                                 QMessageBox::warning(0, tr("Save Error"),
1780                                                                          tr("%1\ncould not be removed before saving").arg(backupFileName));
1781                         }
1782                         else if (!f.rename(backupFileName))
1783                         {
1784                                 QMessageBox::warning(0, tr("Save Error"),
1785                                                                          tr("%1\ncould not be renamed before saving").arg(destPath));
1786                         }
1787                 }
1788         }
1789
1790         if (zipped)
1791         {
1792                 // Create temporary directory for packing
1793                 bool ok;
1794                 tmpZipDir=makeTmpDir (ok,"vym-zip");
1795                 if (!ok)
1796                 {
1797                         QMessageBox::critical( 0, tr( "Critical Load Error" ),
1798                            tr("Couldn't create temporary directory before save\n"));
1799                         return aborted; 
1800                 }
1801
1802                 safeFilePath=filePath;
1803                 setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
1804         } // zipped
1805
1806         // Create mapName and fileDir
1807         makeSubDirs (fileDir);
1808
1809         QString saveFile;
1810         if (savemode==CompleteMap || xelection.isEmpty())
1811         {
1812                 // Save complete map
1813                 saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),NULL);
1814                 mapChanged=false;
1815                 mapUnsaved=false;
1816                 autosaveTimer->stop();
1817         }
1818         else    
1819         {
1820                 // Save part of map
1821                 if (xelection.type()==Selection::FloatImage)
1822                         saveFloatImage();
1823                 else    
1824                         saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),xelection.getBranch());  
1825                 // TODO take care of multiselections
1826         }       
1827
1828         if (!saveStringToDisk(fileDir+mapFileName,saveFile))
1829         {
1830                 err=aborted;
1831                 qWarning ("ME::saveStringToDisk failed!");
1832         }
1833
1834         if (zipped)
1835         {
1836                 // zip
1837                 if (err==success) err=zipDir (tmpZipDir,destPath);
1838
1839                 // Delete tmpDir
1840                 removeDir (QDir(tmpZipDir));
1841
1842                 // Restore original filepath outside of tmp zip dir
1843                 setFilePath (safeFilePath);
1844         }
1845
1846         updateActions();
1847         fileChangedTime=QFileInfo (destPath).lastModified();
1848         return err;
1849 }
1850
1851
1852 void MapEditor::print()
1853 {
1854 }
1855
1856 void MapEditor::setAntiAlias (bool b)
1857 {
1858         setRenderHint(QPainter::Antialiasing,b);
1859 }
1860
1861 void MapEditor::setSmoothPixmap(bool b)
1862 {
1863         setRenderHint(QPainter::SmoothPixmapTransform,b);
1864 }
1865
1866 QPixmap MapEditor::getPixmap()
1867 {
1868         QRectF mapRect=model->getTotalBBox();
1869         QPixmap pix((int)mapRect.width()+2,(int)mapRect.height()+1);
1870         QPainter pp (&pix);
1871         
1872         pp.setRenderHints(renderHints());
1873
1874         // Don't print the visualisation of selection
1875         xelection.unselect();
1876
1877         mapScene->render (      &pp, 
1878                 QRectF(0,0,mapRect.width()+1,mapRect.height()+1),
1879                 QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height() ));
1880
1881         // Restore selection
1882         xelection.reselect();
1883         
1884         return pix;
1885 }
1886
1887 void MapEditor::setHideTmpMode (HideTmpMode mode)
1888 {
1889         hidemode=mode;
1890         model->setHideTmp (hidemode);
1891         model->reposition();
1892         scene()->update();
1893 }
1894
1895 HideTmpMode MapEditor::getHideTmpMode()
1896 {
1897         return hidemode;
1898 }
1899
1900 void MapEditor::setExportMode (bool b)
1901 {
1902         // should be called before and after exports
1903         // depending on the settings
1904         if (b && settings.value("/export/useHideExport","true")=="true")
1905                 setHideTmpMode (HideExport);
1906         else    
1907                 setHideTmpMode (HideNone);
1908 }
1909
1910 void MapEditor::exportASCII(QString fname,bool askName)
1911 {
1912         ExportASCII ex;
1913         ex.setModel (model);
1914         if (fname=="") 
1915                 ex.setFile (mapName+".txt");    
1916         else
1917                 ex.setFile (fname);
1918
1919         if (askName)
1920         {
1921                 //ex.addFilter ("TXT (*.txt)");
1922                 ex.setDir(lastImageDir);
1923                 //ex.setCaption(vymName+ " -" +tr("Export as ASCII")+" "+tr("(still experimental)"));
1924                 ex.execDialog() ; 
1925         } 
1926         if (!ex.canceled())
1927         {
1928                 setExportMode(true);
1929                 ex.doExport();
1930                 setExportMode(false);
1931         }
1932 }
1933
1934 void MapEditor::exportImage(QString fname, bool askName, QString format)
1935 {
1936         if (fname=="")
1937         {
1938                 fname=mapName+".png";
1939                 format="PNG";
1940         }       
1941
1942         if (askName)
1943         {
1944                 QStringList fl;
1945                 QFileDialog *fd=new QFileDialog (this);
1946                 fd->setCaption (tr("Export map as image"));
1947                 fd->setDirectory (lastImageDir);
1948                 fd->setFileMode(QFileDialog::AnyFile);
1949                 fd->setFilters  (imageIO.getFilters() );
1950                 if (fd->exec())
1951                 {
1952                         fl=fd->selectedFiles();
1953                         fname=fl.first();
1954                         format=imageIO.getType(fd->selectedFilter());
1955                 } 
1956         }
1957
1958         setExportMode (true);
1959         QPixmap pix (getPixmap());
1960         pix.save(fname, format);
1961         setExportMode (false);
1962 }
1963
1964 void MapEditor::exportOOPresentation(const QString &fn, const QString &cf)
1965 {
1966         ExportOO ex;
1967         ex.setFile (fn);
1968         ex.setModel (model);
1969         if (ex.setConfigFile(cf)) 
1970         {
1971                 setExportMode (true);
1972                 ex.exportPresentation();
1973                 setExportMode (false);
1974         }
1975 }
1976
1977 void MapEditor::exportXHTML (const QString &dir, bool askForName)
1978 {
1979                         ExportXHTMLDialog dia(this);
1980                         dia.setFilePath (filePath );
1981                         dia.setMapName (mapName );
1982                         dia.readSettings();
1983                         if (dir!="") dia.setDir (dir);
1984
1985                         bool ok=true;
1986                         
1987                         if (askForName)
1988                         {
1989                                 if (dia.exec()!=QDialog::Accepted) 
1990                                         ok=false;
1991                                 else    
1992                                 {
1993                                         QDir d (dia.getDir());
1994                                         // Check, if warnings should be used before overwriting
1995                                         // the output directory
1996                                         if (d.exists() && d.count()>0)
1997                                         {
1998                                                 WarningDialog warn;
1999                                                 warn.showCancelButton (true);
2000                                                 warn.setText(QString(
2001                                                         "The directory %1 is not empty.\n"
2002                                                         "Do you risk to overwrite some of its contents?").arg(d.path() ));
2003                                                 warn.setCaption("Warning: Directory not empty");
2004                                                 warn.setShowAgainName("mainwindow/overwrite-dir-xhtml");
2005
2006                                                 if (warn.exec()!=QDialog::Accepted) ok=false;
2007                                         }
2008                                 }       
2009                         }
2010
2011                         if (ok)
2012                         {
2013                                 exportXML (dia.getDir(),false );
2014                                 dia.doExport(mapName );
2015                                 //if (dia.hasChanged()) setChanged();
2016                         }
2017 }
2018
2019 void MapEditor::exportXML(QString dir, bool askForName)
2020 {
2021         if (askForName)
2022         {
2023                 dir=browseDirectory(this,tr("Export XML to directory"));
2024                 if (dir =="" && !reallyWriteDirectory(dir) )
2025                 return;
2026         }
2027
2028         // Hide stuff during export, if settings want this
2029         setExportMode (true);
2030
2031         // Create subdirectories
2032         makeSubDirs (dir);
2033
2034         // write to directory
2035         QString saveFile=saveToDir (dir,mapName+"-",true,model->getTotalBBox().topLeft() ,NULL);
2036         QFile file;
2037
2038         file.setName ( dir + "/"+mapName+".xml");
2039         if ( !file.open( QIODevice::WriteOnly ) )
2040         {
2041                 // This should neverever happen
2042                 QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open %1").arg(file.name()));
2043                 return;
2044         }       
2045
2046         // Write it finally, and write in UTF8, no matter what 
2047         QTextStream ts( &file );
2048         ts.setEncoding (QTextStream::UnicodeUTF8);
2049         ts << saveFile;
2050         file.close();
2051
2052         // Now write image, too
2053         exportImage (dir+"/images/"+mapName+".png",false,"PNG");
2054
2055         setExportMode (false);
2056 }
2057
2058 void MapEditor::clear()
2059 {
2060         xelection.unselect();
2061         model->clear();
2062 }
2063
2064 void MapEditor::copy()
2065 {
2066         LinkableMapObj *sel=xelection.single();
2067         if (sel)
2068         {
2069                 if (redosAvail == 0)
2070                 {
2071                         // Copy to history
2072                         QString s=model->getSelectString(sel);
2073                         saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy selection to clipboard",sel  );
2074                         curClipboard=curStep;
2075                 }
2076
2077                 // Copy also to global clipboard, because we are at last step in history
2078                 QString bakMapName(QString("history-%1").arg(curStep));
2079                 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2080                 copyDir (bakMapDir,clipboardDir );
2081
2082                 clipboardEmpty=false;
2083                 updateActions();
2084         }           
2085 }
2086
2087 void MapEditor::redo()
2088 {
2089         // Can we undo at all?
2090         if (redosAvail<1) return;
2091
2092         bool blockSaveStateOrg=blockSaveState;
2093         blockSaveState=true;
2094         
2095         redosAvail--;
2096
2097         if (undosAvail<stepsTotal) undosAvail++;
2098         curStep++;
2099         if (curStep>stepsTotal) curStep=1;
2100         QString undoCommand=  undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2101         QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2102         QString redoCommand=  undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2103         QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2104         QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2105         QString version=undoSet.readEntry ("/history/version");
2106
2107         /* TODO Maybe check for version, if we save the history
2108         if (!checkVersion(version))
2109                 QMessageBox::warning(0,tr("Warning"),
2110                         tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2111         */ 
2112
2113         // Find out current undo directory
2114         QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2115
2116         if (debug)
2117         {
2118                 cout << "ME::redo() begin\n";
2119                 cout << "    undosAvail="<<undosAvail<<endl;
2120                 cout << "    redosAvail="<<redosAvail<<endl;
2121                 cout << "       curStep="<<curStep<<endl;
2122                 cout << "    ---------------------------"<<endl;
2123                 cout << "    comment="<<comment.toStdString()<<endl;
2124                 cout << "    undoCom="<<undoCommand.toStdString()<<endl;
2125                 cout << "    undoSel="<<undoSelection.toStdString()<<endl;
2126                 cout << "    redoCom="<<redoCommand.toStdString()<<endl;
2127                 cout << "    redoSel="<<redoSelection.toStdString()<<endl;
2128                 cout << "    ---------------------------"<<endl<<endl;
2129         }
2130
2131         // select  object before redo
2132         if (!redoSelection.isEmpty())
2133                 select (redoSelection);
2134
2135
2136         parseAtom (redoCommand);
2137         model->reposition();
2138
2139         blockSaveState=blockSaveStateOrg;
2140
2141         undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2142         undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2143         undoSet.setEntry ("/history/curStep",QString::number(curStep));
2144         undoSet.writeSettings(histPath);
2145
2146         mainWindow->updateHistory (undoSet);
2147         updateActions();
2148
2149         /* TODO remove testing
2150         cout << "ME::redo() end\n";
2151         cout << "    undosAvail="<<undosAvail<<endl;
2152         cout << "    redosAvail="<<redosAvail<<endl;
2153         cout << "       curStep="<<curStep<<endl;
2154         cout << "    ---------------------------"<<endl<<endl;
2155         */
2156
2157
2158 }
2159
2160 bool MapEditor::isRedoAvailable()
2161 {
2162         if (undoSet.readNumEntry("/history/redosAvail",0)>0)
2163                 return true;
2164         else    
2165                 return false;
2166 }
2167
2168 void MapEditor::undo()
2169 {
2170         // Can we undo at all?
2171         if (undosAvail<1) return;
2172
2173         mainWindow->statusMessage (tr("Autosave disabled during undo."));
2174
2175         bool blockSaveStateOrg=blockSaveState;
2176         blockSaveState=true;
2177         
2178         QString undoCommand=  undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
2179         QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
2180         QString redoCommand=  undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
2181         QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
2182         QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
2183         QString version=undoSet.readEntry ("/history/version");
2184
2185         /* TODO Maybe check for version, if we save the history
2186         if (!checkVersion(version))
2187                 QMessageBox::warning(0,tr("Warning"),
2188                         tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
2189         */
2190
2191         // Find out current undo directory
2192         QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
2193
2194         // select  object before undo
2195         if (!undoSelection.isEmpty())
2196                 select (undoSelection);
2197
2198         if (debug)
2199         {
2200                 cout << "ME::undo() begin\n";
2201                 cout << "    undosAvail="<<undosAvail<<endl;
2202                 cout << "    redosAvail="<<redosAvail<<endl;
2203                 cout << "       curStep="<<curStep<<endl;
2204                 cout << "    ---------------------------"<<endl;
2205                 cout << "    comment="<<comment.toStdString()<<endl;
2206                 cout << "    undoCom="<<undoCommand.toStdString()<<endl;
2207                 cout << "    undoSel="<<undoSelection.toStdString()<<endl;
2208                 cout << "    redoCom="<<redoCommand.toStdString()<<endl;
2209                 cout << "    redoSel="<<redoSelection.toStdString()<<endl;
2210                 cout << "    ---------------------------"<<endl<<endl;
2211         }       
2212         parseAtom (undoCommand);
2213         model->reposition();
2214
2215         undosAvail--;
2216         curStep--; 
2217         if (curStep<1) curStep=stepsTotal;
2218
2219         redosAvail++;
2220
2221         blockSaveState=blockSaveStateOrg;
2222 /* TODO remove testing
2223         cout << "ME::undo() end\n";
2224         cout << "    undosAvail="<<undosAvail<<endl;
2225         cout << "    redosAvail="<<redosAvail<<endl;
2226         cout << "       curStep="<<curStep<<endl;
2227         cout << "    ---------------------------"<<endl<<endl;
2228 */
2229
2230         undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
2231         undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
2232         undoSet.setEntry ("/history/curStep",QString::number(curStep));
2233         undoSet.writeSettings(histPath);
2234
2235         mainWindow->updateHistory (undoSet);
2236         updateActions();
2237         xelection.update();
2238         ensureSelectionVisible();
2239 }
2240
2241 bool MapEditor::isUndoAvailable()
2242 {
2243         if (undoSet.readNumEntry("/history/undosAvail",0)>0)
2244                 return true;
2245         else    
2246                 return false;
2247 }
2248
2249 void MapEditor::gotoHistoryStep (int i)
2250 {
2251         // Restore variables
2252         int undosAvail=undoSet.readNumEntry (QString("/history/undosAvail"));
2253         int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
2254
2255         if (i<0) i=undosAvail+redosAvail;
2256
2257         // Clicking above current step makes us undo things
2258         if (i<undosAvail) 
2259         {       
2260                 for (int j=0; j<undosAvail-i; j++) undo();
2261                 return;
2262         }       
2263         // Clicking below current step makes us redo things
2264         if (i>undosAvail) 
2265                 for (int j=undosAvail; j<i; j++) 
2266                 {
2267                         if (debug) cout << "ME::gotoHistoryStep redo "<<j<<"/"<<undosAvail<<" i="<<i<<endl;
2268                         redo();
2269                 }
2270
2271         // And ignore clicking the current row ;-)      
2272 }
2273
2274 void MapEditor::addMapReplaceInt(const QString &undoSel, const QString &path)
2275 {
2276         QString pathDir=path.left(path.findRev("/"));
2277         QDir d(pathDir);
2278         QFile file (path);
2279
2280         if (d.exists() )
2281         {
2282                 // We need to parse saved XML data
2283                 parseVYMHandler handler;
2284                 QXmlInputSource source( file);
2285                 QXmlSimpleReader reader;
2286                 reader.setContentHandler( &handler );
2287                 reader.setErrorHandler( &handler );
2288                 handler.setModel ( model);
2289                 handler.setTmpDir ( pathDir );  // needed to load files with rel. path
2290                 if (undoSel.isEmpty())
2291                 {
2292                         unselect();
2293                         model->clear();
2294                         handler.setLoadMode (NewMap);
2295                 } else  
2296                 {
2297                         select (undoSel);
2298                         handler.setLoadMode (ImportReplace);
2299                 }       
2300                 blockReposition=true;
2301                 bool ok = reader.parse( source );
2302                 blockReposition=false;
2303                 if (! ok ) 
2304                 {       
2305                         // This should never ever happen
2306                         QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2307                                                                     handler.errorProtocol());
2308                 }
2309         } else  
2310                 QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2311 }
2312
2313 void MapEditor::addMapInsertInt (const QString &path, int pos)
2314 {
2315         BranchObj *sel=xelection.getBranch();
2316         if (sel)
2317         {
2318                 QString pathDir=path.left(path.findRev("/"));
2319                 QDir d(pathDir);
2320                 QFile file (path);
2321
2322                 if (d.exists() )
2323                 {
2324                         // We need to parse saved XML data
2325                         parseVYMHandler handler;
2326                         QXmlInputSource source( file);
2327                         QXmlSimpleReader reader;
2328                         reader.setContentHandler( &handler );
2329                         reader.setErrorHandler( &handler );
2330                         handler.setModel (model);
2331                         handler.setTmpDir ( pathDir );  // needed to load files with rel. path
2332                         handler.setLoadMode (ImportAdd);
2333                         blockReposition=true;
2334                         bool ok = reader.parse( source );
2335                         blockReposition=false;
2336                         if (! ok ) 
2337                         {       
2338                                 // This should never ever happen
2339                                 QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
2340                                                                                 handler.errorProtocol());
2341                         }
2342                         if (sel->getDepth()>0)
2343                                 sel->getLastBranch()->linkTo (sel,pos);
2344                 } else  
2345                         QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
2346         }               
2347 }
2348
2349 void MapEditor::pasteNoSave(const int &n)
2350 {
2351         bool old=blockSaveState;
2352         blockSaveState=true;
2353         bool zippedOrg=zipped;
2354         if (redosAvail > 0 || n!=0)
2355         {
2356                 // Use the "historical" buffer
2357                 QString bakMapName(QString("history-%1").arg(n));
2358                 QString bakMapDir(tmpMapDir +"/"+bakMapName);
2359                 load (bakMapDir+"/"+clipboardFile,ImportAdd, VymMap);
2360         } else
2361                 // Use the global buffer
2362                 load (clipboardDir+"/"+clipboardFile,ImportAdd, VymMap);
2363         zipped=zippedOrg;
2364         blockSaveState=old;
2365 }
2366
2367 void MapEditor::paste()         
2368 {   
2369         BranchObj *sel=xelection.getBranch();
2370         if (sel)
2371         {
2372                 saveStateChangingPart(
2373                         sel,
2374                         sel,
2375                         QString ("paste (%1)").arg(curClipboard),
2376                         QString("Paste to %1").arg( getName(sel))
2377                 );
2378                 pasteNoSave(0);
2379                 model->reposition();
2380         }
2381 }
2382
2383 void MapEditor::cut()
2384 {
2385         LinkableMapObj *sel=xelection.single();
2386         if ( sel && (xelection.type() == Selection::Branch ||
2387                 xelection.type()==Selection::MapCenter ||
2388                 xelection.type()==Selection::FloatImage))
2389         {
2390         /* No savestate! savestate is called in cutNoSave
2391                 saveStateChangingPart(
2392                         sel->getParObj(),
2393                         sel,
2394                         "cut ()",
2395                         QString("Cut %1").arg(getName(sel ))
2396                 );
2397         */      
2398                 copy();
2399                 deleteSelection();
2400                 model->reposition();
2401         }
2402 }
2403
2404 void MapEditor::move(const double &x, const double &y)
2405 {
2406         LinkableMapObj *sel=xelection.single();
2407         if (sel)
2408         {
2409         QPointF ap(sel->getAbsPos());
2410         QPointF to(x, y);
2411         if (ap != to)
2412         {
2413             QString ps=qpointfToString(ap);
2414             QString s=xelection.getSelectString();
2415             saveState(
2416                 s, "move "+ps, 
2417                 s, "move "+qpointfToString(to), 
2418                 QString("Move %1 to %2").arg(getName(sel)).arg(ps));
2419             sel->move(x,y);
2420             model->reposition();
2421             xelection.update();
2422         }
2423         }
2424 }
2425
2426 void MapEditor::moveRel (const double &x, const double &y)
2427 {
2428         LinkableMapObj *sel=xelection.single();
2429         if (sel)
2430         {
2431         QPointF rp(sel->getRelPos());
2432         QPointF to(x, y);
2433         if (rp != to)
2434         {
2435             QString ps=qpointfToString (sel->getRelPos());
2436             QString s=model->getSelectString(sel);
2437             saveState(
2438                 s, "moveRel "+ps, 
2439                 s, "moveRel "+qpointfToString(to), 
2440                 QString("Move %1 to relative position %2").arg(getName(sel)).arg(ps));
2441             ((OrnamentedObj*)sel)->move2RelPos (x,y);
2442             model->reposition();
2443             sel->updateLink();
2444             xelection.update();
2445         }
2446         }
2447 }
2448
2449 void MapEditor::moveBranchUp()
2450 {
2451         BranchObj* bo=xelection.getBranch();
2452         BranchObj* par;
2453         if (bo)
2454         {
2455                 if (!bo->canMoveBranchUp()) return;
2456                 par=(BranchObj*)(bo->getParObj());
2457                 BranchObj *obo=par->moveBranchUp (bo);  // bo will be the one below selection
2458                 saveState (model->getSelectString(bo),"moveBranchDown ()",model->getSelectString(obo),"moveBranchUp ()",QString("Move up %1").arg(getName(bo)));
2459                 model->reposition();
2460                 scene()->update();
2461                 xelection.update();
2462                 ensureSelectionVisible();
2463         }
2464 }
2465
2466 void MapEditor::moveBranchDown()
2467 {
2468         BranchObj* bo=xelection.getBranch();
2469         BranchObj* par;
2470         if (bo)
2471         {
2472                 if (!bo->canMoveBranchDown()) return;
2473                 par=(BranchObj*)(bo->getParObj());
2474                 BranchObj *obo=par->moveBranchDown(bo); // bo will be the one above selection
2475                 saveState(model->getSelectString(bo),"moveBranchUp ()",model->getSelectString(obo),"moveBranchDown ()",QString("Move down %1").arg(getName(bo)));
2476                 model->reposition();
2477                 scene()->update();
2478                 xelection.update();
2479                 ensureSelectionVisible();
2480         }       
2481 }
2482
2483 void MapEditor::sortChildren()
2484 {
2485         BranchObj* bo=xelection.getBranch();
2486         if (bo)
2487         {
2488                 if(bo->countBranches()>1)
2489                 {
2490                         saveStateChangingPart(bo,bo, "sortChildren ()",QString("Sort children of %1").arg(getName(bo)));
2491                         bo->sortChildren();
2492                         model->reposition();
2493                         ensureSelectionVisible();
2494                 }
2495         }
2496 }
2497
2498 void MapEditor::linkTo(const QString &dstString)        
2499 {
2500         FloatImageObj *fio=xelection.getFloatImage();
2501         if (fio)
2502         {
2503                 BranchObj *dst=(BranchObj*)(model->findObjBySelect(dstString));
2504                 if (dst && (typeid(*dst)==typeid (BranchObj) || 
2505                                         typeid(*dst)==typeid (MapCenterObj)))
2506                 {                       
2507                         LinkableMapObj *dstPar=dst->getParObj();
2508                         QString parString=model->getSelectString(dstPar);
2509                         QString fioPreSelectString=model->getSelectString(fio);
2510                         QString fioPreParentSelectString=model->getSelectString (fio->getParObj());
2511                         ((BranchObj*)(dst))->addFloatImage (fio);
2512                         xelection.unselect();
2513                         ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio);
2514                         fio=((BranchObj*)(dst))->getLastFloatImage();
2515                         fio->setRelPos();
2516                         fio->reposition();
2517                         xelection.select(fio);
2518                         saveState(
2519                                 model->getSelectString(fio),
2520                                 QString("linkTo (\"%1\")").arg(fioPreParentSelectString), 
2521                                 fioPreSelectString, 
2522                                 QString ("linkTo (\"%1\")").arg(dstString),
2523                                 QString ("Link floatimage to %1").arg(getName(dst)));
2524                 }
2525         }
2526 }
2527
2528 QString MapEditor::getHeading(bool &ok, QPoint &p)
2529 {
2530         BranchObj *bo=xelection.getBranch();
2531         if (bo)
2532         {
2533                 ok=true;
2534                 p=mapFromScene(bo->getAbsPos());
2535                 return bo->getHeading();
2536         }
2537         ok=false;
2538         return QString();
2539 }
2540
2541 void MapEditor::setHeading(const QString &s)
2542 {
2543         BranchObj *sel=xelection.getBranch();
2544         if (sel)
2545         {
2546                 saveState(
2547                         sel,
2548                         "setHeading (\""+sel->getHeading()+"\")", 
2549                         sel,
2550                         "setHeading (\""+s+"\")", 
2551                         QString("Set heading of %1 to \"%2\"").arg(getName(sel)).arg(s) );
2552                 sel->setHeading(s );
2553                 model->reposition();
2554                 xelection.update();
2555                 ensureSelectionVisible();
2556         }
2557 }
2558
2559 void MapEditor::setHeadingInt(const QString &s)
2560 {
2561         BranchObj *bo=xelection.getBranch();
2562         if (bo)
2563         {
2564                 bo->setHeading(s);
2565                 model->reposition();
2566                 xelection.update();
2567                 ensureSelectionVisible();
2568         }
2569 }
2570
2571 void MapEditor::setVymLinkInt (const QString &s)
2572 {
2573         // Internal function, no saveState needed
2574         BranchObj *bo=xelection.getBranch();
2575         if (bo)
2576         {
2577                 bo->setVymLink(s);
2578                 model->reposition();
2579                 updateActions();
2580                 xelection.update();
2581                 ensureSelectionVisible();
2582         }
2583 }
2584
2585 BranchObj* MapEditor::addMapCenter ()
2586 {
2587         MapCenterObj *mco= model->addMapCenter(contextMenuPos);
2588         xelection.select (mco);
2589         updateActions();
2590         ensureSelectionVisible();
2591         saveState (
2592                 mco,
2593                 "delete()",
2594                 NULL,
2595                 QString ("addMapCenter (%1,%2)").arg (contextMenuPos.x()).arg(contextMenuPos.y()),
2596                 QString ("Adding MapCenter to (%1,%2").arg (contextMenuPos.x()).arg(contextMenuPos.y())
2597         );      
2598         return mco;     
2599 }
2600
2601 BranchObj* MapEditor::addNewBranchInt(int num)
2602 {
2603         // Depending on pos:
2604         // -3           insert in childs of parent  above selection 
2605         // -2           add branch to selection 
2606         // -1           insert in childs of parent below selection 
2607         // 0..n         insert in childs of parent at pos
2608         BranchObj *newbo=NULL;
2609         BranchObj *bo=xelection.getBranch();
2610         if (bo)
2611         {
2612                 if (num==-2)
2613                 {
2614                         // save scroll state. If scrolled, automatically select
2615                         // new branch in order to tmp unscroll parent...
2616                         newbo=bo->addBranch();
2617                         
2618                 }else if (num==-1)
2619                 {
2620                         num=bo->getNum()+1;
2621                         bo=(BranchObj*)bo->getParObj();
2622                         if (bo) newbo=bo->insertBranch(num);
2623                 }else if (num==-3)
2624                 {
2625                         num=bo->getNum();
2626                         bo=(BranchObj*)bo->getParObj();
2627                         if (bo) newbo=bo->insertBranch(num);
2628                 }
2629                 if (!newbo) return NULL;
2630         }       
2631         return newbo;
2632 }       
2633
2634 BranchObj* MapEditor::addNewBranch(int pos)
2635 {
2636         // Different meaning than num in addNewBranchInt!
2637         // -1   add above
2638         //  0   add as child
2639         // +1   add below
2640         BranchObj *bo = xelection.getBranch();
2641         BranchObj *newbo=NULL;
2642
2643         if (bo)
2644         {
2645                 setCursor (Qt::ArrowCursor);
2646
2647                 newbo=addNewBranchInt (pos-2);
2648
2649                 if (newbo)
2650                 {
2651                         saveState(
2652                                 newbo,          
2653                                 "delete ()",
2654                                 bo,
2655                                 QString ("addBranch (%1)").arg(pos),
2656                                 QString ("Add new branch to %1").arg(getName(bo)));     
2657
2658                         model->reposition();
2659                         xelection.update();
2660                         latestSelection=model->getSelectString(newbo);
2661                         // In Network mode, the client needs to know where the new branch is,
2662                         // so we have to pass on this information via saveState.
2663                         // TODO: Get rid of this positioning workaround
2664                         QString ps=qpointfToString (newbo->getAbsPos());
2665                         sendData ("selectLatestAdded ()");
2666                         sendData (QString("move %1").arg(ps));
2667                         sendSelection();
2668                 }
2669         }       
2670         return newbo;
2671 }
2672
2673
2674 BranchObj* MapEditor::addNewBranchBefore()
2675 {
2676         BranchObj *newbo=NULL;
2677         BranchObj *bo = xelection.getBranch();
2678         if (bo && xelection.type()==Selection::Branch)
2679                  // We accept no MapCenterObj here, so we _have_ a parent
2680         {
2681                 QPointF p=bo->getRelPos();
2682
2683
2684                 BranchObj *parbo=(BranchObj*)(bo->getParObj());
2685
2686                 // add below selection
2687                 newbo=parbo->insertBranch(bo->getNum()+1);
2688                 if (newbo)
2689                 {
2690                         newbo->move2RelPos (p);
2691
2692                         // Move selection to new branch
2693                         bo->linkTo (newbo,-1);
2694
2695                         saveState (newbo, "deleteKeepChilds ()", newbo, "addBranchBefore ()", 
2696                                 QString ("Add branch before %1").arg(getName(bo)));
2697
2698                         model->reposition();
2699                         xelection.update();
2700                 }
2701         }       
2702         latestSelection=xelection.getSelectString();
2703         return newbo;
2704 }
2705
2706 void MapEditor::deleteSelection()
2707 {
2708         BranchObj *bo = xelection.getBranch();
2709         if (bo && xelection.type()==Selection::MapCenter)
2710         {
2711         //      BranchObj* par=(BranchObj*)(bo->getParObj());
2712                 xelection.unselect();
2713         /* FIXME Note:  does saveStateRemovingPart work for MCO? (No parent!)
2714                 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2715                 */
2716                 bo=model->removeMapCenter ((MapCenterObj*)bo);
2717                 if (bo) 
2718                 {
2719                         xelection.select (bo);
2720                         ensureSelectionVisible();
2721                         xelection.update();
2722                 }       
2723                 model->reposition();
2724                 return;
2725         }
2726         if (bo && xelection.type()==Selection::Branch)
2727         {
2728                 BranchObj* par=(BranchObj*)bo->getParObj();
2729                 xelection.unselect();
2730                 saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
2731                 par->removeBranch(bo);
2732                 xelection.select (par);
2733                 ensureSelectionVisible();
2734                 model->reposition();
2735 //              xelection.update();
2736                 xelection.update();
2737                 return;
2738         }
2739         FloatImageObj *fio=xelection.getFloatImage();
2740         if (fio)
2741         {
2742                 BranchObj* par=(BranchObj*)fio->getParObj();
2743                 saveStateChangingPart(
2744                         par, 
2745                         fio,
2746                         "delete ()",
2747                         QString("Delete %1").arg(getName(fio))
2748                 );
2749                 xelection.unselect();
2750                 par->removeFloatImage(fio);
2751                 xelection.select (par);
2752                 model->reposition();
2753                 xelection.update();
2754                 ensureSelectionVisible();
2755                 return;
2756         }
2757 }
2758
2759 LinkableMapObj* MapEditor::getSelection()
2760 {
2761         return xelection.single();
2762 }
2763
2764 BranchObj* MapEditor::getSelectedBranch()
2765 {
2766         return xelection.getBranch();
2767 }
2768
2769 FloatImageObj* MapEditor::getSelectedFloatImage()
2770 {
2771         return xelection.getFloatImage();
2772 }
2773
2774 void MapEditor::unselect()
2775 {
2776         xelection.unselect();
2777 }       
2778
2779 void MapEditor::reselect()
2780 {
2781         xelection.reselect();
2782 }       
2783
2784 bool MapEditor::select (const QString &s)
2785 {
2786         if (xelection.select(s))
2787         {
2788                 xelection.update();
2789                 ensureSelectionVisible();
2790                 sendSelection ();
2791                 return true;
2792         }
2793         return false;
2794 }
2795
2796 bool MapEditor::select (LinkableMapObj *lmo)
2797 {
2798         if (xelection.select(lmo))
2799         {
2800                 xelection.update();
2801                 ensureSelectionVisible();
2802                 sendSelection ();
2803                 return true;
2804         }
2805         return false;
2806 }
2807
2808 QString MapEditor::getSelectString()
2809 {
2810         return xelection.getSelectString();
2811 }
2812
2813 void MapEditor::selectInt (LinkableMapObj *lmo)
2814 {
2815         if (lmo && xelection.single()!= lmo && isSelectBlocked()==false )
2816         {
2817                 xelection.select(lmo);
2818                 xelection.update();
2819                 sendSelection ();
2820         }       
2821 }
2822
2823 void MapEditor::selectNextBranchInt()
2824 {
2825         // Increase number of branch
2826         LinkableMapObj *sel=xelection.single();
2827         if (sel)
2828         {
2829                 QString s=xelection.getSelectString();
2830                 QString part;
2831                 QString typ;
2832                 QString num;
2833
2834                 // Where am I? 
2835                 part=s.section(",",-1);
2836                 typ=part.left (3);
2837                 num=part.right(part.length() - 3);
2838
2839                 s=s.left (s.length() -num.length());
2840
2841                 // Go to next lmo
2842                 num=QString ("%1").arg(num.toUInt()+1);
2843
2844                 s=s+num;
2845                 
2846                 // Try to select this one
2847                 if (select (s)) return;
2848
2849                 // We have no direct successor, 
2850                 // try to increase the parental number in order to
2851                 // find a successor with same depth
2852
2853                 int d=xelection.single()->getDepth();
2854                 int oldDepth=d;
2855                 int i;
2856                 bool found=false;
2857                 bool b;
2858                 while (!found && d>0)
2859                 {
2860                         s=s.section (",",0,d-1);
2861                         // replace substring of current depth in s with "1"
2862                         part=s.section(",",-1);
2863                         typ=part.left (3);
2864                         num=part.right(part.length() - 3);
2865
2866                         if (d>1)
2867                         {       
2868                                 // increase number of parent
2869                                 num=QString ("%1").arg(num.toUInt()+1);
2870                                 s=s.section (",",0,d-2) + ","+ typ+num;
2871                         } else
2872                         {
2873                                 // Special case, look at orientation
2874                                 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
2875                                         num=QString ("%1").arg(num.toUInt()+1);
2876                                 else    
2877                                         num=QString ("%1").arg(num.toUInt()-1);
2878                                 s=typ+num;
2879                         }       
2880
2881                         if (select (s))
2882                                 // pad to oldDepth, select the first branch for each depth
2883                                 for (i=d;i<oldDepth;i++)
2884                                 {
2885                                         b=select (s);
2886                                         if (b)
2887                                         {       
2888                                                 if ( xelection.getBranch()->countBranches()>0)
2889                                                         s+=",bo:0";
2890                                                 else    
2891                                                         break;
2892                                         } else
2893                                                 break;
2894                                 }       
2895
2896                         // try to select the freshly built string
2897                         found=select(s);
2898                         d--;
2899                 }
2900                 return;
2901         }       
2902 }
2903
2904 void MapEditor::selectPrevBranchInt()
2905 {
2906         // Decrease number of branch
2907         BranchObj *bo=xelection.getBranch();
2908         if (bo)
2909         {
2910                 QString s=xelection.getSelectString();
2911                 QString part;
2912                 QString typ;
2913                 QString num;
2914
2915                 // Where am I? 
2916                 part=s.section(",",-1);
2917                 typ=part.left (3);
2918                 num=part.right(part.length() - 3);
2919
2920                 s=s.left (s.length() -num.length());
2921
2922                 int n=num.toInt()-1;
2923                 
2924                 // Go to next lmo
2925                 num=QString ("%1").arg(n);
2926                 s=s+num;
2927                 
2928                 // Try to select this one
2929                 if (n>=0 && select (s)) return;
2930
2931                 // We have no direct precessor, 
2932                 // try to decrease the parental number in order to
2933                 // find a precessor with same depth
2934
2935                 int d=xelection.single()->getDepth();
2936                 int oldDepth=d;
2937                 int i;
2938                 bool found=false;
2939                 bool b;
2940                 while (!found && d>0)
2941                 {
2942                         s=s.section (",",0,d-1);
2943                         // replace substring of current depth in s with "1"
2944                         part=s.section(",",-1);
2945                         typ=part.left (3);
2946                         num=part.right(part.length() - 3);
2947
2948                         if (d>1)
2949                         {
2950                                 // decrease number of parent
2951                                 num=QString ("%1").arg(num.toInt()-1);
2952                                 s=s.section (",",0,d-2) + ","+ typ+num;
2953                         } else
2954                         {
2955                                 // Special case, look at orientation
2956                                 if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
2957                                         num=QString ("%1").arg(num.toInt()-1);
2958                                 else    
2959                                         num=QString ("%1").arg(num.toInt()+1);
2960                                 s=typ+num;
2961                         }       
2962
2963                         if (select(s))
2964                                 // pad to oldDepth, select the last branch for each depth
2965                                 for (i=d;i<oldDepth;i++)
2966                                 {
2967                                         b=select (s);
2968                                         if (b)
2969                                                 if ( xelection.getBranch()->countBranches()>0)
2970                                                         s+=",bo:"+ QString ("%1").arg( xelection.getBranch()->countBranches()-1 );
2971                                                 else    
2972                                                         break;
2973                                         else
2974                                                 break;
2975                                 }       
2976                         
2977                         // try to select the freshly built string
2978                         found=select(s);
2979                         d--;
2980                 }
2981                 return;
2982         }       
2983 }
2984
2985 void MapEditor::selectUpperBranch()
2986 {
2987         if (isSelectBlocked() ) return;
2988
2989         BranchObj *bo=xelection.getBranch();
2990         if (bo && xelection.type()==Selection::Branch)
2991         {
2992                 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
2993                         selectPrevBranchInt();
2994                 else
2995                         if (bo->getDepth()==1)
2996                                 selectNextBranchInt();
2997                         else
2998                                 selectPrevBranchInt();
2999         }
3000 }
3001
3002 void MapEditor::selectLowerBranch()
3003 {
3004         if (isSelectBlocked() ) return;
3005
3006         BranchObj *bo=xelection.getBranch();
3007         if (bo && xelection.type()==Selection::Branch)
3008         {
3009                 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3010                         selectNextBranchInt();
3011                 else
3012                         if (bo->getDepth()==1)
3013                                 selectPrevBranchInt();
3014                         else
3015                                 selectNextBranchInt();
3016         }                       
3017 }
3018
3019
3020 void MapEditor::selectLeftBranch()
3021 {
3022         if (isSelectBlocked() ) return;
3023
3024         BranchObj* bo;
3025         BranchObj* par;
3026         LinkableMapObj *sel=xelection.single();
3027         if (sel)
3028         {
3029                 if (xelection.type()== Selection::MapCenter)
3030                 {
3031                         par=xelection.getBranch();
3032                         bo=par->getLastSelectedBranch();
3033                         if (bo)
3034                         {
3035                                 // Workaround for reselecting on left and right side
3036                                 if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
3037                                         bo=par->getLastBranch();
3038                                 if (bo)
3039                                 {
3040                                         bo=par->getLastBranch();
3041                                         xelection.select(bo);
3042                                         xelection.update();
3043                                         ensureSelectionVisible();
3044                                         sendSelection();
3045                                 }
3046                         }       
3047                 } else
3048                 {
3049                         par=(BranchObj*)(sel->getParObj());
3050                         if (sel->getOrientation()==LinkableMapObj::RightOfCenter)
3051                         {
3052                                 if (xelection.type() == Selection::Branch ||
3053                                         xelection.type() == Selection::FloatImage)
3054                                 {
3055                                         xelection.select(par);
3056                                         xelection.update();
3057                                         ensureSelectionVisible();
3058                                         sendSelection();
3059                                 }
3060                         } else
3061                         {
3062                                 if (xelection.type() == Selection::Branch )
3063                                 {
3064                                         bo=xelection.getBranch()->getLastSelectedBranch();
3065                                         if (bo) 
3066                                         {
3067                                                 xelection.select(bo);
3068                                                 xelection.update();
3069                                                 ensureSelectionVisible();
3070                                         sendSelection();
3071                                         }
3072                                 }
3073                         }
3074                 }       
3075         }
3076 }
3077
3078 void MapEditor::selectRightBranch()
3079 {
3080         if (isSelectBlocked() ) return;
3081
3082         BranchObj* bo;
3083         BranchObj* par;
3084         LinkableMapObj *sel=xelection.single();
3085         if (sel)
3086         {
3087                 if (xelection.type()==Selection::MapCenter) 
3088                 {
3089                         par=xelection.getBranch();
3090                         bo=par->getLastSelectedBranch();
3091                         if (bo)
3092                         {
3093                                 // Workaround for reselecting on left and right side
3094                                 if (bo->getOrientation()==LinkableMapObj::LeftOfCenter)
3095                                         bo=par->getFirstBranch();
3096                                 if (bo)
3097                                 {
3098                                         xelection.select(bo);
3099                                         xelection.update();
3100                                         ensureSelectionVisible();
3101                                         sendSelection();
3102                                 }
3103                         }
3104                 } else
3105                 {
3106                         par=(BranchObj*)(xelection.single()->getParObj());
3107                         if (xelection.single()->getOrientation()==LinkableMapObj::LeftOfCenter)
3108                         {
3109                                 if (xelection.type() == Selection::Branch ||
3110                                         xelection.type() == Selection::FloatImage)
3111                                 {
3112                                         xelection.select(par);
3113                                         xelection.update();
3114                                         ensureSelectionVisible();
3115                                         sendSelection();
3116                                 }
3117                         } else
3118                         {
3119                                 if (xelection.type()  == Selection::Branch) 
3120                                 {
3121                                         bo=xelection.getBranch()->getLastSelectedBranch();
3122                                         if (bo) 
3123                                         {
3124                                                 xelection.select(bo);
3125                                                 xelection.update();
3126                                                 ensureSelectionVisible();
3127                                         sendSelection();
3128                                         }
3129                                 }
3130                         }
3131                 }
3132         }
3133 }
3134
3135 void MapEditor::selectFirstBranch()
3136 {
3137         BranchObj *bo1=xelection.getBranch();
3138         BranchObj *bo2;
3139         BranchObj* par;
3140         if (bo1)
3141         {
3142                 par=(BranchObj*)(bo1->getParObj());
3143                 if (!par) return;
3144                 bo2=par->getFirstBranch();
3145                 if (bo2) {
3146                         xelection.select(bo2);
3147                         xelection.update();
3148                         ensureSelectionVisible();
3149                         sendSelection();
3150                 }
3151         }               
3152 }
3153
3154 void MapEditor::selectLastBranch()
3155 {
3156         BranchObj *bo1=xelection.getBranch();
3157         BranchObj *bo2;
3158         BranchObj* par;
3159         if (bo1)
3160         {
3161                 par=(BranchObj*)(bo1->getParObj());
3162                 if (!par) return;
3163                 bo2=par->getLastBranch();
3164                 if (bo2) 
3165                 {
3166                         xelection.select(bo2);
3167                         xelection.update();
3168                         ensureSelectionVisible();
3169                         sendSelection();
3170                 }
3171         }               
3172 }
3173
3174 void MapEditor::selectMapBackgroundImage ()
3175 {
3176         QFileDialog *fd=new QFileDialog( this);
3177         fd->setMode (QFileDialog::ExistingFile);
3178         //fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
3179         QStringList filters = fd->filters();
3180         filters << tr("Images  (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)");
3181         fd->setFilters(filters);
3182         //ImagePreview *p =new ImagePreview (fd);
3183         //fd->setContentsPreviewEnabled( TRUE );
3184         //fd->setContentsPreview( p, p );
3185         //fd->setPreviewMode( Q3FileDialog::Contents );
3186         fd->setCaption(vymName+" - " +tr("Load background image"));
3187         fd->setDir (lastImageDir);
3188         fd->show();
3189
3190         if ( fd->exec() == QDialog::Accepted )
3191         {
3192                 // TODO selectMapBackgroundImg in QT4 use:      lastImageDir=fd->directory();
3193                 lastImageDir=QDir (fd->directory().path());
3194                 setMapBackgroundImage (fd->selectedFile());
3195         }
3196 }       
3197
3198 void MapEditor::setMapBackgroundImage (const QString &fn)       //FIXME missing savestate
3199 {
3200         QColor oldcol=mapScene->backgroundBrush().color();
3201         /*
3202         saveState(
3203                 selection,
3204                 QString ("setMapBackgroundImage (%1)").arg(oldcol.name()),
3205                 selection,
3206                 QString ("setMapBackgroundImage (%1)").arg(col.name()),
3207                 QString("Set background color of map to %1").arg(col.name()));
3208         */      
3209         QBrush brush;
3210         brush.setTextureImage (QPixmap (fn));
3211         mapScene->setBackgroundBrush(brush);
3212 }
3213
3214 void MapEditor::selectMapBackgroundColor()
3215 {
3216         QColor col = QColorDialog::getColor( mapScene->backgroundBrush().color(), this );
3217         if ( !col.isValid() ) return;
3218         setMapBackgroundColor( col );
3219 }
3220
3221
3222 void MapEditor::setMapBackgroundColor(QColor col)
3223 {
3224         QColor oldcol=mapScene->backgroundBrush().color();
3225         saveState(
3226                 QString ("setMapBackgroundColor (\"%1\")").arg(oldcol.name()),
3227                 QString ("setMapBackgroundColor (\"%1\")").arg(col.name()),
3228                 QString("Set background color of map to %1").arg(col.name()));
3229         mapScene->setBackgroundBrush(col);
3230 }
3231
3232 QColor MapEditor::getMapBackgroundColor()
3233 {
3234     return mapScene->backgroundBrush().color();
3235 }
3236
3237 QColor MapEditor::getCurrentHeadingColor()
3238 {
3239         BranchObj *bo=xelection.getBranch();
3240         if (bo) return bo->getColor(); 
3241         
3242         QMessageBox::warning(0,tr("Warning"),tr("Can't get color of heading,\nthere's no branch selected"));
3243         return Qt::black;
3244 }
3245
3246 void MapEditor::colorBranch (QColor c)
3247 {
3248         BranchObj *bo=xelection.getBranch();
3249         if (bo)
3250         {
3251                 saveState(
3252                         bo, 
3253                         QString ("colorBranch (\"%1\")").arg(bo->getColor().name()),
3254                         bo,
3255                         QString ("colorBranch (\"%1\")").arg(c.name()),
3256                         QString("Set color of %1 to %2").arg(getName(bo)).arg(c.name())
3257                 );      
3258                 bo->setColor(c); // color branch
3259         }
3260 }
3261
3262 void MapEditor::colorSubtree (QColor c)
3263 {
3264         BranchObj *bo=xelection.getBranch();
3265         if (bo) 
3266         {
3267                 saveStateChangingPart(
3268                         bo, 
3269                         bo,
3270                         QString ("colorSubtree (\"%1\")").arg(c.name()),
3271                         QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(c.name())
3272                 );      
3273                 bo->setColorSubtree (c); // color links, color childs
3274         }
3275 }
3276
3277
3278 void MapEditor::toggleStandardFlag(QString f)
3279 {
3280         BranchObj *bo=xelection.getBranch();
3281         if (bo) 
3282         {
3283                 QString u,r;
3284                 if (bo->isSetStandardFlag(f))
3285                 {
3286                         r="unsetFlag";
3287                         u="setFlag";
3288                 }       
3289                 else
3290                 {
3291                         u="unsetFlag";
3292                         r="setFlag";
3293                 }       
3294                 saveState(
3295                         bo,
3296                         QString("%1 (\"%2\")").arg(u).arg(f), 
3297                         bo,
3298                         QString("%1 (\"%2\")").arg(r).arg(f),
3299                         QString("Toggling standard flag \"%1\" of %2").arg(f).arg(getName(bo)));
3300                 bo->toggleStandardFlag (f,mainWindow->useFlagGroups());
3301                 xelection.update();
3302         }
3303 }
3304
3305
3306 BranchObj* MapEditor::findText (QString s, bool cs)
3307 {
3308         QTextDocument::FindFlags flags=0;
3309         if (cs) flags=QTextDocument::FindCaseSensitively;
3310
3311         if (!itFind) 
3312         {       // Nothing found or new find process
3313                 if (EOFind)
3314                         // nothing found, start again
3315                         EOFind=false;
3316                 itFind=model->first();
3317         }       
3318         bool searching=true;
3319         bool foundNote=false;
3320         while (searching && !EOFind)
3321         {
3322                 if (itFind)
3323                 {
3324                         // Searching in Note
3325                         if (itFind->getNote().contains(s,cs))
3326                         {
3327                                 if (xelection.single()!=itFind) 
3328                                 {
3329                                         xelection.select(itFind);
3330                                         ensureSelectionVisible();
3331                                 }
3332                                 if (textEditor->findText(s,flags)) 
3333                                 {
3334                                         searching=false;
3335                                         foundNote=true;
3336                                 }       
3337                         }
3338                         // Searching in Heading
3339                         if (searching && itFind->getHeading().contains (s,cs) ) 
3340                         {
3341                                 xelection.select(itFind);
3342                                 ensureSelectionVisible();
3343                                 searching=false;
3344                         }
3345                 }       
3346                 if (!foundNote)
3347                 {
3348                         itFind=model->next(itFind);
3349                         if (!itFind) EOFind=true;
3350                 }
3351         //cout <<"still searching...  "<<qPrintable( itFind->getHeading())<<endl;
3352         }       
3353         if (!searching)
3354                 return xelection.getBranch();
3355         else
3356                 return NULL;
3357 }
3358
3359 void MapEditor::findReset()
3360 {       // Necessary if text to find changes during a find process
3361         itFind=NULL;
3362         EOFind=false;
3363 }
3364 void MapEditor::setURL(const QString &url)
3365 {
3366         BranchObj *bo=xelection.getBranch();
3367         if (bo)
3368         {
3369                 QString oldurl=bo->getURL();
3370                 bo->setURL (url);
3371                 saveState (
3372                         bo,
3373                         QString ("setURL (\"%1\")").arg(oldurl),
3374                         bo,
3375                         QString ("setURL (\"%1\")").arg(url),
3376                         QString ("set URL of %1 to %2").arg(getName(bo)).arg(url)
3377                 );
3378                 updateActions();
3379                 model->reposition();
3380                 xelection.update();
3381                 ensureSelectionVisible();
3382         }
3383 }       
3384
3385 void MapEditor::editURL()
3386 {
3387         BranchObj *bo=xelection.getBranch();
3388         if (bo)
3389         {               
3390                 bool ok;
3391                 QString text = QInputDialog::getText(
3392                                 "VYM", tr("Enter URL:"), QLineEdit::Normal,
3393                                 bo->getURL(), &ok, this );
3394                 if ( ok) 
3395                         // user entered something and pressed OK
3396                         setURL (text);
3397         }
3398 }
3399
3400 void MapEditor::editLocalURL()
3401 {
3402         BranchObj *bo=xelection.getBranch();
3403         if (bo)
3404         {               
3405                 QStringList filters;
3406                 filters <<"All files (*)";
3407                 filters << tr("Text","Filedialog") + " (*.txt)";
3408                 filters << tr("Spreadsheet","Filedialog") + " (*.odp,*.sxc)";
3409                 filters << tr("Textdocument","Filedialog") +" (*.odw,*.sxw)";
3410                 filters << tr("Images","Filedialog") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)";
3411                 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Set URL to a local file"));
3412                 fd->setFilters (filters);
3413                 fd->setCaption(vymName+" - " +tr("Set URL to a local file"));
3414                 fd->setDirectory (lastFileDir);
3415                 if (! bo->getVymLink().isEmpty() )
3416                         fd->selectFile( bo->getURL() );
3417                 fd->show();
3418
3419                 if ( fd->exec() == QDialog::Accepted )
3420                 {
3421                         lastFileDir=QDir (fd->directory().path());
3422                         setURL (fd->selectedFile() );
3423                 }
3424         }
3425 }
3426
3427 QString MapEditor::getURL()
3428 {
3429         BranchObj *bo=xelection.getBranch();
3430         if (bo)
3431                 return bo->getURL();
3432         else
3433                 return "";
3434 }
3435
3436 QStringList MapEditor::getURLs()
3437 {
3438         QStringList urls;
3439         BranchObj *bo=xelection.getBranch();
3440         if (bo)
3441         {               
3442                 bo=bo->first(); 
3443                 while (bo) 
3444                 {
3445                         if (!bo->getURL().isEmpty()) urls.append( bo->getURL());
3446                         bo=bo->next();
3447                 }       
3448         }       
3449         return urls;
3450 }
3451
3452
3453 void MapEditor::editHeading2URL()
3454 {
3455         BranchObj *bo=xelection.getBranch();
3456         if (bo)
3457                 setURL (bo->getHeading());
3458 }       
3459
3460 void MapEditor::editBugzilla2URL()
3461 {
3462         BranchObj *bo=xelection.getBranch();
3463         if (bo)
3464         {               
3465                 QString url= "https://bugzilla.novell.com/show_bug.cgi?id="+bo->getHeading();
3466                 setURL (url);
3467         }
3468 }       
3469
3470 void MapEditor::editFATE2URL()
3471 {
3472         BranchObj *bo=xelection.getBranch();
3473         if (bo)
3474         {               
3475                 QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading();
3476                 saveState(
3477                         bo,
3478                         "setURL (\""+bo->getURL()+"\")",
3479                         bo,
3480                         "setURL (\""+url+"\")",
3481                         QString("Use heading of %1 as link to FATE").arg(getName(bo))
3482                 );      
3483                 bo->setURL (url);
3484                 updateActions();
3485         }
3486 }       
3487
3488 void MapEditor::editVymLink()
3489 {
3490         BranchObj *bo=xelection.getBranch();
3491         if (bo)
3492         {               
3493                 QStringList filters;
3494                 filters <<"VYM map (*.vym)";
3495                 QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Link to another map"));
3496                 fd->setFilters (filters);
3497                 fd->setCaption(vymName+" - " +tr("Link to another map"));
3498                 fd->setDirectory (lastFileDir);
3499                 if (! bo->getVymLink().isEmpty() )
3500                         fd->selectFile( bo->getVymLink() );
3501                 fd->show();
3502
3503                 QString fn;
3504                 if ( fd->exec() == QDialog::Accepted )
3505                 {
3506                         lastFileDir=QDir (fd->directory().path());
3507                         saveState(
3508                                 bo,
3509                                 "setVymLink (\""+bo->getVymLink()+"\")",
3510                                 bo,
3511                                 "setVymLink (\""+fd->selectedFile()+"\")",
3512                                 QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())
3513                         );      
3514                         setVymLinkInt (fd->selectedFile() );
3515                 }
3516         }
3517 }
3518
3519 void MapEditor::deleteVymLink()
3520 {
3521         BranchObj *bo=xelection.getBranch();
3522         if (bo)
3523         {               
3524                 saveState(
3525                         bo,
3526                         "setVymLink (\""+bo->getVymLink()+"\")",
3527                         bo,
3528                         "setVymLink (\"\")",
3529                         QString("Unset vymlink of %1").arg(getName(bo))
3530                 );      
3531                 bo->setVymLink ("" );
3532                 updateActions();
3533                 model->reposition();
3534                 scene()->update();
3535         }
3536 }
3537
3538 void MapEditor::setHideExport(bool b)
3539 {
3540         BranchObj *bo=xelection.getBranch();
3541         if (bo)
3542         {
3543                 bo->setHideInExport (b);
3544                 QString u= b ? "false" : "true";
3545                 QString r=!b ? "false" : "true";
3546                 
3547                 saveState(
3548                         bo,
3549                         QString ("setHideExport (%1)").arg(u),
3550                         bo,
3551                         QString ("setHideExport (%1)").arg(r),
3552                         QString ("Set HideExport flag of %1 to %2").arg(getName(bo)).arg (r)
3553                 );      
3554                 updateActions();
3555                 model->reposition();
3556                 xelection.update();
3557                 scene()->update();
3558         }
3559 }
3560
3561 void MapEditor::toggleHideExport()
3562 {
3563         BranchObj *bo=xelection.getBranch();
3564         if (bo)
3565                 setHideExport ( !bo->hideInExport() );
3566 }
3567
3568 QString MapEditor::getVymLink()
3569 {
3570         BranchObj *bo=xelection.getBranch();
3571         if (bo)
3572                 return bo->getVymLink();
3573         else    
3574                 return "";
3575         
3576 }
3577
3578 QStringList MapEditor::getVymLinks()
3579 {
3580         QStringList links;
3581         BranchObj *bo=xelection.getBranch();
3582         if (bo)
3583         {               
3584                 bo=bo->first(); 
3585                 while (bo) 
3586                 {
3587                         if (!bo->getVymLink().isEmpty()) links.append( bo->getVymLink());
3588                         bo=bo->next();
3589                 }       
3590         }       
3591         return links;
3592 }
3593
3594
3595 void MapEditor::deleteKeepChilds()
3596 {
3597         BranchObj *bo=xelection.getBranch();
3598         BranchObj *par;
3599         if (bo)
3600         {
3601                 par=(BranchObj*)(bo->getParObj());
3602
3603                 // Don't use this on mapcenter
3604                 if (!par) return;
3605
3606                 // Check if we have childs at all to keep
3607                 if (bo->countBranches()==0) 
3608                 {
3609                         deleteSelection();
3610                         return;
3611                 }
3612
3613                 QPointF p=bo->getRelPos();
3614                 saveStateChangingPart(
3615                         bo->getParObj(),
3616                         bo,
3617                         "deleteKeepChilds ()",
3618                         QString("Remove %1 and keep its childs").arg(getName(bo))
3619                 );
3620
3621                 QString sel=model->getSelectString(bo);
3622                 unselect();
3623                 par->removeBranchHere(bo);
3624                 model->reposition();
3625                 select (sel);
3626                 xelection.getBranch()->move2RelPos (p);
3627                 model->reposition();
3628         }       
3629 }
3630
3631 void MapEditor::deleteChilds()
3632 {
3633         BranchObj *bo=xelection.getBranch();
3634         if (bo)
3635         {               
3636                 saveStateChangingPart(
3637                         bo, 
3638                         bo,
3639                         "deleteChilds ()",
3640                         QString( "Remove childs of branch %1").arg(getName(bo))
3641                 );
3642                 bo->removeChilds();
3643                 model->reposition();
3644         }       
3645 }
3646
3647 void MapEditor::editMapInfo()
3648 {
3649         ExtraInfoDialog dia;
3650         dia.setMapName (getFileName() );
3651         dia.setAuthor (model->getAuthor() );
3652         dia.setComment(model->getComment() );
3653
3654         // Calc some stats
3655         QString stats;
3656     stats+=tr("%1 items on map\n","Info about map").arg (mapScene->items().size(),6);
3657
3658         uint b=0;
3659         uint f=0;
3660         uint n=0;
3661         uint xl=0;
3662         BranchObj *bo;
3663         bo=model->first();
3664         while (bo) 
3665         {
3666                 if (!bo->getNote().isEmpty() ) n++;
3667                 f+= bo->countFloatImages();
3668                 b++;
3669                 xl+=bo->countXLinks();
3670                 bo=model->next(bo);
3671         }
3672     stats+=QString ("%1 branches\n").arg (b-1,6);
3673     stats+=QString ("%1 xLinks \n").arg (xl,6);
3674     stats+=QString ("%1 notes\n").arg (n,6);
3675     stats+=QString ("%1 images\n").arg (f,6);
3676         dia.setStats (stats);
3677
3678         // Finally show dialog
3679         if (dia.exec() == QDialog::Accepted)
3680         {
3681                 setMapAuthor (dia.getAuthor() );
3682                 setMapComment (dia.getComment() );
3683         }
3684 }
3685
3686 void MapEditor::ensureSelectionVisible()
3687 {
3688         LinkableMapObj *lmo=xelection.single();
3689         if (lmo) ensureVisible (lmo->getBBox() );
3690         
3691 }
3692
3693 void MapEditor::updateSelection()
3694 {
3695         // Tell selection to update geometries
3696         xelection.update();
3697 }
3698
3699 void MapEditor::updateActions()
3700 {
3701         // Tell mainwindow to update states of actions
3702         mainWindow->updateActions();
3703         // TODO maybe don't update if blockReposition is set
3704 }
3705
3706 void MapEditor::updateNoteFlag()
3707 {
3708         setChanged();
3709         BranchObj *bo=xelection.getBranch();
3710         if (bo) 
3711         {
3712                 bo->updateNoteFlag();
3713                 mainWindow->updateActions();
3714         }       
3715 }
3716
3717 void MapEditor::setMapAuthor (const QString &s)
3718 {
3719         saveState (
3720                 QString ("setMapAuthor (\"%1\")").arg(model->getAuthor()),
3721                 QString ("setMapAuthor (\"%1\")").arg(s),
3722                 QString ("Set author of map to \"%1\"").arg(s)
3723         );
3724         model->setAuthor (s);
3725 }
3726
3727 void MapEditor::setMapComment (const QString &s)
3728 {
3729         saveState (
3730                 QString ("setMapComment (\"%1\")").arg(model->getComment()),
3731                 QString ("setMapComment (\"%1\")").arg(s),
3732                 QString ("Set comment of map")
3733         );
3734         model->setComment (s);
3735 }
3736
3737 void MapEditor::setMapLinkStyle (const QString & s)
3738 {
3739         QString snow;
3740         if (linkstyle==LinkableMapObj::Line)
3741                 snow="StyleLine";
3742         else if (linkstyle==LinkableMapObj::Parabel)
3743                 snow="StyleParabel";
3744         else if (linkstyle==LinkableMapObj::PolyLine)
3745                 snow="StylePolyLine";
3746         else if (linkstyle==LinkableMapObj::PolyParabel)
3747                 snow="StyleParabel";
3748
3749         saveState (
3750                 QString("setMapLinkStyle (\"%1\")").arg(s),
3751                 QString("setMapLinkStyle (\"%1\")").arg(snow),
3752                 QString("Set map link style (\"%1\")").arg(s)
3753         );      
3754
3755         if (s=="StyleLine")
3756                 linkstyle=LinkableMapObj::Line;
3757         else if (s=="StyleParabel")
3758                 linkstyle=LinkableMapObj::Parabel;
3759         else if (s=="StylePolyLine")
3760                 linkstyle=LinkableMapObj::PolyLine;
3761         else    
3762                 linkstyle=LinkableMapObj::PolyParabel;
3763
3764         BranchObj *bo;
3765         bo=model->first();
3766         bo=model->next(bo);
3767         while (bo) 
3768         {
3769                 bo->setLinkStyle(bo->getDefLinkStyle());
3770                 bo=model->next(bo);
3771         }
3772         model->reposition();
3773 }
3774
3775 LinkableMapObj::Style MapEditor::getMapLinkStyle ()
3776 {
3777         return linkstyle;
3778 }       
3779
3780 void MapEditor::setMapDefLinkColor(QColor c)
3781 {
3782         defLinkColor=c;
3783         BranchObj *bo;
3784         bo=model->first();
3785         while (bo) 
3786         {
3787                 bo->setLinkColor();
3788                 bo=model->next(bo);
3789         }
3790         updateActions();
3791 }
3792
3793 void MapEditor::setMapLinkColorHintInt()
3794 {
3795         // called from setMapLinkColorHint(lch) or at end of parse
3796         BranchObj *bo;
3797         bo=model->first();
3798         while (bo) 
3799         {
3800                 bo->setLinkColor();
3801                 bo=model->next(bo);
3802         }
3803 }
3804
3805 void MapEditor::setMapLinkColorHint(LinkableMapObj::ColorHint lch)
3806 {
3807         linkcolorhint=lch;
3808         setMapLinkColorHintInt();
3809 }
3810
3811 void MapEditor::toggleMapLinkColorHint()
3812 {
3813         if (linkcolorhint==LinkableMapObj::HeadingColor)
3814                 linkcolorhint=LinkableMapObj::DefaultColor;
3815         else    
3816                 linkcolorhint=LinkableMapObj::HeadingColor;
3817         BranchObj *bo;
3818         bo=model->first();
3819         while (bo) 
3820         {
3821                 bo->setLinkColor();
3822                 bo=model->next(bo);
3823         }
3824 }
3825
3826 LinkableMapObj::ColorHint MapEditor::getMapLinkColorHint()
3827 {
3828         return linkcolorhint;
3829 }
3830
3831 QColor MapEditor::getMapDefLinkColor()
3832 {
3833         return defLinkColor;
3834 }
3835
3836 void MapEditor::setMapDefXLinkColor(QColor col)
3837 {
3838         defXLinkColor=col;
3839 }
3840
3841 QColor MapEditor::getMapDefXLinkColor()
3842 {
3843         return defXLinkColor;
3844 }
3845
3846 void MapEditor::setMapDefXLinkWidth (int w)
3847 {
3848         defXLinkWidth=w;
3849 }
3850
3851 int MapEditor::getMapDefXLinkWidth()
3852 {
3853         return defXLinkWidth;
3854 }
3855
3856 void MapEditor::selectMapLinkColor()
3857 {
3858         QColor col = QColorDialog::getColor( defLinkColor, this );
3859         if ( !col.isValid() ) return;
3860         saveState (
3861                 QString("setMapDefLinkColor (\"%1\")").arg(getMapDefLinkColor().name()),
3862                 QString("setMapDefLinkColor (\"%1\")").arg(col.name()),
3863                 QString("Set map link color to %1").arg(col.name())
3864         );
3865         setMapDefLinkColor( col );
3866 }
3867
3868 void MapEditor::selectMapSelectionColor()
3869 {
3870         QColor col = QColorDialog::getColor( defLinkColor, this );
3871         setSelectionColor (col);
3872 }
3873
3874 void MapEditor::setSelectionColorInt (QColor col)
3875 {
3876         if ( !col.isValid() ) return;
3877         xelection.setColor (col);
3878 }
3879
3880 void MapEditor::setSelectionColor(QColor col)
3881 {
3882         if ( !col.isValid() ) return;
3883         saveState (
3884                 QString("setSelectionColor (%1)").arg(xelection.getColor().name()),
3885                 QString("setSelectionColor (%1)").arg(col.name()),
3886                 QString("Set color of selection box to %1").arg(col.name())
3887         );
3888         setSelectionColorInt (col);
3889 }
3890
3891 QColor MapEditor::getSelectionColor()
3892 {
3893         return xelection.getColor();
3894 }
3895
3896 bool MapEditor::scrollBranch(BranchObj *bo)
3897 {
3898         if (bo)
3899         {
3900                 if (bo->isScrolled()) return false;
3901                 if (bo->countBranches()==0) return false;
3902                 if (bo->getDepth()==0) return false;
3903                 QString u,r;
3904                 r="scroll";
3905                 u="unscroll";
3906                 saveState(
3907                         bo,
3908                         QString ("%1 ()").arg(u),
3909                         bo,
3910                         QString ("%1 ()").arg(r),
3911                         QString ("%1 %2").arg(r).arg(getName(bo))
3912                 );
3913                 bo->toggleScroll();
3914                 xelection.update();
3915                 scene()->update();
3916                 return true;
3917         }       
3918         return false;
3919 }
3920
3921 bool MapEditor::unscrollBranch(BranchObj *bo)
3922 {
3923         if (bo)
3924         {
3925                 if (!bo->isScrolled()) return false;
3926                 if (bo->countBranches()==0) return false;
3927                 if (bo->getDepth()==0) return false;
3928                 QString u,r;
3929                 u="scroll";
3930                 r="unscroll";
3931                 saveState(
3932                         bo,
3933                         QString ("%1 ()").arg(u),
3934                         bo,
3935                         QString ("%1 ()").arg(r),
3936                         QString ("%1 %2").arg(r).arg(getName(bo))
3937                 );
3938                 bo->toggleScroll();
3939                 xelection.update();
3940                 scene()->update();
3941                 return true;
3942         }       
3943         return false;
3944 }
3945
3946 void MapEditor::toggleScroll()
3947 {
3948         BranchObj *bo=xelection.getBranch();
3949         if (xelection.type()==Selection::Branch )
3950         {
3951                 if (bo->isScrolled())
3952                         unscrollBranch (bo);
3953                 else
3954                         scrollBranch (bo);
3955         }
3956 }
3957
3958 void MapEditor::unscrollChilds() 
3959 {
3960         BranchObj *bo=xelection.getBranch();
3961         if (bo)
3962         {
3963                 bo->first();
3964                 while (bo) 
3965                 {
3966                         if (bo->isScrolled()) unscrollBranch (bo);
3967                         bo=bo->next();
3968                 }
3969         }       
3970 }
3971
3972 FloatImageObj* MapEditor::loadFloatImageInt (QString fn)
3973 {
3974         BranchObj *bo=xelection.getBranch();
3975         if (bo)
3976         {
3977                 FloatImageObj *fio;
3978                 bo->addFloatImage();
3979                 fio=bo->getLastFloatImage();
3980                 fio->load(fn);
3981                 model->reposition();
3982                 scene()->update();
3983                 return fio;
3984         }
3985         return NULL;
3986 }       
3987
3988 void MapEditor::loadFloatImage ()
3989 {
3990         BranchObj *bo=xelection.getBranch();
3991         if (bo)
3992         {
3993
3994                 QFileDialog *fd=new QFileDialog( this);
3995                 fd->setMode (QFileDialog::ExistingFiles);
3996                 //fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
3997                 QStringList filters = fd->filters();
3998                 filters << tr("Images (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)");
3999                 fd->setFilters(filters);
4000                 //ImagePreview *p =new ImagePreview (fd);
4001                 //fd->setContentsPreviewEnabled( TRUE );
4002                 //fd->setContentsPreview( p, p );
4003                 //fd->setPreviewMode( Q3FileDialog::Contents );
4004                 fd->setCaption(vymName+" - " +tr("Load image"));
4005                 fd->setDir (lastImageDir);
4006                 fd->show();
4007
4008                 if ( fd->exec() == QDialog::Accepted )
4009                 {
4010                         // TODO loadFIO in QT4 use:     lastImageDir=fd->directory();
4011                         lastImageDir=QDir (fd->directory().path());
4012                         QString s;
4013                         FloatImageObj *fio;
4014                         for (int j=0; j<fd->selectedFiles().count(); j++)
4015                         {
4016                                 s=fd->selectedFiles().at(j);
4017                                 fio=loadFloatImageInt (s);
4018                                 if (fio)
4019                                         saveState(
4020                                                 (LinkableMapObj*)fio,
4021                                                 "delete ()",
4022                                                 bo, 
4023                                                 QString ("loadImage (%1)").arg(s ),
4024                                                 QString("Add image %1 to %2").arg(s).arg(getName(bo))
4025                                         );
4026                                 else
4027                                         // TODO loadFIO error handling
4028                                         qWarning ("Failed to load "+s);
4029                         }
4030                 }
4031                 //delete (p);
4032                 delete (fd);
4033         }
4034 }
4035
4036 void MapEditor::saveFloatImageInt  (FloatImageObj *fio, const QString &type, const QString &fn)
4037 {
4038         fio->save (fn,type);
4039 }
4040
4041 void MapEditor::saveFloatImage ()
4042 {
4043         FloatImageObj *fio=xelection.getFloatImage();
4044         if (fio)
4045         {
4046                 QFileDialog *fd=new QFileDialog( this);
4047                 fd->setFilters (imageIO.getFilters());
4048                 fd->setCaption(vymName+" - " +tr("Save image"));
4049                 fd->setFileMode( QFileDialog::AnyFile );
4050                 fd->setDirectory (lastImageDir);
4051 //              fd->setSelection (fio->getOriginalFilename());
4052                 fd->show();
4053
4054                 QString fn;
4055                 if ( fd->exec() == QDialog::Accepted && fd->selectedFiles().count()==1)
4056                 {
4057                         fn=fd->selectedFiles().at(0);
4058                         if (QFile (fn).exists() )
4059                         {
4060                                 QMessageBox mb( vymName,
4061                                         tr("The file %1 exists already.\n"
4062                                         "Do you want to overwrite it?").arg(fn),
4063                                 QMessageBox::Warning,
4064                                 QMessageBox::Yes | QMessageBox::Default,
4065                                 QMessageBox::Cancel | QMessageBox::Escape,
4066                                 QMessageBox::NoButton );
4067
4068                                 mb.setButtonText( QMessageBox::Yes, tr("Overwrite") );
4069                                 mb.setButtonText( QMessageBox::No, tr("Cancel"));
4070                                 switch( mb.exec() ) 
4071                                 {
4072                                         case QMessageBox::Yes:
4073                                                 // save 
4074                                                 break;
4075                                         case QMessageBox::Cancel:
4076                                                 // do nothing
4077                                                 delete (fd);
4078                                                 return;
4079                                                 break;
4080                                 }
4081                         }
4082                         saveFloatImageInt (fio,fd->selectedFilter(),fn );
4083                 }
4084                 delete (fd);
4085         }
4086 }
4087
4088 void MapEditor::setFrameType(const FrameObj::FrameType &t)
4089 {
4090         BranchObj *bo=xelection.getBranch();
4091         if (bo)
4092         {
4093                 QString s=bo->getFrameTypeName();
4094                 bo->setFrameType (t);
4095                 saveState (bo, QString("setFrameType (\"%1\")").arg(s),
4096                         bo, QString ("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),QString ("set type of frame to %1").arg(s));
4097                 model->reposition();
4098                 bo->updateLink();
4099         }
4100 }
4101
4102 void MapEditor::setFrameType(const QString &s)  
4103 {
4104         BranchObj *bo=xelection.getBranch();
4105         if (bo)
4106         {
4107                 saveState (bo, QString("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),
4108                         bo, QString ("setFrameType (\"%1\")").arg(s),QString ("set type of frame to %1").arg(s));
4109                 bo->setFrameType (s);
4110                 model->reposition();
4111                 bo->updateLink();
4112         }
4113 }
4114
4115 void MapEditor::setFramePenColor(const QColor &c)       
4116 {
4117         BranchObj *bo=xelection.getBranch();
4118         if (bo)
4119         {
4120                 saveState (bo, QString("setFramePenColor (\"%1\")").arg(bo->getFramePenColor().name() ),
4121                         bo, QString ("setFramePenColor (\"%1\")").arg(c.name() ),QString ("set pen color of frame to %1").arg(c.name() ));
4122                 bo->setFramePenColor (c);
4123         }       
4124 }
4125
4126 void MapEditor::setFrameBrushColor(const QColor &c)     
4127 {
4128         BranchObj *bo=xelection.getBranch();
4129         if (bo)
4130         {
4131                 saveState (bo, QString("setFrameBrushColor (\"%1\")").arg(bo->getFrameBrushColor().name() ),
4132                         bo, QString ("setFrameBrushColor (\"%1\")").arg(c.name() ),QString ("set brush color of frame to %1").arg(c.name() ));
4133                 bo->setFrameBrushColor (c);
4134         }       
4135 }
4136
4137 void MapEditor::setFramePadding (const int &i)
4138 {
4139         BranchObj *bo=xelection.getBranch();
4140         if (bo)
4141         {
4142                 saveState (bo, QString("setFramePadding (\"%1\")").arg(bo->getFramePadding() ),
4143                         bo, QString ("setFramePadding (\"%1\")").arg(i),QString ("set brush color of frame to %1").arg(i));
4144                 bo->setFramePadding (i);
4145                 model->reposition();
4146                 bo->updateLink();
4147         }       
4148 }
4149
4150 void MapEditor::setFrameBorderWidth(const int &i)
4151 {
4152         BranchObj *bo=xelection.getBranch();
4153         if (bo)
4154         {
4155                 saveState (bo, QString("setFrameBorderWidth (\"%1\")").arg(bo->getFrameBorderWidth() ),
4156                         bo, QString ("setFrameBorderWidth (\"%1\")").arg(i),QString ("set border width of frame to %1").arg(i));
4157                 bo->setFrameBorderWidth (i);
4158                 model->reposition();
4159                 bo->updateLink();
4160         }       
4161 }
4162
4163 void MapEditor::setIncludeImagesVer(bool b)     
4164 {
4165         BranchObj *bo=xelection.getBranch();
4166         if (bo)
4167         {
4168                 QString u= b ? "false" : "true";
4169                 QString r=!b ? "false" : "true";
4170                 
4171                 saveState(
4172                         bo,
4173                         QString("setIncludeImagesVertically (%1)").arg(u),
4174                         bo, 
4175                         QString("setIncludeImagesVertically (%1)").arg(r),
4176                         QString("Include images vertically in %1").arg(getName(bo))
4177                 );      
4178                 bo->setIncludeImagesVer(b);
4179                 model->reposition();
4180         }       
4181 }
4182
4183 void MapEditor::setIncludeImagesHor(bool b)     
4184 {
4185         BranchObj *bo=xelection.getBranch();
4186         if (bo)
4187         {
4188                 QString u= b ? "false" : "true";
4189                 QString r=!b ? "false" : "true";
4190                 
4191                 saveState(
4192                         bo,
4193                         QString("setIncludeImagesHorizontally (%1)").arg(u),
4194                         bo, 
4195                         QString("setIncludeImagesHorizontally (%1)").arg(r),
4196                         QString("Include images horizontally in %1").arg(getName(bo))
4197                 );      
4198                 bo->setIncludeImagesHor(b);
4199                 model->reposition();
4200         }       
4201 }
4202
4203 void MapEditor::setHideLinkUnselected (bool b)
4204 {
4205         LinkableMapObj *sel=xelection.single();
4206         if (sel &&
4207                 (xelection.type() == Selection::Branch || 
4208                 xelection.type() == Selection::MapCenter  ||
4209                 xelection.type() == Selection::FloatImage ))
4210         {
4211                 QString u= b ? "false" : "true";
4212                 QString r=!b ? "false" : "true";
4213                 
4214                 saveState(
4215                         sel,
4216                         QString("setHideLinkUnselected (%1)").arg(u),
4217                         sel, 
4218                         QString("setHideLinkUnselected (%1)").arg(r),
4219                         QString("Hide link of %1 if unselected").arg(getName(sel))
4220                 );      
4221                 sel->setHideLinkUnselected(b);
4222         }
4223 }
4224
4225 void MapEditor::importDirInt(BranchObj *dst, QDir d)
4226 {
4227         BranchObj *bo=xelection.getBranch();
4228         if (bo)
4229         {
4230                 // Traverse directories
4231                 d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
4232                 QFileInfoList list = d.entryInfoList();
4233                 QFileInfo fi;
4234
4235                 for (int i = 0; i < list.size(); ++i) 
4236                 {
4237                         fi=list.at(i);
4238                         if (fi.fileName() != "." && fi.fileName() != ".." )
4239                         {
4240                                 dst->addBranch();
4241                                 bo=dst->getLastBranch();
4242                                 bo->setHeading (fi.fileName() );
4243                                 bo->setColor (QColor("blue"));
4244                                 bo->toggleScroll();
4245                                 if ( !d.cd(fi.fileName()) ) 
4246                                         QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory %1").arg(fi.fileName()));
4247                                 else 
4248                                 {
4249                                         // Recursively add subdirs
4250                                         importDirInt (bo,d);
4251                                         d.cdUp();
4252                                 }
4253                         }       
4254                 }               
4255                 // Traverse files
4256                 d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
4257                 list = d.entryInfoList();
4258
4259                 for (int i = 0; i < list.size(); ++i) 
4260                 {
4261                         fi=list.at(i);
4262                         dst->addBranch();
4263                         bo=dst->getLastBranch();
4264                         bo->setHeading (fi.fileName() );
4265                         bo->setColor (QColor("black"));
4266                         if (fi.fileName().right(4) == ".vym" )
4267                                 bo->setVymLink (fi.filePath());
4268                 }       
4269         }               
4270 }
4271
4272 void MapEditor::importDirInt (const QString &s)
4273 {
4274         BranchObj *bo=xelection.getBranch();
4275         if (bo)
4276         {
4277                 saveStateChangingPart (bo,bo,QString ("importDir (\"%1\")").arg(s),QString("Import directory structure from %1").arg(s));
4278
4279                 QDir d(s);
4280                 importDirInt (bo,d);
4281         }
4282 }       
4283
4284 void MapEditor::importDir()
4285 {
4286         BranchObj *bo=xelection.getBranch();
4287         if (bo)
4288         {
4289                 QStringList filters;
4290                 filters <<"VYM map (*.vym)";
4291                 QFileDialog *fd=new QFileDialog( this,vymName+ " - " +tr("Choose directory structure to import"));
4292                 fd->setMode (QFileDialog::DirectoryOnly);
4293                 fd->setFilters (filters);
4294                 fd->setCaption(vymName+" - " +tr("Choose directory structure to import"));
4295                 fd->show();
4296
4297                 QString fn;
4298                 if ( fd->exec() == QDialog::Accepted )
4299                 {
4300                         importDirInt (fd->selectedFile() );
4301                         model->reposition();
4302                         scene()->update();
4303                 }
4304         }       
4305 }
4306
4307 void MapEditor::followXLink(int i)
4308 {
4309         BranchObj *bo=xelection.getBranch();
4310         if (bo)
4311         {
4312                 bo=bo->XLinkTargetAt(i);
4313                 if (bo) 
4314                 {
4315                         xelection.select(bo);
4316                         ensureSelectionVisible();
4317                 }
4318         }
4319 }
4320
4321 void MapEditor::editXLink(int i)        // FIXME missing saveState
4322 {
4323         BranchObj *bo=xelection.getBranch();
4324         if (bo)
4325         {
4326                 XLinkObj *xlo=bo->XLinkAt(i);
4327                 if (xlo) 
4328                 {
4329                         EditXLinkDialog dia;
4330                         dia.setXLink (xlo);
4331                         dia.setSelection(bo);
4332                         if (dia.exec() == QDialog::Accepted)
4333                         {
4334                                 if (dia.useSettingsGlobal() )
4335                                 {
4336                                         setMapDefXLinkColor (xlo->getColor() );
4337                                         setMapDefXLinkWidth (xlo->getWidth() );
4338                                 }
4339                                 if (dia.deleteXLink())
4340                                         bo->deleteXLinkAt(i);
4341                         }
4342                 }       
4343         }
4344 }
4345
4346 AttributeTable* MapEditor::attributeTable()
4347 {
4348         return attrTable;
4349 }
4350
4351 void MapEditor::testFunction1()
4352 {
4353         BranchObj *bo=xelection.getBranch();
4354         if (bo) model->moveAway (bo);
4355         
4356 /* TODO Hide hidden stuff temporary, maybe add this as regular function somewhere
4357         if (hidemode==HideNone)
4358         {
4359                 setHideTmpMode (HideExport);
4360                 mapCenter->calcBBoxSizeWithChilds();
4361                 QRectF totalBBox=mapCenter->getTotalBBox();
4362                 QRectF mapRect=totalBBox;
4363                 QCanvasRectangle *frame=NULL;
4364
4365                 cout << "  map has =("<<totalBBox.x()<<","<<totalBBox.y()<<","<<totalBBox.width()<<","<<totalBBox.height()<<")\n";
4366         
4367                 mapRect.setRect (totalBBox.x(), totalBBox.y(), 
4368                         totalBBox.width(), totalBBox.height());
4369                 frame=new QCanvasRectangle (mapRect,mapScene);
4370                 frame->setBrush (QColor(white));
4371                 frame->setPen (QColor(black));
4372                 frame->setZValue(0);
4373                 frame->show();    
4374         }       
4375         else    
4376         {
4377                 setHideTmpMode (HideNone);
4378         }       
4379         cout <<"  hidemode="<<hidemode<<endl;
4380         */
4381 }       
4382         
4383 void MapEditor::testFunction2()
4384 {
4385
4386 /*
4387         // Toggle hidemode
4388         if (hidemode==HideExport)
4389                 setHideTmpMode (HideNone);
4390         else    
4391                 setHideTmpMode (HideExport);
4392 */              
4393 }
4394
4395 void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
4396 {
4397         // Lineedits are already closed by preceding
4398         // mouseEvent, we don't need to close here.
4399
4400     QPointF p = mapToScene(e->pos());
4401     LinkableMapObj* lmo=model->findMapObj(p, NULL);
4402         
4403     if (lmo) 
4404         {       // MapObj was found
4405                 if (xelection.single() != lmo)
4406                 {
4407                         // select the MapObj
4408                         xelection.select(lmo);
4409                 }
4410                 // Context Menu 
4411                 if (xelection.getBranch() ) 
4412                 {
4413                         // Context Menu on branch or mapcenter
4414                         updateActions();
4415                         branchContextMenu->popup(e->globalPos() );
4416                 } else
4417                 {
4418                         if (xelection.getFloatImage() )
4419                         {
4420                                 // Context Menu on floatimage
4421                                 updateActions();
4422                                 floatimageContextMenu->popup(e->globalPos() );
4423                         }       
4424                 }       
4425         } else 
4426         { // No MapObj found, we are on the Canvas itself
4427                 // Context Menu on scene
4428                 updateActions();
4429                 contextMenuPos=p;
4430                 canvasContextMenu->popup(e->globalPos() );
4431     } 
4432         e->accept();
4433 }
4434
4435 void MapEditor::keyPressEvent(QKeyEvent* e)
4436 {
4437         if (e->modifiers() & Qt::ControlModifier)
4438         {
4439                 switch (mainWindow->getModMode())
4440                 {
4441                         case Main::ModModeColor: 
4442                                 setCursor (PickColorCursor);
4443                                 break;
4444                         case Main::ModModeCopy: 
4445                                 setCursor (CopyCursor);
4446                                 break;
4447                         case Main::ModModeXLink: 
4448                                 setCursor (XLinkCursor);
4449                                 break;
4450                         default :
4451                                 setCursor (Qt::ArrowCursor);
4452                                 break;
4453                 } 
4454         }       
4455 }
4456
4457 void MapEditor::keyReleaseEvent(QKeyEvent* e)
4458 {
4459         if (!(e->modifiers() & Qt::ControlModifier))
4460                 setCursor (Qt::ArrowCursor);
4461 }
4462
4463 void MapEditor::mousePressEvent(QMouseEvent* e)
4464 {
4465         // Ignore right clicks, these will go to context menus
4466         if (e->button() == Qt::RightButton )
4467         {
4468                 e->ignore();
4469                 return;
4470         }
4471
4472         //Ignore clicks while editing heading
4473         if (isSelectBlocked() ) 
4474         {
4475                 e->ignore();
4476                 return;
4477         }
4478
4479     QPointF p = mapToScene(e->pos());
4480     LinkableMapObj* lmo=model->findMapObj(p, NULL);
4481         
4482         e->accept();
4483
4484         //Take care of  system flags _or_ modifier modes
4485         //
4486         if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
4487                 typeid(*lmo)==typeid(MapCenterObj) ))
4488         {
4489                 QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
4490                 if (!foname.isEmpty())
4491                 {
4492                         // systemFlag clicked
4493                         selectInt (lmo);
4494                         if (foname=="url") 
4495                         {
4496                                 if (e->state() & Qt::ControlModifier)
4497                                         mainWindow->editOpenURLTab();
4498                                 else    
4499                                         mainWindow->editOpenURL();
4500                         }       
4501                         else if (foname=="vymLink")
4502                         {
4503                                 mainWindow->editOpenVymLink();
4504                                 // tabWidget may change, better return now
4505                                 // before segfaulting...
4506                         } else if (foname=="note")
4507                                 mainWindow->windowToggleNoteEditor();
4508                         else if (foname=="hideInExport")                
4509                                 toggleHideExport();
4510                         xelection.update();     
4511                         return; 
4512                 } 
4513         } 
4514
4515         // No system flag clicked, take care of modmodes (CTRL-Click)
4516         if (e->state() & Qt::ControlModifier)
4517         {
4518                 if (mainWindow->getModMode()==Main::ModModeColor)
4519                 {
4520                                 pickingColor=true;
4521                                 setCursor (PickColorCursor);
4522                                 return;
4523                 } 
4524                 if (mainWindow->getModMode()==Main::ModModeXLink)
4525                 {       
4526                         BranchObj *bo_begin=NULL;
4527                         if (lmo)
4528                                 bo_begin=(BranchObj*)(lmo);
4529                         else    
4530                                 if (xelection.getBranch() ) 
4531                                         bo_begin=xelection.getBranch();
4532                         if (bo_begin)   
4533                         {
4534                                 drawingLink=true;
4535                                 linkingObj_src=bo_begin;
4536                                 tmpXLink=new XLinkObj (mapScene);
4537                                 tmpXLink->setBegin (bo_begin);
4538                                 tmpXLink->setEnd   (p);
4539                                 tmpXLink->setColor(defXLinkColor);
4540                                 tmpXLink->setWidth(defXLinkWidth);
4541                                 tmpXLink->updateXLink();
4542                                 tmpXLink->setVisibility (true);
4543                                 return;
4544                         } 
4545                 }
4546         }       // End of modmodes
4547
4548     if (lmo) 
4549         {       
4550                 // Select the clicked object
4551                 selectInt (lmo);
4552
4553                 // Left Button      Move Branches
4554                 if (e->button() == Qt::LeftButton )
4555                 {
4556                         //movingObj_start.setX( p.x() - selection->x() );// TODO replaced selection->lmo here   
4557                         //movingObj_start.setY( p.y() - selection->y() );       
4558                         movingObj_start.setX( p.x() - lmo->x() );       
4559                         movingObj_start.setY( p.y() - lmo->y() );       
4560                         movingObj_orgPos.setX (lmo->x() );
4561                         movingObj_orgPos.setY (lmo->y() );
4562                         movingObj_orgRelPos=lmo->getRelPos();
4563
4564                         // If modMode==copy, then we want to "move" the _new_ object around
4565                         // then we need the offset from p to the _old_ selection, because of tmp
4566                         if (mainWindow->getModMode()==Main::ModModeCopy &&
4567                                 e->state() & Qt::ControlModifier)
4568                         {
4569                                 BranchObj *bo=xelection.getBranch();
4570                                 if (bo)
4571                                 {
4572                                         copyingObj=true;
4573                                         bo->addBranch ((BranchObj*)xelection.single());
4574                                         unselect();
4575                                         xelection.select(bo->getLastBranch());
4576                                         model->reposition();
4577                                 }
4578                         } 
4579
4580                         movingObj=xelection.single();   
4581                 } else
4582                         // Middle Button    Toggle Scroll
4583                         // (On Mac OS X this won't work, but we still have 
4584                         // a button in the toolbar)
4585                         if (e->button() == Qt::MidButton )
4586                                 toggleScroll();
4587                 updateActions();
4588                 xelection.update();
4589         } else 
4590         { // No MapObj found, we are on the scene itself
4591                 // Left Button      move Pos of sceneView
4592                 if (e->button() == Qt::LeftButton )
4593                 {
4594                         movingObj=NULL; // move Content not Obj
4595                         movingObj_start=e->globalPos();
4596                         movingCont_start=QPointF (
4597                                 horizontalScrollBar()->value(),
4598                                 verticalScrollBar()->value());
4599                         movingVec=QPointF(0,0);
4600                         setCursor(HandOpenCursor);
4601                 } 
4602     } 
4603 }
4604
4605 void MapEditor::mouseMoveEvent(QMouseEvent* e)
4606 {
4607     QPointF p = mapToScene(e->pos());
4608         LinkableMapObj *lmosel=xelection.single();
4609
4610     // Move the selected MapObj
4611     if ( lmosel && movingObj) 
4612     {   
4613                 // reset cursor if we are moving and don't copy
4614                 if (mainWindow->getModMode()!=Main::ModModeCopy)
4615                         setCursor (Qt::ArrowCursor);
4616
4617                 // To avoid jumping of the sceneView, only 
4618                 // ensureSelectionVisible, if not tmp linked
4619                 if (!lmosel->hasParObjTmp())
4620                         ensureSelectionVisible ();
4621                 
4622                 // Now move the selection, but add relative position 
4623                 // (movingObj_start) where selection was chosen with 
4624                 // mousepointer. (This avoids flickering resp. jumping 
4625                 // of selection back to absPos)
4626                 
4627                 // Check if we could link 
4628                 LinkableMapObj* lmo=model->findMapObj(p, lmosel);
4629                 
4630
4631                 FloatObj *fio=xelection.getFloatImage();
4632                 if (fio)
4633                 {
4634                         fio->move   (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );           
4635                         fio->setRelPos();
4636                         fio->updateLink(); //no need for reposition, if we update link here
4637                         xelection.update();
4638
4639                         // Relink float to new mapcenter or branch, if shift is pressed 
4640                         // Only relink, if selection really has a new parent
4641                         if ( (e->modifiers()==Qt::ShiftModifier) && lmo &&
4642                                 ( (typeid(*lmo)==typeid(BranchObj)) ||
4643                                   (typeid(*lmo)==typeid(MapCenterObj)) ) &&
4644                                 ( lmo != fio->getParObj())  
4645                                 )
4646                         {
4647                                 if (typeid(*fio) == typeid(FloatImageObj) && 
4648                                 ( (typeid(*lmo)==typeid(BranchObj) ||
4649                                   typeid(*lmo)==typeid(MapCenterObj)) ))  
4650                                 {
4651
4652                                         // Also save the move which was done so far
4653                                         QString pold=qpointfToString(movingObj_orgRelPos);
4654                                         QString pnow=qpointfToString(fio->getRelPos());
4655                                         saveState(
4656                                                 fio,
4657                                                 "moveRel "+pold,
4658                                                 fio,
4659                                                 "moveRel "+pnow,
4660                                                 QString("Move %1 to relative position %2").arg(getName(fio)).arg(pnow));
4661                                         fio->getParObj()->requestReposition();
4662                                         model->reposition();
4663
4664                                         linkTo (model->getSelectString(lmo));
4665                                         //movingObj=lmosel;
4666                                         //movingObj_orgRelPos=lmosel->getRelPos();      
4667
4668                                         model->reposition();
4669                                 }       
4670                         }
4671                 } else  
4672                 {       // selection != a FloatObj
4673                         if (lmosel->getDepth()==0)
4674                         {
4675                                 // Move MapCenter
4676                                 if (e->buttons()== Qt::LeftButton && e->modifiers()==Qt::ShiftModifier) 
4677                                         ((MapCenterObj*)lmosel)->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );               
4678                                 else    
4679                                         lmosel->move   (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );                
4680                                 model->updateRelPositions();
4681                         } else
4682                         {       
4683                                 if (lmosel->getDepth()==1)
4684                                 {
4685                                         // Move mainbranch
4686                                         lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );           
4687                                         lmosel->setRelPos();
4688                                 } else
4689                                 {
4690                                         // Move ordinary branch
4691                                         lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y()  );          
4692                                 } 
4693
4694                                 // Maybe we can relink temporary?
4695                                 if (lmo && (lmo!=lmosel) && xelection.getBranch() && 
4696                                          (typeid(*lmo)==typeid(BranchObj) ||
4697                                           typeid(*lmo)==typeid(MapCenterObj)) ) 
4698
4699                                 {
4700                                         if (e->modifiers()==Qt::ControlModifier)
4701                                         {
4702                                                 // Special case: CTRL to link below lmo
4703                                                 lmosel->setParObjTmp (lmo,p,+1);
4704                                         }
4705                                         else if (e->modifiers()==Qt::ShiftModifier)
4706                                                 lmosel->setParObjTmp (lmo,p,-1);
4707                                         else
4708                                                 lmosel->setParObjTmp (lmo,p,0);
4709                                 } else  
4710                                 {
4711                                         lmosel->unsetParObjTmp();
4712                                 }               
4713                                 // reposition subbranch
4714                                 lmosel->reposition();   
4715                         } // depth>0
4716
4717                         xelection.update();
4718                 } // no FloatImageObj
4719
4720                 scene()->update();
4721                 return;
4722         } // selection && moving_obj
4723                 
4724         // Draw a link from one branch to another
4725         if (drawingLink)
4726         {
4727                  tmpXLink->setEnd (p);
4728                  tmpXLink->updateXLink();
4729         }        
4730         
4731     // Move sceneView 
4732     if (!movingObj && !pickingColor &&!drawingLink && e->buttons() == Qt::LeftButton ) 
4733         {
4734                 QPointF p=e->globalPos();
4735                 movingVec.setX(-p.x() + movingObj_start.x() );
4736                 movingVec.setY(-p.y() + movingObj_start.y() );
4737                 horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
4738                 verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
4739     }
4740 }
4741
4742
4743 void MapEditor::mouseReleaseEvent(QMouseEvent* e)
4744 {
4745     QPointF p = mapToScene(e->pos());
4746         LinkableMapObj *dst;
4747         LinkableMapObj *lmosel=xelection.single();
4748         // Have we been picking color?
4749         if (pickingColor)
4750         {
4751                 pickingColor=false;
4752                 setCursor (Qt::ArrowCursor);
4753                 // Check if we are over another branch
4754                 dst=model->findMapObj(p, NULL);
4755                 if (dst && lmosel) 
4756                 {       
4757                         if (e->state() & Qt::ShiftModifier)
4758                                 colorBranch (((BranchObj*)dst)->getColor());
4759                         else    
4760                                 colorSubtree (((BranchObj*)dst)->getColor());
4761                 } 
4762                 return;
4763         }
4764
4765         // Have we been drawing a link?
4766         if (drawingLink)        
4767         {
4768                 drawingLink=false;
4769                 // Check if we are over another branch
4770                 dst=model->findMapObj(p, NULL);
4771                 if (dst && lmosel) 
4772                 {       
4773                         tmpXLink->setEnd ( ((BranchObj*)(dst)) );
4774                         tmpXLink->updateXLink();
4775                         tmpXLink->activate(); //FIXME savestate missing
4776                         //saveStateComplete(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) );      
4777                 } else
4778                 {
4779                         delete(tmpXLink);
4780                         tmpXLink=NULL;
4781                 }
4782                 return;
4783         }
4784         
4785     // Have we been moving something?
4786     if ( lmosel && movingObj ) 
4787     {   
4788                 FloatImageObj *fo=xelection.getFloatImage();
4789                 if(fo)
4790                 {
4791                         // Moved FloatObj. Maybe we need to reposition
4792                     QString pold=qpointfToString(movingObj_orgRelPos);
4793                     QString pnow=qpointfToString(fo->getRelPos());
4794                         saveState(
4795                                 fo,
4796                                 "moveRel "+pold,
4797                                 fo,
4798                                 "moveRel "+pnow,
4799                                 QString("Move %1 to relative position %2").arg(getName(fo)).arg(pnow));
4800
4801                         fo->getParObj()->requestReposition();
4802                         model->reposition();
4803                 }       
4804
4805                 // Check if we are over another branch, but ignore 
4806                 // any found LMOs, which are FloatObjs
4807                 dst=model->findMapObj(mapToScene(e->pos() ), lmosel);
4808
4809                 if (dst && (typeid(*dst)!=typeid(BranchObj) && typeid(*dst)!=typeid(MapCenterObj))) 
4810                         dst=NULL;
4811                 
4812                 BranchObj *bo=xelection.getBranch();
4813                 if (bo && bo->getDepth()==0)
4814                 {       
4815             if (movingObj_orgPos != bo->getAbsPos())
4816             {
4817                 QString pold=qpointfToString(movingObj_orgPos);
4818                 QString pnow=qpointfToString(bo->getAbsPos());
4819                 saveState(
4820                     fo,
4821                     "move "+pold,
4822                     fo,
4823                     "move "+pnow,
4824                     QString("Move mapcenter %1 to position %2").arg(getName(bo)).arg(pnow));
4825             }
4826                 }
4827         
4828                 if (xelection.type() == Selection::Branch )
4829                 {       // A branch was moved
4830                         
4831                         // save the position in case we link to mapcenter
4832                         QPointF savePos=QPointF (lmosel->getAbsPos()  );
4833
4834                         // Reset the temporary drawn link to the original one
4835                         lmosel->unsetParObjTmp();
4836
4837                         // For Redo we may need to save original selection
4838                         QString preSelStr=model->getSelectString(lmosel);
4839
4840                         copyingObj=false;       
4841                         if (dst ) 
4842                         {
4843                                 // We have a destination, relink to that
4844
4845                                 BranchObj* bsel=xelection.getBranch();
4846                                 BranchObj* bdst=(BranchObj*)dst;
4847
4848                                 QString preParStr=model->getSelectString (bsel->getParObj());
4849                                 QString preNum=QString::number (bsel->getNum(),10);
4850                                 QString preDstParStr;
4851
4852                                 if (e->state() & Qt::ShiftModifier && dst->getParObj())
4853                                 {       // Link above dst
4854                                         preDstParStr=model->getSelectString (dst->getParObj());
4855                                         bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum());
4856                                 } else 
4857                                 if (e->state() & Qt::ControlModifier && dst->getParObj())
4858                                 {
4859                                         // Link below dst
4860                                         preDstParStr=model->getSelectString (dst->getParObj());
4861                                         bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum()+1);
4862                                 } else  
4863                                 {       // Append to dst
4864                                         preDstParStr=model->getSelectString(dst);
4865                                         bsel->linkTo (bdst,-1);
4866                                         if (dst->getDepth()==0) bsel->move (savePos);
4867                                 } 
4868                                 QString postSelStr=model->getSelectString(lmosel);
4869                                 QString postNum=QString::number (bsel->getNum(),10);
4870
4871                                 QString undoCom="linkTo (\""+ 
4872                                         preParStr+ "\"," + preNum  +"," + 
4873                                         QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")";
4874
4875                                 QString redoCom="linkTo (\""+ 
4876                                         preDstParStr + "\"," + postNum + "," +
4877                                         QString ("%1,%2").arg(savePos.x()).arg(savePos.y())+ ")";
4878
4879                                 saveState (
4880                                         postSelStr,undoCom,
4881                                         preSelStr, redoCom,
4882                                         QString("Relink %1 to %2").arg(getName(bsel)).arg(getName(dst)) );
4883
4884                                 model->reposition();    // not necessary if we undo temporary move  below
4885                         } else
4886                         {
4887                                 // No destination, undo  temporary move
4888
4889                                 if (lmosel->getDepth()==1)
4890                                 {
4891                                         // The select string might be different _after_ moving around.
4892                                         // Therefor reposition and then use string of old selection, too
4893                                         model->reposition();
4894
4895                     QPointF rp(lmosel->getRelPos());
4896                     if (rp != movingObj_orgRelPos)
4897                     {
4898                         QString ps=qpointfToString(rp);
4899                         saveState(
4900                             model->getSelectString(lmosel), "moveRel "+qpointfToString(movingObj_orgRelPos), 
4901                             preSelStr, "moveRel "+ps, 
4902                             QString("Move %1 to relative position %2").arg(getName(lmosel)).arg(ps));
4903                     }
4904                                 }
4905
4906                                 // Draw the original link, before selection was moved around
4907                                 if (settings.value("/animation/use",false).toBool() && lmosel->getDepth()>1) 
4908                                 {
4909                                         QPointF p=bo->getParObj()->getChildPos();
4910                                         lmosel->setRelPos();    // calc relPos first
4911                                         model->startAnimation(
4912                                                 lmosel->getRelPos(),
4913                                                 QPointF (movingObj_orgPos.x() - p.x(), movingObj_orgPos.y() - p.y() )
4914                                         );      
4915                                 } else  
4916                                         model->reposition();
4917                         }
4918                 }
4919                  xelection.update();
4920                 // Finally resize scene, if needed
4921                 scene()->update();
4922                 movingObj=NULL;         
4923
4924                 // Just make sure, that actions are still ok,e.g. the move branch up/down buttons...
4925                 updateActions();
4926         } else 
4927                 // maybe we moved View: set old cursor
4928                 setCursor (Qt::ArrowCursor);
4929     
4930 }
4931
4932 void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
4933 {
4934         if (isSelectBlocked() ) 
4935         {
4936                 e->ignore();
4937                 return;
4938         }
4939
4940         if (e->button() == Qt::LeftButton )
4941         {
4942                 QPointF p = mapToScene(e->pos());
4943                 LinkableMapObj *lmo=model->findMapObj(p, NULL);
4944                 if (lmo) {      // MapObj was found
4945                         // First select the MapObj than edit heading
4946                         xelection.select(lmo);
4947                         mainWindow->editHeading();
4948                 }
4949         }
4950 }
4951
4952 void MapEditor::resizeEvent (QResizeEvent* e)
4953 {
4954         QGraphicsView::resizeEvent( e );
4955 }
4956
4957 void MapEditor::dragEnterEvent(QDragEnterEvent *event)
4958 {
4959         //for (unsigned int i=0;event->format(i);i++) // Debug mime type
4960         //      cerr << event->format(i) << endl;
4961
4962         if (event->mimeData()->hasImage())
4963                 event->acceptProposedAction();
4964         else    
4965                 if (event->mimeData()->hasUrls())
4966                         event->acceptProposedAction();
4967 }
4968
4969 void MapEditor::dragMoveEvent(QDragMoveEvent *)
4970 {
4971 }
4972
4973 void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
4974 {
4975         event->accept();
4976 }
4977
4978 void MapEditor::dropEvent(QDropEvent *event)
4979 {
4980         BranchObj *sel=xelection.getBranch();
4981         if (sel)
4982         {
4983                 if (debug)
4984                         foreach (QString format,event->mimeData()->formats()) 
4985                                 cout << "MapEditor: Dropped format: "<<qPrintable (format)<<endl;
4986
4987
4988                 QList <QUrl> uris;
4989                 if (event->mimeData()->hasImage()) 
4990                 {
4991                          QVariant imageData = event->mimeData()->imageData();
4992                          addFloatImageInt (qvariant_cast<QPixmap>(imageData));
4993                 } else
4994                 if (event->mimeData()->hasUrls())
4995                         uris=event->mimeData()->urls();
4996
4997                 if (uris.count()>0)
4998                 {
4999                         QStringList files;
5000                         QString s;
5001                         QString heading;
5002                         BranchObj *bo;
5003                         for (int i=0; i<uris.count();i++)
5004                         {
5005                                 // Workaround to avoid adding empty branches
5006                                 if (!uris.at(i).toString().isEmpty())
5007                                 {
5008                                         bo=sel->addBranch();
5009                                         if (bo)
5010                                         {
5011                                                 s=uris.at(i).toLocalFile();
5012                                                 if (!s.isEmpty()) 
5013                                                 {
5014                                                    QString file = QDir::fromNativeSeparators(s);
5015                                                    heading = QFileInfo(file).baseName();
5016                                                    files.append(file);
5017                                                    if (file.endsWith(".vym", false))
5018                                                            bo->setVymLink(file);
5019                                                    else
5020                                                            bo->setURL(uris.at(i).toString());
5021                                            } else 
5022                                            {
5023                                                    bo->setURL(uris.at(i).toString());
5024                                            }
5025
5026                                            if (!heading.isEmpty())
5027                                                    bo->setHeading(heading);
5028                                            else
5029                                                    bo->setHeading(uris.at(i).toString());
5030                                         }
5031                                 }
5032                         }
5033                         model->reposition();
5034                 }
5035         }       
5036         event->acceptProposedAction();
5037 }
5038
5039
5040 void MapEditor::sendSelection()
5041 {
5042         if (netstate!=Server) return;
5043         sendData (QString("select (\"%1\")").arg(xelection.getSelectString()) );
5044 }
5045
5046 void MapEditor::newServer()
5047 {
5048         port=54321;
5049         sendCounter=0;
5050     tcpServer = new QTcpServer(this);
5051     if (!tcpServer->listen(QHostAddress::Any,port)) {
5052         QMessageBox::critical(this, "vym server",
5053                               QString("Unable to start the server: %1.").arg(tcpServer->errorString()));
5054         close();
5055         return;
5056     }
5057         connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newClient()));
5058         netstate=Server;
5059         cout<<"Server is running on port "<<tcpServer->serverPort()<<endl;
5060 }
5061
5062 void MapEditor::connectToServer()
5063 {
5064         port=54321;
5065         server="salam.suse.de";
5066         server="localhost";
5067         clientSocket = new QTcpSocket (this);
5068         clientSocket->abort();
5069     clientSocket->connectToHost(server ,port);
5070         connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readData()));
5071     connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
5072             this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
5073         netstate=Client;                
5074         cout<<"connected to "<<qPrintable (server)<<" port "<<port<<endl;
5075
5076         
5077 }
5078
5079 void MapEditor::newClient()
5080 {
5081     QTcpSocket *newClient = tcpServer->nextPendingConnection();
5082     connect(newClient, SIGNAL(disconnected()),
5083             newClient, SLOT(deleteLater()));
5084
5085         cout <<"ME::newClient  at "<<qPrintable( newClient->peerAddress().toString() )<<endl;
5086
5087         clientList.append (newClient);
5088 }
5089
5090
5091 void MapEditor::sendData(const QString &s)
5092 {
5093         if (clientList.size()==0) return;
5094
5095         // Create bytearray to send
5096         QByteArray block;
5097     QDataStream out(&block, QIODevice::WriteOnly);
5098     out.setVersion(QDataStream::Qt_4_0);
5099
5100         // Reserve some space for blocksize
5101     out << (quint16)0;
5102
5103         // Write sendCounter
5104     out << sendCounter++;
5105
5106         // Write data
5107     out << s;
5108
5109         // Go back and write blocksize so far
5110     out.device()->seek(0);
5111     quint16 bs=(quint16)(block.size() - 2*sizeof(quint16));
5112         out << bs;
5113
5114         if (debug)
5115                 cout << "ME::sendData  bs="<<bs<<"  counter="<<sendCounter<<"  s="<<qPrintable(s)<<endl;
5116
5117         for (int i=0; i<clientList.size(); ++i)
5118         {
5119                 //cout << "Sending \""<<qPrintable (s)<<"\" to "<<qPrintable (clientList.at(i)->peerAddress().toString())<<endl;
5120                 clientList.at(i)->write (block);
5121         }
5122 }
5123
5124 void MapEditor::readData ()
5125 {
5126         while (clientSocket->bytesAvailable() >=(int)sizeof(quint16) )
5127         {
5128                 if (debug)
5129                         cout <<"readData  bytesAvail="<<clientSocket->bytesAvailable();
5130                 quint16 recCounter;
5131                 quint16 blockSize;
5132
5133                 QDataStream in(clientSocket);
5134                 in.setVersion(QDataStream::Qt_4_0);
5135
5136                 in >> blockSize;
5137                 in >> recCounter;
5138                 
5139                 QString t;
5140                 in >>t;
5141                 if (debug)
5142                         cout << "  t="<<qPrintable (t)<<endl;
5143                 parseAtom (t);
5144         }
5145         return;
5146 }
5147
5148 void MapEditor::displayNetworkError(QAbstractSocket::SocketError socketError)
5149 {
5150     switch (socketError) {
5151     case QAbstractSocket::RemoteHostClosedError:
5152         break;
5153     case QAbstractSocket::HostNotFoundError:
5154         QMessageBox::information(this, vymName +" Network client",
5155                                  "The host was not found. Please check the "
5156                                     "host name and port settings.");
5157         break;
5158     case QAbstractSocket::ConnectionRefusedError:
5159         QMessageBox::information(this, vymName + " Network client",
5160                                  "The connection was refused by the peer. "
5161                                     "Make sure the fortune server is running, "
5162                                     "and check that the host name and port "
5163                                     "settings are correct.");
5164         break;
5165     default:
5166         QMessageBox::information(this, vymName + " Network client",
5167                                  QString("The following error occurred: %1.")
5168                                  .arg(clientSocket->errorString()));
5169     }
5170 }
5171
5172 void MapEditor::autosave()
5173 {
5174         QDateTime now=QDateTime().currentDateTime();
5175         /* FIXME debug
5176         cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n"; 
5177         cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
5178         cout << "  fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
5179         cout << "  time: "<<qPrintable (now.toString())<<endl;
5180         cout << " zipped="<<zipped<<endl;
5181         */
5182         // Disable autosave, while we have gone back in history
5183         int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
5184         if (redosAvail>0) return;
5185
5186         // Also disable autosave for new map without filename
5187         if (filePath.isEmpty()) return;
5188
5189
5190         if (mapUnsaved &&mapChanged && settings.value ("/mapeditor/autosave/use",true).toBool() )
5191         {
5192                 if (QFileInfo(filePath).lastModified()<=fileChangedTime) 
5193                         mainWindow->fileSave (this);
5194                 else
5195                         if (debug)
5196                                 cout <<"  ME::autosave  rejected, file on disk is newer than last save.\n"; 
5197
5198         }       
5199 }
5200
5201 void MapEditor::fileChanged()
5202 {
5203         // Check if file on disk has changed meanwhile
5204         if (!filePath.isEmpty())
5205         {
5206                 QDateTime tmod=QFileInfo (filePath).lastModified();
5207                 if (tmod>fileChangedTime)
5208                 {
5209                         
5210                         /* FIXME debug message, sometimes there's a glitch in the metrics...
5211                         cout << "ME::fileChanged()\n" 
5212                              << "  last saved:     "<<qPrintable (fileChangedTime.toString())<<endl
5213                                  << "  last modififed: "<<qPrintable (tmod.toString())<<endl;
5214                         */       
5215                         // FIXME switch to current mapeditor and finish lineedits...
5216                         QMessageBox mb( vymName,
5217                                 tr("The file of the map  on disk has changed:\n\n"  
5218                                    "   %1\n\nDo you want to reload that map with the new file?").arg(filePath),
5219                                 QMessageBox::Question,
5220                                 QMessageBox::Yes ,
5221                                 QMessageBox::Cancel | QMessageBox::Default,
5222                                 QMessageBox::NoButton );
5223
5224                         mb.setButtonText( QMessageBox::Yes, tr("Reload"));
5225                         mb.setButtonText( QMessageBox::No, tr("Ignore"));
5226                         switch( mb.exec() ) 
5227                         {
5228                                 case QMessageBox::Yes:
5229                                         // Reload map
5230                                         load (filePath,NewMap,fileType);
5231                         case QMessageBox::Cancel:
5232                                         fileChangedTime=tmod; // allow autosave to overwrite newer file!
5233                         }
5234                 }
5235         }       
5236
5237 }
5238
5239
5240 /*TODO not needed? void MapEditor::contentsDropEvent(QDropEvent *event) 
5241 {
5242
5243                 } else if (event->provides("application/x-moz-file-promise-url") && 
5244                          event->provides("application/x-moz-nativeimage")) 
5245                 {
5246                         // Contains url to the img src in unicode16
5247                         QByteArray d = event->encodedData("application/x-moz-file-promise-url");
5248                         QString url = QString((const QChar*)d.data(),d.size()/2);
5249                         fetchImage(url);
5250                         event->accept();
5251                         update=true;
5252                 } else if (event->provides ("text/uri-list"))
5253                 {       // Uris provided e.g. by konqueror
5254                         Q3UriDrag::decode (event,uris);
5255                 } else if (event->provides ("_NETSCAPE_URL"))
5256                 {       // Uris provided by Mozilla
5257                   QStringList l = QStringList::split("\n", event->encodedData("_NETSCAPE_URL"));
5258                   uris.append(l[0]);
5259                   heading = l[1];
5260                 } else if (event->provides("text/html")) {
5261
5262                   // Handels text mime types
5263                   // Look like firefox allways handle text as unicode16 (2 bytes per char.)
5264                   QByteArray d = event->encodedData("text/html");
5265                   QString text;
5266                   if (isUnicode16(d)) 
5267                     text = QString((const QChar*)d.data(),d.size()/2);
5268                   else 
5269                     text = QString(d);
5270
5271                   textEditor->setText(text);
5272
5273                   event->accept();
5274                   update=true;
5275                 } else if (event->provides("text/plain")) {
5276                   QByteArray d = event->encodedData("text/plain");
5277                   QString text;
5278                   if (isUnicode16(d))
5279                     text = QString((const QChar*)d.data(),d.size()/2);
5280                   else 
5281                     text = QString(d);
5282
5283                   textEditor->setText(text);
5284                   
5285                   event->accept();
5286                   update= true;
5287                 }
5288
5289                 */
5290
5291
5292
5293 bool isUnicode16(const QByteArray &d) 
5294 {
5295   // TODO: make more precise check for unicode 16.
5296   // Guess unicode16 if any of second bytes are zero
5297   unsigned int length = max(0,d.size()-2)/2;
5298   for (unsigned int i = 0; i<length ; i++)
5299     if (d.at(i*2+1)==0) return true;
5300   return false;
5301 }
5302       
5303 void MapEditor::addFloatImageInt (const QPixmap &img) 
5304 {
5305         BranchObj *bo=xelection.getBranch();
5306         if (bo)
5307   {
5308         FloatImageObj *fio=bo->addFloatImage();
5309     fio->load(img);
5310     fio->setOriginalFilename("No original filename (image added by dropevent)");        
5311         QString s=model->getSelectString(bo);
5312         saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy dropped image to clipboard",fio  );
5313         saveState (fio,"delete ()", bo,QString("paste(%1)").arg(curStep),"Pasting dropped image");
5314     model->reposition();
5315     scene()->update();
5316   }
5317 }
5318
5319 /*
5320
5321 void MapEditor::imageDataFetched(const QByteArray &a, Q3NetworkOperation * / *nop* /) 
5322 {
5323   if (!imageBuffer) imageBuffer = new QBuffer();
5324   if (!imageBuffer->isOpen()) {
5325     imageBuffer->open(QIODevice::WriteOnly | QIODevice::Append);
5326   }
5327   imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a));
5328 }
5329
5330
5331 void MapEditor::imageDataFinished(Q3NetworkOperation *nop) 
5332 {
5333         if (nop->state()==Q3NetworkProtocol::StDone) {
5334                 QPixmap img(imageBuffer->buffer());
5335                 addFloatImageInt (img);
5336         }
5337
5338         if (imageBuffer) {
5339                 imageBuffer->close();
5340                 if (imageBuffer) {
5341                         imageBuffer->close();
5342                         delete imageBuffer;
5343                         imageBuffer = 0;
5344                 }
5345         }
5346 }
5347
5348 void MapEditor::fetchImage(const QString &url) 
5349 {
5350   if (urlOperator) {
5351     urlOperator->stop();
5352     disconnect(urlOperator);
5353     delete urlOperator;
5354   }
5355   
5356   urlOperator = new Q3UrlOperator(url);
5357   connect(urlOperator, SIGNAL(finished(Q3NetworkOperation *)), 
5358           this, SLOT(imageDataFinished(Q3NetworkOperation*)));
5359
5360   connect(urlOperator, SIGNAL(data(const QByteArray &, Q3NetworkOperation *)),
5361           this, SLOT(imageDataFetched(const QByteArray &, Q3NetworkOperation *)));
5362   urlOperator->get();
5363 }
5364 */
5365