From: Sven Hoexter Date: Fri, 26 Sep 2025 17:32:06 +0000 (+0200) Subject: New upstream version 2.9.598 X-Git-Tag: upstream/2.9.598^0 X-Git-Url: https://git.sven.stormbind.net/?a=commitdiff_plain;h=0a4cffb512dcb3fdf8c1c678c19205d9607b53bc;p=sven%2Fvym.git New upstream version 2.9.598 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2f186c --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# CMake files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +install_manifest.txt +Makefile + +# Qt/CMake autogen and deploy +vym_autogen/ +.qt/ + +# Built binary +vym + +# Qt translation artifacts +translations/*.qm diff --git a/CMakeLists.txt b/CMakeLists.txt index 800e4e1..1d23a2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(QtLibraries # or uncomment here: # set(CMAKE_BUILD_TYPE Debug) +# No longer needed with qt_standard_project_setup() below... set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) @@ -49,7 +50,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux) find_package(DBus1) if(DBus1_FOUND) - message(STATUS "Deteced DBUS1 available, adding DBUS interfaces") + message(STATUS "Deteced Linux and DBUS1, adding DBUS interfaces") LIST(APPEND QtComponents DBus) LIST(APPEND QtLibraries Qt6::DBus) @@ -75,6 +76,11 @@ if(WIN32) set(CMAKE_INSTALL_DATAROOTDIR ".") endif() + +# https://doc.qt.io/qt-6/qt-standard-project-setup.html +find_package(Qt6 REQUIRED COMPONENTS Core) +qt_standard_project_setup() + include(GNUInstallDirs) find_package(Qt6 COMPONENTS ${QtComponents} REQUIRED) diff --git a/config/io.github.insilmaril.vym.appdata.xml b/config/io.github.insilmaril.vym.appdata.xml index 55d378a..5d9a24e 100644 --- a/config/io.github.insilmaril.vym.appdata.xml +++ b/config/io.github.insilmaril.vym.appdata.xml @@ -2,7 +2,7 @@ io.github.insilmaril.vym CC0-1.0 - LGPL-2.1-or-later + GPL-2.0 VYM Tool for generating and manipulating mind maps @@ -26,7 +26,9 @@ https://github.com/insilmaril/vym/issues http://www.insilmaril.de/vym/ - vym + + Uwe Drechsel + HiDpiIcon HighContrast diff --git a/demos/default-dark.vym b/demos/default-dark.vym index 607343d..2d55700 100644 Binary files a/demos/default-dark.vym and b/demos/default-dark.vym differ diff --git a/demos/default.vym b/demos/default.vym index 4858026..545a3c9 100644 Binary files a/demos/default.vym and b/demos/default.vym differ diff --git a/demos/lifeforms.vym b/demos/lifeforms.vym index 853932c..9601d2b 100644 Binary files a/demos/lifeforms.vym and b/demos/lifeforms.vym differ diff --git a/demos/math.vym b/demos/math.vym index b8e2c63..8732063 100644 Binary files a/demos/math.vym and b/demos/math.vym differ diff --git a/demos/task-management.vym b/demos/task-management.vym index 9057a98..2023e8a 100644 Binary files a/demos/task-management.vym and b/demos/task-management.vym differ diff --git a/demos/time-management.vym b/demos/time-management.vym index d0554f1..b9ec08f 100644 Binary files a/demos/time-management.vym and b/demos/time-management.vym differ diff --git a/flags/system/applications-internet-new.svg b/flags/system/applications-internet-new.svg deleted file mode 100644 index 72532d0..0000000 --- a/flags/system/applications-internet-new.svg +++ /dev/null @@ -1,1084 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - Jakub Steiner - - - - - Tuomas Kuosmanen - - - - http://jimmac.musichall.cz - - - internet - tools - applications - category - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flags/system/applications-internet.svg b/flags/system/applications-internet.svg deleted file mode 100644 index 632865e..0000000 --- a/flags/system/applications-internet.svg +++ /dev/null @@ -1,591 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - Jakub Steiner - - - - - Tuomas Kuosmanen - - - - http://jimmac.musichall.cz - - - internet - tools - applications - category - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flags/system/flag-jira.svg b/flags/system/flag-jira.svg new file mode 100644 index 0000000..7f35cf2 --- /dev/null +++ b/flags/system/flag-jira.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + diff --git a/flags/system/flag-url.svg b/flags/system/flag-url.svg new file mode 100644 index 0000000..632865e --- /dev/null +++ b/flags/system/flag-url.svg @@ -0,0 +1,591 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Jakub Steiner + + + + + Tuomas Kuosmanen + + + + http://jimmac.musichall.cz + + + internet + tools + applications + category + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flags/system/flag-urlnew.svg b/flags/system/flag-urlnew.svg new file mode 100644 index 0000000..72532d0 --- /dev/null +++ b/flags/system/flag-urlnew.svg @@ -0,0 +1,1084 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Jakub Steiner + + + + + Tuomas Kuosmanen + + + + http://jimmac.musichall.cz + + + internet + tools + applications + category + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flags/system/jissue.svg b/flags/system/jissue.svg deleted file mode 100644 index 7f35cf2..0000000 --- a/flags/system/jissue.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/forms/jira-settings-dialog.ui b/forms/jira-settings-dialog.ui index cf3721a..1a44e5a 100644 --- a/forms/jira-settings-dialog.ui +++ b/forms/jira-settings-dialog.ui @@ -79,29 +79,65 @@ - + - Use Personal Access Token instead of username and password for authentication + Authentication method: - - - Personal Access Token: - + + + + Username/Password + + + + + PAT + + + + + Cloud + + - - - Qt::ImhNone - - - QLineEdit::Password - - - + + + Personal Access Token: + + + + + + + Qt::ImhNone + + + QLineEdit::Password + + + + + + + API token: + + + + + + + Qt::ImhNone + + + QLineEdit::Password + + + diff --git a/macros/macros.vys b/macros/macros.vys index f976638..54ee4c7 100644 --- a/macros/macros.vys +++ b/macros/macros.vys @@ -43,8 +43,9 @@ function colorSubtreeWithQuickColor(n) vym.selectQuickColor(n); c = vym.currentColor(); - b = map.selectedBranch(); - b.colorSubtree (c); + branches = map.selectedBranches(); + for (b of branches) + b.colorSubtree(c); } //! Macro F1: Color subtree red @@ -112,11 +113,11 @@ function macro_f10() colorSubtreeWithQuickColor(9); } -//! Macro F11: Repeat last command +//! Macro F11: function macro_f11() { map = vym.currentMap(); - map.repeatLastCommand(); + // Unused } //! Macro F12: toggle high prio task @@ -163,6 +164,7 @@ function macro_shift_f1() toggle_frame_branch ( map ); b.setFrameBrushColor(true, "#ffb3b4"); vym.statusMessage(status); + } //! Macro Shift + F2: Frame background light green diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index d3b7651..bdcc605 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -87,6 +87,7 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) "" "
  • Patches" "
      " + "
    • Loric Brevet: Enabling Jira Cloud and usability discussions
    • " "
    • Bleyddyn: "Clear" button in "Recent files" menu and improving remembering last directory
    • " "
    • Sven Höxter: Various patches to fix typos and especiall for Debian packaging
    • " "
    • Edward Wang: adding close tab buttons
    • " diff --git a/src/branch-container-base.cpp b/src/branch-container-base.cpp index bbe0a2a..a9eebd5 100644 --- a/src/branch-container-base.cpp +++ b/src/branch-container-base.cpp @@ -21,6 +21,7 @@ void BranchContainerBase::init() setBrush(Qt::NoBrush); setPen(QPen(Qt::NoPen)); + // setPen(QPen(Qt::blue)); // Testing only horizontalDirection = Container::LeftToRight; } diff --git a/src/branch-container.cpp b/src/branch-container.cpp index ccc99b3..dddaacf 100644 --- a/src/branch-container.cpp +++ b/src/branch-container.cpp @@ -123,9 +123,9 @@ void BranchContainer::init() // Center of whole mainBranches should be the heading setCentralContainer(headingContainer); - // Elastic layout experiments FIXME-3 + // Elastic layout experiments. v not really used currently FIXME-3 v_anim = QPointF(0, 0); - v.setParentItem(this); + v.setParentItem(this); // Animation vector for animated layout v.setPen(QPen(Qt::red)); v.setVisible(false); @@ -865,7 +865,8 @@ void BranchContainer::updateUpLink() } // Create/delete bottomline, depends on frame and (List-)Layout - if (frameType(true) != FrameContainer::NoFrame || + if (frameType(true) != FrameContainer::NoFrame || + frameType(false) != FrameContainer::NoFrame || branchesContainerAndOrnamentsVerticalInt || (pbc && pbc->branchesContainerLayoutInt == List)) { if (upLink->hasBottomLine()) @@ -975,14 +976,14 @@ void BranchContainer::setBranchesContainerAndOrnamentsVertical(bool b) branchesContainerAndOrnamentsVerticalInt = b; } -QRectF BranchContainer::headingRect() +QRectF BranchContainer::headingSceneRect() { // Returns scene coordinates of bounding rectanble return headingContainer->mapToScene(headingContainer->rect()) .boundingRect(); } -QRectF BranchContainer::ornamentsRect() +QRectF BranchContainer::ornamentsSceneRect() { // Returns scene coordinates of bounding rectanble return ornamentsContainer->mapToScene(headingContainer->rect()) @@ -1413,7 +1414,7 @@ void BranchContainer::reposition() // on MovingState if (pbc) { if (pbc->hasFloatingBranchesLayout()) { - if (scenePos().x() > pbc->scenePos().x()) // FIXME-2 problematic for rotated elements... + if (scenePos().x() > pbc->scenePos().x()) // FIXME-3 Potentially problematic for rotated elements... // but OTOH using relative coord // often pos.x() == 0 orientation = RightOfParent; diff --git a/src/branch-container.h b/src/branch-container.h index da6683a..5e120c5 100644 --- a/src/branch-container.h +++ b/src/branch-container.h @@ -100,8 +100,8 @@ class BranchContainer : public BranchContainerBase, public LinkableContainer { void setBranchesContainerAndOrnamentsVertical(bool); - QRectF headingRect(); //! Return rectangle of HeadingContainer in absolute coordinates - QRectF ornamentsRect(); //! Return rectangle of ornamentsContainer in absolute coordinates + QRectF headingSceneRect(); //! Return rectangle of HeadingContainer in scene coordinates + QRectF ornamentsSceneRect(); //! Return rectangle of ornamentsContainer in scene coordinates void setColumnWidthAutoDesign(const bool &); bool columnWidthAutoDesign(); diff --git a/src/branch-wrapper.cpp b/src/branch-wrapper.cpp index 367c7de..aa9e72c 100644 --- a/src/branch-wrapper.cpp +++ b/src/branch-wrapper.cpp @@ -306,6 +306,13 @@ QString BranchWrapper::getHeading() return r; } +QString BranchWrapper::getHeadingColor() +{ + QString r = branchItemInt->headingColor().name(); + mainWindow->setScriptResult(r); + return r; +} + QString BranchWrapper::getHeadingXML() { QString r = branchItemInt->heading().saveToDir(); diff --git a/src/branch-wrapper.h b/src/branch-wrapper.h index 394c793..a7a386b 100644 --- a/src/branch-wrapper.h +++ b/src/branch-wrapper.h @@ -46,6 +46,7 @@ class BranchWrapper : public QObject { int getFramePenWidth(const bool & useInnerFrame); QString getFrameType(const bool & useInnerFrame); QString getHeading(); + QString getHeadingColor(); QString getHeadingXML(); QString getImagesLayout(); void getJiraData(bool subtree); diff --git a/src/branchitem.cpp b/src/branchitem.cpp index 797bd83..394b45f 100644 --- a/src/branchitem.cpp +++ b/src/branchitem.cpp @@ -14,6 +14,8 @@ extern TaskModel *taskModel; +extern FlagRowMaster *systemFlagsMaster; + BranchItem::BranchItem(TreeItem *parent) : MapItem(parent) { @@ -247,7 +249,7 @@ void BranchItem::updateTaskFlag() { systemFlags.deactivateGroup("system-tasks"); if (task) { - QString s = "system-" + task->getIconString(); + QString s = "system-" + task->iconString(); systemFlags.activate(s); model->emitDataChanged(this); } @@ -263,6 +265,14 @@ void BranchItem::setTask(Task *t) Task *BranchItem::getTask() { return task; } +Flag *BranchItem::taskFlag() +{ + if (!task) + return nullptr; + + return systemFlagsMaster->findFlagByName("system-" + task->iconString()); +} + void BranchItem::scroll() { if (tmpUnscrolled) diff --git a/src/branchitem.h b/src/branchitem.h index 7d01281..6c0c103 100644 --- a/src/branchitem.h +++ b/src/branchitem.h @@ -42,6 +42,7 @@ class BranchItem : public MapItem { void updateTaskFlag(); void setTask(Task *t); Task *getTask(); + Flag *taskFlag(); private: Task *task; diff --git a/src/command.cpp b/src/command.cpp index 374514f..fa706db 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -77,6 +77,8 @@ QString Command::typeToString(const ParameterType &type) return "Bool"; case BranchPar: return "Branch"; + case BranchListPar: + return "BranchesList"; case ColorPar: return "Color"; case DoublePar: @@ -87,6 +89,8 @@ QString Command::typeToString(const ParameterType &type) return "Int"; case StringPar: return "String"; + case StringListPar: + return "StringsList"; case UndefinedPar: return "Undefined"; case VoidPar: diff --git a/src/command.h b/src/command.h index e5deebf..fce2f2a 100644 --- a/src/command.h +++ b/src/command.h @@ -19,6 +19,7 @@ class Command { AttributePar, BoolPar, BranchPar, + BranchListPar, ColorPar, DoublePar, ImagePar, @@ -28,6 +29,7 @@ class Command { StringListPar, UndefinedPar, VoidPar, + VymModelPar, XLinkPar }; enum SelectionType { diff --git a/src/container.cpp b/src/container.cpp index 700aa4b..ae2ec65 100644 --- a/src/container.cpp +++ b/src/container.cpp @@ -45,7 +45,7 @@ void Container::init() // subcontainers usually may influence position // Only mapCenters will stay where they are - minimumWidth = 0; // FIXME-3 currently unused, maybe for linkSpaceContainer + minimumWidth = 0; // FIXME-3 currently unused, maybe for linkSpaceContainer or fixed dimensions horizontalDirection = LeftToRight; horizontalAlignmentInt = HorAlignedLeft; diff --git a/src/export-ao.cpp b/src/export-ao.cpp index c2d9557..8ae9265 100644 --- a/src/export-ao.cpp +++ b/src/export-ao.cpp @@ -6,6 +6,7 @@ #include "branchitem.h" #include "mainwindow.h" +#include "misc.h" #include "task.h" #include "vymmodel.h" @@ -167,10 +168,3 @@ void ExportAO::doExport() completeExport(); } -QString ExportAO::underline(const QString &text, const QString &line) -{ - QString r = text + "\n"; - for (int j = 0; j < text.length(); j++) - r += line; - return r; -} diff --git a/src/export-ao.h b/src/export-ao.h index 37f8d0f..1d19ad2 100644 --- a/src/export-ao.h +++ b/src/export-ao.h @@ -7,7 +7,6 @@ class ExportAO : public ExportBase { public: ExportAO(); virtual void doExport(); - virtual QString underline(const QString &text, const QString &line); }; #endif diff --git a/src/export-ascii.cpp b/src/export-ascii.cpp index 4d56e9a..467603e 100644 --- a/src/export-ascii.cpp +++ b/src/export-ascii.cpp @@ -6,6 +6,7 @@ #include "branchitem.h" #include "mainwindow.h" +#include "misc.h" #include "task.h" #include "vymmodel.h" @@ -158,14 +159,6 @@ void ExportASCII::doExport() completeExport(args); } -QString ExportASCII::underline(const QString &text, const QString &line) -{ - QString r = text + "\n"; - for (int j = 0; j < text.length(); j++) - r += line; - return r; -} - QString ExportASCII::ensureEmptyLines(QString &text, int n) { // Ensure at least n empty lines at the end of text diff --git a/src/export-ascii.h b/src/export-ascii.h index 083ec89..7bb5aa4 100644 --- a/src/export-ascii.h +++ b/src/export-ascii.h @@ -7,7 +7,6 @@ class ExportASCII : public ExportBase { public: ExportASCII(); virtual void doExport(); - QString underline(const QString &text, const QString &line); QString ensureEmptyLines(QString &text, int n); QString ensureNewLine(QString &text); }; diff --git a/src/export-confluence.cpp b/src/export-confluence.cpp index ef534fc..326729e 100644 --- a/src/export-confluence.cpp +++ b/src/export-confluence.cpp @@ -74,7 +74,7 @@ QString ExportConfluence::getBranchText(BranchItem *current) Task *task = current->getTask(); if (task) { - QString taskName = task->getIconString(); + QString taskName = task->iconString(); taskFlags += QString("\"%2\"") .arg(taskName) .arg(QObject::tr("Flag: %1","Alt tag in HTML export").arg(taskName)); diff --git a/src/export-html.cpp b/src/export-html.cpp index e6c95c4..f2059da 100644 --- a/src/export-html.cpp +++ b/src/export-html.cpp @@ -19,6 +19,7 @@ extern QString vymHome; extern FlagRowMaster *standardFlagsMaster; extern FlagRowMaster *userFlagsMaster; +extern FlagRowMaster *systemFlagsMaster; ExportHTML::ExportHTML() : ExportBase() { init(); } @@ -29,6 +30,8 @@ void ExportHTML::init() exportName = "HTML"; extension = ".html"; frameURLs = true; + + flagWidthInt = " width=\"32\" "; // FIXME-3 use CSS instead } QString ExportHTML::getBranchText(BranchItem *current) @@ -55,14 +58,31 @@ QString ExportHTML::getBranchText(BranchItem *current) // Task flags QString taskFlags; + QString flagName;; + QString flagPath; if (dia.useTaskFlags) { Task *task = current->getTask(); if (task) { - QString taskName = task->getIconString(); - taskFlags += - QString("\"%2\"") - .arg(taskName) - .arg(QObject::tr("Flag: %1", "Alt tag in HTML export").arg(taskName)); + QString taskName = task->iconString(); + Flag *f = current->taskFlag(); + if (f) { + flagName = f->getName(); + ImageContainer *ic = f->getImageContainer(); + if (!ic) { + qWarning() << __func__ << "ic == nullptr for task"; + return "Error..."; + } + + flagPath = flagsDir.path() + "/" + ic->originalFilename(); + + if (!activeSystemFlagNames.contains(flagName)) { + activeSystemFlagNames << flagName; + ic->save(flagPath); + } + taskFlags += + QString("\"%3\"") + .arg(flagWidthInt, basename(flagPath), taskName); + } } } @@ -80,7 +100,8 @@ QString ExportHTML::getBranchText(BranchItem *current) if (f) flags += QString( - "\"%1\"") + "\"%2\"") + .arg(flagWidthInt) .arg(QObject::tr("Flag: %1", "Alt tag in HTML export").arg(f->getName())) .arg(f->getImageContainer()->originalFilename()); } @@ -91,12 +112,30 @@ QString ExportHTML::getBranchText(BranchItem *current) if (dia.useNumbering) number = getSectionString(current) + " "; - // URL + // Url if (!url.isEmpty()) { - s += QString("%2") + Flag *f = current->urlFlag(); + if (f) { + flagName = f->getName(); + ImageContainer *ic = f->getImageContainer(); + if (!ic) { + qWarning() << __func__ << "ic == nullptr for Url"; + return "Error..."; + } + + flagPath = flagsDir.path() + "/" + ic->originalFilename(); + + if (!activeSystemFlagNames.contains(flagName)) { + activeSystemFlagNames << flagName; + ic->save(flagPath); + } + } + s += QString("%2") .arg(url) .arg(number + taskFlags + heading + flags) + .arg(flagWidthInt) + .arg(basename(flagPath)) .arg(QObject::tr("Flag: url", "Alt tag in HTML export")); QRectF fbox = current->getBranchContainer()->getBBoxURLFlag(); @@ -109,6 +148,7 @@ QString ExportHTML::getBranchText(BranchItem *current) .arg(fbox.bottom() - offset.y()) .arg(url) .arg(heading); + } else s += number + taskFlags + heading + flags; @@ -285,7 +325,7 @@ QString ExportHTML::createTOC() return toc; } -void ExportHTML::doExport(bool useDialog) // FIXME-2 System flags not written. (URL, task, scrolled, ...) +void ExportHTML::doExport(bool useDialog) { // Setup dialog and read settings dia.setMapName(model->getMapName()); @@ -398,7 +438,16 @@ void ExportHTML::doExport(bool useDialog) // FIXME-2 System flags not written. ( // reset flags model->resetUsedFlags(); - + flagsDir.setPath(dia.getDir().absolutePath() + "/flags"); + if (!flagsDir.exists()) { + if (!dia.getDir().mkdir("flags")) { + QMessageBox::critical( + 0, QObject::tr("Critical"), + QObject::tr("Trying to create directory for flags:") + "\n\n" + + QObject::tr("Could not create %1").arg(flagsDir.path())); + return; + } + } // Main loop over all mapcenters ts << buildList(model->getRootItem()) << "\n"; @@ -420,17 +469,8 @@ void ExportHTML::doExport(bool useDialog) // FIXME-2 System flags not written. ( ts << ""; file.close(); - QString flagsBasePath = dia.getDir().absolutePath() + "/flags"; - QDir d(flagsBasePath); - if (!d.exists()) { - if (!dia.getDir().mkdir("flags")) { - QMessageBox::critical( - 0, QObject::tr("Critical"), - QObject::tr("Trying to create directory for flags:") + "\n\n" + - QObject::tr("Could not create %1").arg(flagsBasePath)); - return; - } - } + + // Copy standard flags Flag *f; foreach (QUuid uid, activeFlags) { f = standardFlagsMaster->findFlagByUid(uid); @@ -440,7 +480,7 @@ void ExportHTML::doExport(bool useDialog) // FIXME-2 System flags not written. ( if (f) { ImageContainer *ic = f->getImageContainer(); if (ic) - ic->save(flagsBasePath + "/" + ic->originalFilename()); + ic->save(flagsDir.path() + "/" + ic->originalFilename()); } } diff --git a/src/export-html.h b/src/export-html.h index d38b8ab..8c2c199 100644 --- a/src/export-html.h +++ b/src/export-html.h @@ -21,13 +21,18 @@ class ExportHTML : public ExportBase { QString cssSrc; QString cssDst; + QString flagWidthInt; + bool frameURLs; QPointF offset; QSet activeFlags; + QStringList activeSystemFlagNames; ExportHTMLDialog dia; + + QDir flagsDir; }; #endif diff --git a/src/export-markdown.cpp b/src/export-markdown.cpp index 478ff36..7159586 100644 --- a/src/export-markdown.cpp +++ b/src/export-markdown.cpp @@ -6,6 +6,7 @@ #include "branchitem.h" #include "mainwindow.h" +#include "misc.h" #include "task.h" #include "vymmodel.h" @@ -162,10 +163,3 @@ void ExportMarkdown::doExport() completeExport(args); } -QString ExportMarkdown::underline(const QString &text, const QString &line) -{ - QString r = text + "\n"; - for (int j = 0; j < text.length(); j++) - r += line; - return r; -} diff --git a/src/export-markdown.h b/src/export-markdown.h index 6b7f6a9..d4c7331 100644 --- a/src/export-markdown.h +++ b/src/export-markdown.h @@ -7,7 +7,6 @@ class ExportMarkdown : public ExportBase { public: ExportMarkdown(); virtual void doExport(); - virtual QString underline(const QString &text, const QString &line); }; #endif diff --git a/src/findcontrolswidget.cpp b/src/findcontrolswidget.cpp new file mode 100644 index 0000000..02760b8 --- /dev/null +++ b/src/findcontrolswidget.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "findcontrolswidget.h" +#include "mainwindow.h" + +extern Main *mainWindow; +extern bool usingDarkTheme; +extern QString iconTheme; + +FindControlsWidget::FindControlsWidget(QWidget *) +{ + QVBoxLayout *mainLayout = new QVBoxLayout; + QHBoxLayout *row2Layout = new QHBoxLayout; + + QLabel *label = new QLabel; + label->setText(tr("Find:", "FindControlsWidget")); + + // Create LineEdit (here QComboBox) + findcombo = new QComboBox; + findcombo->setMinimumWidth(250); + findcombo->setMaxCount(10); + findcombo->setEditable(true); + + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + findcombo->setSizePolicy(sizePolicy); + connect(findcombo, SIGNAL(editTextChanged(const QString &)), this, + SLOT(findTextChanged(const QString &))); + connect(findcombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(indexChanged(int))); + + nextButton = new QPushButton; + nextButton->setIcon(QPixmap(QString(":/edit-find-%1.svg").arg(iconTheme))); + // nextButton->setText (tr("Find","Find widget")); + connect(nextButton, SIGNAL(clicked()), this, SLOT(nextPressed())); + + // QAction needed to only activate shortcut while FindControlsWidget has focus + QAction *a = new QAction(nextButton->text(), this); + a->setShortcut(Qt::Key_Return); // Find in FindControlsWidget + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + connect(a, SIGNAL(triggered()), this, SLOT(nextPressed())); + addAction(a); + + filterNotesButton = new QPushButton; + filterNotesButton->setIcon(QPixmap(":/flag-note.svg")); + filterNotesButton->setCheckable(true); + filterNotesButton->setChecked(true); + connect(filterNotesButton, SIGNAL(clicked()), this, SLOT(nextPressed())); + + row2Layout->addWidget(label); + row2Layout->addWidget(findcombo); + row2Layout->addWidget(nextButton); + row2Layout->addWidget(filterNotesButton); + + mainLayout->addLayout(row2Layout); + + setLayout(mainLayout); + status = Undefined; +} + +QString FindControlsWidget::getFindText() { return findcombo->currentText(); } + +void FindControlsWidget::nextPressed() +{ + if (findcombo->count() < findcombo->maxCount()) + findcombo->insertItem(0, findcombo->currentText()); + emit nextButtonPressed(findcombo->currentText(), + filterNotesButton->isChecked()); +} + +void FindControlsWidget::findTextChanged(const QString &) { setStatus(Undefined); } + +void FindControlsWidget::indexChanged(int i) +{ + emit nextButtonPressed(findcombo->currentText(), + filterNotesButton->isChecked()); +} + +void FindControlsWidget::setFocus() +{ + findcombo->lineEdit()->selectAll(); + findcombo->lineEdit()->setFocus(); +} + +void FindControlsWidget::setStatus(Status st) +{ + if (st == status) + return; + + status = st; + QPalette p = palette(); + QColor c; + if (usingDarkTheme) + switch (st) { + case Success: + c = QColor(0, 170, 0); + break; + case Failed: + c = QColor(170, 0, 0); + break; + default: + c = p.color(QPalette::Base); + } + else + switch (st) { + case Success: + c = QColor(120, 255, 120); + break; + case Failed: + c = QColor(255, 120, 120); + break; + default: + c = p.color(QPalette::Base); + } + p.setColor(QPalette::Active, static_cast(9), c); + p.setColor(QPalette::Inactive, static_cast(9), c); + findcombo->setPalette(p); +} diff --git a/src/findcontrolswidget.h b/src/findcontrolswidget.h new file mode 100644 index 0000000..9a500e7 --- /dev/null +++ b/src/findcontrolswidget.h @@ -0,0 +1,40 @@ +#ifndef FindControlsWidget_H +#define FindControlsWidget_H + +#include + +class QAction; +class QGroupBox; +class QComboBox; +class QPushButton; + +class FindControlsWidget : public QWidget { + Q_OBJECT + + public: + enum Status { Undefined, Success, Failed }; + + FindControlsWidget(QWidget *parent = nullptr); + QString getFindText(); + + public slots: + void nextPressed(); + void findTextChanged(const QString &); + void indexChanged(int); + void setFocus(); + void setStatus(Status st); + + private: + Status status; + + signals: + void nextButtonPressed(QString, bool); + + private: + QComboBox *findcombo; + QGroupBox *findbox; + QPushButton *nextButton; + QPushButton *filterNotesButton; +}; + +#endif diff --git a/src/findresulttreeview.cpp b/src/findresulttreeview.cpp new file mode 100644 index 0000000..c5b615b --- /dev/null +++ b/src/findresulttreeview.cpp @@ -0,0 +1,74 @@ +#include "findresulttreeview.h" + +#include +#include +#include +#include + +extern QString editorFocusInStyle; +extern QString editorFocusOutStyle; + +/////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// +FindResultTreeView::FindResultTreeView() +{ + init(); +} + +void FindResultTreeView::init() +{ + setSelectionMode(QAbstractItemView::ExtendedSelection); + header()->hide(); + + QAction *a; + + a = new QAction(this); + a->setShortcut(Qt::Key_Return); + a->setShortcutContext(Qt::WidgetShortcut); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(startEdit())); + + + // FIXME-3 Set borders when in focus to editorFocusStyle +} + +FindResultTreeView::~FindResultTreeView() +{ + // qDebug()<<"Destructor FindResultTreeView for "<getMapName(); +} + +QModelIndex FindResultTreeView::getSelectedIndex() +{ + QModelIndexList list = selectionModel()->selectedIndexes(); + if (list.isEmpty()) + return QModelIndex(); + else + return list.first(); +} + +void FindResultTreeView::contextMenuEvent(QContextMenuEvent *e) { + /* + if (model->getSelectedBranch()) + branchContextMenu->popup(e->globalPos()); + else if (model->getSelectedImage()) + floatimageContextMenu->popup(e->globalPos()); + else if (model->getSelectedXLink()) + model->editXLink(); + else + canvasContextMenu->exec(e->globalPos()); + + e->accept(); + */ +} + +void FindResultTreeView::closeEvent(QCloseEvent *event) +{ + qDebug() << "FRTV::close"; + //mainWindow->windowSetFindResultTreeViewsVisibility(false); +} + +void FindResultTreeView::startEdit() +{ + QModelIndex ix = getSelectedIndex(); + emit searchFinished(); +} diff --git a/src/findresulttreeview.h b/src/findresulttreeview.h new file mode 100644 index 0000000..92d2c39 --- /dev/null +++ b/src/findresulttreeview.h @@ -0,0 +1,34 @@ +#ifndef FindResultTreeView_H +#define FindResultTreeView_H + +#include + +class VymModel; + +/*! \brief TreeView widget in vym to display and edit a map, based on + * QTreeView */ + +class FindResultTreeView : public QTreeView { + Q_OBJECT + + public: + FindResultTreeView(); + ~FindResultTreeView(); + void init(); + QModelIndex getSelectedIndex(); + + protected: + virtual void contextMenuEvent(QContextMenuEvent *e); + virtual void closeEvent(QCloseEvent *event); + + signals: + void searchFinished(); + + private slots: + void startEdit(); + + private: + VymModel *model; +}; + +#endif diff --git a/src/findresultwidget.cpp b/src/findresultwidget.cpp index 1e0e3c1..7dc3a56 100644 --- a/src/findresultwidget.cpp +++ b/src/findresultwidget.cpp @@ -5,26 +5,42 @@ #include "findresultitem.h" #include "findresultmodel.h" +#include "findresulttreeview.h" +#include "mainwindow.h" #include "vymmodel.h" +extern Main *mainWindow; + FindResultWidget::FindResultWidget(QWidget *) { // Create results model resultsModel = new FindResultModel; // Create TreeView - view = new QTreeView(this); + view = new FindResultTreeView(); view->setModel(resultsModel); - // Create FindWidget - findWidget = new FindWidget(this); - connect(findWidget, SIGNAL(nextButtonPressed(QString, bool)), this, + // Create FindControlsWidget + findControlsWidget = new FindControlsWidget(this); + connect(findControlsWidget, SIGNAL(nextButtonPressed(QString, bool)), this, SLOT(nextButtonPressed(QString, bool))); + QAction *a = new QAction("Cancel", findControlsWidget); + a->setShortcut(Qt::Key_Escape); // Escape in findControlsWidget + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + connect(a, SIGNAL(triggered()), this, SLOT(cancelPressed())); + addAction(a); + + a = new QAction("Close", findControlsWidget); + a->setShortcut(Qt::CTRL | Qt::Key_D); // Close window in findControlsWidget + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + connect(a, SIGNAL(triggered()), this, SLOT(closeWindow())); + addAction(a); + QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(view); - mainLayout->addWidget(findWidget); + mainLayout->addWidget(findControlsWidget); setLayout(mainLayout); @@ -33,6 +49,8 @@ FindResultWidget::FindResultWidget(QWidget *) SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateSelection(QItemSelection, QItemSelection))); + connect(view, SIGNAL(searchFinished()), this, SLOT(searchFinished())); + connect(resultsModel, SIGNAL(layoutChanged()), view, SLOT(expandAll())); } @@ -40,7 +58,6 @@ void FindResultWidget::addItem(TreeItem *ti) { if (ti) { QModelIndex index = view->selectionModel()->currentIndex(); - // QAbstractItemModel *resultsModel = view->model(); if (!resultsModel->insertRow(index.row() + 1, index.parent())) return; @@ -73,7 +90,7 @@ void FindResultWidget::addItem(const QString &s) } } -QString FindResultWidget::getFindText() { return findWidget->getFindText(); } +QString FindResultWidget::getFindText() { return findControlsWidget->getFindText(); } FindResultModel *FindResultWidget::getResultModel() { return resultsModel; } @@ -81,13 +98,22 @@ void FindResultWidget::popup() { show(); parentWidget()->show(); - findWidget->setFocus(); + findControlsWidget->setFocus(); +} + +void FindResultWidget::cancelPressed() +{ + mainWindow->escapePressed(); } -void FindResultWidget::cancelPressed() { emit hideFindResultWidget(); } +void FindResultWidget::closeWindow() +{ + parentWidget()->hide(); +} void FindResultWidget::nextButtonPressed(QString s, bool searchNotesFlag) { + view->setFocus(); emit findPressed(s, searchNotesFlag); } @@ -109,7 +135,26 @@ void FindResultWidget::updateSelection(QItemSelection newsel, QItemSelection) } } -void FindResultWidget::setStatus(FindWidget::Status st) +void FindResultWidget::setStatus(FindControlsWidget::Status st) +{ + findControlsWidget->setStatus(st); +} + +void FindResultWidget::searchFinished() { - findWidget->setStatus(st); + QModelIndexList sl = view->selectionModel()->selectedIndexes(); + if (!sl.isEmpty() && sl.first().isValid()) { + FindResultItem *fri = + static_cast(sl.first().internalPointer()); + if (fri->getOrgModel() && fri->getOriginalID() > 0) { + TreeItem *ti = fri->getOrgModel()->findID(fri->getOriginalID()); + if (ti) { + fri->getOrgModel()->select(ti); + int i = fri->getOriginalIndex(); + if (i >= 0) + emit noteSelected(resultsModel->getSearchString(), i); + parentWidget()->hide(); + } + } + } } diff --git a/src/findresultwidget.h b/src/findresultwidget.h index e4e1eae..fa7cc0d 100644 --- a/src/findresultwidget.h +++ b/src/findresultwidget.h @@ -4,14 +4,15 @@ #include #include -#include "findwidget.h" +#include "findcontrolswidget.h" class FindResultModel; class TreeItem; class VymModel; class QTreeView; class QPushButton; -class FindWidget; +class FindResultTreeView; +class FindControlsWidget; class FindResultWidget : public QWidget { Q_OBJECT @@ -26,9 +27,11 @@ class FindResultWidget : public QWidget { public slots: void popup(); void cancelPressed(); + void closeWindow(); void nextButtonPressed(QString, bool); void updateSelection(QItemSelection, QItemSelection); - void setStatus(FindWidget::Status st); + void setStatus(FindControlsWidget::Status st); + void searchFinished(); signals: void hideFindResultWidget(); @@ -36,11 +39,11 @@ class FindResultWidget : public QWidget { void findPressed(QString, bool); public: - FindWidget *findWidget; + FindControlsWidget *findControlsWidget; private: FindResultModel *resultsModel; - QTreeView *view; + FindResultTreeView *view; }; #endif diff --git a/src/findwidget.cpp b/src/findwidget.cpp deleted file mode 100644 index d983644..0000000 --- a/src/findwidget.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "findwidget.h" -#include "mainwindow.h" - -extern Main *mainWindow; -extern bool usingDarkTheme; -extern QString iconTheme; - -FindWidget::FindWidget(QWidget *) -{ - QVBoxLayout *mainLayout = new QVBoxLayout; - QHBoxLayout *row2Layout = new QHBoxLayout; - - QLabel *label = new QLabel; - label->setText(tr("Find:", "FindWidget")); - - // Create LineEdit (here QComboBox) - findcombo = new QComboBox; - findcombo->setMinimumWidth(250); - findcombo->setEditable(true); - - QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - findcombo->setSizePolicy(sizePolicy); - connect(findcombo, SIGNAL(highlighted(int)), this, SLOT(nextPressed())); - connect(findcombo, SIGNAL(editTextChanged(const QString &)), this, - SLOT(findTextChanged(const QString &))); - - nextButton = new QPushButton; - nextButton->setIcon(QPixmap(QString(":/edit-find-%1.svg").arg(iconTheme))); - // nextButton->setText (tr("Find","Find widget")); - connect(nextButton, SIGNAL(clicked()), this, SLOT(nextPressed())); - - // QAction needed to only activate shortcut while FindWidget has focus - QAction *a = new QAction(nextButton->text(), this); - a->setShortcut(Qt::Key_Return); - a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - connect(a, SIGNAL(triggered()), this, SLOT(nextPressed())); - addAction(a); - - filterNotesButton = new QPushButton; - filterNotesButton->setIcon(QPixmap(":/flag-note.svg")); - filterNotesButton->setCheckable(true); - filterNotesButton->setChecked(true); - connect(filterNotesButton, SIGNAL(clicked()), this, SLOT(nextPressed())); - - row2Layout->addWidget(label); - row2Layout->addWidget(findcombo); - row2Layout->addWidget(nextButton); - row2Layout->addWidget(filterNotesButton); - - mainLayout->addLayout(row2Layout); - - setLayout(mainLayout); - status = Undefined; -} - -QString FindWidget::getFindText() { return findcombo->currentText(); } - -void FindWidget::cancelPressed() -{ - hide(); - emit hideFindWidget(); // Restore focus -} - -void FindWidget::nextPressed() -{ - emit nextButtonPressed(findcombo->currentText(), - filterNotesButton->isChecked()); -} - -void FindWidget::findTextChanged(const QString &) { setStatus(Undefined); } - -void FindWidget::setFocus() -{ - findcombo->lineEdit()->selectAll(); - findcombo->lineEdit()->setFocus(); -} - -void FindWidget::setStatus(Status st) -{ - if (st == status) - return; - - status = st; - QPalette p = palette(); - QColor c; - if (usingDarkTheme) - switch (st) { - case Success: - c = QColor(0, 170, 0); - break; - case Failed: - c = QColor(170, 0, 0); - break; - default: - c = p.color(QPalette::Base); - } - else - switch (st) { - case Success: - c = QColor(120, 255, 120); - break; - case Failed: - c = QColor(255, 120, 120); - break; - default: - c = p.color(QPalette::Base); - } - p.setColor(QPalette::Active, static_cast(9), c); - p.setColor(QPalette::Inactive, static_cast(9), c); - findcombo->setPalette(p); -} diff --git a/src/findwidget.h b/src/findwidget.h deleted file mode 100644 index be58ba2..0000000 --- a/src/findwidget.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef FINDWIDGET_H -#define FINDWIDGET_H - -#include - -class QAction; -class QGroupBox; -class QComboBox; -class QPushButton; - -class FindWidget : public QWidget { - Q_OBJECT - - public: - enum Status { Undefined, Success, Failed }; - - FindWidget(QWidget *parent = nullptr); - QString getFindText(); - - public slots: - void cancelPressed(); - void nextPressed(); - void findTextChanged(const QString &); - void setFocus(); - void setStatus(Status st); - - private: - Status status; - - signals: - void hideFindWidget(); - void nextButtonPressed(QString, bool); - - private: - QComboBox *findcombo; - QGroupBox *findbox; - QPushButton *nextButton; - QPushButton *filterNotesButton; -}; - -#endif diff --git a/src/flag.cpp b/src/flag.cpp index 246bea1..0a99419 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -74,8 +74,6 @@ void Flag::setName(const QString &n) const QString Flag::getName() { return name; } -const QString Flag::getPath() { return path; } - void Flag::setVisible(bool b) { visible = b; } bool Flag::isVisible() { return visible; } diff --git a/src/flag.h b/src/flag.h index e36262b..0062699 100644 --- a/src/flag.h +++ b/src/flag.h @@ -32,7 +32,6 @@ class Flag : public XMLObj { bool load(const QString &); void setName(const QString &); const QString getName(); - const QString getPath(); void setVisible(bool b); bool isVisible(); void setGroup(const QString &); diff --git a/src/flagrow-master.cpp b/src/flagrow-master.cpp index 545ef16..a6e6e4f 100644 --- a/src/flagrow-master.cpp +++ b/src/flagrow-master.cpp @@ -73,7 +73,7 @@ Flag *FlagRowMaster::findFlagByUid(const QUuid &uid) return nullptr; } -Flag *FlagRowMaster::findFlagByName(const QString &name) +Flag *FlagRowMaster::findFlagByName(const QString &name) // FIXME-3 called quite often. From taskEditor? { int i = 0; while (i <= flags.size() - 1) { diff --git a/src/frame-container.cpp b/src/frame-container.cpp index 8e5f354..69692b8 100644 --- a/src/frame-container.cpp +++ b/src/frame-container.cpp @@ -256,22 +256,24 @@ void FrameContainer::updateGeometry(const QRectF &childRect) qreal pad = framePaddingInt + (framePen.width() - 1) / 2; // "Inner" padding and pen width + qreal wp = framePen.width(); + switch (frameTypeInt) { case NoFrame: break; case Rectangle: rectFrame->setRect( - childRect.left() - pad, - childRect.top() - pad, - childRect.width() + pad * 2, - childRect.height() + pad * 2); + childRect.left() - pad - wp, + childRect.top() - pad - wp, + childRect.width() + pad * 2 + wp * 2, + childRect.height() + pad * 2 + wp * 2); r.setRect( - childRect.left() - pad * 2, - childRect.top() - pad * 2, - childRect.width() + pad * 4, - childRect.height() + pad * 4); + childRect.left() - pad * 2 - wp, + childRect.top() - pad * 2 - wp, + childRect.width() + pad * 4 + wp * 2, + childRect.height() + pad * 4 + wp * 2); break; case RoundedRectangle: { @@ -330,7 +332,7 @@ void FrameContainer::updateGeometry(const QRectF &childRect) path.cubicTo(bl + QPointF( - h, 0), tl + QPointF( - h, 0), tl); pathFrame->setPath(path); - QRectF r = path.boundingRect(); + r = path.boundingRect(); // center of pathFrame might be outside of origin, due to cloud not completely symmetrical // Correct position of pathFrame and child @@ -383,7 +385,7 @@ void FrameContainer::updateGeometry(const QRectF &childRect) } break; - case Cloud: { + case Cloud: { // FIXME-3 penWidth not considered? Compare other (working) types... QPointF tl = childRect.topLeft() + QPointF( - pad, - pad); QPointF tr = childRect.topRight() + QPointF( pad, - pad); QPointF bl = childRect.bottomLeft() + QPointF( - pad, + pad); @@ -449,10 +451,10 @@ void FrameContainer::updateGeometry(const QRectF &childRect) childContainers().first()->setPos(- br.center() + p); r.setRect( - - (br.width() + pad) / 2, - - (br.height() + pad) / 2, // Vertically centered anyway later... - br.width() + 2 * pad, - br.height() + 2 * pad); + - (br.width() + pad + wp) / 2, + - (br.height() + pad + wp) / 2, // Vertically centered anyway later... + br.width() + 2 * pad + wp, + br.height() + 2 * pad + wp); } break; diff --git a/src/historywindow.cpp b/src/historywindow.cpp index fedfecc..2d41b9d 100644 --- a/src/historywindow.cpp +++ b/src/historywindow.cpp @@ -7,6 +7,9 @@ extern Settings settings; extern Main *mainWindow; +extern QString editorFocusInStyle; +extern QString editorFocusOutStyle; + HistoryWindow::HistoryWindow(QWidget *parent) : QDialog(parent) { ui.setupUi(this); @@ -35,6 +38,18 @@ HistoryWindow::HistoryWindow(QWidget *parent) : QDialog(parent) connect(ui.historyTable, SIGNAL(itemSelectionChanged()), this, SLOT(select())); + QAction *a = new QAction(this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + a->setShortcut(Qt::CTRL | Qt::Key_D); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(closeWindow())); + + a = new QAction(this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + a->setShortcut(Qt::Key_Escape); + addAction(a); + connect(a, SIGNAL(triggered()), mainWindow, SLOT(escapePressed())); + // Load Settings resize( @@ -56,6 +71,8 @@ HistoryWindow::HistoryWindow(QWidget *parent) : QDialog(parent) 2, settings.value("/satellite/historywindow/geometry/columnWidth/2", 250) .toInt()); + + ui.historyTable->setStyleSheet("QTableView:focus {" + editorFocusInStyle + "}"); } HistoryWindow::~HistoryWindow() @@ -179,8 +196,12 @@ void HistoryWindow::setStepsTotal(int st) void HistoryWindow::closeEvent(QCloseEvent *ce) { - ce->accept(); - hide(); + closeWindow(); +} + +void HistoryWindow::closeWindow() +{ + parentWidget()->hide(); emit windowClosed(); } diff --git a/src/historywindow.h b/src/historywindow.h index e838712..639fd51 100644 --- a/src/historywindow.h +++ b/src/historywindow.h @@ -20,6 +20,7 @@ class HistoryWindow : public QDialog { void closeEvent(QCloseEvent *); private slots: + void closeWindow(); void undo(); void redo(); void select(); diff --git a/src/image-container.cpp b/src/image-container.cpp index ca58c5e..e8dbaf1 100644 --- a/src/image-container.cpp +++ b/src/image-container.cpp @@ -134,7 +134,8 @@ void ImageContainer::select() bool ImageContainer::load(const QString &fn) { - //qDebug() << "IC::load " << fn; + QFile file (fn); + // qDebug() << "IC::load " << fn << file.fileName(); if (imageType != ImageContainer::Undefined) { qWarning() << "ImageContainer::load (" << fn << ") into existing image of type " << imageType; diff --git a/src/jira-agent.cpp b/src/jira-agent.cpp index 97ceb1e..a44ec68 100644 --- a/src/jira-agent.cpp +++ b/src/jira-agent.cpp @@ -60,8 +60,9 @@ void JiraAgent::init() QObject::connect(killTimer, SIGNAL(timeout()), this, SLOT(timeout())); // Reset credentials, these are server specific beginning in 2.9.18 - authUsingPATInt = true; - personalAccessTokenInt = QString(); + authMethodInt.clear(); + patTokenInt = QString(); + apiTokenInt = QString(); userNameInt = QString(); passwordInt = QString(); serverNameInt = QString(); @@ -77,30 +78,31 @@ bool JiraAgent::setJiraServer(int n) { bool foundServer = false; - bool usePAT = settings.value("authUsingPAT", true).toBool(); + QString method = settings.value("method", "userpass").toString(); QString url = settings.value("baseUrl", "").toString(); if (!url.isEmpty()) { baseUrlInt = url; serverNameInt = settings.value("name","-").toString(); - QString pat = settings.value("PAT", "").toString(); - if (!pat.isEmpty()) { - authUsingPATInt = true; - personalAccessTokenInt = pat; - foundServer = true; - } - - // Looking for username and password - QString user = settings.value("username", "").toString(); - if (!user.isEmpty()) { + authMethodInt = method; + if (method == "userpass") { + userNameInt = settings.value("username", "").toString(); QString pass = settings.value("password", "").toString(); - if (!pass.isEmpty()) { - userNameInt = user; + if (!userNameInt.isEmpty() && !pass.isEmpty()) { passwordInt = pass; foundServer = true; } + } else if (method == "pat") { + patTokenInt = settings.value("PAT", "").toString(); + if (!patTokenInt.isEmpty()) + foundServer = true; + } else { // cloud + userNameInt = settings.value("email", "").toString(); + apiTokenInt = settings.value("apiToken", "").toString(); + if (!userNameInt.isEmpty() && !apiTokenInt.isEmpty()) + foundServer = true; } } - qDebug() << __func__ << " n=" << n << "usePAT=" << authUsingPATInt << " userName=" << userNameInt; + qDebug() << __func__ << " n=" << n << " method=" << authMethodInt << " userName=" << userNameInt; return foundServer; } @@ -195,26 +197,27 @@ bool JiraAgent::setQuery(const QString &s) // FIXME-3 only works for first serv // Search for project = PATTERN and use resulting server settings.beginGroup("/atlassian/jira/servers/1"); - bool usePAT = settings.value("authUsingPAT", true).toBool(); // FIXME-3 should be done in setJiraServer + QString method = settings.value("method", "userpass").toString(); QString url = settings.value("baseUrl", "").toString(); if (!url.isEmpty()) { baseUrlInt = url; - //qDebug() << "JA::setQuery url=" < +#include #include "settings.h" @@ -13,7 +14,7 @@ JiraSettingsDialog::JiraSettingsDialog(QWidget *parent) : QDialog(parent) QDialog::setWindowTitle("VYM - " + tr("Jira settings", "Jira settings dialog title")); - ui.tableWidget->setColumnCount(5); + ui.tableWidget->setColumnCount(4); settings.beginGroup("/atlassian/jira"); QTableWidgetItem *newItem; @@ -23,7 +24,6 @@ JiraSettingsDialog::JiraSettingsDialog(QWidget *parent) : QDialog(parent) headers << "URL"; headers << "Pattern"; headers << "Method"; - headers << "User"; ui.tableWidget->setHorizontalHeaderLabels(headers); int size = settings.beginReadArray("servers"); @@ -41,14 +41,14 @@ JiraSettingsDialog::JiraSettingsDialog(QWidget *parent) : QDialog(parent) newItem = new QTableWidgetItem(settings.value("pattern").toString()); ui.tableWidget->setItem(0, 2, newItem); - if (settings.value("authUsingPAT").toString() == "true") + QString method = settings.value("method", "userpass").toString(); + if (method == "userpass") + newItem = new QTableWidgetItem("Username/Password"); + else if (method == "pat") newItem = new QTableWidgetItem("PAT"); else - newItem = new QTableWidgetItem("Username/Password"); + newItem = new QTableWidgetItem("Cloud"); ui.tableWidget->setItem(0, 3, newItem); - - newItem = new QTableWidgetItem(settings.value("username","-").toString()); - ui.tableWidget->setItem(0, 4, newItem); } } settings.endArray(); @@ -71,7 +71,11 @@ JiraSettingsDialog::JiraSettingsDialog(QWidget *parent) : QDialog(parent) this, SLOT(fieldsChanged())); connect(ui.PATLineEdit, SIGNAL(editingFinished()), this, SLOT(fieldsChanged())); - connect(ui.usePATCheckBox, SIGNAL(clicked()), + connect(ui.apiTokenLineEdit, SIGNAL(editingFinished()), + this, SLOT(fieldsChanged())); + connect(ui.authMethodComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(updateAuthenticationFields())); + connect(ui.authMethodComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(fieldsChanged())); connect(ui.tableWidget, SIGNAL(cellChanged(int, int)), this, SLOT(fieldsChanged())); @@ -91,29 +95,35 @@ void JiraSettingsDialog::deleteServer() void JiraSettingsDialog::updateAuthenticationFields() { - QModelIndexList ixl = ui.tableWidget->selectionModel()->selectedIndexes(); - - int row; - if (ixl.isEmpty() || ixl.count() > 1) - row = -1; - else - row = ixl.first().row(); + int rowCount = ui.tableWidget->rowCount(); + int row = -1; + if (ui.tableWidget->selectionModel()) { + QModelIndexList sel = ui.tableWidget->selectionModel()->selectedIndexes(); + if (!sel.isEmpty()) row = sel.first().row(); + } if (row < 0) { - // No server selected, disable fields ui.selectedServerLineEdit->setText(""); - ui.usePATCheckBox->setEnabled(false); + ui.authMethodComboBox->setEnabled(false); + ui.authMethodComboBox->hide(); + ui.authMethodLabel->hide(); ui.PATLineEdit->setEnabled(false); - ui.PATLabel->setEnabled(false); - ui.userLabel->setEnabled(false); + ui.PATLineEdit->hide(); + ui.PATLabel->hide(); + ui.apiTokenLineEdit->setEnabled(false); + ui.apiTokenLineEdit->hide(); + ui.apiTokenLabel->hide(); ui.userLineEdit->setEnabled(false); - ui.passwordLabel->setEnabled(false); + ui.userLineEdit->hide(); + ui.userLabel->hide(); ui.passwordLineEdit->setEnabled(false); + ui.passwordLineEdit->hide(); + ui.passwordLabel->hide(); - // Empty unused fields ui.userLineEdit->setText(""); ui.passwordLineEdit->setText(""); ui.PATLineEdit->setText(""); + ui.apiTokenLineEdit->setText(""); } else { // Index of selected server in settings @@ -125,57 +135,75 @@ void JiraSettingsDialog::updateAuthenticationFields() ui.selectedServerLineEdit->setText( ui.tableWidget->item(row, 0)->text()); else ui.selectedServerLineEdit->setText(""); - ui.usePATCheckBox->setEnabled(true); - ui.usePATCheckBox->setChecked( - settings.value(selectedServer + "authUsingPAT", true).toBool()); + // Block signal emissions while updating widgets to avoid re-entrancy + QSignalBlocker blockCombo(ui.authMethodComboBox); + QSignalBlocker blockUser(ui.userLineEdit); + QSignalBlocker blockPass(ui.passwordLineEdit); + QSignalBlocker blockPat(ui.PATLineEdit); + + ui.authMethodComboBox->setEnabled(true); + ui.authMethodComboBox->show(); + ui.authMethodLabel->show(); ui.PATLineEdit->setEnabled(true); ui.PATLabel->setEnabled(true); + ui.apiTokenLineEdit->setEnabled(true); + ui.apiTokenLabel->setEnabled(true); ui.userLabel->setEnabled(true); ui.userLineEdit->setEnabled(true); ui.passwordLabel->setEnabled(true); ui.passwordLineEdit->setEnabled(true); - // Show and prefill fields depending on usage of PAT - if (ui.usePATCheckBox->isChecked()) { + int methodIdx = ui.authMethodComboBox->currentIndex(); + if (methodIdx == 2) { // cloud + ui.apiTokenLineEdit->show(); + ui.apiTokenLineEdit->setText( + settings.value(selectedServer + "apiToken","").toString()); + ui.apiTokenLabel->show(); + ui.PATLineEdit->hide(); + ui.PATLabel->hide(); + ui.userLabel->show(); + ui.userLabel->setText(tr("Email:")); + ui.userLineEdit->show(); + ui.userLineEdit->setText( + settings.value(QString("/atlassian/jira/servers/%1/email").arg(n_server), "").toString()); + ui.passwordLabel->hide(); + ui.passwordLineEdit->hide(); + } else if (methodIdx == 1) { // PAT ui.PATLineEdit->show(); ui.PATLineEdit->setText( settings.value(selectedServer + "PAT","").toString()); - settings.value(selectedServer + "PAT","").toString(); ui.PATLabel->show(); + ui.apiTokenLineEdit->hide(); + ui.apiTokenLabel->hide(); ui.userLabel->hide(); ui.userLineEdit->hide(); ui.passwordLabel->hide(); ui.passwordLineEdit->hide(); - } else { + } else { // user/pass ui.PATLineEdit->hide(); ui.PATLabel->hide(); + ui.apiTokenLineEdit->hide(); + ui.apiTokenLabel->hide(); ui.userLabel->show(); + ui.userLabel->setText(tr("Username:")); ui.userLineEdit->show(); ui.userLineEdit->setText( - settings.value(QString("/atlassian/jira/servers/%1/username").arg(n_server), "-").toString()); + settings.value(QString("/atlassian/jira/servers/%1/username").arg(n_server), "").toString()); ui.passwordLabel->show(); ui.passwordLineEdit->show(); ui.passwordLineEdit->setText( settings.value(QString("/atlassian/jira/servers/%1/password").arg(n_server), "").toString()); } } - - // Update layout - adjustSize(); } void JiraSettingsDialog::fieldsChanged() { int rowCount = ui.tableWidget->rowCount(); - if (rowCount < 1) return; - - QModelIndexList ixl = ui.tableWidget->selectionModel()->selectedIndexes(); - - if (ixl.isEmpty() || ixl.count() > 1) return; - - int row = ixl.first().row(); + int row = ui.tableWidget->currentRow(); + if (row < 0 || row >= rowCount) return; int n_server = rowCount - 1 - row; if (n_server < 0) return; @@ -196,24 +224,63 @@ void JiraSettingsDialog::fieldsChanged() settings.setValue("pattern", ui.tableWidget->item(row, 2)->text()); else settings.setValue("pattern", ""); - settings.setValue("authUsingPAT", ui.usePATCheckBox->isChecked()); - if (ui.usePATCheckBox->isChecked()) { - // Don't save password if PAT is used - settings.remove("password"); - settings.setValue("PAT", ui.PATLineEdit->text()); - } else { + + int methodIdx = ui.authMethodComboBox->currentIndex(); + QString method = (methodIdx == 0) ? "userpass" : (methodIdx == 1) ? "pat" : "cloud"; + settings.setValue("method", method); + if (method == "userpass") { settings.setValue("username", ui.userLineEdit->text()); settings.setValue("password", ui.passwordLineEdit->text()); - settings.remove("PAT"); + } else if (method == "pat") { + settings.setValue("PAT", ui.PATLineEdit->text()); + } else { // cloud + settings.setValue("email", ui.userLineEdit->text()); + settings.setValue("apiToken", ui.apiTokenLineEdit->text()); } settings.setValue("servers/size", rowCount); settings.endArray(); settings.endGroup(); + + // Reflect method in table overview without re-triggering cellChanged + { + QSignalBlocker blockTable(ui.tableWidget); + QString methodText = (method == "userpass") ? "Username/Password" : (method == "pat") ? "PAT" : "Cloud"; + QTableWidgetItem *methodItem = new QTableWidgetItem(methodText); + ui.tableWidget->setItem(row, 3, methodItem); + } } void JiraSettingsDialog::selectionChanged(const QItemSelection &selected, const QItemSelection &) { + Q_UNUSED(selected); + + // If nothing selected, just refresh to the hidden state + if (!ui.tableWidget->selectionModel() || + ui.tableWidget->selectionModel()->selectedIndexes().isEmpty()) { + updateAuthenticationFields(); + return; + } + + int row = ui.tableWidget->selectionModel()->selectedIndexes().first().row(); + int rowCount = ui.tableWidget->rowCount(); + if (row < 0 || row >= rowCount) { + updateAuthenticationFields(); + return; + } + + int n_server = rowCount - row; // absolute numbering used in settings path + QString selectedServer = QString("/atlassian/jira/servers/%1/").arg(n_server); + + // Load and set method for selected server without triggering save yet + QString method = settings.value(selectedServer + "method", "userpass").toString(); + int methodIndex = 0; // 0=userpass,1=pat,2=cloud + if (method == "pat") methodIndex = 1; + else if (method == "cloud") methodIndex = 2; + { + QSignalBlocker blockCombo(ui.authMethodComboBox); + ui.authMethodComboBox->setCurrentIndex(methodIndex); + } + updateAuthenticationFields(); } - diff --git a/src/main.cpp b/src/main.cpp index 94e1488..88949f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,7 +11,6 @@ #include "command.h" #include "debuginfo.h" #include "findresultwidget.h" -#include "findwidget.h" #include "flagrow-master.h" #include "headingeditor.h" #include "macros.h" @@ -59,7 +58,7 @@ BranchPropertyEditor *branchPropertyEditor; Main *mainWindow; ScriptEditor *scriptEditor; ScriptOutput *scriptOutput; -FindWidget *findWidget; +FindControlsWidget *findControlsWidget; FindResultWidget *findResultWidget; TaskEditor *taskEditor; @@ -138,9 +137,11 @@ int warningCount = 0; int criticalCount = 0; int fatalCount = 0; -QString editorFocusStyle = - QString(" border-color: #3daee9; border-style:outset; border-width:3px; " - "color:black;"); +// Some styles used in various widgets +QString editorFocusInStyle = + QString(" border-color: #3daee9; border-style:outset; border-width:1px; ");// "color:black;"); +QString editorFocusOutStyle = QString("border-width:0px;"); +QString toolBarStyle; void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) @@ -433,9 +434,14 @@ int main(int argc, char *argv[]) iconTheme = "dark"; } } + /* + qDebug() << "dark settings: " << settingsDarkTheme + << " systemDark=" << systemSeemsDark + << " useDark" << usingDarkTheme; + */ QPalette palette; - if (usingDarkTheme && settingsDarkTheme == "always") { + if (usingDarkTheme) { qApp->setStyle(QStyleFactory::create("fusion")); //qApp->setStyle(QStyleFactory::create("Windows")); //qApp->setStyle(QStyleFactory::create("windowsvista")); @@ -447,7 +453,6 @@ int main(int argc, char *argv[]) palette.setColor(QPalette::AlternateBase, QColor(53,53,53)); palette.setColor(QPalette::ToolTipBase, QColor(53,53,53)); palette.setColor(QPalette::ToolTipText, Qt::white); - // Unused: QPalette::PlaceHolderText palette.setColor(QPalette::Text, Qt::white); palette.setColor(QPalette::Button, QColor(53,53,53)); palette.setColor(QPalette::ButtonText, Qt::white); @@ -461,9 +466,49 @@ int main(int argc, char *argv[]) qApp->setPalette(palette); vymBlueColor =QColor::fromString("#00aaff"); - } else + } else { + if (systemSeemsDark) { + qApp->setStyle(QStyleFactory::create("macOS")); + palette.setColor(QPalette::Window, QColor("#ececec")); // 10 + palette.setColor(QPalette::WindowText, Qt::black); // 0 + palette.setColor(QPalette::Base, QColor("#ffffff")); // 9 + palette.setColor(QPalette::AlternateBase, QColor(253,53,53)); // 16 + palette.setColor(QPalette::ToolTipBase, Qt::white); // 18 + palette.setColor(QPalette::ToolTipText, Qt::black); // 19 + palette.setColor(QPalette::Text, Qt::black); // 6 + palette.setColor(QPalette::Button, QColor("#ececec")); // 1 + palette.setColor(QPalette::ButtonText, Qt::black); // 8 + palette.setColor(QPalette::BrightText, Qt::white); // 7 + + /* + QPalette::Light 2 Lighter than Button color. + QPalette::Midlight 3 Between Button and Light. + QPalette::Dark 4 Darker than Button. + QPalette::Mid 5 Between Button and Dark. + QPalette::Shadow 11 A very dark color. By default, shadow color is Qt::black. + */ + palette.setColor(QPalette::Light, QColor("#ffffff")); // 2 + palette.setColor(QPalette::Midlight, QColor("#f5f5f5")); // 3 + palette.setColor(QPalette::Dark, QColor("#bfbfbf")); // 4 + palette.setColor(QPalette::Mid, QColor("#a9a9a9")); // 5 + palette.setColor(QPalette::Shadow, Qt::black); // 11 + + // Roles of seleced items + palette.setColor(QPalette::Highlight, QColor("#a5cdff")); // 12 + palette.setColor(QPalette::HighlightedText, Qt::black); // 13 + + // Links + /* + QPalette::Link 14 + QPalette::LinkVisited 15 + */ + qApp->setPalette(palette); + } + vymBlueColor =QColor::fromString("#0000ff"); + } + // toolBarStyle = "background-color: " + palette.color(QPalette::Button).name() + "; border: None;"; // FIXME-3 Checked buttons no longer visible, introduced for forced bright theme vymForegroundColor = palette.color(QPalette::WindowText); vymBaseColor = palette.color(QPalette::Base); @@ -531,6 +576,7 @@ int main(int argc, char *argv[]) // Initialize editors noteEditor = new NoteEditor(QObject::tr("Note Editor", "Name of editor shown as window title")); + headingEditor = new HeadingEditor(QObject::tr("Heading Editor", "Name of editor shown as window title")); branchPropertyEditor = new BranchPropertyEditor(); @@ -538,14 +584,27 @@ int main(int argc, char *argv[]) // overwritten during loading of maps lastSessionFiles = settings.value("/mainwindow/sessionFileList", QStringList()).toStringList(); - // Logfiles (no GUI yet for settings) useActionLog = settings.value("/logfile/enabled", false).toBool(); actionLogPath = settings.value("/logfile/path", QDir::homePath() + "/vym.log").toString(); - // Create MainWindow + // Create MainWindow (after creating editors) Main m; + // Add Escape-keys to editors (after creating MainWindow) + QAction *a = new QAction("Cancel", noteEditor); + a->setShortcut(Qt::Key_Escape); // Escape in NoteEditor + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + noteEditor->connect(a, SIGNAL(triggered()), mainWindow, SLOT(escapePressed())); + noteEditor->addAction(a); + + a = new QAction("Cancel", headingEditor); + a->setShortcut(Qt::Key_Escape); // Escape in HeadingEditor + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + headingEditor->connect(a, SIGNAL(triggered()), mainWindow, SLOT(escapePressed())); + headingEditor->addAction(a); + + // Check for zip tools zipToolAvailable = ZipAgent::checkZipTool(); unzipToolAvailable = ZipAgent::checkUnzipTool(); @@ -647,8 +706,9 @@ int main(int argc, char *argv[]) // Enable some last minute cleanup QObject::connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); - // For benchmarking we may want to quit instead of entering event loop - if (options.isActive("quit")) + // For benchmarking or if test script is done + // we may want to quit instead of entering event loop + if (options.isActive("quit") || m.exitAfterScript()) m.fileExitVYM(); else app.exec(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index b46a4d3..c5006f5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2,7 +2,6 @@ #include -#define ADD_SHORTCUT a->setToolTip(a->toolTip() + QString(" (%1)").arg(a->shortcut().toString())); a->setShortcutVisibleInContextMenu(true); #if defined(VYM_DBUS) #include "adaptorvym.h" #endif @@ -119,19 +118,10 @@ extern QString iconTheme; extern bool useActionLog; extern QString actionLogPath; -QMenu *branchAddContextMenu; QMenu *branchContextMenu; -QMenu *branchLinksContextMenu; -QMenu *branchRemoveContextMenu; -QMenu *branchXLinksContextMenuEdit; -QMenu *branchXLinksContextMenuFollow; QMenu *canvasContextMenu; QMenu *floatimageContextMenu; -QMenu *targetsContextMenu; QMenu *taskContextMenu; -QMenu *fileLastMapsMenu; -QMenu *fileImportMenu; -QMenu *fileExportMenu; extern Settings settings; extern Options options; @@ -148,6 +138,8 @@ extern QDir vymInstallDir; extern QColor vymBlueColor; +extern QString toolBarStyle; + Main::Main(QWidget *parent) : QMainWindow(parent) { // qDebug() << "Constr. MainWindow"; @@ -213,9 +205,25 @@ Main::Main(QWidget *parent) : QMainWindow(parent) layout->addWidget(tabWidget); - switchboard.addGroup("MainWindow", tr("Main window", "Shortcut group")); - switchboard.addGroup("MapEditor", tr("Map Editors", "Shortcut group")); - switchboard.addGroup("TextEditor", tr("Text Editors", "Shortcut group")); + switchboard.addScope("MainWindow", tr("Main window", "Shortcut group")); + switchboard.addScope("MapEditor", tr("Map Editors", "Shortcut group")); + switchboard.addScope("TextEditor", tr("Text Editors", "Shortcut group")); + + // Create main menus + + fileMenu = menuBar()->addMenu(tr("&Map", "Map menu")); + editMenu = menuBar()->addMenu(tr("E&dit", "Edit menu")); + selectMenu = menuBar()->addMenu(tr("Select", "Select menu")); + formatMenu = menuBar()->addMenu(tr("F&ormat", "Format menu")); + viewMenu = menuBar()->addMenu(tr("&View")); + toolbarsMenu = + viewMenu->addMenu(tr("Toolbars", "Toolbars overview in view menu")); + windowsMenu = + viewMenu->addMenu(tr("Windows", "Editor windows overview in view menu")); + + viewMenu->addSeparator(); + + connectMenu = menuBar()->addMenu(tr("&Connect")); // Setup actions setupFileActions(); @@ -232,12 +240,14 @@ Main::Main(QWidget *parent) : QMainWindow(parent) setupToolbars(); setupFlagActions(); + // Populate menus + setupEditMenu(); + // Dock widgets /////////////////////////////////////////////// QDockWidget *dw; dw = new QDockWidget(); dw->setWidget(noteEditor); dw->setObjectName("NoteEditor"); - dw->setWindowTitle(noteEditor->getEditorTitle()); dw->hide(); noteEditorDW = dw; addDockWidget(Qt::LeftDockWidgetArea, dw); @@ -245,7 +255,6 @@ Main::Main(QWidget *parent) : QMainWindow(parent) dw = new QDockWidget(); dw->setWidget(headingEditor); dw->setObjectName("HeadingEditor"); - dw->setWindowTitle(headingEditor->getEditorTitle()); dw->hide(); headingEditorDW = dw; addDockWidget(Qt::BottomDockWidgetArea, dw); @@ -294,7 +303,7 @@ Main::Main(QWidget *parent) : QMainWindow(parent) // Connect NoteEditor, so that we can update flags if text changes connect(noteEditor, SIGNAL(textHasChanged(VymText)), this, SLOT(updateNoteText(VymText))); - connect(noteEditor, SIGNAL(windowClosed()), this, SLOT(updateActions())); + connect(noteEditor, SIGNAL(windowClosed()), this, SLOT(updateActions())); // FIXME-2 windowCLosed needed after all? // Connect heading editor connect(headingEditor, SIGNAL(textHasChanged(const VymText &)), this, @@ -303,15 +312,6 @@ Main::Main(QWidget *parent) : QMainWindow(parent) connect(scriptEditor, SIGNAL(runScript(QString)), this, SLOT(runScript(QString))); - // Switch back to MapEditor using Esc or end presentation mode - QAction *a = new QAction(this); - a->setShortcut(Qt::Key_Escape); - a->setShortcutContext(Qt::ApplicationShortcut); - a->setCheckable(false); - a->setEnabled(true); - addAction(a); - connect(a, SIGNAL(triggered()), this, SLOT(escapePressed())); - // Create TaskEditor after setting up above actions, allow cloning taskEditor = new TaskEditor(); dw = new QDockWidget(tr("Task list", "TaskEditor")); @@ -342,13 +342,13 @@ Main::Main(QWidget *parent) : QMainWindow(parent) progressDialog.setCancelButton(nullptr); // Load window settings - restoreState(settings.value("/mainwindow/state", 0).toByteArray()); + restoreState(settings.value("/mainwindow/state").toByteArray()); restoreGeometry(settings.value("/mainwindow/geometry").toByteArray()); updateGeometry(); - actionViewToggleTreeEditor->setChecked(settings.value("/mainwindow/view/showTreeEditors", true).toBool()); - actionViewToggleSlideEditor->setChecked(settings.value("/mainwindow/view/showSlideEditors", false).toBool()); + windowSetTreeEditorsVisibility(settings.value("/mainwindow/view/showTreeEditors", true).toBool()); + windowSetSlideEditorsVisibility(settings.value("/mainwindow/view/showSlideEditors", false).toBool()); // After startup, schedule looking for updates AFTER // release notes have been downloaded @@ -361,11 +361,17 @@ Main::Main(QWidget *parent) : QMainWindow(parent) if (!QDBusConnection::sessionBus().registerObject("/vym", this)) qWarning("MainWindow: Couldn't register DBUS object!"); #endif + + // Allows a (test-)script to make vym quit after script execution + exitAfterScriptInt = false; + + backgroundZipProcesses = 0; + closeAfterLastZipProcess = false; } Main::~Main() { - // qDebug() << "Destr Mainwindow"; + //qDebug() << "Destr Mainwindow begin"; // Make sure there is no focus elsewhere, e.g. in BranchPropertyEditor // which could cause a crash. (Qt bug?) @@ -375,13 +381,8 @@ Main::~Main() if (!testmode) { settings.setValue("/mainwindow/geometry", saveGeometry()); - settings.setValue("/mainwindow/state", saveState(0)); // FIXME-3 use saveState and saveGeometry - // https://doc.qt.io/qt-6/qmainwindow.html#saveState - - settings.setValue("/mainwindow/view/showTreeEditors", - actionViewToggleTreeEditor->isChecked()); - settings.setValue("/mainwindow/view/showSlideEditors", - actionViewToggleSlideEditor->isChecked()); + settings.setValue("/mainwindow/state", saveState()); // FIXME-3 use restoreDockWidget + // https://doc.qt.io/qt-6/qmainwindow.html#saveState settings.setValue("/mainwindow/view/AntiAlias", actionViewToggleAntiAlias->isChecked()); @@ -407,8 +408,6 @@ Main::~Main() settings.setValue("/system/printerFileName", printer->outputFileName()); } - settings.setValue("/mapeditor/editmode/autoSelectText", - actionSettingsAutoSelectText->isChecked()); settings.setValue("/mapeditor/editmode/useFlagGroups", actionSettingsUseFlagGroups->isChecked()); settings.setValue("/export/useHideExport", @@ -425,6 +424,8 @@ Main::~Main() delete standardFlagsMaster; delete userFlagsMaster; delete systemFlagsMaster; + + //qDebug() << "Destr Mainwindow end"; } void Main::loadCmdLine() @@ -536,7 +537,11 @@ void Main::setupAPI() // Below are the commands for vym itself // - Command *c = new Command("clearConsole", Command::AnySel); + Command *c = new Command("callMacro", Command::AnySel); + c->addParameter(Command::StringPar, false, "Include macros and run script"); + vymCommands.append(c); + + c = new Command("clearConsole", Command::AnySel); vymCommands.append(c); c = new Command("closeMapWithID", Command::AnySel); @@ -546,7 +551,7 @@ void Main::setupAPI() c = new Command("currentColor", Command::AnySel); vymCommands.append(c); - c = new Command("currentMap", Command::AnySel); + c = new Command("currentMap", Command::AnySel, Command::VymModelPar); vymCommands.append(c); c = new Command("currentMapIndex", Command::AnySel); @@ -555,6 +560,10 @@ void Main::setupAPI() c = new Command("editHeading", Command::BranchSel); vymCommands.append(c); + c = new Command("exit", Command::AnySel); + c->setComment("Exit vym after script execution"); + vymCommands.append(c); + c = new Command("gotoMap", Command::AnySel); c->addParameter(Command::IntPar, false, "Index of map"); vymCommands.append(c); @@ -566,6 +575,10 @@ void Main::setupAPI() c = new Command("mapCount", Command::AnySel); vymCommands.append(c); + c = new Command("mapWithId", Command::AnySel, Command::VymModelPar); + c->addParameter(Command::IntPar, false, "unique id of map"); + vymCommands.append(c); + c = new Command("print", Command::AnySel); c->setComment("Print string to console"); c->addParameter(Command::StringPar, false, "String to print"); @@ -581,9 +594,6 @@ void Main::setupAPI() c->addParameter(Command::IntPar, false, "Index of quick color [0..6]"); vymCommands.append(c); - c = new Command("toggleTreeEditor", Command::AnySel); - vymCommands.append(c); - c = new Command("usesDarkTheme", Command::AnySel, Command::BoolPar); vymCommands.append(c); @@ -781,7 +791,7 @@ void Main::setupAPI() c->addParameter(Command::IntPar, false, "Index of slide to remove"); modelCommands.append(c); - c = new Command("repeatLastCommand", Command::AnySel); + c = new Command("repeatLastAction", Command::AnySel); modelCommands.append(c); c = new Command("resetBranchIterator", Command::BranchSel, Command::BoolPar); @@ -800,6 +810,9 @@ void Main::setupAPI() c = new Command("selectedBranch", Command::AnySel, Command::BranchPar); modelCommands.append(c); + c = new Command("selectedBranches", Command::AnySel, Command::BranchListPar); + modelCommands.append(c); + c = new Command("selectLatestAdded", Command::AnySel, Command::BoolPar); modelCommands.append(c); @@ -848,14 +861,8 @@ void Main::setupAPI() c->addParameter(Command::DoublePar, false, "Rotation of view of map"); modelCommands.append(c); - c = new Command("setTitle", Command::AnySel); - c->addParameter(Command::StringPar, false, ""); - modelCommands.append(c); - - c = new Command("setZoom", Command::AnySel); - c->addParameter(Command::DoublePar, false, "Zoomfactor of map"); - modelCommands.append(c); - + c = new Command("setSelectionBrushColor", Command::AnySel); + c->addParameter(Command::ColorPar, false, "Color of selection box background"); modelCommands.append(c); c = new Command("setSelectionColor", Command::AnySel); @@ -870,8 +877,14 @@ void Main::setupAPI() c->addParameter(Command::IntPar, false, "Selection box border width "); modelCommands.append(c); - c = new Command("setSelectionBrushColor", Command::AnySel); - c->addParameter(Command::ColorPar, false, "Color of selection box background"); + c = new Command("setTitle", Command::AnySel); + c->addParameter(Command::StringPar, false, ""); + modelCommands.append(c); + + c = new Command("setZoom", Command::AnySel); + c->addParameter(Command::DoublePar, false, "Zoomfactor of map"); + modelCommands.append(c); + modelCommands.append(c); c = new Command("sleep", Command::AnySel); @@ -998,6 +1011,10 @@ void Main::setupAPI() c->addParameter(Command::BoolPar, false, "Use setting for heading if true, for subtree if false"); branchCommands.append(c); + c = new Command("getHeadingColor", Command::BranchSel, Command::StringPar); + c->setComment("Get color of heading as text"); + branchCommands.append(c); + c = new Command("getHeadingXML", Command::BranchSel, Command::StringPar); c->setComment("Get heading of branch as XML"); branchCommands.append(c); @@ -1545,51 +1562,48 @@ void Main::setupAPI() } -void Main::cloneActionMapEditor(QAction *a, QKeySequence ks) +void Main::cloneActionMapEditor(QAction *a) // FIXME-2 obsolete by mapEditorActions.append(...) ? { - a->setShortcut(ks); a->setShortcutContext(Qt::WidgetShortcut); mapEditorActions.append(a); } + // File Actions void Main::setupFileActions() { - QString tag = tr("&Map", "Menu for file actions"); - QMenu *fileMenu = menuBar()->addMenu(tag); - QAction *a; + QString tag = tr("File actions", "MainWindow shortcut groups"); a = new QAction(QPixmap(QString(":/document-new-%1.svg").arg(iconTheme)), tr("&New map", "File menu"), this); - switchboard.addSwitch("fileMapNew", shortcutScope, a, tag); + switchboard.addAction(a, "fileMapNew", Qt::CTRL | Qt::Key_N, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(fileNew())); - cloneActionMapEditor(a, Qt::CTRL | Qt::Key_N); + cloneActionMapEditor(a); fileMenu->addAction(a); actionFileNew = a; a = new QAction(QPixmap(":/filenewcopy.svg"), tr("&Copy to new map", "File menu"), this); - switchboard.addSwitch("fileMapNewCopy", shortcutScope, a, tag); + switchboard.addAction(a, "fileMapNewCopy", Qt::CTRL | Qt::SHIFT | Qt::Key_C, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(fileNewCopy())); - cloneActionMapEditor(a, Qt::CTRL | Qt::SHIFT | Qt::Key_C); + cloneActionMapEditor(a); fileMenu->addAction(a); actionFileNewCopy = a; a = new QAction(QPixmap(QString(":/document-open-%1").arg(iconTheme)), tr("&Open...", "File menu"), this); - switchboard.addSwitch("fileMapOpen", shortcutScope, a, tag); + switchboard.addAction(a, "fileMapOpen", Qt::CTRL | Qt::Key_L, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(fileLoad())); - cloneActionMapEditor(a, Qt::CTRL | Qt::Key_L); + cloneActionMapEditor(a); fileMenu->addAction(a); actionFileOpen = a; a = new QAction(tr("&Restore last session", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_R); - switchboard.addSwitch("fileMapRestore", shortcutScope, a, tag); + switchboard.addAction(a, "fileMapRestore", Qt::CTRL | Qt::Key_S, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(fileRestoreSession())); fileMenu->addAction(a); - actionListFiles.append(a); - actionCopy = a; + a->setEnabled(true); + actionFileRestoreSession = a; fileLastMapsMenu = fileMenu->addMenu(tr("Open Recent", "File menu")); fileMenu->addSeparator(); @@ -1601,8 +1615,8 @@ void Main::setupFileActions() actionClearRecent = a; a = new QAction(QPixmap(QString(":/document-save-%1.svg").arg(iconTheme)), tr("&Save...", "File menu"), this); - switchboard.addSwitch("fileMapSave", shortcutScope, a, tag); - cloneActionMapEditor(a, Qt::CTRL | Qt::Key_S); + switchboard.addAction(a, "fileMapSave", Qt::CTRL | Qt::Key_S, shortcutScope, tag); + cloneActionMapEditor(a); fileMenu->addAction(a); restrictedMapActions.append(a); connect(a, SIGNAL(triggered()), this, SLOT(fileSave())); @@ -1665,11 +1679,12 @@ void Main::setupFileActions() fileExportMenu = fileMenu->addMenu(tr("Export", "File menu")); + tag = tr("Exports", "MainWindow shortcut groups"); a = new QAction(QPixmap(QString(":/document-export-%1.svg").arg(iconTheme)), - tr("Repeat last export (%1)").arg("-"), this); - switchboard.addSwitch("fileExportLast", shortcutScope, a, tag); + tr("Repeat last export"), this); + switchboard.addAction(a, "fileExportLast", Qt::CTRL | Qt::Key_E, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(fileExportLast())); - cloneActionMapEditor(a, Qt::CTRL | Qt::Key_E); + cloneActionMapEditor(a); fileExportMenu->addAction(a); actionFileExportLast = a; actionListFiles.append(a); @@ -1767,7 +1782,7 @@ void Main::setupFileActions() fileMenu->addSeparator(); a = new QAction(tr("Map properties"), this); - switchboard.addSwitch("editMapProperties", shortcutScope, a, tag); + switchboard.addAction(a, "editMapProperties", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editMapProperties())); fileMenu->addAction(a); actionListFiles.append(a); @@ -1777,8 +1792,7 @@ void Main::setupFileActions() a = new QAction(QPixmap(QString(":/document-print-%1.svg").arg(iconTheme)), tr("&Print") + QString("..."), this); - a->setShortcut(Qt::CTRL | Qt::Key_P); - switchboard.addSwitch("fileMapPrint", shortcutScope, a, tag); + switchboard.addAction(a, "fileMapPrint", Qt::CTRL | Qt::Key_P, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(filePrint())); fileMenu->addAction(a); unrestrictedMapActions.append(a); @@ -1786,27 +1800,26 @@ void Main::setupFileActions() a = new QAction(QPixmap(QString(":/document-close-%1.svg").arg(iconTheme)), tr("&Close Map", "File menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_W); - switchboard.addSwitch("fileMapClose", shortcutScope, a, tag); + switchboard.addAction(a, "fileMapClose", Qt::CTRL | Qt::Key_W, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(fileCloseMap())); fileMenu->addAction(a); actionFileClose = a; + tag = tr("Exit", "MainWindow shortcut groups"); a = new QAction(QPixmap(QString(":/application-exit-%1.svg").arg(iconTheme)), tr("E&xit", "File menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Q); - switchboard.addSwitch("fileExit", shortcutScope, a, tag); + switchboard.addAction(a, "fileExit", Qt::CTRL | Qt::Key_Q, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(fileExitVYM())); fileMenu->addAction(a); actionFileExitVym = a; + tag = tr("Miscellaneous", "MainWindow shortcut groups"); a = new QAction("Toggle winter mode", this); - a->setShortcut(Qt::CTRL | Qt::Key_Asterisk); a->setShortcutContext(Qt::WidgetShortcut); if (settings.value("/mainwindow/showTestMenu", false).toBool()) { addAction(a); mapEditorActions.append(a); - switchboard.addSwitch("mapWinterMode", shortcutScope, a, tag); + switchboard.addAction(a, "mapWinterMode", Qt::CTRL | Qt::Key_Asterisk, shortcutScope, tag); } connect(a, SIGNAL(triggered()), this, SLOT(toggleWinter())); actionToggleWinter = a; @@ -1815,281 +1828,248 @@ void Main::setupFileActions() // Edit Actions void Main::setupEditActions() { - QString tag = tr("E&dit", "Edit menu"); - QMenu *editMenu = menuBar()->addMenu(tag); - QAction *a; + QString tag = tr("Undo/Redo", "MainWindow shortcut groups"); a = new QAction(QPixmap(":/undo.png"), tr("&Undo", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Z); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); a->setEnabled(false); - editMenu->addAction(a); mapEditorActions.append(a); restrictedMapActions.append(a); - switchboard.addSwitch("mapUndo", shortcutScope, a, tag); + switchboard.addAction(a, "mapUndo",Qt::CTRL | Qt::Key_Z, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editUndo())); actionUndo = a; + a = new QAction(QPixmap(":/undo.png"), tr("&Undo", "Edit menu"), this); + a->setShortcutContext(Qt::WidgetShortcut); + a->setEnabled(false); + mapEditorActions.append(a); + restrictedMapActions.append(a); + switchboard.addAction(a, "mapUndo", Qt::Key_U, shortcutScope, tag); // Vim Alternative + connect(a, SIGNAL(triggered()), this, SLOT(editUndo())); + actionUndoVim = a; + a = new QAction(QPixmap(":/redo.png"), tr("&Redo", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Y); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); - editMenu->addAction(a); restrictedMapActions.append(a); mapEditorActions.append(a); - switchboard.addSwitch("mapRedo", shortcutScope, a, tag); + switchboard.addAction(a, "mapRedo", Qt::CTRL | Qt::Key_Y, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editRedo())); actionRedo = a; + a = new QAction(tr("Repeat last action", "Edit menu") + " (experimental)", this); + switchboard.addAction(a, "repeatLastAction", Qt::Key_Period, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(editRepeatLastAction())); + //actionListBranches.append(a); + actionRepeatCommand = a; + editMenu->addSeparator(); + a = new QAction(QPixmap(QString(":/edit-copy-%1.svg").arg(iconTheme)), tr("&Copy", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_C); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); a->setEnabled(false); - editMenu->addAction(a); unrestrictedMapActions.append(a); mapEditorActions.append(a); - switchboard.addSwitch("mapCopy", shortcutScope, a, tag); + switchboard.addAction(a, "mapCopy", Qt::CTRL | Qt::Key_C, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editCopy())); actionCopy = a; + a = new QAction(QPixmap(QString(":/edit-copy-%1.svg").arg(iconTheme)), tr("&Copy", "Edit menu"), this); + a->setShortcutContext(Qt::WidgetShortcut); + a->setEnabled(false); + unrestrictedMapActions.append(a); + mapEditorActions.append(a); + switchboard.addAction(a, "mapCopyVim", Qt::Key_Y, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(editCopy())); + actionCopyVim = a; + a = new QAction(QPixmap(QString(":/edit-cut-%1.svg").arg(iconTheme)), tr("Cu&t", "Edit menu"), this); // Multi key shortcuts https://bugreports.qt.io/browse/QTBUG-39127 - a->setShortcut(Qt::CTRL | Qt::Key_X); - ADD_SHORTCUT a->setEnabled(false); a->setShortcutContext(Qt::WidgetShortcut); - editMenu->addAction(a); restrictedMapActions.append(a); mapEditorActions.append(a); restrictedMapActions.append(a); - switchboard.addSwitch("mapCut", shortcutScope, a, tag); + switchboard.addAction(a, "mapCut", Qt::CTRL | Qt::Key_X, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editCut())); addAction(a); actionCut = a; + a = new QAction(QPixmap(QString(":/edit-cut-%1.svg").arg(iconTheme)), tr("Cu&t", "Edit menu"), this); + switchboard.addAction(a, "mapCutVim", Qt::Key_D, shortcutScope, tag); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(editDeleteSelection())); + actionListItems.append(a); + actionCutVim = a; + a = new QAction(QPixmap(QString(":/edit-paste-%1.svg").arg(iconTheme)), tr("&Paste", "Edit menu"), this); connect(a, SIGNAL(triggered()), this, SLOT(editPaste())); - a->setShortcut(Qt::CTRL | Qt::Key_V); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); a->setEnabled(false); - editMenu->addAction(a); restrictedMapActions.append(a); mapEditorActions.append(a); - switchboard.addSwitch("mapPaste", shortcutScope, a, tag); + switchboard.addAction(a, "mapPaste", Qt::CTRL | Qt::Key_V, shortcutScope, tag); actionPaste = a; + a = new QAction(QPixmap(QString(":/edit-paste-%1.svg").arg(iconTheme)), tr("&Paste", "Edit menu"), + this); + connect(a, SIGNAL(triggered()), this, SLOT(editPaste())); + a->setShortcutContext(Qt::WidgetShortcut); + a->setEnabled(false); + restrictedMapActions.append(a); + mapEditorActions.append(a); + switchboard.addAction(a, "mapPasteVim", Qt::Key_P, shortcutScope, tag); + actionPasteVim = a; + // Shortcut to delete selection a = new QAction(tr("Delete Selection", "Edit menu"), this); #if defined(Q_OS_MACOS) - a->setShortcut(Qt::Key_Backspace); + switchboard.addAction(a, "mapDelete", Qt::Key_Backspace, shortcutScope, tag); #else - a->setShortcut(Qt::Key_Delete); + switchboard.addAction(a, "mapDelete", Qt::Key_Delete, shortcutScope, tag); #endif - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapDelete", shortcutScope, a, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editDeleteSelection())); - editMenu->addAction(a); actionListItems.append(a); actionDelete = a; - a = new QAction(tr("Delete Selection", "Edit menu"), this); - a->setShortcut(Qt::Key_D); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapDelete", shortcutScope, a, tag); - addAction(a); - connect(a, SIGNAL(triggered()), this, SLOT(editDeleteSelection())); - editMenu->addAction(a); - actionListItems.append(a); - actionDeleteAlt = a; - + tag = tr("Add", "MainWindow shortcut groups"); // Shortcut to add mapcenter a = new QAction(QPixmap(":/newmapcenter.png"), tr("Add mapcenter", "Canvas context menu"), this); - a->setShortcut(Qt::Key_C); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapAddCenter", shortcutScope, a, tag); + switchboard.addAction(a, "mapAddCenter", Qt::Key_C, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editAddMapCenter())); - editMenu->addAction(a); actionListFiles.append(a); actionAddMapCenter = a; // Shortcut to add branch a = new QAction(QPixmap(":/newbranch.png"), tr("Add branch as child", "Edit menu"), this); - switchboard.addSwitch("mapeditAddBranch", shortcutScope, a, tag); + switchboard.addAction(a, "mapeditAddBranch", Qt::Key_A, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editAddBranch())); - cloneActionMapEditor(a, Qt::Key_A); - ADD_SHORTCUT + cloneActionMapEditor(a); taskEditorActions.append(a); actionListBranches.append(a); actionAddBranch = a; // Add branch by inserting it at selection a = new QAction(tr("Add branch (insert)", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::CTRL | Qt::Key_A); - ADD_SHORTCUT - switchboard.addSwitch("mapEditAddBranchBefore", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditAddBranchBefore", Qt::SHIFT | Qt::CTRL | Qt::Key_A, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editAddBranchBefore())); - editMenu->addAction(a); actionListBranches.append(a); actionAddBranchBefore = a; // Add branch above a = new QAction(tr("Add branch above", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_A); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapEditAddBranchAbove", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditAddBranchAbove", Qt::SHIFT | Qt::Key_A, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editAddBranchAbove())); a->setEnabled(false); actionListBranches.append(a); - editMenu->addAction(a); actionAddBranchAbove = a; a = new QAction(tr("Add branch above", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_Insert); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapEditAddBranchAboveAlt", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditAddBranchAboveAlt", Qt::SHIFT | Qt::Key_Insert, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editAddBranchAbove())); actionListBranches.append(a); // Add branch below a = new QAction(tr("Add branch below", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Insert); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapEditAddBranchBelow", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditAddBranchBelow", Qt::CTRL | Qt::Key_Insert, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editAddBranchBelow())); a->setEnabled(false); actionListBranches.append(a); a = new QAction(tr("Add branch below", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_A); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapEditAddBranchBelowAlt", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditAddBranchBelowAlt", Qt::CTRL | Qt::Key_A, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editAddBranchBelow())); actionListBranches.append(a); - editMenu->addAction(a); actionAddBranchBelow = a; + tag = tr("Move", "MainWindow shortcut groups"); a = new QAction(QPixmap(":/up.png"), tr("Move branch up", "Edit menu"), this); - a->setShortcut(Qt::Key_PageUp); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); mapEditorActions.append(a); taskEditorActions.append(a); restrictedMapActions.append(a); actionListBranches.append(a); actionListImages.append(a); - editMenu->addAction(a); - switchboard.addSwitch("mapEditMoveBranchUp", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditMoveBranchUp", Qt::Key_PageUp, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editMoveUp())); actionMoveUp = a; a = new QAction(QPixmap(":/down.png"), tr("Move branch down", "Edit menu"), this); - a->setShortcut(Qt::Key_PageDown); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); mapEditorActions.append(a); taskEditorActions.append(a); restrictedMapActions.append(a); actionListBranches.append(a); actionListImages.append(a); - editMenu->addAction(a); - switchboard.addSwitch("mapEditMoveBranchDown", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditMoveBranchDown", Qt::Key_PageDown, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editMoveDown())); actionMoveDown = a; a = new QAction(QPixmap(":up-diagonal-right.png"), tr("Move branch diagonally up", "Edit menu"), this); -#if defined(Q_OS_MACOS) - a->setShortcut(Qt::SHIFT | Qt::Key_PageUp); -#else - a->setShortcut(Qt::CTRL | Qt::Key_PageUp); -#endif - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); mapEditorActions.append(a); taskEditorActions.append(a); restrictedMapActions.append(a); actionListBranches.append(a); - editMenu->addAction(a); - switchboard.addSwitch("mapEditMoveBranchUpDiagonally", shortcutScope, a, tag); +#if defined(Q_OS_MACOS) + switchboard.addAction(a, "mapEditMoveBranchUpDiagonally", Qt::SHIFT | Qt::Key_PageUp, shortcutScope, tag); +#else + switchboard.addAction(a, "mapEditMoveBranchUpDiagonally", Qt::CTRL | Qt::Key_PageUp, shortcutScope, tag); +#endif connect(a, SIGNAL(triggered()), this, SLOT(editMoveUpDiagonally())); actionMoveUpDiagonally = a; a = new QAction(QPixmap(":down-diagonal-left.png"), tr("Move branch diagonally down", "Edit menu"), this); -#if defined(Q_OS_MACOS) - a->setShortcut(Qt::SHIFT | Qt::Key_PageDown); -#else - a->setShortcut(Qt::CTRL | Qt::Key_PageDown); -#endif - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); mapEditorActions.append(a); taskEditorActions.append(a); restrictedMapActions.append(a); actionListBranches.append(a); - editMenu->addAction(a); - switchboard.addSwitch("mapEditMoveBranchDownDiagonally", shortcutScope, a, tag); +#if defined(Q_OS_MACOS) + switchboard.addAction(a, "mapEditMoveBranchDownDiagonally", Qt::SHIFT | Qt::Key_PageDown, shortcutScope, tag); +#else + switchboard.addAction(a, "mapEditMoveBranchDownDiagonally", Qt::CTRL | Qt::Key_PageDown, shortcutScope, tag); +#endif connect(a, SIGNAL(triggered()), this, SLOT(editMoveDownDiagonally())); actionMoveDownDiagonally = a; a = new QAction(QPixmap(), tr("&Detach", "Context menu"), this); a->setStatusTip(tr("Detach branch and use as mapcenter", "Context menu")); - a->setShortcut(Qt::Key_D | Qt::SHIFT); - ADD_SHORTCUT - switchboard.addSwitch("mapDetachBranch", shortcutScope, a, tag); + switchboard.addAction(a, "mapDetachBranch", Qt::Key_D | Qt::SHIFT, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editDetach())); - editMenu->addAction(a); actionListBranches.append(a); actionDetach = a; + QString sortDisplayTag = tr("Sort and display", "MainWindow shortcut groups"); a = new QAction(QPixmap(QString(":/view-sort-ascending-name-%1.svg").arg(iconTheme)), tr("Sort children", "Edit menu"), this); a->setEnabled(true); - a->setShortcut(Qt::Key_O); - ADD_SHORTCUT - switchboard.addSwitch("mapSortBranches", shortcutScope, a, tag); + switchboard.addAction(a, "mapSortBranches", Qt::Key_O, shortcutScope, sortDisplayTag); connect(a, SIGNAL(triggered()), this, SLOT(editSortChildren())); - editMenu->addAction(a); actionListBranches.append(a); actionSortChildren = a; a = new QAction(QPixmap(QString(":/view-sort-descending-name-%1.svg").arg(iconTheme)), tr("Sort children backwards", "Edit menu"), this); a->setEnabled(true); - a->setShortcut(Qt::SHIFT | Qt::Key_O); - ADD_SHORTCUT - switchboard.addSwitch("mapSortBranchesReverse", shortcutScope, a, tag); + switchboard.addAction(a, "mapSortBranchesReverse", Qt::SHIFT | Qt::Key_O, shortcutScope, sortDisplayTag); connect(a, SIGNAL(triggered()), this, SLOT(editSortBackChildren())); - editMenu->addAction(a); actionListBranches.append(a); actionSortBackChildren = a; a = new QAction(QPixmap(":/flag-scrolled-right.png"), tr("Scroll branch", "Edit menu"), this); - a->setShortcut(Qt::Key_S); - ADD_SHORTCUT - switchboard.addSwitch("mapToggleScroll", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleScroll", Qt::Key_S, shortcutScope, sortDisplayTag); connect(a, SIGNAL(triggered()), this, SLOT(editToggleScroll())); - editMenu->addAction(a); actionListBranches.append(a); a->setEnabled(false); a->setCheckable(true); @@ -2098,108 +2078,64 @@ void Main::setupEditActions() actionToggleScroll = a; a = new QAction(tr("Unscroll branch and subtree", "Edit menu"), this); - editMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editUnscrollSubtree())); actionListBranches.append(a); + actionUnscrollSubtree = a; + QString geometryTag = tr("Geometry of items", "MainWindow shortcut groups"); a = new QAction(tr("Grow selection", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Plus); - ADD_SHORTCUT - switchboard.addSwitch("mapGrowSelection", shortcutScope, a, tag); + switchboard.addAction(a, "mapGrowSelection", Qt::CTRL | Qt::Key_Plus, shortcutScope, geometryTag); connect(a, SIGNAL(triggered()), this, SLOT(editGrowSelectionSize())); - editMenu->addAction(a); actionListBranches.append(a); actionListImages.append(a); actionGrowSelectionSize = a; a = new QAction(tr("Shrink selection", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Minus); - ADD_SHORTCUT - switchboard.addSwitch("mapShrinkSelection", shortcutScope, a, tag); + switchboard.addAction(a, "mapShrinkSelection", Qt::CTRL | Qt::Key_Minus, shortcutScope, geometryTag); connect(a, SIGNAL(triggered()), this, SLOT(editShrinkSelectionSize())); - editMenu->addAction(a); actionListBranches.append(a); actionListImages.append(a); actionShrinkSelectionSize = a; a = new QAction(tr("Reset selection size", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_0); - ADD_SHORTCUT - switchboard.addSwitch("mapResetSelectionSize", shortcutScope, a, tag); + switchboard.addAction(a, "mapResetSelectionSize", Qt::CTRL | Qt::Key_0, shortcutScope, geometryTag); connect(a, SIGNAL(triggered()), this, SLOT(editResetSelectionSize())); - editMenu->addAction(a); actionListBranches.append(a); actionListImages.append(a); actionResetSelectionSize = a; - editMenu->addSeparator(); - - a = new QAction(QPixmap(), "TE: " + tr("Collapse one level", "Edit menu"), - this); - a->setShortcut(Qt::Key_Less | Qt::CTRL); - ADD_SHORTCUT - switchboard.addSwitch("mapCollapseOneLevel", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(editCollapseOneLevel())); - editMenu->addAction(a); - a->setEnabled(false); - a->setCheckable(false); + a = new QAction(tr("Rotate subtree clockwise", "Edit menu"), this); + switchboard.addAction(a, "mapRotateSubtreeCW", Qt::CTRL | Qt::Key_R, shortcutScope, geometryTag); + connect(a, SIGNAL(triggered()), this, SLOT(editRotateSubtreeCW())); actionListBranches.append(a); - addAction(a); - actionCollapseOneLevel = a; + actionRotateSubtreeCW = a; - a = new QAction(QPixmap(), - "TE: " + tr("Collapse unselected levels", "Edit menu"), - this); - a->setShortcut(Qt::Key_Less); - ADD_SHORTCUT - switchboard.addSwitch("mapCollapseUnselectedLevels", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(editCollapseUnselected())); - editMenu->addAction(a); - a->setEnabled(false); - a->setCheckable(false); + a = new QAction(tr("Rotate subtree counter-clockwise", "Edit menu"), this); + switchboard.addAction(a, "mapRotateSubtreeCCW", Qt::CTRL | Qt::SHIFT | Qt::Key_R, shortcutScope, geometryTag); + connect(a, SIGNAL(triggered()), this, SLOT(editRotateSubtreeCCW())); actionListBranches.append(a); - addAction(a); - actionCollapseUnselected = a; - - a = new QAction(QPixmap(), tr("Expand all branches", "Edit menu"), this); - connect(a, SIGNAL(triggered()), this, SLOT(editExpandAll())); - actionExpandAll = a; - actionExpandAll->setEnabled(false); - actionExpandAll->setCheckable(false); - actionListBranches.append(actionExpandAll); - addAction(a); + actionRotateSubtreeCCW = a; - a = new QAction(QPixmap(), tr("Expand one level", "Edit menu"), this); - a->setShortcut(Qt::Key_Greater); - ADD_SHORTCUT - switchboard.addSwitch("mapExpandOneLevel", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(editExpandOneLevel())); - a->setEnabled(false); - a->setCheckable(false); - addAction(a); - actionListBranches.append(a); - actionExpandOneLevel = a; + editMenu->addSeparator(); - tag = tr("References Context menu", "Shortcuts"); + tag = tr("URLs", "Shortcuts in references context menu"); a = new QAction(QPixmap(":/flag-url.svg"), tr("Open URL", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_U); - ADD_SHORTCUT - switchboard.addSwitch("mapOpenUrl", shortcutScope, a, tag); + switchboard.addAction(a, "mapOpenUrl", shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(openUrl())); actionListBranches.append(a); actionOpenUrl = a; a = new QAction(tr("Open all visible URLs in subtree", "Edit menu"), this); - switchboard.addSwitch("mapOpenUrlsSubTree", shortcutScope, a, tag); + switchboard.addAction(a, "mapOpenUrlsSubTree", shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editOpenMultipleVisUrls())); actionListBranches.append(a); actionOpenMultipleVisUrls = a; a = new QAction(tr("Open all URLs in subtree", "Edit menu"), this); - switchboard.addSwitch("mapOpenMultipleUrls", shortcutScope, a, tag); + switchboard.addAction(a, "mapOpenMultipleUrls", shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editOpenMultipleUrls())); actionListBranches.append(a); @@ -2207,7 +2143,7 @@ void Main::setupEditActions() a = new QAction(tr("Open all URLs in subtree in private mode", "Edit menu"), this); if (settings.value("/mainwindow/showTestMenu", false).toBool()) { - switchboard.addSwitch("mapOpenMultipleUrls", shortcutScope, a, tag); + switchboard.addAction(a, "mapOpenMultipleUrls", shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editOpenMultipleUrlsPrivate())); actionListBranches.append(a); @@ -2215,10 +2151,7 @@ void Main::setupEditActions() actionOpenMultipleUrlsPrivate = a; a = new QAction(QPixmap(), tr("Extract URLs from note", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_N); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapUrlsFromNote", shortcutScope, a, tag); + switchboard.addAction(a, "mapUrlsFromNote", Qt::SHIFT | Qt::Key_N, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editNote2URLs())); actionListBranches.append(a); @@ -2226,44 +2159,33 @@ void Main::setupEditActions() a = new QAction(QPixmap(":/flag-urlnew.svg"), tr("Edit URL...", "Edit menu"), this); - a->setShortcut(Qt::Key_U); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapEditURL", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditURL", Qt::SHIFT | Qt::Key_U, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editURL())); actionListBranches.append(a); actionURLNew = a; a = new QAction(QPixmap(), tr("Edit local URL...", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_U); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapEditLocalURL", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditLocalURL", Qt::CTRL | Qt::Key_U, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editLocalURL())); actionListBranches.append(a); actionLocalURL = a; a = new QAction(tr("Use heading for URL", "Edit menu"), this); - //a->setShortcut(Qt::ALT | Qt::Key_U); - a->setShortcutContext(Qt::ApplicationShortcut); a->setEnabled(false); - switchboard.addSwitch("mapHeading2URL", shortcutScope, a, tag); + switchboard.addAction(a, "mapHeading2URL", shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editHeading2URL())); actionListBranches.append(a); actionHeading2URL = a; - tag = "Jira"; + tag = tr("Connect", "Connection shortcuts in MainWindow"); a = new QAction( QPixmap(":/flag-jira.svg"), tr("Get data from Jira for subtree", "Edit menu"), this); - a->setShortcut(Qt::Key_J | Qt::SHIFT); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapUpdateSubTreeFromJira", shortcutScope, a, tag); + switchboard.addAction(a, "mapUpdateSubTreeFromJira", Qt::Key_J | Qt::SHIFT, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(getJiraDataSubtree())); actionGetJiraDataSubtree = a; @@ -2272,20 +2194,14 @@ void Main::setupEditActions() QPixmap(":/flag-jira.svg"), tr("Set Jira query", "Edit menu"), this); - a->setShortcut(Qt::Key_J | Qt::CTRL); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); - switchboard.addSwitch("mapSetJiraQuery", shortcutScope, a, tag); + switchboard.addAction(a, "mapSetJiraQuery", Qt::Key_J | Qt::CTRL, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(setJiraQuery())); - actionGetJiraDataSubtree = a; + actionSetJiraQuery = a; - tag = "Confluence"; a = new QAction(tr("Get page name and details from Confluence", "Edit menu"), this); - // a->setShortcut ( Qt::Key_J | Qt::CTRL); - // a->setShortcutContext (Qt::WindowShortcut); - // switchboard.addSwitch ("mapUpdateSubTreeFromJira", shortcutScope, a, tag); + switchboard.addAction(a, "mapGetConfluencePageDetails", shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(getConfluencePageDetails())); actionListBranches.append(a); @@ -2293,21 +2209,17 @@ void Main::setupEditActions() a = new QAction(tr("Get page name and details from Confluence for child pages", "Edit menu"), this); - // a->setShortcut ( Qt::Key_J | Qt::CTRL); - // a->setShortcutContext (Qt::WindowShortcut); - // switchboard.addSwitch ("mapUpdateSubTreeFromJira", shortcutScope, a, tag); + switchboard.addAction(a, "mapGetConfluencePagesDetails", shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(getConfluencePageDetailsRecursively())); actionListBranches.append(a); actionGetConfluencePageDetailsRecursively = a; - tag = tr("vymlinks - linking maps", "Shortcuts"); + tag = tr("vymlinks - linking maps", "Shortcuts for vymLinks in MainWindow"); a = new QAction(QPixmap(":/flag-vymlink.png"), tr("Open linked map", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_V); - ADD_SHORTCUT a->setEnabled(false); - switchboard.addSwitch("mapOpenVymLink", shortcutScope, a, tag); + switchboard.addAction(a, "mapOpenVymLink", Qt::SHIFT | Qt::Key_V, shortcutScope, tag); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editOpenVymLink())); actionListBranches.append(a); @@ -2316,7 +2228,7 @@ void Main::setupEditActions() a = new QAction(QPixmap(":/flag-vymlink.png"), tr("Open linked map in background tab", "Edit menu"), this); a->setEnabled(false); - switchboard.addSwitch("mapOpenVymLink", shortcutScope, a, tag); + switchboard.addAction(a, "mapOpenVymLink", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editOpenVymLinkBackground())); actionListBranches.append(a); actionOpenVymLinkBackground = a; @@ -2324,189 +2236,163 @@ void Main::setupEditActions() a = new QAction(QPixmap(), tr("Open all vym links in subtree", "Edit menu"), this); a->setEnabled(false); - switchboard.addSwitch("mapOpenMultipleVymLinks", shortcutScope, a, tag); + switchboard.addAction(a, "mapOpenMultipleVymLinks", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editOpenMultipleVymLinks())); actionListBranches.append(a); actionOpenMultipleVymLinks = a; a = new QAction(QPixmap(":/flag-vymlinknew.png"), tr("Edit vym link...", "Edit menu"), this); - a->setShortcut(Qt::Key_V); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); a->setEnabled(false); - switchboard.addSwitch("mapEditVymLink", shortcutScope, a, tag); + switchboard.addAction(a, "mapEditVymLink", Qt::Key_V, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editVymLink())); actionListBranches.append(a); actionEditVymLink = a; a = new QAction(tr("Delete vym link", "Edit menu"), this); a->setEnabled(false); - switchboard.addSwitch("mapDeleteVymLink", shortcutScope, a, tag); + switchboard.addAction(a, "mapDeleteVymLink", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editDeleteVymLink())); actionListBranches.append(a); actionDeleteVymLink = a; - tag = tr("Exports", "Shortcuts"); a = new QAction(QPixmap(":/flag-hideexport.png"), tr("Hide in exports", "Edit menu"), this); - a->setShortcut(Qt::Key_H); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(true); a->setEnabled(false); addAction(a); - switchboard.addSwitch("mapToggleHideExport", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleHideExport", Qt::Key_H, shortcutScope, sortDisplayTag); connect(a, SIGNAL(triggered()), this, SLOT(editToggleHideExport())); actionListBranches.append(a); actionListImages.append(a); actionToggleHideExport = a; - tag = tr("Tasks", "Shortcuts"); + tag = tr("Tasks", "Shortcuts for tasks in MainWindow"); a = new QAction(QPixmap(":/taskeditor.png"), tr("Toggle task", "Edit menu"), this); - a->setShortcut(Qt::Key_W | Qt::SHIFT); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(true); a->setEnabled(false); addAction(a); - switchboard.addSwitch("mapToggleTask", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleTask", Qt::Key_W | Qt::SHIFT, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editToggleTask())); actionListBranches.append(a); actionToggleTask = a; a = new QAction(QPixmap(), tr("Cycle task status", "Edit menu"), this); - a->setShortcut(Qt::Key_W); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); addAction(a); - switchboard.addSwitch("mapCycleTaskStatus", shortcutScope, a, tag); + switchboard.addAction(a, "mapCycleTaskStatus", Qt::Key_W, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editCycleTaskStatus())); actionListBranches.append(a); actionCycleTaskStatus = a; a = new QAction(QPixmap(), tr("Reset delta priority for visible tasks", "Reset delta"), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); addAction(a); - switchboard.addSwitch("mapResetTaskDeltaPrio", shortcutScope, a, tag); + switchboard.addAction(a, "mapResetTaskDeltaPrio", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskResetDeltaPrio())); actionListBranches.append(a); actionTaskResetDeltaPrio = a; a = new QAction(QPixmap(), tr("Reset sleep", "Task sleep"), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(0); addAction(a); - switchboard.addSwitch("mapResetSleep", shortcutScope, a, tag); + switchboard.addAction(a, "mapResetSleep", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep0 = a; a = new QAction(QPixmap(), tr("Sleep %1 days", "Task sleep").arg("n") + "...", this); - a->setShortcutContext(Qt::WindowShortcut); - a->setShortcut(Qt::Key_Q | Qt::SHIFT); - ADD_SHORTCUT a->setCheckable(false); a->setEnabled(false); a->setData(-1); addAction(a); - switchboard.addSwitch("mapTaskSleepN", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleepN", Qt::Key_Q | Qt::SHIFT, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleepN = a; a = new QAction(QPixmap(), tr("Sleep %1 day", "Task sleep").arg(1), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(1); addAction(a); - switchboard.addSwitch("mapTaskSleep1", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep1", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep1 = a; a = new QAction(QPixmap(), tr("Sleep %1 days", "Task sleep").arg(2), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(2); addAction(a); - switchboard.addSwitch("mapTaskSleep2", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep2", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep2 = a; a = new QAction(QPixmap(), tr("Sleep %1 days", "Task sleep").arg(3), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(3); addAction(a); - switchboard.addSwitch("mapTaskSleep3", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep3", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep3 = a; a = new QAction(QPixmap(), tr("Sleep %1 days", "Task sleep").arg(4), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(4); addAction(a); - switchboard.addSwitch("mapTaskSleep4", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep4", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep4 = a; a = new QAction(QPixmap(), tr("Sleep %1 days", "Task sleep").arg(5), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(5); addAction(a); - switchboard.addSwitch("mapTaskSleep5", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep5", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep5 = a; a = new QAction(QPixmap(), tr("Sleep %1 days", "Task sleep").arg(7), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(7); addAction(a); - switchboard.addSwitch("mapTaskSleep7", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep7", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep7 = a; a = new QAction(QPixmap(), tr("Sleep %1 weeks", "Task sleep").arg(2), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(14); addAction(a); - switchboard.addSwitch("mapTaskSleep14", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep14", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep14 = a; a = new QAction(QPixmap(), tr("Sleep %1 weeks", "Task sleep").arg(4), this); - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(false); a->setEnabled(false); a->setData(28); addAction(a); - switchboard.addSwitch("mapTaskSleep28", shortcutScope, a, tag); + switchboard.addAction(a, "mapTaskSleep28", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editTaskSleepN())); actionListBranches.append(a); actionTaskSleep28 = a; @@ -2523,21 +2409,17 @@ void Main::setupEditActions() // Only remove branch, not its children a = new QAction( tr("Remove only branch and keep its children ", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_X); - ADD_SHORTCUT connect(a, SIGNAL(triggered()), this, SLOT(editDeleteKeepChildren())); a->setEnabled(false); addAction(a); - switchboard.addSwitch("mapDeleteKeepChildren", shortcutScope, a, tag); + switchboard.addAction(a, "mapDeleteKeepChildren", Qt::CTRL | Qt::SHIFT | Qt::Key_X, shortcutScope, tag); actionListBranches.append(a); actionDeleteKeepChildren = a; // Only remove children of a branch a = new QAction(tr("Remove children", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_X); - ADD_SHORTCUT addAction(a); - switchboard.addSwitch("mapDeleteChildren", shortcutScope, a, tag); + switchboard.addAction(a, "mapDeleteChildren", Qt::SHIFT | Qt::Key_X, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editDeleteChildren())); a->setEnabled(false); addAction(a); @@ -2548,11 +2430,8 @@ void Main::setupEditActions() a = new QAction(tr("Add timestamp", "Edit menu"), this); a->setEnabled(false); actionListBranches.append(a); - a->setShortcut(Qt::Key_T); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); addAction(a); - switchboard.addSwitch("mapAddTimestamp", shortcutScope, a, tag); + switchboard.addAction(a, "mapAddTimestamp", Qt::Key_T, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editAddTimestamp())); actionListBranches.append(a); actionAddTimestamp = a; @@ -2564,11 +2443,8 @@ void Main::setupEditActions() actionMapInfo = a; a = new QAction(QPixmap(QString(":/insert-image-%1.svg").arg(iconTheme)), tr("Add image", "Edit and context menus") + "...", this); - a->setShortcutContext(Qt::WindowShortcut); - a->setShortcut(Qt::Key_I | Qt::SHIFT); - ADD_SHORTCUT addAction(a); - switchboard.addSwitch("mapLoadImage", shortcutScope, a, tag); + switchboard.addAction(a, "mapLoadImage", Qt::Key_I | Qt::SHIFT, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editLoadImage())); actionListBranches.append(a); actionLoadImage = a; @@ -2577,65 +2453,113 @@ void Main::setupEditActions() tr("Item property window", "Dialog to edit properties of selected item") + QString("..."), this); - a->setShortcut(Qt::Key_P); - ADD_SHORTCUT - a->setShortcutContext(Qt::WindowShortcut); a->setCheckable(true); addAction(a); - switchboard.addSwitch("mapTogglePropertyEditor", shortcutScope, a, tag); + switchboard.addAction(a, "mapTogglePropertyEditor", Qt::Key_B, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(windowToggleProperty())); actionViewTogglePropertyEditor = a; } +void Main::setupEditMenu() +{ + editMenu->addAction(actionUndo); + editMenu->addAction(actionUndoVim); + editMenu->addAction(actionRedo); + editMenu->addAction(actionRepeatCommand); + + editMenu->addSeparator(); + + editMenu->addAction(actionCopy); + editMenu->addAction(actionCopyVim); + editMenu->addAction(actionCut); + editMenu->addAction(actionPaste); + editMenu->addAction(actionPasteVim); + editMenu->addAction(actionDelete); + + editMenu->addSeparator(); + + editMenu->addMenu(branchAddContextMenu); + editMenu->addMenu(branchRemoveContextMenu); + editMenu->addMenu(branchHierarchyContextMenu); + editMenu->addMenu(branchGeometryContextMenu); + + editMenu->addSeparator(); + + editMenu->addAction(actionToggleScroll); + editMenu->addAction(actionUnscrollSubtree); + +} + // Select Actions void Main::setupSelectActions() { QString tag = tr("Selections", "Shortcuts"); - QMenu *selectMenu = menuBar()->addMenu(tr("Select", "Select menu")); QAction *a; tag = tr("Search functions", "Shortcuts"); a = new QAction(QPixmap(QString(":/edit-find-%1.svg").arg(iconTheme)), tr("Find...", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_F); - ADD_SHORTCUT selectMenu->addAction(a); - switchboard.addSwitch("mapFind", shortcutScope, a, tag); + switchboard.addAction(a, "mapFind", Qt::CTRL | Qt::Key_F, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editOpenFindResultWidget())); actionListFiles.append(a); actionFind = a; a = new QAction(QPixmap(QString(":/edit-find-%1.svg").arg(iconTheme)), tr("Find...", "Edit menu"), this); - a->setShortcut(Qt::Key_Slash); - ADD_SHORTCUT selectMenu->addAction(a); - switchboard.addSwitch("mapFindAlt", shortcutScope, a, tag); + switchboard.addAction(a, "mapFindAlt", Qt::Key_Slash, shortcutScope, tag); // Alternative: VIM Find connect(a, SIGNAL(triggered()), this, SLOT(editOpenFindResultWidget())); actionListFiles.append(a); + actionFindVim = a; + + a = new QAction(tr("Follow reference", "Context menu"), this); + addAction(a); + actionListBranches.append(a); + selectMenu->addAction(a); + switchboard.addAction(a, "mapFollowXLink", Qt::Key_F, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(popupFollowReference())); + actionFollowReference = a; + + a = new QAction("Select first branch in siblings", this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + selectMenu->addAction(a); + switchboard.addAction(a, "Select first branch in siblings", Qt::Key_Home, shortcutScope, tag); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(editSelectFirstSibling())); + + a = new QAction("Select first branch in siblings", this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + selectMenu->addAction(a); + switchboard.addAction(a, "Select first branch in siblings", Qt::Key_0, shortcutScope, tag); // Alternative: VIM Select first + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(editSelectFirstSibling())); + + a = new QAction("Select last branch in siblings", this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + selectMenu->addAction(a); + switchboard.addAction(a, "Select last branch in siblings", Qt::Key_End, shortcutScope, tag); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(editSelectLastSibling())); + + a = new QAction("Select last branch in siblings", this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + selectMenu->addAction(a); + switchboard.addAction(a, "Select last branch in siblings", Qt::Key_Dollar, shortcutScope, tag); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(editSelectLastSibling())); - a = new QAction(tr("Find duplicate URLs", "Edit menu") + " (test)", this); - a->setShortcut(Qt::SHIFT | Qt::Key_F); - ADD_SHORTCUT - switchboard.addSwitch("mapFindDuplicates", shortcutScope, a, tag); - if (settings.value("/mainwindow/showTestMenu", false).toBool()) - selectMenu->addAction(a); - connect(a, SIGNAL(triggered()), this, SLOT(editFindDuplicateURLs())); a = new QAction(QPixmap(":/flag-target.svg"), tr("Toggle target...", "Edit menu"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_T); - ADD_SHORTCUT a->setCheckable(true); selectMenu->addAction(a); - switchboard.addSwitch("mapToggleTarget", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleTarget", Qt::SHIFT | Qt::Key_T, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editToggleTarget())); actionListBranches.append(a); actionToggleTarget = a; a = new QAction(QPixmap(":/flag-target.svg"), tr("Goto target...", "Edit menu"), this); - a->setShortcut(Qt::Key_G); - ADD_SHORTCUT selectMenu->addAction(a); - switchboard.addSwitch("mapGotoTarget", shortcutScope, a, tag); + switchboard.addAction(a, "mapGotoTarget", Qt::Key_G, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editGoToTarget())); actionListBranches.append(a); actionListImages.append(a); @@ -2643,52 +2567,49 @@ void Main::setupSelectActions() a = new QAction(QPixmap(":/flag-target.svg"), tr("Move to target...", "Edit menu"), this); - a->setShortcut(Qt::Key_M); - ADD_SHORTCUT selectMenu->addAction(a); - switchboard.addSwitch("mapMoveToTarget", shortcutScope, a, tag); + switchboard.addAction(a, "mapMoveToTarget", Qt::Key_M, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editMoveToTarget())); actionListBranches.append(a); actionMoveToTarget = a; a = new QAction(QPixmap(":/flag-vymlink.png"), tr("Goto linked map...", "Edit menu"), this); - a->setShortcut(Qt::Key_G | Qt::SHIFT); - ADD_SHORTCUT selectMenu->addAction(a); - switchboard.addSwitch("gotoLinkedMap", shortcutScope, a, tag); + switchboard.addAction(a, "gotoLinkedMap", Qt::Key_G | Qt::SHIFT, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editGoToLinkedMap())); actionListBranches.append(a); actionGoToTargetLinkedMap = a; + a = new QAction(tr("Find duplicate URLs", "Edit menu") + " (test)", this); + switchboard.addAction(a, "mapFindDuplicates", shortcutScope, tag); + if (settings.value("/mainwindow/showTestMenu", false).toBool()) + selectMenu->addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(editFindDuplicateURLs())); + a = new QAction(QPixmap(QString(":/go-previous-%1.svg").arg(iconTheme)), tr("Select previous", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_O); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); selectMenu->addAction(a); actionListFiles.append(a); mapEditorActions.append(a); - switchboard.addSwitch("mapSelectPrevious", shortcutScope, a, tag); + switchboard.addAction(a, "mapSelectPrevious", Qt::CTRL | Qt::Key_O, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editSelectPrevious())); actionSelectPrevious = a; a = new QAction(QPixmap(QString(":/go-next-%1.svg").arg(iconTheme)), tr("Select next", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_I); - ADD_SHORTCUT a->setShortcutContext(Qt::WidgetShortcut); selectMenu->addAction(a); actionListFiles.append(a); mapEditorActions.append(a); - switchboard.addSwitch("mapSelectNext", shortcutScope, a, tag); + switchboard.addAction(a, "mapSelectNext", Qt::CTRL | Qt::Key_I, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editSelectNext())); actionSelectNext = a; a = new QAction(tr("Unselect all", "Edit menu"), this); - // a->setShortcut (Qt::CTRL | Qt::Key_I ); selectMenu->addAction(a); - switchboard.addSwitch("mapSelectNothing", shortcutScope, a, tag); + switchboard.addAction(a, "mapSelectNothing", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editSelectNothing())); actionListFiles.append(a); actionSelectNothing = a; @@ -2698,17 +2619,14 @@ void Main::setupSelectActions() // Format Actions void Main::setupFormatActions() { - QMenu *formatMenu = menuBar()->addMenu(tr("F&ormat", "Format menu")); - QString tag = tr("Formatting", "Shortcuts"); QAction* a; a = new QAction(QPixmap(":/formatcolorpicker.png"), tr("Pic&k color", "Edit menu"), this); - // a->setShortcut (Qt::CTRL | Qt::Key_K ); formatMenu->addAction(a); - switchboard.addSwitch("mapFormatColorPicker", shortcutScope, a, tag); + switchboard.addAction(a, "mapFormatColorPicker", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(formatPickColor())); a->setEnabled(false); actionListBranches.append(a); @@ -2716,9 +2634,8 @@ void Main::setupFormatActions() a = new QAction(QPixmap(":/formatcolorbranch.png"), tr("Color &branch", "Edit menu"), this); - // a->setShortcut (Qt::CTRL | Qt::Key_B | Qt::SHIFT); formatMenu->addAction(a); - switchboard.addSwitch("mapFormatColorBranch", shortcutScope, a, tag); + switchboard.addAction(a, "mapFormatColorBranch", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(formatColorBranch())); a->setEnabled(false); actionListBranches.append(a); @@ -2726,9 +2643,8 @@ void Main::setupFormatActions() a = new QAction(QPixmap(":/formatcolorsubtree.png"), tr("Color sub&tree", "Edit menu"), this); - // a->setShortcut (Qt::CTRL | Qt::Key_B); // Color subtree formatMenu->addAction(a); - switchboard.addSwitch("mapFormatColorSubtree", shortcutScope, a, tag); + switchboard.addAction(a, "mapFormatColorSubtree", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(formatColorSubtree())); a->setEnabled(false); actionListBranches.append(a); @@ -2813,193 +2729,187 @@ void Main::setupFormatActions() // View Actions void Main::setupViewActions() { - QMenu *viewMenu = menuBar()->addMenu(tr("&View")); - toolbarsMenu = - viewMenu->addMenu(tr("Toolbars", "Toolbars overview in view menu")); - windowsMenu = - viewMenu->addMenu(tr("Windows", "Editor windows overview in view menu")); - - viewMenu->addSeparator(); - QAction *a; - QString tag = tr("Views", "Shortcuts"); - - a = new QAction(QPixmap(":view-video-projector.png"), - tr("Toggle Presentation mode", "View action") + " " + - tr("(still experimental)"), - this); - a->setShortcut(Qt::Key_Asterisk || Qt::SHIFT); - ADD_SHORTCUT - viewMenu->addAction(a); - switchboard.addSwitch ("presentationMode", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(togglePresentationMode())); - actionTogglePresentationMode = a; + QString tag = tr("Views", "Mainwindow view shortcut groups"); a = new QAction(QPixmap(QString(":/folder-cloud-%1.svg").arg(iconTheme)), tr("Toggle mode to temporary hide parts", "View action"), this); - a->setShortcut(Qt::Key_H | Qt::SHIFT); - ADD_SHORTCUT - viewMenu->addAction(a); viewMenu->addAction(a); - switchboard.addSwitch ("tmpHideMode", shortcutScope, a, tag); + switchboard.addAction (a, "tmpHideMode", Qt::Key_H | Qt::SHIFT, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(toggleHideTmpMode())); actionToggleHideTmpMode = a; a = new QAction(QPixmap(QString(":/zoom-in-%1.svg").arg(iconTheme)), tr("Zoom in", "View action"), this); - a->setShortcut(Qt::Key_Plus); - ADD_SHORTCUT viewMenu->addAction(a); - switchboard.addSwitch("mapZoomIn", shortcutScope, a, tag); + switchboard.addAction(a, "mapZoomIn", Qt::Key_Plus, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(viewZoomIn())); actionZoomIn = a; a = new QAction(QPixmap(QString(":/zoom-out-%1.svg").arg(iconTheme)), tr("Zoom out", "View action"), this); - a->setShortcut(Qt::Key_Minus); - ADD_SHORTCUT viewMenu->addAction(a); - switchboard.addSwitch("mapZoomOut", shortcutScope, a, tag); + switchboard.addAction(a, "mapZoomOut", Qt::Key_Minus, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(viewZoomOut())); actionZoomOut = a; a = new QAction(QPixmap(QString(":/transform-rotate-ccw-%1.svg").arg(iconTheme)), tr("Rotate counterclockwise", "View action"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_R); - ADD_SHORTCUT viewMenu->addAction(a); - switchboard.addSwitch("mapRotateCounterClockwise", shortcutScope, a, tag); + switchboard.addAction(a, "mapRotateCounterClockwise", Qt::SHIFT | Qt::Key_R, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(viewRotateCounterClockwise())); actionRotateCounterClockwise = a; a = new QAction(QPixmap(QString(":/transform-rotate-cw-%1.svg").arg(iconTheme)), tr("Rotate clockwise", "View action"), this); - a->setShortcut(Qt::Key_R); - ADD_SHORTCUT viewMenu->addAction(a); - switchboard.addSwitch("mapRotateClockwise", shortcutScope, a, tag); + switchboard.addAction(a, "mapRotateClockwise", Qt::Key_R, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(viewRotateClockwise())); actionRotateClockwise = a; a = new QAction(QPixmap(QString(":/zoom-original-%1").arg(iconTheme)), tr("reset Zoom", "View action"), this); - a->setShortcut(Qt::Key_Comma); - ADD_SHORTCUT - switchboard.addSwitch("mapZoomReset", shortcutScope, a, tag); + switchboard.addAction(a, "mapZoomReset", Qt::Key_Comma, shortcutScope, tag); viewMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(viewZoomReset())); actionZoomReset = a; a = new QAction(QPixmap(QString(":/zoom-fit-best-%1.svg").arg(iconTheme)), tr("Center on selection", "View action"), this); - a->setShortcut(Qt::Key_Period); - ADD_SHORTCUT viewMenu->addAction(a); - switchboard.addSwitch("mapCenterOn", shortcutScope, a, tag); + switchboard.addAction(a, "mapCenterOn", Qt::Key_NumberSign, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(viewCenter())); actionCenterOn = a; a = new QAction(tr("Fit view to selection", "View action"), this); - a->setShortcut(Qt::Key_Period | Qt::SHIFT); - ADD_SHORTCUT viewMenu->addAction(a); - switchboard.addSwitch("mapCenterAndFitView", shortcutScope, a, tag); + switchboard.addAction(a, "mapCenterAndFitView", Qt::Key_Semicolon, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(viewCenterScaled())); actionCenterOnScaled = a; a = new QAction( tr("Rotate view to selection", "View action"), this); - a->setShortcut(Qt::Key_NumberSign); - ADD_SHORTCUT viewMenu->addAction(a); - switchboard.addSwitch("mapCenterAndRotateView", shortcutScope, a, tag); + switchboard.addAction(a, "mapCenterAndRotateView", Qt::Key_NumberSign | Qt::SHIFT, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(viewCenterRotated())); actionCenterOnRotated = a; + tag = tr("Tree editor expand/collapse", "Mainwindow view shortcut groups"); + + a = new QAction(QPixmap(), tr("Expand all branches", "Edit menu"), this); + connect(a, SIGNAL(triggered()), this, SLOT(editExpandAll())); + actionExpandAll = a; + actionExpandAll->setEnabled(false); + actionExpandAll->setCheckable(false); + actionListBranches.append(actionExpandAll); + addAction(a); + + a = new QAction(tr("Expand one level", "Edit menu"), this); + switchboard.addAction(a, "mapExpandOneLevel", Qt::Key_Greater, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(editExpandOneLevel())); + a->setEnabled(false); + a->setCheckable(false); + addAction(a); + actionListBranches.append(a); + actionExpandOneLevel = a; + + a = new QAction("TE: " + tr("Collapse one level", "Edit menu"), this); + switchboard.addAction(a, "mapCollapseOneLevel", Qt::Key_Less | Qt::CTRL, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(editCollapseOneLevel())); + viewMenu->addAction(a); + a->setEnabled(false); + a->setCheckable(false); + actionListBranches.append(a); + addAction(a); + actionCollapseOneLevel = a; + + a = new QAction("TE: " + tr("Collapse unselected levels", "Edit menu"), this); + switchboard.addAction(a, "mapCollapseUnselectedLevels", Qt::Key_Less, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(editCollapseUnselected())); + viewMenu->addAction(a); + a->setEnabled(false); + a->setCheckable(false); + actionListBranches.append(a); + addAction(a); + actionCollapseUnselected = a; viewMenu->addSeparator(); // Editor and other windows + tag = tr("Windows", "Mainwindow view shortcut groups"); // a=noteEditorDW->toggleViewAction(); a = new QAction(QPixmap(":/flag-note.svg"), tr("Note editor", "View action"), this); - a->setShortcut(Qt::Key_N); a->setShortcutContext(Qt::WidgetShortcut); a->setCheckable(true); windowsMenu->addAction(a); mapEditorActions.append(a); - switchboard.addSwitch("mapToggleNoteEditor", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(windowToggleNoteEditor())); - actionViewToggleNoteEditor = a; + switchboard.addAction(a, "mapShowNoteEditor", Qt::Key_N, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(windowShowNoteEditor())); + actionViewToggleNoteEditor = a; // FIXME-3 rename action to show // a=headingEditorDW->toggleViewAction(); a = new QAction(QPixmap(":/headingeditor.png"), tr("Heading editor", "View action"), this); a->setCheckable(true); a->setIcon(QPixmap(":/headingeditor.png")); - a->setShortcut(Qt::Key_E); a->setShortcutContext(Qt::WidgetShortcut); mapEditorActions.append(a); windowsMenu->addAction(a); - switchboard.addSwitch("mapToggleHeadingEditor", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(windowToggleHeadingEditor())); - actionViewToggleHeadingEditor = a; + switchboard.addAction(a, "mapShowHeadingEditor", Qt::Key_E, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(windowShowHeadingEditor())); + actionViewToggleHeadingEditor = a; // FIXME-3 rename action to show // Original icon is "category" from KDE a = new QAction(QPixmap(":/treeeditor.png"), - tr("Tree editor", "View action"), this); - a->setShortcut(Qt::CTRL | Qt::Key_T); + tr("Switch between Map editor and Tree editor", "View action"), this); a->setCheckable(true); windowsMenu->addAction(a); - switchboard.addSwitch("mapToggleTreeEditor", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(windowToggleTreeEditors())); - actionViewToggleTreeEditor = a; + switchboard.addAction(a, "switchTreeEditorAndMapEditor", Qt::Key_Tab, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(switchEditors())); + actionViewSwitchEditors = a; a = new QAction(QPixmap(":/taskeditor.png"), tr("Task editor", "View action"), this); a->setCheckable(true); - a->setShortcut(Qt::Key_Q); a->setShortcutContext(Qt::WidgetShortcut); mapEditorActions.append(a); windowsMenu->addAction(a); - switchboard.addSwitch("mapToggleTaskEditor", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleTaskEditor", Qt::Key_Q, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(windowToggleTaskEditor())); - actionViewToggleTaskEditor = a; + actionViewToggleTaskEditor = a; // FIXME-3 rename action to show a = new QAction(QPixmap(":/slideeditor.png"), tr("Slide editor", "View action"), this); a->setCheckable(true); windowsMenu->addAction(a); - switchboard.addSwitch("mapToggleSlideEditor", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(windowToggleSlideEditors())); - actionViewToggleSlideEditor = a; + switchboard.addAction(a, "mapShowSlideEditor", shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(windowShowSlideEditors())); + actionViewShowSlideEditors = a; a = new QAction(QPixmap(":/scripteditor.png"), tr("Script editor", "View action"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_S); a->setCheckable(true); windowsMenu->addAction(a); - switchboard.addSwitch("mapToggleScriptEditor", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleScriptEditor", Qt::SHIFT | Qt::Key_S, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(windowToggleScriptEditor())); - actionViewToggleScriptEditor = a; + actionViewToggleScriptEditor = a; // FIXME-3 show a = new QAction(QPixmap(), tr("Script output window", "View action"), this); - a->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S); a->setCheckable(true); windowsMenu->addAction(a); - switchboard.addSwitch("mapToggleScriptOutput", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleScriptOutput", Qt::CTRL | Qt::SHIFT | Qt::Key_S, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(windowToggleScriptOutput())); - actionViewToggleScriptOutput = a; + actionViewToggleScriptOutput = a; // FIXME-3 show a = new QAction(QPixmap(":/history.png"), tr("History Window", "View action"), this); - a->setShortcut(Qt::CTRL | Qt::Key_H); a->setShortcutContext(Qt::WidgetShortcut); a->setCheckable(true); windowsMenu->addAction(a); mapEditorActions.append(a); - switchboard.addSwitch("mapToggleHistoryWindow", shortcutScope, a, tag); + switchboard.addAction(a, "mapToggleHistoryWindow", Qt::CTRL | Qt::Key_H, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(windowToggleHistory())); actionViewToggleHistoryWindow = a; @@ -3027,54 +2937,61 @@ void Main::setupViewActions() viewMenu->addSeparator(); - // Map and slides - a = new QAction(tr("Next Map", "View action"), this); - a->setStatusTip(a->text()); - a->setShortcut(Qt::SHIFT | Qt::Key_Right); - viewMenu->addAction(a); - switchboard.addSwitch("mapPrevious", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(windowNextEditor())); - - a = new QAction(tr("Previous Map", "View action"), this); - a->setStatusTip(a->text()); - a->setShortcut(Qt::SHIFT | Qt::Key_Left); + // Slides and presentation + tag = tr("Presentation mode", "Mainwindow presentation shortcut groups"); + a = new QAction(QPixmap(":view-video-projector.png"), + tr("Toggle Presentation mode", "View action") + " " + + tr("(still experimental)"), + this); viewMenu->addAction(a); - switchboard.addSwitch("mapNext", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(windowPreviousEditor())); + switchboard.addAction (a, "presentationMode", Qt::Key_Asterisk | Qt::SHIFT, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(togglePresentationMode())); + actionTogglePresentationMode = a; a = new QAction(tr("Next slide", "View action"), this); a->setStatusTip(a->text()); - a->setShortcut(Qt::Key_Space); viewMenu->addAction(a); - switchboard.addSwitch("mapNextSlide", shortcutScope, a, tag); + switchboard.addAction(a, "mapNextSlide", Qt::Key_Space, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(nextSlide())); a = new QAction(tr("Previous slide", "View action"), this); //FIXME-3 no shortcut yet a->setStatusTip(a->text()); - //a->setShortcut(Qt::Key_Backspace); viewMenu->addAction(a); - switchboard.addSwitch("mapPreviousSlide", shortcutScope, a, tag); + switchboard.addAction(a, "mapPreviousSlide", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(previousSlide())); + + // Map navigation + tag = tr("Navigation between maps", "Mainwindow view shortcut groups"); + a = new QAction(tr("Next Map", "View action"), this); + a->setStatusTip(a->text()); + viewMenu->addAction(a); + switchboard.addAction(a, "mapPrevious", Qt::SHIFT | Qt::Key_Right, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(windowNextEditor())); + + a = new QAction(tr("Previous Map", "View action"), this); + a->setStatusTip(a->text()); + viewMenu->addAction(a); + switchboard.addAction(a, "mapNext", Qt::SHIFT | Qt::Key_Left, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(windowPreviousEditor())); } // Connect Actions void Main::setupConnectActions() { - QMenu *connectMenu = menuBar()->addMenu(tr("&Connect")); QString tag = tr("Connect", "Shortcuts"); QAction *a; a = new QAction( tr("Get Confluence user data", "Connect action"), this); - a->setShortcut(Qt::SHIFT | Qt::Key_C); connectMenu->addAction(a); - switchboard.addSwitch ("confluenceUser", shortcutScope, a, tag); + switchboard.addAction(a, "confluenceUser", Qt::SHIFT | Qt::Key_C, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(getConfluenceUser())); actionConnectGetConfluenceUser = a; connectMenu->addAction(actionGetConfluencePageDetails); connectMenu->addAction(actionGetConfluencePageDetailsRecursively); connectMenu->addAction(actionGetJiraDataSubtree); + connectMenu->addAction(actionSetJiraQuery); connectMenu->addSeparator(); @@ -3097,10 +3014,8 @@ void Main::setupModeActions() QIcon(":/mode-select.svg"), tr("Use modifier to select and reorder objects", "Mode modifier"), actionGroupModModes); - a->setShortcut(Qt::Key_J); - ADD_SHORTCUT addAction(a); - switchboard.addSwitch("mapModModePoint", shortcutScope, a, tag); + switchboard.addAction(a, "mapModModePoint", Qt::Key_J, shortcutScope, tag); a->setCheckable(true); a->setChecked(true); actionListFiles.append(a); @@ -3111,10 +3026,8 @@ void Main::setupModeActions() tr("Use modifier to pick color from another branch", "Mode modifier"), actionGroupModModes); - a->setShortcut(Qt::Key_K); - ADD_SHORTCUT addAction(a); - switchboard.addSwitch("mapModModeColor", shortcutScope, a, tag); + switchboard.addAction(a, "mapModModeColor", Qt::Key_K, shortcutScope, tag); a->setCheckable(true); actionListFiles.append(a); actionModModeColor = a; @@ -3122,10 +3035,8 @@ void Main::setupModeActions() a = new QAction(QPixmap(":/mode-xlink.png"), tr("Use modifier to draw xLinks", "Mode modifier"), actionGroupModModes); - a->setShortcut(Qt::Key_L); - ADD_SHORTCUT addAction(a); - switchboard.addSwitch("mapModModeXLink", shortcutScope, a, tag); + switchboard.addAction(a, "mapModModeXLink", Qt::Key_L, shortcutScope, tag); a->setCheckable(true); actionListFiles.append(a); actionModModeXLink = a; @@ -3134,10 +3045,8 @@ void Main::setupModeActions() QPixmap(":/mode-move-object.svg"), tr("Use modifier to move branches without linking", "Mode modifier"), actionGroupModModes); - a->setShortcut(Qt::Key_Odiaeresis); - ADD_SHORTCUT addAction(a); - switchboard.addSwitch("mapModModeMoveObject", shortcutScope, a, tag); + switchboard.addAction(a, "mapModModeMoveObject", Qt::Key_Odiaeresis, shortcutScope, tag); a->setCheckable(true); actionListFiles.append(a); actionModModeMoveObject = a; @@ -3146,10 +3055,8 @@ void Main::setupModeActions() QPixmap(":/mode-move-view.png"), tr("Use modifier to move view without selecting", "Mode modifier"), actionGroupModModes); - a->setShortcut(Qt::Key_Adiaeresis); - ADD_SHORTCUT addAction(a); - switchboard.addSwitch("mapModModeMoveView", shortcutScope, a, tag); + switchboard.addAction(a, "mapModModeMoveView", Qt::Key_Adiaeresis, shortcutScope, tag); a->setCheckable(true); actionListFiles.append(a); actionModModeMoveView = a; @@ -3446,7 +3353,7 @@ Flag *Main::setupFlag(const QString &path, Flag::FlagType type, } if (!flag) - return flag; + return nullptr; flag->setName(name); flag->setToolTip(tooltip); @@ -3571,6 +3478,8 @@ void Main::setupSettingsActions() settingsMenu->addAction(a); actionSettingsJIRA = a; + settingsMenu->addSeparator(); + a = new QAction(tr("Set path for new maps", "Settings action") + "...", this); connect(a, SIGNAL(triggered()), this, SLOT(settingsDefaultMapPath())); @@ -3628,13 +3537,6 @@ void Main::setupSettingsActions() settingsMenu->addAction(a); actionSettingsAutoSelectNewBranch = a; - a = new QAction(tr("Select existing heading", "Settings action"), this); - a->setCheckable(true); - a->setChecked( - settings.value("/mapeditor/editmode/autoSelectText", true).toBool()); - settingsMenu->addAction(a); - actionSettingsAutoSelectText = a; - a = new QAction(tr("Exclusive flags", "Settings action"), this); a->setCheckable(true); a->setChecked( @@ -3697,13 +3599,11 @@ void Main::setupTestActions() QString tag = "Testing"; QAction *a; a = new QAction("Test function 1", this); - a->setShortcut(Qt::ALT | Qt::Key_T); testMenu->addAction(a); - switchboard.addSwitch("mapTest1", shortcutScope, a, tag); + switchboard.addAction(a, "mapTest1", Qt::ALT | Qt::Key_T, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(testFunction1())); a = new QAction("Test function 2", this); - // a->setShortcut (Qt::ALT | Qt::Key_T); testMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(testFunction2())); @@ -3767,7 +3667,7 @@ void Main::setupHelpActions() } // Context Menus -void Main::setupContextMenus() +void Main::setupContextMenus() // FIXME-2 Use context menus add/remove also in Edit menu for better readability { // Context menu for goto/move targets (populated on demand) targetsContextMenu = new QMenu(this); @@ -3787,6 +3687,8 @@ void Main::setupContextMenus() branchAddContextMenu->addSeparator(); branchAddContextMenu->addAction(actionImportAdd); branchAddContextMenu->addAction(actionImportReplace); + foreach (auto a, branchAddContextMenu->actions()) + a->setShortcutVisibleInContextMenu(true); // Submenu "Remove" branchRemoveContextMenu = @@ -3795,10 +3697,30 @@ void Main::setupContextMenus() branchRemoveContextMenu->addAction(actionDelete); branchRemoveContextMenu->addAction(actionDeleteKeepChildren); branchRemoveContextMenu->addAction(actionDeleteChildren); - - branchContextMenu->addAction(actionSaveBranch); - branchContextMenu->addAction(actionFileNewCopy); - branchContextMenu->addAction(actionDetach); + foreach (auto a, branchRemoveContextMenu->actions()) + a->setShortcutVisibleInContextMenu(true); + + // Submenu "Hierarchy" + branchHierarchyContextMenu = + branchContextMenu->addMenu(tr("Hierarchy", "Context menu name")); + branchHierarchyContextMenu->addAction(actionMoveUp); + branchHierarchyContextMenu->addAction(actionMoveDown); + branchHierarchyContextMenu->addAction(actionMoveDownDiagonally); + branchHierarchyContextMenu->addAction(actionMoveUpDiagonally); + branchHierarchyContextMenu->addAction(actionDetach); + branchHierarchyContextMenu->addAction(actionSortChildren); + branchHierarchyContextMenu->addAction(actionSortBackChildren); + //foreach (auto a, branchRemoveContextMenu->actions()) + // a->setShortcutVisibleInContextMenu(true); + + // Submenu "Geometry" + branchGeometryContextMenu = + branchContextMenu->addMenu(tr("Geometry", "Context menu name")); + branchGeometryContextMenu->addAction(actionGrowSelectionSize); + branchGeometryContextMenu->addAction(actionShrinkSelectionSize); + branchGeometryContextMenu->addAction(actionResetSelectionSize); + branchGeometryContextMenu->addAction(actionRotateSubtreeCW); + branchGeometryContextMenu->addAction(actionRotateSubtreeCCW); branchContextMenu->addSeparator(); branchContextMenu->addAction(actionLoadImage); @@ -3821,6 +3743,8 @@ void Main::setupContextMenus() taskContextMenu->addAction(actionTaskSleep7); taskContextMenu->addAction(actionTaskSleep14); taskContextMenu->addAction(actionTaskSleep28); + foreach (auto a, taskContextMenu->actions()) + a->setShortcutVisibleInContextMenu(true); // Submenu for Links (URLs, vymLinks) branchLinksContextMenu = new QMenu(this); @@ -3844,6 +3768,8 @@ void Main::setupContextMenus() branchLinksContextMenu->addAction(actionOpenMultipleVymLinks); branchLinksContextMenu->addAction(actionEditVymLink); branchLinksContextMenu->addAction(actionDeleteVymLink); + foreach (auto a, branchLinksContextMenu->actions()) + a->setShortcutVisibleInContextMenu(true); // Context Menu for XLinks in a branch menu // This will be populated "on demand" in updateActions @@ -3854,16 +3780,10 @@ void Main::setupContextMenus() connect(branchXLinksContextMenuEdit, SIGNAL(triggered(QAction *)), this, SLOT(editEditXLink(QAction *))); QAction *a; - a = new QAction(tr("Follow XLink", "Context menu"), this); - a->setShortcut(Qt::Key_F); - addAction(a); - switchboard.addSwitch("mapFollowXLink", shortcutScope, a, tag); - connect(a, SIGNAL(triggered()), this, SLOT(popupFollowXLink())); - branchXLinksContextMenuFollow = branchContextMenu->addMenu(tr("Follow XLink", "Context menu name")); connect(branchXLinksContextMenuFollow, SIGNAL(triggered(QAction *)), this, - SLOT(editFollowXLink(QAction *))); + SLOT(followReference(QAction *))); branchContextMenu->addSeparator(); branchContextMenu->addAction(actionViewTogglePropertyEditor); @@ -3883,6 +3803,9 @@ void Main::setupContextMenus() floatimageContextMenu->addAction(actionShrinkSelectionSize); floatimageContextMenu->addAction(actionFormatHideLinkUnselected); + foreach (auto a, floatimageContextMenu->actions()) + a->setShortcutVisibleInContextMenu(true); + // Context menu for canvas canvasContextMenu = new QMenu(this); @@ -3908,6 +3831,8 @@ void Main::setupContextMenus() canvasContextMenu->addSeparator(); canvasContextMenu->addAction(actionMapProperties); + foreach (auto a, canvasContextMenu->actions()) + a->setShortcutVisibleInContextMenu(true); // Menu for last opened files // Create actions @@ -4009,9 +3934,12 @@ void Main::setupMacros() void Main::setupToolbars() { + QList toolbars; // File actions fileToolbar = addToolBar(tr("File actions toolbar", "Toolbar for file actions")); + toolbars << fileToolbar; + fileToolbar->setObjectName("fileTB"); fileToolbar->addAction(actionFileNew); fileToolbar->addAction(actionFileOpen); @@ -4022,6 +3950,7 @@ void Main::setupToolbars() // Undo/Redo and clipboard clipboardToolbar = addToolBar(tr("Undo and clipboard toolbar", "Toolbar for redo/undo and clipboard")); + toolbars << clipboardToolbar; clipboardToolbar->setObjectName("clipboard toolbar"); clipboardToolbar->addAction(actionUndo); clipboardToolbar->addAction(actionRedo); @@ -4031,6 +3960,7 @@ void Main::setupToolbars() // Basic edits editActionsToolbar = addToolBar(tr("Edit actions toolbar", "Toolbar name")); + toolbars << editActionsToolbar; editActionsToolbar->setObjectName("basic edit actions TB"); editActionsToolbar->addAction(actionAddMapCenter); editActionsToolbar->addAction(actionAddBranch); @@ -4051,6 +3981,7 @@ void Main::setupToolbars() // Selections selectionToolbar = addToolBar(tr("Selection toolbar", "Toolbar name")); + toolbars << selectionToolbar; selectionToolbar->setObjectName("toolbar for selecting items"); selectionToolbar->addAction(actionFind); selectionToolbar->addAction(actionSelectPrevious); @@ -4059,12 +3990,14 @@ void Main::setupToolbars() // URLs and vymLinks referencesToolbar = addToolBar( tr("URLs and vymLinks toolbar", "Toolbar for URLs and vymlinks")); + toolbars << referencesToolbar; referencesToolbar->setObjectName("URLs and vymlinks toolbar"); referencesToolbar->addAction(actionURLNew); referencesToolbar->addAction(actionEditVymLink); // Format and colors colorsToolbar = new QToolBar(tr("Colors toolbar", "Colors toolbar name")); + toolbars << colorsToolbar; colorsToolbar->setObjectName("colorsTB"); actionGroupQuickColors = new QActionGroup(this); @@ -4095,7 +4028,7 @@ void Main::setupToolbars() a->setCheckable(true); a->setData(n); //formatMenu->addAction(a); - // switchboard.addSwitch("mapFormatColor", shortcutScope, a, tag); + // switchboard.addAction(a, "mapFormatColor", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(quickColorPressed())); colorsToolbar->addAction(a); n++; @@ -4111,8 +4044,9 @@ void Main::setupToolbars() else addToolBar (colorsToolbar); - // View transformations (shrink/grow/rotate) + // View transformations (shrink/grow/rotate) // FIXME-3 add shortcut to rotate selected subtree/item Fn-key maybe and macro? viewTransformationsToolbar = addToolBar(tr("View toolbar", "View Toolbar name")); + toolbars << viewTransformationsToolbar; viewTransformationsToolbar->setObjectName("viewTB"); viewTransformationsToolbar->addAction(actionZoomIn); viewTransformationsToolbar->addAction(actionZoomOut); @@ -4123,24 +4057,27 @@ void Main::setupToolbars() // Modified special view, e.g. presentation mode or temporary hiding of branches limitedViewToolbar = addToolBar(tr("Limited view toolbar", "View Toolbar name")); + toolbars << limitedViewToolbar ; limitedViewToolbar->setObjectName("limitedViewTB"); limitedViewToolbar->addAction(actionTogglePresentationMode); limitedViewToolbar->addAction(actionToggleHideTmpMode); // Editors editorsToolbar = addToolBar(tr("Editors toolbar", "Editor Toolbar name")); + toolbars << editorsToolbar ; editorsToolbar->setObjectName("editorsTB"); editorsToolbar->addAction(actionViewToggleNoteEditor); editorsToolbar->addAction(actionViewToggleHeadingEditor); - editorsToolbar->addAction(actionViewToggleTreeEditor); + editorsToolbar->addAction(actionViewSwitchEditors); editorsToolbar->addAction(actionViewToggleTaskEditor); - editorsToolbar->addAction(actionViewToggleSlideEditor); + editorsToolbar->addAction(actionViewShowSlideEditors); editorsToolbar->addAction(actionViewToggleScriptEditor); editorsToolbar->addAction(actionViewToggleHistoryWindow); // Modifier modes modModesToolbar = addToolBar(tr("Modifier modes toolbar", "Modifier Toolbar name")); + toolbars << modModesToolbar ; modModesToolbar->setObjectName("modesTB"); modModesToolbar->addAction(actionModModePoint); modModesToolbar->addAction(actionModModeColor); @@ -4152,28 +4089,25 @@ void Main::setupToolbars() addToolBarBreak(); standardFlagsToolbar = addToolBar(tr("Standard Flags toolbar", "Standard Flag Toolbar")); + toolbars << standardFlagsToolbar ; standardFlagsToolbar->setObjectName("standardFlagTB"); standardFlagsMaster->setToolBar(standardFlagsToolbar); userFlagsToolbar = addToolBar(tr("User Flags toolbar", "user Flags Toolbar")); + toolbars << userFlagsToolbar ; userFlagsToolbar->setObjectName("userFlagsTB"); + userFlagsMaster->setToolBar(userFlagsToolbar); userFlagsMaster->createConfigureAction(); - // Add all toolbars to View menu - toolbarsMenu->addAction(fileToolbar->toggleViewAction()); - toolbarsMenu->addAction(clipboardToolbar->toggleViewAction()); - toolbarsMenu->addAction(editActionsToolbar->toggleViewAction()); - toolbarsMenu->addAction(selectionToolbar->toggleViewAction()); - toolbarsMenu->addAction(colorsToolbar->toggleViewAction()); - toolbarsMenu->addAction(viewTransformationsToolbar->toggleViewAction()); - toolbarsMenu->addAction(limitedViewToolbar->toggleViewAction()); - toolbarsMenu->addAction(modModesToolbar->toggleViewAction()); - toolbarsMenu->addAction(referencesToolbar->toggleViewAction()); - toolbarsMenu->addAction(editorsToolbar->toggleViewAction()); - toolbarsMenu->addAction(userFlagsToolbar->toggleViewAction()); - toolbarsMenu->addAction(standardFlagsToolbar->toggleViewAction()); + foreach (auto tb, toolbars) { + // Add View menu + toolbarsMenu->addAction(tb->toggleViewAction()); + + // Set backgrounds + tb->setStyleSheet(toolBarStyle); + } // Initialize toolbarStates for presentation mode toolbarStates[fileToolbar] = true; @@ -4372,6 +4306,18 @@ void Main::fileNewCopy() } } +void Main::backgroundZipStarted() +{ + backgroundZipProcesses++; +} + +void Main::backgroundZipFinished() +{ + backgroundZipProcesses--; + if (closeAfterLastZipProcess) + fileExitVYM(); +} + bool Main::fileLoad(QString fn, const File::LoadMode &lmode, const File::FileType &ftype) { @@ -5118,7 +5064,7 @@ void Main::fileExportLast() bool Main::fileCloseMap(int i) { - + //qDebug() << __func__ << "i=" << i << " currentInd=" << tabWidget->currentIndex(); VymModel *m; VymView *vv; if (i < 0) @@ -5128,11 +5074,6 @@ bool Main::fileCloseMap(int i) m = vv->getModel(); if (m) { - if (m->isSaving()) { - //qDebug() << "MW::fileCloseMap ignoring request to close because of running zip process"; - return false; - } - if (m->hasChanged()) { QMessageBox mb( QMessageBox::Warning, @@ -5177,8 +5118,25 @@ void Main::filePrint() currentMapEditor()->print(); } +bool Main::exitAfterScript() +{ + return exitAfterScriptInt; +} + +void Main::setRepeatAction(const QString &script) +{ + repeatActionInt = script; +} + +void Main::setExitAfterScript(bool b) +{ + exitAfterScriptInt = b; +} + bool Main::fileExitVYM() { + closeAfterLastZipProcess = true; + // Only save session if there still are tabs open if (tabWidget->count() > 0) fileSaveSession(); @@ -5191,7 +5149,10 @@ bool Main::fileExitVYM() // Update widgets to show progress qApp->processEvents(); } - qApp->quit(); + if (backgroundZipProcesses > 0) + qDebug() << __func__ << " has still running bg zips..."; + else + qApp->quit(); return false; } @@ -5838,6 +5799,25 @@ void Main::editResetSelectionSize() m->resetSelectionSize(); } +void Main::editRotateSubtreeCW() +{ + VymModel *m = currentModel(); + if (m) + m->rotateSubtree(5); +} + +void Main::editRotateSubtreeCCW() +{ + VymModel *m = currentModel(); + if (m) + m->rotateSubtree(-5); +} + +void Main::editRepeatLastAction() +{ + runScriptWithMacros(repeatActionInt); +} + void Main::editAddMapCenter() { VymModel *m = currentModel(); @@ -5925,7 +5905,7 @@ void Main::editDeleteSelection() { VymModel *m = currentModel(); if (m) - m->deleteSelection(); + m->cut(); } void Main::editLoadImage() @@ -5962,17 +5942,34 @@ void Main::editEditXLink(QAction *a) } } -void Main::popupFollowXLink() +void Main::popupFollowReference() { - branchXLinksContextMenuFollow->exec(QCursor::pos()); + if (branchXLinksContextMenuFollow->actions().count() == 1) + // If only one reference (XLink, Url, VymLink) is available, + // just follow it + followReference(branchXLinksContextMenuFollow->actions().at(0)); + else + // Popup menu + branchXLinksContextMenuFollow->exec(QCursor::pos()); } -void Main::editFollowXLink(QAction *a) +void Main::followReference(QAction *a) { VymModel *m = currentModel(); - if (m) - m->followXLink(branchXLinksContextMenuFollow->actions().indexOf(a)); + if (m) { + QString d = a->data().toString(); + if (d.startsWith("XLink:")) + m->select(QUuid(d.section(':', 1))); + else if (d.startsWith("Url:")) + openUrl(d.section(':', 1)); + else if (d.startsWith("VymLink:")) { + QStringList vymLinks; + vymLinks << d.section(':', 1); + openVymLinks(vymLinks); + } else + qWarning() << __func__ << "Unknown reference in d=" << d; + } } bool Main::initLinkedMapsMenu(VymModel *model, QMenu *menu) @@ -6133,6 +6130,20 @@ void Main::editMoveToTarget() } } +void Main::editSelectFirstSibling() +{ + VymModel *m = currentModel(); + if (m) + m->selectFirstBranch(); +} + +void Main::editSelectLastSibling() +{ + VymModel *m = currentModel(); + if (m) + m->selectLastBranch(); +} + void Main::editSelectPrevious() { VymModel *m = currentModel(); @@ -6156,15 +6167,9 @@ void Main::editSelectNothing() void Main::editOpenFindResultWidget() { - if (!findResultWidget->parentWidget()->isVisible()) { - // findResultWidget->parentWidget()->show(); - findResultWidget->popup(); - } - else - findResultWidget->parentWidget()->hide(); + findResultWidget->popup(); } -#include "findwidget.h" // FIXME-4 Integrated FRW and FW void Main::editFindNext(QString s, bool searchNotesFlag) { Qt::CaseSensitivity cs = Qt::CaseInsensitive; @@ -6172,9 +6177,9 @@ void Main::editFindNext(QString s, bool searchNotesFlag) if (m) { if (m->findAll(findResultWidget->getResultModel(), s, cs, searchNotesFlag)) - findResultWidget->setStatus(FindWidget::Success); + findResultWidget->setStatus(FindControlsWidget::Success); else - findResultWidget->setStatus(FindWidget::Failed); + findResultWidget->setStatus(FindControlsWidget::Failed); } } @@ -6186,8 +6191,7 @@ void Main::editFindDuplicateURLs() // FIXME-4 feature: use FindResultWidget for m->findDuplicateURLs(); } -void Main::updateQueries( - VymModel *) // FIXME-4 disabled for now to avoid selection in FRW +void Main::updateQueries( VymModel *) // FIXME-4 disabled for now to avoid selection in FRW { return; /* @@ -6336,7 +6340,6 @@ void Main::formatSelectLinkColor() if (m) { QColor col = QColorDialog::getColor(m->mapDesign()->defaultLinkColor(), this); m->setDefaultLinkColor(col); - updateActions(); } } @@ -6404,14 +6407,14 @@ void Main::viewRotateCounterClockwise() { MapEditor *me = currentMapEditor(); if (me) - me->setRotationTarget(me->rotationTarget() - 10); + me->setRotationTarget(me->rotationTarget() - 5); } void Main::viewRotateClockwise() { MapEditor *me = currentMapEditor(); if (me) - me->setRotationTarget(me->rotationTarget() + 10); + me->setRotationTarget(me->rotationTarget() + 5); } void Main::viewCenter() @@ -6703,24 +6706,32 @@ bool Main::settingsJIRA() return false; } -void Main::windowToggleNoteEditor() +void Main::windowShowNoteEditor() { - if (noteEditor->parentWidget()->isVisible()) - noteEditor->parentWidget()->hide(); - else { + if (!noteEditor->parentWidget()->isVisible()) noteEditor->parentWidget()->show(); - noteEditor->setFocus(); - } + noteEditor->setFocus(); } -void Main::windowToggleTreeEditors() +void Main::switchEditors() { - windowSetTreeEditorsVisibility(actionViewToggleTreeEditor->isChecked()); + VymView *vv = currentView(); + if (vv) { + MapEditor *me = vv->getMapEditor(); + if (me) { + if (me->hasFocus()) { + windowSetTreeEditorsVisibility(true); + vv->setFocusTreeEditor(); + } else + vv->setFocusMapEditor(); + } + } } void Main::windowSetTreeEditorsVisibility(bool b) { - actionViewToggleTreeEditor->setChecked(b); + // Close *all* TreeEditors in each VymView and update vym settings + settings.setValue("/mainwindow/view/showTreeEditors", b); for (int i = 0; i < tabWidget->count(); i++) ((VymView*)tabWidget->widget(i))->setTreeEditorVisibility(b); } @@ -6737,14 +6748,14 @@ void Main::windowToggleTaskEditor() } } -void Main::windowToggleSlideEditors() +void Main::windowShowSlideEditors() { - windowSetSlideEditorsVisibility(actionViewToggleSlideEditor->isChecked()); + windowSetSlideEditorsVisibility(true); } void Main::windowSetSlideEditorsVisibility(bool b) { - actionViewToggleSlideEditor->setChecked(b); + settings.setValue("/mainwindow/view/showSlideEditors", b); for (int i = 0; i < tabWidget->count(); i++) ((VymView*)tabWidget->widget(i))->setSlideEditorVisibility(b); } @@ -6790,16 +6801,11 @@ void Main::windowToggleProperty() branchPropertyEditor->setModel(currentModel()); } -void Main::windowShowHeadingEditor() { headingEditorDW->show(); } - -void Main::windowToggleHeadingEditor() +void Main::windowShowHeadingEditor() { - if (headingEditor->parentWidget()->isVisible()) - headingEditor->parentWidget()->hide(); - else { + if (!headingEditor->parentWidget()->isVisible()) headingEditor->parentWidget()->show(); - headingEditor->setFocus(); - } + headingEditor->setFocus(); } void Main::windowToggleAntiAlias() @@ -6861,9 +6867,9 @@ void Main::updateNoteEditor(TreeItem *ti) noteEditor->setNote(ti->getNote()); else noteEditor->clear(); // Also sets empty state - return; - } - noteEditor->setInactive(); + } else + noteEditor->setInactive(); + noteEditor->setEditorTitle(); } void Main::updateHeadingEditor(TreeItem *ti) @@ -7102,23 +7108,37 @@ void Main::updateActions() if (m->isSaving()) { actionFileSave->setEnabled(false); actionFileClose->setEnabled(false); - actionFileExitVym->setEnabled(false); } else { if (!m->hasChanged()) actionFileSave->setEnabled(false); - else + else { actionFileSave->setEnabled(true); + actionFileRestoreSession->setEnabled(false); + // qDebug() << __func__ << "disabling restoreSession"; + } actionFileClose->setEnabled(true); - actionFileExitVym->setEnabled(true); } // Undo/Redo - if (!m->isUndoAvailable()) + QWidget *w = clipboardToolbar->widgetForAction(actionUndo); + if (!m->isUndoAvailable()) { actionUndo->setEnabled(false); + actionUndoVim->setEnabled(false); + w->setToolTip(tr("Undo (%1)").arg(actionUndo->shortcut().toString())); + } else { + actionUndo->setToolTip(m->lastUndoComment()); + w->setToolTip(tr("Undo: %1 (%2)").arg(m->lastUndoComment(), actionUndo->shortcut().toString())); + } - if (!m->isRedoAvailable()) + w = clipboardToolbar->widgetForAction(actionRedo); + if (!m->isRedoAvailable()) { actionRedo->setEnabled(false); + w->setToolTip(tr("Redo (%1)").arg(actionRedo->shortcut().toString())); + } else + w->setToolTip(tr("Redo: %1 (%2)").arg(m->lastRedoComment(), actionRedo->shortcut().toString())); + + actionRepeatCommand->setEnabled(!repeatActionInt.isEmpty()); // History window historyWindow->setWindowTitle( @@ -7145,10 +7165,17 @@ void Main::updateActions() com = dest = ""; desc = " - "; } - actionFileExportLast->setText( - tr("Export in last used format: %1\n%2", "status tip") - .arg(desc, dest)); + QString sc = actionFileExportLast->shortcut().toString(); + if (!sc.isEmpty()) { +#if defined(Q_OS_MACOS) + sc.replace("Ctrl","Cmd"); +#endif + sc = " (" + sc + ")"; + } + actionFileExportLast->setToolTip( + tr("Repeat last Export %1\nFormat: %2 to\n%3", "status tip") + .arg(sc, desc, dest)); if (seltis.count() > 0) { // Tree Item selected if (selti) @@ -7178,26 +7205,51 @@ void Main::updateActions() // Take care of xlinks // FIXME-5 similar code in mapeditor mousePressEvent bool b = false; - if (selbi && selbi->xlinkCount() > 0) + if (selbi && selbi->hasReference()) b = true; branchXLinksContextMenuEdit->setEnabled(b); branchXLinksContextMenuFollow->setEnabled(b); branchXLinksContextMenuEdit->clear(); branchXLinksContextMenuFollow->clear(); + actionFollowReference->setEnabled(b); if (b) { BranchItem *bi; QString s; + + // Add XLinks for (int i = 0; i < selbi->xlinkCount(); ++i) { bi = selbi->getXLinkItemNum(i)->getPartnerBranch(); if (bi) { + QString uid = (bi->getUuid()).toString(); s = bi->headingPlain(); if (s.length() > xLinkMenuWidth) s = s.left(xLinkMenuWidth) + "..."; branchXLinksContextMenuEdit->addAction(s); - branchXLinksContextMenuFollow->addAction(s); + branchXLinksContextMenuFollow->addAction( + tr("Branch", "Context menu to follow links") + ": " + s); + branchXLinksContextMenuFollow->actions().last()->setData( + QString("XLink:%1").arg(uid)); } } + + // Add URL + s = selbi->url(); + if (!s.isEmpty()) { + branchXLinksContextMenuFollow->addAction( + tr("Url", "Context menu to follow links") + ": " + s); + branchXLinksContextMenuFollow->actions().last()->setData( + QString("Url:%1").arg(s)); + } + + // Add VymLink + s = selbi->vymLink(); + if (!s.isEmpty()) { + branchXLinksContextMenuFollow->addAction( + tr("Map", "Context menu to follow links") + ": " + s); + branchXLinksContextMenuFollow->actions().last()->setData( + QString("VymLink:%1").arg(s)); + } } // Standard and user flags if (selbi) @@ -7273,10 +7325,12 @@ void Main::updateActions() const QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); if (mimeData->formats().contains("application/x-vym") || - mimeData->hasImage()) - actionPaste->setEnabled(true); - else + mimeData->hasImage()) { + actionPasteVim->setEnabled(true); + } else { actionPaste->setEnabled(false); + actionPasteVim->setEnabled(false); + } actionToggleTarget->setEnabled(true); } // end of BranchItem @@ -7433,7 +7487,6 @@ QVariant Main::runScript(const QString &script) QJSValue vwrapper = scriptEngine->newQObject(vymWrapper); scriptEngine->globalObject().setProperty("vym", vwrapper); - QJSEngine *scriptEngineOrg = scriptEngine; QJSValue result = scriptEngine->evaluate(script); @@ -7468,9 +7521,17 @@ QVariant Main::runScript(const QString &script) scriptEngine->deleteLater(); scriptEngine = nullptr; + if (exitAfterScriptInt) + fileExitVYM(); + return scriptResult; } +QVariant Main::runScriptWithMacros(const QString &script) +{ + return runScript(macros.get() + script); +} + void Main::abortScript(const QJSValue::ErrorType &err, const QString &msg) { if (!scriptEngine) @@ -7543,7 +7604,6 @@ void Main::flagChanged() if (me && m && me->state() != MapEditor::EditingHeading) { m->toggleFlagByUid(QUuid(sender()->objectName()), nullptr, actionSettingsUseFlagGroups->isChecked()); - updateActions(); } } @@ -7566,8 +7626,7 @@ void Main::testFunction2() { VymModel *m = currentModel(); if (m) { - //m->repeatLastCommand(); - currentMapEditor()->testFunction2(); + //currentMapEditor()->testFunction2(); } } @@ -7794,11 +7853,11 @@ void Main::callMacro() // Function keys start at "1", not "0" i++; - QString s = QString("macro_%1f%2();\n").arg(modifiers).arg(i); + QString macro = QString("macro_%1f%2();\n").arg(modifiers).arg(i); - s += macros.get(); - runScript(s); + runScript(macros.get() + macro); + setRepeatAction(macro); } } @@ -8106,4 +8165,3 @@ void Main::toggleHideTmpMode() if (m) m->toggleHideTmpMode(); } - diff --git a/src/mainwindow.h b/src/mainwindow.h index 15eee3a..c51bc00 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -70,10 +70,11 @@ class Main : public QMainWindow { void setupAPI(); /*! Helper method to clone actions later in MapEditor */ - void cloneActionMapEditor(QAction *a, QKeySequence ks); + void cloneActionMapEditor(QAction *a); void setupFileActions(); void setupEditActions(); + void setupEditMenu(); void setupSelectActions(); void setupFormatActions(); void setupViewActions(); @@ -117,7 +118,13 @@ class Main : public QMainWindow { private slots: void editorChanged(); + private: + int backgroundZipProcesses; + bool closeAfterLastZipProcess; + public slots: + void backgroundZipStarted(); + void backgroundZipFinished(); bool fileLoad(QString, const File::LoadMode &, const File::FileType &ftype); void fileLoad(const File::LoadMode &); private slots: @@ -162,11 +169,23 @@ class Main : public QMainWindow { bool fileCloseMap(int i = -1); // Optionally pass number of tab void filePrint(); + public: + bool exitAfterScript(); + void setExitAfterScript(bool b); + + private: + bool exitAfterScriptInt; + QString repeatActionInt; + + public: + void setRepeatAction(const QString &script); + public slots: bool fileExitVYM(); void editUndo(); void editRedo(); void gotoHistoryStep(int); + private slots: void editCopy(); void editPaste(); @@ -222,7 +241,10 @@ class Main : public QMainWindow { void editUnscrollSubtree(); void editGrowSelectionSize(); void editShrinkSelectionSize(); + void editRotateSubtreeCW(); + void editRotateSubtreeCCW(); void editResetSelectionSize(); + void editRepeatLastAction(); void editAddMapCenter(); void editAddBranch(); void editAddBranchBefore(); @@ -236,9 +258,9 @@ class Main : public QMainWindow { void editDeleteSelection(); void editLoadImage(); void editSaveImage(); - void popupFollowXLink(); - void editFollowXLink(QAction *); void editEditXLink(QAction *); + void popupFollowReference(); + void followReference(QAction *); private slots: bool initLinkedMapsMenu(VymModel *model, QMenu *menu); @@ -251,6 +273,8 @@ class Main : public QMainWindow { bool initTargetsMenu(VymModel *model, QMenu *menu); void editGoToTarget(); void editMoveToTarget(); + void editSelectFirstSibling(); + void editSelectLastSibling(); void editSelectPrevious(); void editSelectNext(); void editSelectNothing(); @@ -321,18 +345,17 @@ class Main : public QMainWindow { bool settingsConfluence(); bool settingsJIRA(); - void windowToggleNoteEditor(); - void windowToggleTreeEditors(); + void windowShowNoteEditor(); + void switchEditors(); void windowSetTreeEditorsVisibility(bool); void windowToggleTaskEditor(); - void windowToggleSlideEditors(); + void windowShowSlideEditors(); void windowSetSlideEditorsVisibility(bool); void windowToggleScriptEditor(); void windowToggleScriptOutput(); void windowToggleHistory(); void windowToggleProperty(); void windowShowHeadingEditor(); - void windowToggleHeadingEditor(); void updateHistory(SimpleSettings &); void windowToggleAntiAlias(); bool isAliased(); @@ -355,6 +378,7 @@ class Main : public QMainWindow { void scriptPrint(const QString &, const QString &color = ""); QVariant runScript(const QString &); + QVariant runScriptWithMacros(const QString &); void abortScript(const QJSValue::ErrorType &err, const QString &msg); void abortScript(const QString &msg); QVariant setScriptResult(const QVariant &r); @@ -459,6 +483,26 @@ class Main : public QMainWindow { QMenu *toolbarsMenu; QMenu *windowsMenu; + + QMenu *branchAddContextMenu; + QMenu *branchGeometryContextMenu; + QMenu *branchHierarchyContextMenu; + QMenu *branchLinksContextMenu; + QMenu *branchRemoveContextMenu; + QMenu *branchXLinksContextMenuEdit; + QMenu *branchXLinksContextMenuFollow; // Can also have Urls and VymLinks since 2.9.592 + QMenu *targetsContextMenu; + QMenu *fileLastMapsMenu; + QMenu *fileImportMenu; + QMenu *fileExportMenu; + + QMenu *fileMenu; + QMenu *editMenu; + QMenu *selectMenu; + QMenu *formatMenu; + QMenu *viewMenu; + QMenu *connectMenu; + QToolBar *fileToolbar; QToolBar *clipboardToolbar; QToolBar *editActionsToolbar; @@ -489,10 +533,14 @@ class Main : public QMainWindow { QAction *actionFileExportLast; QAction *actionFileExportConfluence; QAction *actionUndo; + QAction *actionUndoVim; QAction *actionRedo; + QAction *actionRepeatCommand; QAction *actionCopy; + QAction *actionCopyVim; QAction *actionCut; QAction *actionPaste; + QAction *actionPasteVim; QAction *actionMoveUp; QAction *actionMoveDown; QAction *actionMoveDownDiagonally; @@ -501,6 +549,7 @@ class Main : public QMainWindow { QAction *actionSortChildren; QAction *actionSortBackChildren; QAction *actionToggleScroll; + QAction *actionUnscrollSubtree; QAction *actionExpandAll; QAction *actionExpandOneLevel; QAction *actionCollapseOneLevel; @@ -514,6 +563,7 @@ class Main : public QMainWindow { QAction *actionLocalURL; QAction *actionHeading2URL; QAction *actionGetJiraDataSubtree; + QAction *actionSetJiraQuery; QAction *actionGetConfluencePageDetails; QAction *actionGetConfluencePageDetailsRecursively; QAction *actionOpenVymLink; @@ -541,7 +591,7 @@ class Main : public QMainWindow { QAction *actionMapInfo; QAction *actionHeading; QAction *actionDelete; - QAction *actionDeleteAlt; + QAction *actionCutVim; public: QAction *actionAddMapCenter; @@ -562,14 +612,23 @@ class Main : public QMainWindow { QAction *actionShrinkSelectionSize; QAction *actionResetSelectionSize; + QAction *actionRotateSubtreeCW; + QAction *actionRotateSubtreeCCW; + QAction *actionToggleTarget; QAction *actionGoToTargetLinkedMap; QAction *actionGoToTarget; QAction *actionMoveToTarget; + QAction *actionSelectFirstSibling; + QAction *actionSelectFirstSiblingVim; + QAction *actionSelectLastSibling; + QAction *actionSelectLastSiblingVim; QAction *actionSelectPrevious; QAction *actionSelectNext; QAction *actionSelectNothing; QAction *actionFind; + QAction *actionFindVim; + QAction *actionFollowReference; QActionGroup *actionGroupQuickColors; QAction *actionFormatQuickColor; @@ -615,12 +674,8 @@ class Main : public QMainWindow { QAction *actionViewToggleNoteEditor; QAction *actionViewToggleHeadingEditor; QAction *actionViewToggleTaskEditor; - - public: // Allow VymView class to check visibility - QAction *actionViewToggleTreeEditor; - QAction *actionViewToggleSlideEditor; - - private: + QAction *actionViewSwitchEditors; + QAction *actionViewShowSlideEditors; QAction *actionViewToggleScriptEditor; QAction *actionViewToggleScriptOutput; QAction *actionViewToggleHistoryWindow; @@ -631,7 +686,6 @@ class Main : public QMainWindow { QAction *actionConnectGetConfluenceUser; QAction *actionSettingsAutoSelectNewBranch; - QAction *actionSettingsAutoSelectText; QAction *actionSettingsUseFlagGroups; QAction *actionSettingsUseHideExport; QAction *actionSettingsToggleAutosave; diff --git a/src/mapdesign.cpp b/src/mapdesign.cpp index e473179..26e7c99 100644 --- a/src/mapdesign.cpp +++ b/src/mapdesign.cpp @@ -22,6 +22,12 @@ template T & ConfigList::operator[](int i) { } template T ConfigList::tryAt(int i) { + if (qlist.isEmpty()) { + qWarning() << "Empty ConfigList in MapDesign!"; + T t; + return t; + } + if (i >= qlist.count()) return qlist.last(); else @@ -139,26 +145,29 @@ void MapDesign::init() QPalette palette = qApp->palette(); backgroundColorInt = QColor(palette.color(QPalette::Base)); + headingColors << QColor(Qt::white); + innerFramePenColors << QColor(Qt::white); innerFrameBrushColors << QColor(85, 85, 127); innerFramePenColors << QColor(Qt::blue); innerFrameBrushColors << QColor(25, 25, 127); - outerFramePenColors << QColor(Qt::green); - outerFramePenColors << QColor(Qt::red); - outerFramePenColors << QColor(Qt::green); - outerFramePenColors << QColor(Qt::red); - outerFrameBrushColors << QColor(85, 85, 127); - outerFrameBrushColors << QColor(25, 25, 117); - outerFrameBrushColors << QColor(85, 85, 127); - outerFrameBrushColors << QColor(25, 25, 117); + outerFramePenColors << QColor(Qt::blue); + outerFrameBrushColors << QColor(25, 25, 127); } else { backgroundColorInt = QColor(Qt::white); + + headingColors << QColor(Qt::black); + innerFramePenColors << QColor(Qt::black); innerFrameBrushColors << QColor(Qt::white); - outerFramePenColors << QColor(Qt::green); - outerFrameBrushColors << QColor(85, 85, 127); + + innerFramePenColors << QColor(Qt::black); + innerFrameBrushColors << QColor("#dadada"); + + outerFramePenColors << QColor(Qt::black); + outerFrameBrushColors << QColor(Qt::white); } // Font @@ -203,9 +212,6 @@ void MapDesign::init() headingColorHints << MapDesign::InheritedColor; // Use color of parent headingColorUpdateWhenRelinking << false; - headingColors << QColor(Qt::white); - headingColors << QColor(Qt::green); - // Frames innerFrameTypes << FrameContainer::RoundedRectangle; innerFrameTypes << FrameContainer::Rectangle; diff --git a/src/mapeditor.cpp b/src/mapeditor.cpp index e2ef231..ee3993c 100644 --- a/src/mapeditor.cpp +++ b/src/mapeditor.cpp @@ -37,7 +37,7 @@ extern Settings settings; extern QTextStream vout; -extern QString editorFocusStyle; +extern QString editorFocusInStyle; extern FlagRowMaster *systemFlagsMaster; @@ -50,7 +50,7 @@ MapEditor::MapEditor(VymModel *vm) QString shortcutScope = tr("Map Editor", "Shortcut scope"); mapScene = new QGraphicsScene(nullptr); mapScene->setBackgroundBrush(QBrush(Qt::white, Qt::SolidPattern)); - //mapScene->setItemIndexMethod(QGraphicsScene::NoIndex); // FIXME-3 Avoiding crashes... + //mapScene->setItemIndexMethod(QGraphicsScene::NoIndex); // FIXME-4 Avoiding crashes... // Alternatively call removeFromIndex() in destructor // or maybe also prepareGeometryChange() @@ -103,7 +103,7 @@ MapEditor::MapEditor(VymModel *vm) selectionMode = AutoSelection; - setStyleSheet("QGraphicsView:focus {" + editorFocusStyle + "}"); + setStyleSheet("QGraphicsView:focus {" + editorFocusInStyle + "}"); // Create bitmap cursors, platform dependant HandOpenCursor = QCursor(QPixmap(":/mode-move-view.png"), 1, 1); @@ -158,26 +158,24 @@ MapEditor::MapEditor(VymModel *vm) addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(cursorLeft())); - a = new QAction("Select child branch", this); + a = new QAction("Select child or parent branch", this); a->setShortcut(Qt::Key_Right); // a->setShortcutContext (Qt::WidgetWithChildrenShortcut); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(cursorRight())); - a = new QAction("Select first branch", this); - a->setShortcut(Qt::Key_Home); - a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - addAction(a); - connect(a, SIGNAL(triggered()), this, SLOT(cursorFirst())); - - a = new QAction("Select last branch", this); - a->setShortcut(Qt::Key_End); - a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - addAction(a); - connect(a, SIGNAL(triggered()), this, SLOT(cursorLast())); - // Action to embed LineEdit for heading in Scene - lineEdit = nullptr; + lineEdit = new QLineEdit; + lineEdit->setCursor(Qt::IBeamCursor); + editHeadingCancelAction = new QAction("editHeadingCancelAction", lineEdit); + editHeadingCancelAction->setShortcut(Qt::Key_Escape); + //editHeadingCancelAction->setShortcutContext(Qt::ApplicationShortcut); + lineEdit->addAction(editHeadingCancelAction); + proxyWidget = mapScene->addWidget(lineEdit); + connect( editHeadingCancelAction, SIGNAL(triggered()), this, SLOT(editHeadingCanceled())); + lineEdit->show(); + lineEdit->hide(); + a = new QAction(tr("Edit heading", "MapEditor"), this); a->setShortcut(Qt::Key_Return); // Edit heading @@ -195,12 +193,16 @@ MapEditor::MapEditor(VymModel *vm) vPan = QPointF(); connect(panningTimer, SIGNAL(timeout()), this, SLOT(panView())); - // Clone actions defined in MainWindow - foreach (QAction *qa, mainWindow->mapEditorActions) { + // Clone global actions defined in MainWindow // FIXME-3 Problematic, if shortcuts could change later + // Maybe control "duplicate" actions from switchboard + // using scopes? + // Use scope like "MapEditors" for TreeEditor, + // MainWindow and MapEditor? + foreach (auto a_org, mainWindow->mapEditorActions) { a = new QAction(this); - a->setShortcut(qa->shortcut()); - a->setShortcutContext(qa->shortcutContext()); - connect(a, SIGNAL(triggered()), qa, SLOT(trigger())); + a->setShortcut(a_org->shortcut()); + a->setShortcutContext(a_org->shortcutContext()); + connect(a, SIGNAL(triggered()), a_org, SLOT(trigger())); addAction(a); } @@ -703,18 +705,24 @@ void MapEditor::setViewCenterTarget(const QPointF &p, const qreal &zft, void MapEditor::setViewCenterTarget() { - qDebug() << __func__; - MapItem *selti = (MapItem *)(model->getSelectedItem()); - if (selti) { + // qDebug() << __func__; + QList seltis = model->getSelectedItems(); + QPointF p; + int n = 0; + foreach (TreeItem *selti, seltis) { Container *c = nullptr; if (selti->hasTypeBranch()) c = ((BranchItem*)selti)->getBranchContainer()->getHeadingContainer(); else if (selti->hasTypeImage()) c = ((ImageItem*)selti)->getImageContainer(); - else - return; - setViewCenterTarget(c->mapToScene(c->rect().center()), 1, 0); + if (c) { + n++; + p = p + c->mapToScene(c->rect().center()); + } } + + if (n > 0) + setViewCenterTarget( p / n, 1, 0); } QPointF MapEditor::getViewCenterTarget() { return viewCenterTarget; } @@ -1172,18 +1180,18 @@ bool MapEditor::isContainerCloserInDirection(Container *c1, Container *c2, const return false; } -TreeItem* MapEditor::getItemInDirection(TreeItem *ti, RadarDirection radarDir) +TreeItem* MapEditor::getItemInDirection(TreeItem *ti, RadarDirection radarDir) // FIXME-2 setting to enforce hirarchical mode... #161 { SelectionMode selMode = currentSelectionMode(ti); - //qDebug() << "ME::getItemInDir selMode=" << selMode; + // qDebug() << "ME::getItemInDir selMode=" << selMode; if (selMode == GeometricSelection) return getItemFromGeometry(ti, radarDir); if (selMode == OrgChartSelection) return getItemFromOrgChart(ti, radarDir); - return getItemFromClassicMap(ti, radarDir); + return getItemFromHirarchy(ti, radarDir); } TreeItem* MapEditor::getItemFromGeometry(TreeItem *ti, RadarDirection radarDir) // FIXME-3 does not really work @@ -1259,14 +1267,14 @@ TreeItem* MapEditor::getItemFromOrgChart(TreeItem *ti, RadarDirection radarDir) else if (radarDir == DownDirection) return bi->getLastSelectedBranch(); else if (radarDir == LeftDirection) - return getItemFromClassicMap(ti, UpDirection); + return getItemFromHirarchy(ti, UpDirection); else if (radarDir == RightDirection) - return getItemFromClassicMap(ti, DownDirection); + return getItemFromHirarchy(ti, DownDirection); return nullptr; } -TreeItem* MapEditor::getItemFromClassicMap(TreeItem *selti, RadarDirection radarDir) +TreeItem* MapEditor::getItemFromHirarchy(TreeItem *selti, RadarDirection radarDir) { if (!selti) return nullptr; @@ -1553,10 +1561,6 @@ void MapEditor::cursorRight() } } -void MapEditor::cursorFirst() { model->selectFirstBranch(); } // FIXME-3 adapt for images and container layouts - -void MapEditor::cursorLast() { model->selectLastBranch(); } // FIXME-3 adapt for images and container layouts - void MapEditor::editHeading(BranchItem *selbi) { if (editorState == EditingHeading) { @@ -1568,17 +1572,21 @@ void MapEditor::editHeading(BranchItem *selbi) if (selbi) { VymText heading = selbi->heading(); if (heading.isRichText() || selbi->headingPlain().contains("\n")) { + // RichText heading is edited in its own editor, continue there mainWindow->windowShowHeadingEditor(); ensureSelectionVisibleAnimated(); return; } model->setSelectionBlocked(true); - lineEdit = new QLineEdit; - QGraphicsProxyWidget *proxyWidget = mapScene->addWidget(lineEdit); - // FIXME-3-FT get total rotation XXX for BC in scene and do "proxyWidget->setRotation(XXX); - lineEdit->setCursor(Qt::IBeamCursor); + // FIXME-3-FT get total rotation a for BC in scene and do "proxyWidget->setRotation(a); + + // Make sure lineEdit is above everything else, including selection box + mapScene->removeItem(proxyWidget); + mapScene->addItem(proxyWidget); + lineEdit->setCursorPosition(1); + lineEdit->show(); lineEdit->grabKeyboard(); #if defined(Q_OS_WINDOWS) @@ -1594,11 +1602,11 @@ void MapEditor::editHeading(BranchItem *selbi) BranchContainer *bc = selbi->getBranchContainer(); if (bc->getOrientation() == BranchContainer::RightOfParent) { - tl = bc->headingRect().topLeft(); + tl = bc->headingSceneRect().topLeft(); br = tl + QPointF(w, h); } else { - br = bc->headingRect().bottomRight(); + br = bc->headingSceneRect().bottomRight(); tl = br - QPointF(w, h); } // Qt bug when using QProxyWdiget in scaled QGraphicsView @@ -1627,29 +1635,40 @@ void MapEditor::editHeading(BranchItem *selbi) } } +void MapEditor::editHeadingCanceled() +{ + hideLineEdit(); + model->saveStateCancelScript(); +} + void MapEditor::editHeadingFinished() { if (editorState != EditingHeading || !lineEdit ) { qWarning() << "ME::editHeadingFinished not editing heading!"; } else { - lineEdit->clearFocus(); - lineEdit->releaseKeyboard(); QString s = lineEdit->text(); s.replace(QRegularExpression("\\n"), " "); // Don't paste newline chars if (s.length() == 0) s = " "; // Don't allow empty lines, which would screw up drawing model->setHeadingPlainText(s); - delete (lineEdit); - lineEdit = nullptr; - - // Maybe reselect previous branch - mainWindow->editHeadingFinished(model); // Autolayout to avoid overlapping branches with longer headings if (settings.value("/mainwindow/autoLayout/use", "true") == "true") autoLayout(); } + hideLineEdit(); +} + +void MapEditor::hideLineEdit() +{ + lineEdit->clearFocus(); + lineEdit->releaseKeyboard(); + lineEdit->hide(); + + // Maybe reselect previous branch + mainWindow->editHeadingFinished(model); + model->setSelectionBlocked(false); setState(Neutral); } @@ -1924,7 +1943,7 @@ void MapEditor::mousePressEvent(QMouseEvent *e) // FIXME-3 Drop down dialog, if model->getUrl(), e->modifiers() & Qt::AltModifier); } else if (sysFlagName == "system-note") - mainWindow->windowToggleNoteEditor(); + mainWindow->windowShowNoteEditor(); else if (sysFlagName == "hideInExport") model->toggleHideExport(); else if (sysFlagName.startsWith("system-task-")) @@ -2217,7 +2236,7 @@ void MapEditor::moveObject(QMouseEvent *e, const QPointF &p_event) // When temporary linking e.g. to MapCenter, position on a circle // bigger than ornamensContainer - qreal radius = 100 + targetBranchContainer->ornamentsRect().width(); + qreal radius = 100 + targetBranchContainer->ornamentsSceneRect().width(); QPointF center_sp = targetBranchContainer->getHeadingContainer()->mapToScene(QPointF(0,0)); qreal a = getAngle(p_event - center_sp); @@ -2620,9 +2639,16 @@ void MapEditor::wheelEvent(QWheelEvent *e) } } -void MapEditor::focusOutEvent(QFocusEvent *) +void MapEditor::focusInEvent(QFocusEvent *e) +{ + //qDebug() << "ME::focusInEvent" << e->reason(); + setFrameStyle(QFrame::Box); +} + +void MapEditor::focusOutEvent(QFocusEvent *e) { - // qDebug()<<"ME::focusOutEvent"<reason(); + //qDebug() << "ME::focusOutEvent" << e->reason(); + setFrameStyle(QFrame::NoFrame); if (editorState == EditingHeading) editHeadingFinished(); } @@ -2812,44 +2838,35 @@ MapEditor::SelectionMode MapEditor::currentSelectionMode(TreeItem *selti) // Selections should consider logical relations, e.g. siblings and parents // but also geometric. Return the most appropriate mode depending on // rotation of view and layout of selected item. - if (!selti) { - // qDebug() << "ME::selectionMode: Classic"; - return ClassicSelection; - } - - if (rotationInt != 0) { - // qDebug() << "ME::selectionMode: Geometric"; - return GeometricSelection; - } - Container *c = nullptr; - if (selti->hasTypeBranch()) { - BranchContainer *bc = ((BranchItem*)selti)->getBranchContainer(); - if (bc->branchesContainerLayout() == Container::Horizontal) { - // qDebug() << "ME::selectionMode: OrgChart"; - return OrgChartSelection; - } - if (bc->isFloating()) { - // qDebug() << "ME::selectionMode: Geometric"; - return GeometricSelection; - } - } else if (selti->hasTypeImage()) { - // qDebug() << "ME::selectionMode: Geometric"; - return GeometricSelection; - } + SelectionMode sm = HirarchicalSelection; + if (selti) { - if (!c) { - // qDebug() << "ME::selectionMode: Classic"; - return ClassicSelection; - } + if (rotationInt != 0) { + // qDebug() << "ME::selectionMode: rotated"; + sm = GeometricSelection; + } else { + if (selti->hasTypeBranch()) { + BranchContainer *bc = ((BranchItem*)selti)->getBranchContainer(); + if (bc->branchesContainerLayout() == Container::Horizontal) { + // qDebug() << "ME::selectionMode: OrgChart"; + sm = OrgChartSelection; + } else if (bc->isFloating()) { + // qDebug() << "ME::selectionMode: Geometric"; + sm = GeometricSelection; + } - if (c->isFloating()) { - // qDebug() << "ME::selectionMode: Geometric"; - return GeometricSelection; - } + // Missing: !Horizontal and !floating + } else if (selti->hasTypeImage()) { + // qDebug() << "ME::selectionMode: Geometric"; + sm = GeometricSelection; + } + } // view not rotated + } // selti != nullptr - qDebug() << "ME::selectionMode: Classic"; - return ClassicSelection; + if (debug) + qDebug() << "ME::currentSelectionMode: " << sm; + return sm; } void MapEditor::updateData(const QModelIndex &sel) diff --git a/src/mapeditor.h b/src/mapeditor.h index 24f8bfc..a94f786 100644 --- a/src/mapeditor.h +++ b/src/mapeditor.h @@ -177,7 +177,7 @@ class MapEditor : public QGraphicsView { TreeItem* getItemInDirection(TreeItem *ti, RadarDirection); TreeItem* getItemFromGeometry(TreeItem *ti, RadarDirection); TreeItem* getItemFromOrgChart(TreeItem *ti, RadarDirection); - TreeItem* getItemFromClassicMap(TreeItem *ti, RadarDirection); + TreeItem* getItemFromHirarchy(TreeItem *ti, RadarDirection); TreeItem* getItemDirectAbove(TreeItem *ti); TreeItem* getItemDirectBelow( TreeItem *ti); @@ -195,13 +195,15 @@ class MapEditor : public QGraphicsView { void cursorDownToggleSelection(); void cursorLeft(); void cursorRight(); - void cursorFirst(); - void cursorLast(); void editHeading(BranchItem *selbi = nullptr); + void editHeadingCanceled(); void editHeadingFinished(); private: + void hideLineEdit(); QLineEdit *lineEdit; + QAction *editHeadingCancelAction; + QGraphicsProxyWidget *proxyWidget; private: void contextMenuEvent(QContextMenuEvent *e); @@ -214,6 +216,7 @@ class MapEditor : public QGraphicsView { void mouseReleaseEvent(QMouseEvent *); void mouseDoubleClickEvent(QMouseEvent *); void wheelEvent(QWheelEvent *); + void focusInEvent(QFocusEvent *); void focusOutEvent(QFocusEvent *); void resizeEvent(QResizeEvent *); @@ -269,7 +272,7 @@ class MapEditor : public QGraphicsView { public: enum SelectionMode { AutoSelection, - ClassicSelection, + HirarchicalSelection, // legacy selection type (default) OrgChartSelection, GeometricSelection }; diff --git a/src/misc.cpp b/src/misc.cpp index 07e65da..cc229ad 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -247,6 +247,14 @@ bool versionLowerThanVym(const QString &v) return versionLowerOrEqualThanVym(v); } +QString underline(const QString &text, const QString &line) +{ + QString r = text + "\n"; + for (int j = 0; j < text.length(); j++) + r += line; + return r + "\n\n"; +} + bool versionLowerOrEqualThanVym(const QString &v) { // returns true, if Version v <= VYM_VERSION diff --git a/src/misc.h b/src/misc.h index e2c15b5..c22dbe1 100644 --- a/src/misc.h +++ b/src/misc.h @@ -42,6 +42,8 @@ QString pointToString(const QPointF &p); void centerDialog(QDialog *dia); +QString underline(const QString &text, const QString &line); + bool versionLowerThanVym(const QString &); bool versionLowerOrEqualThanVym(const QString &); bool versionLowerOrEqual(const QString &, const QString &); diff --git a/src/noteeditor.cpp b/src/noteeditor.cpp index b4f070f..4b9318c 100644 --- a/src/noteeditor.cpp +++ b/src/noteeditor.cpp @@ -10,6 +10,8 @@ extern QString vymName; NoteEditor::NoteEditor(const QString &eName) : TextEditor(eName) { + editorName = eName; + setWindowTitle(""); menuBar()->show(); diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp index 63f5d94..45a6151 100644 --- a/src/shortcuts.cpp +++ b/src/shortcuts.cpp @@ -5,18 +5,20 @@ #include "shortcuts.h" +#include "misc.h" + ///////////////////////////////////////////////////////////////// // KeySwitch ///////////////////////////////////////////////////////////////// -KeySwitch::KeySwitch(const QString &kIdentifier, const QString &kName, - const QString &kGroup, const QString &kTag, - const QKeySequence &kseq) +KeySwitch::KeySwitch(const QString &identifier, + const QString &scope, + const QString &tag, + QAction* action) { - identifier = kIdentifier; - name = kName; - group = kGroup; - tag = kTag; - keySequence = kseq; + identifierInt = identifier; + scopeInt = scope; + tagInt = tag; + actionInt = action; } ///////////////////////////////////////////////////////////////// @@ -24,64 +26,85 @@ KeySwitch::KeySwitch(const QString &kIdentifier, const QString &kName, ///////////////////////////////////////////////////////////////// Switchboard::Switchboard() {} -void Switchboard::addGroup(QString gIdentifier, QString gName) +void Switchboard::addScope(QString scopeIdentifier, QString scopeName) { - if (groups.contains(gIdentifier)) { - qDebug() << "Warning switchboard: Shortcut group " << gIdentifier + if (scopesMap.contains(scopeIdentifier)) { + qDebug() << "Warning switchboard: Shortcut scope " << scopeIdentifier << " already exists"; return; } - groups.insert(gIdentifier, gName); + scopesMap.insert(scopeIdentifier, scopeName); } -void Switchboard::addSwitch(QString identifier, QString scope, QAction *action, - QString tag) +void Switchboard::addAction(QAction *action, + const QString &identifier, + const QString &scope, + const QString &tag) { - if (!switches.contains(identifier)) { - KeySwitch ksw(identifier, action->text(), scope, tag, - action->shortcut()); - switches.insert(scope, ksw); + addAction(action, identifier, QKeySequence(), scope, tag); +} + +void Switchboard::addAction(QAction *action, + const QString &identifier, + QKeySequence ks, + const QString &scope, + const QString &tag) +{ + action->setShortcut(ks); + action->setShortcutVisibleInContextMenu(true); // FIXME-3 should obsolete setting in MainWindow::setupContextMenus() + + if (!switchesMap.contains(identifier)) { + if (!action->shortcut().toString().isEmpty()) { + // Add shortcut to tooltip + action->setToolTip(action->toolTip() + + QString(" (%1)").arg(action->shortcut().toString())); + } + KeySwitch ksw(identifier, scope, tag, action); + switchesMap.insert(scope, ksw); } else qDebug() - << "Warning switchboard::addSwitch warning: Existing idenifier " + << "Warning switchboard::addAction warning: Existing idenifier " << identifier; } + QString Switchboard::getASCII() { QString s; - QString g; - foreach (g, switches.uniqueKeys()) { - s += "Scope " + g + ":\n"; - QList values = switches.values(g); - for (int i = 0; i < values.size(); ++i) { - QString desc = values.at(i).name; - QString sc = values.at(i).keySequence.toString(); - if (!sc.isEmpty()) { - desc = desc.remove('&'); - desc = desc.remove("..."); - s += QString(" %1: %2\n").arg(sc, 12).arg(desc); - } + QString scope; + foreach (scope, switchesMap.uniqueKeys()) { + s += underline(scope, "="); + + QStringList tagsInScope; + foreach (auto ksw, switchesMap.values(scope)) { + if (!tagsInScope.contains(ksw.tagInt)) + tagsInScope << ksw.tagInt; } - s += "\n"; - } - /* - foreach (g, actions.uniqueKeys()) - { - s += g +"\n"; - QList values=actions.values(g); - for (int i=0;itext(); - QString sc=values.at(i)->shortcut().toString(); - desc=desc.remove('&'); - desc=desc.remove("..."); - s+= QString(" %1: %2\n").arg(sc,12).arg(desc); + foreach (auto tag, tagsInScope) { + s += underline(tag, "-"); + foreach (auto ksw, switchesMap.values(scope)) { + if (ksw.tagInt == tag) { + QString desc = ksw.actionInt->text(); + QString sc = ksw.actionInt->shortcut().toString(); + if (!sc.isEmpty()) { +#if defined(Q_OS_MACOS) + sc.replace("Ctrl","Cmd"); +#endif + + desc = desc.remove('&'); + desc = desc.remove("..."); + s += QString(" %1: %2\n").arg(sc, 12).arg(desc); + } + } + } + if (tag != tagsInScope.last()) + s += "\n"; } + if (scope != switchesMap.uniqueKeys().last()) + s += "\n"; } - */ return s; } @@ -89,10 +112,11 @@ void Switchboard::printASCII() { std::cout << qPrintable(getASCII()); } void Switchboard::printLaTeX() { + /* QString g; - foreach (g, actions.uniqueKeys()) { + foreach (g, actionsMap.uniqueKeys()) { std::cout << "Group: " << qPrintable(g) << "\\\\ \\hline" << std::endl; - QList values = actions.values(g); + QList values = actionsMap.values(g); for (int i = 0; i < values.size(); ++i) if (!values.at(i)->shortcut().toString().isEmpty()) { QString desc = values.at(i)->text(); @@ -104,4 +128,5 @@ void Switchboard::printLaTeX() } std::cout << std::endl; } + */ } diff --git a/src/shortcuts.h b/src/shortcuts.h index 32f9d0d..c10b2ac 100644 --- a/src/shortcuts.h +++ b/src/shortcuts.h @@ -8,32 +8,31 @@ class KeySwitch { public: KeySwitch( - const QString &kIdentifier, //! Unique identifier (still unused) - const QString &kName, //! text saved in related action (translated) - const QString &kGroup, //! Scope - const QString &kTag, //! Tag, used for listing related shortcuts - const QKeySequence &kseq); //! Keysequence from action - QString group; - QString name; - QString identifier; - QString tag; + const QString &identifier, //! Unique identifier (still unused) + const QString &scope, //! Scope + const QString &tag, //! Tag, used for listing related shortcuts + QAction* action); //! Action + QString scopeInt; + QString nameInt; + QString identifierInt; + QString tagInt; QKeySequence keySequence; + QAction *actionInt; }; class Switchboard { public: Switchboard(); - void addGroup(QString gIdentifier, QString gName); - void addSwitch(QString identifier, QString scope, QAction *a, QString tag); + void addScope(QString gIdentifier, QString gName); + void addAction(QAction *a, const QString &identifier, const QString &scope, const QString &tag); + void addAction(QAction *a, const QString &identifier, QKeySequence, const QString &scope, const QString &tag); QString getASCII(); void printASCII(); void printLaTeX(); protected: - QMultiMap actions; - QMultiMap switches; - QMap groups; - QStringList tags; + QMultiMap switchesMap; // Switches grouped by scope + QMap scopesMap; // Hash with translated names of scopes }; #endif diff --git a/src/slideeditor.cpp b/src/slideeditor.cpp index f6798ce..c761b84 100644 --- a/src/slideeditor.cpp +++ b/src/slideeditor.cpp @@ -12,7 +12,7 @@ extern Main *mainWindow; extern SlideEditor *slideEditor; -extern QString editorFocusStyle; +extern QString editorFocusInStyle; SlideEditor::SlideEditor(VymModel *m) { @@ -27,7 +27,7 @@ SlideEditor::SlideEditor(VymModel *m) slideModel->setSelectionModel(view->selectionModel()); - view->setStyleSheet("QTreeView:focus {" + editorFocusStyle + "}"); + view->setStyleSheet("QTreeView:focus {" + editorFocusInStyle + "}"); // Create ControlWidget slideControl = new SlideControlWidget(this); @@ -58,11 +58,28 @@ SlideEditor::SlideEditor(VymModel *m) SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateSelection(QItemSelection, QItemSelection))); + QAction *a = new QAction(this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + a->setShortcut(Qt::CTRL | Qt::Key_D); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(closeWindow())); + + a = new QAction(this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + a->setShortcut(Qt::Key_Escape); + addAction(a); + connect(a, SIGNAL(triggered()), mainWindow, SLOT(escapePressed())); + // connect (resultsModel, SIGNAL(layoutChanged() ), view, SLOT // (expandAll() )); } void SlideEditor::closeEvent(QCloseEvent *event) +{ + closeWindow(); +} + +void SlideEditor::closeWindow() { mainWindow->windowSetSlideEditorsVisibility(false); } diff --git a/src/slideeditor.h b/src/slideeditor.h index 110ce03..c8e87e6 100644 --- a/src/slideeditor.h +++ b/src/slideeditor.h @@ -19,6 +19,7 @@ class SlideEditor : public QWidget { virtual void closeEvent(QCloseEvent *event); public slots: + void closeWindow(); void previousSlide(); void nextSlide(); void addSlide(); diff --git a/src/task.cpp b/src/task.cpp index 18b1caa..f905186 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -6,6 +6,8 @@ #include "taskmodel.h" #include "vymmodel.h" +extern QString flagsPath; + Task::Task(TaskModel *tm) { // qDebug()<<"Constr. Task"; @@ -82,7 +84,7 @@ QString Task::getStatusString() return "Undefined"; } -QString Task::getIconString() +QString Task::iconString() { QString s; switch (status) { diff --git a/src/task.h b/src/task.h index 49e4184..f7c16f1 100644 --- a/src/task.h +++ b/src/task.h @@ -24,8 +24,7 @@ class Task : public XMLObj { void setStatus(Status ts); Status getStatus(); QString getStatusString(); - QString - getIconString(); //! Used to create icons in task list and flags in mapview + QString iconString(); //! Used to create icons in task list and flags in mapview void setAwake(const QString &s); void setAwake(Awake a); Awake getAwake(); diff --git a/src/taskeditor.cpp b/src/taskeditor.cpp index 1e4cc8e..4d30d31 100644 --- a/src/taskeditor.cpp +++ b/src/taskeditor.cpp @@ -24,7 +24,7 @@ extern Settings settings; extern QMenu *taskContextMenu; extern TaskModel *taskModel; -extern QString editorFocusStyle; +extern QString editorFocusInStyle; TaskEditor::TaskEditor(QWidget *) { @@ -188,7 +188,8 @@ TaskEditor::TaskEditor(QWidget *) view->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); - view->setStyleSheet("QTableView:focus {" + editorFocusStyle + "}"); + QString selected = "QTableView::item:selected {border-color: #00ff00; border-width: 3px; background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #CCCC0A, stop: 1 #96960A);}"; + view->setStyleSheet("QTableView:focus {" + editorFocusInStyle + "}" + selected); updateColumnLayout(); } @@ -424,12 +425,6 @@ void TaskEditor::selectionChanged(const QItemSelection &selected, m->select(bi); if (m != mainWindow->currentModel()) mainWindow->gotoModel(m); - /* view->setStyleSheet( // FIXME-5 this resets column widths on Windows... - "QTableView {selection-background-color: " + - m->getSelectionBrushColor().name() + - "; selection-color:" + bi->headingColor().name() + "}" + - "QTableView:focus {" + editorFocusStyle + "}"); - */ } } } diff --git a/src/taskmodel.cpp b/src/taskmodel.cpp index 0f2bfc8..c5b6b9f 100644 --- a/src/taskmodel.cpp +++ b/src/taskmodel.cpp @@ -133,7 +133,7 @@ QVariant TaskModel::data(const QModelIndex &index, int role) const } } else if (role == Qt::DecorationRole && index.column() == 2) { - QString s = t->getIconString(); + QString s = t->iconString(); if (s == "task-new") return task_new_icon; else if (s == "task-new-morning") diff --git a/src/texteditor.cpp b/src/texteditor.cpp index bfa2aa4..196be31 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -30,6 +30,10 @@ extern QColor vymForegroundColor; extern QColor vymBaseColor; extern QAction *actionViewToggleNoteEditor; +extern QString editorFocusInStyle; +extern QString editorFocusOutStyle; +extern QString toolBarStyle; + extern QString vymName; extern Switchboard switchboard; @@ -57,6 +61,14 @@ TextEditor::TextEditor(const QString eName) // FEATURE #137 insert images with connect(editor, SIGNAL(currentCharFormatChanged(const QTextCharFormat &)), this, SLOT(formatChanged(const QTextCharFormat &))); + + QAction *a = new QAction("Close window", this); + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + a->setShortcut(Qt::CTRL | Qt::Key_D); + connect(a, SIGNAL(triggered()), this, SLOT(closeWindow())); + //fileMenu->addAction(a); + editor->addAction(a); + // Load settings init (eName); setWindowIcon(QPixmap(":/vym-editor.png")); @@ -318,15 +330,15 @@ void TextEditor::setFocus() { editor->setFocus(); } void TextEditor::setupFileActions() { QToolBar *tb = addToolBar(tr("Note Actions")); + tb->setStyleSheet(toolBarStyle); tb->setObjectName("noteEditorFileActions"); QMenu *fileMenu = menuBar()->addMenu(tr("&Note", "Menubar")); - QString tag = tr("Texteditor", "Shortcuts"); + QString tag = tr("File actions", "TextEditor shortcut groups"); QAction *a; a = new QAction(QPixmap(QString(":/document-open-%1").arg(iconTheme)), tr("&Import..."), this); - a->setShortcut(Qt::CTRL | Qt::Key_O); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textLoad", shortcutScope, a, tag); + switchboard.addAction(a, "textLoad", Qt::CTRL | Qt::Key_O, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textLoad())); tb->addAction(a); fileMenu->addAction(a); @@ -334,9 +346,8 @@ void TextEditor::setupFileActions() fileMenu->addSeparator(); a = new QAction(QPixmap(QString(":/document-export-%1").arg(iconTheme)), tr("&Export..."), this); - a->setShortcut(Qt::CTRL | Qt::Key_S); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textSave", shortcutScope, a, tag); + switchboard.addAction(a, "textSave", Qt::CTRL | Qt::Key_S, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textExport())); tb->addAction(a); fileMenu->addAction(a); @@ -345,7 +356,7 @@ void TextEditor::setupFileActions() actionFileExport = a; a = new QAction(tr("Export &As...(ASCII)"), this); - switchboard.addSwitch("textExportAsASCII", shortcutScope, a, tag); + switchboard.addAction(a, "textExportAsASCII", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textExportText())); fileMenu->addAction(a); addAction(a); @@ -354,8 +365,7 @@ void TextEditor::setupFileActions() fileMenu->addSeparator(); a = new QAction(QPixmap(QString(":/document-print-%1.svg").arg(iconTheme)), tr("&Print..."), this); - a->setShortcut(Qt::CTRL | Qt::Key_P); - switchboard.addSwitch("textPrint", shortcutScope, a, tag); + switchboard.addAction(a, "textPrint", Qt::CTRL | Qt::Key_P, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textPrint())); tb->addAction(a); fileMenu->addAction(a); @@ -372,17 +382,17 @@ void TextEditor::setupFileActions() void TextEditor::setupEditActions() { - QString tag = tr("Texteditor", "Shortcuts"); + QString tag = tr("Edit actions", "TextEditor shortcut groups"); QToolBar *editToolBar = addToolBar(tr("Edit Actions")); + editToolBar->setStyleSheet(toolBarStyle); editToolBar->setObjectName("noteEditorEditActions"); editToolBar->hide(); QMenu *editMenu = menuBar()->addMenu(tr("Edi&t")); QAction *a; a = new QAction(QPixmap(":/undo.png"), tr("&Undo"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Z); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textUndo", shortcutScope, a, tag); + switchboard.addAction(a, "textUndo", Qt::CTRL | Qt::Key_Z, shortcutScope, tag); connect(a, SIGNAL(triggered()), editor, SLOT(undo())); editMenu->addAction(a); editToolBar->addAction(a); @@ -390,9 +400,8 @@ void TextEditor::setupEditActions() actionEditUndo = a; a = new QAction(QPixmap(":/redo.png"), tr("&Redo"), this); - a->setShortcut(Qt::CTRL | Qt::Key_Y); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textRedo", shortcutScope, a, tag); + switchboard.addAction(a, "textRedo", Qt::CTRL | Qt::Key_Y, shortcutScope, tag); connect(a, SIGNAL(triggered()), editor, SLOT(redo())); editMenu->addAction(a); editToolBar->addAction(a); @@ -402,8 +411,7 @@ void TextEditor::setupEditActions() editMenu->addSeparator(); a = new QAction(QPixmap(), tr("Select and copy &all"), this); a->setShortcutContext(Qt::WidgetShortcut); - a->setShortcut(Qt::CTRL | Qt::Key_A); - switchboard.addSwitch("textCopyAll", shortcutScope, a, tag); + switchboard.addAction(a, "textCopyAll", Qt::CTRL | Qt::Key_A, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editCopyAll())); editMenu->addAction(a); filledEditorActions << a; @@ -411,9 +419,8 @@ void TextEditor::setupEditActions() editMenu->addSeparator(); a = new QAction(QPixmap(QString(":/edit-copy-%1.svg").arg(iconTheme)), tr("&Copy", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_C); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textCopy", shortcutScope, a, tag); + switchboard.addAction(a, "textCopy", Qt::CTRL | Qt::Key_C, shortcutScope, tag); connect(a, SIGNAL(triggered()), editor, SLOT(copy())); editMenu->addAction(a); editToolBar->addAction(a); @@ -421,9 +428,8 @@ void TextEditor::setupEditActions() actionEditCopy = a; a = new QAction(QPixmap(QString(":/edit-cut-%1.svg").arg(iconTheme)), tr("Cu&t", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_X); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textCut", shortcutScope, a, tag); + switchboard.addAction(a, "textCut", Qt::CTRL | Qt::Key_X, shortcutScope, tag); connect(a, SIGNAL(triggered()), editor, SLOT(cut())); editMenu->addAction(a); editToolBar->addAction(a); @@ -431,9 +437,8 @@ void TextEditor::setupEditActions() actionEditCut = a; a = new QAction(QPixmap(QString(":/edit-paste-%1.svg").arg(iconTheme)), tr("&Paste", "Edit menu"), this); - a->setShortcut(Qt::CTRL | Qt::Key_V); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textPaste", shortcutScope, a, tag); + switchboard.addAction(a, "textPaste", Qt::CTRL | Qt::Key_V, shortcutScope, tag); connect(a, SIGNAL(triggered()), editor, SLOT(paste())); editMenu->addAction(a); editToolBar->addAction(a); @@ -451,20 +456,20 @@ void TextEditor::setupEditActions() void TextEditor::setupFormatActions() { - QString tag = tr("Texteditor", "Shortcuts"); + QString tag = tr("Format actions", "TextEditor shortcut groups"); fontHintsToolBar = addToolBar(tr("Font hints", "toolbar in texteditor")); + fontHintsToolBar->setStyleSheet(toolBarStyle); fontHintsToolBar->setObjectName("noteEditorFontToolBar"); QMenu *formatMenu = menuBar()->addMenu(tr("F&ormat")); QAction *a; a = new QAction(QPixmap(":/formatfixedfont.png"), tr("&Font hint"), this); - a->setShortcut(Qt::CTRL | Qt::Key_H); a->setCheckable(true); a->setChecked( settings.value("/noteeditor/fonts/useFixedByDefault", false).toBool()); - switchboard.addSwitch("textToggleFonthint", shortcutScope, a, tag); + switchboard.addAction(a, "textToggleFonthint", Qt::CTRL | Qt::Key_H, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(toggleFonthint())); formatMenu->addAction(a); fontHintsToolBar->addAction(a); @@ -473,10 +478,8 @@ void TextEditor::setupFormatActions() // Original icon: ./share/icons/oxygen/22x22/actions/format-text-color.png a = new QAction(QPixmap(":/formatrichtext.svg"), tr("&Richtext"), this); - // a->setShortcut(Qt::CTRL | Qt::Key_R); - // a->setShortcutContext (Qt::WidgetShortcut); a->setCheckable(true); - switchboard.addSwitch("textToggleRichText", shortcutScope, a, tag); + switchboard.addAction(a, "textToggleRichText", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(toggleRichText())); formatMenu->addAction(a); fontHintsToolBar->addAction(a); @@ -486,6 +489,7 @@ void TextEditor::setupFormatActions() addToolBarBreak(); fontToolBar = addToolBar(tr("Fonts", "toolbar in texteditor")); + fontToolBar->setStyleSheet(toolBarStyle); fontToolBar->setObjectName("noteEditorFontToolBar"); comboFont = new QComboBox; @@ -512,6 +516,7 @@ void TextEditor::setupFormatActions() addToolBarBreak(); formatToolBar = addToolBar(tr("Format", "toolbar in texteditor")); + formatToolBar->setStyleSheet(toolBarStyle); formatToolBar->setObjectName("noteEditorFormatToolBar"); //QPixmap pix(16, 16); @@ -534,9 +539,8 @@ void TextEditor::setupFormatActions() actionTextBGColor = a; a = new QAction(QPixmap(QString(":/format-text-bold-%1.svg").arg(iconTheme)), tr("&Bold"), this); - a->setShortcut(Qt::CTRL | Qt::Key_B); // a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textToggleBold", shortcutScope, a, tag); + switchboard.addAction(a, "textToggleBold", Qt::CTRL | Qt::Key_B, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textBold())); formatToolBar->addAction(a); formatMenu->addAction(a); @@ -545,9 +549,8 @@ void TextEditor::setupFormatActions() actionTextBold = a; a = new QAction(QPixmap(QString(":/format-text-italic-%1.svg").arg(iconTheme)), tr("&Italic"), this); - a->setShortcut(Qt::CTRL | Qt::Key_I); // a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textToggleItalic", shortcutScope, a, tag); + switchboard.addAction(a, "textToggleItalic", Qt::CTRL | Qt::Key_I, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textItalic())); formatToolBar->addAction(a); formatMenu->addAction(a); @@ -556,9 +559,8 @@ void TextEditor::setupFormatActions() actionTextItalic = a; a = new QAction(QPixmap(QString(":/text-format-underline-%1.svg").arg(iconTheme)), tr("&Underline"), this); - a->setShortcut(Qt::CTRL | Qt::Key_U); // a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addSwitch("textToggleUnderline", shortcutScope, a, tag); + switchboard.addAction(a, "textToggleUnderline", Qt::CTRL | Qt::Key_U, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textUnderline())); formatToolBar->addAction(a); formatMenu->addAction(a); @@ -571,23 +573,19 @@ void TextEditor::setupFormatActions() QActionGroup *actGrp2 = new QActionGroup(this); actGrp2->setExclusive(true); a = new QAction(QPixmap(QString(":/text-format-subscript-%1.svg").arg(iconTheme)), tr("Subs&cript"), actGrp2); - a->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_B); -// a->setShortcutContext(Qt::WidgetWithChildrenShortcut); a->setCheckable(true); formatToolBar->addAction(a); formatMenu->addAction(a); - switchboard.addSwitch("textToggleSub", shortcutScope, a, tag); + switchboard.addAction(a, "textToggleSub", Qt::CTRL | Qt::SHIFT | Qt::Key_B, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textVAlign())); filledEditorRichTextActions << a; actionAlignSubScript = a; a = new QAction(QPixmap(QString(":/text-format-superscript-%1.svg").arg(iconTheme)), tr("Su&perscript"), actGrp2); - a->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_P); -// a->setShortcutContext(Qt::WidgetWithChildrenShortcut); a->setCheckable(true); formatToolBar->addAction(a); formatMenu->addAction(a); - switchboard.addSwitch("textToggleSuper", shortcutScope, a, tag); + switchboard.addAction(a, "textToggleSuper", Qt::CTRL | Qt::SHIFT | Qt::Key_P, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(textVAlign())); filledEditorRichTextActions << a; actionAlignSuperScript = a; @@ -709,14 +707,22 @@ void TextEditor::textLoad() void TextEditor::closeEvent(QCloseEvent *ce) { ce->accept(); // TextEditor can be reopened with show() - hide(); - emit windowClosed(); - return; + closeWindow(); } bool TextEditor::eventFilter(QObject *obj, QEvent *ev) { if (obj == editor) { + // qDebug() << "TE::eventFilter ev=" << ev; + if (ev->type() == QEvent::FocusIn) { + //editor->setFrameStyle(QFrame::Box); + editor->setStyleSheet("QTextEdit {" + editorFocusInStyle + "}"); + } + if (ev->type() == QEvent::FocusOut) { + editor->setFrameStyle(QFrame::NoFrame); + editor->setStyleSheet("QTextEdit {" + editorFocusOutStyle + "}"); + + } if (ev->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(ev); if (keyEvent == QKeySequence::Paste) { @@ -839,6 +845,13 @@ void TextEditor::clear() blockChangedSignal = blockChangedOrg; } +void TextEditor::closeWindow() +{ + parentWidget()->hide(); + emit windowClosed(); + return; +} + void TextEditor::deleteAll() { editor->clear(); diff --git a/src/texteditor.h b/src/texteditor.h index 0c13457..9ef3d50 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -55,6 +55,7 @@ class TextEditor : public QMainWindow { void setInactive(); // Nothing can be entered void editCopyAll(); void clear(); + void closeWindow(); protected slots: void deleteAll(); diff --git a/src/treeeditor.cpp b/src/treeeditor.cpp index d8bc48d..79a4751 100644 --- a/src/treeeditor.cpp +++ b/src/treeeditor.cpp @@ -10,7 +10,6 @@ #include "vymmodel.h" extern Main *mainWindow; -extern QString editorFocusStyle; extern QMenu *branchContextMenu; extern QMenu *canvasContextMenu; @@ -63,6 +62,12 @@ void TreeEditor::init() addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(startEdit())); + a = new QAction(this); + a->setShortcutContext(Qt::WidgetShortcut); + a->setShortcut(Qt::CTRL | Qt::Key_D); + addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(closeWindow())); + // Clone actions defined in MainWindow // FIXME-3 PageUp/Down not working in TreeEditor foreach (QAction *qa, mainWindow->mapEditorActions) { a = new QAction(this); @@ -71,8 +76,6 @@ void TreeEditor::init() connect(a, SIGNAL(triggered()), qa, SLOT(trigger())); addAction(a); } - - setStyleSheet("QTreeView:focus {" + editorFocusStyle + "}"); } TreeEditor::~TreeEditor() @@ -104,6 +107,12 @@ void TreeEditor::contextMenuEvent(QContextMenuEvent *e) { void TreeEditor::closeEvent(QCloseEvent *event) { + closeWindow(); +} + +void TreeEditor::closeWindow() +{ + // Close *all* TreeEditors in each VymView and update vym settings mainWindow->windowSetTreeEditorsVisibility(false); } diff --git a/src/treeeditor.h b/src/treeeditor.h index 73b4c7e..9f38a8e 100644 --- a/src/treeeditor.h +++ b/src/treeeditor.h @@ -21,6 +21,9 @@ class TreeEditor : public QTreeView { virtual void contextMenuEvent(QContextMenuEvent *e); virtual void closeEvent(QCloseEvent *event); + public slots: + void closeWindow(); + private slots: void cursorUp(); void cursorDown(); diff --git a/src/treeitem.cpp b/src/treeitem.cpp index e885a6d..b62f5a5 100644 --- a/src/treeitem.cpp +++ b/src/treeitem.cpp @@ -395,9 +395,9 @@ void TreeItem::setUrl(const QString &u) { urlInt = u; if (!urlInt.isEmpty()) - systemFlags.activate(QString("system-url")); + setUrlType(UrlType::GeneralUrl); else - systemFlags.deactivate(QString("system-url")); + setUrlType(UrlType::NoUrl); } QString TreeItem::url() { return urlInt; } @@ -407,6 +407,16 @@ bool TreeItem::hasUrl() { return !urlInt.isEmpty();} void TreeItem::setUrlType(UrlType ut) { urlTypeInt = ut; + if (urlTypeInt == TreeItem::JiraUrl) { + systemFlags.activate("system-jira"); + systemFlags.deactivate("system-url"); + } else { + systemFlags.deactivate("system-jira"); + if (urlTypeInt == TreeItem::GeneralUrl) + systemFlags.activate("system-url"); + else + systemFlags.deactivate("system-url"); + } } TreeItem::UrlType TreeItem::urlType() @@ -414,6 +424,20 @@ TreeItem::UrlType TreeItem::urlType() return urlTypeInt; } +Flag* TreeItem::urlFlag() +{ + if (!hasUrl()) + return nullptr; + + if (urlTypeInt == UrlType::GeneralUrl) + return systemFlagsMaster->findFlagByName("system-url"); + + if (urlTypeInt == UrlType::JiraUrl) + return systemFlagsMaster->findFlagByName("system-jira"); + + return nullptr; +} + void TreeItem::setVymLink(const QString &vl) { if (!vl.isEmpty()) { @@ -444,6 +468,11 @@ QString TreeItem::vymLink() { return vymLinkInt; } bool TreeItem::hasVymLink() { return !vymLinkInt.isEmpty();} +bool TreeItem::hasReference() +{ + return (xlinkCounter > 0) || hasUrl() || hasVymLink(); +} + void TreeItem::toggleTarget() { systemFlags.toggle(QString("system-target")); diff --git a/src/treeitem.h b/src/treeitem.h index 5072248..bf5dbaf 100644 --- a/src/treeitem.h +++ b/src/treeitem.h @@ -111,6 +111,7 @@ class TreeItem : public XMLObj { bool hasUrl(); void setUrlType(UrlType); UrlType urlType(); + Flag *urlFlag(); protected: QString vymLinkInt; @@ -119,6 +120,7 @@ class TreeItem : public XMLObj { void setVymLink(const QString &s); //! Set vymLink QString vymLink(); //! Get vymLink bool hasVymLink(); + bool hasReference(); //! True if vymLink, XLink, or Url are availalble protected: bool target; diff --git a/src/version.h b/src/version.h index c7f56e2..187f027 100644 --- a/src/version.h +++ b/src/version.h @@ -1,8 +1,8 @@ #ifndef VERSION_H #define VERSION_H -#define __VYM_VERSION "2.9.588" -#define __VYM_BUILD_DATE "2025-08-07" +#define __VYM_VERSION "2.9.598" +#define __VYM_BUILD_DATE "2025-09-25" #define __VYM_NAME "VYMng" // FIXME "next generation" in in window title #define __VYM_HOME "http://www.insilmaril.de/vym" diff --git a/src/vym-wrapper.cpp b/src/vym-wrapper.cpp index a7bf6d7..ce99df6 100644 --- a/src/vym-wrapper.cpp +++ b/src/vym-wrapper.cpp @@ -64,6 +64,17 @@ QObject *VymWrapper::currentMap() return mw; } +QObject *VymWrapper::mapWithId(uint n) +{ + VymModel *m = mainWindow->getModel(n); + if (!m) { + mainWindow->abortScript( + QJSValue::ReferenceError, + QString("No model available with id=%1").arg(n)); + } + return (QObject*)(m->getWrapper()); +} + void VymWrapper::editHeading() { MapEditor *me = mainWindow->currentMapEditor(); @@ -82,6 +93,11 @@ bool VymWrapper::directoryExists(const QString &directoryName) return d.exists(); } +void VymWrapper::exit() +{ + mainWindow->setExitAfterScript(true); +} + bool VymWrapper::fileCopy(const QString &srcPath, QString dstPath) { QFile file(srcPath); @@ -218,8 +234,6 @@ uint VymWrapper::currentMapID() return r; } -void VymWrapper::toggleTreeEditor() { mainWindow->windowToggleTreeEditors(); } - void VymWrapper::saveFile( const QString &filename, const QString &s) // FIXME-3 error handling missing (in vymmodel and here) diff --git a/src/vym-wrapper.h b/src/vym-wrapper.h index 46540c6..26fc176 100644 --- a/src/vym-wrapper.h +++ b/src/vym-wrapper.h @@ -9,6 +9,7 @@ class VymModelWrapper; /////////////////////////////////////////////////////////////////////////// class VymWrapper : public QObject { Q_OBJECT + public: VymWrapper(); ~VymWrapper(); @@ -18,10 +19,12 @@ class VymWrapper : public QObject { bool closeMapWithID(uint n); QString currentColor(); Q_INVOKABLE QObject *currentMap(); + Q_INVOKABLE QObject *mapWithId(uint n); uint currentMapID(); void editHeading(); bool directoryIsEmpty(const QString &dirName); bool directoryExists(const QString &dirName); + void exit(); bool fileCopy(const QString &srcPath, QString dstPath); bool fileExists(const QString &fileName); bool fileRemove(const QString &fileName); @@ -38,7 +41,6 @@ class VymWrapper : public QObject { void selectQuickColor(int n); void statusMessage(const QString &s); void saveFile(const QString &filename, const QString &s); - void toggleTreeEditor(); bool usesDarkTheme(); QString version(); QString vymBaseDir(); diff --git a/src/vymmodel.cpp b/src/vymmodel.cpp index 59e0819..41b14bd 100644 --- a/src/vymmodel.cpp +++ b/src/vymmodel.cpp @@ -121,6 +121,7 @@ VymModel::VymModel() VymModel::~VymModel() { //qDebug() << "Destr VymModel begin this=" << this << " " << mapName << "zipAgent=" << zipAgent; + //logInfo("VymModel about to be destroyed", __func__); mapEditor = nullptr; repositionBlocked = true; @@ -128,28 +129,6 @@ VymModel::~VymModel() filePath.clear(); fileChangedTimer->stop(); - if (zipAgent) { - mainWindow->statusMessage(tr("Waiting until map is completely saved and compressed...")); - zipAgent->waitForFinished(); - - // zipAgent might be set to nullptr already in VymModel::zipFinished - if (zipAgent) { - if (zipAgent->exitStatus() != QProcess::NormalExit) { - QMessageBox::critical(0, QObject::tr("Critical Error"), - QObject::tr("zip didn't exit normally")); - } - else { - if (zipAgent->exitCode() > 0) { - QMessageBox::critical( - 0, QObject::tr("Critical Error"), - QString("zip exit code: %1").arg(zipAgent->exitCode())); - } - } - zipAgent->deleteLater(); - zipAgent = nullptr; - } - } - vymLock.releaseLock(); // Delete rootItem already now, while VymModel is still around @@ -162,9 +141,10 @@ VymModel::~VymModel() delete (wrapper); delete mapDesignInt; - // qDebug() << "Destr VymModel end this=" << this; + // VymModel can be destroyed now, zipProcess for saving is handled in MainWindow - logInfo("VymModel destroyed", __func__); + //qDebug() << "Destr VymModel end this=" << this; + //logInfo("VymModel destroyed", __func__); } void VymModel::clear() @@ -185,6 +165,7 @@ void VymModel::init() // No ZipAgent yet and not saving zipAgent = nullptr; isSavingInt = false; + isLoadingInt = false; // Use default author authorInt = settings @@ -341,10 +322,12 @@ QString VymModel::saveToDir(const QString &tmpdir, const QString &prefix, mapAttr += xml.attribute("comment", commentInt) + "\n"; mapAttr += xml.attribute("branchCount", QString().number(branchCount())); + if (mapEditor) { mapAttr += xml.attribute("mapZoomFactor", QString().setNum(mapEditor->zoomFactorTarget())); mapAttr += xml.attribute("mapRotation", QString().setNum(mapEditor->rotationTarget())); + } } header += xml.beginElement("vymmap", mapAttr); @@ -528,6 +511,9 @@ bool VymModel::loadMap(QString fname, const File::LoadMode &lmode, return false; } + // No returns now befor end of function + isLoadingInt = true; + QString xmlfile; if (fname.right(4) == ".xml" || fname.right(3) == ".mm") { xmlfile = fname; @@ -628,7 +614,8 @@ bool VymModel::loadMap(QString fname, const File::LoadMode &lmode, bool saveStateBlockedOrg = saveStateBlocked; repositionBlocked = true; saveStateBlocked = true; - mapEditor->setViewportUpdateMode(QGraphicsView::NoViewportUpdate); + if (mapEditor) + mapEditor->setViewportUpdateMode(QGraphicsView::NoViewportUpdate); // We need to set the tmpDir in order to load files with rel. path QString tmpdir; @@ -666,7 +653,8 @@ bool VymModel::loadMap(QString fname, const File::LoadMode &lmode, // Aftermath repositionBlocked = false; saveStateBlocked = saveStateBlockedOrg; - mapEditor->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); + if (mapEditor) + mapEditor->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); if (noError) { if (parsedWell) { @@ -708,7 +696,7 @@ bool VymModel::loadMap(QString fname, const File::LoadMode &lmode, foreach (BranchItem *center, rootItem->getBranches()) { foreach (BranchItem *mainBranch, center->getBranches()) { BranchContainer *bc = mainBranch->getBranchContainer(); - QRectF rb = bc->ornamentsRect(); + QRectF rb = bc->ornamentsSceneRect(); QPointF offset; offset.setX(rb.width() / 2); offset.setY(rb.height() / 2); @@ -737,6 +725,8 @@ bool VymModel::loadMap(QString fname, const File::LoadMode &lmode, } qApp->processEvents(); // Update view (scene()->update() is not enough) + + isLoadingInt = false; return noError; } @@ -917,14 +907,33 @@ bool VymModel::isSaving() return isSavingInt; } +bool VymModel::isLoading() +{ + return isLoadingInt; +} + +bool VymModel::isBusy() +{ + return isLoadingInt || isSavingInt; +} + void VymModel::zipFinished() { // Cleanup - QString log = QString("Finished zipping %1 to %2").arg(zipAgent->zipDir().path(), zipAgent->zipName()); - logInfo(log, __func__); + QString path = "unknown"; + QString name = "unknown"; + if (zipAgent) { + path = zipAgent->zipDir().path(); + name = zipAgent->zipName(); + + QString log = QString("Finished zipping %1 to %2").arg(path, name); + logInfo(log, __func__); + + zipAgent->deleteLater(); + zipAgent = nullptr; + } else + logWarning("zipAgent == nullptr", __func__); - zipAgent->deleteLater(); - zipAgent = nullptr; isSavingInt = false; mainWindow->statusMessage(tr("Saved %1").arg(filePath)); @@ -1536,25 +1545,37 @@ QString VymModel::lastRedoSelection() } QString VymModel::lastRedoCommand() +{ + if (isRedoAvailable()) + return undoSet.value( + QString("/history/step-%1/redoCommand").arg(curStep + 1)); + else + return QString(); +} + +QString VymModel::lastRedoComment() +{ + if (isRedoAvailable()) + return undoSet.value(QString("/history/step-%1/comment").arg(curStep + 1)); + else + return QString(); +} + +QString VymModel::lastUndoCommand() { if (isUndoAvailable()) return undoSet.value( - QString("/history/step-%1/redoCommand").arg(curStep)); + QString("/history/step-%1/undoCommand").arg(curStep)); else return QString(); } -QVariant VymModel::repeatLastCommand() +QString VymModel::lastUndoComment() { - QString command = QString("vym.gotoMap(%1); m = vym.currentMap();").arg(modelIdInt); - QString redoCommand = undoSet.value( - QString("/history/step-%1/redoCommand").arg(curStep)); - if (isUndoAvailable() && !redoCommand.startsWith("model.")) - // Only repeat command, if not a set of commands - command += "m." + redoCommand + ";"; + if (isUndoAvailable()) + return undoSet.value(QString("/history/step-%1/comment").arg(curStep)); else - return false; - return mainWindow->runScript(command); + return QString(); } void VymModel::undo() @@ -1758,36 +1779,6 @@ QString VymModel::saveState( else logInfo("saveState: " + comment + " " + redoCommand, __func__); - // Increase undo steps, but check for repeated actions - // like editing a vymNote - then do not increase but replace last command - // - bool repeatedCommand = false; - - /* FIXME-3 Repeated command not supported yet in saveState - // Undo Scripts start with "model.select" - do not consider these for repeated actions - if (!undoCommand.startsWith("{")) { - if (curStep > 0 && redoSelection == lastRedoSelection()) { - int i = redoCommand.indexOf("("); - QString rcl = redoCommand.left(i-1); - if (i > 0 && rcl == lastRedoCommand().left(i-1)) { - - // Current command is a repeated one. We only want to "squash" some of these - QRegularExpression re(" stepsTotal) - curStep = 1; - } + curStep++; + if (curStep > stepsTotal) + curStep = 1; // We would have to save all actions in a tree, to keep track of // possible redos after an action. Possible, but we are too lazy: forget @@ -1899,6 +1888,11 @@ QString VymModel::saveStateBranch( const QString &comment) { QString prefix = setBranchVar(bi) + "b."; + + QString repeatAction = QString("m = vym.currentMap();"); + repeatAction += " branches = m.selectedBranches(); for (b of branches) {b." + rc + "}"; + mainWindow->setRepeatAction(repeatAction); + return saveState(prefix + uc, prefix + rc, comment); } @@ -1921,7 +1915,7 @@ void VymModel::saveStateEndScript() if (debug) std::cout << "VM::saveStateEndScript" << endl << " buildingScript=" << buildingUndoScript << endl - << " undoScript=" << undoScript.toStdString() << endl; + << " undoScript=" << undoScript.toStdString() << endl; if (buildingUndoScript) { buildingUndoScript = false; @@ -1938,6 +1932,32 @@ void VymModel::saveStateEndScript() } } +void VymModel::saveStateCancelScript() +{ + if (debug) + std::cout << "VM::saveStateCancelScript" << endl + << " buildingScript=" << buildingUndoScript << endl + << " undoScript=" << undoScript.toStdString() << endl; + + if (buildingUndoScript) { + buildingUndoScript = false; + + logDebug("Canceling building saveStateScript: '" + undoScriptComment + "'", __func__); + + // Drop whole Script, if empty + if (undoScript.isEmpty() && redoScript.isEmpty()) return; + + // Prepare undo of actions so far + saveState( + QString("{%1}").arg(undoScript), + QString("{%1}").arg(redoScript), + undoScriptComment, nullptr); + + // Undo + undo(); + } +} + QGraphicsScene *VymModel::getScene() { return mapEditor->getScene(); } TreeItem *VymModel::findBySelectString(QString s) @@ -2644,7 +2664,7 @@ void VymModel::setFrameAutoDesign(const bool &useInnerFrame, const bool &b, Bran logAction(rc, comment, __func__); - saveStateBeginScript(comment); + saveStateBeginScript(comment); // setFrameAD, calls setFrame* functions bc = selbi->getBranchContainer(); bc->setFrameAutoDesign(useInnerFrame, b); @@ -2688,7 +2708,7 @@ void VymModel::setFrameType(const bool &useInnerFrame, const FrameContainer::Fra // Save also penWidth, colors, etc. to restore frame on undo saveCompleteFrame = true; - saveStateBeginScript("Set frame parameters"); + saveStateBeginScript("Set frame parameters"); // setFrameType, calls setFrame* functions QString colorName = bc->framePenColor(useInnerFrame).name(); saveStateBranch(selbi, QString("setFramePenColor (%1, \"%2\");").arg(uif, colorName), @@ -2908,7 +2928,7 @@ void VymModel::setRotationAutoDesign(const bool &b, BranchItem *bi) logAction(rc, comment, __func__); - saveStateBeginScript(comment); + saveStateBeginScript(comment); // setRotationsAD, calls setRotation* functions if (b) { setRotationHeading(mapDesignInt->rotationHeading(selbi->depth())); setRotationSubtree(mapDesignInt->rotationSubtree(selbi->depth())); @@ -2981,6 +3001,32 @@ void VymModel::setRotationSubtree (const int &i, BranchItem *bi) } } +void VymModel::rotateSubtree(qreal a) +{ + QList selbis = getSelectedBranches(); + + foreach (BranchItem *selbi, selbis) { + BranchContainer *bc = selbi->getBranchContainer(); + qreal a_old = bc->rotationSubtree(); + qreal a_new = a_old + a; + QString uc = QString("setRotationSubtree(\"%1\");").arg(toS(a_old, 1)); + QString rc = QString("setRotationSubtree(\"%1\");").arg(a_new); + QString comment = QString("Set rotation angle of subtree to %1").arg(a_new); + + logAction(rc, comment, __func__); + + saveStateBranch(selbi, uc, rc, comment); + + bc->setRotationSubtree(a_new); + emitDataChanged(selbi); + } + + if (!selbis.isEmpty()) { + branchPropertyEditor->updateControls(); + reposition(); + } +} + void VymModel::setScaleAutoDesign (const bool & b, BranchItem *bi) { QList selbis = getSelectedBranches(bi); @@ -2996,7 +3042,7 @@ void VymModel::setScaleAutoDesign (const bool & b, BranchItem *bi) logAction(rc, c, __func__); - saveStateBeginScript(c); + saveStateBeginScript(c); // setScaleAD, calls setScale* functions if (b) { setScaleHeading(mapDesignInt->scaleHeading(selbi->depth())); setScaleSubtree(mapDesignInt->scaleSubtree(selbi->depth())); @@ -3542,7 +3588,7 @@ BranchItem *VymModel::addTimestamp() .arg(today.day(), 2, 10, c); QString comment = "Add branch with current date as heading: " + s; - saveStateBeginScript(comment); + saveStateBeginScript(comment); // addTimeStamp, calls setHeadingPlain and indirect setUrl BranchItem *newbi = addNewBranch(selbi); setHeadingPlainText(s, newbi); saveStateEndScript(); @@ -3598,8 +3644,6 @@ void VymModel::copy() saveState("", rc, comment); } - - mainWindow->updateActions(); } void VymModel::paste() @@ -4248,7 +4292,7 @@ BranchItem *VymModel::addMapCenter(bool interactive) // Start to build undo/redo scripts // These script will be finished later when setHeading() is called if (hasContextPos) - saveStateBeginScript( + saveStateBeginScript( // addMC QString("Add new MapCenter at (%1)").arg(toS(contextPos))); else saveStateBeginScript("Add new MapCenter"); @@ -4273,10 +4317,9 @@ BranchItem *VymModel::addMapCenter(bool interactive) BranchItem *newbi = addMapCenterAtPos(contextPos, interactive); - if (interactive) + if (interactive && mapEditor) mapEditor->editHeading(newbi); - updateActions(); emitShowSelection(); emitUpdateLayout(); @@ -4390,7 +4433,7 @@ BranchItem *VymModel::addNewBranch(BranchItem *bi, int pos, bool interactive) comment = QString("Add new branch below %1").arg(getObjectName(selbi)); logAction("", comment, __func__); - saveStateBeginScript(comment); + saveStateBeginScript(comment); // addNewBranch: edit new heading if interactive } BranchItem *newbi = addNewBranchInt(selbi, pos); @@ -4422,7 +4465,7 @@ BranchItem *VymModel::addNewBranch(BranchItem *bi, int pos, bool interactive) */ } - if (interactive) { + if (interactive && mapEditor) { select(newbi); mapEditor->editHeading(); } @@ -4442,7 +4485,7 @@ BranchItem *VymModel::addNewBranchBefore(BranchItem *bi, bool interactive) // // saveStateEndScript will be called in VymModel::setHeading() comment = QString("Add new branch before %1").arg(getObjectName(selbi)); logAction("", comment, __func__); - saveStateBeginScript(comment); + saveStateBeginScript(comment); // addNewBranchBefore (incl. relinking) } // add below selection @@ -4470,7 +4513,7 @@ BranchItem *VymModel::addNewBranchBefore(BranchItem *bi, bool interactive) // emitDataChanged(newbi); } - if (interactive) { + if (interactive && mapEditor) { select(newbi); mapEditor->editHeading(); } @@ -4507,7 +4550,7 @@ bool VymModel::relinkBranches(QList branches, BranchItem *dst, int if (!saveStateBlocked) // When ordering branches, we already saveState there and not for // each branch individually - saveStateBeginScript( + saveStateBeginScript( // relinkBranches: also save position if required QString("Relink %1 objects to \"%2\"") .arg(branches.count()) .arg(dst->headingPlain())); @@ -4554,8 +4597,10 @@ bool VymModel::relinkBranches(QList branches, BranchItem *dst, int if (dst == rootItem) { detaching = true; preDetachPos = bc->getHeadingContainer()->scenePos(); - } else - detaching = false; + } else { + // Save position, so // that it can be used // for undo command // later + detaching = false; bc->setOriginalPos(); + } BranchItem *branchpi = bi->parentBranch(); @@ -4670,7 +4715,7 @@ bool VymModel::relinkImage(ImageItem* image, TreeItem *dst_ti, int num_new) { return relinkImages(images, dst_ti, num_new); } -bool VymModel::relinkImages(QList images, TreeItem *dst_ti, int num_new) // FIXME-2 Check relinking, if attributes are in dst_ti (*before) image rows +bool VymModel::relinkImages(QList images, TreeItem *dst_ti, int num_new) { // Selection is lost when removing rows from model QList selectedItems = getSelectedItems(); @@ -4701,7 +4746,7 @@ bool VymModel::relinkImages(QList images, TreeItem *dst_ti, int num if (!saveStateBlocked) // When ordering branches, we already saveState there and not for // each branch individually - saveStateBeginScript( + saveStateBeginScript( // FIXME-3 relink images: script used for multiselection QString("Relink %1 objects to \"%2\"") .arg(images.count()) .arg(dst->headingPlain())); @@ -4738,7 +4783,7 @@ bool VymModel::relinkImages(QList images, TreeItem *dst_ti, int num // - What about updating links of images (later)? // - What about updating design (later)? // - in ImageWrapper: num_new missing - // - does not save positions + // - does not save positions currently QString iv = setImageVar(ii); QString uc = setBranchVar(pi) + iv + "i.relinkToBranch(b);"; @@ -4795,7 +4840,8 @@ void VymModel::deleteSelection(ulong selID) unselectAll(); - mapEditor->stopContainerAnimations(); // FIXME-5 better tell ME about deleted items, so that ME can take care of race conditions, e.g. also deleting while moving objects + if (mapEditor) + mapEditor->stopContainerAnimations(); // FIXME-5 better tell ME about deleted items, so that ME can take care of race conditions, e.g. also deleting while moving objects foreach (ulong id, selectedIDs) { TreeItem *ti = findID(id); @@ -5412,7 +5458,8 @@ void VymModel::colorBranch(QColor c, BranchItem *bi) emitDataChanged(selbi); taskEditor->showSelection(); } - mapEditor->getScene()->update(); + if (mapEditor) + mapEditor->getScene()->update(); } void VymModel::colorSubtree(QColor c, BranchItem *bi) @@ -5439,7 +5486,8 @@ void VymModel::colorSubtree(QColor c, BranchItem *bi) } } taskEditor->showSelection(); - mapEditor->getScene()->update(); + if (mapEditor) + mapEditor->getScene()->update(); } QColor VymModel::getCurrentHeadingColor() @@ -5603,17 +5651,6 @@ void VymModel::updateJiraFlag(TreeItem *ti) } } - // Update UrlType - if (ti->urlType() == TreeItem::JiraUrl) { - ti->activateSystemFlagByName("system-jira"); - ti->deactivateSystemFlagByName("system-url"); - } else { - ti->deactivateSystemFlagByName("system-jira"); - if (ti->urlType() == TreeItem::GeneralUrl) - ti->activateSystemFlagByName("system-url"); - else - ti->deactivateSystemFlagByName("system-url"); - } emitDataChanged(ti); } @@ -5778,16 +5815,6 @@ QStringList VymModel::getVymLinks() return links; } -void VymModel::followXLink(int i) -{ - BranchItem *selbi = getSelectedBranch(); - if (selbi) { - selbi = selbi->getXLinkItemNum(i)->getPartnerBranch(); - if (selbi) - select(selbi); - } -} - void VymModel::editXLink() { XLink *xlink = getSelectedXLink(); @@ -5913,6 +5940,11 @@ void VymModel::setExportMode(bool b) QPointF VymModel::exportImage(QString fname, bool askName, QString format) { + if (!mapEditor) { + qWarning() << __func__ << "mapEditor == nullptr"; + return QPointF(); + } + QPointF offset; // set later, when getting image from MapEditor if (fname == "") { @@ -5945,8 +5977,6 @@ QPointF VymModel::exportImage(QString fname, bool askName, QString format) setExportMode(true); - mapEditor->minimizeView(); // Export minimal image - QImage img(mapEditor->getImage(offset)); if (!img.save(fname, format.toLocal8Bit())) { QMessageBox::critical( @@ -5965,6 +5995,11 @@ QPointF VymModel::exportImage(QString fname, bool askName, QString format) void VymModel::exportPDF(QString fname, bool askName) { + if (!mapEditor) { + qWarning() << __func__ << "mapEditor == nullptr"; + return; + } + if (fname == "") { if (!askName) { qWarning("VymModel::exportPDF called without filename (and " @@ -6497,12 +6532,22 @@ void VymModel::registerMapEditor(QWidget *e) { mapEditor = (MapEditor *)e; } void VymModel::setMapZoomFactor(const double &d) { + if (!mapEditor) { + qWarning() << __func__ << "mapEditor == nullptr"; + return; + } + zoomFactor = d; mapEditor->setZoomFactorTarget(d); } void VymModel::setMapRotation(const double &a) { + if (!mapEditor) { + qWarning() << __func__ << "mapEditor == nullptr"; + return; + } + if (a < 1) // Round to zero, otherwise selectionMode in MapEditor might be // "Geometric" when it should be "Classic" @@ -6518,6 +6563,11 @@ void VymModel::setMapAnimCurve(const QEasingCurve &c) { animCurve = c; } bool VymModel::centerOnID(const QString &id) { + if (!mapEditor) { + qWarning() << __func__ << "mapEditor == nullptr"; + return false; + } + TreeItem *ti = findUuid(QUuid(id)); if (ti && (ti->hasTypeBranch() || ti->hasTypeImage())) { Container *c = ((MapItem*)ti)->getContainer(); @@ -6559,7 +6609,8 @@ void VymModel::reposition(bool force) repositionXLinks(); - mapEditor->minimizeView(); // Optimize view when geometry changes in reposition() + if (mapEditor) + mapEditor->minimizeView(); // Optimize view when geometry changes in reposition() //qDebug() << "VM::reposition end"; if (force) @@ -6844,7 +6895,7 @@ void VymModel::setBackgroundColor(QColor col) { QColor oldcol = mapDesignInt->backgroundColor(); - saveStateBeginScript("Set background color"); + saveStateBeginScript("Set background color"); // Save background image in script if (hasBackgroundImage()) unsetBackgroundImage(); @@ -6873,7 +6924,7 @@ bool VymModel::loadBackgroundImage( const QString &imagePath) logAction(rc, comment, __func__); - saveStateBeginScript(comment); + saveStateBeginScript(comment); // load BG img, save previous img if used bool saveOldImage = false; @@ -6996,26 +7047,24 @@ void VymModel::setPos(const QPointF &pos_new, TreeItem *selti) selItems = getSelectedItems(); QString com = "Move items (non-interactive"; - saveStateBeginScript("Move items (non-interactive)"); + QString uc, rc, itemVar; foreach (TreeItem *ti, selItems) { if (ti->hasTypeBranch() || ti->hasTypeImage()) { Container *c = ((MapItem*)ti)->getContainer(); QString pos_new_str = toS(pos_new); - QString uc, rc, itemVar; if (ti->hasTypeBranch()) itemVar = setBranchVar((BranchItem*)ti) + "b."; else itemVar = setImageVar((ImageItem*)ti) + "i."; - uc = QString("%1.setPos%2;").arg(itemVar, toS(c->getOriginalPos(), 5)); - rc = QString("%1.setPos%2;").arg(itemVar, toS(c->pos(), 5)); - logAction(rc, com, __func__); - saveState(uc, rc); + uc += QString("%1.setPos%2;").arg(itemVar, toS(c->getOriginalPos(), 5)); + rc += QString("%1.setPos%2;").arg(itemVar, toS(c->pos(), 5)); c->setPos(pos_new); } } - saveStateEndScript(); + logAction(rc, com, __func__); + saveState(uc, rc); reposition(); } @@ -7959,11 +8008,13 @@ SlideItem *VymModel::addSlide() // FIXME-3 missing saveState return nullptr; } - inScript.replace( - "CURRENT_ZOOM", - QString().setNum(getMapEditor()->zoomFactorTarget())); - inScript.replace("CURRENT_ANGLE", - QString().setNum(getMapEditor()->rotationTarget())); + if (mapEditor) { + inScript.replace( + "CURRENT_ZOOM", + QString().setNum(mapEditor->zoomFactorTarget())); + inScript.replace("CURRENT_ANGLE", + QString().setNum(mapEditor->rotationTarget())); + } inScript.replace("CURRENT_ID", "\"" + seli->getUuid().toString() + "\""); diff --git a/src/vymmodel.h b/src/vymmodel.h index c779737..2364bfd 100644 --- a/src/vymmodel.h +++ b/src/vymmodel.h @@ -172,16 +172,17 @@ class VymModel : public TreeModel { public: /*! \brief Save the map to file */ bool saveMap(const File::SaveMode &); + bool isLoading(); bool isSaving(); + bool isBusy(); private slots: void zipFinished (); private: - - ZipAgent *zipAgent; bool isSavingInt; + bool isLoadingInt; public: ImageItem* loadImage( @@ -262,14 +263,16 @@ class VymModel : public TreeModel { bool isRedoAvailable(); //!< True, if redo is available QString lastRedoSelection(); QString lastRedoCommand(); - QVariant repeatLastCommand(); //!< Repeat last command on current selection + QString lastRedoComment(); + QString lastUndoCommand(); + QString lastUndoComment(); - void undo(); //!< Undo last action - bool isUndoAvailable(); //!< True, if undo is available - void gotoHistoryStep(int); //!< Goto a specifig step in history + void undo(); //!< Undo last action + bool isUndoAvailable(); //!< True, if undo is available + void gotoHistoryStep(int); //!< Goto a specifig step in history - QString getHistoryPath(); //!< Path to directory containing the history - void resetHistory(); //!< Initialize history + QString getHistoryPath(); //!< Path to directory containing the history + void resetHistory(); //!< Initialize history QString setAttributeVar(AttributeItem*, QString varName ="b"); //!< Returns command to set AttributeItem in scripts for undo/redo QString setBranchVar(BranchItem*, QString varName ="b"); //!< Returns command to set BranchItem in scripts for undo/redo @@ -308,6 +311,7 @@ class VymModel : public TreeModel { /*! Put several states into one Script for a single undo step */ void saveStateBeginScript(const QString &comment); void saveStateEndScript(); + void saveStateCancelScript(); //////////////////////////////////////////// // unsorted so far @@ -392,6 +396,7 @@ class VymModel : public TreeModel { void setRotationAutoDesign(const bool &, BranchItem *bi = nullptr); void setRotationHeading(const int &, BranchItem *bi = nullptr); void setRotationSubtree(const int &, BranchItem *bi = nullptr); + void rotateSubtree(qreal a); void setScaleAutoDesign(const bool &, BranchItem *bi = nullptr); void setScaleHeading(const qreal &, const bool relative = false, BranchItem *bi = nullptr); qreal getScaleHeading(); @@ -595,7 +600,6 @@ class VymModel : public TreeModel { void deleteVymLink(); // delete link to another map QString getVymLink(); // return path to map QStringList getVymLinks(); // return paths in subtree - void followXLink(int); void editXLink(); void setXLinkColor(const QString &, XLink *xl = nullptr); void setXLinkStyle(const QString &, XLink *xl = nullptr); diff --git a/src/vymmodelwrapper.cpp b/src/vymmodelwrapper.cpp index 4022208..4b53c01 100644 --- a/src/vymmodelwrapper.cpp +++ b/src/vymmodelwrapper.cpp @@ -481,11 +481,6 @@ void VymModelWrapper::removeXLink(XLinkWrapper *xlw) modelInt->deleteXLink(xlw->xlink()); } -QVariant VymModelWrapper::repeatLastCommand() -{ - return modelInt->repeatLastCommand(); -} - bool VymModelWrapper::saveSelection(const QString &filename) { QString filename_org = modelInt->getFilePath(); // Restore filename later @@ -541,6 +536,17 @@ BranchWrapper* VymModelWrapper::selectedBranch() return nullptr; // caught by QJSEngine } +QList VymModelWrapper::selectedBranches() +{ + QList selbis = modelInt->getSelectedBranches(); + + QList rlist; + foreach (BranchItem *selbi, selbis) + rlist << selbi->branchWrapper(); + + return rlist; +} + XLinkWrapper* VymModelWrapper::selectedXLink() { XLinkItem *xli = modelInt->getSelectedXLinkItem(); diff --git a/src/vymmodelwrapper.h b/src/vymmodelwrapper.h index 21f9061..137a2e0 100644 --- a/src/vymmodelwrapper.h +++ b/src/vymmodelwrapper.h @@ -64,11 +64,11 @@ class VymModelWrapper : public QObject { void removeKeepChildren(BranchWrapper *bw); void removeSlide(int n); void removeXLink(XLinkWrapper *xlw); - QVariant repeatLastCommand(); bool saveSelection(const QString &filename); bool select(const QString &s); Q_INVOKABLE AttributeWrapper* selectedAttribute(); Q_INVOKABLE BranchWrapper* selectedBranch(); + QList selectedBranches(); Q_INVOKABLE XLinkWrapper* selectedXLink(); bool selectUids(QJSValueList args); bool selectLatestAdded(); diff --git a/src/vymview.cpp b/src/vymview.cpp index 4c0e6eb..3e24b45 100644 --- a/src/vymview.cpp +++ b/src/vymview.cpp @@ -11,6 +11,8 @@ extern Main *mainWindow; extern Settings settings; +extern QString editorFocusInStyle; + VymView::VymView(VymModel *m) { model = m; @@ -30,12 +32,19 @@ VymView::VymView(VymModel *m) TreeDelegate *delegate = new TreeDelegate(this); treeEditor->setItemDelegate(delegate); + // Add Escape-keys to editors + QAction *a = new QAction("Cancel", treeEditor); + a->setShortcut(Qt::Key_Escape); // Escape in NoteEditor + a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + treeEditor->connect(a, SIGNAL(triggered()), mainWindow, SLOT(escapePressed())); + treeEditor->addAction(a); + DockEditor *de; de = new DockEditor(tr("Tree Editor", "Title of dockable editor widget"), this, model); de->setWidget(treeEditor); de->setAllowedAreas(Qt::AllDockWidgetAreas); - de->setVisible(mainWindow->actionViewToggleTreeEditor->isChecked()); + de->setVisible(settings.value("/mainwindow/view/showTreeEditors", true).toBool()); addDockWidget(Qt::LeftDockWidgetArea, de); treeEditorDE = de; @@ -52,7 +61,7 @@ VymView::VymView(VymModel *m) this, model); de->setWidget(slideEditor); de->setAllowedAreas(Qt::AllDockWidgetAreas); - de->setVisible(mainWindow->actionViewToggleSlideEditor->isChecked()); + de->setVisible(settings.value("/mainwindow/view/showSlideEditors", false).toBool()); addDockWidget(Qt::RightDockWidgetArea, de); slideEditorDE = de; connect(slideEditorDE, SIGNAL(visibilityChanged(bool)), mainWindow, @@ -118,12 +127,6 @@ void VymView::updateColors() // TreeEditor, HeadingEditor and MapEditor QString s; - // Selection - /* - treeEditor->setStyleSheet( - "selection-background-color: " + brush.color().name(QColor::HexArgb) + ";" + - "background-color: " + mapEditor->getScene()->backgroundBrush().color().name()); - */ MapDesign *mapDesign = model->mapDesign(); @@ -157,7 +160,7 @@ void VymView::updateColors() treeEditor->setPalette(palette); // s += "QTreeView::branch {color: red; background: palette(base);}"; - treeEditor->setStyleSheet(s); + treeEditor->setStyleSheet("QTreeView{" + s + "} QTreeView:focus{" + editorFocusInStyle + "}"); } void VymView::changeSelection(const QItemSelection &newsel, @@ -300,3 +303,4 @@ void VymView::setSlideEditorVisibility(bool b) } void VymView::setFocusMapEditor() { mapEditor->setFocus(); } +void VymView::setFocusTreeEditor() { treeEditor->setFocus(); } diff --git a/src/vymview.h b/src/vymview.h index d71fe81..06a1442 100644 --- a/src/vymview.h +++ b/src/vymview.h @@ -35,6 +35,7 @@ class VymView : public QMainWindow { void setTreeEditorVisibility(bool); void setSlideEditorVisibility(bool); void setFocusMapEditor(); + void setFocusTreeEditor(); private: VymModel *model; diff --git a/src/zip-agent.cpp b/src/zip-agent.cpp index 3dbca91..f7ad8bd 100644 --- a/src/zip-agent.cpp +++ b/src/zip-agent.cpp @@ -15,12 +15,11 @@ ZipAgent::ZipAgent(QDir zipDir, QString zipName) // FIXME-4 Does not support d zipNameInt = QDir::toNativeSeparators(zipName); zipDirInt = zipDir; isBackgroundProcessInt = true; - } ZipAgent::~ZipAgent() { - //qDebug() << "Destr ZipAgent"; + // qDebug() << "Destr ZipAgent"; } bool ZipAgent::checkZipTool() @@ -74,7 +73,7 @@ void ZipAgent::startZip() args << "."; #endif setArguments(args); - mainWindow->logInfo("Starting compressing " + zipDirInt.path() + " : " + zipToolPath + " " + args.join(" ")); + mainWindow->logInfo("ZipAgent: Starting compressing " + zipDirInt.path() + " : " + zipToolPath + " " + args.join(" ") + QString(" Background=%1").arg(isBackgroundProcessInt)); start(); @@ -103,11 +102,17 @@ void ZipAgent::startZip() } } } - } + } else { + connect (this, SIGNAL(backgroundZipStarted()), mainWindow, SLOT(backgroundZipStarted())); + connect (this, SIGNAL(backgroundZipFinished()), mainWindow, SLOT(backgroundZipFinished())); + emit backgroundZipStarted(); + } + } void ZipAgent::zipProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { + //qDebug() << __func__ << "starting."; mainWindow->logInfo(QString("ZA::zipProcessFinished exitCode=%1 exitStatus=%2").arg(exitCode).arg(exitStatus), __func__); #if defined(Q_OS_WINDOWS) @@ -166,6 +171,10 @@ void ZipAgent::zipProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) } #endif emit zipFinished(); + if (isBackgroundProcessInt) + emit backgroundZipFinished(); + + // qDebug() << __func__ << "done."; } void ZipAgent::startUnzip() diff --git a/src/zip-agent.h b/src/zip-agent.h index a5ea86e..312af1a 100644 --- a/src/zip-agent.h +++ b/src/zip-agent.h @@ -25,6 +25,8 @@ class ZipAgent : public QProcess { QString zipName(); signals: + void backgroundZipStarted(); + void backgroundZipFinished(); void zipFinished(); void zipError(); diff --git a/test/vym-selftest.vys b/test/vym-selftest.vys index a26e83f..b65dcab 100644 --- a/test/vym-selftest.vys +++ b/test/vym-selftest.vys @@ -36,7 +36,7 @@ not_yet_ported_tests = [ ]; tests = all_tests; -//tests = ["layouts"]; +// tests = ["modify_branches"]; var verbosity = 0; @@ -1109,6 +1109,29 @@ function test_modify_branches() expect("After undo of inverse sorting first child of \"Main A\" is \"" + ha + "\"", branch_0Aa.headingText(), ha); expect("After undo of inverse sorting last child of \"Main A\" is \"" + hc + "\"", branch_0Ac.headingText(), hc); closeCurrentMap(); + + // Coloring + map = initMap(testMapDefault); + + b = map.findBranchBySelection(main_A_string); + col = b.getHeadingColor(); + b.colorBranch("#ff0000"); + expect("colorBranch", b.getHeadingColor(), "#ff0000"); + map.undo(); + expect("Undo: colorBranch", b.getHeadingColor(), col); + + b2 = map.findBranchBySelection(branch_0Aa_string); + col = b2.getHeadingColor(); + b.colorSubtree("#00ff00"); + expect("colorSubtree", b2.getHeadingColor(), "#00ff00"); + + map.undo(); + b = map.findBranchBySelection(main_A_string); + b2 = map.findBranchBySelection(branch_0Aa_string); + expect("Undo: colorSubtree a) in tree", b2.getHeadingColor(), col); + expect("Undo: colorSubtree b) branch", b.getHeadingColor(), col); + + closeCurrentMap(); } function test_modify_images() @@ -1811,3 +1834,4 @@ if (tests.includes("tasks")) { test_tasks(); } if (tests.includes("xlinks")) { test_xlinks(); } summary(); +vym.exit(); diff --git a/tex/vym.tex b/tex/vym.tex index 392a619..2e64f81 100644 --- a/tex/vym.tex +++ b/tex/vym.tex @@ -1451,7 +1451,8 @@ To hide the link between a branch and its parent open the \subsection{XLinks} \label{xlinks} -So far all the data in the \vym map has been treelike. Using xLinks you +So far all the data in the \vym map has been treelike. Using xLinks +("crosslinks") you can link one branch to any other, just like attaching a rope between two branches in a real tree. This is especially useful in complex maps, where you want to have crossreferences which can not be displayed on the @@ -1487,12 +1488,12 @@ the control points: \subsubsection*{Follow a xLink} In a complex \vym map it sometimes comes in handy to be able to jump to -the other end of a xLink. You can do this by opening the context menu of -the branch and clicking on "Goto xLink" and selecting the xLink you -want to follow. Even easier is to click on the lower right end of a -branch -- a popup menu will show up with all xLinked branches. Click one -of them to jump to it. +the other end of a xLink. There are several ways to do so: +If the current branch has exactly one outgoing xLink and no +other reference (Url or vymLink), the linked branch will be +selected. If multiple xLinks or other references are available, +a popup menu will ask you to select the reference. \subsection{Adding and removing branches} The context menu of a branch shows some more ways to add and delete data @@ -1509,30 +1510,11 @@ between {\em Add Map (Insert)} and {\em Add Map (Replace)}: The imported data will be added after the selected branch. \section{\vym on Mac OS X} -%FIXME-3 Currently not yet supported on Mac OS X in 1.13.x - -%\subsection{Overview} -%Sorry, currently (\vym 2.2.2) there is no Mac port available. Please -%contact the author\footnote{ -% Email Uwe Drechsel: \href{mailto:vym@insilmaril.de}{vym@insilmaril.de}} if -%you are interested in a Mac version. - -%Basically there are two ways to run \vym on Macs: -%\subsubsection*{Qt Mac Edition:} -% \vym here provides the well known Mac look and feel. \vym is -% available as Mac OS X application package in contained in a disk -% image ({\tt vym.dmg}). It has been compiled and tested in -% Mac~OS~10.4. This package includes runtime libraries of Qt by -% Trolltech. - -%\subsubsection*{X11 version} \vym can also be run using the Linux -%version, but then menus and handling will also be those of the Linux -%version e.g. The menu bar will look different. \subsection {Contextmenu and special keys} Most Macs unfortunatly just have a single mouse button. In order to show the context menu which usually would be opened with the right mouse -button, you can click while pressing the \key{kommand}-key. +button, you can click while pressing the \key{command}-key. Especially on Laptops some of the keys usually used on PC keyboards seem to be missing. The Qt-Mac Edition of \vym has its own keyboard diff --git a/vym.qrc b/vym.qrc index 0296628..b59051e 100644 --- a/vym.qrc +++ b/vym.qrc @@ -41,11 +41,11 @@ flags/flag-thumb-down.png flags/flag-thumb-up.png flags/flag-tmpUnscrolled-right.png - flags/system/applications-internet.svg - flags/system/applications-internet-new.svg + flags/system/flag-url.svg + flags/system/flag-urlnew.svg flags/flag-vymlink.png flags/flag-vymlinknew.png - flags/system/jissue.svg + flags/system/flag-jira.svg flags/standard/edit-undo.svg flags/freemind/attach.png