initial import
[vym] / mapeditor.cpp
diff --git a/mapeditor.cpp b/mapeditor.cpp
new file mode 100644 (file)
index 0000000..c9405f4
--- /dev/null
@@ -0,0 +1,5365 @@
+#include "mapeditor.h"
+
+//#include <q3filedialog.h>
+
+#include <iostream>
+#include <cstdlib>
+#include <typeinfo>
+
+#include "parser.h"
+#include "editxlinkdialog.h"
+#include "exports.h"
+#include "exportxhtmldialog.h"
+#include "extrainfodialog.h"
+#include "file.h"
+#include "linkablemapobj.h"
+#include "mainwindow.h"
+#include "misc.h"
+#include "texteditor.h"
+#include "warningdialog.h"
+#include "xml-freemind.h"
+#include "xml-vym.h"
+
+
+extern TextEditor *textEditor;
+extern int statusbarTime;
+extern Main *mainWindow;
+extern QString tmpVymDir;
+extern QString clipboardDir;
+extern QString clipboardFile;
+extern bool clipboardEmpty;
+extern bool debug;
+extern FlagRowObj *standardFlagsDefault;
+
+extern QMenu* branchContextMenu;
+extern QMenu* branchAddContextMenu;
+extern QMenu* branchRemoveContextMenu;
+extern QMenu* branchLinksContextMenu;
+extern QMenu* branchXLinksContextMenuEdit;
+extern QMenu* branchXLinksContextMenuFollow;
+extern QMenu* floatimageContextMenu;
+extern QMenu* canvasContextMenu;
+
+
+extern Settings settings;
+extern ImageIO imageIO;
+
+extern QString vymName;
+extern QString vymVersion;
+
+extern QString iconPath;
+extern QDir vymBaseDir;
+extern QDir lastImageDir;
+extern QDir lastFileDir;
+
+int MapEditor::mapNum=0;       // make instance
+
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+MapEditor::MapEditor( QWidget* parent) :
+  QGraphicsView(parent)  
+{
+       setObjectName ("MapEditor");
+
+       //cout << "Constructor ME "<<this<<endl;
+       mapNum++;
+
+
+       mapScene= new QGraphicsScene(parent);
+       //mapScene= new QGraphicsScene(QRectF(0,0,width(),height()), parent);
+       mapScene->setBackgroundBrush (QBrush(Qt::white, Qt::SolidPattern));
+
+       model=new VymModel();
+       model->setScene (mapScene);
+       model->setMapEditor (this);
+
+    setScene (mapScene);
+
+    printer=NULL;
+
+       defLinkColor=QColor (0,0,255);
+       defXLinkColor=QColor (180,180,180);
+       linkcolorhint=LinkableMapObj::DefaultColor;
+       linkstyle=LinkableMapObj::PolyParabel;
+
+       // Create bitmap cursors, platform dependant
+       HandOpenCursor=QCursor (QPixmap(iconPath+"cursorhandopen.png"),1,1);            
+       PickColorCursor=QCursor ( QPixmap(iconPath+"cursorcolorpicker.png"), 5,27 ); 
+       CopyCursor=QCursor ( QPixmap(iconPath+"cursorcopy.png"), 1,1 ); 
+       XLinkCursor=QCursor ( QPixmap(iconPath+"cursorxlink.png"), 1,7 ); 
+
+       setFocusPolicy (Qt::StrongFocus);
+
+       pickingColor=false;
+       drawingLink=false;
+       copyingObj=false;
+
+    editingBO=NULL;
+    movingObj=NULL;
+
+       xelection.setModel (model);
+       xelection.unselect();
+
+       defXLinkWidth=1;
+       defXLinkColor=QColor (230,230,230);
+
+    mapChanged=false;
+       mapDefault=true;
+       mapUnsaved=false;
+       
+       zipped=true;
+       filePath="";
+       fileName=tr("unnamed");
+       mapName="";
+
+       stepsTotal=settings.readNumEntry("/mapeditor/stepsTotal",100);
+       undoSet.setEntry ("/history/stepsTotal",QString::number(stepsTotal));
+       mainWindow->updateHistory (undoSet);
+       
+       // Initialize find routine
+       itFind=NULL;                            
+       EOFind=false;
+
+       printFrame=true;
+       printFooter=true;
+
+       blockReposition=false;
+       blockSaveState=false;
+
+       hidemode=HideNone;
+
+       // Create temporary files
+       makeTmpDirs();
+
+       curStep=0;
+       redosAvail=0;
+       undosAvail=0;
+
+       setAcceptDrops (true);  
+
+       model->reposition();
+
+       // autosave
+       autosaveTimer=new QTimer (this);
+       connect(autosaveTimer, SIGNAL(timeout()), this, SLOT(autosave()));
+
+       fileChangedTimer=new QTimer (this);
+       fileChangedTimer->start(3000);
+       connect(fileChangedTimer, SIGNAL(timeout()), this, SLOT(fileChanged()));
+
+       // Network
+       netstate=Offline;
+
+       // Attributes   //FIXME testing only...
+       QString k;
+       AttributeDef *ad;
+       attrTable= new AttributeTable();
+       k="A - StringList";
+       ad=attrTable->addKey (k,StringList);
+       if (ad)
+       {
+               QStringList sl;
+               sl <<"val 1"<<"val 2"<< "val 3";
+               ad->setValue (QVariant (sl));
+       }
+       //attrTable->addValue ("Key A","P 1");
+       //attrTable->addValue ("Key A","P 2");
+       //attrTable->addValue ("Key A","P 3");
+       //attrTable->addValue ("Key A","P 4");
+       k="B - FreeString";
+       ad=attrTable->addKey (k,FreeString);
+       if (ad)
+       {
+               //attrTable->addValue ("Key B","w1");
+               //attrTable->addValue ("Key B","w2");
+       }
+       k="C - UniqueString";
+       ad=attrTable->addKey (k,UniqueString);
+       if (ad)
+       {
+       //attrTable->addKey ("Key Prio");
+       //attrTable->addValue ("Key Prio","Prio 1");
+       //attrTable->addValue ("Key Prio","Prio 2");
+       }
+}
+
+MapEditor::~MapEditor()
+{
+       //cout <<"Destructor MapEditor\n";
+       autosaveTimer->stop();
+       fileChangedTimer->stop();
+
+       // tmpMapDir is in tmpVymDir, so it gets removed automagically when vym closes
+       
+       //removeDir(QDir(tmpMapDir));
+       delete (model);
+}
+
+VymModel* MapEditor::getModel()
+{
+    return model;
+}
+
+QGraphicsScene * MapEditor::getScene()
+{
+    return mapScene;
+}
+
+MapEditor::State MapEditor::getState()
+{
+    return state;
+}
+
+void MapEditor::setStateEditHeading(bool s)
+{
+       if (s)
+       {
+               if (state==Idle) state=EditHeading;
+       }
+       else    
+               state=Idle;
+}
+
+bool MapEditor::isRepositionBlocked()
+{
+       return blockReposition;
+}
+
+void MapEditor::setSaveStateBlocked(bool b)
+{
+       blockSaveState=b;
+}
+
+bool MapEditor::isSelectBlocked()
+{
+       if (state==EditHeading)
+               return true;
+       else
+               return false; 
+}
+
+QString MapEditor::getName (const LinkableMapObj *lmo)
+{
+       QString s;
+       if (!lmo) return QString("Error: NULL has no name!");
+
+       if ((typeid(*lmo) == typeid(BranchObj) ||
+                                     typeid(*lmo) == typeid(MapCenterObj))) 
+       {
+               
+               s=(((BranchObj*)lmo)->getHeading());
+               if (s=="") s="unnamed";
+               return QString("branch (%1)").arg(s);
+       }       
+       if ((typeid(*lmo) == typeid(FloatImageObj) ))
+               return QString ("floatimage [%1]").arg(((FloatImageObj*)lmo)->getOriginalFilename());
+       return QString("Unknown type has no name!");
+}
+
+void MapEditor::makeTmpDirs()
+{
+       // Create unique temporary directories
+       tmpMapDir = tmpVymDir+QString("/mapeditor-%1").arg(mapNum);
+       histPath = tmpMapDir+"/history";
+       QDir d;
+       d.mkdir (tmpMapDir);
+}
+
+QString MapEditor::saveToDir(const QString &tmpdir, const QString &prefix, bool writeflags, const QPointF &offset, LinkableMapObj *saveSel)
+{
+       // tmpdir               temporary directory to which data will be written
+       // prefix               mapname, which will be appended to images etc.
+       // writeflags   Only write flags for "real" save of map, not undo
+       // offset               offset of bbox of whole map in scene. 
+       //                              Needed for XML export
+       
+       // Save Header
+       QString ls;
+       switch (linkstyle)
+       {
+               case LinkableMapObj::Line: 
+                       ls="StyleLine";
+                       break;
+               case LinkableMapObj::Parabel:
+                       ls="StyleParabel";
+                       break;
+               case LinkableMapObj::PolyLine:  
+                       ls="StylePolyLine";
+                       break;
+               default:
+                       ls="StylePolyParabel";
+                       break;
+       }       
+
+       QString s="<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE vymmap>\n";
+       QString colhint="";
+       if (linkcolorhint==LinkableMapObj::HeadingColor) 
+               colhint=attribut("linkColorHint","HeadingColor");
+
+       QString mapAttr=attribut("version",vymVersion);
+       if (!saveSel)
+               mapAttr+= attribut("author",model->getAuthor()) +
+                                 attribut("comment",model->getComment()) +
+                             attribut("date",model->getDate()) +
+                         attribut("backgroundColor", mapScene->backgroundBrush().color().name() ) +
+                         attribut("selectionColor", xelection.getColor().name() ) +
+                         attribut("linkStyle", ls ) +
+                         attribut("linkColor", defLinkColor.name() ) +
+                         attribut("defXLinkColor", defXLinkColor.name() ) +
+                         attribut("defXLinkWidth", QString().setNum(defXLinkWidth,10) ) +
+                         colhint; 
+       s+=beginElement("vymmap",mapAttr);
+       incIndent();
+
+       // Find the used flags while traversing the tree
+       standardFlagsDefault->resetUsedCounter();
+       
+       // Reset the counters before saving
+       // TODO constr. of FIO creates lots of objects, better do this in some other way...
+       FloatImageObj (mapScene).resetSaveCounter();
+
+       // Build xml recursivly
+       if (!saveSel || typeid (*saveSel) == typeid (MapCenterObj))
+               // Save complete map, if saveSel not set
+               s+=model->saveToDir(tmpdir,prefix,writeflags,offset);
+       else
+       {
+               if ( typeid(*saveSel) == typeid(BranchObj) )
+                       // Save Subtree
+                       s+=((BranchObj*)(saveSel))->saveToDir(tmpdir,prefix,offset);
+               else if ( typeid(*saveSel) == typeid(FloatImageObj) )
+                       // Save image
+                       s+=((FloatImageObj*)(saveSel))->saveToDir(tmpdir,prefix);
+       }
+
+       // Save local settings
+       s+=settings.getDataXML (destPath);
+
+       // Save selection
+       if (!xelection.isEmpty() && !saveSel ) 
+               s+=valueElement("select",xelection.getSelectString());
+
+       decIndent();
+       s+=endElement("vymmap");
+
+       if (writeflags)
+               standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags);
+       return s;
+}
+
+QString MapEditor::getHistoryDir()
+{
+       QString histName(QString("history-%1").arg(curStep));
+       return (tmpMapDir+"/"+histName);
+}
+
+void MapEditor::saveState(const SaveMode &savemode, const QString &undoSelection, const QString &undoCom, const QString &redoSelection, const QString &redoCom, const QString &comment, LinkableMapObj *saveSel)
+{
+       sendData(redoCom);      //FIXME testing
+
+       // Main saveState
+
+
+       if (blockSaveState) return;
+
+       if (debug) cout << "ME::saveState() for  "<<qPrintable (mapName)<<endl;
+       
+       // Find out current undo directory
+       if (undosAvail<stepsTotal) undosAvail++;
+       curStep++;
+       if (curStep>stepsTotal) curStep=1;
+       
+       QString backupXML="";
+       QString histDir=getHistoryDir();
+       QString bakMapPath=histDir+"/map.xml";
+
+       // Create histDir if not available
+       QDir d(histDir);
+       if (!d.exists()) 
+               makeSubDirs (histDir);
+
+       // Save depending on how much needs to be saved 
+       if (saveSel)
+               backupXML=saveToDir (histDir,mapName+"-",false, QPointF (),saveSel);
+               
+       QString undoCommand="";
+       if (savemode==UndoCommand)
+       {
+               undoCommand=undoCom;
+       }       
+       else if (savemode==PartOfMap )
+       {
+               undoCommand=undoCom;
+               undoCommand.replace ("PATH",bakMapPath);
+       }
+
+       if (!backupXML.isEmpty())
+               // Write XML Data to disk
+               saveStringToDisk (bakMapPath,backupXML);
+
+       // We would have to save all actions in a tree, to keep track of 
+       // possible redos after a action. Possible, but we are too lazy: forget about redos.
+       redosAvail=0;
+
+       // Write the current state to disk
+       undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
+       undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
+       undoSet.setEntry ("/history/curStep",QString::number(curStep));
+       undoSet.setEntry (QString("/history/step-%1/undoCommand").arg(curStep),undoCommand);
+       undoSet.setEntry (QString("/history/step-%1/undoSelection").arg(curStep),undoSelection);
+       undoSet.setEntry (QString("/history/step-%1/redoCommand").arg(curStep),redoCom);
+       undoSet.setEntry (QString("/history/step-%1/redoSelection").arg(curStep),redoSelection);
+       undoSet.setEntry (QString("/history/step-%1/comment").arg(curStep),comment);
+       undoSet.setEntry (QString("/history/version"),vymVersion);
+       undoSet.writeSettings(histPath);
+
+       if (debug)
+       {
+               // TODO remove after testing
+               //cout << "          into="<< histPath.toStdString()<<endl;
+               cout << "    stepsTotal="<<stepsTotal<<
+               ", undosAvail="<<undosAvail<<
+               ", redosAvail="<<redosAvail<<
+               ", curStep="<<curStep<<endl;
+               cout << "    ---------------------------"<<endl;
+               cout << "    comment="<<comment.toStdString()<<endl;
+               cout << "    undoCom="<<undoCommand.toStdString()<<endl;
+               cout << "    undoSel="<<undoSelection.toStdString()<<endl;
+               cout << "    redoCom="<<redoCom.toStdString()<<endl;
+               cout << "    redoSel="<<redoSelection.toStdString()<<endl;
+               if (saveSel) cout << "    saveSel="<<qPrintable (model->getSelectString(saveSel))<<endl;
+               cout << "    ---------------------------"<<endl;
+       }
+
+       mainWindow->updateHistory (undoSet);
+       setChanged();
+       updateActions();
+}
+
+
+void MapEditor::saveStateChangingPart(LinkableMapObj *undoSel, LinkableMapObj* redoSel, const QString &rc, const QString &comment)
+{
+       // save the selected part of the map, Undo will replace part of map 
+       QString undoSelection="";
+       if (undoSel)
+               undoSelection=model->getSelectString(undoSel);
+       else
+               qWarning ("MapEditor::saveStateChangingPart  no undoSel given!");
+       QString redoSelection="";
+       if (redoSel)
+               redoSelection=model->getSelectString(undoSel);
+       else
+               qWarning ("MapEditor::saveStateChangingPart  no redoSel given!");
+               
+
+       saveState (PartOfMap,
+               undoSelection, "addMapReplace (\"PATH\")",
+               redoSelection, rc, 
+               comment, 
+               undoSel);
+}
+
+void MapEditor::saveStateRemovingPart(LinkableMapObj *redoSel, const QString &comment)
+{
+       if (!redoSel)
+       {
+               qWarning ("MapEditor::saveStateRemovingPart  no redoSel given!");
+               return;
+       }
+       QString undoSelection=model->getSelectString (redoSel->getParObj());
+       QString redoSelection=model->getSelectString(redoSel);
+       if (typeid(*redoSel) == typeid(BranchObj)  ) 
+       {
+               // save the selected branch of the map, Undo will insert part of map 
+               saveState (PartOfMap,
+                       undoSelection, QString("addMapInsert (\"PATH\",%1)").arg(((BranchObj*)redoSel)->getNum()),
+                       redoSelection, "delete ()", 
+                       comment, 
+                       redoSel);
+       }
+}
+
+
+void MapEditor::saveState(LinkableMapObj *undoSel, const QString &uc, LinkableMapObj *redoSel, const QString &rc, const QString &comment) 
+{
+       // "Normal" savestate: save commands, selections and comment
+       // so just save commands for undo and redo
+       // and use current selection
+
+       QString redoSelection="";
+       if (redoSel) redoSelection=model->getSelectString(redoSel);
+       QString undoSelection="";
+       if (undoSel) undoSelection=model->getSelectString(undoSel);
+
+       saveState (UndoCommand,
+               undoSelection, uc,
+               redoSelection, rc, 
+               comment, 
+               NULL);
+}
+
+void MapEditor::saveState(const QString &undoSel, const QString &uc, const QString &redoSel, const QString &rc, const QString &comment) 
+{
+       // "Normal" savestate: save commands, selections and comment
+       // so just save commands for undo and redo
+       // and use current selection
+       saveState (UndoCommand,
+               undoSel, uc,
+               redoSel, rc, 
+               comment, 
+               NULL);
+}
+
+void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment) 
+{
+       // "Normal" savestate applied to model (no selection needed): 
+       // save commands  and comment
+       saveState (UndoCommand,
+               NULL, uc,
+               NULL, rc, 
+               comment, 
+               NULL);
+}
+
+               
+void MapEditor::parseAtom(const QString &atom)
+{
+       BranchObj *selb=xelection.getBranch();
+       QString s,t;
+       double x,y;
+       int n;
+       bool b,ok;
+
+       // Split string s into command and parameters
+       parser.parseAtom (atom);
+       QString com=parser.getCommand();
+       
+       // External commands
+       /////////////////////////////////////////////////////////////////////
+       if (com=="addBranch")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else 
+               {       
+                       QList <int> pl;
+                       pl << 0 <<1;
+                       if (parser.checkParCount(pl))
+                       {
+                               if (parser.parCount()==0)
+                                       addNewBranch (0);
+                               else
+                               {
+                                       n=parser.parInt (ok,0);
+                                       if (ok ) addNewBranch (n);
+                               }
+                       }
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="addBranchBefore")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else 
+               {       
+                       if (parser.parCount()==0)
+                       {
+                               addNewBranchBefore ();
+                       }       
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com==QString("addMapCenter"))
+       {
+               if (parser.checkParCount(2))
+               {
+                       x=parser.parDouble (ok,0);
+                       if (ok)
+                       {
+                               y=parser.parDouble (ok,1);
+                               if (ok) model->addMapCenter (QPointF(x,y));
+                       }
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com==QString("addMapReplace"))
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       //s=parser.parString (ok,0);    // selection
+                       t=parser.parString (ok,0);      // path to map
+                       if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
+                       addMapReplaceInt(model->getSelectString(selb),t);       
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com==QString("addMapInsert"))
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else 
+               {       
+                       if (parser.checkParCount(2))
+                       {
+                               t=parser.parString (ok,0);      // path to map
+                               n=parser.parInt(ok,1);          // position
+                               if (QDir::isRelativePath(t)) t=(tmpMapDir + "/"+t);
+                               addMapInsertInt(t,n);   
+                       }
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="clearFlags")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {
+                       selb->clearStandardFlags();     
+                       selb->updateFlagsToolbar();
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="colorBranch")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {       
+                       QColor c=parser.parColor (ok,0);
+                       if (ok) colorBranch (c);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="colorSubtree")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {       
+                       QColor c=parser.parColor (ok,0);
+                       if (ok) colorSubtree (c);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="copy")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       //FIXME missing action for copy
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="cut")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if ( xelection.type()!=Selection::Branch  && 
+                                       xelection.type()!=Selection::MapCenter  &&
+                                       xelection.type()!=Selection::FloatImage )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch or floatimage");
+               } else if (parser.checkParCount(0))
+               {       
+                       cut();
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="delete")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } 
+               /*else if (xelection.type() != Selection::Branch && xelection.type() != Selection::FloatImage )
+               {
+                       parser.setError (Aborted,"Type of selection is wrong.");
+               } 
+               */
+               else if (parser.checkParCount(0))
+               {       
+                       deleteSelection();
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="deleteKeepChilds")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       deleteKeepChilds();
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="deleteChilds")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb)
+               {
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       deleteChilds();
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="exportASCII")
+       {
+               QString fname="";
+               ok=true;
+               if (parser.parCount()>=1)
+                       // Hey, we even have a filename
+                       fname=parser.parString(ok,0); 
+               if (!ok)
+               {
+                       parser.setError (Aborted,"Could not read filename");
+               } else
+               {
+                               exportASCII (fname,false);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="exportImage")
+       {
+               QString fname="";
+               ok=true;
+               if (parser.parCount()>=2)
+                       // Hey, we even have a filename
+                       fname=parser.parString(ok,0); 
+               if (!ok)
+               {
+                       parser.setError (Aborted,"Could not read filename");
+               } else
+               {
+                       QString format="PNG";
+                       if (parser.parCount()>=2)
+                       {
+                               format=parser.parString(ok,1);
+                       }
+                       exportImage (fname,false,format);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="exportXHTML")
+       {
+               QString fname="";
+               ok=true;
+               if (parser.parCount()>=2)
+                       // Hey, we even have a filename
+                       fname=parser.parString(ok,1); 
+               if (!ok)
+               {
+                       parser.setError (Aborted,"Could not read filename");
+               } else
+               {
+                       exportXHTML (fname,false);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="exportXML")
+       {
+               QString fname="";
+               ok=true;
+               if (parser.parCount()>=2)
+                       // Hey, we even have a filename
+                       fname=parser.parString(ok,1); 
+               if (!ok)
+               {
+                       parser.setError (Aborted,"Could not read filename");
+               } else
+               {
+                       exportXML (fname,false);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="importDir")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) importDirInt(s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="linkTo")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if ( selb)
+               {
+                       if (parser.checkParCount(4))
+                       {
+                               // 0    selectstring of parent
+                               // 1    num in parent (for branches)
+                               // 2,3  x,y of mainbranch or mapcenter
+                               s=parser.parString(ok,0);
+                               LinkableMapObj *dst=model->findObjBySelect (s);
+                               if (dst)
+                               {       
+                                       if (typeid(*dst) == typeid(BranchObj) ) 
+                                       {
+                                               // Get number in parent
+                                               n=parser.parInt (ok,1);
+                                               if (ok)
+                                               {
+                                                       selb->linkTo ((BranchObj*)(dst),n);
+                                                       xelection.update();
+                                               }       
+                                       } else if (typeid(*dst) == typeid(MapCenterObj) ) 
+                                       {
+                                               selb->linkTo ((BranchObj*)(dst),-1);
+                                               // Get coordinates of mainbranch
+                                               x=parser.parDouble(ok,2);
+                                               if (ok)
+                                               {
+                                                       y=parser.parDouble(ok,3);
+                                                       if (ok) 
+                                                       {
+                                                               selb->move (x,y);
+                                                               xelection.update();
+                                                       }
+                                               }
+                                       }       
+                               }       
+                       }       
+               } else if ( xelection.type() == Selection::FloatImage) 
+               {
+                       if (parser.checkParCount(1))
+                       {
+                               // 0    selectstring of parent
+                               s=parser.parString(ok,0);
+                               LinkableMapObj *dst=model->findObjBySelect (s);
+                               if (dst)
+                               {       
+                                       if (typeid(*dst) == typeid(BranchObj) ||
+                                               typeid(*dst) == typeid(MapCenterObj)) 
+                                               linkTo (model->getSelectString(dst));
+                               } else  
+                                       parser.setError (Aborted,"Destination is not a branch");
+                       }               
+               } else
+                       parser.setError (Aborted,"Type of selection is not a floatimage or branch");
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="loadImage")
+       {
+               if (xelection.isEmpty())
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) loadFloatImageInt (s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="moveBranchUp")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {
+                       moveBranchUp();
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="moveBranchDown")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {
+                       moveBranchDown();
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="move")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if ( xelection.type()!=Selection::Branch  && 
+                                       xelection.type()!=Selection::MapCenter  &&
+                                       xelection.type()!=Selection::FloatImage )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch or floatimage");
+               } else if (parser.checkParCount(2))
+               {       
+                       x=parser.parDouble (ok,0);
+                       if (ok)
+                       {
+                               y=parser.parDouble (ok,1);
+                               if (ok) move (x,y);
+                       }
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="moveRel")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if ( xelection.type()!=Selection::Branch  && 
+                                       xelection.type()!=Selection::MapCenter  &&
+                                       xelection.type()!=Selection::FloatImage )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch or floatimage");
+               } else if (parser.checkParCount(2))
+               {       
+                       x=parser.parDouble (ok,0);
+                       if (ok)
+                       {
+                               y=parser.parDouble (ok,1);
+                               if (ok) moveRel (x,y);
+                       }
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="nop")
+       {
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="paste")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {       
+                       n=parser.parInt (ok,0);
+                       if (ok) pasteNoSave(n);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="qa")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(4))
+               {       
+                       QString c,u;
+                       c=parser.parString (ok,0);
+                       if (!ok)
+                       {
+                               parser.setError (Aborted,"No comment given");
+                       } else
+                       {
+                               s=parser.parString (ok,1);
+                               if (!ok)
+                               {
+                                       parser.setError (Aborted,"First parameter is not a string");
+                               } else
+                               {
+                                       t=parser.parString (ok,2);
+                                       if (!ok)
+                                       {
+                                               parser.setError (Aborted,"Condition is not a string");
+                                       } else
+                                       {
+                                               u=parser.parString (ok,3);
+                                               if (!ok)
+                                               {
+                                                       parser.setError (Aborted,"Third parameter is not a string");
+                                               } else
+                                               {
+                                                       if (s!="heading")
+                                                       {
+                                                               parser.setError (Aborted,"Unknown type: "+s);
+                                                       } else
+                                                       {
+                                                               if (! (t=="eq") ) 
+                                                               {
+                                                                       parser.setError (Aborted,"Unknown operator: "+t);
+                                                               } else
+                                                               {
+                                                                       if (! selb    )
+                                                                       {
+                                                                               parser.setError (Aborted,"Type of selection is not a branch");
+                                                                       } else
+                                                                       {
+                                                                               if (selb->getHeading() == u)
+                                                                               {
+                                                                                       cout << "PASSED: " << qPrintable (c)  << endl;
+                                                                               } else
+                                                                               {
+                                                                                       cout << "FAILED: " << qPrintable (c)  << endl;
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               } 
+                                       } 
+                               } 
+                       }
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="saveImage")
+       {
+               FloatImageObj *fio=xelection.getFloatImage();
+               if (!fio)
+               {
+                       parser.setError (Aborted,"Type of selection is not an image");
+               } else if (parser.checkParCount(2))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok)
+                       {
+                               t=parser.parString(ok,1);
+                               if (ok) saveFloatImageInt (fio,t,s);
+                       }
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="scroll")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       if (!scrollBranch (selb))       
+                               parser.setError (Aborted,"Could not scroll branch");
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="select")
+       {
+               if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) select (s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="selectLastBranch")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       BranchObj *bo=selb->getLastBranch();
+                       if (!bo)
+                               parser.setError (Aborted,"Could not select last branch");
+                       selectInt (bo); 
+                               
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="selectLastImage")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       FloatImageObj *fio=selb->getLastFloatImage();
+                       if (!fio)
+                               parser.setError (Aborted,"Could not select last image");
+                       selectInt (fio);        
+                               
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="selectLatestAdded")
+       {
+               if (latestSelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"No latest added object");
+               } else
+               {       
+                       if (!select (latestSelection))
+                               parser.setError (Aborted,"Could not select latest added object "+latestSelection);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setFrameType")
+       {
+               if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
+               {
+                       parser.setError (Aborted,"Type of selection does not allow setting frame type");
+               }
+               else if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) setFrameType (s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setFramePenColor")
+       {
+               if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
+               {
+                       parser.setError (Aborted,"Type of selection does not allow setting of pen color");
+               }
+               else if (parser.checkParCount(1))
+               {
+                       QColor c=parser.parColor(ok,0);
+                       if (ok) setFramePenColor (c);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setFrameBrushColor")
+       {
+               if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
+               {
+                       parser.setError (Aborted,"Type of selection does not allow setting brush color");
+               }
+               else if (parser.checkParCount(1))
+               {
+                       QColor c=parser.parColor(ok,0);
+                       if (ok) setFrameBrushColor (c);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setFramePadding")
+       {
+               if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
+               {
+                       parser.setError (Aborted,"Type of selection does not allow setting frame padding");
+               }
+               else if (parser.checkParCount(1))
+               {
+                       n=parser.parInt(ok,0);
+                       if (ok) setFramePadding(n);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setFrameBorderWidth")
+       {
+               if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
+               {
+                       parser.setError (Aborted,"Type of selection does not allow setting frame border width");
+               }
+               else if (parser.checkParCount(1))
+               {
+                       n=parser.parInt(ok,0);
+                       if (ok) setFrameBorderWidth (n);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setMapAuthor")
+       {
+               if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) setMapAuthor (s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setMapComment")
+       {
+               if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) setMapComment(s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setMapBackgroundColor")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! xelection.getBranch() )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       QColor c=parser.parColor (ok,0);
+                       if (ok) setMapBackgroundColor (c);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setMapDefLinkColor")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       QColor c=parser.parColor (ok,0);
+                       if (ok) setMapDefLinkColor (c);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setMapLinkStyle")
+       {
+               if (parser.checkParCount(1))
+               {
+                       s=parser.parString (ok,0);
+                       if (ok) setMapLinkStyle(s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setHeading")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString (ok,0);
+                       if (ok) 
+                               setHeading (s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setHideExport")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (xelection.type()!=Selection::Branch && xelection.type() != Selection::MapCenter &&xelection.type()!=Selection::FloatImage)
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch or floatimage");
+               } else if (parser.checkParCount(1))
+               {
+                       b=parser.parBool(ok,0);
+                       if (ok) setHideExport (b);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setIncludeImagesHorizontally")
+       { 
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb)
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       b=parser.parBool(ok,0);
+                       if (ok) setIncludeImagesHor(b);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setIncludeImagesVertically")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb)
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       b=parser.parBool(ok,0);
+                       if (ok) setIncludeImagesVer(b);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setHideLinkUnselected")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if ( xelection.type()!=Selection::Branch && xelection.type()!= Selection::MapCenter && xelection.type()!=Selection::FloatImage)
+               {                                 
+                       parser.setError (Aborted,"Type of selection does not allow hiding the link");
+               } else if (parser.checkParCount(1))
+               {
+                       b=parser.parBool(ok,0);
+                       if (ok) setHideLinkUnselected(b);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setSelectionColor")
+       {
+               if (parser.checkParCount(1))
+               {
+                       QColor c=parser.parColor (ok,0);
+                       if (ok) setSelectionColorInt (c);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setURL")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString (ok,0);
+                       if (ok) setURL(s);
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setVymLink")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString (ok,0);
+                       if (ok) setVymLinkInt(s);
+               }       
+       }
+       /////////////////////////////////////////////////////////////////////
+       else if (com=="setFlag")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) 
+                       {
+                               selb->activateStandardFlag(s);
+                               selb->updateFlagsToolbar();
+                       }       
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="setFrameType")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) 
+                               setFrameType (s);
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="sortChildren")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {
+                       sortChildren();
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="toggleFlag")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) 
+                       {
+                               selb->toggleStandardFlag(s);    
+                               selb->updateFlagsToolbar();
+                       }       
+               }
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="unscroll")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       if (!unscrollBranch (selb))     
+                               parser.setError (Aborted,"Could not unscroll branch");
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="unscrollChilds")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(0))
+               {       
+                       unscrollChilds ();
+               }       
+       /////////////////////////////////////////////////////////////////////
+       } else if (com=="unsetFlag")
+       {
+               if (xelection.isEmpty() )
+               {
+                       parser.setError (Aborted,"Nothing selected");
+               } else if (! selb )
+               {                                 
+                       parser.setError (Aborted,"Type of selection is not a branch");
+               } else if (parser.checkParCount(1))
+               {
+                       s=parser.parString(ok,0);
+                       if (ok) 
+                       {
+                               selb->deactivateStandardFlag(s);
+                               selb->updateFlagsToolbar();
+                       }       
+               }
+       } else
+               parser.setError (Aborted,"Unknown command");
+
+       // Any errors?
+       if (parser.errorLevel()==NoError)
+       {
+               // setChanged();  FIXME should not be called e.g. for export?!
+               model->reposition();
+       }       
+       else    
+       {
+               // TODO Error handling
+               qWarning("MapEditor::parseAtom: Error!");
+               qWarning(parser.errorMessage());
+       } 
+}
+
+void MapEditor::runScript (QString script)
+{
+       parser.setScript (script);
+       parser.runScript();
+       while (parser.next() ) 
+               parseAtom(parser.getAtom());
+}
+
+bool MapEditor::isDefault()
+{
+    return mapDefault;
+}
+
+bool MapEditor::hasChanged()
+{
+    return mapChanged;
+}
+
+void MapEditor::setChanged()
+{
+       if (!mapChanged)
+               autosaveTimer->start(settings.value("/mapeditor/autosave/ms/",300000).toInt());
+       mapChanged=true;
+       mapDefault=false;
+       mapUnsaved=true;
+       findReset();
+
+}
+
+void MapEditor::closeMap()
+{
+       // Unselect before disabling the toolbar actions
+       if (!xelection.isEmpty() ) xelection.unselect();
+       xelection.clear();
+       updateActions();
+
+    clear();
+       // close();  FIXME needed?
+}
+
+void MapEditor::setFilePath(QString fpath, QString destname)
+{
+       if (fpath.isEmpty() || fpath=="")
+       {
+               filePath="";
+               fileName="";
+               destPath="";
+       } else
+       {
+               filePath=fpath;         // becomes absolute path
+               fileName=fpath;         // gets stripped of path
+               destPath=destname;      // needed for vymlinks and during load to reset fileChangedTime
+
+               // If fpath is not an absolute path, complete it
+               filePath=QDir(fpath).absPath();
+               fileDir=filePath.left (1+filePath.findRev ("/"));
+
+               // Set short name, too. Search from behind:
+               int i=fileName.findRev("/");
+               if (i>=0) fileName=fileName.remove (0,i+1);
+
+               // Forget the .vym (or .xml) for name of map
+               mapName=fileName.left(fileName.findRev(".",-1,true) );
+       }
+}
+
+void MapEditor::setFilePath(QString fpath)
+{
+       setFilePath (fpath,fpath);
+}
+
+QString MapEditor::getFilePath()
+{
+       return filePath;
+}
+
+QString MapEditor::getFileName()
+{
+       return fileName;
+}
+
+QString MapEditor::getMapName()
+{
+       return mapName;
+}
+
+QString MapEditor::getDestPath()
+{
+       return destPath;
+}
+
+ErrorCode MapEditor::load (QString fname, const LoadMode &lmode, const FileType &ftype)
+{
+       ErrorCode err=success;
+
+       parseBaseHandler *handler;
+       fileType=ftype;
+       switch (fileType)
+       {
+               case VymMap: handler=new parseVYMHandler; break;
+               case FreemindMap : handler=new parseFreemindHandler; break;
+               default: 
+                       QMessageBox::critical( 0, tr( "Critical Parse Error" ),
+                                  "Unknown FileType in MapEditor::load()");
+               return aborted; 
+       }
+       if (lmode==NewMap)
+       {
+               xelection.clear();
+               model->setMapEditor(this);
+               // (map state is set later at end of load...)
+       } else
+       {
+               BranchObj *bo=xelection.getBranch();
+               if (!bo) return aborted;
+               if (lmode==ImportAdd)
+                       saveStateChangingPart(
+                               bo,
+                               bo,
+                               QString("addMapInsert (%1)").arg(fname),
+                               QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
+               else    
+                       saveStateChangingPart(
+                               bo,
+                               bo,
+                               QString("addMapReplace(%1)").arg(fname),
+                               QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
+       }       
+    
+
+       // Create temporary directory for packing
+       bool ok;
+       QString tmpZipDir=makeTmpDir (ok,"vym-pack");
+       if (!ok)
+       {
+               QMessageBox::critical( 0, tr( "Critical Load Error" ),
+                  tr("Couldn't create temporary directory before load\n"));
+               return aborted; 
+       }
+
+       // Try to unzip file
+       err=unzipDir (tmpZipDir,fname);
+       QString xmlfile;
+       if (err==nozip)
+       {
+               xmlfile=fname;
+               zipped=false;
+       } else
+       {
+               zipped=true;
+               
+               // Look for mapname.xml
+               xmlfile= fname.left(fname.findRev(".",-1,true));
+               xmlfile=xmlfile.section( '/', -1 );
+               QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
+               if (!mfile.exists() )
+               {
+                       // mapname.xml does not exist, well, 
+                       // maybe someone renamed the mapname.vym file...
+                       // Try to find any .xml in the toplevel 
+                       // directory of the .vym file
+                       QStringList flist=QDir (tmpZipDir).entryList("*.xml");
+                       if (flist.count()==1) 
+                       {
+                               // Only one entry, take this one
+                               xmlfile=tmpZipDir + "/"+flist.first();
+                       } else
+                       {
+                               for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it ) 
+                                       *it=tmpZipDir + "/" + *it;
+                               // TODO Multiple entries, load all (but only the first one into this ME)
+                               //mainWindow->fileLoadFromTmp (flist);
+                               //returnCode=1; // Silently forget this attempt to load
+                               qWarning ("MainWindow::load (fn)  multimap found...");
+                       }       
+                               
+                       if (flist.isEmpty() )
+                       {
+                               QMessageBox::critical( 0, tr( "Critical Load Error" ),
+                                                  tr("Couldn't find a map (*.xml) in .vym archive.\n"));
+                               err=aborted;                               
+                       }       
+               } //file doesn't exist  
+               else
+                       xmlfile=mfile.name();
+       }
+
+       QFile file( xmlfile);
+
+       // I am paranoid: file should exist anyway
+       // according to check in mainwindow.
+       if (!file.exists() )
+       {
+               QMessageBox::critical( 0, tr( "Critical Parse Error" ),
+                                  tr(QString("Couldn't open map %1").arg(file.name())));
+               err=aborted;    
+       } else
+       {
+               bool blockSaveStateOrg=blockSaveState;
+               blockReposition=true;
+               blockSaveState=true;
+               QXmlInputSource source( file);
+               QXmlSimpleReader reader;
+               reader.setContentHandler( handler );
+               reader.setErrorHandler( handler );
+               handler->setModel ( model);
+
+
+               // We need to set the tmpDir in order  to load files with rel. path
+               QString tmpdir;
+               if (zipped)
+                       tmpdir=tmpZipDir;
+               else
+                       tmpdir=fname.left(fname.findRev("/",-1));       
+               handler->setTmpDir (tmpdir);
+               handler->setInputFile (file.name());
+               handler->setLoadMode (lmode);
+               bool ok = reader.parse( source );
+               blockReposition=false;
+               blockSaveState=blockSaveStateOrg;
+               file.close();
+               if ( ok ) 
+               {
+                       model->reposition();    // FIXME reposition the view instead...
+                       xelection.update();
+                       if (lmode==NewMap)
+                       {
+                               mapDefault=false;
+                               mapChanged=false;
+                               mapUnsaved=false;
+                               autosaveTimer->stop();
+                       }
+
+                       // Reset timestamp to check for later updates of file
+                       fileChangedTime=QFileInfo (destPath).lastModified();
+               } else 
+               {
+                       QMessageBox::critical( 0, tr( "Critical Parse Error" ),
+                                          tr( handler->errorProtocol() ) );
+                       // returnCode=1;        
+                       // Still return "success": the map maybe at least
+                       // partially read by the parser
+               }       
+       }       
+
+       // Delete tmpZipDir
+       removeDir (QDir(tmpZipDir));
+
+       updateActions();
+
+       return err;
+}
+
+ErrorCode MapEditor::save (const SaveMode &savemode)
+{
+       QString tmpZipDir;
+       QString mapFileName;
+       QString safeFilePath;
+
+       ErrorCode err=success;
+
+       if (zipped)
+               // save as .xml
+               mapFileName=mapName+".xml";
+       else
+               // use name given by user, even if he chooses .doc
+               mapFileName=fileName;
+
+       // Look, if we should zip the data:
+       if (!zipped)
+       {
+               QMessageBox mb( vymName,
+                       tr("The map %1\ndid not use the compressed "
+                       "vym file format.\nWriting it uncompressed will also write images \n"
+                       "and flags and thus may overwrite files in the "
+                       "given directory\n\nDo you want to write the map").arg(filePath),
+                       QMessageBox::Warning,
+                       QMessageBox::Yes | QMessageBox::Default,
+                       QMessageBox::No ,
+                       QMessageBox::Cancel | QMessageBox::Escape);
+               mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
+               mb.setButtonText( QMessageBox::No, tr("uncompressed") );
+               mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
+               switch( mb.exec() ) 
+               {
+                       case QMessageBox::Yes:
+                               // save compressed (default file format)
+                               zipped=true;
+                               break;
+                       case QMessageBox::No:
+                               // save uncompressed
+                               zipped=false;
+                               break;
+                       case QMessageBox::Cancel:
+                               // do nothing
+                               return aborted;
+                               break;
+               }
+       }
+
+       // First backup existing file, we 
+       // don't want to add to old zip archives
+       QFile f(destPath);
+       if (f.exists())
+       {
+               if ( settings.value ("/mapeditor/writeBackupFile").toBool())
+               {
+                       QString backupFileName(destPath + "~");
+                       QFile backupFile(backupFileName);
+                       if (backupFile.exists() && !backupFile.remove())
+                       {
+                               QMessageBox::warning(0, tr("Save Error"),
+                                                                        tr("%1\ncould not be removed before saving").arg(backupFileName));
+                       }
+                       else if (!f.rename(backupFileName))
+                       {
+                               QMessageBox::warning(0, tr("Save Error"),
+                                                                        tr("%1\ncould not be renamed before saving").arg(destPath));
+                       }
+               }
+       }
+
+       if (zipped)
+       {
+               // Create temporary directory for packing
+               bool ok;
+               tmpZipDir=makeTmpDir (ok,"vym-zip");
+               if (!ok)
+               {
+                       QMessageBox::critical( 0, tr( "Critical Load Error" ),
+                          tr("Couldn't create temporary directory before save\n"));
+                       return aborted; 
+               }
+
+               safeFilePath=filePath;
+               setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
+       } // zipped
+
+       // Create mapName and fileDir
+       makeSubDirs (fileDir);
+
+       QString saveFile;
+       if (savemode==CompleteMap || xelection.isEmpty())
+       {
+               // Save complete map
+               saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),NULL);
+               mapChanged=false;
+               mapUnsaved=false;
+               autosaveTimer->stop();
+       }
+       else    
+       {
+               // Save part of map
+               if (xelection.type()==Selection::FloatImage)
+                       saveFloatImage();
+               else    
+                       saveFile=saveToDir (fileDir,mapName+"-",true,QPointF(),xelection.getBranch());  
+               // TODO take care of multiselections
+       }       
+
+       if (!saveStringToDisk(fileDir+mapFileName,saveFile))
+       {
+               err=aborted;
+               qWarning ("ME::saveStringToDisk failed!");
+       }
+
+       if (zipped)
+       {
+               // zip
+               if (err==success) err=zipDir (tmpZipDir,destPath);
+
+               // Delete tmpDir
+               removeDir (QDir(tmpZipDir));
+
+               // Restore original filepath outside of tmp zip dir
+               setFilePath (safeFilePath);
+       }
+
+       updateActions();
+       fileChangedTime=QFileInfo (destPath).lastModified();
+       return err;
+}
+
+
+void MapEditor::print()
+{
+}
+
+void MapEditor::setAntiAlias (bool b)
+{
+       setRenderHint(QPainter::Antialiasing,b);
+}
+
+void MapEditor::setSmoothPixmap(bool b)
+{
+       setRenderHint(QPainter::SmoothPixmapTransform,b);
+}
+
+QPixmap MapEditor::getPixmap()
+{
+       QRectF mapRect=model->getTotalBBox();
+       QPixmap pix((int)mapRect.width()+2,(int)mapRect.height()+1);
+       QPainter pp (&pix);
+       
+       pp.setRenderHints(renderHints());
+
+       // Don't print the visualisation of selection
+       xelection.unselect();
+
+       mapScene->render (      &pp, 
+               QRectF(0,0,mapRect.width()+1,mapRect.height()+1),
+               QRectF(mapRect.x(),mapRect.y(),mapRect.width(),mapRect.height() ));
+
+       // Restore selection
+       xelection.reselect();
+       
+       return pix;
+}
+
+void MapEditor::setHideTmpMode (HideTmpMode mode)
+{
+       hidemode=mode;
+       model->setHideTmp (hidemode);
+       model->reposition();
+       scene()->update();
+}
+
+HideTmpMode MapEditor::getHideTmpMode()
+{
+       return hidemode;
+}
+
+void MapEditor::setExportMode (bool b)
+{
+       // should be called before and after exports
+       // depending on the settings
+       if (b && settings.value("/export/useHideExport","true")=="true")
+               setHideTmpMode (HideExport);
+       else    
+               setHideTmpMode (HideNone);
+}
+
+void MapEditor::exportASCII(QString fname,bool askName)
+{
+       ExportASCII ex;
+       ex.setModel (model);
+       if (fname=="") 
+               ex.setFile (mapName+".txt");    
+       else
+               ex.setFile (fname);
+
+       if (askName)
+       {
+               //ex.addFilter ("TXT (*.txt)");
+               ex.setDir(lastImageDir);
+               //ex.setCaption(vymName+ " -" +tr("Export as ASCII")+" "+tr("(still experimental)"));
+               ex.execDialog() ; 
+       } 
+       if (!ex.canceled())
+       {
+               setExportMode(true);
+               ex.doExport();
+               setExportMode(false);
+       }
+}
+
+void MapEditor::exportImage(QString fname, bool askName, QString format)
+{
+       if (fname=="")
+       {
+               fname=mapName+".png";
+               format="PNG";
+       }       
+
+       if (askName)
+       {
+               QStringList fl;
+               QFileDialog *fd=new QFileDialog (this);
+               fd->setCaption (tr("Export map as image"));
+               fd->setDirectory (lastImageDir);
+               fd->setFileMode(QFileDialog::AnyFile);
+               fd->setFilters  (imageIO.getFilters() );
+               if (fd->exec())
+               {
+                       fl=fd->selectedFiles();
+                       fname=fl.first();
+                       format=imageIO.getType(fd->selectedFilter());
+               } 
+       }
+
+       setExportMode (true);
+       QPixmap pix (getPixmap());
+       pix.save(fname, format);
+       setExportMode (false);
+}
+
+void MapEditor::exportOOPresentation(const QString &fn, const QString &cf)
+{
+       ExportOO ex;
+       ex.setFile (fn);
+       ex.setModel (model);
+       if (ex.setConfigFile(cf)) 
+       {
+               setExportMode (true);
+               ex.exportPresentation();
+               setExportMode (false);
+       }
+}
+
+void MapEditor::exportXHTML (const QString &dir, bool askForName)
+{
+                       ExportXHTMLDialog dia(this);
+                       dia.setFilePath (filePath );
+                       dia.setMapName (mapName );
+                       dia.readSettings();
+                       if (dir!="") dia.setDir (dir);
+
+                       bool ok=true;
+                       
+                       if (askForName)
+                       {
+                               if (dia.exec()!=QDialog::Accepted) 
+                                       ok=false;
+                               else    
+                               {
+                                       QDir d (dia.getDir());
+                                       // Check, if warnings should be used before overwriting
+                                       // the output directory
+                                       if (d.exists() && d.count()>0)
+                                       {
+                                               WarningDialog warn;
+                                               warn.showCancelButton (true);
+                                               warn.setText(QString(
+                                                       "The directory %1 is not empty.\n"
+                                                       "Do you risk to overwrite some of its contents?").arg(d.path() ));
+                                               warn.setCaption("Warning: Directory not empty");
+                                               warn.setShowAgainName("mainwindow/overwrite-dir-xhtml");
+
+                                               if (warn.exec()!=QDialog::Accepted) ok=false;
+                                       }
+                               }       
+                       }
+
+                       if (ok)
+                       {
+                               exportXML (dia.getDir(),false );
+                               dia.doExport(mapName );
+                               //if (dia.hasChanged()) setChanged();
+                       }
+}
+
+void MapEditor::exportXML(QString dir, bool askForName)
+{
+       if (askForName)
+       {
+               dir=browseDirectory(this,tr("Export XML to directory"));
+               if (dir =="" && !reallyWriteDirectory(dir) )
+               return;
+       }
+
+       // Hide stuff during export, if settings want this
+       setExportMode (true);
+
+       // Create subdirectories
+       makeSubDirs (dir);
+
+       // write to directory
+       QString saveFile=saveToDir (dir,mapName+"-",true,model->getTotalBBox().topLeft() ,NULL);
+       QFile file;
+
+       file.setName ( dir + "/"+mapName+".xml");
+       if ( !file.open( QIODevice::WriteOnly ) )
+       {
+               // This should neverever happen
+               QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open %1").arg(file.name()));
+               return;
+       }       
+
+       // Write it finally, and write in UTF8, no matter what 
+       QTextStream ts( &file );
+       ts.setEncoding (QTextStream::UnicodeUTF8);
+       ts << saveFile;
+       file.close();
+
+       // Now write image, too
+       exportImage (dir+"/images/"+mapName+".png",false,"PNG");
+
+       setExportMode (false);
+}
+
+void MapEditor::clear()
+{
+       xelection.unselect();
+       model->clear();
+}
+
+void MapEditor::copy()
+{
+       LinkableMapObj *sel=xelection.single();
+       if (sel)
+       {
+               if (redosAvail == 0)
+               {
+                       // Copy to history
+                       QString s=model->getSelectString(sel);
+                       saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy selection to clipboard",sel  );
+                       curClipboard=curStep;
+               }
+
+               // Copy also to global clipboard, because we are at last step in history
+               QString bakMapName(QString("history-%1").arg(curStep));
+               QString bakMapDir(tmpMapDir +"/"+bakMapName);
+               copyDir (bakMapDir,clipboardDir );
+
+               clipboardEmpty=false;
+               updateActions();
+       }           
+}
+
+void MapEditor::redo()
+{
+       // Can we undo at all?
+       if (redosAvail<1) return;
+
+       bool blockSaveStateOrg=blockSaveState;
+       blockSaveState=true;
+       
+       redosAvail--;
+
+       if (undosAvail<stepsTotal) undosAvail++;
+       curStep++;
+       if (curStep>stepsTotal) curStep=1;
+       QString undoCommand=  undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
+       QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
+       QString redoCommand=  undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
+       QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
+       QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
+       QString version=undoSet.readEntry ("/history/version");
+
+       /* TODO Maybe check for version, if we save the history
+       if (!checkVersion(version))
+               QMessageBox::warning(0,tr("Warning"),
+                       tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
+       */ 
+
+       // Find out current undo directory
+       QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
+
+       if (debug)
+       {
+               cout << "ME::redo() begin\n";
+               cout << "    undosAvail="<<undosAvail<<endl;
+               cout << "    redosAvail="<<redosAvail<<endl;
+               cout << "       curStep="<<curStep<<endl;
+               cout << "    ---------------------------"<<endl;
+               cout << "    comment="<<comment.toStdString()<<endl;
+               cout << "    undoCom="<<undoCommand.toStdString()<<endl;
+               cout << "    undoSel="<<undoSelection.toStdString()<<endl;
+               cout << "    redoCom="<<redoCommand.toStdString()<<endl;
+               cout << "    redoSel="<<redoSelection.toStdString()<<endl;
+               cout << "    ---------------------------"<<endl<<endl;
+       }
+
+       // select  object before redo
+       if (!redoSelection.isEmpty())
+               select (redoSelection);
+
+
+       parseAtom (redoCommand);
+       model->reposition();
+
+       blockSaveState=blockSaveStateOrg;
+
+       undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
+       undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
+       undoSet.setEntry ("/history/curStep",QString::number(curStep));
+       undoSet.writeSettings(histPath);
+
+       mainWindow->updateHistory (undoSet);
+       updateActions();
+
+       /* TODO remove testing
+       cout << "ME::redo() end\n";
+       cout << "    undosAvail="<<undosAvail<<endl;
+       cout << "    redosAvail="<<redosAvail<<endl;
+       cout << "       curStep="<<curStep<<endl;
+       cout << "    ---------------------------"<<endl<<endl;
+       */
+
+
+}
+
+bool MapEditor::isRedoAvailable()
+{
+       if (undoSet.readNumEntry("/history/redosAvail",0)>0)
+               return true;
+       else    
+               return false;
+}
+
+void MapEditor::undo()
+{
+       // Can we undo at all?
+       if (undosAvail<1) return;
+
+       mainWindow->statusMessage (tr("Autosave disabled during undo."));
+
+       bool blockSaveStateOrg=blockSaveState;
+       blockSaveState=true;
+       
+       QString undoCommand=  undoSet.readEntry (QString("/history/step-%1/undoCommand").arg(curStep));
+       QString undoSelection=undoSet.readEntry (QString("/history/step-%1/undoSelection").arg(curStep));
+       QString redoCommand=  undoSet.readEntry (QString("/history/step-%1/redoCommand").arg(curStep));
+       QString redoSelection=undoSet.readEntry (QString("/history/step-%1/redoSelection").arg(curStep));
+       QString comment=undoSet.readEntry (QString("/history/step-%1/comment").arg(curStep));
+       QString version=undoSet.readEntry ("/history/version");
+
+       /* TODO Maybe check for version, if we save the history
+       if (!checkVersion(version))
+               QMessageBox::warning(0,tr("Warning"),
+                       tr("Version %1 of saved undo/redo data\ndoes not match current vym version %2.").arg(version).arg(vymVersion));
+       */
+
+       // Find out current undo directory
+       QString bakMapDir(QString(tmpMapDir+"/undo-%1").arg(curStep));
+
+       // select  object before undo
+       if (!undoSelection.isEmpty())
+               select (undoSelection);
+
+       if (debug)
+       {
+               cout << "ME::undo() begin\n";
+               cout << "    undosAvail="<<undosAvail<<endl;
+               cout << "    redosAvail="<<redosAvail<<endl;
+               cout << "       curStep="<<curStep<<endl;
+               cout << "    ---------------------------"<<endl;
+               cout << "    comment="<<comment.toStdString()<<endl;
+               cout << "    undoCom="<<undoCommand.toStdString()<<endl;
+               cout << "    undoSel="<<undoSelection.toStdString()<<endl;
+               cout << "    redoCom="<<redoCommand.toStdString()<<endl;
+               cout << "    redoSel="<<redoSelection.toStdString()<<endl;
+               cout << "    ---------------------------"<<endl<<endl;
+       }       
+       parseAtom (undoCommand);
+       model->reposition();
+
+       undosAvail--;
+       curStep--; 
+       if (curStep<1) curStep=stepsTotal;
+
+       redosAvail++;
+
+       blockSaveState=blockSaveStateOrg;
+/* TODO remove testing
+       cout << "ME::undo() end\n";
+       cout << "    undosAvail="<<undosAvail<<endl;
+       cout << "    redosAvail="<<redosAvail<<endl;
+       cout << "       curStep="<<curStep<<endl;
+       cout << "    ---------------------------"<<endl<<endl;
+*/
+
+       undoSet.setEntry ("/history/undosAvail",QString::number(undosAvail));
+       undoSet.setEntry ("/history/redosAvail",QString::number(redosAvail));
+       undoSet.setEntry ("/history/curStep",QString::number(curStep));
+       undoSet.writeSettings(histPath);
+
+       mainWindow->updateHistory (undoSet);
+       updateActions();
+       xelection.update();
+       ensureSelectionVisible();
+}
+
+bool MapEditor::isUndoAvailable()
+{
+       if (undoSet.readNumEntry("/history/undosAvail",0)>0)
+               return true;
+       else    
+               return false;
+}
+
+void MapEditor::gotoHistoryStep (int i)
+{
+       // Restore variables
+       int undosAvail=undoSet.readNumEntry (QString("/history/undosAvail"));
+       int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
+
+       if (i<0) i=undosAvail+redosAvail;
+
+       // Clicking above current step makes us undo things
+       if (i<undosAvail) 
+       {       
+               for (int j=0; j<undosAvail-i; j++) undo();
+               return;
+       }       
+       // Clicking below current step makes us redo things
+       if (i>undosAvail) 
+               for (int j=undosAvail; j<i; j++) 
+               {
+                       if (debug) cout << "ME::gotoHistoryStep redo "<<j<<"/"<<undosAvail<<" i="<<i<<endl;
+                       redo();
+               }
+
+       // And ignore clicking the current row ;-)      
+}
+
+void MapEditor::addMapReplaceInt(const QString &undoSel, const QString &path)
+{
+       QString pathDir=path.left(path.findRev("/"));
+       QDir d(pathDir);
+       QFile file (path);
+
+       if (d.exists() )
+       {
+               // We need to parse saved XML data
+               parseVYMHandler handler;
+               QXmlInputSource source( file);
+               QXmlSimpleReader reader;
+               reader.setContentHandler( &handler );
+               reader.setErrorHandler( &handler );
+               handler.setModel ( model);
+               handler.setTmpDir ( pathDir );  // needed to load files with rel. path
+               if (undoSel.isEmpty())
+               {
+                       unselect();
+                       model->clear();
+                       handler.setLoadMode (NewMap);
+               } else  
+               {
+                       select (undoSel);
+                       handler.setLoadMode (ImportReplace);
+               }       
+               blockReposition=true;
+               bool ok = reader.parse( source );
+               blockReposition=false;
+               if (! ok ) 
+               {       
+                       // This should never ever happen
+                       QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
+                                                                   handler.errorProtocol());
+               }
+       } else  
+               QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
+}
+
+void MapEditor::addMapInsertInt (const QString &path, int pos)
+{
+       BranchObj *sel=xelection.getBranch();
+       if (sel)
+       {
+               QString pathDir=path.left(path.findRev("/"));
+               QDir d(pathDir);
+               QFile file (path);
+
+               if (d.exists() )
+               {
+                       // We need to parse saved XML data
+                       parseVYMHandler handler;
+                       QXmlInputSource source( file);
+                       QXmlSimpleReader reader;
+                       reader.setContentHandler( &handler );
+                       reader.setErrorHandler( &handler );
+                       handler.setModel (model);
+                       handler.setTmpDir ( pathDir );  // needed to load files with rel. path
+                       handler.setLoadMode (ImportAdd);
+                       blockReposition=true;
+                       bool ok = reader.parse( source );
+                       blockReposition=false;
+                       if (! ok ) 
+                       {       
+                               // This should never ever happen
+                               QMessageBox::critical( 0, tr( "Critical Parse Error while reading %1").arg(path),
+                                                                               handler.errorProtocol());
+                       }
+                       if (sel->getDepth()>0)
+                               sel->getLastBranch()->linkTo (sel,pos);
+               } else  
+                       QMessageBox::critical( 0, tr( "Critical Error" ), tr("Could not read %1").arg(path));
+       }               
+}
+
+void MapEditor::pasteNoSave(const int &n)
+{
+       bool old=blockSaveState;
+       blockSaveState=true;
+       bool zippedOrg=zipped;
+       if (redosAvail > 0 || n!=0)
+       {
+               // Use the "historical" buffer
+               QString bakMapName(QString("history-%1").arg(n));
+               QString bakMapDir(tmpMapDir +"/"+bakMapName);
+               load (bakMapDir+"/"+clipboardFile,ImportAdd, VymMap);
+       } else
+               // Use the global buffer
+               load (clipboardDir+"/"+clipboardFile,ImportAdd, VymMap);
+       zipped=zippedOrg;
+       blockSaveState=old;
+}
+
+void MapEditor::paste()                
+{   
+       BranchObj *sel=xelection.getBranch();
+       if (sel)
+       {
+               saveStateChangingPart(
+                       sel,
+                       sel,
+                       QString ("paste (%1)").arg(curClipboard),
+                       QString("Paste to %1").arg( getName(sel))
+               );
+               pasteNoSave(0);
+               model->reposition();
+       }
+}
+
+void MapEditor::cut()
+{
+       LinkableMapObj *sel=xelection.single();
+       if ( sel && (xelection.type() == Selection::Branch ||
+               xelection.type()==Selection::MapCenter ||
+               xelection.type()==Selection::FloatImage))
+       {
+       /* No savestate! savestate is called in cutNoSave
+               saveStateChangingPart(
+                       sel->getParObj(),
+                       sel,
+                       "cut ()",
+                       QString("Cut %1").arg(getName(sel ))
+               );
+       */      
+               copy();
+               deleteSelection();
+               model->reposition();
+       }
+}
+
+void MapEditor::move(const double &x, const double &y)
+{
+       LinkableMapObj *sel=xelection.single();
+       if (sel)
+       {
+        QPointF ap(sel->getAbsPos());
+        QPointF to(x, y);
+        if (ap != to)
+        {
+            QString ps=qpointfToString(ap);
+            QString s=xelection.getSelectString();
+            saveState(
+                s, "move "+ps, 
+                s, "move "+qpointfToString(to), 
+                QString("Move %1 to %2").arg(getName(sel)).arg(ps));
+            sel->move(x,y);
+            model->reposition();
+            xelection.update();
+        }
+       }
+}
+
+void MapEditor::moveRel (const double &x, const double &y)
+{
+       LinkableMapObj *sel=xelection.single();
+       if (sel)
+       {
+        QPointF rp(sel->getRelPos());
+        QPointF to(x, y);
+        if (rp != to)
+        {
+            QString ps=qpointfToString (sel->getRelPos());
+            QString s=model->getSelectString(sel);
+            saveState(
+                s, "moveRel "+ps, 
+                s, "moveRel "+qpointfToString(to), 
+                QString("Move %1 to relative position %2").arg(getName(sel)).arg(ps));
+            ((OrnamentedObj*)sel)->move2RelPos (x,y);
+            model->reposition();
+            sel->updateLink();
+            xelection.update();
+        }
+       }
+}
+
+void MapEditor::moveBranchUp()
+{
+       BranchObj* bo=xelection.getBranch();
+       BranchObj* par;
+       if (bo)
+       {
+               if (!bo->canMoveBranchUp()) return;
+               par=(BranchObj*)(bo->getParObj());
+               BranchObj *obo=par->moveBranchUp (bo);  // bo will be the one below selection
+               saveState (model->getSelectString(bo),"moveBranchDown ()",model->getSelectString(obo),"moveBranchUp ()",QString("Move up %1").arg(getName(bo)));
+               model->reposition();
+               scene()->update();
+               xelection.update();
+               ensureSelectionVisible();
+       }
+}
+
+void MapEditor::moveBranchDown()
+{
+       BranchObj* bo=xelection.getBranch();
+       BranchObj* par;
+       if (bo)
+       {
+               if (!bo->canMoveBranchDown()) return;
+               par=(BranchObj*)(bo->getParObj());
+               BranchObj *obo=par->moveBranchDown(bo); // bo will be the one above selection
+               saveState(model->getSelectString(bo),"moveBranchUp ()",model->getSelectString(obo),"moveBranchDown ()",QString("Move down %1").arg(getName(bo)));
+               model->reposition();
+               scene()->update();
+               xelection.update();
+               ensureSelectionVisible();
+       }       
+}
+
+void MapEditor::sortChildren()
+{
+       BranchObj* bo=xelection.getBranch();
+       if (bo)
+       {
+               if(bo->countBranches()>1)
+               {
+                       saveStateChangingPart(bo,bo, "sortChildren ()",QString("Sort children of %1").arg(getName(bo)));
+                       bo->sortChildren();
+                       model->reposition();
+                       ensureSelectionVisible();
+               }
+       }
+}
+
+void MapEditor::linkTo(const QString &dstString)       
+{
+       FloatImageObj *fio=xelection.getFloatImage();
+       if (fio)
+       {
+               BranchObj *dst=(BranchObj*)(model->findObjBySelect(dstString));
+               if (dst && (typeid(*dst)==typeid (BranchObj) || 
+                                       typeid(*dst)==typeid (MapCenterObj)))
+               {                       
+                       LinkableMapObj *dstPar=dst->getParObj();
+                       QString parString=model->getSelectString(dstPar);
+                       QString fioPreSelectString=model->getSelectString(fio);
+                       QString fioPreParentSelectString=model->getSelectString (fio->getParObj());
+                       ((BranchObj*)(dst))->addFloatImage (fio);
+                       xelection.unselect();
+                       ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio);
+                       fio=((BranchObj*)(dst))->getLastFloatImage();
+                       fio->setRelPos();
+                       fio->reposition();
+                       xelection.select(fio);
+                       saveState(
+                               model->getSelectString(fio),
+                               QString("linkTo (\"%1\")").arg(fioPreParentSelectString), 
+                               fioPreSelectString, 
+                               QString ("linkTo (\"%1\")").arg(dstString),
+                               QString ("Link floatimage to %1").arg(getName(dst)));
+               }
+       }
+}
+
+QString MapEditor::getHeading(bool &ok, QPoint &p)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               ok=true;
+               p=mapFromScene(bo->getAbsPos());
+               return bo->getHeading();
+       }
+       ok=false;
+       return QString();
+}
+
+void MapEditor::setHeading(const QString &s)
+{
+       BranchObj *sel=xelection.getBranch();
+       if (sel)
+       {
+               saveState(
+                       sel,
+                       "setHeading (\""+sel->getHeading()+"\")", 
+                       sel,
+                       "setHeading (\""+s+"\")", 
+                       QString("Set heading of %1 to \"%2\"").arg(getName(sel)).arg(s) );
+               sel->setHeading(s );
+               model->reposition();
+               xelection.update();
+               ensureSelectionVisible();
+       }
+}
+
+void MapEditor::setHeadingInt(const QString &s)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               bo->setHeading(s);
+               model->reposition();
+               xelection.update();
+               ensureSelectionVisible();
+       }
+}
+
+void MapEditor::setVymLinkInt (const QString &s)
+{
+       // Internal function, no saveState needed
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               bo->setVymLink(s);
+               model->reposition();
+               updateActions();
+               xelection.update();
+               ensureSelectionVisible();
+       }
+}
+
+BranchObj* MapEditor::addMapCenter ()
+{
+       MapCenterObj *mco= model->addMapCenter(contextMenuPos);
+       xelection.select (mco);
+       updateActions();
+       ensureSelectionVisible();
+       saveState (
+               mco,
+               "delete()",
+               NULL,
+               QString ("addMapCenter (%1,%2)").arg (contextMenuPos.x()).arg(contextMenuPos.y()),
+               QString ("Adding MapCenter to (%1,%2").arg (contextMenuPos.x()).arg(contextMenuPos.y())
+       );      
+       return mco;     
+}
+
+BranchObj* MapEditor::addNewBranchInt(int num)
+{
+       // Depending on pos:
+       // -3           insert in childs of parent  above selection 
+       // -2           add branch to selection 
+       // -1           insert in childs of parent below selection 
+       // 0..n         insert in childs of parent at pos
+       BranchObj *newbo=NULL;
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               if (num==-2)
+               {
+                       // save scroll state. If scrolled, automatically select
+                       // new branch in order to tmp unscroll parent...
+                       newbo=bo->addBranch();
+                       
+               }else if (num==-1)
+               {
+                       num=bo->getNum()+1;
+                       bo=(BranchObj*)bo->getParObj();
+                       if (bo) newbo=bo->insertBranch(num);
+               }else if (num==-3)
+               {
+                       num=bo->getNum();
+                       bo=(BranchObj*)bo->getParObj();
+                       if (bo) newbo=bo->insertBranch(num);
+               }
+               if (!newbo) return NULL;
+       }       
+       return newbo;
+}      
+
+BranchObj* MapEditor::addNewBranch(int pos)
+{
+       // Different meaning than num in addNewBranchInt!
+       // -1   add above
+       //  0   add as child
+       // +1   add below
+       BranchObj *bo = xelection.getBranch();
+       BranchObj *newbo=NULL;
+
+       if (bo)
+       {
+               setCursor (Qt::ArrowCursor);
+
+               newbo=addNewBranchInt (pos-2);
+
+               if (newbo)
+               {
+                       saveState(
+                               newbo,          
+                               "delete ()",
+                               bo,
+                               QString ("addBranch (%1)").arg(pos),
+                               QString ("Add new branch to %1").arg(getName(bo)));     
+
+                       model->reposition();
+                       xelection.update();
+                       latestSelection=model->getSelectString(newbo);
+                       // In Network mode, the client needs to know where the new branch is,
+                       // so we have to pass on this information via saveState.
+                       // TODO: Get rid of this positioning workaround
+                       QString ps=qpointfToString (newbo->getAbsPos());
+                       sendData ("selectLatestAdded ()");
+                       sendData (QString("move %1").arg(ps));
+                       sendSelection();
+               }
+       }       
+       return newbo;
+}
+
+
+BranchObj* MapEditor::addNewBranchBefore()
+{
+       BranchObj *newbo=NULL;
+       BranchObj *bo = xelection.getBranch();
+       if (bo && xelection.type()==Selection::Branch)
+                // We accept no MapCenterObj here, so we _have_ a parent
+       {
+               QPointF p=bo->getRelPos();
+
+
+               BranchObj *parbo=(BranchObj*)(bo->getParObj());
+
+               // add below selection
+               newbo=parbo->insertBranch(bo->getNum()+1);
+               if (newbo)
+               {
+                       newbo->move2RelPos (p);
+
+                       // Move selection to new branch
+                       bo->linkTo (newbo,-1);
+
+                       saveState (newbo, "deleteKeepChilds ()", newbo, "addBranchBefore ()", 
+                               QString ("Add branch before %1").arg(getName(bo)));
+
+                       model->reposition();
+                       xelection.update();
+               }
+       }       
+       latestSelection=xelection.getSelectString();
+       return newbo;
+}
+
+void MapEditor::deleteSelection()
+{
+       BranchObj *bo = xelection.getBranch();
+       if (bo && xelection.type()==Selection::MapCenter)
+       {
+       //      BranchObj* par=(BranchObj*)(bo->getParObj());
+               xelection.unselect();
+       /* FIXME Note:  does saveStateRemovingPart work for MCO? (No parent!)
+               saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
+               */
+               bo=model->removeMapCenter ((MapCenterObj*)bo);
+               if (bo) 
+               {
+                       xelection.select (bo);
+                       ensureSelectionVisible();
+                       xelection.update();
+               }       
+               model->reposition();
+               return;
+       }
+       if (bo && xelection.type()==Selection::Branch)
+       {
+               BranchObj* par=(BranchObj*)bo->getParObj();
+               xelection.unselect();
+               saveStateRemovingPart (bo, QString ("Delete %1").arg(getName(bo)));
+               par->removeBranch(bo);
+               xelection.select (par);
+               ensureSelectionVisible();
+               model->reposition();
+//             xelection.update();
+               xelection.update();
+               return;
+       }
+       FloatImageObj *fio=xelection.getFloatImage();
+       if (fio)
+       {
+               BranchObj* par=(BranchObj*)fio->getParObj();
+               saveStateChangingPart(
+                       par, 
+                       fio,
+                       "delete ()",
+                       QString("Delete %1").arg(getName(fio))
+               );
+               xelection.unselect();
+               par->removeFloatImage(fio);
+               xelection.select (par);
+               model->reposition();
+               xelection.update();
+               ensureSelectionVisible();
+               return;
+       }
+}
+
+LinkableMapObj* MapEditor::getSelection()
+{
+       return xelection.single();
+}
+
+BranchObj* MapEditor::getSelectedBranch()
+{
+       return xelection.getBranch();
+}
+
+FloatImageObj* MapEditor::getSelectedFloatImage()
+{
+       return xelection.getFloatImage();
+}
+
+void MapEditor::unselect()
+{
+       xelection.unselect();
+}      
+
+void MapEditor::reselect()
+{
+       xelection.reselect();
+}      
+
+bool MapEditor::select (const QString &s)
+{
+       if (xelection.select(s))
+       {
+               xelection.update();
+               ensureSelectionVisible();
+               sendSelection ();
+               return true;
+       }
+       return false;
+}
+
+bool MapEditor::select (LinkableMapObj *lmo)
+{
+       if (xelection.select(lmo))
+       {
+               xelection.update();
+               ensureSelectionVisible();
+               sendSelection ();
+               return true;
+       }
+       return false;
+}
+
+QString MapEditor::getSelectString()
+{
+       return xelection.getSelectString();
+}
+
+void MapEditor::selectInt (LinkableMapObj *lmo)
+{
+       if (lmo && xelection.single()!= lmo && isSelectBlocked()==false )
+       {
+               xelection.select(lmo);
+               xelection.update();
+               sendSelection ();
+       }       
+}
+
+void MapEditor::selectNextBranchInt()
+{
+       // Increase number of branch
+       LinkableMapObj *sel=xelection.single();
+       if (sel)
+       {
+               QString s=xelection.getSelectString();
+               QString part;
+               QString typ;
+               QString num;
+
+               // Where am I? 
+               part=s.section(",",-1);
+               typ=part.left (3);
+               num=part.right(part.length() - 3);
+
+               s=s.left (s.length() -num.length());
+
+               // Go to next lmo
+               num=QString ("%1").arg(num.toUInt()+1);
+
+               s=s+num;
+               
+               // Try to select this one
+               if (select (s)) return;
+
+               // We have no direct successor, 
+               // try to increase the parental number in order to
+               // find a successor with same depth
+
+               int d=xelection.single()->getDepth();
+               int oldDepth=d;
+               int i;
+               bool found=false;
+               bool b;
+               while (!found && d>0)
+               {
+                       s=s.section (",",0,d-1);
+                       // replace substring of current depth in s with "1"
+                       part=s.section(",",-1);
+                       typ=part.left (3);
+                       num=part.right(part.length() - 3);
+
+                       if (d>1)
+                       {       
+                               // increase number of parent
+                               num=QString ("%1").arg(num.toUInt()+1);
+                               s=s.section (",",0,d-2) + ","+ typ+num;
+                       } else
+                       {
+                               // Special case, look at orientation
+                               if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
+                                       num=QString ("%1").arg(num.toUInt()+1);
+                               else    
+                                       num=QString ("%1").arg(num.toUInt()-1);
+                               s=typ+num;
+                       }       
+
+                       if (select (s))
+                               // pad to oldDepth, select the first branch for each depth
+                               for (i=d;i<oldDepth;i++)
+                               {
+                                       b=select (s);
+                                       if (b)
+                                       {       
+                                               if ( xelection.getBranch()->countBranches()>0)
+                                                       s+=",bo:0";
+                                               else    
+                                                       break;
+                                       } else
+                                               break;
+                               }       
+
+                       // try to select the freshly built string
+                       found=select(s);
+                       d--;
+               }
+               return;
+       }       
+}
+
+void MapEditor::selectPrevBranchInt()
+{
+       // Decrease number of branch
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               QString s=xelection.getSelectString();
+               QString part;
+               QString typ;
+               QString num;
+
+               // Where am I? 
+               part=s.section(",",-1);
+               typ=part.left (3);
+               num=part.right(part.length() - 3);
+
+               s=s.left (s.length() -num.length());
+
+               int n=num.toInt()-1;
+               
+               // Go to next lmo
+               num=QString ("%1").arg(n);
+               s=s+num;
+               
+               // Try to select this one
+               if (n>=0 && select (s)) return;
+
+               // We have no direct precessor, 
+               // try to decrease the parental number in order to
+               // find a precessor with same depth
+
+               int d=xelection.single()->getDepth();
+               int oldDepth=d;
+               int i;
+               bool found=false;
+               bool b;
+               while (!found && d>0)
+               {
+                       s=s.section (",",0,d-1);
+                       // replace substring of current depth in s with "1"
+                       part=s.section(",",-1);
+                       typ=part.left (3);
+                       num=part.right(part.length() - 3);
+
+                       if (d>1)
+                       {
+                               // decrease number of parent
+                               num=QString ("%1").arg(num.toInt()-1);
+                               s=s.section (",",0,d-2) + ","+ typ+num;
+                       } else
+                       {
+                               // Special case, look at orientation
+                               if (xelection.single()->getOrientation()==LinkableMapObj::RightOfCenter)
+                                       num=QString ("%1").arg(num.toInt()-1);
+                               else    
+                                       num=QString ("%1").arg(num.toInt()+1);
+                               s=typ+num;
+                       }       
+
+                       if (select(s))
+                               // pad to oldDepth, select the last branch for each depth
+                               for (i=d;i<oldDepth;i++)
+                               {
+                                       b=select (s);
+                                       if (b)
+                                               if ( xelection.getBranch()->countBranches()>0)
+                                                       s+=",bo:"+ QString ("%1").arg( xelection.getBranch()->countBranches()-1 );
+                                               else    
+                                                       break;
+                                       else
+                                               break;
+                               }       
+                       
+                       // try to select the freshly built string
+                       found=select(s);
+                       d--;
+               }
+               return;
+       }       
+}
+
+void MapEditor::selectUpperBranch()
+{
+       if (isSelectBlocked() ) return;
+
+       BranchObj *bo=xelection.getBranch();
+       if (bo && xelection.type()==Selection::Branch)
+       {
+               if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
+                       selectPrevBranchInt();
+               else
+                       if (bo->getDepth()==1)
+                               selectNextBranchInt();
+                       else
+                               selectPrevBranchInt();
+       }
+}
+
+void MapEditor::selectLowerBranch()
+{
+       if (isSelectBlocked() ) return;
+
+       BranchObj *bo=xelection.getBranch();
+       if (bo && xelection.type()==Selection::Branch)
+       {
+               if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
+                       selectNextBranchInt();
+               else
+                       if (bo->getDepth()==1)
+                               selectPrevBranchInt();
+                       else
+                               selectNextBranchInt();
+       }                       
+}
+
+
+void MapEditor::selectLeftBranch()
+{
+       if (isSelectBlocked() ) return;
+
+       BranchObj* bo;
+       BranchObj* par;
+       LinkableMapObj *sel=xelection.single();
+       if (sel)
+       {
+               if (xelection.type()== Selection::MapCenter)
+               {
+                       par=xelection.getBranch();
+                       bo=par->getLastSelectedBranch();
+                       if (bo)
+                       {
+                               // Workaround for reselecting on left and right side
+                               if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
+                                       bo=par->getLastBranch();
+                               if (bo)
+                               {
+                                       bo=par->getLastBranch();
+                                       xelection.select(bo);
+                                       xelection.update();
+                                       ensureSelectionVisible();
+                                       sendSelection();
+                               }
+                       }       
+               } else
+               {
+                       par=(BranchObj*)(sel->getParObj());
+                       if (sel->getOrientation()==LinkableMapObj::RightOfCenter)
+                       {
+                               if (xelection.type() == Selection::Branch ||
+                                       xelection.type() == Selection::FloatImage)
+                               {
+                                       xelection.select(par);
+                                       xelection.update();
+                                       ensureSelectionVisible();
+                                       sendSelection();
+                               }
+                       } else
+                       {
+                               if (xelection.type() == Selection::Branch )
+                               {
+                                       bo=xelection.getBranch()->getLastSelectedBranch();
+                                       if (bo) 
+                                       {
+                                               xelection.select(bo);
+                                               xelection.update();
+                                               ensureSelectionVisible();
+                                       sendSelection();
+                                       }
+                               }
+                       }
+               }       
+       }
+}
+
+void MapEditor::selectRightBranch()
+{
+       if (isSelectBlocked() ) return;
+
+       BranchObj* bo;
+       BranchObj* par;
+       LinkableMapObj *sel=xelection.single();
+       if (sel)
+       {
+               if (xelection.type()==Selection::MapCenter) 
+               {
+                       par=xelection.getBranch();
+                       bo=par->getLastSelectedBranch();
+                       if (bo)
+                       {
+                               // Workaround for reselecting on left and right side
+                               if (bo->getOrientation()==LinkableMapObj::LeftOfCenter)
+                                       bo=par->getFirstBranch();
+                               if (bo)
+                               {
+                                       xelection.select(bo);
+                                       xelection.update();
+                                       ensureSelectionVisible();
+                                       sendSelection();
+                               }
+                       }
+               } else
+               {
+                       par=(BranchObj*)(xelection.single()->getParObj());
+                       if (xelection.single()->getOrientation()==LinkableMapObj::LeftOfCenter)
+                       {
+                               if (xelection.type() == Selection::Branch ||
+                                       xelection.type() == Selection::FloatImage)
+                               {
+                                       xelection.select(par);
+                                       xelection.update();
+                                       ensureSelectionVisible();
+                                       sendSelection();
+                               }
+                       } else
+                       {
+                               if (xelection.type()  == Selection::Branch) 
+                               {
+                                       bo=xelection.getBranch()->getLastSelectedBranch();
+                                       if (bo) 
+                                       {
+                                               xelection.select(bo);
+                                               xelection.update();
+                                               ensureSelectionVisible();
+                                       sendSelection();
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+void MapEditor::selectFirstBranch()
+{
+       BranchObj *bo1=xelection.getBranch();
+       BranchObj *bo2;
+       BranchObj* par;
+       if (bo1)
+       {
+               par=(BranchObj*)(bo1->getParObj());
+               if (!par) return;
+               bo2=par->getFirstBranch();
+               if (bo2) {
+                       xelection.select(bo2);
+                       xelection.update();
+                       ensureSelectionVisible();
+                       sendSelection();
+               }
+       }               
+}
+
+void MapEditor::selectLastBranch()
+{
+       BranchObj *bo1=xelection.getBranch();
+       BranchObj *bo2;
+       BranchObj* par;
+       if (bo1)
+       {
+               par=(BranchObj*)(bo1->getParObj());
+               if (!par) return;
+               bo2=par->getLastBranch();
+               if (bo2) 
+               {
+                       xelection.select(bo2);
+                       xelection.update();
+                       ensureSelectionVisible();
+                       sendSelection();
+               }
+       }               
+}
+
+void MapEditor::selectMapBackgroundImage ()
+{
+        QFileDialog *fd=new QFileDialog( this);
+        fd->setMode (QFileDialog::ExistingFile);
+        //fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
+        QStringList filters = fd->filters();
+        filters << tr("Images  (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)");
+        fd->setFilters(filters);
+        //ImagePreview *p =new ImagePreview (fd);
+        //fd->setContentsPreviewEnabled( TRUE );
+        //fd->setContentsPreview( p, p );
+        //fd->setPreviewMode( Q3FileDialog::Contents );
+       fd->setCaption(vymName+" - " +tr("Load background image"));
+       fd->setDir (lastImageDir);
+       fd->show();
+
+       if ( fd->exec() == QDialog::Accepted )
+       {
+               // TODO selectMapBackgroundImg in QT4 use:      lastImageDir=fd->directory();
+                lastImageDir=QDir (fd->directory().path());
+               setMapBackgroundImage (fd->selectedFile());
+       }
+}      
+
+void MapEditor::setMapBackgroundImage (const QString &fn)      //FIXME missing savestate
+{
+       QColor oldcol=mapScene->backgroundBrush().color();
+       /*
+       saveState(
+               selection,
+               QString ("setMapBackgroundImage (%1)").arg(oldcol.name()),
+               selection,
+               QString ("setMapBackgroundImage (%1)").arg(col.name()),
+               QString("Set background color of map to %1").arg(col.name()));
+       */      
+       QBrush brush;
+       brush.setTextureImage (QPixmap (fn));
+       mapScene->setBackgroundBrush(brush);
+}
+
+void MapEditor::selectMapBackgroundColor()
+{
+       QColor col = QColorDialog::getColor( mapScene->backgroundBrush().color(), this );
+       if ( !col.isValid() ) return;
+       setMapBackgroundColor( col );
+}
+
+
+void MapEditor::setMapBackgroundColor(QColor col)
+{
+       QColor oldcol=mapScene->backgroundBrush().color();
+       saveState(
+               QString ("setMapBackgroundColor (\"%1\")").arg(oldcol.name()),
+               QString ("setMapBackgroundColor (\"%1\")").arg(col.name()),
+               QString("Set background color of map to %1").arg(col.name()));
+       mapScene->setBackgroundBrush(col);
+}
+
+QColor MapEditor::getMapBackgroundColor()
+{
+    return mapScene->backgroundBrush().color();
+}
+
+QColor MapEditor::getCurrentHeadingColor()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo) return bo->getColor(); 
+       
+       QMessageBox::warning(0,tr("Warning"),tr("Can't get color of heading,\nthere's no branch selected"));
+       return Qt::black;
+}
+
+void MapEditor::colorBranch (QColor c)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               saveState(
+                       bo, 
+                       QString ("colorBranch (\"%1\")").arg(bo->getColor().name()),
+                       bo,
+                       QString ("colorBranch (\"%1\")").arg(c.name()),
+                       QString("Set color of %1 to %2").arg(getName(bo)).arg(c.name())
+               );      
+               bo->setColor(c); // color branch
+       }
+}
+
+void MapEditor::colorSubtree (QColor c)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo) 
+       {
+               saveStateChangingPart(
+                       bo, 
+                       bo,
+                       QString ("colorSubtree (\"%1\")").arg(c.name()),
+                       QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(c.name())
+               );      
+               bo->setColorSubtree (c); // color links, color childs
+       }
+}
+
+
+void MapEditor::toggleStandardFlag(QString f)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo) 
+       {
+               QString u,r;
+               if (bo->isSetStandardFlag(f))
+               {
+                       r="unsetFlag";
+                       u="setFlag";
+               }       
+               else
+               {
+                       u="unsetFlag";
+                       r="setFlag";
+               }       
+               saveState(
+                       bo,
+                       QString("%1 (\"%2\")").arg(u).arg(f), 
+                       bo,
+                       QString("%1 (\"%2\")").arg(r).arg(f),
+                       QString("Toggling standard flag \"%1\" of %2").arg(f).arg(getName(bo)));
+               bo->toggleStandardFlag (f,mainWindow->useFlagGroups());
+               xelection.update();
+       }
+}
+
+
+BranchObj* MapEditor::findText (QString s, bool cs)
+{
+       QTextDocument::FindFlags flags=0;
+       if (cs) flags=QTextDocument::FindCaseSensitively;
+
+       if (!itFind) 
+       {       // Nothing found or new find process
+               if (EOFind)
+                       // nothing found, start again
+                       EOFind=false;
+               itFind=model->first();
+       }       
+       bool searching=true;
+       bool foundNote=false;
+       while (searching && !EOFind)
+       {
+               if (itFind)
+               {
+                       // Searching in Note
+                       if (itFind->getNote().contains(s,cs))
+                       {
+                               if (xelection.single()!=itFind) 
+                               {
+                                       xelection.select(itFind);
+                                       ensureSelectionVisible();
+                               }
+                               if (textEditor->findText(s,flags)) 
+                               {
+                                       searching=false;
+                                       foundNote=true;
+                               }       
+                       }
+                       // Searching in Heading
+                       if (searching && itFind->getHeading().contains (s,cs) ) 
+                       {
+                               xelection.select(itFind);
+                               ensureSelectionVisible();
+                               searching=false;
+                       }
+               }       
+               if (!foundNote)
+               {
+                       itFind=model->next(itFind);
+                       if (!itFind) EOFind=true;
+               }
+       //cout <<"still searching...  "<<qPrintable( itFind->getHeading())<<endl;
+       }       
+       if (!searching)
+               return xelection.getBranch();
+       else
+               return NULL;
+}
+
+void MapEditor::findReset()
+{      // Necessary if text to find changes during a find process
+       itFind=NULL;
+       EOFind=false;
+}
+void MapEditor::setURL(const QString &url)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               QString oldurl=bo->getURL();
+               bo->setURL (url);
+               saveState (
+                       bo,
+                       QString ("setURL (\"%1\")").arg(oldurl),
+                       bo,
+                       QString ("setURL (\"%1\")").arg(url),
+                       QString ("set URL of %1 to %2").arg(getName(bo)).arg(url)
+               );
+               updateActions();
+               model->reposition();
+               xelection.update();
+               ensureSelectionVisible();
+       }
+}      
+
+void MapEditor::editURL()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               bool ok;
+               QString text = QInputDialog::getText(
+                               "VYM", tr("Enter URL:"), QLineEdit::Normal,
+                               bo->getURL(), &ok, this );
+               if ( ok) 
+                       // user entered something and pressed OK
+                       setURL (text);
+       }
+}
+
+void MapEditor::editLocalURL()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               QStringList filters;
+               filters <<"All files (*)";
+               filters << tr("Text","Filedialog") + " (*.txt)";
+               filters << tr("Spreadsheet","Filedialog") + " (*.odp,*.sxc)";
+               filters << tr("Textdocument","Filedialog") +" (*.odw,*.sxw)";
+               filters << tr("Images","Filedialog") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)";
+               QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Set URL to a local file"));
+               fd->setFilters (filters);
+               fd->setCaption(vymName+" - " +tr("Set URL to a local file"));
+               fd->setDirectory (lastFileDir);
+               if (! bo->getVymLink().isEmpty() )
+                       fd->selectFile( bo->getURL() );
+               fd->show();
+
+               if ( fd->exec() == QDialog::Accepted )
+               {
+                       lastFileDir=QDir (fd->directory().path());
+                       setURL (fd->selectedFile() );
+               }
+       }
+}
+
+QString MapEditor::getURL()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+               return bo->getURL();
+       else
+               return "";
+}
+
+QStringList MapEditor::getURLs()
+{
+       QStringList urls;
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               bo=bo->first(); 
+               while (bo) 
+               {
+                       if (!bo->getURL().isEmpty()) urls.append( bo->getURL());
+                       bo=bo->next();
+               }       
+       }       
+       return urls;
+}
+
+
+void MapEditor::editHeading2URL()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+               setURL (bo->getHeading());
+}      
+
+void MapEditor::editBugzilla2URL()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               QString url= "https://bugzilla.novell.com/show_bug.cgi?id="+bo->getHeading();
+               setURL (url);
+       }
+}      
+
+void MapEditor::editFATE2URL()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading();
+               saveState(
+                       bo,
+                       "setURL (\""+bo->getURL()+"\")",
+                       bo,
+                       "setURL (\""+url+"\")",
+                       QString("Use heading of %1 as link to FATE").arg(getName(bo))
+               );      
+               bo->setURL (url);
+               updateActions();
+       }
+}      
+
+void MapEditor::editVymLink()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               QStringList filters;
+               filters <<"VYM map (*.vym)";
+               QFileDialog *fd=new QFileDialog( this,vymName+" - " +tr("Link to another map"));
+               fd->setFilters (filters);
+               fd->setCaption(vymName+" - " +tr("Link to another map"));
+               fd->setDirectory (lastFileDir);
+               if (! bo->getVymLink().isEmpty() )
+                       fd->selectFile( bo->getVymLink() );
+               fd->show();
+
+               QString fn;
+               if ( fd->exec() == QDialog::Accepted )
+               {
+                       lastFileDir=QDir (fd->directory().path());
+                       saveState(
+                               bo,
+                               "setVymLink (\""+bo->getVymLink()+"\")",
+                               bo,
+                               "setVymLink (\""+fd->selectedFile()+"\")",
+                               QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())
+                       );      
+                       setVymLinkInt (fd->selectedFile() );
+               }
+       }
+}
+
+void MapEditor::deleteVymLink()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               saveState(
+                       bo,
+                       "setVymLink (\""+bo->getVymLink()+"\")",
+                       bo,
+                       "setVymLink (\"\")",
+                       QString("Unset vymlink of %1").arg(getName(bo))
+               );      
+               bo->setVymLink ("" );
+               updateActions();
+               model->reposition();
+               scene()->update();
+       }
+}
+
+void MapEditor::setHideExport(bool b)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               bo->setHideInExport (b);
+               QString u= b ? "false" : "true";
+               QString r=!b ? "false" : "true";
+               
+               saveState(
+                       bo,
+                       QString ("setHideExport (%1)").arg(u),
+                       bo,
+                       QString ("setHideExport (%1)").arg(r),
+                       QString ("Set HideExport flag of %1 to %2").arg(getName(bo)).arg (r)
+               );      
+               updateActions();
+               model->reposition();
+               xelection.update();
+               scene()->update();
+       }
+}
+
+void MapEditor::toggleHideExport()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+               setHideExport ( !bo->hideInExport() );
+}
+
+QString MapEditor::getVymLink()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+               return bo->getVymLink();
+       else    
+               return "";
+       
+}
+
+QStringList MapEditor::getVymLinks()
+{
+       QStringList links;
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               bo=bo->first(); 
+               while (bo) 
+               {
+                       if (!bo->getVymLink().isEmpty()) links.append( bo->getVymLink());
+                       bo=bo->next();
+               }       
+       }       
+       return links;
+}
+
+
+void MapEditor::deleteKeepChilds()
+{
+       BranchObj *bo=xelection.getBranch();
+       BranchObj *par;
+       if (bo)
+       {
+               par=(BranchObj*)(bo->getParObj());
+
+               // Don't use this on mapcenter
+               if (!par) return;
+
+               // Check if we have childs at all to keep
+               if (bo->countBranches()==0) 
+               {
+                       deleteSelection();
+                       return;
+               }
+
+               QPointF p=bo->getRelPos();
+               saveStateChangingPart(
+                       bo->getParObj(),
+                       bo,
+                       "deleteKeepChilds ()",
+                       QString("Remove %1 and keep its childs").arg(getName(bo))
+               );
+
+               QString sel=model->getSelectString(bo);
+               unselect();
+               par->removeBranchHere(bo);
+               model->reposition();
+               select (sel);
+               xelection.getBranch()->move2RelPos (p);
+               model->reposition();
+       }       
+}
+
+void MapEditor::deleteChilds()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {               
+               saveStateChangingPart(
+                       bo, 
+                       bo,
+                       "deleteChilds ()",
+                       QString( "Remove childs of branch %1").arg(getName(bo))
+               );
+               bo->removeChilds();
+               model->reposition();
+       }       
+}
+
+void MapEditor::editMapInfo()
+{
+       ExtraInfoDialog dia;
+       dia.setMapName (getFileName() );
+       dia.setAuthor (model->getAuthor() );
+       dia.setComment(model->getComment() );
+
+       // Calc some stats
+       QString stats;
+    stats+=tr("%1 items on map\n","Info about map").arg (mapScene->items().size(),6);
+
+       uint b=0;
+       uint f=0;
+       uint n=0;
+       uint xl=0;
+       BranchObj *bo;
+       bo=model->first();
+       while (bo) 
+       {
+               if (!bo->getNote().isEmpty() ) n++;
+               f+= bo->countFloatImages();
+               b++;
+               xl+=bo->countXLinks();
+               bo=model->next(bo);
+       }
+    stats+=QString ("%1 branches\n").arg (b-1,6);
+    stats+=QString ("%1 xLinks \n").arg (xl,6);
+    stats+=QString ("%1 notes\n").arg (n,6);
+    stats+=QString ("%1 images\n").arg (f,6);
+       dia.setStats (stats);
+
+       // Finally show dialog
+       if (dia.exec() == QDialog::Accepted)
+       {
+               setMapAuthor (dia.getAuthor() );
+               setMapComment (dia.getComment() );
+       }
+}
+
+void MapEditor::ensureSelectionVisible()
+{
+       LinkableMapObj *lmo=xelection.single();
+       if (lmo) ensureVisible (lmo->getBBox() );
+       
+}
+
+void MapEditor::updateSelection()
+{
+       // Tell selection to update geometries
+       xelection.update();
+}
+
+void MapEditor::updateActions()
+{
+       // Tell mainwindow to update states of actions
+       mainWindow->updateActions();
+       // TODO maybe don't update if blockReposition is set
+}
+
+void MapEditor::updateNoteFlag()
+{
+       setChanged();
+       BranchObj *bo=xelection.getBranch();
+       if (bo) 
+       {
+               bo->updateNoteFlag();
+               mainWindow->updateActions();
+       }       
+}
+
+void MapEditor::setMapAuthor (const QString &s)
+{
+       saveState (
+               QString ("setMapAuthor (\"%1\")").arg(model->getAuthor()),
+               QString ("setMapAuthor (\"%1\")").arg(s),
+               QString ("Set author of map to \"%1\"").arg(s)
+       );
+       model->setAuthor (s);
+}
+
+void MapEditor::setMapComment (const QString &s)
+{
+       saveState (
+               QString ("setMapComment (\"%1\")").arg(model->getComment()),
+               QString ("setMapComment (\"%1\")").arg(s),
+               QString ("Set comment of map")
+       );
+       model->setComment (s);
+}
+
+void MapEditor::setMapLinkStyle (const QString & s)
+{
+       QString snow;
+       if (linkstyle==LinkableMapObj::Line)
+               snow="StyleLine";
+       else if (linkstyle==LinkableMapObj::Parabel)
+               snow="StyleParabel";
+       else if (linkstyle==LinkableMapObj::PolyLine)
+               snow="StylePolyLine";
+       else if (linkstyle==LinkableMapObj::PolyParabel)
+               snow="StyleParabel";
+
+       saveState (
+               QString("setMapLinkStyle (\"%1\")").arg(s),
+               QString("setMapLinkStyle (\"%1\")").arg(snow),
+               QString("Set map link style (\"%1\")").arg(s)
+       );      
+
+       if (s=="StyleLine")
+               linkstyle=LinkableMapObj::Line;
+       else if (s=="StyleParabel")
+               linkstyle=LinkableMapObj::Parabel;
+       else if (s=="StylePolyLine")
+               linkstyle=LinkableMapObj::PolyLine;
+       else    
+               linkstyle=LinkableMapObj::PolyParabel;
+
+       BranchObj *bo;
+       bo=model->first();
+       bo=model->next(bo);
+       while (bo) 
+       {
+               bo->setLinkStyle(bo->getDefLinkStyle());
+               bo=model->next(bo);
+       }
+       model->reposition();
+}
+
+LinkableMapObj::Style MapEditor::getMapLinkStyle ()
+{
+       return linkstyle;
+}      
+
+void MapEditor::setMapDefLinkColor(QColor c)
+{
+       defLinkColor=c;
+       BranchObj *bo;
+       bo=model->first();
+       while (bo) 
+       {
+               bo->setLinkColor();
+               bo=model->next(bo);
+       }
+       updateActions();
+}
+
+void MapEditor::setMapLinkColorHintInt()
+{
+       // called from setMapLinkColorHint(lch) or at end of parse
+       BranchObj *bo;
+       bo=model->first();
+       while (bo) 
+       {
+               bo->setLinkColor();
+               bo=model->next(bo);
+       }
+}
+
+void MapEditor::setMapLinkColorHint(LinkableMapObj::ColorHint lch)
+{
+       linkcolorhint=lch;
+       setMapLinkColorHintInt();
+}
+
+void MapEditor::toggleMapLinkColorHint()
+{
+       if (linkcolorhint==LinkableMapObj::HeadingColor)
+               linkcolorhint=LinkableMapObj::DefaultColor;
+       else    
+               linkcolorhint=LinkableMapObj::HeadingColor;
+       BranchObj *bo;
+       bo=model->first();
+       while (bo) 
+       {
+               bo->setLinkColor();
+               bo=model->next(bo);
+       }
+}
+
+LinkableMapObj::ColorHint MapEditor::getMapLinkColorHint()
+{
+       return linkcolorhint;
+}
+
+QColor MapEditor::getMapDefLinkColor()
+{
+       return defLinkColor;
+}
+
+void MapEditor::setMapDefXLinkColor(QColor col)
+{
+       defXLinkColor=col;
+}
+
+QColor MapEditor::getMapDefXLinkColor()
+{
+       return defXLinkColor;
+}
+
+void MapEditor::setMapDefXLinkWidth (int w)
+{
+       defXLinkWidth=w;
+}
+
+int MapEditor::getMapDefXLinkWidth()
+{
+       return defXLinkWidth;
+}
+
+void MapEditor::selectMapLinkColor()
+{
+       QColor col = QColorDialog::getColor( defLinkColor, this );
+       if ( !col.isValid() ) return;
+       saveState (
+               QString("setMapDefLinkColor (\"%1\")").arg(getMapDefLinkColor().name()),
+               QString("setMapDefLinkColor (\"%1\")").arg(col.name()),
+               QString("Set map link color to %1").arg(col.name())
+       );
+       setMapDefLinkColor( col );
+}
+
+void MapEditor::selectMapSelectionColor()
+{
+       QColor col = QColorDialog::getColor( defLinkColor, this );
+       setSelectionColor (col);
+}
+
+void MapEditor::setSelectionColorInt (QColor col)
+{
+       if ( !col.isValid() ) return;
+       xelection.setColor (col);
+}
+
+void MapEditor::setSelectionColor(QColor col)
+{
+       if ( !col.isValid() ) return;
+       saveState (
+               QString("setSelectionColor (%1)").arg(xelection.getColor().name()),
+               QString("setSelectionColor (%1)").arg(col.name()),
+               QString("Set color of selection box to %1").arg(col.name())
+       );
+       setSelectionColorInt (col);
+}
+
+QColor MapEditor::getSelectionColor()
+{
+       return xelection.getColor();
+}
+
+bool MapEditor::scrollBranch(BranchObj *bo)
+{
+       if (bo)
+       {
+               if (bo->isScrolled()) return false;
+               if (bo->countBranches()==0) return false;
+               if (bo->getDepth()==0) return false;
+               QString u,r;
+               r="scroll";
+               u="unscroll";
+               saveState(
+                       bo,
+                       QString ("%1 ()").arg(u),
+                       bo,
+                       QString ("%1 ()").arg(r),
+                       QString ("%1 %2").arg(r).arg(getName(bo))
+               );
+               bo->toggleScroll();
+               xelection.update();
+               scene()->update();
+               return true;
+       }       
+       return false;
+}
+
+bool MapEditor::unscrollBranch(BranchObj *bo)
+{
+       if (bo)
+       {
+               if (!bo->isScrolled()) return false;
+               if (bo->countBranches()==0) return false;
+               if (bo->getDepth()==0) return false;
+               QString u,r;
+               u="scroll";
+               r="unscroll";
+               saveState(
+                       bo,
+                       QString ("%1 ()").arg(u),
+                       bo,
+                       QString ("%1 ()").arg(r),
+                       QString ("%1 %2").arg(r).arg(getName(bo))
+               );
+               bo->toggleScroll();
+               xelection.update();
+               scene()->update();
+               return true;
+       }       
+       return false;
+}
+
+void MapEditor::toggleScroll()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (xelection.type()==Selection::Branch )
+       {
+               if (bo->isScrolled())
+                       unscrollBranch (bo);
+               else
+                       scrollBranch (bo);
+       }
+}
+
+void MapEditor::unscrollChilds() 
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               bo->first();
+               while (bo) 
+               {
+                       if (bo->isScrolled()) unscrollBranch (bo);
+                       bo=bo->next();
+               }
+       }       
+}
+
+FloatImageObj* MapEditor::loadFloatImageInt (QString fn)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               FloatImageObj *fio;
+               bo->addFloatImage();
+               fio=bo->getLastFloatImage();
+               fio->load(fn);
+               model->reposition();
+               scene()->update();
+               return fio;
+       }
+       return NULL;
+}      
+
+void MapEditor::loadFloatImage ()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+
+                QFileDialog *fd=new QFileDialog( this);
+                fd->setMode (QFileDialog::ExistingFiles);
+                //fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)"));
+                QStringList filters = fd->filters();
+                filters << tr("Images (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)");
+                fd->setFilters(filters);
+                //ImagePreview *p =new ImagePreview (fd);
+                //fd->setContentsPreviewEnabled( TRUE );
+                //fd->setContentsPreview( p, p );
+                //fd->setPreviewMode( Q3FileDialog::Contents );
+               fd->setCaption(vymName+" - " +tr("Load image"));
+               fd->setDir (lastImageDir);
+               fd->show();
+
+               if ( fd->exec() == QDialog::Accepted )
+               {
+                       // TODO loadFIO in QT4 use:     lastImageDir=fd->directory();
+                        lastImageDir=QDir (fd->directory().path());
+                       QString s;
+                       FloatImageObj *fio;
+                       for (int j=0; j<fd->selectedFiles().count(); j++)
+                       {
+                               s=fd->selectedFiles().at(j);
+                               fio=loadFloatImageInt (s);
+                               if (fio)
+                                       saveState(
+                                               (LinkableMapObj*)fio,
+                                               "delete ()",
+                                               bo, 
+                                               QString ("loadImage (%1)").arg(s ),
+                                               QString("Add image %1 to %2").arg(s).arg(getName(bo))
+                                       );
+                               else
+                                       // TODO loadFIO error handling
+                                       qWarning ("Failed to load "+s);
+                       }
+               }
+                //delete (p);
+               delete (fd);
+       }
+}
+
+void MapEditor::saveFloatImageInt  (FloatImageObj *fio, const QString &type, const QString &fn)
+{
+       fio->save (fn,type);
+}
+
+void MapEditor::saveFloatImage ()
+{
+       FloatImageObj *fio=xelection.getFloatImage();
+       if (fio)
+       {
+               QFileDialog *fd=new QFileDialog( this);
+               fd->setFilters (imageIO.getFilters());
+               fd->setCaption(vymName+" - " +tr("Save image"));
+               fd->setFileMode( QFileDialog::AnyFile );
+               fd->setDirectory (lastImageDir);
+//             fd->setSelection (fio->getOriginalFilename());
+               fd->show();
+
+               QString fn;
+               if ( fd->exec() == QDialog::Accepted && fd->selectedFiles().count()==1)
+               {
+                       fn=fd->selectedFiles().at(0);
+                       if (QFile (fn).exists() )
+                       {
+                               QMessageBox mb( vymName,
+                                       tr("The file %1 exists already.\n"
+                                       "Do you want to overwrite it?").arg(fn),
+                               QMessageBox::Warning,
+                               QMessageBox::Yes | QMessageBox::Default,
+                               QMessageBox::Cancel | QMessageBox::Escape,
+                               QMessageBox::NoButton );
+
+                               mb.setButtonText( QMessageBox::Yes, tr("Overwrite") );
+                               mb.setButtonText( QMessageBox::No, tr("Cancel"));
+                               switch( mb.exec() ) 
+                               {
+                                       case QMessageBox::Yes:
+                                               // save 
+                                               break;
+                                       case QMessageBox::Cancel:
+                                               // do nothing
+                                               delete (fd);
+                                               return;
+                                               break;
+                               }
+                       }
+                       saveFloatImageInt (fio,fd->selectedFilter(),fn );
+               }
+               delete (fd);
+       }
+}
+
+void MapEditor::setFrameType(const FrameObj::FrameType &t)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               QString s=bo->getFrameTypeName();
+               bo->setFrameType (t);
+               saveState (bo, QString("setFrameType (\"%1\")").arg(s),
+                       bo, QString ("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),QString ("set type of frame to %1").arg(s));
+               model->reposition();
+               bo->updateLink();
+       }
+}
+
+void MapEditor::setFrameType(const QString &s) 
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               saveState (bo, QString("setFrameType (\"%1\")").arg(bo->getFrameTypeName()),
+                       bo, QString ("setFrameType (\"%1\")").arg(s),QString ("set type of frame to %1").arg(s));
+               bo->setFrameType (s);
+               model->reposition();
+               bo->updateLink();
+       }
+}
+
+void MapEditor::setFramePenColor(const QColor &c)      
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               saveState (bo, QString("setFramePenColor (\"%1\")").arg(bo->getFramePenColor().name() ),
+                       bo, QString ("setFramePenColor (\"%1\")").arg(c.name() ),QString ("set pen color of frame to %1").arg(c.name() ));
+               bo->setFramePenColor (c);
+       }       
+}
+
+void MapEditor::setFrameBrushColor(const QColor &c)    
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               saveState (bo, QString("setFrameBrushColor (\"%1\")").arg(bo->getFrameBrushColor().name() ),
+                       bo, QString ("setFrameBrushColor (\"%1\")").arg(c.name() ),QString ("set brush color of frame to %1").arg(c.name() ));
+               bo->setFrameBrushColor (c);
+       }       
+}
+
+void MapEditor::setFramePadding (const int &i)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               saveState (bo, QString("setFramePadding (\"%1\")").arg(bo->getFramePadding() ),
+                       bo, QString ("setFramePadding (\"%1\")").arg(i),QString ("set brush color of frame to %1").arg(i));
+               bo->setFramePadding (i);
+               model->reposition();
+               bo->updateLink();
+       }       
+}
+
+void MapEditor::setFrameBorderWidth(const int &i)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               saveState (bo, QString("setFrameBorderWidth (\"%1\")").arg(bo->getFrameBorderWidth() ),
+                       bo, QString ("setFrameBorderWidth (\"%1\")").arg(i),QString ("set border width of frame to %1").arg(i));
+               bo->setFrameBorderWidth (i);
+               model->reposition();
+               bo->updateLink();
+       }       
+}
+
+void MapEditor::setIncludeImagesVer(bool b)    
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               QString u= b ? "false" : "true";
+               QString r=!b ? "false" : "true";
+               
+               saveState(
+                       bo,
+                       QString("setIncludeImagesVertically (%1)").arg(u),
+                       bo, 
+                       QString("setIncludeImagesVertically (%1)").arg(r),
+                       QString("Include images vertically in %1").arg(getName(bo))
+               );      
+               bo->setIncludeImagesVer(b);
+               model->reposition();
+       }       
+}
+
+void MapEditor::setIncludeImagesHor(bool b)    
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               QString u= b ? "false" : "true";
+               QString r=!b ? "false" : "true";
+               
+               saveState(
+                       bo,
+                       QString("setIncludeImagesHorizontally (%1)").arg(u),
+                       bo, 
+                       QString("setIncludeImagesHorizontally (%1)").arg(r),
+                       QString("Include images horizontally in %1").arg(getName(bo))
+               );      
+               bo->setIncludeImagesHor(b);
+               model->reposition();
+       }       
+}
+
+void MapEditor::setHideLinkUnselected (bool b)
+{
+       LinkableMapObj *sel=xelection.single();
+       if (sel &&
+               (xelection.type() == Selection::Branch || 
+               xelection.type() == Selection::MapCenter  ||
+               xelection.type() == Selection::FloatImage ))
+       {
+               QString u= b ? "false" : "true";
+               QString r=!b ? "false" : "true";
+               
+               saveState(
+                       sel,
+                       QString("setHideLinkUnselected (%1)").arg(u),
+                       sel, 
+                       QString("setHideLinkUnselected (%1)").arg(r),
+                       QString("Hide link of %1 if unselected").arg(getName(sel))
+               );      
+               sel->setHideLinkUnselected(b);
+       }
+}
+
+void MapEditor::importDirInt(BranchObj *dst, QDir d)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               // Traverse directories
+               d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
+               QFileInfoList list = d.entryInfoList();
+               QFileInfo fi;
+
+               for (int i = 0; i < list.size(); ++i) 
+               {
+                       fi=list.at(i);
+                       if (fi.fileName() != "." && fi.fileName() != ".." )
+                       {
+                               dst->addBranch();
+                               bo=dst->getLastBranch();
+                               bo->setHeading (fi.fileName() );
+                               bo->setColor (QColor("blue"));
+                               bo->toggleScroll();
+                               if ( !d.cd(fi.fileName()) ) 
+                                       QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory %1").arg(fi.fileName()));
+                               else 
+                               {
+                                       // Recursively add subdirs
+                                       importDirInt (bo,d);
+                                       d.cdUp();
+                               }
+                       }       
+               }               
+               // Traverse files
+               d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
+               list = d.entryInfoList();
+
+               for (int i = 0; i < list.size(); ++i) 
+               {
+                       fi=list.at(i);
+                       dst->addBranch();
+                       bo=dst->getLastBranch();
+                       bo->setHeading (fi.fileName() );
+                       bo->setColor (QColor("black"));
+                       if (fi.fileName().right(4) == ".vym" )
+                               bo->setVymLink (fi.filePath());
+               }       
+       }               
+}
+
+void MapEditor::importDirInt (const QString &s)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               saveStateChangingPart (bo,bo,QString ("importDir (\"%1\")").arg(s),QString("Import directory structure from %1").arg(s));
+
+               QDir d(s);
+               importDirInt (bo,d);
+       }
+}      
+
+void MapEditor::importDir()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               QStringList filters;
+               filters <<"VYM map (*.vym)";
+               QFileDialog *fd=new QFileDialog( this,vymName+ " - " +tr("Choose directory structure to import"));
+               fd->setMode (QFileDialog::DirectoryOnly);
+               fd->setFilters (filters);
+               fd->setCaption(vymName+" - " +tr("Choose directory structure to import"));
+               fd->show();
+
+               QString fn;
+               if ( fd->exec() == QDialog::Accepted )
+               {
+                       importDirInt (fd->selectedFile() );
+                       model->reposition();
+                       scene()->update();
+               }
+       }       
+}
+
+void MapEditor::followXLink(int i)
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               bo=bo->XLinkTargetAt(i);
+               if (bo) 
+               {
+                       xelection.select(bo);
+                       ensureSelectionVisible();
+               }
+       }
+}
+
+void MapEditor::editXLink(int i)       // FIXME missing saveState
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+       {
+               XLinkObj *xlo=bo->XLinkAt(i);
+               if (xlo) 
+               {
+                       EditXLinkDialog dia;
+                       dia.setXLink (xlo);
+                       dia.setSelection(bo);
+                       if (dia.exec() == QDialog::Accepted)
+                       {
+                               if (dia.useSettingsGlobal() )
+                               {
+                                       setMapDefXLinkColor (xlo->getColor() );
+                                       setMapDefXLinkWidth (xlo->getWidth() );
+                               }
+                               if (dia.deleteXLink())
+                                       bo->deleteXLinkAt(i);
+                       }
+               }       
+       }
+}
+
+AttributeTable* MapEditor::attributeTable()
+{
+       return attrTable;
+}
+
+void MapEditor::testFunction1()
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo) model->moveAway (bo);
+       
+/* TODO Hide hidden stuff temporary, maybe add this as regular function somewhere
+       if (hidemode==HideNone)
+       {
+               setHideTmpMode (HideExport);
+               mapCenter->calcBBoxSizeWithChilds();
+               QRectF totalBBox=mapCenter->getTotalBBox();
+               QRectF mapRect=totalBBox;
+               QCanvasRectangle *frame=NULL;
+
+               cout << "  map has =("<<totalBBox.x()<<","<<totalBBox.y()<<","<<totalBBox.width()<<","<<totalBBox.height()<<")\n";
+       
+               mapRect.setRect (totalBBox.x(), totalBBox.y(), 
+                       totalBBox.width(), totalBBox.height());
+               frame=new QCanvasRectangle (mapRect,mapScene);
+               frame->setBrush (QColor(white));
+               frame->setPen (QColor(black));
+               frame->setZValue(0);
+               frame->show();    
+       }       
+       else    
+       {
+               setHideTmpMode (HideNone);
+       }       
+       cout <<"  hidemode="<<hidemode<<endl;
+       */
+}      
+       
+void MapEditor::testFunction2()
+{
+
+/*
+       // Toggle hidemode
+       if (hidemode==HideExport)
+               setHideTmpMode (HideNone);
+       else    
+               setHideTmpMode (HideExport);
+*/             
+}
+
+void MapEditor::contextMenuEvent ( QContextMenuEvent * e )
+{
+       // Lineedits are already closed by preceding
+       // mouseEvent, we don't need to close here.
+
+    QPointF p = mapToScene(e->pos());
+    LinkableMapObj* lmo=model->findMapObj(p, NULL);
+       
+    if (lmo) 
+       {       // MapObj was found
+               if (xelection.single() != lmo)
+               {
+                       // select the MapObj
+                       xelection.select(lmo);
+               }
+               // Context Menu 
+               if (xelection.getBranch() ) 
+               {
+                       // Context Menu on branch or mapcenter
+                       updateActions();
+                       branchContextMenu->popup(e->globalPos() );
+               } else
+               {
+                       if (xelection.getFloatImage() )
+                       {
+                               // Context Menu on floatimage
+                               updateActions();
+                               floatimageContextMenu->popup(e->globalPos() );
+                       }       
+               }       
+       } else 
+       { // No MapObj found, we are on the Canvas itself
+               // Context Menu on scene
+               updateActions();
+               contextMenuPos=p;
+               canvasContextMenu->popup(e->globalPos() );
+    } 
+       e->accept();
+}
+
+void MapEditor::keyPressEvent(QKeyEvent* e)
+{
+       if (e->modifiers() & Qt::ControlModifier)
+       {
+               switch (mainWindow->getModMode())
+               {
+                       case Main::ModModeColor: 
+                               setCursor (PickColorCursor);
+                               break;
+                       case Main::ModModeCopy: 
+                               setCursor (CopyCursor);
+                               break;
+                       case Main::ModModeXLink: 
+                               setCursor (XLinkCursor);
+                               break;
+                       default :
+                               setCursor (Qt::ArrowCursor);
+                               break;
+               } 
+       }       
+}
+
+void MapEditor::keyReleaseEvent(QKeyEvent* e)
+{
+       if (!(e->modifiers() & Qt::ControlModifier))
+               setCursor (Qt::ArrowCursor);
+}
+
+void MapEditor::mousePressEvent(QMouseEvent* e)
+{
+       // Ignore right clicks, these will go to context menus
+       if (e->button() == Qt::RightButton )
+       {
+               e->ignore();
+               return;
+       }
+
+       //Ignore clicks while editing heading
+       if (isSelectBlocked() ) 
+       {
+               e->ignore();
+               return;
+       }
+
+    QPointF p = mapToScene(e->pos());
+    LinkableMapObj* lmo=model->findMapObj(p, NULL);
+       
+       e->accept();
+
+       //Take care of  system flags _or_ modifier modes
+       //
+       if (lmo && (typeid(*lmo)==typeid(BranchObj) ||
+               typeid(*lmo)==typeid(MapCenterObj) ))
+       {
+               QString foname=((BranchObj*)lmo)->getSystemFlagName(p);
+               if (!foname.isEmpty())
+               {
+                       // systemFlag clicked
+                       selectInt (lmo);
+                       if (foname=="url") 
+                       {
+                               if (e->state() & Qt::ControlModifier)
+                                       mainWindow->editOpenURLTab();
+                               else    
+                                       mainWindow->editOpenURL();
+                       }       
+                       else if (foname=="vymLink")
+                       {
+                               mainWindow->editOpenVymLink();
+                               // tabWidget may change, better return now
+                               // before segfaulting...
+                       } else if (foname=="note")
+                               mainWindow->windowToggleNoteEditor();
+                       else if (foname=="hideInExport")                
+                               toggleHideExport();
+                       xelection.update();     
+                       return; 
+               } 
+       } 
+
+       // No system flag clicked, take care of modmodes (CTRL-Click)
+       if (e->state() & Qt::ControlModifier)
+       {
+               if (mainWindow->getModMode()==Main::ModModeColor)
+               {
+                               pickingColor=true;
+                               setCursor (PickColorCursor);
+                               return;
+               } 
+               if (mainWindow->getModMode()==Main::ModModeXLink)
+               {       
+                       BranchObj *bo_begin=NULL;
+                       if (lmo)
+                               bo_begin=(BranchObj*)(lmo);
+                       else    
+                               if (xelection.getBranch() ) 
+                                       bo_begin=xelection.getBranch();
+                       if (bo_begin)   
+                       {
+                               drawingLink=true;
+                               linkingObj_src=bo_begin;
+                               tmpXLink=new XLinkObj (mapScene);
+                               tmpXLink->setBegin (bo_begin);
+                               tmpXLink->setEnd   (p);
+                               tmpXLink->setColor(defXLinkColor);
+                               tmpXLink->setWidth(defXLinkWidth);
+                               tmpXLink->updateXLink();
+                               tmpXLink->setVisibility (true);
+                               return;
+                       } 
+               }
+       }       // End of modmodes
+
+    if (lmo) 
+       {       
+               // Select the clicked object
+               selectInt (lmo);
+
+               // Left Button      Move Branches
+               if (e->button() == Qt::LeftButton )
+               {
+                       //movingObj_start.setX( p.x() - selection->x() );// TODO replaced selection->lmo here   
+                       //movingObj_start.setY( p.y() - selection->y() );       
+                       movingObj_start.setX( p.x() - lmo->x() );       
+                       movingObj_start.setY( p.y() - lmo->y() );       
+                       movingObj_orgPos.setX (lmo->x() );
+                       movingObj_orgPos.setY (lmo->y() );
+                       movingObj_orgRelPos=lmo->getRelPos();
+
+                       // If modMode==copy, then we want to "move" the _new_ object around
+                       // then we need the offset from p to the _old_ selection, because of tmp
+                       if (mainWindow->getModMode()==Main::ModModeCopy &&
+                               e->state() & Qt::ControlModifier)
+                       {
+                               BranchObj *bo=xelection.getBranch();
+                               if (bo)
+                               {
+                                       copyingObj=true;
+                                       bo->addBranch ((BranchObj*)xelection.single());
+                                       unselect();
+                                       xelection.select(bo->getLastBranch());
+                                       model->reposition();
+                               }
+                       } 
+
+                       movingObj=xelection.single();   
+               } else
+                       // Middle Button    Toggle Scroll
+                       // (On Mac OS X this won't work, but we still have 
+                       // a button in the toolbar)
+                       if (e->button() == Qt::MidButton )
+                               toggleScroll();
+               updateActions();
+               xelection.update();
+       } else 
+       { // No MapObj found, we are on the scene itself
+               // Left Button      move Pos of sceneView
+               if (e->button() == Qt::LeftButton )
+               {
+                       movingObj=NULL; // move Content not Obj
+                       movingObj_start=e->globalPos();
+                       movingCont_start=QPointF (
+                               horizontalScrollBar()->value(),
+                               verticalScrollBar()->value());
+                       movingVec=QPointF(0,0);
+                       setCursor(HandOpenCursor);
+               } 
+    } 
+}
+
+void MapEditor::mouseMoveEvent(QMouseEvent* e)
+{
+    QPointF p = mapToScene(e->pos());
+       LinkableMapObj *lmosel=xelection.single();
+
+    // Move the selected MapObj
+    if ( lmosel && movingObj) 
+    {  
+               // reset cursor if we are moving and don't copy
+               if (mainWindow->getModMode()!=Main::ModModeCopy)
+                       setCursor (Qt::ArrowCursor);
+
+               // To avoid jumping of the sceneView, only 
+               // ensureSelectionVisible, if not tmp linked
+               if (!lmosel->hasParObjTmp())
+                       ensureSelectionVisible ();
+               
+               // Now move the selection, but add relative position 
+               // (movingObj_start) where selection was chosen with 
+               // mousepointer. (This avoids flickering resp. jumping 
+               // of selection back to absPos)
+               
+               // Check if we could link 
+               LinkableMapObj* lmo=model->findMapObj(p, lmosel);
+               
+
+               FloatObj *fio=xelection.getFloatImage();
+               if (fio)
+               {
+                       fio->move   (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );           
+                       fio->setRelPos();
+                       fio->updateLink(); //no need for reposition, if we update link here
+                       xelection.update();
+
+                       // Relink float to new mapcenter or branch, if shift is pressed 
+                       // Only relink, if selection really has a new parent
+                       if ( (e->modifiers()==Qt::ShiftModifier) && lmo &&
+                               ( (typeid(*lmo)==typeid(BranchObj)) ||
+                                 (typeid(*lmo)==typeid(MapCenterObj)) ) &&
+                               ( lmo != fio->getParObj())  
+                               )
+                       {
+                               if (typeid(*fio) == typeid(FloatImageObj) && 
+                               ( (typeid(*lmo)==typeid(BranchObj) ||
+                                 typeid(*lmo)==typeid(MapCenterObj)) ))  
+                               {
+
+                                       // Also save the move which was done so far
+                                       QString pold=qpointfToString(movingObj_orgRelPos);
+                                       QString pnow=qpointfToString(fio->getRelPos());
+                                       saveState(
+                                               fio,
+                                               "moveRel "+pold,
+                                               fio,
+                                               "moveRel "+pnow,
+                                               QString("Move %1 to relative position %2").arg(getName(fio)).arg(pnow));
+                                       fio->getParObj()->requestReposition();
+                                       model->reposition();
+
+                                       linkTo (model->getSelectString(lmo));
+                                       //movingObj=lmosel;
+                                       //movingObj_orgRelPos=lmosel->getRelPos();      
+
+                                       model->reposition();
+                               }       
+                       }
+               } else  
+               {       // selection != a FloatObj
+                       if (lmosel->getDepth()==0)
+                       {
+                               // Move MapCenter
+                               if (e->buttons()== Qt::LeftButton && e->modifiers()==Qt::ShiftModifier) 
+                                       ((MapCenterObj*)lmosel)->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );               
+                               else    
+                                       lmosel->move   (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );                
+                               model->updateRelPositions();
+                       } else
+                       {       
+                               if (lmosel->getDepth()==1)
+                               {
+                                       // Move mainbranch
+                                       lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() );           
+                                       lmosel->setRelPos();
+                               } else
+                               {
+                                       // Move ordinary branch
+                                       lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y()  );          
+                               } 
+
+                               // Maybe we can relink temporary?
+                               if (lmo && (lmo!=lmosel) && xelection.getBranch() && 
+                                        (typeid(*lmo)==typeid(BranchObj) ||
+                                         typeid(*lmo)==typeid(MapCenterObj)) ) 
+
+                               {
+                                       if (e->modifiers()==Qt::ControlModifier)
+                                       {
+                                               // Special case: CTRL to link below lmo
+                                               lmosel->setParObjTmp (lmo,p,+1);
+                                       }
+                                       else if (e->modifiers()==Qt::ShiftModifier)
+                                               lmosel->setParObjTmp (lmo,p,-1);
+                                       else
+                                               lmosel->setParObjTmp (lmo,p,0);
+                               } else  
+                               {
+                                       lmosel->unsetParObjTmp();
+                               }               
+                               // reposition subbranch
+                               lmosel->reposition();   
+                       } // depth>0
+
+                       xelection.update();
+               } // no FloatImageObj
+
+               scene()->update();
+               return;
+       } // selection && moving_obj
+               
+       // Draw a link from one branch to another
+       if (drawingLink)
+       {
+                tmpXLink->setEnd (p);
+                tmpXLink->updateXLink();
+       }        
+       
+    // Move sceneView 
+    if (!movingObj && !pickingColor &&!drawingLink && e->buttons() == Qt::LeftButton ) 
+       {
+               QPointF p=e->globalPos();
+               movingVec.setX(-p.x() + movingObj_start.x() );
+               movingVec.setY(-p.y() + movingObj_start.y() );
+               horizontalScrollBar()->setSliderPosition((int)( movingCont_start.x()+movingVec.x() ));
+               verticalScrollBar()->setSliderPosition((int)( movingCont_start.y()+movingVec.y() ) );
+    }
+}
+
+
+void MapEditor::mouseReleaseEvent(QMouseEvent* e)
+{
+    QPointF p = mapToScene(e->pos());
+       LinkableMapObj *dst;
+       LinkableMapObj *lmosel=xelection.single();
+       // Have we been picking color?
+       if (pickingColor)
+       {
+               pickingColor=false;
+               setCursor (Qt::ArrowCursor);
+               // Check if we are over another branch
+               dst=model->findMapObj(p, NULL);
+               if (dst && lmosel) 
+               {       
+                       if (e->state() & Qt::ShiftModifier)
+                               colorBranch (((BranchObj*)dst)->getColor());
+                       else    
+                               colorSubtree (((BranchObj*)dst)->getColor());
+               } 
+               return;
+       }
+
+       // Have we been drawing a link?
+       if (drawingLink)        
+       {
+               drawingLink=false;
+               // Check if we are over another branch
+               dst=model->findMapObj(p, NULL);
+               if (dst && lmosel) 
+               {       
+                       tmpXLink->setEnd ( ((BranchObj*)(dst)) );
+                       tmpXLink->updateXLink();
+                       tmpXLink->activate(); //FIXME savestate missing
+                       //saveStateComplete(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) );      
+               } else
+               {
+                       delete(tmpXLink);
+                       tmpXLink=NULL;
+               }
+               return;
+       }
+       
+    // Have we been moving something?
+    if ( lmosel && movingObj ) 
+    {  
+               FloatImageObj *fo=xelection.getFloatImage();
+               if(fo)
+               {
+                       // Moved FloatObj. Maybe we need to reposition
+                   QString pold=qpointfToString(movingObj_orgRelPos);
+                   QString pnow=qpointfToString(fo->getRelPos());
+                       saveState(
+                               fo,
+                               "moveRel "+pold,
+                               fo,
+                               "moveRel "+pnow,
+                               QString("Move %1 to relative position %2").arg(getName(fo)).arg(pnow));
+
+                       fo->getParObj()->requestReposition();
+                       model->reposition();
+               }       
+
+               // Check if we are over another branch, but ignore 
+               // any found LMOs, which are FloatObjs
+               dst=model->findMapObj(mapToScene(e->pos() ), lmosel);
+
+               if (dst && (typeid(*dst)!=typeid(BranchObj) && typeid(*dst)!=typeid(MapCenterObj))) 
+                       dst=NULL;
+               
+               BranchObj *bo=xelection.getBranch();
+               if (bo && bo->getDepth()==0)
+               {       
+            if (movingObj_orgPos != bo->getAbsPos())
+            {
+                QString pold=qpointfToString(movingObj_orgPos);
+                QString pnow=qpointfToString(bo->getAbsPos());
+                saveState(
+                    fo,
+                    "move "+pold,
+                    fo,
+                    "move "+pnow,
+                    QString("Move mapcenter %1 to position %2").arg(getName(bo)).arg(pnow));
+            }
+               }
+       
+               if (xelection.type() == Selection::Branch )
+               {       // A branch was moved
+                       
+                       // save the position in case we link to mapcenter
+                       QPointF savePos=QPointF (lmosel->getAbsPos()  );
+
+                       // Reset the temporary drawn link to the original one
+                       lmosel->unsetParObjTmp();
+
+                       // For Redo we may need to save original selection
+                       QString preSelStr=model->getSelectString(lmosel);
+
+                       copyingObj=false;       
+                       if (dst ) 
+                       {
+                               // We have a destination, relink to that
+
+                               BranchObj* bsel=xelection.getBranch();
+                               BranchObj* bdst=(BranchObj*)dst;
+
+                               QString preParStr=model->getSelectString (bsel->getParObj());
+                               QString preNum=QString::number (bsel->getNum(),10);
+                               QString preDstParStr;
+
+                               if (e->state() & Qt::ShiftModifier && dst->getParObj())
+                               {       // Link above dst
+                                       preDstParStr=model->getSelectString (dst->getParObj());
+                                       bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum());
+                               } else 
+                               if (e->state() & Qt::ControlModifier && dst->getParObj())
+                               {
+                                       // Link below dst
+                                       preDstParStr=model->getSelectString (dst->getParObj());
+                                       bsel->linkTo ( (BranchObj*)(bdst->getParObj()), bdst->getNum()+1);
+                               } else  
+                               {       // Append to dst
+                                       preDstParStr=model->getSelectString(dst);
+                                       bsel->linkTo (bdst,-1);
+                                       if (dst->getDepth()==0) bsel->move (savePos);
+                               } 
+                               QString postSelStr=model->getSelectString(lmosel);
+                               QString postNum=QString::number (bsel->getNum(),10);
+
+                               QString undoCom="linkTo (\""+ 
+                                       preParStr+ "\"," + preNum  +"," + 
+                                       QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")";
+
+                               QString redoCom="linkTo (\""+ 
+                                       preDstParStr + "\"," + postNum + "," +
+                                       QString ("%1,%2").arg(savePos.x()).arg(savePos.y())+ ")";
+
+                               saveState (
+                                       postSelStr,undoCom,
+                                       preSelStr, redoCom,
+                                       QString("Relink %1 to %2").arg(getName(bsel)).arg(getName(dst)) );
+
+                               model->reposition();    // not necessary if we undo temporary move  below
+                       } else
+                       {
+                               // No destination, undo  temporary move
+
+                               if (lmosel->getDepth()==1)
+                               {
+                                       // The select string might be different _after_ moving around.
+                                       // Therefor reposition and then use string of old selection, too
+                                       model->reposition();
+
+                    QPointF rp(lmosel->getRelPos());
+                    if (rp != movingObj_orgRelPos)
+                    {
+                        QString ps=qpointfToString(rp);
+                        saveState(
+                            model->getSelectString(lmosel), "moveRel "+qpointfToString(movingObj_orgRelPos), 
+                            preSelStr, "moveRel "+ps, 
+                            QString("Move %1 to relative position %2").arg(getName(lmosel)).arg(ps));
+                    }
+                               }
+
+                               // Draw the original link, before selection was moved around
+                               if (settings.value("/animation/use",false).toBool() && lmosel->getDepth()>1) 
+                               {
+                                       QPointF p=bo->getParObj()->getChildPos();
+                                       lmosel->setRelPos();    // calc relPos first
+                                       model->startAnimation(
+                                               lmosel->getRelPos(),
+                                               QPointF (movingObj_orgPos.x() - p.x(), movingObj_orgPos.y() - p.y() )
+                                       );      
+                               } else  
+                                       model->reposition();
+                       }
+               }
+                xelection.update();
+               // Finally resize scene, if needed
+               scene()->update();
+               movingObj=NULL;         
+
+               // Just make sure, that actions are still ok,e.g. the move branch up/down buttons...
+               updateActions();
+       } else 
+               // maybe we moved View: set old cursor
+               setCursor (Qt::ArrowCursor);
+    
+}
+
+void MapEditor::mouseDoubleClickEvent(QMouseEvent* e)
+{
+       if (isSelectBlocked() ) 
+       {
+               e->ignore();
+               return;
+       }
+
+       if (e->button() == Qt::LeftButton )
+       {
+               QPointF p = mapToScene(e->pos());
+               LinkableMapObj *lmo=model->findMapObj(p, NULL);
+               if (lmo) {      // MapObj was found
+                       // First select the MapObj than edit heading
+                       xelection.select(lmo);
+                       mainWindow->editHeading();
+               }
+       }
+}
+
+void MapEditor::resizeEvent (QResizeEvent* e)
+{
+       QGraphicsView::resizeEvent( e );
+}
+
+void MapEditor::dragEnterEvent(QDragEnterEvent *event)
+{
+       //for (unsigned int i=0;event->format(i);i++) // Debug mime type
+       //      cerr << event->format(i) << endl;
+
+       if (event->mimeData()->hasImage())
+               event->acceptProposedAction();
+       else    
+               if (event->mimeData()->hasUrls())
+                       event->acceptProposedAction();
+}
+
+void MapEditor::dragMoveEvent(QDragMoveEvent *)
+{
+}
+
+void MapEditor::dragLeaveEvent(QDragLeaveEvent *event)
+{
+       event->accept();
+}
+
+void MapEditor::dropEvent(QDropEvent *event)
+{
+       BranchObj *sel=xelection.getBranch();
+       if (sel)
+       {
+               if (debug)
+                       foreach (QString format,event->mimeData()->formats()) 
+                               cout << "MapEditor: Dropped format: "<<qPrintable (format)<<endl;
+
+
+               QList <QUrl> uris;
+               if (event->mimeData()->hasImage()) 
+               {
+                        QVariant imageData = event->mimeData()->imageData();
+                        addFloatImageInt (qvariant_cast<QPixmap>(imageData));
+               } else
+               if (event->mimeData()->hasUrls())
+                       uris=event->mimeData()->urls();
+
+               if (uris.count()>0)
+               {
+                       QStringList files;
+                       QString s;
+                       QString heading;
+                       BranchObj *bo;
+                       for (int i=0; i<uris.count();i++)
+                       {
+                               // Workaround to avoid adding empty branches
+                               if (!uris.at(i).toString().isEmpty())
+                               {
+                                       bo=sel->addBranch();
+                                       if (bo)
+                                       {
+                                               s=uris.at(i).toLocalFile();
+                                               if (!s.isEmpty()) 
+                                               {
+                                                  QString file = QDir::fromNativeSeparators(s);
+                                                  heading = QFileInfo(file).baseName();
+                                                  files.append(file);
+                                                  if (file.endsWith(".vym", false))
+                                                          bo->setVymLink(file);
+                                                  else
+                                                          bo->setURL(uris.at(i).toString());
+                                          } else 
+                                          {
+                                                  bo->setURL(uris.at(i).toString());
+                                          }
+
+                                          if (!heading.isEmpty())
+                                                  bo->setHeading(heading);
+                                          else
+                                                  bo->setHeading(uris.at(i).toString());
+                                       }
+                               }
+                       }
+                       model->reposition();
+               }
+       }       
+       event->acceptProposedAction();
+}
+
+
+void MapEditor::sendSelection()
+{
+       if (netstate!=Server) return;
+       sendData (QString("select (\"%1\")").arg(xelection.getSelectString()) );
+}
+
+void MapEditor::newServer()
+{
+       port=54321;
+       sendCounter=0;
+    tcpServer = new QTcpServer(this);
+    if (!tcpServer->listen(QHostAddress::Any,port)) {
+        QMessageBox::critical(this, "vym server",
+                              QString("Unable to start the server: %1.").arg(tcpServer->errorString()));
+        close();
+        return;
+    }
+       connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newClient()));
+       netstate=Server;
+       cout<<"Server is running on port "<<tcpServer->serverPort()<<endl;
+}
+
+void MapEditor::connectToServer()
+{
+       port=54321;
+       server="salam.suse.de";
+       server="localhost";
+       clientSocket = new QTcpSocket (this);
+       clientSocket->abort();
+    clientSocket->connectToHost(server ,port);
+       connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readData()));
+    connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+            this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
+       netstate=Client;                
+       cout<<"connected to "<<qPrintable (server)<<" port "<<port<<endl;
+
+       
+}
+
+void MapEditor::newClient()
+{
+    QTcpSocket *newClient = tcpServer->nextPendingConnection();
+    connect(newClient, SIGNAL(disconnected()),
+            newClient, SLOT(deleteLater()));
+
+       cout <<"ME::newClient  at "<<qPrintable( newClient->peerAddress().toString() )<<endl;
+
+       clientList.append (newClient);
+}
+
+
+void MapEditor::sendData(const QString &s)
+{
+       if (clientList.size()==0) return;
+
+       // Create bytearray to send
+       QByteArray block;
+    QDataStream out(&block, QIODevice::WriteOnly);
+    out.setVersion(QDataStream::Qt_4_0);
+
+       // Reserve some space for blocksize
+    out << (quint16)0;
+
+       // Write sendCounter
+    out << sendCounter++;
+
+       // Write data
+    out << s;
+
+       // Go back and write blocksize so far
+    out.device()->seek(0);
+    quint16 bs=(quint16)(block.size() - 2*sizeof(quint16));
+       out << bs;
+
+       if (debug)
+               cout << "ME::sendData  bs="<<bs<<"  counter="<<sendCounter<<"  s="<<qPrintable(s)<<endl;
+
+       for (int i=0; i<clientList.size(); ++i)
+       {
+               //cout << "Sending \""<<qPrintable (s)<<"\" to "<<qPrintable (clientList.at(i)->peerAddress().toString())<<endl;
+               clientList.at(i)->write (block);
+       }
+}
+
+void MapEditor::readData ()
+{
+       while (clientSocket->bytesAvailable() >=(int)sizeof(quint16) )
+       {
+               if (debug)
+                       cout <<"readData  bytesAvail="<<clientSocket->bytesAvailable();
+               quint16 recCounter;
+               quint16 blockSize;
+
+               QDataStream in(clientSocket);
+               in.setVersion(QDataStream::Qt_4_0);
+
+               in >> blockSize;
+               in >> recCounter;
+               
+               QString t;
+               in >>t;
+               if (debug)
+                       cout << "  t="<<qPrintable (t)<<endl;
+               parseAtom (t);
+       }
+       return;
+}
+
+void MapEditor::displayNetworkError(QAbstractSocket::SocketError socketError)
+{
+    switch (socketError) {
+    case QAbstractSocket::RemoteHostClosedError:
+        break;
+    case QAbstractSocket::HostNotFoundError:
+        QMessageBox::information(this, vymName +" Network client",
+                                 "The host was not found. Please check the "
+                                    "host name and port settings.");
+        break;
+    case QAbstractSocket::ConnectionRefusedError:
+        QMessageBox::information(this, vymName + " Network client",
+                                 "The connection was refused by the peer. "
+                                    "Make sure the fortune server is running, "
+                                    "and check that the host name and port "
+                                    "settings are correct.");
+        break;
+    default:
+        QMessageBox::information(this, vymName + " Network client",
+                                 QString("The following error occurred: %1.")
+                                 .arg(clientSocket->errorString()));
+    }
+}
+
+void MapEditor::autosave()
+{
+       QDateTime now=QDateTime().currentDateTime();
+       /* FIXME debug
+       cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n"; 
+       cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
+       cout << "  fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
+       cout << "  time: "<<qPrintable (now.toString())<<endl;
+       cout << " zipped="<<zipped<<endl;
+       */
+       // Disable autosave, while we have gone back in history
+       int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
+       if (redosAvail>0) return;
+
+       // Also disable autosave for new map without filename
+       if (filePath.isEmpty()) return;
+
+
+       if (mapUnsaved &&mapChanged && settings.value ("/mapeditor/autosave/use",true).toBool() )
+       {
+               if (QFileInfo(filePath).lastModified()<=fileChangedTime) 
+                       mainWindow->fileSave (this);
+               else
+                       if (debug)
+                               cout <<"  ME::autosave  rejected, file on disk is newer than last save.\n"; 
+
+       }       
+}
+
+void MapEditor::fileChanged()
+{
+       // Check if file on disk has changed meanwhile
+       if (!filePath.isEmpty())
+       {
+               QDateTime tmod=QFileInfo (filePath).lastModified();
+               if (tmod>fileChangedTime)
+               {
+                       
+                       /* FIXME debug message, sometimes there's a glitch in the metrics...
+                       cout << "ME::fileChanged()\n" 
+                            << "  last saved:     "<<qPrintable (fileChangedTime.toString())<<endl
+                                << "  last modififed: "<<qPrintable (tmod.toString())<<endl;
+                       */       
+                       // FIXME switch to current mapeditor and finish lineedits...
+                       QMessageBox mb( vymName,
+                               tr("The file of the map  on disk has changed:\n\n"  
+                                  "   %1\n\nDo you want to reload that map with the new file?").arg(filePath),
+                               QMessageBox::Question,
+                               QMessageBox::Yes ,
+                               QMessageBox::Cancel | QMessageBox::Default,
+                               QMessageBox::NoButton );
+
+                       mb.setButtonText( QMessageBox::Yes, tr("Reload"));
+                       mb.setButtonText( QMessageBox::No, tr("Ignore"));
+                       switch( mb.exec() ) 
+                       {
+                               case QMessageBox::Yes:
+                                       // Reload map
+                                       load (filePath,NewMap,fileType);
+                       case QMessageBox::Cancel:
+                                       fileChangedTime=tmod; // allow autosave to overwrite newer file!
+                       }
+               }
+       }       
+
+}
+
+
+/*TODO not needed? void MapEditor::contentsDropEvent(QDropEvent *event) 
+{
+
+               } else if (event->provides("application/x-moz-file-promise-url") && 
+                        event->provides("application/x-moz-nativeimage")) 
+               {
+                       // Contains url to the img src in unicode16
+                       QByteArray d = event->encodedData("application/x-moz-file-promise-url");
+                       QString url = QString((const QChar*)d.data(),d.size()/2);
+                       fetchImage(url);
+                       event->accept();
+                       update=true;
+               } else if (event->provides ("text/uri-list"))
+               {       // Uris provided e.g. by konqueror
+                       Q3UriDrag::decode (event,uris);
+               } else if (event->provides ("_NETSCAPE_URL"))
+               {       // Uris provided by Mozilla
+                 QStringList l = QStringList::split("\n", event->encodedData("_NETSCAPE_URL"));
+                 uris.append(l[0]);
+                 heading = l[1];
+               } else if (event->provides("text/html")) {
+
+                 // Handels text mime types
+                 // Look like firefox allways handle text as unicode16 (2 bytes per char.)
+                 QByteArray d = event->encodedData("text/html");
+                 QString text;
+                 if (isUnicode16(d)) 
+                   text = QString((const QChar*)d.data(),d.size()/2);
+                 else 
+                   text = QString(d);
+
+                 textEditor->setText(text);
+
+                 event->accept();
+                 update=true;
+               } else if (event->provides("text/plain")) {
+                 QByteArray d = event->encodedData("text/plain");
+                 QString text;
+                 if (isUnicode16(d))
+                   text = QString((const QChar*)d.data(),d.size()/2);
+                 else 
+                   text = QString(d);
+
+                 textEditor->setText(text);
+                 
+                 event->accept();
+                 update= true;
+               }
+
+               */
+
+
+
+bool isUnicode16(const QByteArray &d) 
+{
+  // TODO: make more precise check for unicode 16.
+  // Guess unicode16 if any of second bytes are zero
+  unsigned int length = max(0,d.size()-2)/2;
+  for (unsigned int i = 0; i<length ; i++)
+    if (d.at(i*2+1)==0) return true;
+  return false;
+}
+      
+void MapEditor::addFloatImageInt (const QPixmap &img) 
+{
+       BranchObj *bo=xelection.getBranch();
+       if (bo)
+  {
+       FloatImageObj *fio=bo->addFloatImage();
+    fio->load(img);
+    fio->setOriginalFilename("No original filename (image added by dropevent)");       
+       QString s=model->getSelectString(bo);
+       saveState (PartOfMap, s, "nop ()", s, "copy ()","Copy dropped image to clipboard",fio  );
+       saveState (fio,"delete ()", bo,QString("paste(%1)").arg(curStep),"Pasting dropped image");
+    model->reposition();
+    scene()->update();
+  }
+}
+
+/*
+
+void MapEditor::imageDataFetched(const QByteArray &a, Q3NetworkOperation * / *nop* /) 
+{
+  if (!imageBuffer) imageBuffer = new QBuffer();
+  if (!imageBuffer->isOpen()) {
+    imageBuffer->open(QIODevice::WriteOnly | QIODevice::Append);
+  }
+  imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a));
+}
+
+
+void MapEditor::imageDataFinished(Q3NetworkOperation *nop) 
+{
+       if (nop->state()==Q3NetworkProtocol::StDone) {
+               QPixmap img(imageBuffer->buffer());
+               addFloatImageInt (img);
+       }
+
+       if (imageBuffer) {
+               imageBuffer->close();
+               if (imageBuffer) {
+                       imageBuffer->close();
+                       delete imageBuffer;
+                       imageBuffer = 0;
+               }
+       }
+}
+
+void MapEditor::fetchImage(const QString &url) 
+{
+  if (urlOperator) {
+    urlOperator->stop();
+    disconnect(urlOperator);
+    delete urlOperator;
+  }
+  
+  urlOperator = new Q3UrlOperator(url);
+  connect(urlOperator, SIGNAL(finished(Q3NetworkOperation *)), 
+         this, SLOT(imageDataFinished(Q3NetworkOperation*)));
+
+  connect(urlOperator, SIGNAL(data(const QByteArray &, Q3NetworkOperation *)),
+         this, SLOT(imageDataFetched(const QByteArray &, Q3NetworkOperation *)));
+  urlOperator->get();
+}
+*/
+