diff -r 000000000000 -r 512536ce7773 mapeditor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapeditor.cpp Sun Jan 30 12:59:03 2005 +0000 @@ -0,0 +1,3062 @@ +#include "mapeditor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "version.h" + +#include "xml.h" +#include "texteditor.h" +#include "linkablemapobj.h" +#include "exports.h" +#include "misc.h" +#include "mainwindow.h" +#include "extrainfodialog.h" +#include "settings.h" + +#include "icons/flag-note.xpm" +#include "icons/flag-url.xpm" +#include "icons/flag-vymlink.xpm" +#include "icons/flag-scrolled-right.xpm" +#include "icons/flag-tmpUnscrolled-right.xpm" +#include "icons/flag-questionmark.xpm" +#include "icons/flag-exclamationmark.xpm" +#include "icons/flag-hook-green.xpm" +#include "icons/flag-cross-red.xpm" +#include "icons/flag-stopsign.xpm" +#include "icons/flag-smiley-good.xpm" +#include "icons/flag-smiley-sad.xpm" +#include "icons/flag-clock.xpm" +#include "icons/flag-lamp.xpm" +#include "icons/flag-arrow-up.xpm" +#include "icons/flag-arrow-down.xpm" +#include "icons/flag-thumb-up.xpm" +#include "icons/flag-thumb-down.xpm" +#include "icons/flag-heart.xpm" +#include "icons/flag-flash.xpm" +#include "icons/flag-lifebelt.xpm" + +extern TextEditor *textEditor; +extern int statusbarTime; +extern Main *mainWindow; +extern FlagRowObj *systemFlagsDefault; +extern FlagRowObj *standardFlagsDefault; +extern MapEditor *clipboardME; + +extern QAction *actionFileSave; +extern QAction *actionEditUndo; +extern QAction *actionEditCopy; +extern QAction *actionEditCut; +extern QAction *actionEditPaste; +extern QAction *actionEditMoveUp; +extern QAction *actionEditMoveDown; +extern QAction *actionEditToggleScroll; +extern QAction *actionEditOpenURL; +extern QAction *actionEditURL; +extern QAction *actionEditHeading2URL; +extern QAction *actionEditBugzilla2URL; +extern QAction *actionEditOpenVymLink; +extern QAction *actionEditVymLink; +extern QAction *actionEditDeleteVymLink; +extern QAction *actionEditHeading; +extern QAction *actionEditDelete; +extern QAction *actionEditAddBranch; +extern QAction *actionEditAddBranchAbove; +extern QAction *actionEditAddBranchBelow; +extern QAction *actionEditImportAdd; +extern QAction *actionEditImportReplace; +extern QAction *actionEditSaveBranch; +extern QAction *actionEditSelectFirst; +extern QAction *actionEditSelectLast; +extern QAction *actionEditLoadImage; +extern QAction *actionEditToggleFloatExport; + +extern QAction* actionFormatPickColor; +extern QAction* actionFormatColorBranch; +extern QAction* actionFormatColorSubtree; +extern QAction *actionFormatLinkColorHint; +extern QAction *actionFormatBackColor; +extern QAction *actionFormatLinkColor; + +extern QActionGroup *actionGroupFormatFrameTypes; +extern QAction *actionFormatFrameNone; +extern QAction *actionFormatFrameRectangle; + +extern QActionGroup *actionGroupFormatLinkStyles; +extern QAction *actionFormatLinkStyleLine; +extern QAction *actionFormatLinkStyleParabel; +extern QAction *actionFormatLinkStylePolyLine; +extern QAction *actionFormatLinkStylePolyParabel; + +extern QAction *actionViewToggleNoteEditor; + +extern QAction *actionSettingsAutoedit; +extern QAction *actionSettingsAutoselectHeading; +extern QAction *actionSettingsAutoselectText; +extern QAction *actionSettingsPasteNewHeading; + +extern QPopupMenu *branchContextMenu; +extern QPopupMenu *floatimageContextMenu; +extern QPopupMenu *saveImageFormatMenu; +extern QPopupMenu *exportImageFormatMenu; +extern QPopupMenu *canvasContextMenu; + +extern Settings settings; + + +/////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// +MapEditor::MapEditor( + QWidget* parent, bool interactive, const char* name, WFlags f) : + QCanvasView(parent,name,f) +{ + //cout << "Constructor ME "<setAdvancePeriod(30); + + setCanvas (mapCanvas); + + setVScrollBarMode ( QScrollView::AlwaysOn ); + setHScrollBarMode ( QScrollView::AlwaysOn ); + + // Now create the _global_ system flags _once_: + // (Later all OrnamentedObj copy from this + // and set their own canvas) + if (!systemFlagsDefault) + { + systemFlagsDefault = new FlagRowObj (mapCanvas); + systemFlagsDefault->setVisibility (false); + systemFlagsDefault->setName ("systemFlagsDef"); + + FlagObj *fo = new FlagObj (mapCanvas); + fo->load(QPixmap(flag_note_xpm)); + fo->setName("note"); + fo->setToolTip(tr("Note")); + systemFlagsDefault->addFlag (fo); // makes deep copy + + fo->load(QPixmap(flag_url_xpm)); + fo->setName("url"); + fo->setToolTip(tr("WWW Document (external)")); + systemFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_vymlink_xpm)); + fo->setName("vymLink"); + fo->setToolTip(tr("Link to another vym map")); + systemFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_scrolled_right_xpm)); + fo->setName("scrolledright"); + fo->setToolTip(tr("subtree is scrolled")); + systemFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_tmpUnscrolled_right_xpm)); + fo->setName("tmpUnscrolledright"); + fo->setToolTip(tr("subtree is temporary scrolled")); + systemFlagsDefault->addFlag (fo); + delete (fo); + } + if (!standardFlagsDefault) + { + standardFlagsDefault = new FlagRowObj (mapCanvas); + standardFlagsDefault->setVisibility (false); + standardFlagsDefault->setName ("standardFlagsDef"); + + FlagObj *fo = new FlagObj (mapCanvas); + fo->load(QPixmap(flag_exclamationmark_xpm)); + fo->setName("exclamationmark"); + fo->setToolTip(tr("Take care!")); + standardFlagsDefault->addFlag (fo); // makes deep copy + + fo->load(QPixmap(flag_questionmark_xpm)); + fo->setName("questionmark"); + fo->setToolTip(tr("Really?")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_hook_green_xpm)); + fo->setName("hook-green"); + fo->setToolTip(tr("ok!")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_cross_red_xpm)); + fo->setName("cross-red"); + fo->setToolTip(tr("Not ok!")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_stopsign_xpm)); + fo->setName("stopsign"); + fo->setToolTip(tr("This won't work!")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_smiley_good_xpm)); + fo->setName("smiley-good"); + fo->setToolTip(tr("Good")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_smiley_sad_xpm)); + fo->setName("smiley-sad"); + fo->setToolTip(tr("Bad")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_clock_xpm)); + fo->setName("clock"); + fo->setToolTip(tr("Time critical")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_lamp_xpm)); + fo->setName("lamp"); + fo->setToolTip(tr("Idea!")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_arrow_up_xpm)); + fo->setName("arrow-up"); + fo->setToolTip(tr("Important")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_arrow_down_xpm)); + fo->setName("arrow-down"); + fo->setToolTip(tr("Unimportant")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_thumb_up_xpm)); + fo->setName("thumb-up"); + fo->setToolTip(tr("I like this")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_thumb_down_xpm)); + fo->setName("thumb-down"); + fo->setToolTip(tr("I do not like this")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_heart_xpm)); + fo->setName("heart"); + fo->setToolTip(tr("I just love... ")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_flash_xpm)); + fo->setName("flash"); + fo->setToolTip(tr("Dangerous")); + standardFlagsDefault->addFlag (fo); + + fo->load(QPixmap(flag_lifebelt_xpm)); + fo->setName("lifebelt"); + fo->setToolTip(tr("This will help")); + standardFlagsDefault->addFlag (fo); + delete (fo); + + } + + mapCenter = new MapCenterObj(mapCanvas); + mapCenter->setVisibility (true); + mapCenter->setMapEditor (this); + mapCenter->setHeading (tr("New Map")); + + printer=NULL; + + lineedit = new QLineEdit(this, "lineedit" ); + connect( lineedit, SIGNAL( returnPressed() ), SLOT( finishedLineEditNoSave() ) ); + lineedit->hide(); + + actColor=black; setColor (actColor); + deflinkcolor=QColor (0,0,255); + linkcolorhint=DefaultColor; + linkstyle=StylePolyParabel; + mapCanvas->setBackgroundColor (white); + + // Create bitmap cursors, patform dependant + #if defined(Q_OS_MACX) + #include "icons/cursorhandopen16.xpm" + #include "icons/cursorcolorpicker16.xpm" + QBitmap cb( 16, 16, chandopen, TRUE ); + QBitmap cm( 16, 16, chandopenmask, TRUE ); + handOpenCursor=QCursor ( cb, cm ); + // set hot spot to tip of picker + pickColorCursor=QCursor ( cursorcolorpicker_xpm, 1,15 ); + #else + #include "icons/cursorhandopen.xpm" + #include "icons/cursorcolorpicker.xpm" + + QBitmap cb( 32, 32, chandopen, TRUE ); + QBitmap cm( 32, 32, chandopenmask, TRUE ); + handOpenCursor=QCursor ( cb, cm ); + // set hot spot to tip of picker + pickColorCursor=QCursor ( cursorcolorpicker_xpm, 5,27 ); + #endif + + + pickingColor=false; + + editingBO=NULL; + selection=NULL; + selectionLast=NULL; + movingObj=NULL; + + mapChanged=false; + mapDefault=true; + mapUnsaved=false; + undoSelection=NULL; + + zipped=true; + filePath=""; + fileName="unnamed"; + mapName=""; + + // Initialize find routine + itFind=NULL; + EOFind=false; + + printFrame=true; + printFooter=true; + + blockreposition=false; + isInteractive=interactive; + if (isInteractive) + // Create temporary files + makeTmpDirs(); + + // Initially set movingCentre + updateViewCenter(); + + mapCenter->reposition(); // for positioning heading +} + +MapEditor::~MapEditor() +{ + //cout <<"Destructor MapEditor\n"; + if (isInteractive) delTmpDirs(); + + // Save Settings + //settings.writeEntry( "/vym/mapeditor/editmode/autoselect", ); + +} + +QColor MapEditor::color() +{ + return actColor; +} + +QColor MapEditor::backgroundColor() +{ + return mapCanvas->backgroundColor(); +} + +MapCenterObj* MapEditor::getMapCenter() +{ + return mapCenter; +} + +QCanvas* MapEditor::getCanvas() +{ + return mapCanvas; +} + +void MapEditor::adjustCanvasSize() +{ + // To adjust the canvas to map, viewport size and position, we have to + // do some coordinate magic... + // + // Get rectangle of (scroll-)view. + // We want to be in canvas coords, so + // we map. Important if view is zoomed... + QRect view = inverseWorldMatrix().mapRect( QRect( contentsX(), contentsY(), + visibleWidth(), visibleHeight()) ); + + // Now we need the bounding box of view AND map to calc the correct canvas size. + // Why? Because if the map itself is moved out of view, the view has to be enlarged + // to avoid jumping aroung... + QRect map=mapCenter->getTotalBBox(); + + // right edge - left edge + int cw= max(map.x() + map.width(), view.x() + view.width()) - min(map.x(), view.x()); + int ch= max(map.y() + map.height(), view.y() + view.height()) - min(map.y(), view.y()); + + + if ( (cw!=mapCanvas->width()) || (ch!=mapCanvas->height()) || + !mapCanvas->onCanvas (map.topLeft()) || !mapCanvas->onCanvas (map.bottomRight()) + ) + { + // move the map on canvas (in order to not move it on screen) this is neccessary + // a) if topleft corner of canvas is left or above topleft corner of view and also left of + // above topleft corner of map. E.g. if map is completly inside view, but it would be possible + // to scroll to an empty area of canvas to the left. + // b) if topleft corner of map left of or above topleft of canvas + int dx=0; + int dy=0; + + if (cw > mapCanvas->width() ) + { + if (map.x()<0) dx=-map.x(); + } + if (cw < mapCanvas->width() ) + dx=-min (view.x(),map.x()); + if (ch > mapCanvas->height() ) + { + if (map.y()<0) dy=-map.y(); + } + if (ch < mapCanvas->height() ) + { + dy=-min (view.y(),map.y()); + } + // We really have to resize now. Let's go... + mapCanvas->resize (cw,ch); + if ( (dx!=0) || (dy!=0) ) + { + mapCenter->moveAllBy(dx,dy); + mapCenter->reposition(); + + // scroll the view (in order to not move map on screen) + scrollBy (dx,dy); + } + } +} + +bool MapEditor::blockReposition() +{ + return blockreposition; +} + +void MapEditor::makeTmpDirs() +{ + // Create unique temporary directories + char tmpdir[]="/tmp/vym-XXXXXX"; + bakMapDir=mkdtemp(tmpdir); + makeSubDirs(bakMapDir); + // FIXME set permissions + // and maybe use QT method for portability +} + +void MapEditor::delTmpDirs() +{ + //FIXME delete tmp directory, better use QT methods here: + system ( "rm -rf "+ bakMapDir ); +} + + +void MapEditor::makeSubDirs(const QString &s) +{ + QDir d(s); + d.mkdir ("images"); + d.mkdir ("flags"); +} + + +QString MapEditor::saveToDir(const QString &tmpdir, const QString &prefix, bool writeflags, const QPoint &offset, SaveMode savemode) +{ + // tmpdir temporary directory to which data will be writte + // 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 canvas. + // Needed for XML export + // completeMap if false, only vympart will be written, without + // mapcenter + + // Save Header + QString ls; + switch (linkstyle) + { + case StyleLine: + ls="StyleLine"; + break; + case StyleParabel: + ls="StyleParabel"; + break; + case StylePolyLine: + ls="StylePolyLine"; + break; + default: + ls="StylePolyParabel"; + break; + } + + QString s="\n"; + QString colhint=""; + if (linkcolorhint==HeadingColor) + colhint=attribut("linkColorHint","HeadingColor"); + + QString mapAttr=attribut("version",__VYM_VERSION__); + if (savemode==CompleteMap) + mapAttr+= attribut("author",mapCenter->getAuthor()) + + attribut("comment",mapCenter->getComment()) + + attribut("date",mapCenter->getDate()) + + attribut("backgroundColor", mapCanvas->backgroundColor().name() ) + + attribut("linkStyle", ls ) + + attribut("linkColor", deflinkcolor.name() ) + + colhint; + s+=beginElement("vymmap",mapAttr); + incIndent(); + + // Find the used flags while traversing the tree + standardFlagsDefault->resetUsedCounter(); + + // Build xml recursivly + if (savemode==CompleteMap) + s+=mapCenter->saveToDir(tmpdir,prefix,writeflags,offset); + else + { + if ( undoSelection && + typeid(*undoSelection) == typeid(BranchObj) ) + s+=((BranchObj*)(undoSelection))->saveToDir(tmpdir,prefix,offset); + } + + // Save local settings + s+=settings.getXMLData (destPath); + + // Save selection + if (selection) + s+=valueElement("select",selection->getSelectString()); + + decIndent(); + s+=endElement("vymmap"); + + if (writeflags) + standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags); + + return s; +} + +void MapEditor::saveState() +{ + saveState (CompleteMap,NULL); +} + +void MapEditor::saveState(const SaveMode &mode, LinkableMapObj *part) +{ + // all binary data is saved in bakMapDir (created in Constructor) + // the xml data itself is kept in memory in backupXML + // + // For faster write/read of data, a part of the map can be + // written. Then the undoSelection will mark, which part of the + // map should be replaced if an undo is wanted later. + + if (mode==PartOfMap && part && (typeid(*part) == typeid (BranchObj) ) ) + { + // Writing a vympart only is useful for BranchObj + undoSelection=part; + backupXML=saveToDir (bakMapDir,mapName+"-",false, QPoint (),PartOfMap); + } else + { + undoSelection=NULL; + backupXML=saveToDir (bakMapDir,mapName+"-",false, QPoint (),CompleteMap); + } +} + +void MapEditor::finishedLineEditNoSave() +{ + // This is called by finishedLineEdit or any MapEditor method, + // which wants to assure, that lineedits finish, before e.g. a branch is + // deleted + + // After calling LineEdit and using the clipboard, the + // focus is not any longer on the main widget, we + // have to restore it using parentWidget()->setFocus() + + if (editingBO!=NULL) + { + editingBO->setHeading(lineedit->text() ); + editingBO=NULL; + lineedit->releaseKeyboard(); + lineedit->hide(); + parentWidget()->setFocus(); + mapCenter->reposition(); + adjustCanvasSize(); + ensureSelectionVisible(); + } +} + + +bool MapEditor::isDefault() +{ + return mapDefault; +} + +bool MapEditor::isUnsaved() +{ + return mapUnsaved; +} + +bool MapEditor::hasChanged() +{ + return mapChanged; +} + +void MapEditor::setChanged() +{ + mapChanged=true; + mapDefault=false; + mapUnsaved=true; + actionEditUndo->setEnabled (true); + actionFileSave->setEnabled (true); + findReset(); +} + +void MapEditor::closeMap() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + // Unselect before disabling the toolbar actions + if (selection) selection->unselect(); + selection=NULL; + updateActions(); + + clear(); + close(); +} + +void MapEditor::setFilePath(QString fname) +{ + setFilePath (fname,fname); +} + +void MapEditor::setFilePath(QString fname, QString destname) +{ + filePath=fname; + fileName=fname; + destPath=destname; + + // If fname is not an absolute path, complete it + filePath=QDir(fname).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) ); +} + +QString MapEditor::getFilePath() +{ + return filePath; +} + +QString MapEditor::getFileName() +{ + return fileName; +} + +QString MapEditor::getMapName() +{ + return mapName; +} + +QString MapEditor::getDestPath() +{ + return destPath; +} + +int MapEditor::load (QString &fname, const LoadMode &lmode) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + int returnCode=0; + + if (lmode==NewMap) + { + if (selection) selection->unselect(); + selection=NULL; + mapCenter->clear(); + mapCenter->setMapEditor(this); + // (map state is set later at end of load...) + } else + { + setChanged(); + saveState(PartOfMap,selection); + } + + + mapBuilderHandler handler; + QFile file( fname ); + + // I am paranoid: file should exist anyway + // according to check in mainwindow. + if (!file.exists() ) + { + QMessageBox::critical( 0, tr( "Critical Parse Error" ), + tr("Couldn't open map " +fname)+"."); + returnCode=1; + } else + { + blockreposition=true; + QXmlInputSource source( file); + QXmlSimpleReader reader; + reader.setContentHandler( &handler ); + reader.setErrorHandler( &handler ); + handler.setMapEditor( this ); + handler.setTmpDir (filePath.left(filePath.findRev("/",-1))); // needed to load files with rel. path + handler.setLoadMode (lmode); + bool ok = reader.parse( source ); + blockreposition=false; + file.close(); + if ( ok ) + { + mapCenter->reposition(); + adjustCanvasSize(); + if (lmode==NewMap) + { + mapDefault=false; + mapChanged=false; + mapUnsaved=false; + } + } 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 + } + } + updateActions(); + return returnCode; +} + +int MapEditor::save (const SaveMode &savemode) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + int returnCode=0; + + // Create mapName and fileDir + makeSubDirs (fileDir); + QString fname; + if (saveZipped()) + // save as .xml + fname=mapName+".xml"; + else + // use name given by user, even if he chooses .doc + fname=fileName; + + + // Check if fname is writeable + QFile file( fileDir+fname); + if (!file.open( IO_WriteOnly ) ) + { + QMessageBox::critical( 0, tr( "Critical Save Error" ), + tr("Couldn't write to ") +fileDir+fname); + return 1; + } + file.close(); + + QString saveFile; + saveFile=saveToDir (fileDir,mapName+"-",true,QPoint(),savemode); + + file.setName ( fileDir + fname); + if ( !file.open( IO_WriteOnly ) ) + { + // This should neverever happen + QMessageBox::critical(0, tr("Critcal save error"),"MapEditor::save() Couldn't open "+file.name()); + return 1; + } + + // Write it finally, and write in UTF8, no matter what + QTextStream ts( &file ); + ts.setEncoding (QTextStream::UnicodeUTF8); + ts << saveFile; + file.close(); + + if (returnCode==0) + { + mapChanged=false; + mapUnsaved=false; + actionFileSave->setEnabled(false); + } + + return returnCode; +} + +void MapEditor::setZipped (bool z) +{ + zipped=z; +} + +bool MapEditor::saveZipped () +{ + return zipped; +} + +void MapEditor::print() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if ( !printer ) + { + printer = new QPrinter; + printer->setColorMode (QPrinter::Color); + } + + QRect totalBBox=mapCenter->getTotalBBox(); + + // Try to set orientation automagically + // Note: Interpretation of generated postscript is amibiguous, if + // there are problems with landscape mode, see + // http://sdb.suse.de/de/sdb/html/jsmeix_print-cups-landscape-81.html + + if (totalBBox.width()>totalBBox.height()) + // recommend landscape + printer->setOrientation (QPrinter::Landscape); + else + // recommend portrait + printer->setOrientation (QPrinter::Portrait); + + if ( printer->setup(this) ) + // returns false, if printing is canceled + { + QPainter pp(printer); + + // Don't print the visualisation of selection + LinkableMapObj *oldselection=NULL; + if (selection) + { + oldselection=selection; + selection->unselect(); + } + + // Handle sizes of map and paper: + // + // setWindow defines which part of the canvas will be transformed + // setViewport defines area on paper in device coordinates (dpi) + // e.g. (0,50,700,700) is upper part on A4 + // see also /usr/lib/qt3/doc/html/coordsys.html + + QPaintDeviceMetrics metrics (printer); + + double paperAspect = (double)metrics.width() / (double)metrics.height(); + double mapAspect = (double)totalBBox.width() / (double)totalBBox.height(); + + QRect mapRect=mapCenter->getTotalBBox(); + QCanvasRectangle *frame=NULL; + QCanvasText *footerFN=NULL; + QCanvasText *footerDate=NULL; + if (printFrame || printFooter) + { + + if (printFrame) + { + // Print frame around map + mapRect.setRect (mapRect.x()-10, mapRect.y()-10, + mapRect.width()+20, mapRect.height()+20); + frame=new QCanvasRectangle (mapRect,mapCanvas); + frame->setBrush (QColor(white)); + frame->setPen (QColor(black)); + frame->setZ(0); + frame->show(); + } + if (printFooter) + { + // Print footer below map + QFont font; + font.setPointSize(10); + footerFN=new QCanvasText (mapCanvas); + footerFN->setText ("VYM - " + fileName); + footerFN->setFont(font); + footerFN->move (mapRect.x(), mapRect.y() + mapRect.height() ); + footerFN->setZ(Z_TEXT); + footerFN->show(); + footerDate=new QCanvasText (mapCanvas); + footerDate->setText (QDate::currentDate().toString(Qt::TextDate)); + footerDate->setFont(font); + footerDate->move (mapRect.x()+mapRect.width()-footerDate->boundingRect().width(), mapRect.y() + mapRect.height() ); + footerDate->setZ(Z_TEXT); + footerDate->show(); + mapRect.setRect (mapRect.x(), mapRect.y(), + mapRect.width(), mapRect.height()+20); + } + pp.setWindow (mapRect.x(), mapRect.y(), mapRect.width(), mapRect.height()); + } else + { + pp.setWindow (mapRect); + } + + if (mapAspect>=paperAspect) + { + // Fit horizontally to paper width + pp.setViewport(0,0, metrics.width(),(int)(metrics.width()/mapAspect) ); + } else + { + // Fit vertically to paper height + pp.setViewport(0,0,(int)(metrics.height()*mapAspect),metrics.height()); + } + + mapCanvas->drawArea(mapRect, &pp); // draw Canvas to printer + + // Delete Frame and footer + if (footerFN) + { + delete (footerFN); + delete (footerDate); + } + if (frame) delete (frame); + + // Restore selection + if (oldselection) + { + selection=oldselection; + selection->select(); + } + } +} + +QPixmap MapEditor::getPixmap() +{ + QRect mapRect=mapCenter->getTotalBBox(); + QPixmap pix (mapRect.size()); + QPainter pp (&pix); + + // Don't print the visualisation of selection + LinkableMapObj *oldselection=NULL; + if (selection) + { + oldselection=selection; + selection->unselect(); + } + + pp.setWindow (mapRect); + + mapCanvas->drawArea(mapRect, &pp); // draw Canvas to painter + + + // Restore selection + if (oldselection) + { + selection=oldselection; + selection->select(); + } + + return pix; +} + +void MapEditor::exportImage(QString fn) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + QPixmap pix (getPixmap()); + pix.save(fn, "PNG"); +} + +void MapEditor::exportImage(QString fn, int item) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + QPixmap pix (getPixmap()); + pix.save(fn, exportImageFormatMenu->text(item) ); +} + +void MapEditor::exportASCII() +{ + // FIXME still experimental + QFileDialog *fd=new QFileDialog( this, tr("VYM - Export (ASCII)")); + fd->addFilter ("TXT (*.txt)"); + fd->setCaption("VYM - Export (ASCII) (still experimental)"); + fd->setMode( QFileDialog::AnyFile ); + fd->show(); + + if ( fd->exec() == QDialog::Accepted ) + { + if (QFile (fd->selectedFile()).exists() ) + { + QMessageBox mb( "VYM", + tr("The file ") + fd->selectedFile() + + tr(" exists already. Do you want to overwrite it?"), + QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::Cancel | QMessageBox::Escape, + QMessageBox::NoButton ); + + mb.setButtonText( QMessageBox::Yes, tr("Overwrite") ); + mb.setButtonText( QMessageBox::No, tr("Cancel")); + Export ex; + switch( mb.exec() ) + { + case QMessageBox::Yes: + // save + if (!ex.setOutputDir ("out")) + { + QMessageBox::critical (0,tr("Critical Export Error "),tr("Couldn't create directory ") + "out"); + return; + } + break;; + case QMessageBox::Cancel: + // do nothing + return; + break; + } + } + Export ex; + ex.setPath (fd->selectedFile() ); + ex.setMapCenter(mapCenter); + ex.exportMap(); + } +} + + +void MapEditor::exportXML(const QString &dir) +{ + // Create subdirectories + makeSubDirs (dir); + + // write to directory + QString saveFile=saveToDir (dir,mapName+"-",true,mapCenter->getTotalBBox().topLeft() ,CompleteMap); + QFile file; + + file.setName ( dir + "/"+mapName+".xml"); + if ( !file.open( IO_WriteOnly ) ) + { + // This should neverever happen + QMessageBox::critical (0,tr("Critical Export Error"),tr("MapEditor::exportXML couldn't open ")+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"); +} + +void MapEditor::clear() +{ + if (selection) + { + selection->unselect(); + selection=NULL; + } + + mapCenter->clear(); +} + +void MapEditor::undo() +{ + QDir d; + d.setPath(bakMapDir); + if (d.exists() ) + { + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (selection) + { + selection->unselect(); + selection=NULL; + } + + mapBuilderHandler handler; + QXmlInputSource source; + source.setData(backupXML); + QXmlSimpleReader reader; + reader.setContentHandler( &handler ); + reader.setErrorHandler( &handler ); + handler.setMapEditor( this ); + handler.setTmpDir ( bakMapDir ); // needed to load files with rel. path + if (undoSelection) + { + selection=undoSelection; + selection->select(); + handler.setLoadMode (ImportReplace); + + } else + { + mapCenter->clear(); + handler.setLoadMode (NewMap); + } + blockreposition=true; + bool ok = reader.parse( source ); + blockreposition=false; + if ( ok ) + mapCenter->reposition(); + + else + { + // This should never ever happen + QMessageBox::critical( 0, tr( "Critical Parse Error by reading backupFile" ), + tr( handler.errorProtocol() )+" in "+backupXML ); + } + // Undo not longer available now + actionEditUndo->setEnabled (false); + undoSelection=false; + mapChanged=false; + return; + } else + { + QMessageBox::critical( 0, tr( "Critical Error" ), + "Temporary directory " +bakMapDir + + tr (" used for undo is gone. \n" + "I will create a new one, but at the moment no undo is available.\n" + "Maybe you want to reload your original data.\n\n" + "Sorry for any inconveniences.") ); + makeTmpDirs(); + } +} + +void MapEditor::copy() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (selection) + { + if (typeid(*selection) == typeid(BranchObj) ) + { + BranchObj* to; + BranchObj* from; + clipboardME->clear(); + clipboardME->getMapCenter()->addBranch(); + to=clipboardME->getMapCenter()->getLastBranch(); + if (to) + { + from=(BranchObj*)(selection); + to->copy(from); + + // keep position relative to parent + to->move2RelPos ( from->getRelPos()); + + // select data in clipboard + clipboardME->select ("bo:0"); + + // repositioning makes testing nicer, + // but is not needed usually: + if (clipboardME->isVisible()) + { + clipboardME->getMapCenter()->reposition(); + } + else + clipboardME->hide(); + } + } + if (typeid(*selection) == typeid(FloatImageObj) ) + { + FloatImageObj* to; + FloatImageObj* from; + clipboardME->clear(); + clipboardME->getMapCenter()->addFloatImage(); + to=clipboardME->getMapCenter()->getLastFloatImage(); + if (to) + { + from=(FloatImageObj*)(selection); + to->copy(from); + + // select data in clipboard + clipboardME->select ("fi:0"); + + // repositioning makes testing nicer, + // but is not needed usually: + if (clipboardME->isVisible()) + { + clipboardME->getMapCenter()->reposition(); + } + else + clipboardME->hide(); + } + } + } +} + +LinkableMapObj* MapEditor::pasteNoSave() +{ + return pasteAtNoSave (-1); +} + +LinkableMapObj* MapEditor::pasteAtNoSave(int pos) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + LinkableMapObj *fromLMO=clipboardME->getSelection(); + LinkableMapObj *returnLMO=NULL; + + if (selection && fromLMO) + { + + if (typeid(*fromLMO) == typeid(BranchObj) ) + { + if (typeid(*selection) == typeid(MapCenterObj)) + { + returnLMO=mapCenter->addBranch( (BranchObj*)(fromLMO) ); + ((BranchObj*)(returnLMO))->move2RelPos(normalise(fromLMO->getRelPos() ) ); + } + if (typeid(*selection) == typeid(BranchObj)) + if (pos<0) + returnLMO=((BranchObj*)(selection))->addBranch((BranchObj*)(fromLMO) ); + else + { + BranchObj *par=(BranchObj*)(selection->getParObj()); + if (par) returnLMO=par->insertBranch((BranchObj*)(fromLMO),pos ); + } + } + + if (typeid(*fromLMO) == typeid(FloatImageObj) && + (typeid(*selection) == typeid (BranchObj) || + typeid(*selection)==typeid(MapCenterObj)) ) + returnLMO=((BranchObj*) (selection))->addFloatImage ((FloatImageObj*)(fromLMO)); + + } + return returnLMO; +} + +void MapEditor::cutNoSave() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + BranchObj* bo; + BranchObj* par; + if (selection != NULL) { + if (typeid(*selection) == typeid(BranchObj) ) + { + bo=(BranchObj*)(selection); + par=(BranchObj*)(bo->getParObj()); + bo->unselect(); + selection=NULL; + par->removeBranch(bo); + selection=par; + selection->select(); + } + if (typeid(*selection) == typeid(FloatImageObj) ) + { + FloatImageObj* fio=(FloatImageObj*)(selection); + par=(BranchObj*)(fio->getParObj()); + fio->unselect(); + selection=NULL; + par->removeFloatImage(fio); + selection=par; + selection->select(); + } + } +} + +void MapEditor::paste() +{ + setChanged(); + saveState(PartOfMap,selection); + pasteNoSave(); + mapCenter->reposition(); + adjustCanvasSize(); +} + +void MapEditor::cut() +{ + setChanged(); + saveState(PartOfMap,selection->getParObj()); + copy(); + cutNoSave(); + mapCenter->reposition(); + adjustCanvasSize(); +} + +void MapEditor::moveBranchUp() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + BranchObj* bo; + BranchObj* par; + if (typeid(*selection) == typeid(BranchObj) ) + { + setChanged(); + saveState(PartOfMap,selection->getParObj()); + bo=(BranchObj*)(selection); + par=(BranchObj*)(bo->getParObj()); + selection->unselect(); + selection=par->moveBranchUp (bo); + selection->select(); + mapCenter->reposition(); + ensureSelectionVisible(); + } +} + +void MapEditor::moveBranchDown() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + BranchObj* bo; + BranchObj* par; + if (typeid(*selection) == typeid(BranchObj) ) + { + setChanged(); + saveState(PartOfMap,selection->getParObj()); + bo=(BranchObj*)(selection); + par=(BranchObj*)(bo->getParObj()); + selection->unselect(); + selection=par->moveBranchDown(bo); + selection->select(); + mapCenter->reposition(); + ensureSelectionVisible(); + } +} + +void MapEditor::editHeading() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (selection && + (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj) ) ) + { + setChanged(); + saveState(PartOfMap,selection); + + ensureSelectionVisible(); + BranchObj *bo=(BranchObj*)(selection); + editingBO=(BranchObj*)(selection); + QPoint p = worldMatrix().map(QPoint (bo->x(),bo->y())); + lineedit->setGeometry(p.x()-contentsX(),p.y()-contentsY(),200,25); + QString s=bo->getHeading(); + lineedit->setText(s); + lineedit->setCursorPosition(1); + if (actionSettingsAutoselectText->isOn() && !s.isEmpty() && actionSettingsPasteNewHeading->isOn() ) + lineedit->selectAll(); + lineedit->show(); + + lineedit->grabKeyboard(); + lineedit->setFocus(); + } +} + + +void MapEditor::addNewBranch(int pos) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (selection && + (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj) ) ) + { + setChanged(); + saveState(PartOfMap,selection); + + BranchObj* bo1 = (BranchObj*) (selection); + bool wasScrolled=false; + BranchObj *newbo=NULL; + if (pos==0) + { + // save scroll state. If scrolled, automatically select + // new branch in order to tmp unscroll parent... + wasScrolled=bo1->isScrolled(); + newbo=bo1->addBranch(); + } else + { + BranchObj *parbo=(BranchObj*)(selection->getParObj()); + if (parbo) + { + if (pos<0) + // add above selection + newbo=parbo->insertBranch(bo1->getNum()); + else + // add below selection + newbo=parbo->insertBranch(bo1->getNum()+1); + } else + // This should not happen... + return; + + } + + LinkableMapObj *oldselection=selection; + + mapCenter->reposition(); + adjustCanvasSize(); + if (actionSettingsAutoedit->isOn() || + actionSettingsAutoselectHeading->isOn() ) + { + selection->unselect(); + selection=newbo; + selection->select(); + if (actionSettingsPasteNewHeading->isOn() ) + { + BranchObj *bo2= (BranchObj*)(selection); + bo2->setHeading(""); + } + if (actionSettingsAutoedit->isOn() ) + editHeading(); + if (!actionSettingsAutoselectHeading->isOn() + && !wasScrolled) + { + selection->unselect(); + selection=oldselection; + selection->select(); + } + } + } +} + +void MapEditor::deleteSelection() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (selection && typeid(*selection) ==typeid(BranchObj) ) + { + setChanged(); + saveState(PartOfMap,selection->getParObj()); + BranchObj* bo=dynamic_cast (selection); + BranchObj* par=(BranchObj*)(bo->getParObj()); + bo->unselect(); + selection=NULL; + par->removeBranch(bo); + selection=par; + selection->select(); + ensureSelectionVisible(); + mapCenter->reposition(); + adjustCanvasSize(); + } + if (selection && typeid(*selection) ==typeid(FloatImageObj) ) + { + setChanged(); + saveState(PartOfMap,selection->getParObj()); + FloatImageObj* fio=dynamic_cast (selection); + BranchObj* par=(BranchObj*)(fio->getParObj()); + fio->unselect(); + selection=NULL; + par->removeFloatImage(fio); + selection=par; + selection->select(); + ensureSelectionVisible(); + mapCenter->reposition(); + adjustCanvasSize(); + } +} + +LinkableMapObj* MapEditor::getSelection() +{ + return selection; +} + +bool MapEditor::select (QString s) +{ + LinkableMapObj *lmo=mapCenter; + QString part; + QString typ; + QString num; + while (!s.isEmpty() ) + { + part=s.section(",",0,0); + typ=part.left (3); + num=part.right(part.length() - 3); + + if (typ=="mc:") + { + if (num=="") + break; + else + lmo=mapCenter->getBranchNum (num.toUInt()); + } else + if (typ=="bo:") + lmo=((BranchObj*)(lmo))->getBranchNum (num.toUInt()); + else + if (typ=="fi:") + lmo=((BranchObj*)(lmo))->getFloatImageNum (num.toUInt()); + + + + if (!lmo) break; + + if (s.contains(",")) + s=s.right(s.length() - part.length() -1 ); + else + break; + } + + // Finally select the found object + if (lmo) + { + if (selection) selection->unselect(); + selection=lmo; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + return true; + } else + return false; + + +} + +void MapEditor::unselect() +{ + if (selection) + { + selectionLast=selection; + selection->unselect(); + selection=NULL; + } +} + +void MapEditor::reselect() +{ + if (selectionLast) + { + selection=selectionLast; + selection->select(); + selectionLast=NULL; + } +} + +void MapEditor::selectNextBranch() +{ + // Increase number of branch + if (selection) + { + QString s=selection->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=selection->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 (selection->getOrientation()==OrientRightOfCenter) + 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;icountBranches()>0) + s+=",bo:0"; + else + break; + } else + break; + } + + // try to select the freshly built string + found=select(s); + d--; + } + return; + } +} + +void MapEditor::selectPrevBranch() +{ + // Decrease number of branch + if (selection) + { + QString s=selection->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 precessor, + // try to decrease the parental number in order to + // find a precessor with same depth + + int d=selection->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.toUInt()-1); + s=s.section (",",0,d-2) + ","+ typ+num; + } else + { + // Special case, look at orientation + if (selection->getOrientation()==OrientRightOfCenter) + 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 last branch for each depth + for (i=d;icountBranches()>0) + s+=",bo:"+ QString ("%1").arg( ((BranchObj*)(selection))->countBranches()-1 ); + else + break; + else + break; + } + + // try to select the freshly built string + found=select(s); + d--; + } + return; + } +} + +void MapEditor::selectUpperBranch() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (selection) + { + if (typeid(*selection) == typeid(BranchObj)) + { + if (selection->getOrientation()==OrientRightOfCenter) + selectPrevBranch(); + else + if (selection->getDepth()==1) + selectNextBranch(); + else + selectPrevBranch(); + } + } +} + +void MapEditor::selectLowerBranch() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (selection) + { + if (typeid(*selection) == typeid(BranchObj)) + { + if (selection->getOrientation()==OrientRightOfCenter) + selectNextBranch(); + else + if (selection->getDepth()==1) + selectPrevBranch(); + else + selectNextBranch(); + } + } +} + + +void MapEditor::selectLeftBranch() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + BranchObj* bo; + BranchObj* par; + if (selection) + { + if (typeid(*selection) == typeid(MapCenterObj)) + { + par= (BranchObj*) (selection); + bo=par->getLastSelectedBranch(); + if (bo) + { + // Workaround for reselecting on left and right side + if (bo->getOrientation()==OrientRightOfCenter) + { + bo=par->getLastBranch(); + } + if (bo) + { + par->unselect(); + selection=bo; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + } + } + } else + { + par=(BranchObj*)(selection->getParObj()); + if (selection->getOrientation()==OrientRightOfCenter) + { + if (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(FloatImageObj)) + { + selection->unselect(); + selection=par; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + } + } else + { + if (typeid(*selection) == typeid(BranchObj) ) + { + bo=((BranchObj*)(selection))->getLastSelectedBranch(); + if (bo) + { + selection->unselect(); + selection=bo; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + } + } + } + } + } +} + +void MapEditor::selectRightBranch() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + BranchObj* bo; + BranchObj* par; + + if (selection) + { + if (typeid(*selection) == typeid(MapCenterObj)) + { + par= (BranchObj*) (selection); + bo=par->getLastSelectedBranch(); + if (bo) + { + // Workaround for relecting on left and right side + if (bo->getOrientation()==OrientLeftOfCenter) + bo=par->getFirstBranch(); + if (bo) + { + par->unselect(); + selection=bo; + selection->select(); + ensureSelectionVisible(); + } + } + } else + { + par=(BranchObj*)(selection->getParObj()); + if (selection->getOrientation()==OrientLeftOfCenter) + { + if (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(FloatImageObj)) + { + selection->unselect(); + selection=par; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + } + } else + { + if (typeid(*selection) == typeid(BranchObj) ) + { + bo=((BranchObj*)(selection))->getLastSelectedBranch(); + if (bo) + { + selection->unselect(); + selection=bo; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + } + } + } + } + } +} + +void MapEditor::selectFirstBranch() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + BranchObj *bo1; + BranchObj *bo2; + BranchObj* par; + if (selection) { + if (typeid(*selection) == typeid(BranchObj)) + { + bo1= (BranchObj*) (selection); + par=(BranchObj*)(bo1->getParObj()); + bo2=par->getFirstBranch(); + if (bo2) { + bo1->unselect(); + selection=bo2; + selection->select(); + ensureSelectionVisible(); + } + } + adjustCanvasSize(); + } +} + +void MapEditor::selectLastBranch() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + BranchObj *bo1; + BranchObj *bo2; + BranchObj* par; + if (selection) { + if (typeid(*selection) == typeid(BranchObj)) + { + bo1= (BranchObj*) (selection); + par=(BranchObj*)(bo1->getParObj()); + bo2=par->getLastBranch(); + if (bo2) { + bo1->unselect(); + selection=bo2; + selection->select(); + ensureSelectionVisible(); + } + } + adjustCanvasSize(); + } +} + +void MapEditor::setColor(QColor c) +{ + actColor=c; +} + +void MapEditor::selectBackgroundColor() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + QColor col = QColorDialog::getColor( mapCanvas->backgroundColor(), this ); + if ( !col.isValid() ) return; + setBackgroundColor( col ); + setChanged(); +} + +void MapEditor::setBackgroundColor(QColor c) +{ + mapCanvas->setBackgroundColor (c); +} + +QColor MapEditor::pickColor() +{ + if (selection) + { + if (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) + { + BranchObj *bo=(BranchObj*)(selection); + actColor=bo->getColor(); + } + } + return actColor; +} + +void MapEditor::colorItem() +{ + if (selection) + { + if (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) + { + setChanged(); + saveState(PartOfMap,selection); + BranchObj *bo=(BranchObj*)(selection); + bo->setColor(actColor, false); // color links, color childs + } + } +} + +void MapEditor::colorBranch() +{ + if (selection) + { + if (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) + { + setChanged(); + saveState(PartOfMap,selection); + BranchObj *bo=(BranchObj*)(selection); + bo->setColor(actColor, true); // color links, color childs + } + } +} + + +void MapEditor::toggleStandardFlag(QString f) +{ + if (selection) + { + setChanged(); + saveState(PartOfMap,selection); + ((BranchObj*)(selection))->toggleStandardFlag (f); + } +} + +void MapEditor::setViewCenter() +{ + // transform to CanvasView Coord: + QPoint p=worldMatrix().map(movingCenter); + center ( p.x(), p.y()); +} + + +BranchObj* MapEditor::findText (QString s, bool cs) +{ + if (!itFind) + { // Nothing found or new find process + if (EOFind) + // nothing found, start again + EOFind=false; + itFind=mapCenter->first(); + } + bool searching=true; + bool foundNote=false; + while (searching && !EOFind) + { + if (itFind) + { + // Searching in Note + if (itFind->getNote().contains(s,cs)) + { + if (selection!=itFind) + { + if (selection) ((BranchObj*)(selection))->unselect(); + selection=itFind; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + } + if (textEditor->findText(s,cs)) + { + searching=false; + foundNote=true; + } + } + // Searching in Heading + if (searching && itFind->getHeading().contains (s,cs) ) + { + if (selection) ((BranchObj*)(selection))->unselect(); + selection=itFind; + selection->select(); + adjustCanvasSize(); + ensureSelectionVisible(); + searching=false; + } + } + if (!foundNote) + { + itFind=itFind->next(); + if (!itFind) EOFind=true; + } + } + if (!searching) + { + adjustCanvasSize(); + return (BranchObj*)(selection); + } else + return NULL; +} + +void MapEditor::findReset() +{ // Necessary if text to find changes during a find process + itFind=NULL; + EOFind=false; +} + +void MapEditor::openURL() +{ + if (selection ) + { + if (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) + { + QString url=((BranchObj*)(selection))->getURL(); + + QProcess *proc = new QProcess( this ); + +#if !defined(Q_OS_MACX) + proc->addArgument( settings.readEntry("/vym/mainwindow/readerURL","konqueror" )); +#else + proc->addArgument( settings.readEntry("/vym/mainwindow/readerURL", + "/Applications/Safari.app/Contents/MacOS/Safari" )); +#endif + + proc->addArgument( url); + + if ( !proc->start() ) + // error handling + if (mainWindow->settingsURL() ) + openURL(); + } + } +} + +void MapEditor::editURL() +{ + if (selection && (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) ) + { + bool ok; + QString text = QInputDialog::getText( + "VYM", tr("Enter URL:"), QLineEdit::Normal, + ((BranchObj*)(selection))->getURL(), &ok, this ); + if ( ok) + { + // user entered something and pressed OK + ((BranchObj*)(selection))->setURL (text); + updateActions(); + setChanged(); + } + } +} + +void MapEditor::editHeading2URL() +{ + if (selection && (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) ) + { + BranchObj *b=(BranchObj*)(selection); + b->setURL (b->getHeading()); + updateActions(); + setChanged(); + } +} + +void MapEditor::editBugzilla2URL() +{ + if (selection && (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) ) + { + BranchObj *b=(BranchObj*)(selection); + b->setURL ("http://bugzilla.suse.de/show_bug.cgi?id="+b->getHeading()); + updateActions(); + setChanged(); + } +} + +void MapEditor::editVymLink() +{ + if (selection && (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) ) + { + QFileDialog *fd=new QFileDialog( this,tr("VYM - Link to another map")); + fd->addFilter (QString (tr("vym map") + " (*.vym)")); + fd->setCaption(tr("VYM - Link to another map")); + if (! ((BranchObj*)(selection))->getVymLink().isEmpty() ) + fd->setSelection( ((BranchObj*)(selection))->getVymLink() ); + fd->show(); + + QString fn; + if ( fd->exec() == QDialog::Accepted ) + ((BranchObj*)(selection))->setVymLink (fd->selectedFile() ); + updateActions(); + mapCenter->reposition(); + adjustCanvasSize(); + canvas()->update(); + setChanged(); + } +} + +void MapEditor::deleteVymLink() +{ + if (selection && (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) ) + { + ((BranchObj*)(selection))->setVymLink ("" ); + updateActions(); + mapCenter->reposition(); + adjustCanvasSize(); + canvas()->update(); + setChanged(); + } +} + +QString MapEditor::getVymLink() +{ + if (selection && (typeid(*selection) == typeid(BranchObj) || + typeid(*selection) == typeid(MapCenterObj)) ) + { + return ((BranchObj*)(selection))->getVymLink(); + } + return ""; + +} + +void MapEditor::editMapInfo() +{ + ExtraInfoDialog dia; + dia.setMapName (getFileName() ); + dia.setAuthor (mapCenter->getAuthor() ); + dia.setComment(mapCenter->getComment() ); + + // Calc some stats + QString stats; + int i=0; + QCanvasItemList l=canvas()->allItems(); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) + i++; + stats+=QString ("%1 items on canvas\n").arg (i,6); + + uint b=0; + uint f=0; + uint n=0; + BranchObj *bo; + bo=mapCenter->first(); + while (bo) + { + if (!bo->getNote().isEmpty() ) n++; + f+= bo->countFloatImages(); + b++; + bo=bo->next(); + } + stats+=QString ("%1 branches\n").arg (b-1,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) + { + mapCenter->setAuthor (dia.getAuthor() ); + mapCenter->setComment (dia.getComment() ); + setChanged(); + } +} + +void MapEditor::updateActions() +{ + if (getLinkColorHint()==HeadingColor) + actionFormatLinkColorHint->setOn(true); + else + actionFormatLinkColorHint->setOn(false); + + switch (linkstyle) + { + case StyleLine: + actionFormatLinkStyleLine->setOn(true); + break; + case StyleParabel: + actionFormatLinkStyleParabel->setOn(true); + break; + case StylePolyLine: + actionFormatLinkStylePolyLine->setOn(true); + break; + case StylePolyParabel: + actionFormatLinkStylePolyParabel->setOn(true); + break; + default: + break; + } + + QPixmap pix( 16, 16 ); + pix.fill( mapCanvas->backgroundColor() ); + actionFormatBackColor->setIconSet( pix ); + pix.fill( deflinkcolor ); + actionFormatLinkColor->setIconSet( pix ); + + actionEditUndo->setEnabled( mapChanged ); + actionFileSave->setEnabled( mapUnsaved ); + + if (selection) + { + if ( (typeid(*selection) == typeid(BranchObj)) || + (typeid(*selection) == typeid(MapCenterObj)) ) + { + standardFlagsDefault->setEnabled (true); + + if ( ((BranchObj*)(selection))->getURL().isEmpty() ) + actionEditOpenURL->setEnabled (false); + else + actionEditOpenURL->setEnabled (true); + actionEditURL->setEnabled (true); + actionEditHeading2URL->setEnabled (true); + actionEditBugzilla2URL->setEnabled (true); + + if ( ((BranchObj*)(selection))->getVymLink().isEmpty() ) + { + actionEditOpenVymLink->setEnabled (false); + actionEditDeleteVymLink->setEnabled (false); + } else + { + actionEditOpenVymLink->setEnabled (true); + actionEditDeleteVymLink->setEnabled (true); + } + actionEditVymLink->setEnabled (true); + + actionEditCopy->setEnabled (true); + actionEditCut->setEnabled (true); + actionEditPaste->setEnabled (true); + actionEditMoveUp->setEnabled (true); + actionEditMoveDown->setEnabled (true); + actionEditToggleScroll->setEnabled (true); + actionEditHeading->setEnabled (true); + actionEditDelete->setEnabled (true); + actionEditAddBranch->setEnabled (true); + actionEditAddBranchAbove->setEnabled (true); + actionEditAddBranchBelow->setEnabled (true); + actionEditImportAdd->setEnabled (true); + actionEditImportReplace->setEnabled (true); + actionEditSaveBranch->setEnabled (true); + actionEditSelectFirst->setEnabled (true); + actionEditSelectLast->setEnabled (true); + actionEditToggleFloatExport->setEnabled (false); + actionFormatPickColor->setEnabled (true); + actionFormatColorBranch->setEnabled (true); + actionFormatColorSubtree->setEnabled (true); + switch (selection->getFrameType()) + { + case NoFrame: + actionFormatFrameNone->setOn(true); + break; + case Rectangle: + actionFormatFrameRectangle->setOn(true); + break; + default: + break; + } + } + if ( (typeid(*selection) == typeid(FloatImageObj)) ) + { + standardFlagsDefault->setEnabled (false); + + actionEditOpenURL->setEnabled (false); + actionEditURL->setEnabled (false); + actionEditHeading2URL->setEnabled (false); + actionEditBugzilla2URL->setEnabled (false); + actionEditOpenVymLink->setEnabled (false); + actionEditVymLink->setEnabled (false); + actionEditDeleteVymLink->setEnabled (false); + + actionEditCopy->setEnabled (true); + actionEditCut->setEnabled (true); + actionEditPaste->setEnabled (false); //FIXME + actionEditMoveUp->setEnabled (false); + actionEditMoveDown->setEnabled (false); + actionEditToggleScroll->setEnabled (false); + actionEditHeading->setEnabled (false); + actionEditDelete->setEnabled (true); + actionEditAddBranch->setEnabled (false); + actionEditAddBranchAbove->setEnabled (false); + actionEditAddBranchBelow->setEnabled (false); + actionEditImportAdd->setEnabled (false); + actionEditSaveBranch->setEnabled (false); + actionEditImportReplace->setEnabled (false); + actionEditSelectFirst->setEnabled (false); + actionEditSelectLast->setEnabled (false); + actionEditToggleFloatExport->setOn + ( ((FloatImageObj*)(selection))->getFloatExport() ); + actionFormatPickColor->setEnabled (false); + actionFormatColorBranch->setEnabled (false); + actionFormatColorSubtree->setEnabled (false); + } + + } else + { + standardFlagsDefault->setEnabled (false); + + actionEditCopy->setEnabled (false); + actionEditCut->setEnabled (false); + actionEditPaste->setEnabled (false); + actionEditMoveUp->setEnabled (false); + actionEditMoveDown->setEnabled (false); + actionEditToggleScroll->setEnabled (false); + actionEditOpenURL->setEnabled (false); + actionEditURL->setEnabled (false); + actionEditOpenVymLink->setEnabled (false); + actionEditVymLink->setEnabled (false); + actionEditDeleteVymLink->setEnabled (false); + actionEditHeading2URL->setEnabled (false); + actionEditBugzilla2URL->setEnabled (false); + actionEditHeading->setEnabled (false); + actionEditDelete->setEnabled (false); + actionEditAddBranch->setEnabled (false); + actionEditAddBranchAbove->setEnabled (false); + actionEditAddBranchBelow->setEnabled (false); + actionEditSaveBranch->setEnabled (false); + actionEditImportReplace->setEnabled (false); + actionEditSelectFirst->setEnabled (false); + actionEditSelectLast->setEnabled (false); + actionEditToggleFloatExport->setEnabled (false); + actionFormatPickColor->setEnabled (false); + actionFormatColorBranch->setEnabled (false); + actionFormatColorSubtree->setEnabled (false); + } +} + +void MapEditor::setLinkStyle (LinkStyle ls) +{ + linkstyle=ls; + + BranchObj *bo; + bo=mapCenter->first(); + bo=bo->next(); + while (bo) + { + bo->setLinkStyle(bo->getDefLinkStyle()); + bo=bo->next(); + } + //setChanged(); + //saveState(); +} + +LinkStyle MapEditor::getLinkStyle () +{ + return linkstyle; +} + +void MapEditor::setLinkColor(QColor c) +{ + deflinkcolor=c; + updateActions(); +} + +void MapEditor::setLinkColorHint() +{ + // called from setLinkColorHint(lch) or at end of parse + BranchObj *bo; + bo=mapCenter->first(); + while (bo) + { + bo->setLinkColor(); + bo=bo->next(); + } +} + +void MapEditor::setLinkColorHint(LinkColorHint lch) +{ + linkcolorhint=lch; + setLinkColorHint(); +} + +void MapEditor::toggleLinkColorHint() +{ + if (linkcolorhint==HeadingColor) + linkcolorhint=DefaultColor; + else + linkcolorhint=HeadingColor; + BranchObj *bo; + bo=mapCenter->first(); + while (bo) + { + bo->setLinkColor(); + bo=bo->next(); + } +} + +LinkColorHint MapEditor::getLinkColorHint() +{ + return linkcolorhint; +} + +QColor MapEditor::getDefLinkColor() +{ + return deflinkcolor; +} + +void MapEditor::selectLinkColor() +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + QColor col = QColorDialog::getColor( deflinkcolor, this ); + if ( !col.isValid() ) return; + setLinkColor( col ); + setChanged(); +} + +void MapEditor::toggleScroll() +{ + if (selection && (typeid(*selection) == typeid(BranchObj)) ) + { + BranchObj *bo=((BranchObj*)(selection)); + if (bo->countBranches()==0) return; + if (bo->getDepth()==0) return; + setChanged(); + saveState(PartOfMap,selection); + bo->toggleScroll(); + adjustCanvasSize(); + canvas()->update(); + } +} + +void MapEditor::unScrollAll() +{ + BranchObj *bo; + bo=mapCenter->first(); + while (bo) + { + if (bo->isScrolled()) bo->toggleScroll(); + bo=bo->next(); + } +} + +void MapEditor::loadFloatImage () +{ + if (selection && + (typeid(*selection) == typeid(BranchObj)) || + (typeid(*selection) == typeid(MapCenterObj)) ) + { + BranchObj *bo=((BranchObj*)(selection)); + + QFileDialog *fd=new QFileDialog( this,tr("vym - load image")); + fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)")); + ImagePreview *p =new ImagePreview (fd); + fd->setContentsPreviewEnabled( TRUE ); + fd->setContentsPreview( p, p ); + fd->setPreviewMode( QFileDialog::Contents ); + fd->setCaption(tr("vym - Load image")); + fd->setDir (lastImageDir); + fd->show(); + + QString fn; + if ( fd->exec() == QDialog::Accepted ) + { + setChanged(); + saveState(PartOfMap,selection); + QString fn=fd->selectedFile(); + lastImageDir=fn.left(fn.findRev ("/")); + bo->addFloatImage(); + // FIXME check if load was successful + bo->getLastFloatImage()->load(fn); + bo->getLastFloatImage()->setOriginalFilename(fn); + mapCenter->reposition(); + adjustCanvasSize(); + canvas()->update(); + } + } +} + +void MapEditor::saveFloatImage (int item) +{ + if (selection && + (typeid(*selection) == typeid(FloatImageObj)) ) + { + FloatImageObj *fio=((FloatImageObj*)(selection)); + const char* fmt = saveImageFormatMenu->text(item); + + QFileDialog *fd=new QFileDialog( this, tr("vym - save image as") + fmt); + fd->addFilter ("PNG (*.png)"); + fd->addFilter ("BMP (*.bmp)"); + fd->addFilter ("XBM (*.xbm)"); + fd->addFilter ("JPG (*.jpg)"); + fd->addFilter ("XPM (*.xpm)"); + fd->addFilter ("GIF (*.gif)"); + fd->addFilter ("PNM (*.pnm)"); + fd->addFilter (QString (tr("Images") + " (*.png *.bmp *.xbm *.jpg *.png *.xpm *.gif *.pnm)")); + fd->setCaption(tr("vym - Save image as ") + fmt); + fd->setMode( QFileDialog::AnyFile ); + fd->setSelection (fio->getOriginalFilename()); + fd->show(); + + QString fn; + if ( fd->exec() == QDialog::Accepted ) + { + if (QFile (fd->selectedFile()).exists() ) + { + QMessageBox mb( "VYM", + tr("The file ") + fd->selectedFile() + + tr(" exists already. " + "Do you want to overwrite it?"), + QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::Cancel | QMessageBox::Escape, + QMessageBox::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 + return; + break; + } + } + fio->save (fd->selectedFile(),fmt); + } + } +} + +void MapEditor::toggleFloatExport() +{ + if (selection && + (typeid(*selection) == typeid(FloatImageObj))|| + (typeid(*selection) == typeid(FloatObj)) ) + { + FloatImageObj *fio=((FloatImageObj*)(selection)); + fio->setFloatExport (actionEditToggleFloatExport->isOn() ); + } +} + +void MapEditor::setFrame(const FrameType &t) +{ + if (selection && + (typeid(*selection) == typeid(BranchObj)) || + (typeid(*selection) == typeid(MapCenterObj)) ) + { + selection->setFrameType (t); + mapCenter->reposition(); + selection->updateLink(); + } +} + +void MapEditor::importDir(BranchObj *dst, QDir d) +{ + if (selection && + (typeid(*selection) == typeid(BranchObj)) || + (typeid(*selection) == typeid(MapCenterObj)) ) + { + BranchObj *bo; + + // Traverse directories + d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks ); + const QFileInfoList *dirlist = d.entryInfoList(); + QFileInfoListIterator itdir( *dirlist ); + QFileInfo *fi; + + while ( (fi = itdir.current()) != 0 ) + { + if (fi->fileName() != "." && fi->fileName() != ".." ) + { + dst->addBranch(); + bo=dst->getLastBranch(); + bo->setHeading (fi->fileName() ); + bo->setColor (QColor("blue"),false); + bo->toggleScroll(); + if ( !d.cd(fi->fileName()) ) + QMessageBox::critical (0,tr("Critical Import Error"),tr("Cannot find the directory")); + else + { + importDir (bo,d); + d.cdUp(); + } + } + ++itdir; + } + // Traverse files + d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks ); + const QFileInfoList *filelist = d.entryInfoList(); + QFileInfoListIterator itfile( *filelist ); + + while ( (fi = itfile.current()) != 0 ) + { + dst->addBranch(); + bo=dst->getLastBranch(); + bo->setHeading (fi->fileName() ); + bo->setColor (QColor("black"),false); + ++itfile; + } + } +} + +void MapEditor::importDir() +{ + if (selection && + (typeid(*selection) == typeid(BranchObj)) || + (typeid(*selection) == typeid(MapCenterObj)) ) + { + QFileDialog *fd=new QFileDialog( this,tr("VYM - Choose directory structur to import")); + fd->setMode (QFileDialog::DirectoryOnly); + fd->addFilter (QString (tr("vym map") + " (*.vym)")); + fd->setCaption(tr("VYM - Choose directory structur to import")); + fd->show(); + + QString fn; + if ( fd->exec() == QDialog::Accepted ) + { + BranchObj *bo=((BranchObj*)(selection)); + importDir (bo,QDir(fd->selectedFile()) ); + mapCenter->reposition(); + adjustCanvasSize(); + canvas()->update(); + } + } +} + +void MapEditor::testFunction() +{ + cout << "MapEditor::testFunction() called\n"; +} + +void MapEditor::ensureSelectionVisible() +{ + LinkableMapObj* lmo= dynamic_cast (selection); + QPoint p; + if (selection->getOrientation() == OrientLeftOfCenter) + p= worldMatrix().map(QPoint (lmo->x(),lmo->y())); + else + p= worldMatrix().map(QPoint (lmo->x()+lmo->width(),lmo->y()+lmo->height())); + ensureVisible (p.x(), p.y() ); + +} + +void MapEditor::updateViewCenter() +{ + // Update movingCenter, so that we can zoom comfortably later + QRect rc = QRect( contentsX(), contentsY(), + visibleWidth(), visibleHeight() ); + QRect canvasRect = inverseWorldMatrix().mapRect(rc); + movingCenter.setX((canvasRect.right() + canvasRect.left())/2); + movingCenter.setY((canvasRect.top() + canvasRect.bottom())/2); +} + +void MapEditor::contentsContextMenuEvent ( QContextMenuEvent * e ) +{ + // Lineedits are already closed by preceding + // mouseEvent, we don't need to close here. + + QPoint p = inverseWorldMatrix().map(e->pos()); + LinkableMapObj* lmo=mapCenter->findMapObj(p, NULL); + + if (lmo) + { // MapObj was found + if (selection != lmo) + { + // select the MapObj + if (selection) selection->unselect(); + selection=lmo; + selection->select(); + adjustCanvasSize(); + } + // Context Menu + if (selection) + { + if (typeid(*selection)==typeid(BranchObj) || + typeid(*selection)==typeid(MapCenterObj) ) + { + // Context Menu on branch or mapcenter + updateActions(); + branchContextMenu->popup(e->globalPos() ); + } + if (typeid(*selection)==typeid(FloatImageObj)) + { + // Context Menu on floatimage + updateActions(); + floatimageContextMenu->popup(e->globalPos() ); + } + } + } else + { // No MapObj found, we are on the Canvas itself + // Context Menu on Canvas + updateActions(); + canvasContextMenu->popup(e->globalPos() ); + } +} + +void MapEditor::contentsMousePressEvent(QMouseEvent* e) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + QPoint p = inverseWorldMatrix().map(e->pos()); + LinkableMapObj* lmo=mapCenter->findMapObj(p, NULL); + + // Special case: CTRL is pressed, don't select anything + if (e->state() & QMouseEvent::ControlButton) + { + pickingColor=true; + setCursor (pickColorCursor); + return; + } + + if (lmo) + { // MapObj was found + if (selection != lmo) + { + // select the MapObj + if (selection) selection->unselect(); + selection=lmo; + selection->select(); + + adjustCanvasSize(); + } + + // Check, if systemFlag clicked + if (typeid(*selection)==typeid(BranchObj) || + typeid(*selection)==typeid(MapCenterObj) ) + { + QString foname=((BranchObj*)(selection))->getSystemFlagName(p); + if (!foname.isEmpty()) + { + // Do not move, if systemFlag clicked + if (foname=="url") + openURL(); + else + if (foname=="vymLink") + { + mainWindow->editOpenVymLink(); + // tabWidget may change, better return now + // before segfaulting... + return; + } else + if (foname=="note") + mainWindow->windowToggleNoteEditor(); + } + } + + // Left Button Move Branches + if (e->button() == QMouseEvent::LeftButton ) + { + movingObj=selection; + movingObj_start.setX( p.x() - selection->x() ); + movingObj_start.setY( p.y() - selection->y() ); + } 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() == QMouseEvent::MidButton ) + { + toggleScroll(); + } + updateActions(); + } else + { // No MapObj found, we are on the Canvas itself + // Left Button move Pos of CanvasView + if (e->button() == QMouseEvent::LeftButton ) + { + movingObj=NULL; // move Content not Obj + movingObj_start=e->globalPos(); + movingCont_start=QPoint (contentsX(), contentsY() ); + movingVec=QPoint(0,0); + setCursor(handOpenCursor); + } + } +} + +void MapEditor::contentsMouseMoveEvent(QMouseEvent* e) +{ + // Move the selected MapObj + if ( selection && movingObj) + { + QPoint p = inverseWorldMatrix().map(e->pos()); + + // 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) + + LinkableMapObj *lmosel; + lmosel = dynamic_cast (selection); + + // Check if we could link + LinkableMapObj* lmo=mapCenter->findMapObj(p, lmosel); + + + if (typeid(*selection) == typeid(FloatImageObj)) + { + setChanged(); + saveState(); + FloatObj *fo=(FloatObj*)(selection); + if (fo->getLinkStyle()==StyleUndef) + { + fo->setLinkStyle(fo->getDefLinkStyle()); + fo->setLinkColor(fo->getParObj()->getLinkColor()); + } + fo->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() ); + fo->setRelPos(); + fo->reposition(); + + // Relink float to new mapcenter or branch, if shift is pressed + // Only relink, if selection really has a new parent + if ( (e->state() & QMouseEvent::ShiftButton) && lmo && + ( (typeid(*lmo)==typeid(BranchObj)) || + (typeid(*lmo)==typeid(MapCenterObj)) ) && + ( lmo != fo->getParObj()) + ) + { + if (typeid(*fo) == typeid(FloatImageObj)) + { + FloatImageObj *fio=(FloatImageObj*)(fo); + ((BranchObj*)(lmo))->addFloatImage (fio); + fio->unselect(); + ((BranchObj*)(fio->getParObj()))->removeFloatImage (fio); + fio=((BranchObj*)(lmo))->getLastFloatImage(); + fio->setRelPos(); + fio->reposition(); + selection=(LinkableMapObj*)(fio); + selection->select(); + movingObj=(MapObj*)(fio); + // setLinkStyle calls updateLink, only set it once + if (fio->getLinkStyle()!=fio->getDefLinkStyle() ) + fio->setLinkStyle (fio->getDefLinkStyle()); + + } + // TODO if (typeid(*selection) == typeid(FloatTextObj)) + } + } else // selection != a FloatObj + { + if (lmosel->getDepth()==0) + { + if (e->state() == (LeftButton | !ShiftButton)) + // If mapCenter is moved, move all the rest by default, too. + mapCenter->moveAll(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() ); + else + mapCenter->move (p.x() -movingObj_start.x(), p.y()-movingObj_start.y() ); + } else + { + if (lmosel->getDepth()==1) + { + // depth==1, mainbranch + setChanged(); + saveState(PartOfMap,lmosel); + lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() ); + } else + { + // depth>1 + if (lmosel->getOrientation() == OrientLeftOfCenter) + // Add width of bbox here, otherwise alignRelTo will cause jumping around + lmosel->move(p.x() -movingObj_start.x()+lmosel->getBBox().width(), + p.y()-movingObj_start.y() ); + else + lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() ); + } + // reposition subbranch + lmosel->reposition(); + ensureSelectionVisible(); + + if (lmo && (lmo!=selection) && + (typeid(*lmo) == typeid(BranchObj) || + (typeid(*lmo) == typeid(MapCenterObj) ) + ) ) + { + if (e->state() & QMouseEvent::ControlButton) + { + // Special case: CTRL to link below lmo + lmosel->setParObjTmp (lmo,p,+1); + } + else if (e->state() & QMouseEvent::ShiftButton) + lmosel->setParObjTmp (lmo,p,-1); + else + lmosel->setParObjTmp (lmo,p,0); + } else + { + if (lmo &&(lmo==selection)) + // Could link to myself (happens sometimes...) + lmosel->unsetParObjTmp(); + if (!lmo) + // no Obj under selection, go back to original Parent + lmosel->unsetParObjTmp(); + } + } // depth>0 + + } // no FloatImageObj + + canvas()->update(); + return; + } // selection && moving_obj + + // Move CanvasView + if (!movingObj && !pickingColor) + { + QPoint p=e->globalPos(); + movingVec.setX(-p.x() + movingObj_start.x() ); + movingVec.setY(-p.y() + movingObj_start.y() ); + setContentsPos( movingCont_start.x() + movingVec.x(), + movingCont_start.y() + movingVec.y()); + + updateViewCenter(); + } +} + + +void MapEditor::contentsMouseReleaseEvent(QMouseEvent* e) +{ + LinkableMapObj *dst; + // Have we been picking color? + if (pickingColor) + { + pickingColor=false; + setCursor (ArrowCursor); + // Check if we are over another branch + dst=mapCenter->findMapObj(inverseWorldMatrix().map(e->pos() ), NULL); + if (dst && selection) + { + if (e->state() & QMouseEvent::ShiftButton) + { + ((BranchObj*)(selection))->setColor (((BranchObj*)(dst))->getColor(),false); + ((BranchObj*)(selection))->setLinkColor (); + } + else + { + ((BranchObj*)(selection))->setColor (((BranchObj*)(dst))->getColor(),true); + ((BranchObj*)(selection))->setLinkColor (); + } + } + return; + } + // Have we been moving something? + if ( selection && movingObj ) + { + // Check if we are over another branch, but ignore + // any found LMOs, which are FloatObjs + dst=mapCenter->findMapObj(inverseWorldMatrix().map(e->pos() ), + ((LinkableMapObj*)(selection)) ); + + if (dst && + (typeid(*dst)!=typeid(BranchObj)&&typeid(*dst)!=typeid(MapCenterObj))) + { + dst=NULL; + } + + // Now check, if we have been moving a branch + if (typeid(*selection) == typeid(BranchObj) ) + { + // save the position in case we link to mapcenter + QPoint savePos=QPoint (selection->x(),selection->y() ); + + // Reset the temporary drawn link to the original one + ((LinkableMapObj*)(selection))->unsetParObjTmp(); + + if (dst ) + { + setChanged(); + saveState(); + // TODO we also could check, if dest and src are on same branch, + // then it would be sufficient to saveState of this branch + + // FIXME better introduce BO::move to speed up and keep IDs + copy(); // copy selection to clipboard + cutNoSave(); // remove selection here + + selection->unselect(); + selection=dst; + // Modifiers allow to insert above/below dst + if (e->state() & QMouseEvent::ShiftButton) + { + selection=pasteAtNoSave (((BranchObj*)(dst))->getNum()); + if (selection) selection->select(); + } + else if (e->state() & QMouseEvent::ControlButton) + { + selection=pasteAtNoSave (((BranchObj*)(dst))->getNum()+1); + if (selection) selection->select(); + } + else + { + selection=pasteNoSave(); + selection->select(); + if (dst->getDepth()==0) + ((BranchObj*)(selection))->move (savePos); + } + } + // Draw the original link, before selection was moved around + mapCenter->reposition(); + } + // Finally resize canvas, if needed + adjustCanvasSize(); + canvas()->update(); + movingObj=NULL; + } else + { // maybe we moved View: set old cursor + setCursor (ArrowCursor); + } +} + +void MapEditor::contentsMouseDoubleClickEvent(QMouseEvent* e) +{ + // Finish open lineEdits + if (lineedit) finishedLineEditNoSave(); + + if (e->button() == QMouseEvent::LeftButton ) + { + QPoint p = inverseWorldMatrix().map(e->pos()); + LinkableMapObj *lmo=mapCenter->findMapObj(p, NULL); + if (lmo) { // MapObj was found + // First select the MapObj than edit heading + if (selection) selection->unselect(); + selection=lmo; + selection->select(); + setChanged(); + saveState(PartOfMap,selection); + editHeading(); + } + } +} + +void MapEditor::resizeEvent (QResizeEvent* e) +{ + QCanvasView::resizeEvent( e ); + + QString s=""; + if (!fileName.isEmpty()) s=fileName; + adjustCanvasSize(); +} +