#include "mapeditor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "version.h" #include "api.h" #include "editxlinkdialog.h" #include "exports.h" #include "extrainfodialog.h" #include "file.h" #include "linkablemapobj.h" #include "mainwindow.h" #include "misc.h" #include "settings.h" #include "texteditor.h" #include "warningdialog.h" #include "xml.h" #include extern TextEditor *textEditor; extern int statusbarTime; extern Main *mainWindow; extern QString tmpVymDir; extern QString clipboardDir; extern bool clipboardEmpty; extern FlagRowObj *systemFlagsDefault; extern FlagRowObj *standardFlagsDefault; extern QPtrList actionListBranches; 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 *actionEditOpenURLTab; extern QAction *actionEditURL; extern QAction *actionEditHeading2URL; extern QAction *actionEditBugzilla2URL; extern QAction *actionEditFATE2URL; extern QAction *actionEditOpenVymLink; extern QAction *actionEditVymLink; extern QAction *actionEditDeleteVymLink; extern QAction *actionEditToggleHideExport; extern QAction *actionEditHeading; extern QAction *actionEditDelete; extern QAction *actionEditAddBranch; extern QAction *actionEditAddBranchAbove; extern QAction *actionEditAddBranchBelow; extern QAction *actionEditRemoveBranchHere; extern QAction *actionEditRemoveChilds; extern QAction *actionEditImportAdd; extern QAction *actionEditImportReplace; extern QAction *actionEditSaveBranch; extern QAction *actionEditSelectFirst; extern QAction *actionEditSelectLast; extern QAction *actionEditLoadImage; extern QAction* actionFormatPickColor; extern QAction* actionFormatColorBranch; extern QAction* actionFormatColorSubtree; extern QAction *actionFormatLinkColorHint; extern QAction *actionFormatBackColor; extern QAction *actionFormatLinkColor; extern QActionGroup* actionGroupModModes; extern QAction* actionModModeColor; extern QAction* actionModModeLink; extern QAction* actionModModeCopy; extern QActionGroup *actionGroupFormatFrameTypes; extern QAction *actionFormatFrameNone; extern QAction *actionFormatFrameRectangle; extern QActionGroup *actionGroupFormatLinkStyles; extern QAction *actionFormatIncludeImagesVer; extern QAction *actionFormatIncludeImagesHor; extern QAction *actionFormatHideLinkUnselected; 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 QAction *actionSettingsUseFlagGroups; extern QPopupMenu *branchContextMenu; extern QPopupMenu *branchLinksContextMenu; extern QPopupMenu *branchLinksContextMenuDup; extern QPopupMenu *floatimageContextMenu; extern QPopupMenu *saveImageFormatMenu; extern QPopupMenu *exportImageFormatMenu; extern QPopupMenu *canvasContextMenu; extern Settings settings; extern QString iconPath; extern QDir vymBaseDir; int MapEditor::mapNum=0; // make instance /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// MapEditor::MapEditor( QWidget* parent, bool interactive, const char* name, WFlags f) : QCanvasView(parent,name,f), urlOperator(0), imageBuffer(0) { //cout << "Constructor ME "<setAcceptDrops(true); mapCanvas = new QCanvas(1000,800); mapCanvas->setAdvancePeriod(30); mapCanvas->setBackgroundColor (white); setCanvas (mapCanvas); // Always show scroll bars (automatic would flicker sometimes) setVScrollBarMode ( QScrollView::AlwaysOn ); setHScrollBarMode ( QScrollView::AlwaysOn ); mapCenter = new MapCenterObj(mapCanvas); mapCenter->setVisibility (true); mapCenter->setMapEditor (this); mapCenter->setHeading (tr("New Map","Heading of mapcenter in new map")); mapCenter->move(mapCanvas->width()/2-mapCenter->width()/2,mapCanvas->height()/2-mapCenter->height()/2); printer=NULL; lineedit = new QLineEdit(this, "lineedit" ); connect( lineedit, SIGNAL( returnPressed() ), SLOT( finishedLineEdit() ) ); lineedit->hide(); actColor=black; setColor (actColor); defLinkColor=QColor (0,0,255); defXLinkColor=QColor (180,180,180); linkcolorhint=DefaultColor; linkstyle=StylePolyParabel; // Create bitmap cursors, patform dependant #if defined(Q_OS_MACX) handOpenCursor=QCursor ( QPixmap(iconPath+"cursorhandopen16.png") ); // set hot spot to tip of picker pickColorCursor=QCursor ( QPixmap (iconPath+"cursorcolorpicker16.png"), 1,15 ); #else handOpenCursor=QCursor (QPixmap(iconPath+"cursorhandopen16.png")); // set hot spot to tip of picker pickColorCursor=QCursor ( QPixmap(iconPath+"cursorcolorpicker.png"), 5,27 ); #endif pickingColor=false; drawingLink=false; copyingObj=false; editingBO=NULL; selection=NULL; selectionLast=NULL; movingObj=NULL; defXLinkWidth=1; defXLinkColor=QColor (230,230,230); mapChanged=false; mapDefault=true; mapUnsaved=false; zipped=true; filePath=""; fileName=tr("unnamed"); mapName=""; undosTotal=settings.readNumEntry("/vym/mapeditor/undoLevels",50); undosAvail=0; undoNum=0; // Initialize find routine itFind=NULL; EOFind=false; printFrame=true; printFooter=true; blockReposition=false; blockSaveState=false; hidemode=HideNone; isInteractive=interactive; if (isInteractive) // Create temporary files makeTmpDirs(); // Initially set movingCentre updateViewCenter(); // For testing purposes create history window historyWindow = new ShowTextDialog (this); historyWindow->setCaption (fileName); mapCenter->reposition(); // for positioning heading } MapEditor::~MapEditor() { if (imageBuffer) delete imageBuffer; if (urlOperator) { urlOperator->stop(); delete urlOperator; } //cout <<"Destructor MapEditor\n"; // 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(); // mapCenter->positionBBox(); // To move float // scroll the view (in order to not move map on screen) scrollBy (dx,dy); } } } bool MapEditor::isRepositionBlocked() { return blockReposition; } QString MapEditor::getName (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); QDir d; d.mkdir (tmpMapDir,true); } QString MapEditor::saveToDir(const QString &tmpdir, const QString &prefix, bool writeflags, const QPoint &offset, LinkableMapObj *saveSelection) { // 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 canvas. // Needed for XML export // 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 (!saveSelection) 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() ) + 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 FloatImageObj (mapCanvas).resetSaveCounter(); // Build xml recursivly if (!saveSelection) s+=mapCenter->saveToDir(tmpdir,prefix,writeflags,offset); else { if ( typeid(*saveSelection) == typeid(BranchObj) ) s+=((BranchObj*)(saveSelection))->saveToDir(tmpdir,prefix,offset); else if ( typeid(*saveSelection) == typeid(FloatImageObj) ) s+=((FloatImageObj*)(saveSelection))->saveToDir(tmpdir,prefix,offset); else if (selection && typeid(*selection)==typeid(BranchObj)) // This is used if selected branch is saved from mainwindow s+=((BranchObj*)selection)->saveToDir(tmpdir,prefix,offset); } // Save local settings s+=settings.getXMLData (destPath); // Save selection if (selection && !saveSelection ) s+=valueElement("select",selection->getSelectString()); decIndent(); s+=endElement("vymmap"); if (writeflags) standardFlagsDefault->saveToDir (tmpdir+"/flags/","",writeflags); return s; } void MapEditor::saveState(const QString &comment) { // Save complete map saveState (CompleteMap,"",NULL,"",NULL, comment); } void MapEditor::saveState(LinkableMapObj *undoSel, const QString &comment) { // save the given part of the map saveState (PartOfMap,"",undoSel,"",NULL, comment); } void MapEditor::saveState(const QString &uc, const QString &rc, const QString &comment) { // selection does not change during action, // so just save commands for undo and redo LinkableMapObj *unsel; if (selection) unsel=selection; else unsel=NULL; saveState (UndoCommand,uc,unsel,rc,unsel, comment); } void MapEditor::saveState(const QString & uncom, LinkableMapObj *unsel, const QString &comment) { saveState (UndoCommand,uncom,unsel,"FIXME-redoCom",NULL, comment); } void MapEditor::saveState(const SaveMode &savemode, const QString &undoCom, LinkableMapObj *undoSel, const QString &redoCom, LinkableMapObj *redoSel, const QString &comment) { // Main saveState if (blockSaveState) return; /* TODO remove after testing cout << "ME::saveState() begin\n"<append (comment); setChanged(); // Find out current undo directory if (undosAvailundosTotal) undoNum=1; QString backupXML; QString bakMapDir=QDir::convertSeparators (QString(tmpMapDir+"/undo-%1").arg(undoNum)); QString bakMapPath=QDir::convertSeparators(bakMapDir+"/map.xml"); // Create bakMapDir if not available QDir d(bakMapDir); if (!d.exists()) makeSubDirs (bakMapDir); // Save current selection QString redoSelection=""; if (redoSel) redoSelection=redoSel->getSelectString(); // Save the object, which should be undone QString undoSelection=""; if (undoSel) undoSelection=undoSel->getSelectString(); // Save depending on how much needs to be saved QString undoCommand=""; if (savemode==UndoCommand) { undoCommand=undoCom; backupXML=""; } else if (savemode==PartOfMap && undoSel) { undoCommand="undoPart (\""+ undoSelection+"\",\""+bakMapPath+"\")"; backupXML=saveToDir (bakMapDir,mapName+"-",false, QPoint (),undoSel); } else { undoCommand="undoMap (\""+bakMapPath+"\")"; backupXML=saveToDir (bakMapDir,mapName+"-",false, QPoint (),NULL); undoSelection=""; } if (!backupXML.isEmpty()) // Write XML Data to disk saveStringToDisk (QString(bakMapPath),backupXML); SimpleSettings set; set.setEntry (QString("undoCommand"),undoCommand); set.setEntry (QString("undoSelection"),undoSelection); set.setEntry (QString("redoCommand"),redoCom); set.setEntry (QString("redoSelection"),redoSelection); set.setEntry (QString("comment"),comment); set.writeSettings(QString(bakMapDir+"/commands")); /* TODO remove after testing cout << " into="<< bakMapDir<findObjBySelect (s); if (dst) { if (typeid(*dst) == typeid(BranchObj) ) { // Get number in parent x=api.parInt (ok,1); if (ok) ((BranchObj*)selection)->moveBranchTo ((BranchObj*)(dst),x); } else if (typeid(*dst) == typeid(MapCenterObj) ) { ((BranchObj*)selection)->moveBranchTo ((BranchObj*)(dst),-1); // Get coordinates of mainbranch x=api.parInt (ok,2); if (ok) { y=api.parInt (ok,3); if (ok) ((BranchObj*)selection)->move (x,y); } } } } } } else if (com=="setHeading") { if (api.checkParamCount(1)) { s=api.parString (ok,0); if (ok) setHeading (s); } } else if (com=="setURL") { if (api.checkParamCount(1)) { s=api.parString (ok,0); if (ok) setURL(s); } } else if (com=="setVymLink") { if (api.checkParamCount(1)) { s=api.parString (ok,0); if (ok) setVymLink(s); } } // Internal commands, used for undo etc. else if (com==QString("undoMap")) { if (api.checkParamCount(1)) undoXML("",api.parString (ok,0)); } else if (com==QString("undoPart")) { if (api.checkParamCount(2)) { s=api.parString (ok,0); t=api.parString (ok,1); undoXML(s,t); } } else if (com=="select") if (api.checkParamCount(1)) { s=api.parString(ok,0); if (ok) select (s); } else { api.setError ("Unknown command in: "+atom); cout << "ME::parse api should have error now...\n"; } // Any errors? if (api.error()) { cout << "MapEditor::parseAtom: Error!\n"; cout << " "<setFocus() if (editingBO!=NULL) { saveState("setHeading (\""+editingBO->getHeading()+"\")",editingBO, QString("Set heading of %1 to \"%2\"").arg(getName(editingBO)).arg(lineedit->text()) ); editingBO->setHeading(lineedit->text() ); editingBO=NULL; lineedit->releaseKeyboard(); lineedit->hide(); parentWidget()->setFocus(); mapCenter->reposition(); adjustCanvasSize(); ensureSelectionVisible(); } } void MapEditor::toggleHistoryWindow() { if (historyWindow->isVisible()) historyWindow->hide(); else historyWindow->show(); } 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) finishedLineEdit(); // 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) { if (fname.isEmpty() || fname=="") { filePath=""; fileName=""; destPath=""; } else { filePath=fname; // becomes absolute path fileName=fname; // gets stripped of path destPath=destname; // needed for vymlinks // 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) ); // Adjust history window historyWindow->setCaption (fileName); } } 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, LoadMode lmode) { // Finish open lineEdits if (lineedit) finishedLineEdit(); ErrorCode err=success; if (lmode==NewMap) { if (selection) selection->unselect(); selection=NULL; mapCenter->clear(); mapCenter->setMapEditor(this); // (map state is set later at end of load...) } else { saveState(selection,"Load map"); } 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)+"."); err=aborted; } 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.setInputFile (file.name()); handler.setLoadMode (lmode); blockSaveState=true; bool ok = reader.parse( source ); blockReposition=false; blockSaveState=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 err; } int MapEditor::save (const SaveMode &savemode) { // Finish open lineEdits if (lineedit) finishedLineEdit(); int returnCode=0; // The SaveMode UndoCommand is not supported here if (savemode==UndoCommand) return 1; // 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; QString saveFile; if (savemode==CompleteMap || selection==NULL) saveFile=saveToDir (fileDir,mapName+"-",true,QPoint(),NULL); else saveFile=saveToDir (fileDir,mapName+"-",true,QPoint(),selection); if (!saveStringToDisk(fileDir+fname,saveFile)) return 1; 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) finishedLineEdit(); if ( !printer ) { printer = new QPrinter; printer->setColorMode (QPrinter::Color); printer->setPrinterName (settings.readEntry("/vym/mainwindow/printerName",printer->printerName())); } 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=totalBBox; QCanvasRectangle *frame=NULL; QCanvasText *footerFN=NULL; QCanvasText *footerDate=NULL; if (printFrame || printFooter) { if (printFrame) { // Print frame around map mapRect.setRect (totalBBox.x()-10, totalBBox.y()-10, totalBBox.width()+20, totalBBox.height()+20); frame=new QCanvasRectangle (mapRect,mapCanvas); frame->setBrush (QColor(white)); frame->setPen (QColor(black)); frame->setZ(0); frame->show(); } /* TODO remove after testing QCanvasLine *l=new QCanvasLine (mapCanvas); l->setPoints (0,0,mapRect.width(),mapRect.height()); l->setPen (QPen(QColor(black), 1)); l->setZ (200); l->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(); } pp.setWindow (mapRect.x(), mapRect.y(), mapRect.width(), mapRect.height()+20); } 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(); } // Save settings in vymrc settings.writeEntry("/vym/mainwindow/printerName",printer->printerName()); } } 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::setHideTmpMode (HideTmpMode mode) { hidemode=mode; mapCenter->setHideTmp (hidemode); mapCenter->reposition(); adjustCanvasSize(); canvas()->update(); } HideTmpMode MapEditor::getHideTmpMode() { return hidemode; } void MapEditor::exportImage(QString fn) { // Finish open lineEdits if (lineedit) finishedLineEdit(); setExportMode (true); QPixmap pix (getPixmap()); pix.save(fn, "PNG"); setExportMode (false); } void MapEditor::setExportMode (bool b) { // should be called before and after exports // depending on the settings if (b && settings.readEntry("/vym/export/useHideExport","yes")) setHideTmpMode (HideExport); else setHideTmpMode (HideNone); } void MapEditor::exportImage(QString fn, int item) { // Finish open lineEdits if (lineedit) finishedLineEdit(); setExportMode (true); QPixmap pix (getPixmap()); pix.save(fn, exportImageFormatMenu->text(item) ); setExportMode (false); } void MapEditor::exportOOPresentation(const QString &fn, const QString &cf) { ExportOO ex; ex.setFile (fn); ex.setMapCenter(mapCenter); if (ex.setConfigFile(cf)) { setExportMode (true); ex.exportPresentation(); setExportMode (false); } } void MapEditor::exportXML(const QString &dir) { // Hide stuff during export, if settings want this setExportMode (true); // Create subdirectories makeSubDirs (dir); // write to directory QString saveFile=saveToDir (dir,mapName+"-",true,mapCenter->getTotalBBox().topLeft() ,NULL); 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 %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"); setExportMode (false); } void MapEditor::clear() { if (selection) { selection->unselect(); selection=NULL; } mapCenter->clear(); } void MapEditor::copy() { // Finish open lineEdits if (lineedit) finishedLineEdit(); if (selection) { // write to directory QString clipfile="part"; QString saveFile=saveToDir (fileDir,clipfile+"-",true,QPoint(),selection); QFile file; file.setName ( clipboardDir + "/"+clipfile+".xml"); if ( !file.open( IO_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(); clipboardEmpty=false; updateActions(); } } void MapEditor::redo() { // Finish open lineEdits if (lineedit) finishedLineEdit(); blockSaveState=true; // Find out current undo directory QString bakMapDir=QDir::convertSeparators (QString(tmpMapDir+"/undo-%1").arg(undoNum)); // Restore variables QString undoCommand; QString undoSelection; QString redoCommand; QString redoSelection; SimpleSettings set; set.readSettings(QString(bakMapDir+"/commands")); undoCommand=set.readEntry ("undoCommand"); undoSelection=set.readEntry ("undoSelection"); redoCommand=set.readEntry ("redoCommand"); redoSelection=set.readEntry ("redoSelection"); // select object before redo if (!redoSelection.isEmpty()) select (redoSelection); /* TODO remove testing cout << "ME::redo() begin\n"; cout << " undosTotal="<reposition(); //if (!redoSelection.isEmpty()) // select (redoSelection); undosAvail--; if (undosAvail<1) // Undo not longer available now actionEditUndo->setEnabled (false); else undoNum--; if (undoNum<1) undoNum=undosTotal; blockSaveState=false; /* TODO remove testing cout << "ME::redo() end\n"; cout << " undosAvail="<reposition(); //if (!redoSelection.isEmpty()) // select (redoSelection); undosAvail--; if (undosAvail<1) // Undo not longer available now actionEditUndo->setEnabled (false); else undoNum--; if (undoNum<1) undoNum=undosTotal; blockSaveState=false; /* TODO remove testing cout << "ME::undo() end\n"; cout << " undosAvail="<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 by reading backupFile" ), tr( handler.errorProtocol() )+" in "+bakMapDir ); } } else { QMessageBox::critical( 0, tr( "Critical Error" ), tr("Temporary directory %1 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.").arg(bakMapDir) ); makeTmpDirs(); } } void MapEditor::pasteNoSave() { // Finish open lineEdits if (lineedit) finishedLineEdit(); load (clipboardDir+"/part.xml",ImportAdd); } void MapEditor::cutNoSave() { copy(); deleteSelection(); } void MapEditor::paste() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj))) { saveState(selection,QString("Paste to %1").arg( getName(selection))); pasteNoSave(); mapCenter->reposition(); adjustCanvasSize(); } } void MapEditor::cut() { saveState(selection->getParObj(),QString("Cut %1").arg(getName(selection))); copy(); cutNoSave(); mapCenter->reposition(); adjustCanvasSize(); } void MapEditor::move(const int &x, const int &y) { // TODO no saveState, because this is only internal at undo so far if (selection) selection->move(x,y); if (typeid(*selection) == typeid(FloatImageObj)) ((FloatImageObj*)selection)->setRelPos(); } void MapEditor::moveBranchUp() { // Finish open lineEdits if (lineedit) finishedLineEdit(); BranchObj* bo; BranchObj* par; if (typeid(*selection) == typeid(BranchObj) ) { bo=(BranchObj*)selection; if (!bo->canMoveBranchUp()) return; par=(BranchObj*)(bo->getParObj()); selection->unselect(); selection=par->moveBranchUp (bo); selection->select(); saveState("moveBranchDown ()",bo,QString("Move up %1").arg(getName(bo))); mapCenter->reposition(); ensureSelectionVisible(); } } void MapEditor::moveBranchDown() { // Finish open lineEdits if (lineedit) finishedLineEdit(); BranchObj* bo; BranchObj* par; if (typeid(*selection) == typeid(BranchObj) ) { bo=(BranchObj*)selection; if (!bo->canMoveBranchDown()) return; par=(BranchObj*)(bo->getParObj()); selection->unselect(); selection=par->moveBranchDown(bo); selection->select(); saveState("moveBranchUp ()",bo,QString("Move down %1").arg(getName(bo))); mapCenter->reposition(); ensureSelectionVisible(); } } void MapEditor::editHeading() { // Finish open lineEdits if (lineedit) finishedLineEdit(); if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj) ) ) { editingBO=(BranchObj*)selection; ensureSelectionVisible(); QPoint p = worldMatrix().map(QPoint (editingBO->x(),editingBO->y())); lineedit->setGeometry(p.x()-contentsX(),p.y()-contentsY(),200,25); QString s=editingBO->getHeading(); lineedit->setText(s); lineedit->setCursorPosition(1); if (actionSettingsAutoselectText->isOn() && !s.isEmpty() && actionSettingsPasteNewHeading->isOn() ) lineedit->selectAll(); lineedit->show(); lineedit->grabKeyboard(); lineedit->setFocus(); } } void MapEditor::setHeading(const QString &s) { // Internal function, no saveState needed if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj) ) ) { ((BranchObj*)selection)->setHeading(s); mapCenter->reposition(); adjustCanvasSize(); ensureSelectionVisible(); } } void MapEditor::setURL (const QString &s) { // Internal function, no saveState needed if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj) ) ) { ((BranchObj*)selection)->setURL(s); mapCenter->reposition(); adjustCanvasSize(); ensureSelectionVisible(); } } void MapEditor::setVymLink (const QString &s) { // Internal function, no saveState needed if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj) ) ) { ((BranchObj*)selection)->setVymLink(s); mapCenter->reposition(); adjustCanvasSize(); ensureSelectionVisible(); } } void MapEditor::addNewBranch(int pos) { // Finish open lineEdits if (lineedit) finishedLineEdit(); if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj) ) ) { BranchObj* bo1 = (BranchObj*) selection; saveState(selection, QString("Add new branch to %1").arg(getName(bo1))); //TODO undoCommand 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::addNewBranchHere() { // Finish open lineEdits if (lineedit) finishedLineEdit(); if (selection && (typeid(*selection) == typeid(BranchObj) ) ) { BranchObj* bo1 = (BranchObj*) selection; saveState(selection, QString("Add new branch here").arg(getName(bo1))); bool wasScrolled=false; BranchObj *newbo=NULL; BranchObj *parbo=(BranchObj*)(selection->getParObj()); if (parbo) { // add below selection newbo=parbo->insertBranch(bo1->getNum()+1); } LinkableMapObj *oldselection=selection; ((BranchObj*)selection)->moveBranchTo (newbo,-1); 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) finishedLineEdit(); if (selection && typeid(*selection) ==typeid(BranchObj) ) { BranchObj* bo=dynamic_cast (selection); BranchObj* par=(BranchObj*)(bo->getParObj()); bo->unselect(); if (selection->getDepth()>1) // Normal branch, save parent with childs saveState(par,QString("Delete %1").arg(getName(bo))); else // Mainbranch, save whole map // TODO Better would be to insert mainbranch again at pos // But undoCommand is missing right now saveState(QString("Delete %1").arg(getName(bo))); selection=NULL; par->removeBranch(bo); selection=par; selection->select(); ensureSelectionVisible(); mapCenter->reposition(); adjustCanvasSize(); } if (selection && typeid(*selection) ==typeid(FloatImageObj) ) { FloatImageObj* fio=dynamic_cast (selection); BranchObj* par=(BranchObj*)(fio->getParObj()); saveState(par, QString("Delete %1").arg(getName(fio))); fio->unselect(); selection=NULL; par->removeFloatImage(fio); selection=par; selection->select(); ensureSelectionVisible(); mapCenter->reposition(); adjustCanvasSize(); } } LinkableMapObj* MapEditor::getSelection() { return selection; } void MapEditor::unselect() { if (selection) { selectionLast=selection; selection->unselect(); selection=NULL; } } void MapEditor::reselect() { if (selectionLast) { selection=selectionLast; selection->select(); selectionLast=NULL; } } bool MapEditor::select (const QString &s) { LinkableMapObj *lmo=mapCenter->findObjBySelect(s); // Finally select the found object if (lmo) { if (selection) unselect(); selection=lmo; selection->select(); adjustCanvasSize(); ensureSelectionVisible(); return true; } return false; } void MapEditor::select (LinkableMapObj *lmo) { if (lmo && selection != lmo) { // select the MapObj if (selection) selection->unselect(); selection=lmo; selection->select(); adjustCanvasSize(); } } 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) finishedLineEdit(); 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) finishedLineEdit(); 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) finishedLineEdit(); 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) finishedLineEdit(); 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) finishedLineEdit(); 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) finishedLineEdit(); 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) finishedLineEdit(); QColor col = QColorDialog::getColor( mapCanvas->backgroundColor(), this ); if ( !col.isValid() ) return; setBackgroundColor( col ); saveState(QString("Set background color of map to %1").arg(col.name())); } 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)) { BranchObj *bo=(BranchObj*)selection; saveState(selection, QString("Set color of %1 to %2").arg(getName(bo)).arg(actColor.name())); //TODO undoCommand bo->setColor(actColor); // color branch } } } void MapEditor::colorBranch() { if (selection) { if (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) { BranchObj *bo=(BranchObj*)selection; saveState(selection, QString ("Set color of %1 and childs to %2").arg(getName(bo)).arg(actColor.name())); //TODO undoCommand bo->setColorChilds(actColor); // color links, color childs } } } void MapEditor::toggleStandardFlag(QString f) { if (selection) { BranchObj *bo=(BranchObj*)selection; QString s; if (bo->isSetStandardFlag(f)) s="Unset"; else s="Set"; saveState(selection, QString("%1 standard flag \"%2\" of %3").arg(s).arg(f).arg(getName(bo)));// TODO undoCommand bo->toggleStandardFlag (f,actionSettingsUseFlagGroups->isOn()); adjustCanvasSize(); } } 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::editURL() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) { bool ok; BranchObj *bo=(BranchObj*)selection; QString text = QInputDialog::getText( "VYM", tr("Enter URL:"), QLineEdit::Normal, bo->getURL(), &ok, this ); if ( ok) { // user entered something and pressed OK saveState("setURL (\""+bo->getURL()+"\")","setURL (\""+text+"\")", QString("Set URL of %1 to %21").arg(getName(bo)).arg(text)); bo->setURL (text); updateActions(); } } } QString MapEditor::getURL() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) return ((BranchObj*)selection)->getURL(); else return ""; } void MapEditor::editHeading2URL() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) { BranchObj *bo=(BranchObj*)selection; saveState("setURL (\""+bo->getURL()+"\")","setURL (\""+bo->getHeading()+"\")",QString("Copy heading of %1 to URL").arg(getName(bo))); bo->setURL (bo->getHeading()); updateActions(); } } void MapEditor::editBugzilla2URL() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) { BranchObj *bo=(BranchObj*)selection; QString url= "https://bugzilla.novell.com/show_bug.cgi?id="+bo->getHeading(); saveState("setURL (\""+bo->getURL()+"\")","setURL (\""+url+"\")",QString("Use heading of %1 as link to Novell Bugzilla").arg(getName(bo))); bo->setURL (url); updateActions(); } } void MapEditor::editFATE2URL() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) { BranchObj *bo=(BranchObj*)selection; QString url= "http://keeper.suse.de:8080/webfate/match/id?value=ID"+bo->getHeading(); saveState("setURL (\""+bo->getURL()+"\")","setURL (\""+url+"\")",QString("Use heading of %1 as link to FATE").arg(getName(bo))); bo->setURL (url); updateActions(); } } void MapEditor::editVymLink() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) { BranchObj *bo=(BranchObj*)selection; QFileDialog *fd=new QFileDialog( this,__VYM " - " +tr("Link to another map")); fd->addFilter (QString (tr("vym map") + " (*.vym)")); fd->setCaption(__VYM " - " +tr("Link to another map")); if (! bo->getVymLink().isEmpty() ) fd->setSelection( bo->getVymLink() ); fd->show(); QString fn; if ( fd->exec() == QDialog::Accepted ) { saveState("setVymLink (\""+bo->getVymLink()+"\")","setVymLink (\""+fd->selectedFile()+"\")",QString("Set vymlink of %1 to %2").arg(getName(bo)).arg(fd->selectedFile())); bo->setVymLink (fd->selectedFile() ); updateActions(); mapCenter->reposition(); adjustCanvasSize(); canvas()->update(); } } } void MapEditor::deleteVymLink() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) { BranchObj *bo=(BranchObj*)selection; saveState("setVymLink (\""+bo->getVymLink()+"\")","setVymLink (\"\")",QString("Unset vymlink of %1").arg(getName(bo))); bo->setVymLink ("" ); updateActions(); mapCenter->reposition(); adjustCanvasSize(); canvas()->update(); } } void MapEditor::toggleHideExport() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) || (typeid(*selection)==typeid(FloatImageObj)) ) { OrnamentedObj *oo=(OrnamentedObj*)selection; QString s; if (oo->hideInExport()) { oo->setHideInExport(false); s="Unset"; } else { oo->setHideInExport(true); s="Set"; } saveState(QString ("%1 hide export flag of %2").arg(s).arg(getName(selection))); //TODO undoCommand actionEditToggleHideExport->setOn (oo->hideInExport()); updateActions(); mapCenter->reposition(); adjustCanvasSize(); canvas()->update(); } } QString MapEditor::getVymLink() { if (selection && (typeid(*selection) == typeid(BranchObj) || typeid(*selection) == typeid(MapCenterObj)) ) { return ((BranchObj*)selection)->getVymLink(); } return ""; } void MapEditor::removeBranchKeepChilds() { if (selection && (typeid(*selection) == typeid(BranchObj) )) { BranchObj* bo=(BranchObj*)selection; BranchObj* par=(BranchObj*)(bo->getParObj()); QString s=QString("Remove %1 and keep its childs").arg(getName(bo)); if (bo->getDepth()==1) saveState(s); else saveState(selection->getParObj(),s); // TODO undoCommand QString sel=selection->getSelectString(); unselect(); par->removeBranchHere(bo); mapCenter->reposition(); select (sel); } } void MapEditor::removeChilds() { if (selection && (typeid(*selection) == typeid(BranchObj) )) { saveState(selection->getParObj(), QString("Remove childs of branch %1").arg(getName(selection))); ((BranchObj*)selection)->removeChilds(); mapCenter->reposition(); } } 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; uint xl=0; BranchObj *bo; bo=mapCenter->first(); while (bo) { if (!bo->getNote().isEmpty() ) n++; f+= bo->countFloatImages(); b++; xl+=bo->countXLinks(); bo=bo->next(); } 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) { saveState("Edit info about map"); //TODO undoCommand mapCenter->setAuthor (dia.getAuthor() ); mapCenter->setComment (dia.getComment() ); } } void MapEditor::updateActions() { QAction *a; 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)) ) { BranchObj *bo=(BranchObj*)selection; // Take care of links if (bo->countXLinks()==0) { branchLinksContextMenu->clear(); branchLinksContextMenu->insertItem ("No xLink available"); branchLinksContextMenuDup->clear(); branchLinksContextMenuDup->insertItem ("No xLink available"); } else { BranchObj *bot; QString s; branchLinksContextMenu->clear(); branchLinksContextMenuDup->clear(); for (int i=0; i<=bo->countXLinks();i++) { bot=bo->XLinkTargetAt(i); if (bot) { s=bot->getHeading(); if (s.length()>25) s=s.left(25)+"..."; branchLinksContextMenu->insertItem (s); branchLinksContextMenuDup->insertItem (s); } } } standardFlagsDefault->setEnabled (true); actionEditToggleScroll->setEnabled (true); if ( bo->isScrolled() ) actionEditToggleScroll->setOn(true); else actionEditToggleScroll->setOn(false); if ( bo->getURL().isEmpty() ) { actionEditOpenURL->setEnabled (false); actionEditOpenURLTab->setEnabled (false); } else { actionEditOpenURL->setEnabled (true); actionEditOpenURLTab->setEnabled (true); } if ( bo->getVymLink().isEmpty() ) { actionEditOpenVymLink->setEnabled (false); actionEditDeleteVymLink->setEnabled (false); } else { actionEditOpenVymLink->setEnabled (true); actionEditDeleteVymLink->setEnabled (true); } if (bo->canMoveBranchUp()) actionEditMoveUp->setEnabled (true); else actionEditMoveUp->setEnabled (false); if (bo->canMoveBranchDown()) actionEditMoveDown->setEnabled (true); else actionEditMoveDown->setEnabled (false); actionEditToggleHideExport->setEnabled (true); actionEditToggleHideExport->setOn (bo->hideInExport() ); actionEditCopy->setEnabled (true); actionEditCut->setEnabled (true); if (!clipboardEmpty) actionEditPaste->setEnabled (true); else actionEditPaste->setEnabled (false); for (a=actionListBranches.first();a;a=actionListBranches.next()) a->setEnabled(true); actionEditDelete->setEnabled (true); switch (selection->getFrameType()) { case NoFrame: actionFormatFrameNone->setOn(true); break; case Rectangle: actionFormatFrameRectangle->setOn(true); break; default: break; } actionFormatIncludeImagesVer->setOn ( ((BranchObj*)selection)->getIncludeImagesVer()); actionFormatIncludeImagesHor->setOn ( ((BranchObj*)selection)->getIncludeImagesHor()); actionFormatHideLinkUnselected->setOn (selection->getHideLinkUnselected()); } if ( (typeid(*selection) == typeid(FloatImageObj)) ) { FloatObj *fo=(FloatImageObj*)selection; standardFlagsDefault->setEnabled (false); actionEditOpenURL->setEnabled (false); actionEditOpenVymLink->setEnabled (false); actionEditDeleteVymLink->setEnabled (false); actionEditToggleHideExport->setEnabled (true); actionEditToggleHideExport->setOn (fo->hideInExport() ); actionEditCopy->setEnabled (true); actionEditCut->setEnabled (true); actionEditPaste->setEnabled (false); for (a=actionListBranches.first();a;a=actionListBranches.next()) a->setEnabled(false); actionEditDelete->setEnabled (true); actionFormatHideLinkUnselected->setOn ( selection->getHideLinkUnselected()); actionEditMoveUp->setEnabled (false); actionEditMoveDown->setEnabled (false); } } else { standardFlagsDefault->setEnabled (false); actionEditCopy->setEnabled (false); actionEditCut->setEnabled (false); actionEditPaste->setEnabled (false); for (a=actionListBranches.first();a;a=actionListBranches.next()) a->setEnabled(false); actionEditToggleScroll->setEnabled (false); actionEditOpenURL->setEnabled (false); actionEditOpenVymLink->setEnabled (false); actionEditDeleteVymLink->setEnabled (false); actionEditHeading2URL->setEnabled (false); actionEditDelete->setEnabled (false); actionEditMoveUp->setEnabled (false); actionEditMoveDown->setEnabled (false); actionEditToggleHideExport->setEnabled (false); } } void MapEditor::updateNoteFlag() { if (selection) if ( (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) ((BranchObj*)selection)->updateNoteFlag(); } void MapEditor::setLinkStyle (LinkStyle ls) { linkstyle=ls; saveState("Set link style"); // TODO undoCommand BranchObj *bo; bo=mapCenter->first(); bo=bo->next(); while (bo) { bo->setLinkStyle(bo->getDefLinkStyle()); bo=bo->next(); } mapCenter->reposition(); } 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::setDefXLinkColor(QColor col) { defXLinkColor=col; } QColor MapEditor::getDefXLinkColor() { return defXLinkColor; } void MapEditor::setDefXLinkWidth (int w) { defXLinkWidth=w; } int MapEditor::getDefXLinkWidth() { return defXLinkWidth; } void MapEditor::selectLinkColor() { // Finish open lineEdits if (lineedit) finishedLineEdit(); QColor col = QColorDialog::getColor( defLinkColor, this ); if ( !col.isValid() ) return; setLinkColor( col ); saveState(QString("Set link color to %1").arg(col.name())); //TODO undoCommand } void MapEditor::toggleScroll() { if (selection && (typeid(*selection) == typeid(BranchObj)) ) { BranchObj *bo=((BranchObj*)selection); if (bo->countBranches()==0) return; if (bo->getDepth()==0) return; QString s; if (bo->isScrolled()) s="Unscroll"; else s="Scroll"; saveState(selection, QString ("%1 %2").arg(s).arg(getName(bo))); 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); fd->setMode (QFileDialog::ExistingFiles); 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(__VYM " - " +tr("Load image")); fd->setDir (lastImageDir); fd->show(); QString fn; if ( fd->exec() == QDialog::Accepted ) { saveState(selection, QString("Add floatimage to %1").arg(getName(selection))); lastImageDir=fn.left(fn.findRev ("/")); QStringList flist = fd->selectedFiles(); QStringList::Iterator it = flist.begin(); while( it != flist.end() ) { fn = *it; bo->addFloatImage(); // TODO check if load was successful bo->getLastFloatImage()->load(*it); bo->getLastFloatImage()->setOriginalFilename(fn); ++it; } mapCenter->reposition(); adjustCanvasSize(); canvas()->update(); } delete (p); delete (fd); } } 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(__VYM " - " +tr("Save image as %1").arg(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 %1 exists already.\n" "Do you want to overwrite it?").arg(fd->selectedFile()), 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::setFrame(const FrameType &t) { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) { selection->setFrameType (t); mapCenter->reposition(); selection->updateLink(); } } void MapEditor::setIncludeImagesVer(bool b) { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) ((BranchObj*)selection)->setIncludeImagesVer(b); mapCenter->reposition(); } void MapEditor::setIncludeImagesHor(bool b) { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) ((BranchObj*)selection)->setIncludeImagesHor(b); mapCenter->reposition(); } void MapEditor::setHideLinkUnselected (bool b) { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) || (typeid(*selection) == typeid(FloatImageObj)) ) selection->setHideLinkUnselected(b); } 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")); 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 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")); if (fi->fileName().right(4) == ".vym" ) bo->setVymLink (fi->filePath()); ++itfile; } } } void MapEditor::importDir() { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) { QFileDialog *fd=new QFileDialog( this,__VYM " - " +tr("Choose directory structure to import")); fd->setMode (QFileDialog::DirectoryOnly); fd->addFilter (QString (tr("vym map") + " (*.vym)")); fd->setCaption(__VYM " - " +tr("Choose directory structure 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::followXLink(int i) { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) { BranchObj *bo=((BranchObj*)selection)->XLinkTargetAt(i); if (bo) { selection->unselect(); selection=bo; selection->select(); ensureSelectionVisible(); } } } void MapEditor::editXLink(int i) { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) { XLinkObj *xlo=((BranchObj*)selection)->XLinkAt(i); if (xlo) { EditXLinkDialog dia; dia.setXLink (xlo); dia.setSelection(selection); if (dia.exec() == QDialog::Accepted) { if (dia.useSettingsGlobal() ) { setDefXLinkColor (xlo->getColor() ); setDefXLinkWidth (xlo->getWidth() ); } if (dia.deleteXLink()) ((BranchObj*)selection)->deleteXLinkAt(i); saveState("Edit xLink"); //TODO undoCommand } } } } void MapEditor::testFunction() { cout << "MapEditor::testFunction() called\n"; mapCenter->positionBBox(); return; WarningDialog dia; dia.setCancelButton (true); dia.setText("This is a longer \nWarning"); dia.setCaption("Warning: Flux problem"); dia.setShowAgainName("/vym/warnings/mapeditor"); if (dia.exec()==QDialog::Accepted) cout << "accepted!\n"; else cout << "canceled!\n"; return; QString ub=vymBaseDir.path()+"/scripts/update-bookmarks"; QProcess *proc = new QProcess( this ); proc->addArgument(ub); if ( !proc->start() ) { QMessageBox::warning(0, tr("Warning"), tr("Couldn't find script %1\nto notifiy Browsers of changed bookmarks.").arg(ub)); } /* if (hidemode==HideNone) { setHideTmpMode (HideExport); mapCenter->calcBBoxSizeWithChilds(); QRect totalBBox=mapCenter->getTotalBBox(); QRect mapRect=totalBBox; QCanvasRectangle *frame=NULL; cout << " map has =("<setBrush (QColor(white)); frame->setPen (QColor(black)); frame->setZ(0); frame->show(); } else { setHideTmpMode (HideNone); } cout <<" hidemode="< (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() ); } e->accept(); } void MapEditor::contentsMousePressEvent(QMouseEvent* e) { // Ignore right clicks, these will go to context menus if (e->button() == QMouseEvent::RightButton ) { e->ignore(); return; } // Finish open lineEdits if (lineedit) finishedLineEdit(); QPoint p = inverseWorldMatrix().map(e->pos()); LinkableMapObj* lmo=mapCenter->findMapObj(p, NULL); e->accept(); //Take care of clickdesystem 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 select (lmo); if (foname=="url") { if (e->state() & QMouseEvent::ControlButton) 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(); return; } } // No system flag clicked, take care of modmodes // Special case: CTRL is pressed if (e->state() & QMouseEvent::ControlButton) { if (actionModModeColor->isOn()) { pickingColor=true; setCursor (pickColorCursor); return; } if (actionModModeLink->isOn()) { BranchObj *bo_begin=NULL; if (lmo) bo_begin=(BranchObj*)(lmo); else if (selection && ((typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj))) ) bo_begin=(BranchObj*)selection; if (bo_begin) { drawingLink=true; linkingObj_src=bo_begin; tmpXLink=new XLinkObj (mapCanvas); tmpXLink->setBegin (bo_begin); tmpXLink->setEnd (p); tmpXLink->setColor(defXLinkColor); tmpXLink->setWidth(defXLinkWidth); tmpXLink->updateXLink(); tmpXLink->setVisibility (true); return; } } } if (lmo) { select (lmo); // Left Button Move Branches if (e->button() == QMouseEvent::LeftButton ) { movingObj_start.setX( p.x() - selection->x() ); movingObj_start.setY( p.y() - selection->y() ); movingObj_orgPos.setX (lmo->x() ); movingObj_orgPos.setY (lmo->y() ); // 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 (actionModModeCopy->isOn() && e->state() & QMouseEvent::ControlButton) { if (typeid(*selection)==typeid(BranchObj) ) { copyingObj=true; mapCenter->addBranch ((BranchObj*)selection); unselect(); selection=mapCenter->getLastBranch(); selection->select(); mapCenter->reposition(); } } movingObj=selection; } 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) { QPoint p = inverseWorldMatrix().map(e->pos()); // Move the selected MapObj if ( selection && movingObj) { // To avoid jumping of the CanvasView, only // ensureSelectionVisible, if not tmp linked if (!selection->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) LinkableMapObj *lmosel; lmosel = dynamic_cast (selection); // Check if we could link LinkableMapObj* lmo=mapCenter->findMapObj(p, lmosel); if (typeid(*selection) == typeid(FloatImageObj)) { FloatObj *fo=(FloatObj*)selection; saveState( "move "+qpointToString(movingObj_orgPos),fo->getSelectString() , QString("Move %1").arg(getName(selection))); 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)) { saveState(QString("Relink %1 to %2").arg(getName(fo)).arg(getName(lmo) ) ); 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); } } } 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 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() +lmosel->getTopPad() ); else lmosel->move(p.x() -movingObj_start.x(), p.y()-movingObj_start.y() -lmosel->getTopPad()); } // 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 { lmosel->unsetParObjTmp(); } } // depth>0 } // no FloatImageObj canvas()->update(); return; } // selection && moving_obj // Draw a link from one branch to another if (drawingLink) { tmpXLink->setEnd (p); tmpXLink->updateXLink(); } // Move CanvasView if (!movingObj && !pickingColor &&!drawingLink) { 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()); ((BranchObj*)selection)->setLinkColor (); } else { ((BranchObj*)selection)->setColorChilds (((BranchObj*)(dst))->getColor()); ((BranchObj*)selection)->setLinkColor (); } } return; } // Have we been drawing a link? if (drawingLink) { drawingLink=false; // Check if we are over another branch dst=mapCenter->findMapObj(inverseWorldMatrix().map(e->pos() ), NULL); if (dst && selection) { tmpXLink->setEnd ( ((BranchObj*)(dst)) ); tmpXLink->updateXLink(); tmpXLink->activate(); saveState(QString("Activate xLink from %1 to %2").arg(getName(tmpXLink->getBegin())).arg(getName(tmpXLink->getEnd())) ); //TODO undoCommand } else { delete(tmpXLink); tmpXLink=NULL; } return; } // Have we been moving something? if ( selection && movingObj ) { // Moved FloatObj? Maybe we need to reposition if(typeid(*selection)==typeid (FloatImageObj)) { selection->getParObj()->requestReposition(); mapCenter->reposition(); } // 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(); copyingObj=false; if (dst ) { BranchObj* bs=((BranchObj*)selection); QString undoCom="linkBranchToPos (\""+ (bs->getParObj())->getSelectString()+ "\","+ QString("%1").arg(bs->getNum())+ ","+ QString ("%1,%2").arg(movingObj_orgPos.x()).arg(movingObj_orgPos.y())+ ")"; // TODO we also could check, if dest and src are on same branch, // then it would be sufficient to saveState of this branch // Modifiers allow to insert above/below dst if (e->state() & QMouseEvent::ShiftButton) { bs->moveBranchTo ( (BranchObj*)(dst->getParObj()), ((BranchObj*)(dst))->getNum()); } else if (e->state() & QMouseEvent::ControlButton) { bs->moveBranchTo ( (BranchObj*)(dst->getParObj()), ((BranchObj*)(dst))->getNum()+1); } else { bs->moveBranchTo ((BranchObj*)(dst),-1); if (dst->getDepth()==0) bs->move (savePos); } saveState (undoCom,bs->getSelectString(),QString("Relink %1 to %2").arg(getName(bs)).arg(getName(dst)) ); } else if (selection->getDepth()==1) // If we have moved mainbranch only save endposition saveState("move "+qpointToString(movingObj_orgPos), selection->getSelectString(), QString("Move %1 to %2").arg(getName(selection)).arg(qpointToString(movingObj_orgPos))); // 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) finishedLineEdit(); 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(); editHeading(); } } } void MapEditor::resizeEvent (QResizeEvent* e) { QCanvasView::resizeEvent( e ); adjustCanvasSize(); } void MapEditor::contentsDragEnterEvent(QDragEnterEvent *event) { // for (unsigned int i=0;event->format(i);i++) // Debug mime type // cerr << event->format(i) << endl; if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj))) { // If QImageDrag can decode mime type if (QImageDrag::canDecode(event)) { event->accept(); return; } // If image are dragged from firefox if (event->provides("application/x-moz-file-promise-url") && event->provides("application/x-moz-nativeimage")) { event->accept(true); return; } // If QUriDrag can decode mime type if (QUriDrag::canDecode(event)) { event->accept(); return; } // If Uri are dragged from firefox if (event->provides("_NETSCAPE_URL")){ event->accept(); return; } // If QTextDrag can decode mime type if (QTextDrag::canDecode(event)) { event->accept(); return; } } event->ignore(); } 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; iprovides("image/png")) { QPixmap pix; if (QImageDrag::decode(event, pix)) { addFloatImage(pix); event->accept(); update=true; } else event->ignore(); } 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 QUriDrag::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; } if (uris.count()>0) { QStringList files; QStringList urls; QString s; BranchObj *bo; for (const char* u=uris.first(); u; u=uris.next()) { bo=((BranchObj*)selection)->addBranch(); if (bo) { s=QUriDrag::uriToLocalFile(u); if (s) { QString file = QDir::convertSeparators(s); heading = QFileInfo(file).baseName(); files.append(file); if (file.endsWith(".vym", false)) bo->setVymLink(file); else bo->setURL(u); } else { urls.append (u); bo->setURL(u); } if (heading) bo->setHeading(heading); else bo->setHeading(u); } } update=true; } if (update) { //FIXME saveState has to be called earlier for each of the drops... saveState("Drop Event"); //TODO undo Command mapCenter->reposition(); adjustCanvasSize(); canvas()->update(); } } } void MapEditor::addFloatImage(const QPixmap &img) { if (selection && (typeid(*selection) == typeid(BranchObj)) || (typeid(*selection) == typeid(MapCenterObj)) ) { BranchObj *bo=((BranchObj*)selection); saveState(selection,QString("Add floatimage to %1").arg(getName(bo))); //QString fn=fd->selectedFile(); //lastImageDir=fn.left(fn.findRev ("/")); bo->addFloatImage(); // FIXME check if load was successful bo->getLastFloatImage()->load(img); //bo->getLastFloatImage()->setOriginalFilename(fn); mapCenter->reposition(); adjustCanvasSize(); canvas()->update(); } } void MapEditor::imageDataFetched(const QByteArray &a, QNetworkOperation */*nop*/) { if (!imageBuffer) imageBuffer = new QBuffer(); if (!imageBuffer->isOpen()) { imageBuffer->open(IO_WriteOnly | IO_Append); } imageBuffer->at(imageBuffer->at()+imageBuffer->writeBlock(a)); } void MapEditor::imageDataFinished(QNetworkOperation *nop) { if (nop->state()==QNetworkProtocol::StDone) { QPixmap img(imageBuffer->buffer()); addFloatImage(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 QUrlOperator(url); connect(urlOperator, SIGNAL(finished(QNetworkOperation *)), this, SLOT(imageDataFinished(QNetworkOperation*))); connect(urlOperator, SIGNAL(data(const QByteArray &, QNetworkOperation *)), this, SLOT(imageDataFetched(const QByteArray &, QNetworkOperation *))); urlOperator->get(); }