From: Sven Hoexter Date: Wed, 19 Aug 2026 12:37:55 +0000 (+0200) Subject: New upstream version 3.0.0+git20260819 X-Git-Tag: upstream/3.0.0+git20260819-1 X-Git-Url: https://git.sven.stormbind.net/?a=commitdiff_plain;h=528763b23050a8bb03a48563e79d8d4193daacf6;p=sven%2Fvym.git New upstream version 3.0.0+git20260819 --- diff --git a/.gitignore b/.gitignore index d2f186c..2e6d227 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ vym # Qt translation artifacts translations/*.qm + +# Temporary files +tmp/ diff --git a/CMakeLists.txt b/CMakeLists.txt index f87dd74..3055ba8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,32 +57,101 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux) endif() endif() -if(WIN32) - set(OPENSSL_ROOT_DIR "C:/OpenSSL-Win64") - find_package(OpenSSL) - if( OPENSSL_FOUND ) - include_directories(${OPENSSL_INCLUDE_DIRS}) - link_directories(${OPENSSL_LIBRARIES}) - message(STATUS "vym: Using OpenSSL version: ${OPENSSL_VERSION}") +# https://doc.qt.io/qt-6/qt-standard-project-setup.html +find_package(Qt6 REQUIRED COMPONENTS Core) +find_package(Qt6 COMPONENTS ${QtComponents} REQUIRED) + +# Build date +string(TIMESTAMP BUILD_DATE_IN "%Y-%m-%d") +add_compile_definitions(BUILD_DATE_IN="${BUILD_DATE_IN}") +configure_file( + ${CMAKE_SOURCE_DIR}/src/buildinfo.h.in + ${CMAKE_SOURCE_DIR}/src/buildinfo.h) + +# Check if git is installed AND if we are inside a git repo, to get the +# current branch and commit hash +# +# If not, fall back to use the default values in src/git.h.in +# +find_package (Git) +if (GIT_FOUND) + message(STATUS "vym: found git ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}") + + execute_process( + COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_SOURCE_DIR} rev-parse --is-inside-work-tree + RESULT_VARIABLE RESULT + OUTPUT_VARIABLE GIT_REPO_FOUND) + string (STRIP ${GIT_REPO_FOUND} GIT_REPO_FOUND) + + if (GIT_REPO_FOUND STREQUAL "true") + message(STATUS "vym: git repo found in ${CMAKE_SOURCE_DIR}") + + execute_process( + COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_SOURCE_DIR} branch --show-current + RESULT_VARIABLE RESULT + OUTPUT_VARIABLE GIT_BRANCH) + + execute_process( + COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_SOURCE_DIR} rev-parse --short HEAD + RESULT_VARIABLE RESULT + OUTPUT_VARIABLE GIT_COMMIT_HASH) + + string (STRIP ${GIT_BRANCH} GIT_BRANCH) + string (STRIP ${GIT_COMMIT_HASH} GIT_COMMIT_HASH) + + message(STATUS "vym: git branch: \"${GIT_BRANCH}\" - commit ${GIT_COMMIT_HASH}") + + add_compile_definitions( + GIT_BRANCH="${GIT_BRANCH}" + GIT_COMMIT_HASH="${GIT_COMMIT_HASH}") + + configure_file(${CMAKE_SOURCE_DIR}/src/git.h.in ${CMAKE_SOURCE_DIR}/src/git.h) else() - message(STATUS "vym: No openSSL found?!") - # Error; with REQUIRED, pkg_search_module() will throw an error by it's own - endif() + message(STATUS "vym: no git repo found in ${CMAKE_SOURCE_DIR}") + message(STATUS "vym: GIT_REPO_FOUND=${GIT_REPO_FOUND}") + endif () +endif () - set(CMAKE_INSTALL_DATAROOTDIR ".") - endif() +# Translations +# +# To update the translation files based on source code changes +# add the targest update_translations and release_translations +# +# See also (for Qt 6): +# https://doc.qt.io/qt-6/qtlinguist-cmake-qt-add-lrelease.html +# https://doc.qt.io/qt-6/qtlinguist-cmake-qt-add-translations.html +file(GLOB ts_files RELATIVE ${CMAKE_SOURCE_DIR} "lang/*.ts") -# https://doc.qt.io/qt-6/qt-standard-project-setup.html -find_package(Qt6 REQUIRED COMPONENTS Core) -qt_standard_project_setup( I18N_TRANSLATED_LANGUAGES - el cs_CZ de en es fr hr_HR ia it ja pt_BR ru sv zh_CN zh_TW -) # FIXME add missing translations +message(STATUS "vym: Creating ${CMAKE_BINARY_DIR}/translations") +file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/translations") -include(GNUInstallDirs) +set_source_files_properties(${ts_files} PROPERTIES OUTPUT_LOCATION ${CMAKE_BINARY_DIR}/translations) -find_package(Qt6 COMPONENTS ${QtComponents} REQUIRED) + +#qt_add_lrelease(target TS_FILES ${ts_files} QM_FILES_OUTPUT_VARIABLE ${CMAKE_BINARY_DIR}/translations) + +message(STATUS "vym: Found Qt version: ${Qt6_VERSION}") + +if(Qt6_VERSION VERSION_GREATER_EQUAL 6.7) + qt_standard_project_setup( I18N_TRANSLATED_LANGUAGES + el cs_CZ de en es fr hr_HR ia it ja pt_BR ru sv zh_CN zh_TW + ) # FIXME add missing translations + + qt_add_translations( vym + TS_FILE_DIR ${CMAKE_SOURCE_DIR}/lang # TS_OUTPUT_DIRECTORY in Qt 6.9 + RESOURCE_PREFIX ${CMAKE_BINARY_DIR}/translations + #QM_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/translations # Only in Qt 6.9 + ) + # qm files will be created + # - for APPLE in # ${CMAKE_BINARY_DIR}/translations +else() + # Fallback without translations for the time being + qt_standard_project_setup() +endif() + +include(GNUInstallDirs) list(APPEND CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_SOURCE_DIR}/forms") @@ -100,9 +169,9 @@ include_directories( # Source files file(GLOB VymSources RELATIVE ${CMAKE_SOURCE_DIR} "src/*.cpp") -if(WIN32) +if(WIN32) # FIXME still needed? list(APPEND VymSources - src/mkdtemp.cpp + #src/mkdtemp.cpp vym.rc ) ADD_COMPILE_DEFINITIONS(_USE_MATH_DEFINES) @@ -115,31 +184,9 @@ if(DBus1_FOUND) ADD_COMPILE_DEFINITIONS(VYM_DBUS) endif() -# Translations -# -# To update the translation files based on source code changes -# add the targest update_translations and release_translations -# -# See also (for Qt 6): -# https://doc.qt.io/qt-6/qtlinguist-cmake-qt-add-lrelease.html - -file(GLOB ts_files RELATIVE ${CMAKE_SOURCE_DIR} "lang/*.ts") -#message(STATUS "vym: Creating ${CMAKE_BINARY_DIR}/translations") - -#file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/translations") -set_source_files_properties(${ts_files} PROPERTIES OUTPUT_LOCATION ${CMAKE_BINARY_DIR}/translations) - -qt_add_translations(TARGETS vym - TS_FILE_DIR ${CMAKE_SOURCE_DIR}/lang # TS_OUTPUT_DIRECTORY in Qt 6.9 - RESOURCE_PREFIX ${CMAKE_BINARY_DIR}/translations - #QM_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/translations # Only in Qt 6.9 -) - -#qt_add_lrelease(target TS_FILES ${ts_files} QM_FILES_OUTPUT_VARIABLE ${CMAKE_BINARY_DIR}/translations) add_compile_definitions(CMAKE_SOURCE_DIR) -message(STATUS "vym: CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}") message(STATUS "vym: ts_files: ${ts_files}") message(STATUS "vym: qm_files: ${qm_files}") @@ -170,7 +217,7 @@ else() endif() if(APPLE) - message(STATUS "vym: Detected APPLE") + message(STATUS "vym: Detected APPLE, preparing bundle:") set(MACOSX_BUNDLE_EXECUTABLE_NAME ${PROJECT_NAME}) @@ -184,12 +231,14 @@ if(APPLE) MACOSX_BUNDLE TRUE ) - # Root paths to be copied to vym.app bundle (adjust if needed) + # Root paths from sources to be copied to vym.app bundle (adjust if needed) set(DIRLIST demos doc exports flags icons macros styles) + # Copy above directories from sources to bundle + set(RESOURCE_DIR "${CMAKE_BINARY_DIR}/vym.app/Contents/Resources") foreach(CURRENT_DIR ${DIRLIST}) set(SOURCE_DIR "${CMAKE_SOURCE_DIR}/${CURRENT_DIR}") - set(RESOURCE_DIR "${CMAKE_BINARY_DIR}/vym.app/Contents/Resources/${CURRENT_DIR}") + set(TARGET_DIR "${RESOURCE_DIR}/${CURRENT_DIR}") # --- 1. Add all subdirectories of SOURCE to the include path --- @@ -209,26 +258,27 @@ if(APPLE) # Add them to your target target_include_directories(vym PRIVATE ${INCLUDE_DIRS}) - message(STATUS "CURRENT_DIR=${CURRENT_DIR} includeDirs=${INCLUDE_DIRS}") + # message(STATUS "CURRENT_DIR=${CURRENT_DIR} includeDirs=${INCLUDE_DIRS}") - # --- 2. Copy SOURCE_DIR -> RESOURCE_DIR at build time --- + # --- 2. Copy SOURCE_DIR -> TARGET_DIR at build time --- add_custom_command( TARGET vym POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${SOURCE_DIR}" - "${RESOURCE_DIR}" - COMMENT "Copying SOURCE directory ${SOURCE_DIR} to RESOURCE directory ${RESOURCE_DIR}..." + "${TARGET_DIR}" + COMMENT "Copying SOURCE directory ${SOURCE_DIR} to TARGET directory ${TARGET_DIR}..." ) endforeach() # Finally copy generated translations to bundle + set(SOURCE_DIR "${CMAKE_BINARY_DIR}/translations") + set(TARGET_DIR "${RESOURCE_DIR}/translations") add_custom_command( TARGET vym POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - "${CMAKE_BINARY_DIR}/translations" - "${RESOURCE_DIR}" - COMMENT "Copying translations directory to RESOURCE directory ${RESOURCE_DIR}..." + COMMAND ${CMAKE_COMMAND} -E copy_directory "${SOURCE_DIR}" "${TARGET_DIR}" + # COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue "vym: Copying ${SOURCE_DIR} to ${TARGET_DIR}..." + COMMENT "Copying translations directory to TARGET directory ${TARGET_DIR}..." ) endif() diff --git a/README.md b/README.md index e3b6b10..e4ea0aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -VYM - View Your Mind (c) 2004-2025 by Uwe Drechsel +VYM - View Your Mind (c) 2004-2026 by Uwe Drechsel ================================================== About diff --git a/demos/default-dark.vym b/demos/default-dark.vym index 2d55700..c22c515 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 545a3c9..d2d7b07 100644 Binary files a/demos/default.vym and b/demos/default.vym differ diff --git a/demos/frames.vym b/demos/frames.vym index d1d91e0..4dbd870 100644 Binary files a/demos/frames.vym and b/demos/frames.vym differ diff --git a/demos/lifeforms.vym b/demos/lifeforms.vym index 9601d2b..0c8c86a 100644 Binary files a/demos/lifeforms.vym and b/demos/lifeforms.vym differ diff --git a/demos/math.vym b/demos/math.vym index 8732063..9419a8e 100644 Binary files a/demos/math.vym and b/demos/math.vym differ diff --git a/demos/scripts/stats.vys b/demos/scripts/stats.vys new file mode 100644 index 0000000..34c2e0d --- /dev/null +++ b/demos/scripts/stats.vys @@ -0,0 +1,104 @@ +// VYM script to identify the size of subtrees in a big map +// +// The script will set two attributes for each branch: +// - stats_sum_subtree: the number of branches in the subtree of the branch +// (including itself) +// - stats_percent_total: the percentage of branches in the +// subtree compared to the total number of branches in the map +// +// For leaf branches no attributes will be set, as they have no subtree. If you +// want to set the percentage for leaf branches as well, set the variable +// setAttributesForLeafBranches to true. +// +// The script will first clean up old data by removing the attributes if they +// already exist. Then it will calculate the stats and set the attributes for +// each branch. +// +// You can then use the TreeEditor to see the subtree sizes in the new attributes +// +// Note: The script assumes that the map is not modified while it is running, +// as it relies on the order of branches in the item list. If you modify the +// map while the script is running, the results may be incorrect. + +function cleanupOldData() { + vym.print("Cleaning up old data, if available (" + il.count() + " items)"); + counted = 0; + while (b = il.nextBranch() ) { + counted++; + + vym.print (" - [" + (counted / sum_total * 100).toFixed(2) + "%] Current branch: " + b.headingText()); + a = ["stats_sum_subtree", "stats_percent_total"]; + for (let s of a) { + if (b.hasAttributeWithKey(s)) { + vym.print (" - Removing old attribute: " + s); + b.deleteAttribute(s); + } + } + } +} + +function calculateStatsAndSetAttributes() { + vym.print("Setting attributes for " + sum_total + " branches"); + last_depth = -1; + last_parent = null; + counted = 0; + percent_single_branch = (1 / sum_total).toFixed(1) + "%"; + + il.reset(); + while (b = il.nextBranch() ) + { + counted++; + vym.print (" - [" + (counted / sum_total * 100).toFixed(2) + "%] Current branch: " + b.headingText()); + + // Determine type of movement + if (last_depth < 0) { + // vym.print (" - First item"); + last_depth = b.depth(); + if (setAttributesForLeafBranches) + b.setAttribute("stats_percent_total", percent_single_branch); + } else if (b.parentBranch() == last_parent) { + // vym.print (" - Same parent"); + if (setAttributesForLeafBranches) + b.setAttribute("stats_percent_total", percent_single_branch); + } else if (b.depth() < last_depth) { + // vym.print (" - Moved up"); + n = 0; + for (i = 0; i < b.branchCount(); i++) { + c = b.branchAt(i); + if (!c) { + vym.print (" - No child at index " + i); + continue; + } + // vym.print (" - c " + c.headingText()); + if (c.hasAttributeWithKey("stats_sum_subtree")) { + n += c.attributeAsInt("stats_sum_subtree"); + } + } + b.setAttribute("stats_sum_subtree", n + b.branchCount()); + b.setAttribute("stats_percent_total", ((n + b.branchCount() + 1) / sum_total * 100).toFixed(1) + "%"); + } else { + // vym.print (" - Moved down"); + if (setAttributesForLeafBranches) + b.setAttribute("stats_percent_total", percent_single_branch); + } + + last_parent = b.parentBranch(); + + last_depth = b.depth(); + } +} + +vym.clearConsole(); +map = vym.currentMap(); + +il = map.itemList(); +il.setModeBranches(true); + +setAttributesForLeafBranches = false; + +sum_total = il.count(); + +cleanupOldData(); + +calculateStatsAndSetAttributes(); + diff --git a/demos/task-management.vym b/demos/task-management.vym index 2023e8a..496df57 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 b9ec08f..4530495 100644 Binary files a/demos/time-management.vym and b/demos/time-management.vym differ diff --git a/demos/vym-contribute.vym b/demos/vym-contribute.vym index c700127..25be5b8 100644 Binary files a/demos/vym-contribute.vym and b/demos/vym-contribute.vym differ diff --git a/doc/vym.pdf b/doc/vym.pdf index c276efe..e48586d 100644 Binary files a/doc/vym.pdf and b/doc/vym.pdf differ diff --git a/lang/vym_de.ts b/lang/vym_de.ts index c0c5716..a20427c 100644 --- a/lang/vym_de.ts +++ b/lang/vym_de.ts @@ -4,19 +4,19 @@ AboutDialog - + Credits Help->About vym dialog Mitwirkende - + License Help->About vym dialog Lizenz - + Ok Ok Button Ok @@ -25,25 +25,25 @@ AboutTextBrowser - + Please use Settings-> Bitte setzen sie einen Pfad in Einstellungen-> - + Warning About window Warnung - + Couldn't find a viewer to open %1. About window Konnte kein Programm zum Öffnen von %1 finden. - + Set application to open an URL... Anwendung zum Offnen einer URL... @@ -51,18 +51,18 @@ ActionLogDialog - + Logfile settings Dialog to set if and where logfile is used Log Einstellungen - + Logfiles Log Datein - + Set path to logfile Pfad zur Logdatei @@ -85,19 +85,19 @@ BackgroundDialog - + Set background Dialog to set background color or image Hintergrund Einstellungen - + Map backgroundcolor Map background dialog Hintergrundfarbe - + Load background image Hintergrundbild laden @@ -218,56 +218,56 @@ - - + Property Editor Window caption Eigenschaften - + Name Branchprop window: Attribute name Name - + Value Branchprop window: Attribute value Wert - + Type Branchprop window: Attribute type Typ - - + + %1 days ago task related times vor %1 Tagen - + sleeping %1 days task related times Wiedervorlage in %1 Tagen - + Task is awake task related times Aufgabe ist aktiv - + Frame border color Branch property dialog Rahmenfarbe - + Color of frame background Branch property dialog Hintergrundfarbe Rahmen @@ -276,21 +276,21 @@ ConfluenceAgent - - + + Update existing confluence page Existierende Confluence Seite updaten - - - - + + + + Warning Warnung - + Authentication problem when contacting Confluence Authentifizierungsproblem beim Versuch Confluence zu kontaktieren @@ -298,7 +298,7 @@ ConfluenceSettingsDialog - + Confluence settings Confluence settings dialog title Confluence Einstellungen @@ -311,7 +311,7 @@ Dialog - + Find Confluence user dialog window title Confluence Benutzer suchen @@ -364,7 +364,7 @@ System Einstellungen für dunkles Design verwenden - + DarkThemeSettingsDialog dialog dialog window title Dunkles Design Einstellungen @@ -373,7 +373,7 @@ DefaultMapSettingsDialog - + Set vym default map to be loaded on startup Default map setzen, die beim Start geladen wird @@ -381,8 +381,8 @@ DownloadAgent - - + + Warning Warnung @@ -565,12 +565,12 @@ Abbrechen - + Warning Warnung - + The settings saved in the map would like to run script: %1 @@ -584,7 +584,7 @@ want to allow this in your system! Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! - + VYM - Export HTML to directory VYM - Exportiere HTML in Verzeichnis @@ -702,7 +702,7 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! FindControlsWidget - + Find: FindControlsWidget Suchen nach: @@ -739,7 +739,7 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! Rückgängig - + Current state Current bar in history hwindow Aktueller Zustand @@ -753,19 +753,19 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! Zeit - + Action Table with actions Befehl - + Comment Table with actions Bemerkungen - + Undo action Table with actions Rückgängig @@ -774,14 +774,14 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! JiraAgent - - + + Warning Warnung - - + + Authentication problem when contacting JIRA Authentifizierungsproblem beim Versuch JIRA zu kontaktieren @@ -805,12 +805,12 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! Entfernen - + Email: Email: - + Username: Benutzername: @@ -828,7 +828,7 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! JIRA Einstellungen - + Jira settings Jira settings dialog title Jira Einstellungen @@ -845,12 +845,12 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! TextLabel - + Cancel Abbrechen - + Ok Ok @@ -862,12 +862,12 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! Dialog - + Delete lockfile Lockdatei entfernen - + Open readonly Nur zum Lesen öffnen @@ -875,17 +875,17 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! Main - + Linkstyle Line Verbindungsstil Linie - + Linkstyle Thick Line Verbindungsstil gefülltes Polygon - + Set &Link Color &Farbe der Verbindungen @@ -894,25 +894,25 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! &Hintergrundfarbe - + &View &Ansicht - - + + Set application to open an URL URLs öffnen mit... - + Overwrite Überschreiben - - - + + + Cancel Abbrechen @@ -929,58 +929,56 @@ Bitte prüfen Sie, ob Sie das wirklich erlauben wollen! Änderungen verwerfen - - - - - - - + + + + + Critical Error Kritischer Fehler - + Open anyway Trotzdem öffnen - + Critcal error Kritischer Fehler - + Create Anlegen - + VYM -Information: vym-Information: - + Load vym map Lade vym Map - + Import: Add vym map to selection Import: Füge Map zu Auswahl hinzu - + Import: Replace selection with vym map Import: Ersetze Auswahl mit Map - + Add Hinzufügen - + The map %1 is already opened.Opening the same map in multiple editors may lead to confusion when finishing working with vym.Do you want to @@ -990,7 +988,7 @@ zu bearbeiten kann beim Beenden von vym zu Verwirrung führen. Wollen Sie - + This map does not exist: %1 Do you want to create a new one? @@ -1003,147 +1001,146 @@ Wollen Sie eine neue anlegen? %1 gespeichert - - + The file %1 exists already. Do you want to Die Datei %1 gibt es bereits. Wollen Sie sie überschreiben? - + The map %1 has been modified but not saved yet. Do you want to Die Map %1 wurde geändert, aber noch nicht gespeichert. Wollen Sie - + Couldn't open map %1 Konnte die Map %1 nicht öffnen - + Take care! Standardflag Vorsicht! - + Really? Standardflag Wirklich? - + This won't work! Standardflag Das geht nicht! - + Good Standardflag Gut - + Bad Standardflag Schlecht - + Time critical Standardflag Zeitkritisch - + Idea! Standardflag Idee! - + Windows Mainwindow view shortcut groups Fenster - + Script output View action Skript Ausgabe - + History window View action Verlaufsfenster - + Important Standardflag Wichtig - + Unimportant Standardflag Unwichtig - + I like this Standardflag Finde ich gut - + I do not like this Standardflag Finde ich schlecht - + Dangerous Standardflag Gefährlich - + This will help Standardflag Das könnte helfen - - - + + + Import Importieren - - - - - - - - - - - - - - + + + + + + + + + + + + + + (still experimental) (noch experimentelle Funktion) - + &Print &Drucken @@ -1152,77 +1149,76 @@ aber noch nicht gespeichert. Wollen Sie Exportieren als - - - - - - - - - + + + + + + + + Warning Warnung - - - + + + Couldn't find a viewer to open %1. Konnte kein Programm zum Öffnen von %1 finden. - - - + + + Please use Settings-> Bitte setzen sie einen Pfad in Einstellungen-> - + Couldn't set sleep time to %1. Konnte Wiedervorlage nicht setzen auf %1 - - + + Set application to open PDF files PDFs öffnen mit - + Oh no! Standardflag Oh nein! - + Search results list FindResultWidget Liste der Suchergebnisse - + File actions toolbar Toolbar for file actions Datei Werkzeugleiste - + Edit actions toolbar Toolbar name Editieren Werkzeugleiste - + Property Editor PropertyEditor Eigenschaften - + History window HistoryWidget Verlaufsfenster @@ -1238,13 +1234,13 @@ aber noch nicht gespeichert. Wollen Sie Map Editor - + Text Editors Shortcut group Text Editor - + Script output window Script Ausgabe @@ -1254,55 +1250,55 @@ aber noch nicht gespeichert. Wollen Sie &Map - + &Restore last session Edit menu &Letzte Session wiederherstellen - + Save as default map File menu Datei als standard map speichern - + Import Dir... Import Filters Verzeichnis importieren - + Webpage (HTML)... File export menu Webseite (HTML) - + Confluence (HTML)... File export menu Confluence (HTML) - + Text (ASCII)... File export menu Text (ASCII) - + Text (Markdown)... File export menu Text (Markdown) - + Text with tasks File export menu Text mit Aufgaben - + CSV... CSV... @@ -1311,84 +1307,84 @@ aber noch nicht gespeichert. Wollen Sie Attribut hinzufügen - + &Detach Context menu Loslösen - + Detach branch and use as mapcenter Context menu Zweig loslösen und als Zentrum verwenden - + Sort children backwards Edit menu Unterzweige aufsteigend sortieren - + Follow reference Context menu Referenz folgen - + Set &Background color and image Hintergrundfarbe und -bild setzen - + Views Mainwindow view shortcut groups Ansichten - + Toggle mode to temporary hide parts View action Teile temporär verbergen - + Rotate clockwise View action Rotieren im Uhrzeigersinn - + Rotate view to selection View action Ansicht rotieren zu Auswahl - + Tree editor expand/collapse Mainwindow view shortcut groups Baumeditor aus- und einklappen - + Expand all branches Edit menu Alle Zweige ausklappen - + Expand one level Edit menu Ausklappen - + Collapse one level Edit menu Einklappen - + Collapse unselected levels Edit menu Nicht selektierte Ebenen einklappen @@ -1399,43 +1395,43 @@ aber noch nicht gespeichert. Wollen Sie Unterzweige ausrollen - + Grow selection Edit menu Auswahl vergössern - + Shrink selection Edit menu Auswahl verkleinern - + Reset selection size Edit menu Grösse der Auswahl zurücksetzen - + Toggle target... Edit menu Ziel einschalten/ausschalten - + Goto target... Edit menu Gehe zu Ziel - + Move to target... Edit menu Verschiebe zu Ziel - + Find duplicate URLs Edit menu Doppelte URLs finden @@ -1446,85 +1442,85 @@ aber noch nicht gespeichert. Wollen Sie Alle URLs im Unterbaum öffnen - + Extract URLs from note Edit menu Extrahiere URLs aus Notiz - + Add timestamp Edit menu Zeitstempel hinzufügen - + Remove children Edit menu Unterzweige entfernen - + Center on selection View action Zeige Auswahl - + Editors toolbar Editor Toolbar name Werkzeugleiste Editoren - + Modifier modes toolbar Modifier Toolbar name Werkzeugleiste Modifizierer - + E&dit Edit menu E&dit - + Select previous Edit menu vorherige Auswahl - + Select next Edit menu nächste Auswahl - + Unselect all Edit menu Nichts auswählen - + Select default font Branch attribute Default Zeichensatz auswählen - + Toolbars Toolbars overview in view menu Werkzeugleisten - + Toggle Presentation mode View action Präsentationsmodus an/abschalten - + Rotate counterclockwise View action Rotieren gegen Uhrzeigersinn @@ -1535,25 +1531,25 @@ aber noch nicht gespeichert. Wollen Sie Rotieren im Uhrzeigersinn - + Tree editor View action Baum Editor - + Task editor View action Aufgaben Editor - + Slide editor View action Folien Editor - + Script editor View action Skript Editor @@ -1564,85 +1560,85 @@ aber noch nicht gespeichert. Wollen Sie Script Ausgabe - + Next slide View action Nächste Folie - + Previous slide View action Vorherige Folie - + Map target SystemFlag Ziel - + Standard Flags toolbar Standard Flag Toolbar Werkzeugleiste Standardflags - + Status - ok,done Standardflag Status - ok, erledigt - + Status - work in progress Standardflag Status - In Arbeit - + Status - missing, not started Standardflag Status - unvollständig, nicht begonnen - + Call... Standardflag Anrufen... - + Very important! Standardflag Sehr wichtig! - + Very unimportant! Standardflag Sehr unwichtig! - + Rose Standardflag Rose - + Surprise! Standardflag Überraschung! - + Info Standardflag Info - + Check for release notes and updates Settings action Release notes und Updates prüfen @@ -1653,118 +1649,118 @@ aber noch nicht gespeichert. Wollen Sie Anwendung um Daten zu speichern (zip/unzip) - + Download and show release notes Help action Release Notes herunterladen und anzeigen - + Check, if updates are available Help action Prüfen, ob Updates verfügbar sind - + Show keyboard macros Help action Tatstur Makros anzeigen - + XLinks Menu for file actions XLinks - + Untitled Default name in FileSaveAs dialog unbenannt - - + + Open %1 map Öffne Map %1 - + Enter Url: Url eingeben: - + unknown user default name for map author in settings unbekannter Benutzer - + Number of parents shown for a task: Anzahl der Elternzweige, die bei Aufgabe gezeigt werden: - + Firefox Bookmarks Firefox Lesezeichen - + &Map Map menu &Map - + Toggle window Toggle visibility of editor windows overview in view menu Fenster zeigen - + Focus window Toggle visibility of editor windows overview in view menu Fenster fokussieren - + File actions MainWindow shortcut groups Datei Aktionen - + &Open... File menu &Öffnen... - + Open Recent File menu Zuletzt geöffnete Dateien - + &Clear Clear recent files menu Liste leeren - + &Save... File menu &Speichern... - + Save &As... File menu Speichern &unter... - + Import File menu Importieren @@ -1774,270 +1770,270 @@ aber noch nicht gespeichert. Wollen Sie (noch experimentell) - + Export File menu Exportieren - + Exports MainWindow shortcut groups Exports - + Repeat last export Wiederhole letzten Export - + Image%1 File export menu Bild %1 - + Map properties Map Eigenschaften... - + &Close Map File menu Schlie&ßen - + Exit MainWindow shortcut groups B&eenden - + E&xit File menu B&eenden - + Miscellaneous MainWindow shortcut groups Verschiedenes - + Undo/Redo MainWindow shortcut groups Rückgängig und Wiederholen - - + + &Undo Edit menu &Rückgängig - + &Redo Edit menu Wieder&herstellen - + Repeat last action Edit menu Wiederhole letzte Aktion - - + + &Copy Edit menu &Kopieren - - + + Cu&t Edit menu &Ausschneiden - - + + &Paste Edit menu Ein&fügen - + Delete Selection Edit menu Entfernen - + Add MainWindow shortcut groups Hinzufügen - + Add branch as child Edit menu Neuer Zweig - + Add branch (insert) Edit menu Neuen Zweig einfügen - - + + Add branch above Edit menu Neuer Zweig - oben - - + + Add branch below Edit menu Neuer Zweig - unten - + Move MainWindow shortcut groups Bewegen - + Sort and display MainWindow shortcut groups Sortieren und Anzeigen - + Scroll branch Edit menu Zweig einrollen - + Unscroll branch and subtree Edit menu Zweig und Unterzweige ausklappen - + Geometry of items MainWindow shortcut groups Geometrie von Objekten - + Rotate subtree clockwise Edit menu Rotiere Unterbaum im Uhrzeigersinn - + Rotate subtree counter-clockwise Edit menu Rotiere Unterbaum gegen Uhrzeigersinn - + URLs Shortcuts in references context menu URLs - + Open all visible URLs in subtree Edit menu Alle URLs im Unterbaum öffnen - + Open all URLs in subtree in private mode Edit menu Alle URLs in Unterbaum in privatem Modus öffnen - + Connect Connection shortcuts in MainWindow Verbindungen - + Get data from Jira for subtree Edit menu Daten von JIRA für Unterbaum holen - + Set Jira query Edit menu Jira Suche setzen - + Get page name and details from Confluence Edit menu Titel der Seite von Confluence übernehmen - + Get page name and details from Confluence for child pages Edit menu Titel der Seiten in Unterbaum von Confluence übernehmen - + vymlinks - linking maps Shortcuts for vymLinks in MainWindow vym-Verbindungen zwischen Maps - + Tasks Shortcuts for tasks in MainWindow Aufgaben - + Add image Edit and context menus Bild hinzufügen - + Item properties Dialog to edit properties of selected item Eigenschaften - - + + Find... Edit menu Suchen - + Open URL Edit menu URL öffnen - + Main window Shortcut scope Hauptfenster @@ -2048,139 +2044,139 @@ aber noch nicht gespeichert. Wollen Sie URL in neuen Tab öffnen - + Open all URLs in subtree Edit menu Alle URLs in Unterbaum öffnen - + Edit URL... Edit menu URL editieren... - + Use heading for URL Edit menu Beschriftung als URL übernehmen - + Open linked map Edit menu Verlinkte Map öffnen - + Open all vym links in subtree Edit menu Alle Verbindungen zu vym maps in Unterbaum öffnen - + Edit vym link... Edit menu vym Verknüpfung editieren - + Delete vym link Edit menu vym Verknüpfung löschen - + Hide in exports Edit menu In Export nicht anzeigen - + Add map (insert) Edit menu Map einfügen (An Selektion hinzufügen) - + Add map (replace) Edit menu Map einfügen (Selektion austauschen) - + Save selection Edit menu Auswahl speichern - + F&ormat Format menu F&ormat - + Pic&k color Edit menu Farbe &übernehmen - + Color &branch Edit menu Zweig &färben - + Color sub&tree Edit menu &Unterbaum färben - + Hide link if object is not selected Branch attribute Verbindung verbergen, falls Objekt nicht selektiert ist - + &Use color of heading for link Branch attribute &Verbindungen haben Farbe der Beschriftungen - + reset Zoom View action Keine Vergrösserung - + Zoom in View action Vergrössern - + Task list TaskEditor Aufgabenliste - + Script Editor ScriptEditor Skript Editor - + Firefox Bookmarks Import filters Firefox Lesezeichen - + Text (A&O report)... Export format Text (A&O Format) @@ -2190,13 +2186,13 @@ aber noch nicht gespeichert. Wollen Sie Eigenschaften - + Move branch up Edit menu Zweig nach oben bewegen - + Move branch down Edit menu Zweig nach unten bewegen @@ -2212,7 +2208,7 @@ aber noch nicht gespeichert. Wollen Sie vym-Verbindungen zwischen Maps - + Open linked map in background tab Edit menu Verbundene Map im Hintergrund öffnen @@ -2228,97 +2224,97 @@ aber noch nicht gespeichert. Wollen Sie Aufgaben - + Toggle task Edit menu Aufgabe einschalten/ausschalten - + Cycle task status Edit menu Aufgabenstatus weiterschalten - + Reset sleep Task sleep Aufgabe aufwecken - - - - - - + + + + + + Sleep %1 days Task sleep Wiedervorlage in %1 Tagen - + Sleep %1 day Task sleep Wiedervorlage in %1 Tagen - - + + Sleep %1 weeks Task sleep Wiedervorlage in %1 Wochen - + Removing parts of a map Shortcuts Teile einer Map entfernen - + Remove only branch and keep its children Edit menu Zweig entfernen und Unterzweige behalten - + Various Shortcuts Verschiedene - + Map properties... Edit menu Map Eigenschaften... - + Selections Shortcuts Auswahl - + Select Select menu Auswählen - + Goto linked map... Edit menu Verlinkte Map öffnen... - + Search functions Shortcuts Suchfunktionen - + Formatting Shortcuts Formattierung @@ -2329,19 +2325,19 @@ aber noch nicht gespeichert. Wollen Sie Ansichten - + Zoom out View action Verkleinern - + Note editor View action Notiz Editor - + Heading editor View action Beschriftungs Editor @@ -2356,19 +2352,19 @@ aber noch nicht gespeichert. Wollen Sie Alle - + URL SystemFlag URL - + User Flags toolbar user Flags Toolbar Werzeugleiste Benuzterflags - + Hm... Standardflag Hm... @@ -2378,42 +2374,42 @@ aber noch nicht gespeichert. Wollen Sie (experimentell) - + Firefox Bookmarks File export menu Firefox Lesezeichen - + Move branch diagonally up Edit menu Zeig schräg nach oben bewegen - + Move branch diagonally down Edit menu Zweig schräg nach unten bewegen - + &Connect Verbindungen - + Connect Shortcuts Verbindungen - + Get Confluence user data Connect action Nutzer Infos von Confluence holen - + Use modifier to select and reorder objects Mode modifier Auswählen und Anordnen @@ -2424,152 +2420,152 @@ aber noch nicht gespeichert. Wollen Sie Einfärben mit der Farbe eines anderen Zweiges - + Use modifier to move branches without linking Mode modifier Zweige bewegen ohne sie umzuhängen - + Use modifier to move view without selecting Mode modifier Ansicht verschieben ohne Zweige auszuwählen - - + + Important Freemind flag Wichtig - + Back Freemind flag Zurück - + Forward Freemind flag Vorwärts - + Look here Freemind flag Schau hier - + Dangerous Freemind flag Gefährlich - + Don't forget Freemind flag Nicht vergessen - + Flag Freemind flag Flag - + Home Freemind flag Startseite - + Telephone Freemind flag Telefon - + Music Freemind flag Musik - + Mailbox Freemind flag Briefkasten - + Password Freemind flag Passwort - + To be improved Freemind flag Zu verbessern - + Stop Freemind flag Stop - + Magic Freemind flag Magie - + To be discussed Freemind flag Zu überlegen - + Reminder Freemind flag Erinnerung - + Excellent Freemind flag Ausgezeichnet - + Linux Freemind flag Linux - + Sweet Freemind flag Süß - + Set author for new maps Settings action Author für neue Maps angeben - + Confluence Credentials Settings action Confluence Zugangsdaten - + JIRA Credentials Settings action JIRA Zugangsdaten @@ -2580,25 +2576,25 @@ aber noch nicht gespeichert. Wollen Sie Pfad festlegen für Standardmap - + Number of visible parents in task editor Settings action Anzahl sichtbarer Elternzweige im Aufgaben Editor - + Number of visible parents in find results window Settings action Anzahl sichtbarer Elternzweige im Ergebnisfenster der Suche - + Debug info Option to show debugging info Infos zur Fehlersuche - + Couldn't load default map: %1 @@ -2608,14 +2604,13 @@ vym will create an empty map now. Konnte Standardmap nicht laden - + Couldn't save %1, because file exists and cannot be changed. Konnte %1 nicht speichern, da die Datei bereits existiert und nicht geändert werden darf. - - + Couldn't save %1, because of existing lockfile: @@ -2631,47 +2626,47 @@ da die Lockdatei nicht angelegt werden konnte: - + branches Info about map Zweige - + notes Info about map Notizen - + images Info about map Bilder - + slides Info about map Folien - + xLinks Info about map Querverbindungen - + Set author for new maps (used in lockfile) Author für neue Maps angeben (zur Verwendung in Lockdatei) - + Number of parents shown in find results: Anzahl sichtbarer Elternzweige im Ergebnisfenster der Suche - + (readonly) (nur lesen) @@ -2691,51 +2686,50 @@ da die Lockdatei nicht angelegt werden konnte: Bild hinzufügen - + View toolbar View Toolbar name Werkzeugleiste ANsicht - + Save map as new default map Map als standard map speichern - You have no permissions to write to - Keine Berechtigung zum Schreiben von + Keine Berechtigung zum Schreiben von Overwrite as new default map Als neue standard map überschreiben - + Import Firefox Bookmarks into new map Importiere Firefox Lesezeichen in neue Map - + Enter sleep time (number of days, hours with 'h' or date YYYY-MM-DD or DD.MM[.YYYY] task sleep time dialog Wiedervorlage (als Anzahl Tage oder als Datum: JJJJ-MM-TT oder TT.MM[JJJJ]) - + tasks total Info about map Aufgaben insgesamt - + tasks in map Info about map Aufgaben in Map - + Load vym script Script laden @@ -2744,13 +2738,13 @@ Map als standard map speichern Default map setzen, die beim Start geladen wird - - + + No SSL support available for this build of vym SSL nicht unterstützt - + Repeat last Export %1 Format: %2 to %3 @@ -2760,85 +2754,85 @@ Format: %2 nach %3 - + Branch Context menu to follow links Zweig - + Url Context menu to follow links Url - + Map Context menu to follow links Map - + Please allow vym to download release notes! Bitte erlauben Sie vym die Release-Anmerkungen herunterzuladen! - + Allow Erlauben - + Do not allow Nicht erlauben - + Thank you for enabling downloads! Danke für das Erlauben der Downloads! - + Update information Update Information - + vym is up to date. MainWindow vym ist auf dem neuesten Stand. - + Checking for updates... MainWindow Prüfen auf Updates... - + Please allow vym to check for updates! Bitte vym erlauben nach Updates zu sehen! - + Use modifier to draw xLinks Mode modifier Modifizierer zum Anlegen von xLinks verwenden - + Set application to open pdf files Settings action pdf-Dateien öffnen mit... - + Set application to open external links Settings action Anwendung zum Öffnen externen Verweise - + Select branch after adding it Settings action Zweig nach dem Einfügen auswählen @@ -2849,85 +2843,85 @@ Format: %2 nach Beschriftung vor dem editieren auswählen - + Exclusive flags Settings action Exklusive Flags - + Use hide flags Settings action Während des Exports das "Verbergen" Flag verwenden - + &Help Help menubar entry &Hilfe - + Open VYM Documentation (pdf) Help action VYM Handbuch (pdf) - + About VYM Help action Über VYM - + About QT Help action Über QT - + Remove Context menu name Entfernen - + Edit XLink Context menu name xLink ändern - + Follow XLink Context menu name XLink folgen - + Save image Context action Speichere Bild - + &New map File menu Neue map - + &Copy to new map File menu Kopieren in neue Map - + PDF%1 File export menu PDF%1 - + SVG%1 File export menu SVG%1 @@ -2937,19 +2931,19 @@ Format: %2 nach Letzten Export wiederholen (%1) - + Add mapcenter Canvas context menu Mapcenter hinzufügen - + Sort children Edit menu Unterzweige aufsteigend sortieren - + Edit local URL... Edit menu Lokale URL editieren @@ -2960,17 +2954,17 @@ Format: %2 nach Eigenschaften - + Linkstyle Curve Verbindungsstil Parabel - + Linkstyle Thick Curve Verbindungsstil Parabel - + Set &Selection Color Farbe der Auswahlmarkierung @@ -2979,7 +2973,7 @@ Format: %2 nach Hintergrundbild laden - + Fit view to selection View action Zeige Auwahl und vergrößere @@ -2990,197 +2984,197 @@ Format: %2 nach Verlaufsfenster - + Antialiasing View action Antialiasing - + Smooth pixmap transformations View action Weiche Bild Transformationen - + Presentation mode Mainwindow presentation shortcut groups Präsentations Modus - + Navigation between maps Mainwindow view shortcut groups Navigieren in Maps - + Next Map View action Nächste Map - + Previous Map View action Vorherige Map - + Modifier modes Shortcuts Tasten Modifizierer - + Use modifier to pick color from another branch Mode modifier Verwende Modifizierer um Farbe eines anderen Zweiges zu erhalten - + Load user flag Lade benutzerdefiniertes Flag - - - - - - - - + + + + + + + + Note SystemFlag Notiz - + Jira SystemFlag Jira - + Link to another vym map SystemFlag Verweis zu einer anderen Map - + subtree is scrolled SystemFlag Teilbaum ist eingerollt - + subtree is temporary scrolled SystemFlag Teilbaum ist momentan ausgerollt - + Hide object in exported maps SystemFlag Objekt beim Exportieren nicht anzeigen - + Settings Einstellungen - + Set path for new maps Settings action Pfad für neue Maps setzen - + Set path for macros Settings action Pfad für Makros - + Set number of undo levels Settings action Anzahl der Rückgängig Aktionen - + Autosave Settings action Automatisch speichern - + Autosave time Settings action Zeit für automatisches speichern - + Write backup file on save Settings action Beim Verlassen Sicherungskopie anlegen - + Logfile settings Settings action Log Einstellungen - + Animation Settings action Animation - + Automatic layout Settings action Autolayout - + Test Test - + Open VYM example maps Help action VYM Beispielmaps - + Show keyboard shortcuts Help action Zeige Tastaturkürzel - + Hierarchy Context menu name Hierarchie - + Geometry Context menu name Geometrie - + Tasks Context menu Aufgaben - + References (URLs, vymLinks, ...) Context menu name Verweise (URLS, vym, ...) @@ -3191,48 +3185,48 @@ Format: %2 nach XLink folgen - + Undo and clipboard toolbar Toolbar for redo/undo and clipboard Rückgängig Werkzeugleiste - + Selection toolbar Toolbar name Auswahl Werkzeugleiste - + URLs and vymLinks toolbar Toolbar for URLs and vymlinks URLs und vymLinks Werkzeugleiste - + Colors toolbar Colors toolbar name Farben Werkzeugleiste - + Limited view toolbar View Toolbar name Vereinfachte Werkzeugleiste Ansicht - + Loading: %1 Progress dialog while loading maps Lade: %1 - + Loaded %1 %1 geladen - + or File Dialog oder @@ -3242,7 +3236,7 @@ Format: %2 nach Speichere %1... - + Save map as Speichern &unter... @@ -3255,47 +3249,47 @@ Format: %2 nach Neue URL: - + HTML Filedialog HTML - + Text Filedialog Text - + Spreadsheet Filedialog Tabellendokument - + Textdocument Filedialog Textdokument - + Images Filedialog Bilder - + Set URL to a local file URL zu einer lokalen Datei setzen - + Enter Jira query: Jira Suche: - + %1 items on map Info about map @@ -3303,64 +3297,69 @@ Format: %2 nach - + + Save part of map + Teil einer Map speichern + + + Load images Lade Bilder - + Color of selection box Mainwindow Farbe der Auswahlmarkierung - + Set application to open external links Anwendung zum Öffnen externen Verweise - + Number of undo/redo levels: Anzahl der Rückgängig Aktionen - + Settings have been changed. The next map opened will have "%1" undo/redo levels Die Einstellungen wurden geändert. Die nächste geöffnete Map wird %1 Rückgängig Schritte haben. - + Number of seconds before autosave: Anzahl der Sekunden vor automatischem Speichern - + Information Information - + Undo (%1) Rückgängig (%1) - + Undo: %1 (%2) Rückgängig (%1)-(%2) - + Redo (%1) Wiederholen(%1) - + Redo: %1 (%2) Wiederholen: %1 (%2) - + History for %1 Window Caption Verlauf von %1 @@ -3371,25 +3370,25 @@ wird %1 Rückgängig Schritte haben. Exportiere im zuletzt genutzten Format (%1) nach: %2 - + Couldn't find the documentation %1 in: %2 Konnte die Dokumentation %1 nicht finden in %2 - + Load vym example map Lade vym Beispiel Map - + I just love... Standardflag Ich liebe das - + Mail Freemind flag Post @@ -3399,63 +3398,62 @@ wird %1 Rückgängig Schritte haben. Öffne Freemind map - + Link to another vym map Verbindung zu weiterer vym map - + Set as link to vym map Verbindung zu vym map - + Reset delta priority for visible tasks Reset delta Delta Priorität für sichtbare Aufgaben zurücksetzen - + Select color (Press Shift for more options) Farbe auswählen (Drücke Shift für mehr Optionen) - + Saving the map failed: Couldn't rename map to %1 Map konnte nicht gespeichert werden Konnte nicht umbenennen zu %1 - Couldn't save as default, failed to rename to %1 - Konnte nicht als Standard speichern, das umbennen ist fehlgeschlagen: + Konnte nicht als Standard speichern, das umbennen ist fehlgeschlagen: %1 - + Dark theme Settings action Dunkles Design - + Restart vym to apply the changed dark theme setting Bitte vym neu starten um die Einstellungen für dunkles Design zu verwenden - + <html><h3>Do you allow vym to check online for updates or release notes?</h3>If you allow, vym will <ul><li>check once for release notes</li><li>check regulary for updates and notify you in case you should update, e.g. if there are important bug fixes available</li><li>receive a cookie with a random ID and send some anonymous data, like:<ul><li>vym version</li><li>platform name and the ID (e.g. "Windows" or "Linux")</li><li>if you are using dark theme</li></ul>This data is sent to me, Uwe Drechsel.<p>As vym developer I am motivated to see many people using vym. Of course I am curious to see, on which system vym is used. Maintaining each of the systems requires a lot of my (spare) time.</p> <p>No other data than above will be sent, especially no private data will be collected or sent.(Check the source code, if you don't believe.)</p></li></ul>If you do not allow, <ul><li>nothing will be downloaded and especially I will <b>not be motivated</b> to spend some more thousands of hours on developing a free software tool.</ul>Please allow vym to check for updates :-) <html><h3>Erlauben Sie vym online nach Updates oder Release Anmerkungen zu suchen?</h3>Wenn Sie es erlauben, wird vym <ul><li>einmalig online nach Release Anmerkungen suchen</li><li>regelmäßig nach Updates suchen und Sie benachrichtigen, sollten Updates wie z.B. wichtige Fehlerbehebungen verfügbar sein</li><li>ein cookie erhalten mit eineer zufällig erzeugten ID und einige anonymisierte Daten senden, wie z.B.<ul><li>vym Version</li><li>Plattform Name und ID "Windows" oder "Linux")</li><li>Einstellungen wie z.B. Sprache und ob dunkles Design verwendet wird</li></ul>Diese Daten werden geschickt zum Author von vym: Uwe Drechsel.<p>Als vym Entwickler motiviert es mich zu sehen, wenn viele Menschen vym benutzen. Natürlich bin ich neugierig, auf welchen Plattformen vym verwendet wird. Jede dieser Plattformen benötigt eine Menge meiner (Frei-)zeit.</p> <p>Abgesehen von obigen Daten wird nichts weiteres gesendet, insbesondere keine privaten Daten. (Bitte bei Zweifel gerne die Quellen prüfen!)</p></li></ul>Falls Sie es nicht zulassen, wird<ul><li>nichts heruntergeladen und <b>besonders werde ich nicht motiviert</b> weiter tausende Stunden meiner Zeit in die Entwicklung einer freien Software zu stecken.</ul>Bitte erlauben Sie vym nach Updates zu sehen :-) - + That's ok, though I would be happy to see many users working with vym and also on which platforms. Schade, ich würde mich wirklich freuen, wenn ich viele Menschen vym benutzen sehe und auch auf welchen Plattformen vym genutzt wird. - + Show scripting commands Help action Skript Befehle anzeigen @@ -3464,32 +3462,32 @@ Konnte nicht umbenennen zu %1 MapEditor - + Map Editor Shortcut scope Map Editor - + Map Editors Shortcut group Map Editoren - - + + Edit heading MapEditor Zweig-Überschrift bearbeiten - + Print vym map MapEditor Map drucken - + Warning Warnung @@ -3498,6 +3496,21 @@ Konnte nicht umbenennen zu %1 %1 Objekte ausgewählt + + MyTextEdit + + + Open URL + TextEdit menu + URL öffnen + + + + Insert or edit URL + TextEdit menu + URL einfügen + + NoteEditor @@ -3509,123 +3522,124 @@ Konnte nicht umbenennen zu %1 QObject - + Export as AO report Map AO report exportieren - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + Critical Export Error Kritischer Fehler beim Exportieren - - - + + + Could not write %1 %1 konnte nicht - + Exporting to %1 will overwrite the existing file: %2 Die Datei %2 gibt es bereits. Wollen Sie sie überschreiben für einen Export nach %1? - + Warning: Overwriting file Warnung: Überschreiben einer Datei - + Could not export as AO to %1 Konnte nicht als AO nach %1 exportieren - + Could not export as ASCII to %1 Konnte nicht als ASCII nach %1 exportieren - + Export as CSV Exportiere als CSV - + Could not export as CSV to %1 Konnte nicht als CSV nach %1 exportieren - - + + Contents: Used in HTML export Inhalt - + Export aborted. Export fehlgeschlagen. - + Trying to create directory for flags: Versuche Verzeichnis für Flags anzulegen - + Could not create %1 %1 konnte nicht angelegt werden - + Flag: %1 Alt tag in HTML export Flag: %1 - + Flag: url Alt tag in HTML export Flag: URL - - + + Critical Kritisch - + Could not find stylesheet %1 Konnte stylesheet %1 nicht finden - + Error ExportHTML Fehler - + Could not copy %1 to %2 @@ -3635,110 +3649,115 @@ Wollen Sie sie überschreiben für einen Export nach %1? %2 - - + + Trying to save HTML file: Versuche HTML Datei zu speichern: - - - - - - - - - + + + + + + + + + Export failed. Export fehlgeschlagen. - + Could not export as OrgMode to %1 Konnte nicht als OrgMode nach %1 exportieren - + Could not export as LaTeX to %1 Konnte nicht als LaTeX nach %1 exportieren - + Export as LibreOffice Impress presentation Exportieren als LibreOffice Impress Präsentation - + No objects in map! Keine Objekte in Map! - + + Could not start compressing file %1 + Konnte das Komprimieren der Datei nicht starten + + + Could not compress file %1 Konnte Datei nicht komprimieren %1 - + Couldn't read settings from "%1" Konnte Einstellungen nicht lesen von %1 - + Check "%1" in %2 Bitte "%1" prüfen in %2 - - - + + + Could not read %1 %1 konnte nicht gelesen werden - + Note Editor Name of editor shown as window title Notiz Editor - + Heading Editor Name of editor shown as window title Editor Zweigbeschriftungen - - - - - - - - - - - - - - + + + + + + + + + + + + + + Critical Error Kritischer Fehler - + Couldn't find tool to zip/unzip data,or your Windows version is older than Windows 10. Konnte Tool zum Auspacken oder Komprimieren der Daten nicht finden, oder Windows Version ist älter als Windows 10. - + Couldn't find tar tool to zip data. Konnte das tar Werkzeug zum Komprimieren der Daten nicht finden. - + Couldn't find tar tool to unzip data. Konnte das tar Werkzeug zum Entpacken der Daten nicht finden. @@ -3753,7 +3772,7 @@ The map could not be saved, please check if backup file is available or export a Die Map konnte nicht gespeichert werden: Bitte prüfen, ob eine Backup Datei vorhanden ist oder die Map als XML Datei exportieren! - + Couldn't start to compress data! The map could not be saved, please check if backup file is available or export as XML file! @@ -3765,15 +3784,15 @@ ob ein Backup existiert oder exportiere die Map als XML-Datei! - - - - + + + + zip didn't exit normally zip wurde nicht richtig beendet - + Couldn't start tool to decompress data! @@ -3805,68 +3824,68 @@ ob ein Backup existiert oder exportiere die Map als XML-Datei! Konnte %1 nicht starten, um die Daten auszupacken! - + Could not start %1 %1 konnte nicht gestartet werden - + %1 didn't exit normally %1 wurde nicht richtig beendet - + Images Bilder - + Overwrite Überschreiben - + Cancel Abbrechen - + Warning Warnung - - - - - - - - - - + + + + + + + + + + Error Fehler - - + + Couldn't access temporary directory Auf das temporäre Verzeichnis konnte nicht zugegriffen werden - + Export as ASCII Exportiere als ASCII - + (still experimental) (noch experimentelle Funktion) - + The directory %1 is not empty. Do you risk to overwrite its contents? write directory @@ -3874,12 +3893,12 @@ Do you risk to overwrite its contents? Riskieren Sie es dessen Inhalt zu überschreiben? - + Warning: Version Problem Warnung: Versionsproblem - + <h3>Map is newer than VYM</h3><p>The map you are just trying to load was saved using vym %1. The version of this vym is %2. If you run into problems after pressing the ok-button below, updating vym should help.</p> <h3>Map ist neuer als VYM</h3><p>Die Map, die Sie gerade versuchen zu laden wurde mit vym %1 gespeichert. Die vorliegende Version von vym ist %2. Falls nach dem Fortfahren mit Ok Probleme autauchen, sollte ein Update von vym helfen.</p> @@ -3893,29 +3912,29 @@ Riskieren Sie es dessen Inhalt zu überschreiben? Konnte Makro nicht finden in %1. - + Couldn't find macros at %1. Macros::pathExists Konnte Makro nicht finden in %1. - + Please use Settings-> Bitte setzen sie einen Pfad in Einstellungen-> - + Set directory for vym macros Verzeichnis für vym Makros - + Export as Markdown Als Markdown exportieren - + Could not export as Markdown to %1 Konnte nicht als Markdown nach %1 exportieren @@ -3930,8 +3949,8 @@ Riskieren Sie es dessen Inhalt zu überschreiben? Konnte Tool zum Auspacken oder Komprimieren der Daten nicht finden. Bitte passend zur Plattform installieren und Pfad in den Einstellungen setzen. - - + + Couldn't open "%1" . Konnte %1 nicht öffnen. @@ -3944,57 +3963,57 @@ Riskieren Sie es dessen Inhalt zu überschreiben? - + Couldn't write macros to "%1" . Konnte Makros nicht speichern nach "%1" - - + + Couldn't read script from "%1" . Konnte script nicht lesen von "%1" - + Couldn't write script to "%1" . Konnte script nicht speichern in "%1" - + Export as Firefox bookmarks Exportieren als Firefox Lesezeichen - + Could not export as Firefox bookmarks to %1 Konnte Firefox Lesezeichen nicht exportieren nach %1 - + Import Firefox bookmarks Import dialog Importiere Firefox Lesezeichen - + Loading bookmarks: Progress dialog while importing bookmarks Importiere Lesezeichen: - + Imported %1 bookmarks Import dialog %1 Lesezeichen importiert. - + Existing lockfiles have been ignored for the maps listed below. Please check, if the maps might be openend in another instance of vym: @@ -4002,24 +4021,30 @@ Riskieren Sie es dessen Inhalt zu überschreiben? - + JIRA agent not setup. JIRA agent ist nicht eingerichtet - + Image: %1 Alt tag in HTML export Bild: %1 - + %1 Line %2, column %3 Error message while parsing XML %1 Zeile %2, Spalte %3 + + + (Vim alternative shortcut) + Shortcut help dialog + (Vim - alternatives Tastenkürzel) + ScriptEditor @@ -4052,63 +4077,68 @@ Zeile %2, Spalte %3 Speichern - - + + Warning Warnung - + Slide Mode in scriptEditor Folie - + Macro Mode in scriptEditor Makro - + Script Mode in scriptEditor Script - + No script selected scriptname in scriptEditor Kein script geladen - Script Editor Shortcut scope + Skript Editor + + + + Script editor + Shortcut scope Skript Editor - + Couldn't get model to save script into slide! Konnte Datenmodell zum Speichern des Scripts nicht auffinden! - + Couldn't find slide to save script into slide! Konnte Folie zum Speichern des Scripts nicht finden! - + Macros saved to %1 Makros gespeichert nach %1 - + Script saved to %1 Script gespeichert nach %1 - + Save script Script speichern @@ -4129,7 +4159,7 @@ Wollen Sie sie überschreiben? Abbrechen - + Load script Script laden @@ -4148,44 +4178,44 @@ Wollen Sie sie überschreiben? TaskEditor - + Show only tasks from current map Filters in task Editor Nur Aufgaben aus aktuelle Map anzeigen - + Show only active tasks Filters in task Editor Nur aktive Aufgaben anzeigen - + Show only new tasks Filters in task Editor Nur neue Aufgaben anzeigen - + Show only blocker tasks Filters in task Editor Nur Blocker Aufgaben anzeigen - - + + Show only tasks marked with this arrow-up flag Filters in task Editor Nur Aufgaben mit diesem Pfeil anzeigen - + Show only tasks marked without any arrow-up flag Filters in task Editor Nur Aufgaben ohne Pfeil anzeigen - + Task Editor Shortcut group Aufgaben Editor @@ -4194,55 +4224,55 @@ Wollen Sie sie überschreiben? TaskModel - + Prio TaskEditor Priorität - + Delta TaskEditor Delta - + Status TaskEditor Status - + Age total TaskEditor Alter insg. - + Age mod. TaskEditor Alter letzte Änderung - + Sleep TaskEditor Wiedervorlage - + Map TaskEditor Map - + Flags TaskEditor Flaggen - + Task TaskEditor Aufgabe @@ -4251,32 +4281,32 @@ Wollen Sie sie überschreiben? TextEditor - + &Import... &Importiere - + &Export... &Export - + &Print... &Drucken - + &Undo R&ückgängig - + &Redo Wieder&herstellen - + Select and copy &all &Alles auswählen und kopieren @@ -4293,27 +4323,47 @@ Wollen Sie sie überschreiben? Ein&fügen - + &Delete All Alles &löschen - + + &Color text using foreground color + Text mit Vordergrundfarbe einfärben + + + + &Select text foreground color... + Text Vordergrundfarbe auswählen + + + + &Mark text using background color... + Text mit Hintergrundfarbe markieren + + + + &Select text background color... + Text Hintergrundfarbe auswählen + + + &Settings &Einstellungen - + Set &fixed font Wähle Zeichensatz mit f&ixer Breite - + Set &variable font Wähle Zeichensatz mit v&ariabler Breite - + &fixed font is default Verwende fixen Zeichensatz p&er default @@ -4322,29 +4372,28 @@ Wollen Sie sie überschreiben? Exportiere Notiz &als... (HTML) - Export &As...(ASCII) - Exportiere a&ls (ASCII) + Exportiere a&ls (ASCII) - + Edi&t Edi&tieren - + Font hints toolbar in texteditor Zeichensatz Hint - + Fonts toolbar in texteditor Zeichensätze - + Format toolbar in texteditor Format @@ -4354,84 +4403,83 @@ Wollen Sie sie überschreiben? &Farbe... - + &Bold F&ett - + &Italic K&ursiv - + &Underline &Unterstrichen - + &Left &Linksbündig - + C&enter &Zentriert - + &Right &Rechtsbündig - + &Justify &Blocksatz - + Export Note to single file Notiz in eine einzelne Datei exportieren - - + + Overwrite Überschreiben - - + + Cancel Abbrechen - Export Note to single file (ASCII) - Notiz als ASCII in eine einzelne Datei ausgeben + Notiz als ASCII in eine einzelne Datei ausgeben - + &Font hint Zeichensatz &umschalten - + Subs&cript &Tiefgestellt - + Su&perscript &Hochgestellt - + Note Editor Notiz Editor - + F&ormat F&ormat @@ -4441,12 +4489,12 @@ Wollen Sie sie überschreiben? Text Editor - + Edit Actions Edit Actions - + Note Actions Note Actions @@ -4456,94 +4504,97 @@ Wollen Sie sie überschreiben? Bereit - No filename available for this note. Statusbar message - Notiz hat keinen Dateinamen + Notiz hat keinen Dateinamen - + &Note Menubar &Notiz - + File actions TextEditor shortcut groups Datei Aktionen - + Edit actions TextEditor shortcut groups Editier Aktionen - + &Copy Edit menu &Kopieren - + Cu&t Edit menu &Ausschneiden - + &Paste Edit menu Ein&fügen - + + Insert or edit URL + TextEditor + URL einfügen oder ändern + + + Insert image TextEditor Bild einfügen - + Format actions TextEditor shortcut groups Formatier Actions - + &Richtext &Richtext - &Text Color... - &Text Farbe + &Text Farbe - &Text background color... - &Text Hintergrundfarbe + &Text Hintergrundfarbe - + Set RichText mode editor background color TextEditor Setze Standardfarbe für Hintergrund mit RichText - + Set RichText mode default text color TextEditor Setze Standardfarbe für Hintergrund mit RichText - + Set RichText mode default text background color TextEditor Setze Standardfarbe für Hintergrund mit RichText - + The file %1 exists already. Do you want to overwrite it? @@ -4552,49 +4603,48 @@ Do you want to overwrite it? Wollen Sie sie überschreiben? - Couldn't export note dialog 'save note as' - Konnte Notiz nicht exportieren + Konnte Notiz nicht exportieren - + Print TextEditor Drucken - + Text color TextEditor windows &Text Farbe - + Text background color TextEditor windows &Text Hintergrundfarbe - + Text editor background color TextEditor windows Text Editor Hintergrundfarbe - + Text editor default text color TextEditor windows Setze Standardzeichenfarbe für Texteditor - + Text editor default text background color TextEditor windows Setze Standardhintergrundfarbe für Texteditor - + Load image TextEditor Lade Bild @@ -4613,13 +4663,13 @@ Wollen Sie sie überschreiben? TreeEditor - + Select upper object Tree Editor Zweig oben auswählen - + Select lower object Tree Editor Zweig unten auswählen @@ -4628,64 +4678,64 @@ Wollen Sie sie überschreiben? VymModel - + unknown user default name for map author in settings unbekannter Benutzer - + unnamed unbenannt - - - + + + Critical Parse Error Kritischer Fehler beim Verarbeiten - - - - - + + + + + Critical Load Error Kritischer Fehler beim Laden - + Couldn't create temporary directory before load Konnte temporäres Verzeichnis vor dem Laden nicht erzeugen - + Uncompressing %1 Entpacke %1 - + Loading %1 Lade: %1 - + Couldn't find %1 in map file. Konnte %1 in der Map Datei nicht finden - + Couldn't find a map (*.xml) in .vym archive. Konnte keine map (*.xml) in .vym Datei finden. - + The map %1 did not use the compressed vym file format. Writing it uncompressed will also write images @@ -4700,97 +4750,103 @@ könnte damit Dateien im Verzeichnis überschreiben Soll die Map geschrieben werden? - + uncompressed, potentially overwrite existing data unkomprimiert, u.U werden Daten überschrieben - + + %1 +could not be renamed as backup file before saving + %1 +konnte nicht als Backupdatei umbenannt werden vor dem Speichern + + + Couldn't access zipDir %1 Konnte nicht auf zipDir zugreifen: %1 - + Saving %1... Speichere %1... - + Couldn't save Datei konnte nicht gespeichert werden - + Compressing %1 Komprimiere %1 - - - + + + Saved %1 %1 gespeichert - + unknown user Default for lockfiles of maps unbekannter Benutzer - + Warning: Map already opended VymModel Warnung: Map ist bereits geöffnet - + Couldn't find configuration for export to LibreOffice Impress Konnte Konfiguration zum Exportieren nach LibreOffice nicht finden - + %1 items selected Status message when selecting multiple items %1 Objekte ausgewählt - + compressed (vym default) komprimieren (vym default) - - + + Cancel Abbrechen - - + + Save Error Fehler beim Speichern - + %1 could not be removed before saving %1 konnte vor dem Speichern nicht entfernt werden - %1 could not be renamed before saving - %1 + %1 konnte vor dem Speichern nicht umbenannt werden - + Critical Save Error Kritischer Fehler beim Speichern @@ -4800,12 +4856,12 @@ konnte vor dem Speichern nicht umbenannt werden Konnte temporäres Verzeichnis vor dem Speichern nicht erzeugen - + Images Bilder - + All Filedialog Alle @@ -4815,51 +4871,51 @@ konnte vor dem Speichern nicht umbenannt werden Lade Bild - + Save image Speichere Bild - + The file %1 exists already. Do you want to overwrite it? Die Datei %1 gibt es bereits. Wollen Sie sie überschreiben? - + Overwrite Überschreiben - - + + Critical Error Kritischer Fehler - + Couldn't save %1 Konnte %1 nicht speichern - + Critical Import Error Kritischer Fehler beim Importieren - + Cannot find the directory %1 Konnte das Verzeichnis %1 nicht finden - - + + Choose directory structure to import Bitte Verzeichnis zum Importieren auswählen - + Map seems to be already opened in another vym instance! Map is locked by "%1" on "%2" @@ -4872,41 +4928,41 @@ Map ist gesperrt von "%1" auf "%2" Bitte Lockdatei nur entfernen, wenn wirklich niemand anderes diese Map momentan verwendet. - + Could not setup JiraAgent to retrieve data from Jira Konnte JiraAgent nicht initialisieren um Daten von Jira zu holen - + Contacting Jira... VymModel Kontaktiere JIRA... - + Removed lockfile for %1 Lockdateo für %1 entfernt. - + Couldn't remove lockfile for %1 Konnte Lockdatei für %1 nicht entfernen - + Cannot create lockfile of map! It will be opened in readonly mode. Konnte Lockdatei nicht anlegen! Map wird nur zum Lesen geöffnet. - + Warning VymModel Warnung - + The file of the map on disk has changed: %1 @@ -4919,29 +4975,29 @@ Do you want to reload that map with the new file? Soll die Map durch die neue Datei ersetzt werden? - + Reload Neu laden - + Ignore Ignorieren - - - + + + Warning Warnung - + Autosave disabled during undo. Autosave ausgeschaltet während der Aktion "Rückgängig" - + Note FindAll in VymModel Notiz @@ -4952,56 +5008,56 @@ Soll die Map durch die neue Datei ersetzt werden? Neue Map - + Export map as image Map als Bild exportieren - + Couldn't save QImage %1 in format %2 Konnte Bild %1 nicht im Format %2 speichern - + Export map as PDF Als PDF exportieren - + Export map as SVG Als SVG exportieren - - + + Export to Exportieren als - + Export map as XML Als XML exportieren - + Export XML to directory Exportiere XML in Verzeichnis - + Critical Export Error Kritischer Fehler beim Exportieren - - - + + + (still experimental) (noch experimentelle Funktion) - - + + Export as csv Exportiere als CSV @@ -5015,8 +5071,8 @@ Soll die Map durch die neue Datei ersetzt werden? Konnte keine JIRA Ticket Zeichenfolge finden in %1 - - + + Received Jira data. VymModel Jira Daten empfangen @@ -5025,35 +5081,31 @@ Soll die Map durch die neue Datei ersetzt werden? VymModelWrapper - - Saving the selection in map failed: Couldn't rename map to %1 - Map konnte nicht gespeichert werden + Map konnte nicht gespeichert werden Konnte nicht umbenennen zu %1 - - Critical Error - Kritischer Fehler + Kritischer Fehler VymProcess - - + + Critical Error Kritischer Fehler - + %1 didn't exit normally %1 wurde nicht richtig beendet - + Could not start %1 Konnte nicht starten: %1 @@ -5061,13 +5113,13 @@ Konnte nicht umbenennen zu %1 VymView - + Tree Editor Title of dockable editor widget Baum Editor - + Slide Editor Title of dockable editor widget Folien Editor @@ -5076,17 +5128,17 @@ Konnte nicht umbenennen zu %1 WarningDialog - + Proceed Weiter - + Show this message again Diese Meldung das nächste Mal wieder zeigen - + Warning Warning dialog default window name Warnung @@ -5096,7 +5148,7 @@ Konnte nicht umbenennen zu %1 Dialog - + Cancel Abbrechen diff --git a/macros/macros.vys b/macros/macros.vys index 364161c..2ed2ffe 100644 --- a/macros/macros.vys +++ b/macros/macros.vys @@ -2,14 +2,15 @@ // Macros called when function keys are pressed +//! Helper function to toggle frame background color of a single branch -//! Helper function to toggle frame function toggle_frame_branch(color, msg) { map = vym.currentMap(); branches = map.selectedBranches(); - for (b of branches) { + // Make sure changes are saved + b.setFrameAutoDesign(true, false); if (b.getFrameType(true) == "NoFrame" ) { b.setFrameType (true, "RoundedRectangle"); b.setFrameBrushColor(true, color); @@ -21,12 +22,15 @@ function toggle_frame_branch(color, msg) } } +//! Helper function to toggle frame background color of a whole subtree + function toggle_frame_subtree(color, msg) { map = vym.currentMap(); branches = map.selectedBranches(); - for (b of branches) { + // Make sure changes are saved + b.setFrameAutoDesign(false, false); if (b.getFrameType(false) == "NoFrame" ) { b.setFrameType (false, "RoundedRectangle"); b.setFrameBrushColor(false, color); @@ -38,29 +42,32 @@ function toggle_frame_subtree(color, msg) } } +//! Helper function to color only the selected branch using a quick color slot function colorBranchWithQuickColor(n) { map = vym.currentMap(); vym.selectQuickColor(n); c = vym.currentColor(); - branches = map.selectedBranches(); for (b of branches) b.colorBranch(c); } +//! Helper function to color the whole subtree using a quick color slot + function colorSubtreeWithQuickColor(n) { map = vym.currentMap(); vym.selectQuickColor(n); c = vym.currentColor(); - branches = map.selectedBranches(); for (b of branches) b.colorSubtree(c); } +// ─── Plain function keys: color the whole subtree ──────────────────────────── + //! Macro F1: Color subtree red function macro_f1() { @@ -71,7 +78,6 @@ function macro_f1() function macro_f2() { colorSubtreeWithQuickColor(1); - // Or if you prefer to edit the heading of a branch using "F2"-key, // you can use below instead of above: // vym.editHeading(); @@ -83,7 +89,6 @@ function macro_f3() colorSubtreeWithQuickColor(2); } - //! Macro F4: Color subtree purple function macro_f4() { @@ -96,7 +101,7 @@ function macro_f5() colorSubtreeWithQuickColor(4); } -//! Macro F6: Color subtree blue +//! Macro F6: Color subtree cyan function macro_f6() { colorSubtreeWithQuickColor(5); @@ -120,30 +125,30 @@ function macro_f9() colorSubtreeWithQuickColor(8); } -//! Macro F10: Color subtree light white +//! Macro F10: Color subtree white function macro_f10() { colorSubtreeWithQuickColor(9); } -//! Macro F11: +//! Macro F11: (unused) function macro_f11() { map = vym.currentMap(); // Unused } -//! Macro F12: toggle high prio task +//! Macro F12: Toggle high-priority task state function macro_f12() { - // Assuming 3 states, which are cycled: - // 0 - nothing set - // 1 - high prio task with arrows - // 2 - done task without arrows, but green hook + // Assuming 3 states, which are cycled: + // 0 - nothing set + // 1 - high prio task with arrows + // 2 - done task without arrows, but green hook map = vym.currentMap(); b = map.selectedBranch(); if (b.hasTask() ) { - // Switch to state 2 + // Switch to state 2 b.toggleTask(); b.unsetFlagByName("2arrow-up"); b.unsetFlagByName("stopsign"); @@ -164,218 +169,214 @@ function macro_f12() } } +// ─── Shift + function keys: color only the selected branch ─────────────────── -//! Macro Shift + F1: Frame background light red +//! Macro Shift+F1: Color branch red function macro_shift_f1() { - toggle_frame_branch ( "#ffb3b4", "Branch frame background light red" ); + colorBranchWithQuickColor(0); } -//! Macro Shift + F2: Frame background light green +//! Macro Shift+F2: Color branch orange function macro_shift_f2() { - toggle_frame_branch ( "#bdffd6", "Branch frame background light green"); + colorBranchWithQuickColor(1); } -//! Macro Shift + F3: Frame background light yellow +//! Macro Shift+F3: Color branch green function macro_shift_f3() { - toggle_frame_branch ( "#efefb3", "Branch frame background light yellow"); + colorBranchWithQuickColor(2); } -//! Macro Shift + F4: Frame background light blue +//! Macro Shift+F4: Color branch purple function macro_shift_f4() { - toggle_frame_branch ( "#e2e6ff", "Branch frame background light blue"); + colorBranchWithQuickColor(3); } -//! Macro Shift + F5: Frame background light grey +//! Macro Shift+F5: Color branch blue function macro_shift_f5() { - toggle_frame_branch ( "#d6d6d6", "Branch frame background light grey"); + colorBranchWithQuickColor(4); } -//! Macro Shift + F6: Frame background purple +//! Macro Shift+F6: Color branch cyan function macro_shift_f6() { - toggle_frame_branch ( "#ffaaff", "Branch frame background purple"); + colorBranchWithQuickColor(5); } -//! Macro Shift + F7: Frame background white +//! Macro Shift+F7: Color branch black function macro_shift_f7() { - toggle_frame_branch ( "#ffffff", "Branch frame background white"); + colorBranchWithQuickColor(6); } -//! Macro Shift + F8: Frame background black +//! Macro Shift+F8: Color branch dark gray function macro_shift_f8() { - toggle_frame_branch ( "#000000", "Branch frame background black"); + colorBranchWithQuickColor(7); } -// Macro Shift + F9: +//! Macro Shift+F9: Color branch light gray function macro_shift_f9() { + colorBranchWithQuickColor(8); } -//! Macro Shift + F10: +//! Macro Shift+F10: Color branch white function macro_shift_f10() { + colorBranchWithQuickColor(9); } -//! Macro Shift + F11: +//! Macro Shift+F11: (unused) function macro_shift_f11() { } -//! Macro Shift + F12: +//! Macro Shift+F12: (unused) function macro_shift_f12() { } +// ─── Ctrl + function keys: toggle frame background color of the branch ─────── -// New ///////////////////////////////////// -//! Macro Ctrl + F1: Subtree background light red +//! Macro Ctrl+F1: Toggle branch frame background light red function macro_ctrl_f1() { - toggle_frame_subtree ( "#ffb3b4", "Branch frame background light red"); + toggle_frame_branch ( "#ffb3b4", "Branch frame background light red" ); } -//! Macro Ctrl + F2: Subtree background light green - +//! Macro Ctrl+F2: Toggle branch frame background light green function macro_ctrl_f2() { - toggle_frame_subtree ( "#bdffd6", "Branch frame background light green"); + toggle_frame_branch ( "#bdffd6", "Branch frame background light green" ); } -//! Macro Ctrl + F3: Subtree background light yellow +//! Macro Ctrl+F3: Toggle branch frame background light yellow function macro_ctrl_f3() { - toggle_frame_subtree ( "#efefb3", "Branch frame background light yellow"); + toggle_frame_branch ( "#efefb3", "Branch frame background light yellow" ); } -//! Macro Ctrl + F4: Subtree background light blue +//! Macro Ctrl+F4: Toggle branch frame background light blue function macro_ctrl_f4() { - toggle_frame_subtree ( "#e2e6ff", "Branch frame background light yellow"); + toggle_frame_branch ( "#e2e6ff", "Branch frame background light blue" ); } -//! Macro Ctrl + F5: Subtree background light grey +//! Macro Ctrl+F5: Toggle branch frame background light grey function macro_ctrl_f5() { - toggle_frame_subtree ( "#d6d6d6", "Branch frame background light grey"); + toggle_frame_branch ( "#d6d6d6", "Branch frame background light grey" ); } -//! Macro Ctrl + F6: Subtree background purple +//! Macro Ctrl+F6: Toggle branch frame background purple function macro_ctrl_f6() { - toggle_frame_subtree ( "#ffaaff", "Branch frame background light purple"); + toggle_frame_branch ( "#ffaaff", "Branch frame background purple" ); } -//! Macro Ctrl + F7: Subtree background white +//! Macro Ctrl+F7: Toggle branch frame background white function macro_ctrl_f7() { - toggle_frame_subtree ( "#ffffff", "Branch frame background light white"); + toggle_frame_branch ( "#ffffff", "Branch frame background white" ); } -//! Macro Ctrl + F8: Subtree background black +//! Macro Ctrl+F8: Toggle branch frame background black function macro_ctrl_f8() { - toggle_frame_subtree ( "#000000", "Branch frame background light black"); + toggle_frame_branch ( "#000000", "Branch frame background black" ); } -//! Macro Ctrl + F9: +//! Macro Ctrl+F9: (unused) function macro_ctrl_f9() { - vym.statusMessage("Macro F9 + Ctrl triggered"); } -//! Macro Ctrl + F10: +//! Macro Ctrl+F10: (unused) function macro_ctrl_f10() { - vym.statusMessage("Macro F10 + Ctrl triggered"); } -//! Macro Ctrl + F11: +//! Macro Ctrl+F11: (unused) function macro_ctrl_f11() { - vym.statusMessage("Macro F11 + Ctrl triggered"); } -//! Macro Ctrl + F12: +//! Macro Ctrl+F12: (unused) function macro_ctrl_f12() { - vym.statusMessage("Macro F12 + Ctrl triggered"); } -//! Macro Ctrl + Shift + F1: +// ─── Ctrl+Shift + function keys: toggle frame background color of subtree ──── + +//! Macro Ctrl+Shift+F1: Toggle subtree frame background light red function macro_ctrl_shift_f1() { - vym.statusMessage("Macro F1 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#ffb3b4", "Subtree frame background light red" ); } -//! Macro Ctrl + Shift + F2: +//! Macro Ctrl+Shift+F2: Toggle subtree frame background light green function macro_ctrl_shift_f2() { - vym.statusMessage("Macro F2 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#bdffd6", "Subtree frame background light green" ); } -//! Macro Ctrl + Shift + F3: +//! Macro Ctrl+Shift+F3: Toggle subtree frame background light yellow function macro_ctrl_shift_f3() { - vym.statusMessage("Macro F3 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#efefb3", "Subtree frame background light yellow" ); } -//! Macro Ctrl + Shift + F4: +//! Macro Ctrl+Shift+F4: Toggle subtree frame background light blue function macro_ctrl_shift_f4() { - vym.statusMessage("Macro F4 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#e2e6ff", "Subtree frame background light blue" ); } -//! Macro Ctrl + Shift + F5: +//! Macro Ctrl+Shift+F5: Toggle subtree frame background light grey function macro_ctrl_shift_f5() { - vym.statusMessage("Macro F5 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#d6d6d6", "Subtree frame background light grey" ); } -//! Macro Ctrl + Shift + F6: +//! Macro Ctrl+Shift+F6: Toggle subtree frame background purple function macro_ctrl_shift_f6() { - vym.statusMessage("Macro F6 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#ffaaff", "Subtree frame background purple" ); } -//! Macro Ctrl + Shift + F7: +//! Macro Ctrl+Shift+F7: Toggle subtree frame background white function macro_ctrl_shift_f7() { - vym.statusMessage("Macro F7 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#ffffff", "Subtree frame background white" ); } -//! Macro Ctrl + Shift + F8: +//! Macro Ctrl+Shift+F8: Toggle subtree frame background black function macro_ctrl_shift_f8() { - vym.statusMessage("Macro F8 + Ctrl + Shift triggered"); + toggle_frame_subtree ( "#000000", "Subtree frame background black" ); } -//! Macro Ctrl + Shift + F9: +//! Macro Ctrl+Shift+F9: (unused) function macro_ctrl_shift_f9() { - vym.statusMessage("Macro F9 + Ctrl + Shift triggered"); } -//! Macro Ctrl + Shift + F10: +//! Macro Ctrl+Shift+F10: (unused) function macro_ctrl_shift_f10() { - vym.statusMessage("Macro F10 + Ctrl + Shift triggered"); } -//! Macro Ctrl + Shift + F11: +//! Macro Ctrl+Shift+F11: (unused) function macro_ctrl_shift_f11() { - vym.statusMessage("Macro F11 + Ctrl + Shift triggered"); } -//! Macro Ctrl + Shift + F12: +//! Macro Ctrl+Shift+F12: (unused) function macro_ctrl_shift_f12() { - vym.statusMessage("Macro F12 + Ctrl + Shift triggered"); -} \ No newline at end of file +} diff --git a/release-notes-3.0.md b/release-notes-3.0.md new file mode 100644 index 0000000..a93fd7a --- /dev/null +++ b/release-notes-3.0.md @@ -0,0 +1,676 @@ +Release notes VYM - View Your Mind +================================== + + +The lists below shows main changes between the current 3.0 version of vym and +the previous official release 2.9.27. + +vym has been rewritten in large parts: + + * New layout engine + - Supports rotation and scaling of elements + - Supports frames around subtrees + - Transparency for frame colors + + * Introducing MapDesign + - Mapdesign defines how a map looks visually, e.g. colors, frames, + links + - The design can be saved within the map, e.g. with the default map, + which is loaded initially + - MapDesign defines how elements look depending on depth, e.g. + MapCenters and first level MainBranches may have frames, other + branches not. + + * More personalization options + - Mapdesign above allows to save personal preferences for designs in + default maps or easily share them + - Theming has improved + - Dark mode support + - New icons and additional icons for dark mode + - Even selection box can be styled (so far only be modifying + mapdesign in xml file, e.g. using vivym script) + + * Improved text handling in NoteEditor and HeadingEditor + - RichText in headings of branches + - Copy & paste information including bulletpoints and even + images into the heading of a branch + - Improved color handling + - New shortcuts to color text (Ctrl-T) and "mark" background (Ctrl-M) + - Color buttons in toolbar no longer update to current cursor color, + but remember previously selected colors + - [#176](https://github.com/insilmaril/vym/issues/176) Add and follow hyperlinks in TextEditors + - [#168](https://github.com/insilmaril/vym/issues/168) Background style in TextEditors + + * Keyboard shortcuts + - Unified shortcuts for satellite editors + - One key to open a specific editor, e.g. N for NoteEditor, B for Properties + - One key to close each editor: Ctrl-D + - More shortcuts inspired by vim editor without Ctrl/Cmd key: + - D to delete + - Y to yank/copy + - P to paste + - 0/$ to go to first/last branch in current subtree + - U Undo + - / Find + - Repeat last action with . + - Move a branch up/down "diagonally" by making it a sibling or a + child + - Zoom view easily with + and - (without Ctrl) + - Resize items easily with Ctlr-+/- + - Center view on item and reset zoom factor with , + - Center view and zoom in to item with Shift-, + - Move view to make item visible with # + - Heading editor and note editor: color text (Ctrl-T) and "mark" background (Ctrl-M) + + + * Speedup and optimizations + - The layout is calculated only once when data related to graphics + change (internally: less calls to reposition() function) + - When maps are saved, vym still zips the XML-data, but the + compression is done as background process, while vym already is + responsive to user input again. + + * New scripting engine + - Internally the engine was migrated from (no longer supported) + QScriptEngine to QJSEngine + - Scripts can be nested now to improve undo/redo handling and + automated tests + - Various commands have been renamed + - Abstraction of vym, VymModel, and elements like Branch, Image etc. + has been implemented in classes available in scripting (See the + related wrapper classes in C++ source code for details) + +Feel free to report any bugs or feature requests on +[https://github.com/insilmaril/vym/issues](https://github.com/insilmaril/vym/issues) + +Thanks for using vym! + +Uwe Drechsel - July 2026 + +## Unreleased +### Bugfixes + * [#150](https://github.com/insilmaril/vym/issues/150) No more redundant overwrite confirmation on macOS when saving a map, saving an image or exporting; the manual confirmation is kept on Windows and Linux + * [#174](https://github.com/insilmaril/vym/issues/174) Tasks now visible in a new map created from a command-line filename (TaskEditor map filter was left stale) + * [#218](https://github.com/insilmaril/vym/issues/218) Scroll/unscroll of a branch while it is animated no longer breaks its positioning + * Bugfix: MapEditor animation settings not only considered when map is created + * Fixed floating branches (e.g. mainbranches) jumping to a wrong position when dragged and released without relinking; they now stay where they are dropped + * Fixed the first (or a single) dragged branch briefly animating to a wrong position inside the temporary move container + * Fixed downlink to children starting at the branch center (as for a MapCenter) while a mainbranch is being dragged; the original downlink position is now kept + * Fixed orientation of floating children flipping and flickering while their parent branch is being dragged; the orientation is now kept stable during the drag + +## Version 3.0.1 +### Bugfixes + * Fixed wrong x/y positions of branches while moving multiple selected branches with the mouse; they are now animated into their stacked positions (if animations are enabled) + * [#217](https://github.com/insilmaril/vym/issues/217) Moving selected branches to a target can be repeated using "."-key + * [#216](https://github.com/insilmaril/vym/issues/216) Find results don't refresh when switching to another map + +## Version 2.9.617 +### Bugfixes + * [#210](https://github.com/insilmaril/vym/issues/210) BranchPropertyEditor not updated when changing maps + +## Version 2.9.616 +### Features + * Script stats.vys to analyze sizes of subtrees + +### Bugfixes + * [#207](https://github.com/insilmaril/vym/issues/207) Cmd-D not working to close Script output window + * [#206](https://github.com/insilmaril/vym/issues/206) Two dialogs when creating new vymLink + * Fix building with Qt 6.6 + +## Version 2.9.614 +### Bugfixes + * [#189](https://github.com/insilmaril/vym/issues/189) Updated demo maps + +### Changes + * Only ask once to allow vym to download release notes and check for + updates + +## Version 2.9.613 +### Features + * Feature: Notes in Html export are collapsible + +### Bugfixes + * [#204](https://github.com/insilmaril/vym/issues/204) Crash after image/branch manipulation + +## Version 2.9.612 +### Features + * [#197](https://github.com/insilmaril/vym/issues/197) Improved function key handling + - Add shortcuts to color only branch, not whole subtree + * [#194](https://github.com/insilmaril/vym/issues/194) Group keyboard shortcuts + +### Bugfixes + * [#196](https://github.com/insilmaril/vym/issues/196) Xlink control points not accessible when "behind" heading + * Remove double overwrite confirmation on Mac for exporting notes + * Load translations on Mac + +## Version 2.9.610 +### Bugfixes + * [#195](https://github.com/insilmaril/vym/issues/195) Save background color when exporting RichText in TextEditor + +## Version 2.9.609 +### Features + * Improved color handling in text editors + - New shortcuts to color text (Ctrl-T) and "mark" background (Ctrl-M) + - Color buttons in toolbar no longer update to current cursor color, + but remember previously selected colors + +## Version 2.9.608 +### Bugfixes + * When importing maps, don't read mapdesign. + * [#191](https://github.com/insilmaril/vym/issues/191) AddMapReplace crashes for MapCenter + +### Changes + * When clicking on the map, find branches before XLinks + +## Version 2.9.607 +### Bugfixes + * Branches without frames + * [#185](https://github.com/insilmaril/vym/issues/185) After loading a zoomed map is not centered correctly + +## Version 2.9.606 +### Bugfixes + * [#181](https://github.com/insilmaril/vym/issues/181) Relative positioning of images or branches + +## Version 2.9.605 +### Bugfixes + * autoDesign frame settings when loading/saving maps + * [#188](https://github.com/insilmaril/vym/issues/188) save selection + - Added script command isBusy() + - Added script command setSaveAsBackgroundProcess() + + Changed handling of zipping in background. Maps were renamed before zip + was finished. For testing added option to wait for finishing zip as + foreground process, otherwise tests would have failed. + + Also re-added action to file menu to save selection. + + * [#187](https://github.com/insilmaril/vym/issues/187) Make sure zip processes are finished when leaving vym + + Under certain circumstances vym had still background processes when + accepting e.g. a close event from window manager. + + Now MainWindow requests closing a map directly from the vym map. The map + itself triggers it's removal from MainWindow once the zipProcess is done. + + * [#187](https://github.com/insilmaril/vym/issues/187) Missing image in xml of map modifies branches + + +## Version 2.9.604 +### Bugfixes +* [#180](https://github.com/insilmaril/vym/issues/180) in TaskEditor adds heading of parent branch to selected branch +* [#179](https://github.com/insilmaril/vym/issues/179) Changes to frames via script are not saved + + e.g. when using macros bound to function keys to change frames. + + Now autoDesign is disabled when script functions change frames. + +* [#186](https://github.com/insilmaril/vym/issues/186) Exporting note might overwrite export of previous branch +* [#182](https://github.com/insilmaril/vym/issues/182) Zoom and rotation after loading map +* [#183](https://github.com/insilmaril/vym/issues/183) Rotation of subtree not save when changed with shortcut + - Disable autodesign option + + +## Version 2.9.603 +### Features + * Set heading width also for RichText headings + +### Bugfixes + * QThreadStorage: entry 1 destroyed before end of thread when quitting via shortcut cut + +## Version 2.9.601 +### Features + * [#177](https://github.com/insilmaril/vym/issues/177) Toggling frames of multiple selected branches + * [#176](https://github.com/insilmaril/vym/issues/176) Open and edit Urls in TextEditors + * [#176](https://github.com/insilmaril/vym/issues/176) Add and follow hyperlinks in TextEditors + * [#178](https://github.com/insilmaril/vym/issues/178) Don't adapt view to show many selected items + * On Macs open history window with Shift-Cmd-H + +### Bugfixes + * [#175](https://github.com/insilmaril/vym/issues/175) Enable GoTo target when nothing is selected + * Packaging for MACOSX + + +## Version 2.9.599 +### Features + * [#165](https://github.com/insilmaril/vym/issues/165) Switch focus between Find-LineEdit and Find-Results with tab + * [#169](https://github.com/insilmaril/vym/issues/169) AppStream / Metainfo Improvements + * [#167](https://github.com/insilmaril/vym/issues/167) cmake: install resources under share/vym and set VYMBASEDIR + +### Bugfixes + * [#153](https://github.com/insilmaril/vym/issues/153) Center on selected item not subtree when selecting slide + * [#173](https://github.com/insilmaril/vym/issues/173) Scroll to selected task in TaskEditor + * [#161](https://github.com/insilmaril/vym/issues/161) , [#165](https://github.com/insilmaril/vym/issues/165) Focus handling with satellite windows + +## Version 2.9.598 +### Changes + * Use CTRL-S for "Restore session" until map was changed + + Then CTRL-S will become "Save map". This frees up the shortcut to rotate + subtrees with CTRL-R + +### Features + * Shortcuts to rotate subtree (Ctrl-R and Ctrl-Shift-R) + * [#160](https://github.com/insilmaril/vym/issues/160) Support Jira Cloud + * Remember last searches in FindResultWidget + * "Delete" is now equivalent to "Cut" + * [#16](https://github.com/insilmaril/vym/issues/16) Escape-key cancels editing heading of a branch + +### Bugfixes + * [#168](https://github.com/insilmaril/vym/issues/168) Background style in TextEditors + * Undo colorSubtree + +Version 2.9.594 +### Features + * [#162](https://github.com/insilmaril/vym/issues/162) Switch focus between editors using Tab-key + +### Bugfixes + * Bugfix: Forced bright theme when system uses dark theme + +## Version 2.9.593 +### Features + * Y-Key to yank (copy) in Vim style + * Draw border around editor which has keyboard focus + * Exit vym from script + * Repeat last action for multiple actions + +### Bugfixes + * [#80](https://github.com/insilmaril/vym/issues/80) Improved handling of default colors + * [#161](https://github.com/insilmaril/vym/issues/161) Switch back to MapEditor using Esc-Key + * Noteeditor has correct window name + * Consider penWidth of frame + * No bottomline for both inner/outer frame + * Frametype Pipe had wrong dimensions + +## Version 2.9.592 +### Features + * Easy following of references: xLinks, Urls and vymLinks + + If a branch has exactly one reference, Key-F will just "follow" this + reference. Popup menu is only used if multiple references require a + decision. + +## Version 2.9.591 +### Features + * VIM-like shortcuts 0 and $ to select first/last sibling + +### Bugfixes + * Better selection color handling TaskEditor + + Colors also no longer depend if selection was clicked in TE or in ME + + * Allow macros to work on all selected branches + * Craah when closing map while loading + +## Version 2.9.590 +### Features + * Use Key U for undo like in vim + +### Bugfixes + * Avoid crash when zipAgent is no longer available and zipFinished called + * Always enable fileExitVym action + * HTML export correctly exports flags now + * [#158](https://github.com/insilmaril/vym/issues/158) Update Appstream Data + + +## Version 2.9.588 +### Features + * Improving HTML export with flags and dark theme css file + +## Version 2.9.587 +### Changes + * Linkstyle now refers to current branch depth + +### Bugfixes + * Undo/redo for setLinkStyle() + * Remove upLink when detaching mainBranch + +## Version 2.9.586 +### Features + * New scripting commands to iterate over branches + +### Bugfixes + * Missing whitespaces in "Goto linked map menu" + * Bigger circle for positioning when relinking to MapCenter + +## Version 2.9.585 +### Bugfixes + * Intermittent crash when dropping tasks in TaskEditor + +## Version 2.9.584 +### Bugfixes + * [#151](https://github.com/insilmaril/vym/issues/151) Fixed permissions for new directories + +## Version 2.9.583 +### Features + * [#151](https://github.com/insilmaril/vym/issues/151) Use shared renderer for svg flags + +### Bugfixes + * [#151](https://github.com/insilmaril/vym/issues/151) Store vym temporary files in user directory + * Remove warnings by using new svg for "lifebelt" flag + * [#152](https://github.com/insilmaril/vym/issues/152) signed bundle + * Toggle subtree frames with function keys + + +## Version 2.9.582 +### Bugfixes + * [#149](https://github.com/insilmaril/vym/issues/149) Building on Linux + +## Version 2.9.581 +### Bugfixes + * Menu entry to open visible Urls in subtree + * [#148](https://github.com/insilmaril/vym/issues/148) Removed warnings related to old Q\_OS\_MACX macro + +## Version 2.9.580 +### Features + * On Macs Urls can be opened in private mode in Firefox + * Allow drag and drop of images without downloads + * Reset selection size with Ctrl-0 (or Cmd-0) + +### Bugfixes + * Undo/Redo of changing branches and images layouts + * Fixed script to download image after drop event + +## Version 2.9.578 +### Bugfixes + * [#147](https://github.com/insilmaril/vym/issues/147) Default settings TextEditors + +## Version 2.9.577 +### Features + * Improve listing of keyboard shortcuts + +### Bugfixes + * Fixed history tests. 308 tests available + * Undo/Redo for scaling images + +## Version 2.6.569 +### Bugfixes + * Undo/redo for heading column width and autodesign option + * Improved alignment of info in ExtraInfoDialog + +## Version 2.9.567 +### Features + * Initial support to import IThoughts maps + +## Version 2.9.564 +### Bugfixes + * [#136](https://github.com/insilmaril/vym/issues/136) No longer ignore "Accept" in downloads dialog ([#136](https://github.com/insilmaril/vym/issues/136) ) + +## Version 2.9.563 +### Bugfixes + * [#135](https://github.com/insilmaril/vym/issues/135) Don't use STREQUAL on Max + * Minor improvements CMakeLists.txt + +## Version 2.9.562 +### Bugfixes + * Fixed when moving branches up + +## Version 2.9.560 +### Features + * Show keyboard shortcuts in context menus + * On Macs use backspace as shortcut instead of delete + +### Bugfixes + * Crashes when running scripts + * [#123](https://github.com/insilmaril/vym/issues/123) Add io.github.insilmaril.vym.appdata.xml + * Remove shortkey conflict for Key\Plus + * Bugfix: Don't add command from last saveState script, if no script is used + + +## Version 2.9.558 +### Features + * New dialog for logfile settings + * Toggle temporary hide mode + * Temporary hide parts of map + + "Clouded" branches are not exported and can be temporary hidden. + This commit also fixes, that clouded parts are still saved, even while + invisible. + +### Bugfixes + * Stop view animations when wheel is used for scrolling + * Confluence export with Urls containing ampersands + * Deleting children in a new map without path, might cause hang + * Crash with dangling xlinks + * darkTheme handling + +## Version 2.9.557 +### Features + * New icons in MainWindow for more modern look + - based on KDE breeze + - prepared for theming (bright, dark, classic) + * [#35](https://github.com/insilmaril/vym/issues/35) Insert images in NoteEditor + * New icons for NoteEditor and HeadingEditor + * New icon to edit fill color in TextEditors + +### Bugfixes + * Fixed crash related to QJSEngine + If a scriptEngine was destroyed in MainWindow, the engine also deleted + the vymWrapper due to wrong ownership. + + Subsequent scriptEngines got initialized with dangling vymWrapper + pointer + +## Version 2.9.555 +### Bugfixes + * Adjust viewport size when moving items + +## Version 2.9.554 +### Features + * Get Confluence page last edit details + + Add attributes for + - Author + - Timestamp + * [#130](https://github.com/insilmaril/vym/issues/130) Update about dialog to reflect current reality. + * Get labels from Confluence and modify them + - Recursively get page tree of a given page + - Update attributes with metadata from Confluence + - Added script command to delete label in Confluence + - Added demo scripts to find and delete labels from pages + +### Bugfixes + * Fixed iterating branches in scripts. Improved Confluence page details handling + * Updating heading from Confluence URL won't save color + * Get Confluence labels as part of pageInfo + - Updates heading of branch with page title + - Adds page labes as attributes to branch + +## Version 2.9.553 + +### Bugfixes + * Crash when deleting XLinks + * Set and unset Url flag correctly + +## Version 2.9.551 +### Features + * Alignment of imagesContainer relative to branchesContainer + +### Bugfixes + * [#95](https://github.com/insilmaril/vym/issues/95) LibreOffice Impress export improved + * Redo adding xlink + * Toggling flags in groups (incl. undo/redo) + * Ported tests for flags + * Partially update mainbranches and their children during load + +## Version 2.9.550 +### Features + * undo/redo modifying attributes + * Ported tests for legacy maps + +### Bugfixes + * undo/redo of setHideLinkUnselected() and setHideExport() + * undo/redo loadImage() + * undo/redo toggleTarget() + * undo/redo for rotations and scalings + * TaskJuggler export including XSL transformation + * Save position when moving images + +## Version 2.9.549 +### Bugfixes + * add branch before (including undo/redo in one step) + +## Version 2.9.548 +### Features + * Adding a branch and editing heading only has one undo step now + * Only one undo/redo step for adding MapCenters + +### Bugfixes + * [#126](https://github.com/insilmaril/vym/issues/126) write flags and userflags in XML export + * deleting XLinkItem left XLink dangling around + +## Version 2.9.547 + * Use multiple and local scriptEngines + +## Version 2.9.546 +### Features + * Use special Url flag for Jira tickets + + If the attribute "Jira.issueUrl" is set, the system-jira flag will be + used instead of the system-url flag. + + TreeItem class has new methods to set and get the urlType, currently + GeneralUrl and JiraUrl. + + Queries are not really supported yet. + + * [#121](https://github.com/insilmaril/vym/issues/121) Improved editing of cells in the TaskEditor. + +### Changes + * Disabled shortcut to switch to RichText Ctrl-R in TextEditor + Conflicts with shortcut to restore session + +### Bugfixes + * [#120](https://github.com/insilmaril/vym/issues/120) Crash when using bright theme + * Added icon to Bleyddyns patch to clear recent files ([#95](https://github.com/insilmaril/vym/issues/95) ) + * [#119](https://github.com/insilmaril/vym/issues/119) Clear recent menu item + - Added a menu item to clear the recent map menu. + - Changed menu item name to just 'Clear'. For Issue ([#95](https://github.com/insilmaril/vym/issues/95) ) + +## Version 2.9.545 +### Features + * New frame type "Pipe" + * Changing frame colors updates map instantly + * [#118](https://github.com/insilmaril/vym/issues/118) While loading update MapEditor + * Use system services to open local and remote Urls + + By default system specific apps will be used to open pdfs, webpages, + spreadsheets, ... + +### Bugfixes + * Finalized fix for ([#98](https://github.com/insilmaril/vym/issues/98) ) + - Set lastMapDir also for Main::fileSaveAs() + * [#117](https://github.com/insilmaril/vym/issues/117) Update lastMapDir in more places. Fix for [#98](https://github.com/insilmaril/vym/issues/98) . + +## Version 2.9.544 +### Features + * Improved selection of items in map with keyboard + + Introduced selection modes based layout and geometry, e.g. navigating in + grids and orgcharts works now as expected. Also jumping from a branch to + nearest image. + * Select nearest branch below current one + * Set Jira ticket ID in heading + +## Version 2.9.543 +### Bugfixes + * Fixed XLink related scripting + * Fixed restoring window geometry on Windows + +## Version 2.9.542 +### Bugfixes + * Fixed test to add branch above/below + * Fixed adding above/below with undo/redo + +### Changes + * Unified shortcuts for adding branches + + - [Key_A] with modifiers to add + - as child of selection + - insert before selection [Shift + Ctrl] + - above selection [Shift] + - below selection [Ctrl] + +## Version 2.9.538 +### Features + * [#115](https://github.com/insilmaril/vym/issues/115) Update Russian translations vym.ru.ts + +### Bugfixes + * Fixed segfault when exiting vym after running selftests + +### Changes + * Reworked scripting commands: + + Moved from VymModelWrapper to BranchWrapper + - branchCount() + - clearFlags() + - colorBranch() + - colorSubtree() + - selectFirstBranch() + - selectLastBranch() + - selectParent() + +## Version 5.9.537 +### Features + * Macro to toggle task considers dark theme. + + Use new mode file sync (-FS) when zipping directories on Linux and Mac. + Seems also to work similar on Windows 11 using tar. + +## Version 2.9.536 +### Changes + * Reworked saveState and handling of notes and headings + - Continues to work on new saveState function, which no longer uses + undo/redo selection, but uses uses script commands on specific + branches/images, which are found using Uuid. + - Removed parseVymText to to set notes and headings + - Introduced a number of new commands for branches and images + - Introduced ImageWrapper to allow applying commands on images + - Introduced command to check availability of dark theme + + +## Version 2.9.535 +### Bugfixes + * [#113](https://github.com/insilmaril/vym/issues/113) Heading color is lost when note is available + +## Version 2.9.534 +### Changes + * [#112](https://github.com/insilmaril/vym/issues/112) XLinks now use UUID instead of selectionID + + This allows processing XLinks also in XSL transformations. See + +## Version 2.9.533 +### Bugfixes + * Ampersands in notes exported to libreoffice impress + * Fixed unzip on Windows + +## Version 2.9.28 +### Features + * [#109](https://github.com/insilmaril/vym/issues/109) Link app icon as a mimetype icon for the hicolor default theme + + * On Linux/Unix systems cmake already installs the vym.png application + icon (what is referenced via the .desktop file) and a mime type definition + for `application/x-vym`. What is missing is the icon to use on `.vym` + files which are associated with this mime type. Instead of installing + the icon a second time, a relativ symlink is created referencing the app + icon. + +### Bugfixes + * [#107](https://github.com/insilmaril/vym/issues/107) Do not install manpage in doc dir + * Open french documention if required + * Don't autosave while still saving + * [#108](https://github.com/insilmaril/vym/issues/108) Spelling fix: remove duplicate word + +## Version 2.9.532 +### Changes + * Run zip process in foreground when exporting to libreoffice impress. + * zip running as background process on Linux and Mac. + + Windows not ported yet. + +### Features + * Only write images once to zipDir to save time and disk space + +### Bugfixes + * [#105](https://github.com/insilmaril/vym/issues/105) Spelling fixes + * [#106](https://github.com/insilmaril/vym/issues/106) Desktop file improvements + diff --git a/src/branch-container-base.cpp b/src/branch-container-base.cpp index a9eebd5..ce5f49d 100644 --- a/src/branch-container-base.cpp +++ b/src/branch-container-base.cpp @@ -46,7 +46,7 @@ int BranchContainerBase::branchCount() if (!branchesContainer) return 0; else - return branchesContainer->childItems().count(); + return branchesContainer->childContainers().count(); } void BranchContainerBase::addToBranchesContainer(BranchContainer *bc) {} @@ -61,7 +61,7 @@ int BranchContainerBase::imageCount() if (!imagesContainer) return 0; else - return imagesContainer->childItems().count(); + return imagesContainer->childContainers().count(); } void BranchContainerBase::createImagesContainer() {} @@ -79,7 +79,7 @@ QList BranchContainerBase::childBranches() if (!branchesContainer) return list; - foreach (QGraphicsItem *g_item, branchesContainer->childItems()) + foreach (QGraphicsItem *g_item, branchesContainer->childContainers()) list << (BranchContainer*)g_item; return list; @@ -91,7 +91,7 @@ QList BranchContainerBase::childImages() if (!imagesContainer) return list; - foreach (QGraphicsItem *g_item, imagesContainer->childItems()) + foreach (QGraphicsItem *g_item, imagesContainer->childContainers()) list << (ImageContainer*)g_item; return list; diff --git a/src/branch-container.cpp b/src/branch-container.cpp index 5b616f4..5cfad2d 100644 --- a/src/branch-container.cpp +++ b/src/branch-container.cpp @@ -58,7 +58,7 @@ void BranchContainer::init() // BranchContainer defaults // partially overwriting MinimalBranchContainer // can be overwritten by MapDesign later - containerType = Container::Branch; + setContainerType(Container::Branch); setLayout(Container::Horizontal); @@ -95,12 +95,12 @@ void BranchContainer::init() outerFrame = nullptr; ornamentsContainer = new Container; - ornamentsContainer->containerType = OrnamentsContainer; + ornamentsContainer->setContainerType(OrnamentsContainer); linkContainer = new LinkContainer; innerContainer = new Container; - innerContainer->containerType = InnerContainer; + innerContainer->setContainerType(InnerContainer); standardFlagRowContainer = nullptr; systemFlagRowContainer = nullptr; @@ -267,7 +267,7 @@ void BranchContainer::addToBranchesContainer(BranchContainer *bc) // (It will be deleted later in updateChildrenStructure(), if there // are no children) branchesContainer = new Container(); - branchesContainer->containerType = Container::BranchesContainer; + branchesContainer->setContainerType(Container::BranchesContainer); branchesContainer->zPos = Z_BRANCHES; branchesContainer->setLayout(branchesContainerLayoutInt); branchesContainer->setVerticalAlignment( @@ -289,8 +289,9 @@ void BranchContainer::createOuterContainer() { if (!outerContainer) { outerContainer = new Container; - outerContainer->containerType = OuterContainer; + outerContainer->setContainerType(OuterContainer); outerContainer->setLayout(BoundingFloats); + outerContainer->setCentralContainer(headingContainer); // heading will be in origin addContainer(outerContainer); // Children structure is updated in updateChildrenStructure(), which is @@ -309,12 +310,36 @@ void BranchContainer::deleteOuterContainer() addContainer(innerContainer); if (imagesContainer) innerContainer->addContainer(imagesContainer); + if (branchesContainer) + innerContainer->addContainer(branchesContainer); delete outerContainer; outerContainer = nullptr; } } +void BranchContainer::createImagesAndBranchesContainer() +{ + if (imagesAndBranchesContainer) + return; + + imagesAndBranchesContainer = new Container; + imagesAndBranchesContainer->setContainerType(Container::ImagesAndBranchesContainer); + innerContainer->addContainer(imagesAndBranchesContainer, + Z_IMAGE); +} + +void BranchContainer::deleteImagesAndBranchesContainer() +{ + if (!imagesAndBranchesContainer) + return; + + updateImagesContainerParent(); + updateBranchesContainerParent(); + delete imagesAndBranchesContainer; + imagesAndBranchesContainer = nullptr; +} + void BranchContainer::updateTransformations() { MapDesign *md = nullptr; @@ -365,7 +390,6 @@ void BranchContainer::updateTransformations() void BranchContainer::updateChildrenStructure() { - logDebug("BC::updateChildrenStructure of " + info()); if (branchesContainerLayoutInt == List) { if (!listContainer) { // Create and setup a listContainer *below* the ornamentsContainer @@ -375,7 +399,7 @@ void BranchContainer::updateChildrenStructure() // listContainer has one linkSpaceContainer left of // branchesContainer listContainer = new Container; - listContainer->containerType = Container::ListContainer; + listContainer->setContainerType(Container::ListContainer); listContainer->setLayout(Horizontal); if (linkSpaceContainer) listContainer->addContainer(linkSpaceContainer); @@ -405,36 +429,26 @@ void BranchContainer::updateChildrenStructure() // depends on layouts of imagesContainer and branchesContainer: // // Usually both inagesContainer and branchesContainer are children of - // innerContainer. The layout of innerContainer is either Horizontal or - // BoundingFloats. outerContainer is only needed in corner case d) + // innerContainer. The layout of innerContainer is Horizontal. // // a) No FloatingBounded children // - No outerContainer - // - innerContainer is Horizontal - // - branchesContainer is not FloatingBounded - // - if imagesContainer is not floating: - // - Check imagesPosition(), where images should be relative to - // children branches // // b) Only branches are FloatingBounded - // - No outerContainer - // - innerContainer BoundingFloats - // - branchesContainer is FloatingBounded - // - imagesContainer is FloatingFree + // - outerContainer contains + // - innerContainer + // - branchesContainer // // c) images and branches are FloatingBounded - // - No outerContainer - // - innerContainer BoundingFloats - // - branchesContainer is FloatingBounded - // - imagesContainer is FloatingBounded + // - outerContainer contains + // - innerContainer + // - imagesContainer + // - branchesContainer // // d) Only images are FloatingBounded // - outerContainer contains // - innerContainer // - imagesContainer - // - innerContainer is Horizontal - // - branchesContainer is Vertical - // - imagesContainer is FloatingBounded // qDebug() << "BC::updateChildrenStructure() of " << info(); @@ -460,15 +474,15 @@ void BranchContainer::updateChildrenStructure() Container::Vertical; // FIXME-3 get from MapDesign if (!imagesAndBranchesContainer) { imagesAndBranchesContainer = new Container; - imagesAndBranchesContainer->containerType = - Container::ImagesAndBranchesContainer; + imagesAndBranchesContainer->setContainerType(Container::ImagesAndBranchesContainer); innerContainer->addContainer(imagesAndBranchesContainer, Z_IMAGE); - imagesAndBranchesContainer->addContainer( - imagesContainer); - imagesAndBranchesContainer->addContainer( - branchesContainer); } + if (imagesContainer->parentContainer() != imagesAndBranchesContainer) + imagesAndBranchesContainer->addContainer(imagesContainer); + if (branchesContainer->parentContainer() != imagesAndBranchesContainer) + imagesAndBranchesContainer->addContainer(branchesContainer); + imagesAndBranchesContainer->setLayout(ibcl); if (imagesFirst) // FIXME-3 Check for imagesPosition // relative to branches, hardcoded for now @@ -478,15 +492,8 @@ void BranchContainer::updateChildrenStructure() } else { // No imagesAndBranchesContainer required - // - // TODO Remove imagesAndBranchesCont, relink imagesCont and - // branchesCont - if (imagesAndBranchesContainer) { - updateImagesContainerParent(); - updateBranchesContainerParent(); - delete imagesAndBranchesContainer; - imagesAndBranchesContainer = nullptr; - } + if (imagesAndBranchesContainer) + deleteImagesAndBranchesContainer(); } } } @@ -494,28 +501,35 @@ void BranchContainer::updateChildrenStructure() else if (branchesContainerLayoutInt == FloatingBounded && imagesContainerLayoutInt != FloatingBounded) { // b) Only branches are FloatingBounded - deleteOuterContainer(); - innerContainer->setLayout(BoundingFloats); + createOuterContainer(); + if (imagesAndBranchesContainer) + deleteImagesAndBranchesContainer(); + innerContainer->setLayout(Horizontal); } else if (branchesContainerLayoutInt == FloatingBounded && imagesContainerLayoutInt == FloatingBounded) { // c) images and branches are FloatingBounded - deleteOuterContainer(); - innerContainer->setLayout(BoundingFloats); + createOuterContainer(); + if (imagesAndBranchesContainer) + deleteImagesAndBranchesContainer(); + innerContainer->setLayout(Horizontal); } else if (branchesContainerLayoutInt != FloatingBounded && imagesContainerLayoutInt == FloatingBounded) { // d) Only images are FloatingBounded createOuterContainer(); + if (imagesAndBranchesContainer) + deleteImagesAndBranchesContainer(); + if (listContainer) innerContainer->setLayout(Vertical); else innerContainer->setLayout(Horizontal); + } else { - // e) remaining cases - deleteOuterContainer(); - innerContainer->setLayout(FloatingBounded); + // e) remaining cases, should not happen + qWarning() << __func__ << " mess of layouts."; } updateTransformations(); @@ -528,8 +542,19 @@ void BranchContainer::updateChildrenStructure() else outerContainer->setParentItem(this); outerContainer->addContainer(innerContainer); - if (imagesContainer) - outerContainer->addContainer(imagesContainer); + if (imagesContainer) { + if (imagesContainer->layoutInt == FloatingBounded) + outerContainer->addContainer(imagesContainer); + else + innerContainer->addContainer(imagesContainer); + } + + if (branchesContainer) { + if (branchesContainer->layoutInt == FloatingBounded) + outerContainer->addContainer(branchesContainer); + else + innerContainer->addContainer(branchesContainer); + } } // Structure for bullet point list layouts @@ -606,7 +631,7 @@ void BranchContainer::updateChildrenStructure() void BranchContainer::updateImagesContainer() { - if (imagesContainer && imagesContainer->childItems().count() == 0) { + if (imagesContainer && imagesContainer->childContainers().count() == 0) { delete imagesContainer; imagesContainer = nullptr; } @@ -626,7 +651,7 @@ void BranchContainer::createImagesContainer() // The destructor of ImageItem calls // updateChildrenStructure() in parentBranch() imagesContainer = new Container(); - imagesContainer->containerType = ImagesContainer; + imagesContainer->setContainerType(ImagesContainer); imagesContainer->setLayout(imagesContainerLayoutInt); updateImagesContainerParent(); @@ -673,12 +698,12 @@ QPointF BranchContainer::getPositionHintNewChild(Container *c) bool useCircle = false; int n = 0; qreal radius; - if (c->containerType == Branch && hasFloatingBranchesLayout()) { + if (c->containerTypeInt == Branch && hasFloatingBranchesLayout()) { useCircle = true; radius = 190; n = branchCount(); } - else if (c->containerType == Image && hasFloatingImagesLayout()) { + else if (c->containerTypeInt == Image && hasFloatingImagesLayout()) { useCircle = true; radius = 100; n = imageCount(); @@ -714,8 +739,10 @@ QPointF BranchContainer::downLinkPos(const Orientation &orientationChild) ornamentsContainer->bottomCenter()); if (frameType(true) != FrameContainer::NoFrame) { - if (!parentBranchContainer()) + if (!parentBranchContainer() && movingStateInt != Moving) // Framed MapCenter: Use center of frame // FIXME-3 downLinkPos should depend on layout, not depth + // While moving, parentBranchContainer() also returns nullptr, but a + // moved branch must keep its edge downLinkPos, not the center. return ornamentsContainer->mapToScene(ornamentsContainer->center()); else { // Framed branch: Use left or right edge @@ -849,7 +876,7 @@ void BranchContainer::updateUpLink() } // Color of link (depends on current parent) - if (upLink->linkColorHint() == LinkObj::HeadingColor) + if (branchItem->mapDesign()->linkColorHint() == LinkObj::HeadingColor) upLink->setLinkColor(branchItem->headingColor()); else { if (branchItem) @@ -885,7 +912,7 @@ void BranchContainer::updateUpLink() void BranchContainer::setLayout(const Layout &l) { - if (containerType != Branch && containerType != TmpParent) + if (containerTypeInt != Branch && containerTypeInt != TmpParent) qWarning() << "BranchContainer::setLayout (...) called for non-branch: " << info(); Container::setLayout(l); @@ -1416,7 +1443,13 @@ void BranchContainer::reposition() // on MovingState if (pbc) { if (pbc->hasFloatingBranchesLayout()) { - if (scenePos().x() > pbc->scenePos().x()) // FIXME-3 Potentially problematic for rotated elements... + if (pbc->movingState() == Moving) { + // While the parent is being dragged its container origin + // (used as reference below) is not stable, so recomputing + // the orientation would make the children flip and flicker. + // Keep the orientation the child had before the drag. + } + else if (scenePos().x() > pbc->scenePos().x()) // FIXME-3 Potentially problematic for rotated elements... // but OTOH using relative coord // often pos.x() == 0 orientation = RightOfParent; @@ -1447,11 +1480,6 @@ void BranchContainer::reposition() if (depth == 0) { // MapCenter setHorizontalDirection(LeftToRight); - // FIXME-3 set in updateChildrenStructure: - // innerContainer->setHorizontalDirection(LeftToRight); - - // FIXME-3 set in updateChildrenStructure: - // innerContainer->setLayout(BoundingFloats); } else { // Branch or mainbranch diff --git a/src/branch-container.h b/src/branch-container.h index 8f0fe7c..e437609 100644 --- a/src/branch-container.h +++ b/src/branch-container.h @@ -50,6 +50,8 @@ class BranchContainer : public BranchContainerBase, public LinkableContainer { private: void createOuterContainer(); //! Used if only images have FloatingBounded layout void deleteOuterContainer(); + void createImagesAndBranchesContainer(); + void deleteImagesAndBranchesContainer(); void updateTransformations(); //! Update rotation and scaling public: diff --git a/src/branch-wrapper.cpp b/src/branch-wrapper.cpp index aa9e72c..e0983c6 100644 --- a/src/branch-wrapper.cpp +++ b/src/branch-wrapper.cpp @@ -172,6 +172,16 @@ QString BranchWrapper::attributeAsString(const QString &key) return r; } +BranchWrapper* BranchWrapper::branchAt(int pos) +{ + BranchItem* bi = branchItemInt->getBranchNum(pos); + if (!bi) { + mainWindow->abortScript(QJSValue::GenericError,"Couldn't find branch at position " + QString::number(pos)); + return nullptr; + } else + return bi->branchWrapper(); +} + int BranchWrapper::branchCount() { int r = branchItemInt->branchCount(); diff --git a/src/branch-wrapper.h b/src/branch-wrapper.h index a7a386b..ef07ee9 100644 --- a/src/branch-wrapper.h +++ b/src/branch-wrapper.h @@ -29,6 +29,7 @@ class BranchWrapper : public QObject { const QString &color, const QString &penstyle); int attributeAsInt(const QString &key); QString attributeAsString(const QString &key); + Q_INVOKABLE BranchWrapper* branchAt(int n); int branchCount(); void clearFlags(); void colorBranch(const QString &color); diff --git a/src/branchitem.cpp b/src/branchitem.cpp index 394b45f..e98e436 100644 --- a/src/branchitem.cpp +++ b/src/branchitem.cpp @@ -160,32 +160,34 @@ QString BranchItem::saveToDir(const QString &tmpdir, const QString &prefix, else elementName = "branch"; + // qDebug() << "BI::saveToDir elName=" << elementName << " bc=" << branchContainer; + // Free positioning of children - if (!branchContainer->branchesContainerAutoLayout) + if (branchContainer && !branchContainer->branchesContainerAutoLayout) // Save the manually set layout for children branches attr += attribute("branchesLayout", branchContainer->layoutString(branchContainer->branchesContainerLayout())); - if (!branchContainer->imagesContainerAutoLayout) + if (branchContainer && !branchContainer->imagesContainerAutoLayout) // Save the manually set layout for children Images attr += attribute("imagesLayout", branchContainer->Container::layoutString(branchContainer->imagesContainerLayout())); - if (!branchContainer->rotationsAutoDesign()) { + if (branchContainer && !branchContainer->rotationsAutoDesign()) { attr += attribute("rotHeading", QString("%1").arg(branchContainer->rotationHeading())); attr += attribute("rotSubtree", QString("%1").arg(branchContainer->rotationSubtree())); } - if (!branchContainer->scaleAutoDesign()) { + if (branchContainer && !branchContainer->scaleAutoDesign()) { attr += attribute("scaleHeading", QString("%1").arg(branchContainer->scaleHeading())); attr += attribute("scaleSubtree", QString("%1").arg(branchContainer->scaleSubtree())); } // width of heading - if (!branchContainer->columnWidthAutoDesign()) + if (branchContainer && !branchContainer->columnWidthAutoDesign()) attr += attribute("colWidth", QString("%1").arg(branchContainer->getHeadingContainer()->columnWidth())); - if (parentItem == rootItem || branchContainer->isFloating()) + if (parentItem == rootItem || (branchContainer && branchContainer->isFloating())) attr += getPosAttr(); QString s = beginElement(elementName + " " + attr); @@ -199,9 +201,20 @@ QString BranchItem::saveToDir(const QString &tmpdir, const QString &prefix, s += note.saveToDir(); // Save frame - if (branchContainer->frameType(true) != FrameContainer::NoFrame || - branchContainer->frameType(false) != FrameContainer::NoFrame) + if (branchContainer && + (branchContainer->frameType(true) != FrameContainer::NoFrame || + branchContainer->frameType(false) != FrameContainer::NoFrame) + ) { + // Save if frame is used s += branchContainer->saveFrame(); + } else { + if (branchContainer && + model->mapDesign()->frameType(true, depth()) != FrameContainer::NoFrame && + branchContainer->frameType(true) == FrameContainer::NoFrame + ) + // Save if no frame is used and MapDesign would use one + s += singleElement("frame", "autoDesign=\"false\" frameType=\"NoFrame\""); + } // save names of flag set s += standardFlags.saveState(); diff --git a/src/buildinfo.h b/src/buildinfo.h new file mode 100644 index 0000000..6a18241 --- /dev/null +++ b/src/buildinfo.h @@ -0,0 +1 @@ +#define __VYM_BUILD_DATE "2026-07-21" diff --git a/src/buildinfo.h.in b/src/buildinfo.h.in new file mode 100644 index 0000000..4b86655 --- /dev/null +++ b/src/buildinfo.h.in @@ -0,0 +1 @@ +#define __VYM_BUILD_DATE "${BUILD_DATE_IN}" diff --git a/src/confluence-agent.cpp b/src/confluence-agent.cpp index aeb8a72..c3aaed8 100644 --- a/src/confluence-agent.cpp +++ b/src/confluence-agent.cpp @@ -207,7 +207,7 @@ void ConfluenceAgent::continueJob(int nextStep) return; } if (jobStep == 3) { - model = mainWindow->getModel(modelID); + model = mainWindow->modelWithId(modelID); if (model) { BranchItem *bi = (BranchItem *)(model->findID(branchID)); @@ -264,7 +264,7 @@ void ConfluenceAgent::continueJob(int nextStep) } if (jobStep == 5) { - model = mainWindow->getModel(modelID); + model = mainWindow->modelWithId(modelID); if (model) { BranchItem *bi = (BranchItem *)(model->findID(branchID)); @@ -379,7 +379,7 @@ void ConfluenceAgent::continueJob(int nextStep) if (jobStep == 4) { // qDebug() << "CA::finished Created page with ID: " << pageObj["id"].toString(); // cout << QJsonDocument(pageObj).toJson(QJsonDocument::Indented).toStdString(); - model = mainWindow->getModel(modelID); + model = mainWindow->modelWithId(modelID); if (model) { pageURL = QString("https://%1/pages/viewpage.action?pageId=%2") .arg(baseURL).arg(pageObj["id"].toString()); @@ -453,7 +453,7 @@ void ConfluenceAgent::continueJob(int nextStep) mainWindow->statusMessage( QString("Updated Confluence page %1").arg(pageURL)); - model = mainWindow->getModel(modelID); + model = mainWindow->modelWithId(modelID); if (model) { pageURL = QString("https://%1/pages/viewpage.action?pageId=%2") .arg(baseURL).arg(pageObj["id"].toString()); diff --git a/src/container.cpp b/src/container.cpp index ea7a1f5..8e62fc6 100644 --- a/src/container.cpp +++ b/src/container.cpp @@ -30,7 +30,7 @@ Container::~Container() void Container::copy(Container *other) { - containerType = other->containerType; + containerTypeInt = other->containerTypeInt; originalPos = other->originalPos; name = other->name; @@ -43,7 +43,7 @@ void Container::copy(Container *other) void Container::init() { - containerType = UndefinedType; + containerTypeInt = UndefinedType; layoutInt = Horizontal; // subcontainers usually may influence position @@ -71,9 +71,9 @@ void Container::init() show(); } -Container::ContainerType Container::getContainerType() +Container::ContainerType Container::containerType() { - return containerType; + return containerTypeInt; } int Container::type() const @@ -83,18 +83,28 @@ int Container::type() const void Container::setContainerType(const Container::ContainerType &t) { - containerType = t; + containerTypeInt = t; + /* + if ( t == Branch) + addDebugGraphics(Qt::blue); + else if ( t == InnerContainer) + addDebugGraphics(Qt::green); + else if ( t == ImagesContainer) + addDebugGraphics(Qt::red); + else if ( t == BranchesContainer) + addDebugGraphics(Qt::cyan); + */ } -void Container::setName(const QString &n) // FIXME-4 debugging only +void Container::setName(const QString &n) // debugging only { name = n; } -QString Container::getName() // FIXME-4 debugging only +QString Container::getName() // debugging only { QString t; - switch (containerType) { + switch (containerTypeInt) { case Branch: t = "Branch"; break; @@ -116,6 +126,9 @@ QString Container::getName() // FIXME-4 debugging only case Image: t = "Image"; break; + case ImagesAndBranchesContainer: + t = "ImagesAndBranchesContainer"; + break; case ImagesContainer: t = "ImagesContainer"; break; @@ -147,7 +160,7 @@ QString Container::getName() // FIXME-4 debugging only t = "Undefined"; break; default: - t = "Unknown"; + t = QString("Unknown (%1)").arg(containerTypeInt); break; } return QString("[%1]").arg(t); @@ -159,8 +172,8 @@ QString Container::info (const QString &prefix) + getName() + QString(" z: %1").arg(zPos) //+ QString(" a: %1").arg(qRound(rotation())) - //+ QString(" scenePos: %1").arg(toS(scenePos(), 0)) - //+ QString(" pos: %1").arg(toS(pos(), 0)) + + QString(" scenePos: %1").arg(toS(scenePos(), 0)) + + QString(" pos: %1").arg(toS(pos(), 0)) + QString(" rect: %1").arg(toS(rect(), 0)) //+ QString(" sceneRect: %1").arg(toS(mapRectToScene(rect()), 0)) //+ QString(" vis: %1").arg(isVisible()); @@ -210,6 +223,17 @@ QString Container::ind() return s; } +void Container::addDebugGraphics(const QColor &col) +{ + setPen(col); + QGraphicsLineItem *line1 = new QGraphicsLineItem(this); + line1->setPen(col); + line1->setLine(0, -5, 0, 5); + QGraphicsLineItem *line2 = new QGraphicsLineItem(this); + line2->setPen(col); + line2->setLine(-5, 0, 5, 0); +} + QPointF Container::pointByName(PointName pn) { switch (pn) { @@ -449,12 +473,12 @@ QPointF Container::alignTo(PointName ownPointName, Container* targetContainer, P return mapFromItem(targetContainer, targetContainer->pointByName(targetPointName)) - pointByName(ownPointName); } -#include // FIXME-2 debugging +#include // FIXME-3 debugging void Container::addContainer(Container *c, int z) { if (childContainers().contains(c)) return; - if (!c) { // FIXME-2 debugging + if (!c) { // FIXME-3 debugging. Still occured in 2.9.608, very rare logDebug("Container::addContainer adding 0 to " + info() + " would crash"); QMessageBox::warning(0, "Warning", "Would have crashed now in ::addContainer"); return; @@ -544,7 +568,7 @@ QPointF Container::getOriginalPos() void Container::reposition() { - // qdbg() << ind() << QString("### Reposition of %1").arg(info()) << " childCount=" << childContainers().count(); + //qdbg() << ind() << QString("### Reposition of %1").arg(info()) << " childCount=" << childContainers().count(); // Repositioning is done recursively: // First the size sizes of subcontainers are calculated, @@ -573,16 +597,13 @@ void Container::reposition() switch (layoutInt) { case BoundingFloats: { - // qdbg() << ind() << " - BF starting for " << info(); + //qdbg() << ind() << " - BoundingFloats starting for " << info(); - // BoundingFloats is special case: - // Only used for innerContainer or outerContainer - // First child container is ornamentsContainer (or innerContainer), - // next children are imagesContainer and/or branchesContainer + // BoundingFloats is special case: Only used for outerContainer - if (childContainers().count() > 4 ) { + if (childContainers().count() > 3 ) { qWarning() << "Container::reposition " << info(); - qWarning() << "Wrong number of children containers: " << childItems().count(); + qWarning() << "Too many children containers: " << childContainers().count(); foreach (Container *c, childContainers()) qdbg() << " " << c->info(); @@ -599,6 +620,7 @@ void Container::reposition() } // Translate everything, so that center of rectangle is in origin + // Required, because vert/horiz layouts expect it so atm QPointF t = bbox.center(); foreach (Container *c, childContainers()) c->setPos(c->pos() - t); @@ -606,11 +628,11 @@ void Container::reposition() setRect(bbox); - // qdbg() << ind() << " - BF finished for " << info(); + //qdbg() << ind() << " - BF finished for " << info(); // << " t=" << toS(t); } // BoundingFloats layout break; - case FloatingReservedSpace: // FIXME-3 not used at all... why? + case FloatingReservedSpace: // FIXME-3 Only used by TmpParentContainer { // Size is calculated already in MapEditor: @@ -681,7 +703,6 @@ void Container::reposition() } setRect(r); - //qdbg() << ind() << " + FloatingBounded r=" << toS(r) << " pos=" << pos() << getName(); } break; @@ -696,7 +717,7 @@ void Container::reposition() // qdbg() << ind() << " * HL starting for " << info(); foreach (Container *c, childContainers()) { - if (!c->overlay) { + if (!c->overlay && c->layoutInt != FloatingBounded) { QRectF c_bbox = mapRectFromItem(c, c->rect()); w_total += c_bbox.width(); @@ -706,35 +727,36 @@ void Container::reposition() } // Left (or right) line, where next children will be aligned to - qreal x = - w_total / 2; + qreal x_current = - w_total / 2; if (horizontalDirection == RightToLeft) - x = -x; + x_current = -x_current; // Position children initially. (So far only centered vertically) foreach (Container *c, childContainers()) { - if (!c->overlay) { + if (!c->overlay && c->layoutInt != FloatingBounded) { QRectF c_bbox = mapRectFromItem(c, c->rect()); QPointF origin_mapped = mapFromItem(c, QPointF()); - qreal offset; + QPointF offset; // Upper left corner of c_bbox in my coords // Pre alignment if (horizontalDirection == LeftToRight) - offset = - (c_bbox.left() - origin_mapped.x()); + offset.setX( - (c_bbox.left() - origin_mapped.x())); else - offset = - (c_bbox.right() - origin_mapped.x()); - - // qdbg() << ind() << " HL x=" << x << " offset=" << offset << " c: " << c->info(); + offset.setX( - (c_bbox.right() - origin_mapped.x())); + //offset.setY(origin_mapped.y()); + //offset.setY( - 0.5 * (c_bbox.top() + c_bbox.bottom())); + // qdbg() << ind() << " HL x_current=" << x_current << " offset=" << offset << " c: " << c->info(); switch (verticalAlignmentInt) { case VertAlignedTop: - c->setPos (x + offset, - (h_max - c_bbox.height()) / 2); + c->setPos (x_current + offset.x(), - (h_max - c_bbox.height()) / 2); break; case VertAlignedBottom: - c->setPos (x + offset, + (h_max - c_bbox.height()) / 2); + c->setPos (x_current + offset.x(), + (h_max - c_bbox.height()) / 2); break; case VertAlignedCentered: // consider mapped(!) dimensions - c->setPos (x + offset, 0); + c->setPos (x_current + offset.x(), offset.y()); break; default: @@ -744,9 +766,9 @@ void Container::reposition() // Post alignment if (horizontalDirection == LeftToRight) { - x += c_bbox.width(); + x_current += c_bbox.width(); } else - x -= c_bbox.width(); + x_current -= c_bbox.width(); // qdbg() << ind() << " HL Done positioning: " << c->info(); } // No overlay container @@ -755,7 +777,10 @@ void Container::reposition() // Move everything, so that center of central container will be in origin QPointF v_central; + if (centralContainer) { + // qdbg() << ind() << " * centralContainer = " << centralContainer->info(); + // Now we might want to adjust positions of children, so // that centralContainer (==headingContainer) keeps its position // This may happen, if @@ -763,18 +788,24 @@ void Container::reposition() // - I am a MapCenter myself if ((parentContainer() && parentContainer()->hasFloatingLayout()) || !parentContainer() ) { v_central = mapFromItem(centralContainer, centralContainer->rect().center()); + // qdbg() << ind() << " * v_central=" << toS(v_central); if (!v_central.isNull()) { foreach (Container *c, childContainers()) { - if (!c->overlay) + if (!c->overlay && c->layoutInt != FloatingBounded) c->setPos(c->pos() - v_central); } } } - } + } //else + //qdbg() << ind() << " * No central containe"; - setRect(QRectF(- w_total / 2 - v_central.x(), - h_max / 2 - v_central.y(), w_total, h_max)); + setRect(QRectF( + - w_total / 2 - v_central.x(), + - h_max / 2 - v_central.y(), + w_total, + h_max)); - // qdbg() << ind() << " * HL Finished for " << info(); + //qdbg() << ind() << " * HL Finished for " << info(); } // Horizontal layout break; @@ -854,6 +885,7 @@ void Container::reposition() case List: case Vertical: { + // qdbg() << ind() << " # VL starting for " << info(); qreal h_total = 0; qreal w_max = 0; @@ -887,7 +919,7 @@ void Container::reposition() break; default: qWarning() << "Container::reposition vertically - undefined alignment:" << horizontalAlignmentInt << " in " << info(); - if (containerType == BranchesContainer) + if (containerTypeInt == BranchesContainer) qWarning() << " orient=" << ((BranchContainer*)this)->getOrientation(); } @@ -897,6 +929,8 @@ void Container::reposition() // Set rect setRect(-w_max / 2, -h_total / 2, w_max, h_total); + // qdbg() << ind() << " # VL finished for " << info(); + } // Vertical layout break; default: diff --git a/src/container.h b/src/container.h index 552cf14..30d8c0f 100644 --- a/src/container.h +++ b/src/container.h @@ -80,7 +80,7 @@ class Container : public QGraphicsRectItem { virtual void init(); void setContainerType(const ContainerType &t); - ContainerType getContainerType(); + ContainerType containerType(); enum {Type = UserType + 1}; int type() const override; @@ -95,6 +95,8 @@ class Container : public QGraphicsRectItem { int containerDepth(); QString ind(); + void addDebugGraphics(const QColor &col); + // Convenience coordinates QPointF pointByName(PointName pn); QPointF topLeft(); @@ -166,7 +168,7 @@ class Container : public QGraphicsRectItem { virtual void reposition(); protected: - ContainerType containerType; + ContainerType containerTypeInt; bool overlay; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 59eb2d5..2854781 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -1,5 +1,6 @@ #include "debuginfo.h" + #include #include #include @@ -9,6 +10,8 @@ #include #include +#include "buildinfo.h" +#include "git.h" #include "settings.h" extern bool usingDarkTheme; @@ -41,11 +44,12 @@ extern QString zipToolPath; QString debugInfo() { QString s; - s = QString("vym version: %1 - %2 - %3 %4\n") + s = QString("vym version: %1 - %2 - \"%3\" Quality: %4\n") .arg(vymVersion) .arg(vymBuildDate) - .arg(vymCodeQuality) - .arg(vymCodeName); + .arg(vymCodeName) + .arg(vymCodeQuality); + s += QString(" git: \"%1\" branch - commit %2\n").arg(GIT_BRANCH, GIT_COMMIT_HASH); s += QString(" Platform: %1\n").arg(vymPlatform); s += QString(" tmpVymDir: %1\n").arg(tmpVymDir.path()); s += QString(" zipToolPath: %1\n").arg(zipToolPath); diff --git a/src/export-base.cpp b/src/export-base.cpp index 878e2d4..27dc924 100644 --- a/src/export-base.cpp +++ b/src/export-base.cpp @@ -38,6 +38,7 @@ ExportBase::~ExportBase() void ExportBase::init() { + blockMapChangedDuringExport = false; indentPerDepth = " "; exportName = "unnamed"; lastCommand = ""; @@ -47,6 +48,11 @@ void ExportBase::init() dirPath = defaultDirPath; } +void ExportBase::setBlockMapChangedDuringExport(bool b) +{ + blockMapChangedDuringExport = b; +} + void ExportBase::setupTmpDir() { bool ok; @@ -110,6 +116,9 @@ bool ExportBase::execDialog() QFileDialog::DontConfirmOverwrite); if (!fn.isEmpty()) { + +// Macs check for replacing existing file in native dialog +#ifndef Q_OS_MACOS if (QFile(fn).exists()) { WarningDialog dia; dia.showCancelButton(true); @@ -125,6 +134,7 @@ bool ExportBase::execDialog() return false; } } +#endif dirPath = fn.left(fn.lastIndexOf("/")); filePath = fn; return true; @@ -166,7 +176,7 @@ void ExportBase::completeExport(QStringList args) model->setExportLastDescription(exportName); // Trigger saving of export command if it has changed - if (model && (lastCommand != command)) + if (model && !blockMapChangedDuringExport && (lastCommand != command)) model->setChanged(); switch (result) { diff --git a/src/export-base.h b/src/export-base.h index e648c2b..4d816db 100644 --- a/src/export-base.h +++ b/src/export-base.h @@ -21,6 +21,7 @@ class ExportBase { ExportBase(VymModel *m); virtual ~ExportBase(); virtual void init(); + virtual void setBlockMapChangedDuringExport(bool b); virtual void setupTmpDir(); virtual void setDirPath(const QString &); virtual QString getDirPath(); @@ -43,6 +44,7 @@ class ExportBase { protected: VymModel *model; + bool blockMapChangedDuringExport; // block changing map in chained exports QString exportName; QString lastCommand; virtual QString getSectionString(TreeItem *); diff --git a/src/export-html.cpp b/src/export-html.cpp index f2059da..6f3e9c1 100644 --- a/src/export-html.cpp +++ b/src/export-html.cpp @@ -223,9 +223,10 @@ QString ExportHTML::getBranchText(BranchItem *current) if (current->getNote().getFontHint() == "fixed") n = "
" + n + "
"; } - s += "\n
\n\n" + - n + "\n
\n"; + s += "\n\n" + "
\n" + + n + + "\n
\n"; } return s; } @@ -371,16 +372,26 @@ void ExportHTML::doExport(bool useDialog) QObject::tr("Could not find stylesheet %1").arg(cssSrc)); return; } - QFile src(cssSrc); + QString cssContent; + if (!loadStringFromDisk(cssSrc, cssContent)) { + QMessageBox::critical( + 0, QObject::tr("Error", "ExportHTML"), + QObject::tr("Could not read \n%1", "ExportHTML") + .arg(cssSrc)); + return; + } + + // Replace mapBackgroundColor placeholder with actual map background color + cssContent.replace("$MapBackgroundColor", model->backgroundColor().name()); + QFile dst(cssDst); if (dst.exists()) dst.remove(); - if (!src.copy(cssDst)) { + if (!saveStringToDisk(cssDst, cssContent)) { QMessageBox::critical( 0, QObject::tr("Error", "ExportHTML"), - QObject::tr("Could not copy\n%1 to\n%2", "ExportHTML") - .arg(cssSrc) + QObject::tr("Could not write to \n%1", "ExportHTML") .arg(cssDst)); return; } @@ -422,6 +433,11 @@ void ExportHTML::doExport(bool useDialog) // Include image // (be careful: this resets Export mode, so call before exporting branches) if (dia.includeMapImage) { + // Workaround to preserve mapChanged status, + // which otherwise might become true because of + // implicit image export + setBlockMapChangedDuringExport(true); + QString mapName = getMapName(); ts << "
\n"; offset = model->exportImage(dirPath + "/" + mapName + ".png", false, "PNG"); + + setBlockMapChangedDuringExport(false); } // Include table of contents @@ -458,14 +476,29 @@ void ExportHTML::doExport(bool useDialog) ts << "
\n"; ts << " \n\ \n\ - \n\ - \n\ - \n\ + \n\ + \n\ + \n\ \n \
" + - filePath + "" + - toS(QDate::currentDate()) + " vym " + vymVersion + "" + "vym " + vymVersion + " - " + toS(QDate::currentDate()) + "
\n"; + ts << "\n"; ts << ""; file.close(); diff --git a/src/export-impress.cpp b/src/export-impress.cpp index 6d90cce..2185740 100644 --- a/src/export-impress.cpp +++ b/src/export-impress.cpp @@ -147,19 +147,27 @@ void ExportImpress::exportPresentation() // zip tmpdir to destination ZipAgent zipAgent(tmpDir, filePath); zipAgent.setBackgroundProcess(false); - zipAgent.startZip(); - if(zipAgent.exitStatus() != QProcess::NormalExit || - zipAgent.exitCode() > 0) { + if (!zipAgent.startZip()) { QMessageBox::critical( 0, QObject::tr("Critical Export Error"), - QObject::tr("Could not compress file %1").arg(filePath)); + QObject::tr("Could not start compressing file %1").arg(filePath)); + result = ExportBase::Failed; + return; + } else { + if(zipAgent.exitStatus() != QProcess::NormalExit || + zipAgent.exitCode() > 0) { + QMessageBox::critical( + 0, QObject::tr("Critical Export Error"), + QObject::tr("Could not compress file %1").arg(filePath)); + result = ExportBase::Failed; + return; + } } + result = ExportBase::Success; displayedDestination = filePath; - result = ExportBase::Success; - QStringList args; args << filePath; args << configFile; diff --git a/src/findcontrolswidget.cpp b/src/findcontrolswidget.cpp index c7b8770..54764c6 100644 --- a/src/findcontrolswidget.cpp +++ b/src/findcontrolswidget.cpp @@ -70,6 +70,8 @@ FindControlsWidget::FindControlsWidget(QWidget *) QString FindControlsWidget::getFindText() { return findcombo->currentText(); } +bool FindControlsWidget::getSearchNotes() { return filterNotesButton->isChecked(); } + void FindControlsWidget::nextPressed() { if (findcombo->count() < findcombo->maxCount()) diff --git a/src/findcontrolswidget.h b/src/findcontrolswidget.h index 9a500e7..f71d062 100644 --- a/src/findcontrolswidget.h +++ b/src/findcontrolswidget.h @@ -16,6 +16,7 @@ class FindControlsWidget : public QWidget { FindControlsWidget(QWidget *parent = nullptr); QString getFindText(); + bool getSearchNotes(); public slots: void nextPressed(); diff --git a/src/findresultwidget.cpp b/src/findresultwidget.cpp index 156ad79..a532d34 100644 --- a/src/findresultwidget.cpp +++ b/src/findresultwidget.cpp @@ -111,6 +111,11 @@ void FindResultWidget::addItem(const QString &s) QString FindResultWidget::getFindText() { return findControlsWidget->getFindText(); } +bool FindResultWidget::getSearchNotes() +{ + return findControlsWidget->getSearchNotes(); +} + FindResultModel *FindResultWidget::getResultModel() { return resultsModel; } void FindResultWidget::popup() diff --git a/src/findresultwidget.h b/src/findresultwidget.h index 682d0cb..14697dc 100644 --- a/src/findresultwidget.h +++ b/src/findresultwidget.h @@ -29,6 +29,7 @@ class FindResultWidget : public QWidget { void addItem(TreeItem *ti); void addItem(const QString &s); QString getFindText(); + bool getSearchNotes(); public slots: void popup(); diff --git a/src/flag-container.cpp b/src/flag-container.cpp index 28f30d1..fb4d97c 100644 --- a/src/flag-container.cpp +++ b/src/flag-container.cpp @@ -17,7 +17,7 @@ FlagContainer::~FlagContainer() void FlagContainer::init() { avis = true; - containerType = FlagCont; + setContainerType(FlagCont); //setPen(QPen(Qt::green)); } diff --git a/src/flagrow-container.cpp b/src/flagrow-container.cpp index 477548e..9cd24d1 100644 --- a/src/flagrow-container.cpp +++ b/src/flagrow-container.cpp @@ -12,7 +12,7 @@ FlagRowContainer::FlagRowContainer() { // qDebug() << "Const FlagRowContainer ()"; // setPen(QPen(Qt::red)); - containerType = FlagRowCont; + setContainerType(FlagRowCont); layoutInt = Horizontal; horizontalDirection = LeftToRight; horizontalAlignmentInt = HorAlignedCentered; @@ -44,7 +44,7 @@ void FlagRowContainer::updateActiveFlagContainers(const QList activeFlagU } // Remove flags no longer active in TreeItem - foreach (QGraphicsItem *child, childItems()) { + foreach (QGraphicsItem *child, childContainers()) { FlagContainer* fc = (FlagContainer*) child; if (!activeFlagUids.contains(fc->getUuid())) { delete fc; @@ -79,7 +79,7 @@ void FlagRowContainer::activateFlag(Flag *flag) FlagContainer *FlagRowContainer::findFlagContainerByUid(const QUuid &uid) { - foreach (QGraphicsItem *child, childItems()) { + foreach (QGraphicsItem *child, childContainers()) { FlagContainer* fc = (FlagContainer*) child; if (fc->getUuid() == uid) return fc; @@ -92,7 +92,7 @@ QUuid FlagRowContainer::findFlagByPos(const QPointF &p) if (!boundingRect().contains(mapFromScene(p))) return QUuid(); - foreach (QGraphicsItem *child, childItems()) { + foreach (QGraphicsItem *child, childContainers()) { FlagContainer* fc = (FlagContainer*) child; if (fc->boundingRect().contains(fc->mapFromScene(p))) return fc->getUuid(); diff --git a/src/frame-container.cpp b/src/frame-container.cpp index 69692b8..cba4c7d 100644 --- a/src/frame-container.cpp +++ b/src/frame-container.cpp @@ -26,7 +26,7 @@ FrameContainer::~FrameContainer() void FrameContainer::init() { - containerType = Frame; + setContainerType(Frame); frameTypeInt = NoFrame; clear(); framePen.setColor(Qt::black); diff --git a/src/git.h b/src/git.h new file mode 100644 index 0000000..b109406 --- /dev/null +++ b/src/git.h @@ -0,0 +1,2 @@ +#define GIT_BRANCH "develop" +#define GIT_COMMIT_HASH "410a3541" diff --git a/src/git.h.in b/src/git.h.in new file mode 100644 index 0000000..4fceda2 --- /dev/null +++ b/src/git.h.in @@ -0,0 +1,2 @@ +#define GIT_BRANCH "${GIT_BRANCH}" +#define GIT_COMMIT_HASH "${GIT_COMMIT_HASH}" diff --git a/src/heading-container.cpp b/src/heading-container.cpp index dabbd1a..270c152 100644 --- a/src/heading-container.cpp +++ b/src/heading-container.cpp @@ -21,7 +21,7 @@ HeadingContainer::~HeadingContainer() void HeadingContainer::init() { - containerType = Container::Heading; + setContainerType(Container::Heading); headingInt.setText(" "); headingColorInt = QColor(Qt::black); @@ -209,7 +209,7 @@ qreal HeadingContainer::getScrollOpacity() // FIXME-3 needed? void HeadingContainer::reposition() { - // qdbg() << ind() << "HC::reposition " + info(); + // My rectangle is defined above in setText() return; } diff --git a/src/historywindow.cpp b/src/historywindow.cpp index 2977a17..a2e525d 100644 --- a/src/historywindow.cpp +++ b/src/historywindow.cpp @@ -12,6 +12,8 @@ extern QString editorFocusOutStyle; HistoryWindow::HistoryWindow(QWidget *parent) : QDialog(parent) { + modelIdInt = 0; + ui.setupUi(this); ui.historyTable->setRowCount( settings.value("/history/stepsTotal", 75).toInt()); @@ -123,8 +125,11 @@ void HistoryWindow::updateRow(int row, int step, SimpleSettings &set) ui.historyTable->setItem(row, 2, item); } -void HistoryWindow::update(SimpleSettings &set) +void HistoryWindow::update(uint model, SimpleSettings &set) { + // Remember model id + modelIdInt = model; + int undosAvail = set.numValue("/history/undosAvail", 0); int redosAvail = set.numValue("/history/redosAvail", 0); int stepsTotal = set.numValue("/history/stepsTotal", 1000); @@ -134,6 +139,12 @@ void HistoryWindow::update(SimpleSettings &set) int r = undosAvail - 1; QTableWidgetItem *item; + /* + qDebug() << "HistoryWindow::update: undosAvail=" << undosAvail + << "redosAvail=" << redosAvail << "stepsTotal=" << stepsTotal + << "curStep=" << curStep; + */ + // Update number of rows ui.historyTable->setRowCount(undosAvail + redosAvail + 1); @@ -214,8 +225,12 @@ void HistoryWindow::undo() { mainWindow->editUndo(); } void HistoryWindow::redo() { mainWindow->editRedo(); } -void HistoryWindow::select() +void HistoryWindow::select() // FIXME-2 Better save current vymModel in HistoryWIndow and undo/redo directly without MainWindow. { - mainWindow->gotoHistoryStep( - ui.historyTable->row(ui.historyTable->selectedItems().first())); + QList selis = ui.historyTable->selectedItems(); + if (selis.size() < 1) { + qDebug() << "HistoryWindow::select() no selection"; + return; + } + mainWindow->gotoHistoryStep(modelIdInt, ui.historyTable->row(selis.first())); } diff --git a/src/historywindow.h b/src/historywindow.h index 0c6c2f9..8f7fc9c 100644 --- a/src/historywindow.h +++ b/src/historywindow.h @@ -14,7 +14,7 @@ class HistoryWindow : public QDialog { HistoryWindow(QWidget *parent = 0); ~HistoryWindow(); void setFocus(); - void update(SimpleSettings &); + void update(uint modelId, SimpleSettings &); void setStepsTotal(int); protected: @@ -30,9 +30,11 @@ class HistoryWindow : public QDialog { void windowClosed(); private: + Ui::HistoryWindow ui; + + uint modelIdInt; void clearRow(int); void updateRow(int, int, SimpleSettings &); - Ui::HistoryWindow ui; }; #endif diff --git a/src/image-container.cpp b/src/image-container.cpp index 2b64410..a7794ce 100644 --- a/src/image-container.cpp +++ b/src/image-container.cpp @@ -82,7 +82,7 @@ void ImageContainer::copy(ImageContainer *other) void ImageContainer::init() { - containerType = Image; + setContainerType(Image); originalFilenameInt = ""; @@ -274,8 +274,9 @@ void ImageContainer::linkTo(BranchContainer *pbc) void ImageContainer::updateUpLink() { /* + qDebug() << "IC::updateUpLink() this=" << this << " ii=" << imageItem << "type=" << type(); if (imageItem) - qDebug() << "IC::updateUpLink() ii=" << imageItem->headingText() << " vis=" << isVisible() << " par_item=" << parentItem(); + qDebug() << "IC::updateUpLink() ii=" << imageItem->headingText() << " vis=" << isVisible() << " par_item=" << parentItem(); else qDebug() << "IC::updateUpLink() No ii."; */ @@ -317,12 +318,13 @@ void ImageContainer::updateUpLink() // Color of link (depends on current parent) BranchItem *pb = imageItem->parentBranch(); - if (pb) { - if (upLink->linkColorHint() == LinkObj::HeadingColor) + if (imageItem && pb) { + if (pb->mapDesign()->linkColorHint() == LinkObj::HeadingColor) upLink->setLinkColor(pb->headingColor()); else upLink->setLinkColor(pb->mapDesign()->defaultLinkColor()); - } + } else + return; // Finally update geometry upLink->updateLinkGeometry(); diff --git a/src/imageitem.cpp b/src/imageitem.cpp index 973530e..bdd4b9c 100644 --- a/src/imageitem.cpp +++ b/src/imageitem.cpp @@ -33,8 +33,9 @@ ImageItem::~ImageItem() imageContainer = nullptr; // Remove images container, if no longer required - if (parentBranch()) - parentBranch()->getBranchContainer()->updateChildrenStructure(); + BranchItem *pb = parentBranch(); + if (pb && pb->getBranchContainer()) + pb->getBranchContainer()->updateChildrenStructure(); } if (!filePathInZipDir.isEmpty() && QFile(filePathInZipDir).exists()) { diff --git a/src/itemlist-wrapper.cpp b/src/itemlist-wrapper.cpp index 109260b..eac5105 100644 --- a/src/itemlist-wrapper.cpp +++ b/src/itemlist-wrapper.cpp @@ -26,8 +26,13 @@ void ItemListWrapper::init() { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); itemList.clear(); - currentIndex = -1; deepLevelsFirstInt = false; + reset(); +} + +void ItemListWrapper::reset() +{ + currentIndex = -1; } void ItemListWrapper::setModeBranches(bool deepLevelsFirst) diff --git a/src/itemlist-wrapper.h b/src/itemlist-wrapper.h index b6a8dfa..da91f2e 100644 --- a/src/itemlist-wrapper.h +++ b/src/itemlist-wrapper.h @@ -18,6 +18,7 @@ public: void init(); public slots: + void reset(); Q_INVOKABLE void setModeBranches(bool deepLevelsFirst = false); Q_INVOKABLE void setModeSelectedBranches(); Q_INVOKABLE void setModeSelectedSubtrees(bool deepLevelsFirst = false); diff --git a/src/link-container.cpp b/src/link-container.cpp index 8a15cad..a090c12 100644 --- a/src/link-container.cpp +++ b/src/link-container.cpp @@ -23,7 +23,7 @@ LinkContainer::~LinkContainer() void LinkContainer::init() { - containerType = Link; + setContainerType(Link); } void LinkContainer::addLink(LinkObj *lo) diff --git a/src/linkobj.cpp b/src/linkobj.cpp index ab12e50..ed94904 100644 --- a/src/linkobj.cpp +++ b/src/linkobj.cpp @@ -176,16 +176,6 @@ QString LinkObj::styleString(int style) } } -void LinkObj::setLinkColorHint(ColorHint hint) -{ - colorHint = hint; -} - -LinkObj::ColorHint LinkObj::linkColorHint() -{ - return colorHint; -} - LinkObj::ColorHint LinkObj::linkColorHint(const QString &s) { if (s == "HeadingColor") diff --git a/src/linkobj.h b/src/linkobj.h index a2b5028..9e07a25 100644 --- a/src/linkobj.h +++ b/src/linkobj.h @@ -55,8 +55,6 @@ class LinkObj : public MapObj { static Style styleFromString(const QString &); static QString styleString(int); - void setLinkColorHint(ColorHint); - ColorHint linkColorHint(); static ColorHint linkColorHint(const QString &); static QString linkColorHintName(ColorHint); @@ -84,7 +82,7 @@ class LinkObj : public MapObj { int thickness_start; // for StylePoly* Style style; // Current style QColor linkcolor; // Link color - ColorHint colorHint; + QPen pen; QGraphicsLineItem *l; // line style QGraphicsPolygonItem *p; // poly styles diff --git a/src/main.cpp b/src/main.cpp index 732e6ec..d042448 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,10 +8,12 @@ #include #include "branchpropeditor.h" +#include "buildinfo.h" #include "command.h" #include "debuginfo.h" #include "findresultwidget.h" #include "flagrow-master.h" +#include "git.h" #include "headingeditor.h" #include "macros.h" #include "mainwindow.h" @@ -261,6 +263,7 @@ int main(int argc, char *argv[]) s += QString(" - \"%1\"").arg(vymCodeName); s += "\n"; s += " Quality: " + vymCodeQuality + "\n"; + s += QString(" git: branch \"%1\" - commit %2\n").arg(GIT_BRANCH, GIT_COMMIT_HASH); s += "Build date: " + vymBuildDate + "\n"; std::cout << s.toStdString(); @@ -539,14 +542,21 @@ int main(int argc, char *argv[]) warn.exec(); } else { bool ok; + QString lname; if (!localeName.isEmpty()) // Use localeName to load specific language - ok = vymTranslator.load(QString("vym_%1.qm").arg(localeName), vymTranslationsDir.path()); + lname = QString("vym_%1.qm").arg(localeName); else { - ok = vymTranslator.load(QLocale(), "vym", ".", vymTranslationsDir.path(), ".qm"); - if (!ok) - // No system locale found, go for English - ok = vymTranslator.load(QString("vym_en.qm"), vymTranslationsDir.path()); + QString s = QLocale::system().name(); + lname = s.left(s.indexOf("_")); + } + + ok = vymTranslator.load(QString("vym_%1.qm").arg(lname), vymTranslationsDir.path()); + + if (!ok) { + // No system locale found, go for English + qDebug() << "Main: No system locale found, trying Enlish"; + ok = vymTranslator.load(QString("vym_en.qm"), vymTranslationsDir.path()); } if (!ok) { @@ -721,7 +731,7 @@ int main(int argc, char *argv[]) // For benchmarking or if test script is done // we may want to quit instead of entering event loop if (options.isActive("quit") || mainWindow->exitAfterScript()) - mainWindow->fileExitVYM(); + mainWindow->fileExitVym(); else app.exec(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4353555..e5f3ddf 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -200,7 +200,7 @@ Main::Main(QWidget *parent) : QMainWindow(parent) // Allow closing of tabs (introduced in Qt 4.5) tabWidget->setTabsClosable(true); connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, - SLOT(fileCloseMap(int))); + SLOT(fileCloseTab(int))); tabWidget->setMovable(true); @@ -217,8 +217,6 @@ Main::Main(QWidget *parent) : QMainWindow(parent) viewMenu = menuBar()->addMenu(tr("&View")); toolbarsMenu = viewMenu->addMenu(tr("Toolbars", "Toolbars overview in view menu")); - toggleWindowsMenu = - viewMenu->addMenu(tr("Toggle window", "Toggle visibility of editor windows overview in view menu")); focusWindowsMenu = viewMenu->addMenu(tr("Focus window", "Toggle visibility of editor windows overview in view menu")); @@ -369,8 +367,7 @@ Main::Main(QWidget *parent) : QMainWindow(parent) // Allows a (test-)script to make vym quit after script execution exitAfterScriptInt = false; - backgroundZipProcesses = 0; - closeAfterLastZipProcess = false; + exitAfterLastMapClosed = false; } Main::~Main() @@ -526,11 +523,8 @@ void Main::satelliteVisibilityChanged() void Main::closeEvent(QCloseEvent *event) { - if (tabWidget->count() > 0 && fileExitVYM()) - // Some problem when closing tabs - event->ignore(); - else - event->accept(); + fileExitVym(); + event->ignore(); } QPrinter *Main::setupPrinter() @@ -554,8 +548,8 @@ void Main::setupAPI() c = new Command("clearConsole", Command::AnySel); vymCommands.append(c); - c = new Command("closeMapWithID", Command::AnySel); - c->addParameter(Command::IntPar, false, "ID of map (unsigned int)"); + c = new Command("closeMapWithId", Command::AnySel); + c->addParameter(Command::IntPar, false, "Id of map (unsigned int)"); vymCommands.append(c); c = new Command("currentColor", Command::AnySel); @@ -733,6 +727,10 @@ void Main::setupAPI() c->setComment("Returns true, if map uses an image as background"); modelCommands.append(c); + c = new Command("isBusy", Command::AnySel); + c->setComment("Returns true while map is saving or loading"); + modelCommands.append(c); + c = new Command("itemList", Command::AnySel, Command::BoolPar); c->addParameter(Command::BoolPar, true, "Flag to go deep levels first (currently unused)"); c->setComment("Create new itemList to iterate over branches"); @@ -749,6 +747,11 @@ void Main::setupAPI() c->setComment("Replace branch with data from given path"); modelCommands.append(c); + c = new Command("moveSelectionToTarget", Command::BranchSel, Command::BoolPar); + c->setComment("Move selected branches to target branch"); + c->addParameter(Command::BranchPar, false, "Target branch"); + modelCommands.append(c); + c = new Command("moveSlideDown", Command::AnySel); modelCommands.append(c); @@ -891,6 +894,11 @@ void Main::setupAPI() c->addParameter(Command::StringPar, false, ""); modelCommands.append(c); + c = new Command("setSaveAsBackgroundProcess", Command::AnySel); + c->addParameter(Command::BoolPar, false, "Enable (default) or disable background saving"); + c->setComment("Use background progress to save maps or selections"); + modelCommands.append(c); + c = new Command("setZoom", Command::AnySel); c->addParameter(Command::DoublePar, false, "Zoomfactor of map"); modelCommands.append(c); @@ -925,16 +933,16 @@ void Main::setupAPI() // c = new Command("addBranch", Command::BranchSel); - c->setComment("Add branch as child branch to current branch"); + c->setComment("Add branch as child branch to current branch and return it"); branchCommands.append(c); c = new Command("addBranchAt", Command::BranchSel); - c->setComment("Add branch at position to current branch"); + c->setComment("Add branch at position to current branch and return it"); c->addParameter(Command::IntPar, true, "Index of new branch"); branchCommands.append(c); c = new Command("addBranchBefore", Command::BranchSel); - c->setComment("Add branch as parent before current branch"); + c->setComment("Add branch as parent before current branch and return it"); branchCommands.append(c); c = new Command("attributeAsInt", Command::BranchSel, Command::IntPar); @@ -947,6 +955,11 @@ void Main::setupAPI() c->addParameter(Command::StringPar, false, "Key of string attribute"); branchCommands.append(c); + c = new Command("branchAt", Command::BranchSel); + c->setComment("Return child branch at given index"); + c->addParameter(Command::IntPar, false, "Index of child branch"); + branchCommands.append(c); + c = new Command("branchCount", Command::BranchSel, Command::IntPar); c->setComment("Return number of child branches"); branchCommands.append(c); @@ -1537,6 +1550,10 @@ void Main::setupAPI() c->setReturnType(Command::IntPar); itemListCommands.append(c); + c = new Command("reset"); + c->setComment("Reset the current item position to the beginning of the list"); + itemListCommands.append(c); + c = new Command("setModeBranches"); c->setComment("Set iteration mode to include all branches in map"); c->addParameter(Command::BoolPar, true, "Deep levels first"); @@ -1641,51 +1658,14 @@ void Main::setupFileActions() fileMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(fileSaveAsDefault())); - fileMenu->addSeparator(); - - fileImportMenu = fileMenu->addMenu(tr("Import", "File menu")); - - // Import at selection (adding to selection) - a = new QAction(tr("Add map (insert)", "Edit menu"), this); - connect(a, SIGNAL(triggered()), this, SLOT(editImportAdd())); - a->setEnabled(false); - actionListBranches.append(a); - actionImportAdd = a; - fileImportMenu->addAction(a); - - // Import at selection (replacing selection) - a = new QAction(tr("Add map (replace)", "Edit menu"), this); - connect(a, SIGNAL(triggered()), this, SLOT(editImportReplace())); + a = new QAction(tr("Save selection", "Edit menu"), this); + connect(a, SIGNAL(triggered()), this, SLOT(editSaveSelection())); a->setEnabled(false); + fileMenu->addAction(a); actionListBranches.append(a); - actionImportReplace = a; - fileImportMenu->addAction(a); - fileImportMenu->addSeparator(); + actionSaveSelection = a; - a = new QAction( tr("Firefox Bookmarks", "Import filters") + - tr("(still experimental)"), - this); - connect(a, SIGNAL(triggered()), this, - SLOT(fileImportFirefoxBookmarks())); - fileImportMenu->addAction(a); - - a = new QAction("Freemind..." + tr("(still experimental)"), this); - connect(a, SIGNAL(triggered()), this, SLOT(fileImportFreemind())); - fileImportMenu->addAction(a); - - a = new QAction("IThoughts..." + tr("(still experimental)"), this); - connect(a, SIGNAL(triggered()), this, SLOT(fileImportIThoughts())); - fileImportMenu->addAction(a); - - a = new QAction("Mind Manager..." + tr("(still experimental)"), this); - connect(a, SIGNAL(triggered()), this, SLOT(fileImportMM())); - fileImportMenu->addAction(a); - - a = new QAction(tr("Import Dir...", "Import Filters") + " " + - tr("(still experimental)"), - this); - connect(a, SIGNAL(triggered()), this, SLOT(fileImportDir())); - fileImportMenu->addAction(a); + fileMenu->addSeparator(); fileExportMenu = fileMenu->addMenu(tr("Export", "File menu")); @@ -1789,6 +1769,50 @@ void Main::setupFileActions() fileExportMenu->addAction(a); actionListFiles.append(a); + fileImportMenu = fileMenu->addMenu(tr("Import", "File menu")); + + // Import at selection (adding to selection) + a = new QAction(tr("Add map (insert)", "Edit menu"), this); + connect(a, SIGNAL(triggered()), this, SLOT(editImportAdd())); + a->setEnabled(false); + actionListBranches.append(a); + actionImportAdd = a; + fileImportMenu->addAction(a); + + // Import at selection (replacing selection) + a = new QAction(tr("Add map (replace)", "Edit menu"), this); + connect(a, SIGNAL(triggered()), this, SLOT(editImportReplace())); + a->setEnabled(false); + actionListBranches.append(a); + actionImportReplace = a; + fileImportMenu->addAction(a); + fileImportMenu->addSeparator(); + + a = new QAction( tr("Firefox Bookmarks", "Import filters") + + tr("(still experimental)"), + this); + connect(a, SIGNAL(triggered()), this, + SLOT(fileImportFirefoxBookmarks())); + fileImportMenu->addAction(a); + + a = new QAction("Freemind..." + tr("(still experimental)"), this); + connect(a, SIGNAL(triggered()), this, SLOT(fileImportFreemind())); + fileImportMenu->addAction(a); + + a = new QAction("IThoughts..." + tr("(still experimental)"), this); + connect(a, SIGNAL(triggered()), this, SLOT(fileImportIThoughts())); + fileImportMenu->addAction(a); + + a = new QAction("Mind Manager..." + tr("(still experimental)"), this); + connect(a, SIGNAL(triggered()), this, SLOT(fileImportMM())); + fileImportMenu->addAction(a); + + a = new QAction(tr("Import Dir...", "Import Filters") + " " + + tr("(still experimental)"), + this); + connect(a, SIGNAL(triggered()), this, SLOT(fileImportDir())); + fileImportMenu->addAction(a); + fileMenu->addSeparator(); a = new QAction(tr("Map properties"), this); @@ -1811,14 +1835,14 @@ void Main::setupFileActions() a = new QAction(QPixmap(QString(":/document-close-%1.svg").arg(iconTheme)), tr("&Close Map", "File menu"), this); switchboard.addAction(a, "fileMapClose", Qt::CTRL | Qt::Key_W, shortcutScope, tag); - connect(a, SIGNAL(triggered()), this, SLOT(fileCloseMap())); + connect(a, SIGNAL(triggered()), this, SLOT(fileCloseCurrentMap())); 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); switchboard.addAction(a, "fileExit", Qt::CTRL | Qt::Key_Q, shortcutScope, tag); - connect(a, SIGNAL(triggered()), this, SLOT(fileExitVYM())); + connect(a, SIGNAL(triggered()), this, SLOT(fileExitVym())); fileMenu->addAction(a); actionFileExitVym = a; @@ -1853,8 +1877,9 @@ void Main::setupEditActions() a->setShortcutContext(Qt::WidgetShortcut); a->setEnabled(false); mapEditorActions.append(a); + vimActions.append(a); restrictedMapActions.append(a); - switchboard.addAction(a, "mapUndo", Qt::Key_U, shortcutScope, tag); // Vim Alternative + switchboard.addAction(a, "mapUndoVimAlt", Qt::Key_U, shortcutScope, tag); // Vim Alternative connect(a, SIGNAL(triggered()), this, SLOT(editUndo())); actionUndoVim = a; @@ -1867,7 +1892,7 @@ void Main::setupEditActions() actionRedo = a; a = new QAction(tr("Repeat last action", "Edit menu") + " (experimental)", this); - switchboard.addAction(a, "repeatLastAction", Qt::Key_Period, shortcutScope, tag); + switchboard.addAction(a, "repeatLastActionVim", Qt::Key_Period, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editRepeatLastAction())); //actionListBranches.append(a); actionRepeatCommand = a; @@ -1888,7 +1913,8 @@ void Main::setupEditActions() a->setEnabled(false); unrestrictedMapActions.append(a); mapEditorActions.append(a); - switchboard.addAction(a, "mapCopyVim", Qt::Key_Y, shortcutScope, tag); + vimActions.append(a); + switchboard.addAction(a, "mapCopyVimAlt", Qt::Key_Y, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(editCopy())); actionCopyVim = a; @@ -1905,8 +1931,9 @@ void Main::setupEditActions() 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); + switchboard.addAction(a, "mapCutVimAlt", Qt::Key_D, shortcutScope, tag); addAction(a); + vimActions.append(a); connect(a, SIGNAL(triggered()), this, SLOT(editDeleteSelection())); actionListItems.append(a); actionCutVim = a; @@ -1928,7 +1955,8 @@ void Main::setupEditActions() a->setEnabled(false); restrictedMapActions.append(a); mapEditorActions.append(a); - switchboard.addAction(a, "mapPasteVim", Qt::Key_P, shortcutScope, tag); + vimActions.append(a); + switchboard.addAction(a, "mapPasteVimAlt", Qt::Key_P, shortcutScope, tag); actionPasteVim = a; // Shortcut to delete selection @@ -2407,13 +2435,6 @@ void Main::setupEditActions() actionListBranches.append(a); actionTaskSleep28 = a; - // Save selection - a = new QAction(tr("Save selection", "Edit menu"), this); - connect(a, SIGNAL(triggered()), this, SLOT(editSaveBranch())); - a->setEnabled(false); - actionListBranches.append(a); - actionSaveBranch = a; - tag = tr("Removing parts of a map", "Shortcuts"); // Only remove branch, not its children @@ -2518,7 +2539,8 @@ void Main::setupSelectActions() a = new QAction(QPixmap(QString(":/edit-find-%1.svg").arg(iconTheme)), tr("Find...", "Edit menu"), this); selectMenu->addAction(a); - switchboard.addAction(a, "mapFindAlt", Qt::Key_Slash, shortcutScope, tag); // Alternative: VIM Find + vimActions.append(a); + switchboard.addAction(a, "mapFindVimAlt", Qt::Key_Slash, shortcutScope, tag); // Alternative: VIM Find connect(a, SIGNAL(triggered()), this, SLOT(editOpenFindResultWidget())); actionListFiles.append(a); actionFindVim = a; @@ -2541,8 +2563,9 @@ void Main::setupSelectActions() a = new QAction("Select first branch in siblings", this); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + vimActions.append(a); selectMenu->addAction(a); - switchboard.addAction(a, "Select first branch in siblings", Qt::Key_0, shortcutScope, tag); // Alternative: VIM Select first + switchboard.addAction(a, "selectFirstSiblingVim", Qt::Key_0, shortcutScope, tag); // Alternative: VIM Select first actionListBranches.append(a); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editSelectFirstSibling())); @@ -2557,8 +2580,9 @@ void Main::setupSelectActions() a = new QAction("Select last branch in siblings", this); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); + vimActions.append(a); selectMenu->addAction(a); - switchboard.addAction(a, "Select last branch in siblings", Qt::Key_Dollar, shortcutScope, tag); + switchboard.addAction(a, "selectLastSiblingVim", Qt::Key_Dollar, shortcutScope, tag); actionListBranches.append(a); addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(editSelectLastSibling())); @@ -2865,7 +2889,6 @@ void Main::setupViewActions() a = new QAction(QPixmap(":/flag-note.svg"), n, this); a->setCheckable(true); - toggleWindowsMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(toggleNoteEditor())); actionViewToggleNoteEditor = a; // @@ -2881,7 +2904,6 @@ void Main::setupViewActions() a = new QAction(QPixmap(":/headingeditor.png"), n, this); a->setCheckable(true); mapEditorActions.append(a); - toggleWindowsMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(toggleHeadingEditor())); actionViewToggleHeadingEditor = a; @@ -2889,7 +2911,6 @@ void Main::setupViewActions() // Original icon is "category" from KDE a = new QAction(QPixmap(":/treeeditor.png"), n, this); a->setCheckable(true); - toggleWindowsMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(toggleTreeEditors())); actionViewToggleTreeEditors = a; @@ -2912,14 +2933,12 @@ void Main::setupViewActions() a = new QAction(QPixmap(":/taskeditor.png"), n, this); a->setCheckable(true); - toggleWindowsMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(toggleTaskEditor())); actionViewToggleTaskEditor = a; n = tr("Slide editor", "View action"); a = new QAction(QPixmap(":/slideeditor.png"), n, this); a->setCheckable(true); - toggleWindowsMenu->addAction(a); switchboard.addAction(a, "mapShowSlideEditor", shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(toggleSlideEditors())); actionViewToggleSlideEditors = a; @@ -2933,16 +2952,19 @@ void Main::setupViewActions() a = new QAction(QPixmap(":/scripteditor.png"), n, this); a->setCheckable(true); - toggleWindowsMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(toggleScriptEditor())); actionViewToggleScriptEditor = a; + a = new QAction(QPixmap(), tr("Script output", "View action"), this); + focusWindowsMenu->addAction(a); + switchboard.addAction(a, "mapFocusScriptOutput", Qt::CTRL | Qt::SHIFT | Qt::Key_S, shortcutScope, tag); + connect(a, SIGNAL(triggered()), this, SLOT(focusScriptOutput())); + actionViewFocusScriptOutput = a; + a = new QAction(QPixmap(), tr("Script output", "View action"), this); a->setCheckable(true); - toggleWindowsMenu->addAction(a); - switchboard.addAction(a, "mapToggleScriptOutput", Qt::CTRL | Qt::SHIFT | Qt::Key_S, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(toggleScriptOutput())); - actionViewToggleScriptOutput = a; // FIXME-3 show + actionViewToggleScriptOutput = a; n = tr("History window", "View action"); a = new QAction(QPixmap(":/history.png"), n, this); @@ -2959,12 +2981,10 @@ void Main::setupViewActions() a = new QAction(QPixmap(":/history.png"), n, this); a->setCheckable(true); - toggleWindowsMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(toggleHistory())); actionViewToggleHistoryWindow = a; focusWindowsMenu->addAction(actionViewFocusPropertyEditor); - toggleWindowsMenu->addAction(actionViewTogglePropertyEditor); viewMenu->addSeparator(); @@ -3035,7 +3055,6 @@ void Main::setupConnectActions() a = new QAction( tr("Get Confluence user data", "Connect action"), this); connectMenu->addAction(a); - switchboard.addAction(a, "confluenceUser", Qt::SHIFT | Qt::Key_C, shortcutScope, tag); connect(a, SIGNAL(triggered()), this, SLOT(getConfluenceUser())); actionConnectGetConfluenceUser = a; @@ -3137,6 +3156,7 @@ void Main::setupFlagActions() // Create System Flags // Tasks + // Origin: ./share/icons/oxygen/48x48/status/task-reject.png flag = setupFlag(":/flag-task-new.svg", Flag::SystemFlag, "system-task-new", tr("Note", "SystemFlag")); @@ -3708,6 +3728,11 @@ void Main::setupHelpActions() helpMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(helpDebugInfo())); + helpMenu->addSeparator(); + a = new QAction(tr("Help VYM development", "Help action"), this); + helpMenu->addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(helpVymDevelopment())); + a = new QAction(tr("About QT", "Help action"), this); connect(a, SIGNAL(triggered()), this, SLOT(helpAboutQT())); helpMenu->addAction(a); @@ -3731,6 +3756,7 @@ void Main::setupContextMenus() branchAddContextMenu->addAction(actionPaste); branchAddContextMenu->addAction(actionLoadImage); branchAddContextMenu->addAction(actionAddMapCenter); + branchAddContextMenu->addSeparator(); branchAddContextMenu->addAction(actionAddBranch); branchAddContextMenu->addAction(actionAddBranchBefore); branchAddContextMenu->addAction(actionAddBranchAbove); @@ -4216,7 +4242,7 @@ VymModel *Main::currentModel() const return nullptr; } -VymModel *Main::getModel(uint id) // Used in BugAgent +VymModel *Main::modelWithId(uint id) // Used in BugAgent { if (id <= 0) return nullptr; @@ -4257,23 +4283,39 @@ bool Main::closeModelWithId(uint id) for (int i = 0; i < tabWidget->count(); i++) { vm = view(i)->getModel(); if (vm && vm->modelId() == id) { - VymView *vv = view(i); - tabWidget->removeTab(i); + if (!vm->isBusy()) { + VymView *vv = view(i); + tabWidget->removeTab(i); - // Destroy stuff, order is important - branchPropertyEditor->setModel(nullptr); - delete (vm->getMapEditor()); - delete (vv); - delete (vm); + // Destroy stuff, order is important + branchPropertyEditor->setModel(nullptr); + delete (vm->getMapEditor()); + delete (vv); + delete (vm); - updateActions(); - return true; + updateActions(); + if (tabWidget->count() == 0 && exitAfterLastMapClosed) + fileExitVym(); + + return true; // Found Id, Closing scheduled successful (used in script) + } } } return false; } +void Main::closeSavedModels() +{ + // Called from VymModel::zipFinished via QTimer::singleShot + // to avoid race conditions + for (int i = 0; i < tabWidget->count(); i++) { + VymModel *vm = view(i)->getModel(); + if (vm && vm->readyToClose()) + closeModelWithId(vm->modelId()); + } +} + int Main::modelCount() { return tabWidget->count(); } void Main::updateTabName(VymModel *vm) @@ -4304,8 +4346,20 @@ void Main::editorChanged() updateQueries(vm); taskEditor->setMapName(vm->getMapName()); updateDockWidgetTitles(vm); + + // Re-run search in the newly selected map, so the FindResultWidget + // reflects the current map instead of the previous one (issue #216) + if (findResultWidget->isVisible() && + !findResultWidget->getFindText().isEmpty()) + editFindNext(findResultWidget->getFindText(), + findResultWidget->getSearchNotes()); } + // Update BranchPropertyEditor to reflect the map of the current tab. + // Selection does not change when switching tabs, so changeSelection() + // is not triggered and the editor would still show the previous map. + branchPropertyEditor->setModel(vm); + // Update actions to in menus and toolbars according to editor updateActions(); } @@ -4357,18 +4411,6 @@ 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) { @@ -4470,6 +4512,10 @@ bool Main::fileLoad(QString fn, const File::LoadMode &lmode, vm = currentMapEditor()->getModel(); vm->setFilePath(fn); updateTabName(vm); + // Notify satellite editors about the new map, e.g. so the + // TaskEditor's "current map only" filter uses the new map + // name instead of the previous (default) one. (See #174) + editorChanged(); statusBar()->showMessage("Created " + fn); return true; } @@ -4478,7 +4524,7 @@ bool Main::fileLoad(QString fn, const File::LoadMode &lmode, statusBar()->showMessage("Loading " + fn + " failed!"); int cur = tabWidget->currentIndex(); tabWidget->setCurrentIndex(tabWidget->count() - 1); - fileCloseMap(); + fileCloseCurrentMap(); tabWidget->setCurrentIndex(cur); return false; } @@ -4513,7 +4559,7 @@ bool Main::fileLoad(QString fn, const File::LoadMode &lmode, // Finally check for errors and go home if (!noError) { if (lmode == File::NewMap) - fileCloseMap(); + fileCloseCurrentMap(); statusBar()->showMessage("Could not load " + fn); } else { @@ -4531,7 +4577,12 @@ bool Main::fileLoad(QString fn, const File::LoadMode &lmode, } editorChanged(); - vm->emitShowSelection(false, false); + if (vm->hasViewCenterTarget()) + // Maps since version 2.9.606 save center of view + vm->getMapEditor()->setViewCenterTarget(vm->viewCenterTarget()); + else + vm->emitShowSelection(false, false); + statusBar()->showMessage(tr("Loaded %1").arg(fn)); } } @@ -4592,7 +4643,7 @@ void Main::fileSaveSession() flist.append(view(i)->getModel()->getFilePath()); settings.setValue("/mainwindow/sessionFileList", flist); - //logInfo("Current session list: " + flist.join(","), __func__); + // qDebug() << __func__ << "Current session list: " + flist.join(","); // Also called by event loop regulary, but apparently not often enough settings.sync(); @@ -4679,7 +4730,7 @@ void Main::fileSave(VymModel *m, const File::SaveMode &savemode) // We have no filepath yet, // call fileSaveAs() now, this will call fileSave() // again. First switch to editor - fileSaveAs(savemode); + fileSaveAs(); return; // avoid saving twice... } @@ -4690,164 +4741,120 @@ void Main::fileSave() { fileSave(currentModel(), File::CompleteMap); } void Main::fileSave(VymModel *m) { fileSave(m, File::CompleteMap); } -void Main::fileSaveAs(const File::SaveMode &savemode) +bool Main::fileSaveAs(const File::SaveMode &saveMode, QString fileName) { VymModel *m = currentModel(); - if (!m) return; + if (!m) return false; - QString filter; - if (savemode == File::CompleteMap) - filter = "VYM map (*.vym)"; - else - filter = "VYM part of map (*vyp)"; - filter += ";;All (* *.*)"; + QString fileName_org = m->getFilePath(); // Restore fileName later - // Get destination path - QString fn = QFileDialog::getSaveFileName( - this, - tr("Save map as"), - lastMapDir.path() + "/" + tr("Untitled", "Default name in FileSaveAs dialog") + ".vym", - filter, nullptr, QFileDialog::DontConfirmOverwrite); - if (!fn.isEmpty()) { - // Check for existing file - if (QFile(fn).exists()) { - // Check if the existing file is writable - if (!QFileInfo(fn).isWritable()) { - QMessageBox::critical(0, tr("Critical Error"), - tr("Couldn't save %1,\nbecause file " - "exists and cannot be changed.") - .arg(fn)); - return; - } + // Check for existing file + if (QFile(fileName).exists()) { + // Check if the existing file is writable + if (!QFileInfo(fileName).isWritable()) { + QMessageBox::critical(0, tr("Critical Error"), + tr("Couldn't save %1,\nbecause file " + "exists and cannot be changed.") + .arg(fileName)); + return false; + } - QMessageBox mb( - QMessageBox::Warning, - vymName, - tr("The file %1\nexists already. Do you want to").arg(fn)); - QPushButton *overwriteButton = mb.addButton(tr("Overwrite"), QMessageBox::AcceptRole); - mb.addButton(tr("Cancel"), QMessageBox::RejectRole); - mb.exec(); - if (mb.clickedButton() != overwriteButton) return; +// Macs check for replacing existing file in native dialog +#ifndef Q_OS_MACOS + // Ask if existing file can be overwritten + QMessageBox mb( + QMessageBox::Warning, + vymName, + tr("The file %1\nexists already. Do you want to").arg(fileName)); + QPushButton *overwriteButton = mb.addButton(tr("Overwrite"), QMessageBox::AcceptRole); + mb.addButton(tr("Cancel"), QMessageBox::RejectRole); + mb.exec(); + if (mb.clickedButton() != overwriteButton) return false; +#endif + } + else { + // New file, add extension to filename, if missing + // This is always .vym or .vyp, depending on saveMode + if (saveMode == File::CompleteMap) { + if (!fileName.contains(".vym") && !fileName.contains(".xml")) + fileName += ".vym"; } else { - // New file, add extension to filename, if missing - // This is always .vym or .vyp, depending on savemode - if (savemode == File::CompleteMap) { - if (!fn.contains(".vym") && !fn.contains(".xml")) - fn += ".vym"; - } - else { - if (!fn.contains(".vyp") && !fn.contains(".xml")) - fn += ".vyp"; - } + if (!fileName.contains(".vyp") && !fileName.contains(".xml")) + fileName += ".vyp"; } + } - // Save original filepath, might want to restore after saving - QString fn_org = m->getFilePath(); + m->setFilePath(fileName); - // Check for existing lockfile - QFile lockFile(fn + ".lock"); - if (lockFile.exists()) { - QMessageBox::critical(0, tr("Critical Error"), - tr("Couldn't save %1,\nbecause of " - "existing lockfile:\n\n%2") - .arg(fn, lockFile.fileName())); - return; - } + // Check for existing lockfile + QFile lockFile(fileName + ".lock"); + if (lockFile.exists()) { + QMessageBox::critical(0, tr("Critical Error"), + tr("Couldn't save %1,\nbecause of " + "existing lockfile:\n\n%2") + .arg(fileName, lockFile.fileName())); + m->setFilePath(fileName_org); + return false; + } - if (!m->renameMap(fn)) { - QMessageBox::critical(0, tr("Critical Error"), - tr("Saving the map failed:\nCouldn't rename map to %1").arg(fn)); - return; // FIXME-3 Check: If saved part of map and this error occurs? - } + // Rename also current lockfile, if saving complete map + if (saveMode == File::CompleteMap && !m->changeLock(fileName)) { + QMessageBox::critical(0, tr("Critical Error"), + tr("Saving the map failed:\nCouldn't rename map to %1").arg(fileName)); + m->setFilePath(fileName_org); + return false; // FIXME-3 Check: If saved part of map and this error occurs? + } - fileSave(m, savemode); + fileSave(m, saveMode); - // Set name of tab - if (savemode == File::CompleteMap) - { - addRecentMap(m->getFileName()); - updateTabName(m); - } - else { // Renaming map to original name, because we only saved the - // selected part of it - m->setFilePath(fn_org); - if (!m->renameMap(fn_org)) { - QMessageBox::critical(0, "Critical Error", - "Couldn't rename map back to " + fn_org); - } - } - lastMapDir.setPath(m->getFileDir()); - return; + // Set name of tab + if (saveMode == File::CompleteMap) + { + addRecentMap(m->getFileName()); + updateTabName(m); + } else if (saveMode == File::PartOfMap) { + m->setFilePath(fileName_org); } -} -void Main::fileSaveAs() { fileSaveAs(File::CompleteMap); } + lastMapDir.setPath(m->getFileDir()); + return true; +} -void Main::fileSaveAsDefault() +void Main::fileSaveAs() { - if (currentMapEditor()) { - QString fn = QFileDialog::getSaveFileName( - this, tr("Save map as new default map"), newMapPath(), - "VYM map (*.vym)", nullptr, QFileDialog::DontConfirmOverwrite); - - if (!fn.isEmpty()) { + VymModel *m = currentModel(); + if (!m) return; - // Check for existing file - if (QFile(fn).exists()) { - // Check if the existing file is writable - if (!QFileInfo(fn).isWritable()) { - QMessageBox::critical( - 0, tr("Warning"), - tr("You have no permissions to write to ") + fn); - return; - } + QString filter = "VYM map (*.vym)"; + filter += ";;All (* *.*)"; - // Confirm overwrite of existing file - QMessageBox mb( - QMessageBox::Warning, - vymName, - tr("The file %1\nexists already. Do you want to").arg(fn)); - mb.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); - mb.setDefaultButton(QMessageBox::Save); - switch (mb.exec()) { - case QMessageBox::Save: - // save - break; - case QMessageBox::Cancel: - return; - } - } + // Get destination path + QString fileName = QFileDialog::getSaveFileName( + this, + tr("Save map as"), + lastMapDir.path() + "/" + tr("Untitled", "Default name in FileSaveAs dialog") + ".vym", + filter, nullptr, QFileDialog::DontConfirmOverwrite); - // Save now as new default - VymModel *m = currentModel(); - - // Check for existing lockfile - QFile lockFile(fn + ".lock"); - if (lockFile.exists()) { - QMessageBox::critical( - 0, tr("Critical Error"), - tr("Couldn't save %1,\nbecause of existing lockfile:\n\n%2") - .arg(fn, lockFile.fileName())); - return; - } + fileSaveAs(File::CompleteMap, fileName); +} - if (!m->renameMap(fn)) { - QMessageBox::critical(0, tr("Critical Error"), - tr("Couldn't save as default, failed to rename to\n%1").arg(fn)); - return; - } - lastMapDir.setPath(m->getFileDir()); +void Main::fileSaveAsDefault() +{ + VymModel *m = currentModel(); + if (!m) return; - fileSave(m, File::CompleteMap); + QString filter = "VYM map (*.vym)"; + filter += ";;All (* *.*)"; - // Set name of tab - updateTabName(m); + QString fileName = QFileDialog::getSaveFileName( + this, tr("Save map as new default map"), newMapPath(), + filter, nullptr, QFileDialog::DontConfirmOverwrite); - // Set new default path - settings.setValue("/system/defaultMap/auto", false); - settings.setValue("/system/defaultMap/path", fn); - } + if (fileSaveAs(File::CompleteMap, fileName)) { + // Set new default path + settings.setValue("/system/defaultMap/auto", false); // Don't autoselect based on theme + settings.setValue("/system/defaultMap/path", fileName); } } @@ -5113,56 +5120,62 @@ void Main::fileExportLast() m->exportLast(); } -bool Main::fileCloseMap(int i) +void Main::fileCloseTab(int i) { - //qDebug() << __func__ << "i=" << i << " currentInd=" << tabWidget->currentIndex(); - VymModel *m; - VymView *vv; - if (i < 0) - i = tabWidget->currentIndex(); + if (i < tabWidget->count()) + { + VymView *vv = view(i); + if (vv) { + VymModel *vm = vv->getModel(); + if (vm) + fileCloseMapWithId(vm->modelId()); + } + fileSaveSession(); + } +} - vv = view(i); - m = vv->getModel(); +void Main::fileCloseCurrentMap() +{ + fileCloseMapWithId(currentMapId()); +} - if (m) { - if (m->hasChanged()) { +void Main::fileCloseMapWithId(uint id) +{ + VymModel *vm = nullptr; + VymView *vv; + for (int i = 0; i < tabWidget->count(); i++) { + vm = view(i)->getModel(); + if (vm && vm->modelId() == id) + break; + } + + if (vm) { + if (vm->hasChanged()) { QMessageBox mb( QMessageBox::Warning, vymName, tr("The map %1 has been modified but not saved yet. Do you " - "want to").arg(m->getFileName())); + "want to").arg(vm->getFileName())); mb.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); mb.setDefaultButton(QMessageBox::Save); mb.setModal(true); switch (mb.exec()) { case QMessageBox::Save: // save and close - fileSave(m, File::CompleteMap); - break; + vm->closeAfterSaving(); + fileSave(vm, File::CompleteMap); + return; case QMessageBox::Discard: // close without saving break; case QMessageBox::Cancel: // do nothing - return false; + return; } } - logInfo(__func__ + QString(" before removing tab %1 - %2").arg(i).arg(m->mapTitle())); // FIXME-2 debugging - tabWidget->removeTab(i); - logInfo(__func__ + QString(" after removing tab %1 - %2").arg(i).arg(m->mapTitle())); // FIXME-2 debugging - - // Destroy stuff, order is important - noteEditor->clear(); - branchPropertyEditor->setModel(nullptr); - delete (m->getMapEditor()); - delete (vv); - delete (m); - - updateActions(); - return true; + closeModelWithId(id); } - return false; // Better don't exit vym if there is no currentModel()... } void Main::filePrint() @@ -5186,27 +5199,30 @@ void Main::setExitAfterScript(bool b) exitAfterScriptInt = b; } -bool Main::fileExitVYM() +void Main::fileExitVym() { - closeAfterLastZipProcess = true; + if (tabWidget->count() == 0) + qApp->exit(); + + exitAfterLastMapClosed = true; + + if (tabWidget->count() == 0) + qApp->exit(0); // Only save session if there still are tabs open if (tabWidget->count() > 0) fileSaveSession(); - // Check if one or more editors have changed - while (tabWidget->count() > 0) { - tabWidget->setCurrentIndex(0); - if (!fileCloseMap()) - return true; - // Update widgets to show progress - qApp->processEvents(); + // Get list of open maps and trigger closing, save if necessary + QList modelIds; + for (int i = 0; i < tabWidget->count(); i++) { + VymModel *vm = view(i)->getModel(); + if (vm) + modelIds << vm->modelId(); } - if (backgroundZipProcesses > 0) - qDebug() << __func__ << " has still running bg zips..."; - else - qApp->exit(0); - return false; + + foreach (auto id, modelIds) + fileCloseMapWithId(id); } void Main::editUndo() @@ -5223,9 +5239,9 @@ void Main::editRedo() m->redo(); } -void Main::gotoHistoryStep(int i) +void Main::gotoHistoryStep(uint modelId, int i) { - VymModel *m = currentModel(); + VymModel *m = modelWithId(modelId); if (m) m->gotoHistoryStep(i); } @@ -5557,7 +5573,6 @@ void Main::editVymLink() fd.setAcceptMode(QFileDialog::AcceptOpen); if (!bi->vymLink().isEmpty()) fd.selectFile(bi->vymLink()); - fd.show(); if (fd.exec() == QDialog::Accepted && !fd.selectedFiles().isEmpty()) { @@ -5938,7 +5953,19 @@ void Main::editImportAdd() { fileLoad(File::ImportAdd); } void Main::editImportReplace() { fileLoad(File::ImportReplace); } -void Main::editSaveBranch() { fileSaveAs(File::PartOfMap); } +void Main::editSaveSelection() +{ + VymModel *m = currentModel(); + if (!m) return; + + QString filter = "Part of VYM map (*.vyp)"; + + QString fileName = QFileDialog::getSaveFileName( + this, tr("Save part of map"), m->getFileDir() + "/" + m->getMapName() + ".vyp", + filter, nullptr, QFileDialog::DontConfirmOverwrite); + + fileSaveAs(File::PartOfMap, fileName); +} void Main::editDeleteKeepChildren() { @@ -6144,41 +6171,9 @@ void Main::editMoveToTarget() QAction *a = targetsContextMenu->exec(QCursor::pos()); if (a) { TreeItem *dsti = model->findID(a->data().toUInt()); - /* - BranchItem *selbi = model->getSelectedBranch(); - if (!selbi) - return; - */ - - QList itemList = model->getSelectedItems(); - if (itemList.count() < 1) return; - - if (dsti && dsti->hasTypeBranch() ) { - BranchItem *selbi; - BranchItem *pi; - foreach (TreeItem *ti, itemList) { - if (ti->hasTypeBranch() ) - { - selbi = (BranchItem*)ti; - pi = selbi->parentBranch(); - - // If branch below exists, select that one - // Makes it easier to quickly resort using the MoveTo function - BranchItem *below = pi->getBranchNum(selbi->num() + 1); - if (below) - model->select(below); - else { - BranchItem *above = pi->getBranchNum(selbi->num() - 1); - if (above) - model->select(above); - else if (pi) - model->select(pi); - } - model->relinkBranch(selbi, (BranchItem *)dsti, -1); - } - } - } + if (dsti && dsti->hasTypeBranch()) + model->moveSelectionToTarget((BranchItem *)dsti); } } } @@ -6440,7 +6435,7 @@ void Main::viewZoomReset() { MapEditor *me = currentMapEditor(); if (me) - me->setViewCenterTarget(); + me->setViewCenterSelection(); } void Main::viewZoomIn() @@ -6520,7 +6515,7 @@ void Main::downloadFinished() // only used for drop events in mapeditor and */ QString script = agent->getFinishedScript(); - VymModel *model = getModel(agent->getFinishedScriptModelID()); + VymModel *model = modelWithId(agent->getFinishedScriptModelID()); if (!script.isEmpty() && model) { script.replace("$TMPFILE", agent->getDestination()); runScript(script); @@ -6718,7 +6713,7 @@ void Main::settingsToggleAnimation() actionSettingsUseAnimation->isChecked()); } -void Main::settingsToggleDownloads() { downloadsEnabled(true); } +void Main::settingsToggleDownloads() { vymDownloadsEnabled(true); } bool Main::settingsConfluence() { @@ -6810,12 +6805,7 @@ void Main::setTreeEditorsVisibility(bool 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++) { - logInfo(__func__ + QString(" Setting vis in vymview %1 to %2").arg(i, b)); // FIXME-2 debugging - if (!((VymView*)tabWidget->widget(i))) { - logInfo("Main::setTreeEditorsVisibility: Fatal. widget i is nullptr"); // FIXME-2 debugging - QMessageBox::warning(0, "Warning", "Would have crashed now in setTEVis, please notify development team!"); - } - else + if (((VymView*)tabWidget->widget(i))) ((VymView*)tabWidget->widget(i))->setTreeEditorVisibility(b); } updateActions(); @@ -6878,8 +6868,6 @@ void Main::focusScriptOutput() { scriptOutput->parentWidget()->show(); actionViewToggleScriptOutput->setChecked(true); - // Currently ScriptEditor gets focus, when output is toggled - // scriptOutput->setFocus(); focusScriptEditor(); } void Main::toggleScriptOutput() @@ -6967,9 +6955,12 @@ void Main::toggleSmoothPixmap() void Main::clearScriptOutput() { scriptOutput->clear(); } -void Main::updateHistory(SimpleSettings &undoSet) +void Main::updateHistory(VymModel *model, SimpleSettings &undoSet) { - historyWindow->update(undoSet); + if (model) { + // qDebug() << __func__ << " model=" << model << model->getFileName(); + historyWindow->update(model->modelId(), undoSet); + } } void Main::updateHeading(const VymText &vt) @@ -7664,7 +7655,7 @@ QVariant Main::runScript(const QString &script) scriptEngine = nullptr; if (exitAfterScriptInt) - fileExitVYM(); + fileExitVym(); return scriptResult; } @@ -7959,6 +7950,41 @@ void Main::helpDebugInfo() dia.exec(); } +void Main::helpVymDevelopment() +{ + DownloadAgent *agent = + new DownloadAgent(QUrl("https://www.insilmaril.de/vym/helpVymDevelopment.html")); + connect(agent, SIGNAL(downloadFinished()), this, + SLOT(helpVymDevelopmentFinished())); + QTimer::singleShot(0, agent, SLOT(execute())); +} + +void Main::helpVymDevelopmentFinished() +{ + DownloadAgent *agent = static_cast(sender()); + + if (agent->isSuccess()) { + QString page; + if (loadStringFromDisk(agent->getDestination(), page)) { + ShowTextDialog dia(this); + dia.setText(page); + dia.setMinimumWidth(900); + dia.setMinimumHeight(600); + dia.exec(); + } + } + else { + statusMessage("Downloading VYM development page failed."); + logInfo("Failed to download page: " + agent->getResultMessage(), __func__); + if (debug) { + qDebug() << "Main::helpVymDevelopmentFinished "; + qDebug() << " result: failed"; + qDebug() << " msg: " << agent->getResultMessage(); + } + } + agent->deleteLater(); +} + void Main::helpAbout() { AboutDialog ad; @@ -8011,6 +8037,7 @@ void Main::downloadReleaseNotesFinished() QString page; if (agent->isSuccess()) { if (loadStringFromDisk(agent->getDestination(), page)) { + page.replace("", " (" + vymVersion + ")"); ShowTextDialog dia(this); dia.setText(page); dia.exec(); @@ -8070,7 +8097,7 @@ void Main::checkReleaseNotes () else userTriggered = false; - if (downloadsEnabled()) { + if (vymDownloadsEnabled()) { if (userTriggered || versionLowerThanVym( settings.value("/downloads/releaseNotes/shownVersion", "0.0.1") @@ -8088,26 +8115,23 @@ void Main::checkReleaseNotes () QMessageBox::warning( 0, tr("Warning"), tr("Please allow vym to download release notes!")); - if (downloadsEnabled(userTriggered)) + if (vymDownloadsEnabled(userTriggered)) checkUpdates(); } } } -bool Main::downloadsEnabled(bool userTriggered) +bool Main::vymDownloadsEnabled(bool userTriggered) { bool result; - if (!userTriggered && - settings.value("/downloads/enabled", false).toBool()) { + if (!userTriggered && settings.value("/downloads/enabled", false).toBool()) { + // Download triggered by timer (updates) AND previously allowed result = true; } else { - QDate lastAsked = - settings.value("/downloads/permissionLastAsked", QDate(1970, 1, 1)) - .toDate(); + // Download triggered by user, or first run without permission asked before if (userTriggered || - !settings.contains("/downloads/permissionLastAsked") || - lastAsked.daysTo(QDate::currentDate()) > 7) { + !settings.contains("/downloads/permissionLastAsked") ) { QString infotext; infotext = tr("" @@ -8183,6 +8207,7 @@ void Main::downloadUpdatesFinished(bool userTriggered) dia.setWindowTitle(vymName + " - " + tr("Update information")); QString page; if (loadStringFromDisk(agent->getDestination(), page)) { + page.replace("", " (" + vymVersion + ")"); if (page.contains("vymisuptodate")) { statusMessage(tr("vym is up to date.", "MainWindow")); if (userTriggered) { @@ -8244,7 +8269,7 @@ void Main::checkUpdates() else userTriggered = false; - if (downloadsEnabled()) { + if (vymDownloadsEnabled()) { // Too much time passed since last update check? QDate lastChecked = settings.value("/downloads/updates/lastChecked", QDate(1970, 1, 1)) @@ -8263,7 +8288,7 @@ void Main::checkUpdates() // Notification: vym could not check for updates QMessageBox::warning(0, tr("Warning"), tr("Please allow vym to check for updates!")); - if (downloadsEnabled(userTriggered)) + if (vymDownloadsEnabled(userTriggered)) checkUpdates(); } } diff --git a/src/mainwindow.h b/src/mainwindow.h index c7e61c9..dd269e4 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -110,10 +110,15 @@ class Main : public QMainWindow { VymModel *currentModel() const; uint currentMapId() const; int currentMapIndex() const; - VymModel *getModel(uint); + VymModel *modelWithId(uint); bool gotoModel(VymModel *m); bool gotoModelWithId(uint id); + + public slots: bool closeModelWithId(uint id); + void closeSavedModels(); + + public: int modelCount(); void updateTabName(VymModel *vm); @@ -121,12 +126,9 @@ class Main : public QMainWindow { void editorChanged(); private: - int backgroundZipProcesses; - bool closeAfterLastZipProcess; + bool exitAfterLastMapClosed; public slots: - void backgroundZipStarted(); - void backgroundZipFinished(); bool fileLoad(QString, const File::LoadMode &, const File::FileType &ftype); void fileLoad(const File::LoadMode &); private slots: @@ -143,8 +145,8 @@ class Main : public QMainWindow { public slots: void fileSave(VymModel *); // autosave from MapEditor private slots: + bool fileSaveAs(const File::SaveMode &, QString fileName); void fileSaveAs(); - void fileSaveAs(const File::SaveMode &); void fileSaveAsDefault(); void fileImportFirefoxBookmarks(); void fileImportFreemind(); @@ -168,7 +170,9 @@ class Main : public QMainWindow { void fileExportTaskJuggler(); void fileExportXML(); void fileExportLast(); - bool fileCloseMap(int i = -1); // Optionally pass number of tab + void fileCloseTab(int i); // Index of tab + void fileCloseCurrentMap(); // Calls fileCloseModelWithId(-1); + void fileCloseMapWithId(uint i); // id = -1 uses current model void filePrint(); public: @@ -183,10 +187,10 @@ class Main : public QMainWindow { void setRepeatAction(const QString &script); public slots: - bool fileExitVYM(); + void fileExitVym(); void editUndo(); void editRedo(); - void gotoHistoryStep(int); + void gotoHistoryStep(uint modelId, int step); private slots: void editCopy(); @@ -254,7 +258,7 @@ class Main : public QMainWindow { void editAddBranchBelow(); void editImportAdd(); void editImportReplace(); - void editSaveBranch(); + void editSaveSelection(); void editDeleteKeepChildren(); void editDeleteChildren(); void editDeleteSelection(); @@ -367,7 +371,7 @@ class Main : public QMainWindow { void toggleProperty(); void focusHeadingEditor(); void toggleHeadingEditor(); - void updateHistory(SimpleSettings &); + void updateHistory(VymModel*, SimpleSettings &); void toggleAntiAlias(); bool isAliased(); bool hasSmoothPixmapTransform(); @@ -427,6 +431,8 @@ class Main : public QMainWindow { void helpDebugInfo(); void helpAbout(); void helpAboutQT(); + void helpVymDevelopment(); + void helpVymDevelopmentFinished(); void callMacro(); void downloadReleaseNotesFinished(); @@ -439,7 +445,7 @@ class Main : public QMainWindow { public slots: void checkReleaseNotes(); - bool downloadsEnabled(bool userTriggered = false); + bool vymDownloadsEnabled(bool userTriggered = false); void downloadUpdatesFinished(bool userTriggered = false); void downloadUpdatesFinishedInt(); void downloadUpdates(bool userTriggered); @@ -465,9 +471,11 @@ class Main : public QMainWindow { public: QList - mapEditorActions; //! allows mapEditor to clone actions and shortcuts + mapEditorActions; //! allows mapEditor to clone actions and shortcuts + QList + taskEditorActions; //! allows taskEditor to clone actions and shortcuts QList - taskEditorActions; //! allows taskEditor to clone actions and shortcuts + vimActions; //! Actions with vim inspired shortcuts private: QList restrictedMapActions; //! Actions reqire map and write access @@ -493,7 +501,6 @@ class Main : public QMainWindow { QList quickColors; QMenu *toolbarsMenu; - QMenu *toggleWindowsMenu; QMenu *focusWindowsMenu; QMenu *branchAddContextMenu; @@ -617,7 +624,7 @@ class Main : public QMainWindow { QAction *actionDeleteChildren; QAction *actionImportAdd; QAction *actionImportReplace; - QAction *actionSaveBranch; + QAction *actionSaveSelection; QAction *actionLoadImage; QAction *actionGrowSelectionSize; diff --git a/src/mapeditor.cpp b/src/mapeditor.cpp index 7d4dd39..394e894 100644 --- a/src/mapeditor.cpp +++ b/src/mapeditor.cpp @@ -213,9 +213,6 @@ MapEditor::MapEditor(VymModel *vm) winter = nullptr; // animations - animationUse = settings.value("/animation/use", true) .toBool(); - animationTicks = settings.value("/animation/snapback/ticks", 50).toInt(); - animationInterval = settings.value("/animation/snapback/interval", 15).toInt(); animatedContainers.clear(); animationTimer = new QTimer(this); connect(animationTimer, SIGNAL(timeout()), this, SLOT(animate())); @@ -279,7 +276,7 @@ void MapEditor::ensureAreaVisibleAnimated( bool rotated, qreal new_rotation) { - qDebug() << __func__ << "scaled=" << scaled << "rotated=" <repositionXLinks(); } @@ -539,7 +535,7 @@ void MapEditor::startAnimation(Container *c, const QPointF &start, AnimPoint ap; ap.setStart(start); ap.setDest(dest); - ap.setTicks(animationTicks); + ap.setTicks(settings.value("/animation/snapback/ticks", 50).toInt()); ap.setAnimated(true); c->setAnimation(ap); if (!animatedContainers.contains(c)) @@ -612,7 +608,6 @@ void MapEditor::setZoomFactorTarget(const qreal &zft) zoomAnimation.setStartValue(zoomFactorInt); zoomAnimation.setEndValue(zft); zoomAnimation.start(); - qDebug() << __func__ << zft; } else setZoomFactor(zft); @@ -674,7 +669,7 @@ void MapEditor::setViewCenterTarget(const QPointF &p, const qreal &zft, viewCenter = mapToScene(viewport()->geometry()).boundingRect().center(); - //qDebug() << __func__ << "zft=" << zft << "rot=" << at; + // qDebug() << __func__ << " p=" << toS(p) << " zft=" << zft << "rot=" << at; stopViewAnimations(); @@ -712,7 +707,7 @@ void MapEditor::setViewCenterTarget(const QPointF &p, const qreal &zft, } } -void MapEditor::setViewCenterTarget() +void MapEditor::setViewCenterSelection() { // qDebug() << __func__; QList seltis = model->getSelectedItems(); @@ -734,7 +729,10 @@ void MapEditor::setViewCenterTarget() setViewCenterTarget( p / n, 1, 0); } -QPointF MapEditor::getViewCenterTarget() { return viewCenterTarget; } +void MapEditor::setViewCenterTarget(QPointF p) +{ + setViewCenterTarget(p, zoomFactorTargetInt, rotationTargetInt); +} void MapEditor::setViewCenter(const QPointF &vc) { // For wheel events // useTransFormationOrigin == true @@ -1026,31 +1024,22 @@ TreeItem *MapEditor::findMapItem( const QList &excludedItems, bool findNearCenter) { - // Search XLinks - XLink *xlink; - for (int i = 0; i < model->xlinkCount(); i++) { - xlink = model->getXLinkNum(i); - if (xlink) { - XLinkObj *xlo = xlink->getXLinkObj(); - if (xlo) { - XLinkObj::SelectionType xlinkSelection = xlo->couldSelect(p); - if (xlinkSelection == XLinkObj::Path) { - // Found path of XLink, now return the nearest XLinkItem of p - qreal d0 = Geometry::distance(p, xlo->getBeginPos()); - qreal d1 = Geometry::distance(p, xlo->getEndPos()); - if (d0 < d1) - return xlink->beginXLinkItem(); - else - return xlink->endXLinkItem(); - } - if (xlinkSelection == XLinkObj::C0) - return xlink->beginXLinkItem(); - if (xlinkSelection == XLinkObj::C1) - return xlink->endXLinkItem(); - } + // If already a xlink is selected, try to find control points first + TreeItem *seli = model->getSelectedItem(); + if (seli && seli->hasTypeXLink()) { + XLinkItem* xli = (XLinkItem*)seli; + XLinkObj* xlo = xli->getXLinkObj(); + XLink* xl = xli->getXLink(); + if (xlo && xl) { + XLinkObj::SelectionType xlinkSelection = xlo->couldSelect(p); + if (xlinkSelection == XLinkObj::C0) + return xl->beginXLinkItem(); + if (xlinkSelection == XLinkObj::C1) + return xl->endXLinkItem(); } } + // Search branches (and their childs, e.g. images // Start with mapcenter, no images allowed at rootItem BranchItem *nearestFloatingCenter = nullptr; @@ -1087,6 +1076,31 @@ TreeItem *MapEditor::findMapItem( if (nearestFloatingCenter && d < 80 && !excludedItems.contains(nearestFloatingCenter)) return nearestFloatingCenter; + // Search XLinks + XLink *xlink; + for (int i = 0; i < model->xlinkCount(); i++) { + xlink = model->getXLinkNum(i); + if (xlink) { + XLinkObj *xlo = xlink->getXLinkObj(); + if (xlo) { + XLinkObj::SelectionType xlinkSelection = xlo->couldSelect(p); + if (xlinkSelection == XLinkObj::Path) { + // Found path of XLink, now return the nearest XLinkItem of p + qreal d0 = Geometry::distance(p, xlo->getBeginPos()); + qreal d1 = Geometry::distance(p, xlo->getEndPos()); + if (d0 < d1) + return xlink->beginXLinkItem(); + else + return xlink->endXLinkItem(); + } + if (xlinkSelection == XLinkObj::C0) + return xlink->beginXLinkItem(); + if (xlinkSelection == XLinkObj::C1) + return xlink->endXLinkItem(); + } + } + } + return nullptr; } @@ -2083,7 +2097,12 @@ void MapEditor::moveObject(QMouseEvent *e, const QPointF &p_event) // Add selected branches and images temporary to tmpParentContainer, // if they are not there yet: BranchContainer *bc_first = nullptr; - BranchContainer *bc_prev = nullptr; + bool branchesAttached = false; // True if branches were just added to tmpParentContainer + // Branches to animate into their position in tmpParentContainer. This + // excludes the first branch (bc_first): tmpParentContainer is positioned so + // that bc_first follows the cursor, so bc_first is already in its correct + // position and must not be animated (otherwise it would drift away). + QList animateAttached; if (movingItems.count() > 0 && (tmpParentContainer->childrenCount() == 0)) { BranchContainer *bc; foreach (TreeItem *ti, movingItems) @@ -2118,25 +2137,22 @@ void MapEditor::moveObject(QMouseEvent *e, const QPointF &p_event) bc->setOriginalPos(); bc->setOriginalOrientation(); // Also sets originalParentBranchContainer tmpParentContainer->addToBranchesContainer(bc); + branchesAttached = true; + // Animate all attached branches into their stacked position, + // except the first one, which tmpParentContainer is + // positioned by and is already in its correct place. + if (bc != bc_first) + animateAttached << bc; } - if (bc_first && bc_first != bc) { - QPointF p; - // Animate other items to position horizontally centered below first one - if (bc_first->getOriginalOrientation() == BranchContainer::RightOfParent) { - p = tmpParentContainer->mapFromItem(bc, - bc->alignTo(Container::TopLeft, bc_prev, Container::BottomLeft)); - } else if (bc_first->getOriginalOrientation() == BranchContainer::LeftOfParent) - p = tmpParentContainer->mapFromItem(bc, - bc->alignTo(Container::TopRight, bc_prev, Container::BottomRight)); - else - p = tmpParentContainer->mapFromItem(bc, - bc->alignTo(Container::TopCenter, bc_prev, Container::BottomCenter)); - - startAnimation ( bc, bc->pos(), p); - } - bc_prev = bc; + // Stacking the branches vertically and aligning them left/right + // according to orientation is done by tmpParentContainer->reposition() + // below (FloatingReservedSpace layout). Animating them into position + // must happen *after* reposition() has calculated the final positions: + // an active animation makes Container::setPos() ignore the coordinates + // calculated during reposition, so animating with positions guessed + // here would leave the moved branches at wrong x/y positions. } else if (ti->hasTypeImage()) { ImageContainer *ic = ((ImageItem*)ti)->getImageContainer(); if (ic->parentItem() != tmpParentContainer->getImagesContainer()) { @@ -2157,6 +2173,31 @@ void MapEditor::moveObject(QMouseEvent *e, const QPointF &p_event) } } // add to tmpParentContainer + // If branches have just been attached, remember their current (scattered) + // positions, so they can be animated into the stacked positions calculated + // by reposition() below - but only if animations are enabled globally. + // The first branch (bc_first) is excluded: tmpParentContainer follows the + // cursor via bc_first, so it is already in its correct position. + QList animationContainers; + QList animationStartPositions; + if (branchesAttached && settings.value("/animation/use", true).toBool()) { + foreach (BranchContainer *bc, animateAttached) { + animationContainers << bc; + animationStartPositions << bc->pos(); + } + } + + tmpParentContainer->reposition(); // Reposition children of tmpParentContainer, if necessary + + // Now that final positions are known, animate the branches into place + if (!animationContainers.isEmpty()) { + int i = 0; + foreach (BranchContainer *bc, animationContainers) { + startAnimation(bc, animationStartPositions.at(i), bc->pos()); + i++; + } + } + if (tmpParentContainer->childBranches().count() > 0) // If ME::moveObject is called AFTER tPC has been filled previously, // bc_first still might be unset here @@ -2469,6 +2510,7 @@ void MapEditor::mouseReleaseEvent(QMouseEvent *e) // Loop over images // FIXME-3 refactor in VM similar to relinkBranches foreach(ImageContainer *ic, tmpParentContainer->childImages()) { + ic->setMovingState(SelectableContainer::NotMoving); ImageItem *ii = ic->getImageItem(); model->relinkImage(ii, destinationBranch); } @@ -2515,6 +2557,23 @@ void MapEditor::mouseReleaseEvent(QMouseEvent *e) if (bi->depth() == 0) // MapCenter bc->setPos(bc->getHeadingContainer()->mapToScene(QPointF(0, 0))); + else { + // Re-anchor floating branch to the position it has on + // release. While moving, the branch was laid out under + // the (non-floating) tmpParentContainer, so its heading + // is not centered on the container origin. The final + // model->reposition() below will re-center the heading + // on the origin (the real parent is floating), which + // would shift the branch away from where it was dropped. + // Lay out the internals here the same way, then move the + // container so the heading stays where it was released. + QPointF headingScenePos = + bc->getHeadingContainer()->mapToScene(QPointF(0, 0)); + bc->reposition(); + QPointF headingScenePosNew = + bc->getHeadingContainer()->mapToScene(QPointF(0, 0)); + bc->setPos(bc->pos() + headingScenePos - headingScenePosNew); + } // Save position change QString uc, rc; uc = QString("setPos%1;").arg(toS(bc->getOriginalPos(), 5)); @@ -2531,7 +2590,7 @@ void MapEditor::mouseReleaseEvent(QMouseEvent *e) model->saveStateEndScript(); } // Empty tmpParenContainer - if (animationUse && animationContainers.count() > 0) { + if (settings.value("/animation/use", true) .toBool() && animationContainers.count() > 0) { int i = 0; foreach(BranchContainer *bc, animationContainers) { startAnimation(bc, animationCurrentPositions.at(i), bc->getOriginalPos()); @@ -2546,6 +2605,7 @@ void MapEditor::mouseReleaseEvent(QMouseEvent *e) } foreach(ImageContainer *ic, tmpParentContainer->childImages()) { + ic->setMovingState(SelectableContainer::NotMoving); ImageItem *ii = ic->getImageItem(); BranchItem *pi = ii->parentBranch(); diff --git a/src/mapeditor.h b/src/mapeditor.h index a94f786..197b9ba 100644 --- a/src/mapeditor.h +++ b/src/mapeditor.h @@ -128,9 +128,8 @@ class MapEditor : public QGraphicsView { const QPointF &p, const qreal &zft, const qreal &at, const int duration = 2000, const QEasingCurve &easingCurve = QEasingCurve::OutQuint); - void - setViewCenterTarget(); //! Convenience function, center on selected item - QPointF getViewCenterTarget(); + void setViewCenterSelection(); //! Convenience function, center on selected item + void setViewCenterTarget(QPointF p); //! Centers on target with previously set rotation/zoom targets void setViewCenter(const QPointF &p); QPointF getViewCenter(); QPropertyAnimation viewCenterAnimation; diff --git a/src/misc.cpp b/src/misc.cpp index cc229ad..4d2266b 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -233,11 +233,6 @@ void centerDialog(QDialog *dia) 0.5 * QPoint(dia->rect().width(), dia->rect().height())); } -// #include "version.h" - -// #include -// #include - bool versionLowerThanVym(const QString &v) { // returns true, if Version v < VYM_VERSION diff --git a/src/scripteditor.cpp b/src/scripteditor.cpp index 4f6f66f..5bbd2b1 100644 --- a/src/scripteditor.cpp +++ b/src/scripteditor.cpp @@ -102,7 +102,7 @@ ScriptEditor::ScriptEditor(QWidget *parent) : QWidget(parent) slideEditor->setStyleSheet("QPlainTextEdit {" + editorFocusInStyle + "}"); macroEditor->setStyleSheet("QPlainTextEdit {" + editorFocusInStyle + "}"); - QString shortcutScope = parentWidget()->windowTitle(); + QString shortcutScope = tr("Script editor", "Shortcut scope"); switchboard.addScope("MainWindow", shortcutScope); QAction *a = new QAction("Close window", this); @@ -137,7 +137,7 @@ QString ScriptEditor::getScriptFile() { return codeEditor->toPlainText(); } void ScriptEditor::saveSlide() { - VymModel *vm = mainWindow->getModel(vymModelID); + VymModel *vm = mainWindow->modelWithId(vymModelID); if (!vm) { QMessageBox::warning( 0, tr("Warning"), diff --git a/src/scriptoutput.cpp b/src/scriptoutput.cpp index 2ac5a55..0dc1c7b 100644 --- a/src/scriptoutput.cpp +++ b/src/scriptoutput.cpp @@ -1,11 +1,19 @@ #include "scriptoutput.h" +#include + ScriptOutput::ScriptOutput(QWidget *parent) : QWidget(parent) { editor = new QTextEdit(this); // FIXME-4 use QTextBrowser and add button to clear browser layout = new QVBoxLayout; layout->addWidget(editor); setLayout(layout); + + 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())); } ScriptOutput::~ScriptOutput() @@ -14,6 +22,8 @@ ScriptOutput::~ScriptOutput() delete editor; } +void ScriptOutput::closeWindow() { parentWidget()->hide(); } + void ScriptOutput::setFocus() { //FIXME-5 missing implementation // qDebug() << "SO::setFOcus"; // Currently ScriptEditor gets focus, when output is toggled diff --git a/src/scriptoutput.h b/src/scriptoutput.h index 000f5e3..226e0e8 100644 --- a/src/scriptoutput.h +++ b/src/scriptoutput.h @@ -15,6 +15,9 @@ class ScriptOutput : public QWidget { QString text(); void append(const QString &text); + public slots: + void closeWindow(); + private: QTextEdit *editor; QVBoxLayout *layout; diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp index 9795560..7bd4cd3 100644 --- a/src/shortcuts.cpp +++ b/src/shortcuts.cpp @@ -26,6 +26,23 @@ KeySwitch::KeySwitch(const QString &identifier, ///////////////////////////////////////////////////////////////// Switchboard::Switchboard() {} +QList Switchboard::valuesReversed(const QString &scope) +{ + QList list; + if (!scope.isEmpty()) + list = switchesMap.values(scope); + else + list = switchesMap.values(); + QList rlist; + + QListIterator it(list); + it.toBack(); + while (it.hasPrevious()) { + rlist << it.previous(); + } + return rlist; +} + void Switchboard::addScope(QString scopeIdentifier, QString scopeName) { if (!scopesMap.contains(scopeIdentifier)) @@ -80,10 +97,13 @@ QString Switchboard::getASCII() foreach (auto tag, tagsInScope) { s += underline(tag, "-"); - foreach (auto ksw, switchesMap.values(scope)) { + foreach (auto ksw, valuesReversed(scope)) { if (ksw.tagInt == tag) { QString desc = ksw.actionInt->text(); QString sc = ksw.actionInt->shortcut().toString(); + QString alt; + if (ksw.identifierInt.contains("VimAlt")) + alt = QObject::tr("(Vim alternative shortcut)","Shortcut help dialog"); if (!sc.isEmpty()) { #if defined(Q_OS_MACOS) sc.replace("Ctrl","Cmd"); @@ -91,16 +111,28 @@ QString Switchboard::getASCII() desc = desc.remove('&'); desc = desc.remove("..."); - s += QString(" %1: %2\n").arg(sc, 12).arg(desc); + s += QString(" %1: %2 %3\n").arg(sc, 12).arg(desc).arg(alt); } } } if (tag != tagsInScope.last()) s += "\n"; } - if (scope != switchesMap.uniqueKeys().last()) - s += "\n"; + s += "\n"; } + + // Finally list vim inspired shortcuts + s += underline("VIM-like shortcuts", "="); + foreach (auto ksw, valuesReversed()) { + QString sc = ksw.actionInt->shortcut().toString(); + if (!sc.isEmpty() && ksw.identifierInt.contains("Vim")) { + QString desc = ksw.actionInt->text(); + desc = desc.remove('&'); + desc = desc.remove("..."); + s += QString(" %1: %2\n").arg(sc, 12).arg(desc); + } + } + return s; } diff --git a/src/shortcuts.h b/src/shortcuts.h index c10b2ac..1c1e06a 100644 --- a/src/shortcuts.h +++ b/src/shortcuts.h @@ -23,6 +23,7 @@ class KeySwitch { class Switchboard { public: Switchboard(); + QList valuesReversed(const QString &scope = ""); 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); diff --git a/src/taskeditor.cpp b/src/taskeditor.cpp index f2c3605..65702c6 100644 --- a/src/taskeditor.cpp +++ b/src/taskeditor.cpp @@ -120,7 +120,7 @@ TaskEditor::TaskEditor(QWidget *) a = new QAction("Close window", this); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); - switchboard.addAction(a, "taskEditorCloseWindow", Qt::CTRL | Qt::Key_D, shortcutScope, ""); + switchboard.addAction(a, "taskEditorCloseWindow", Qt::CTRL | Qt::Key_D, shortcutScope, "Misc"); connect(a, SIGNAL(triggered()), this, SLOT(closeWindow())); view->addAction(a); diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 65e8bb1..38e4407 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "file.h" #include "mainwindow.h" @@ -108,14 +109,25 @@ TextEditor::~TextEditor() void TextEditor::init() { QString n = QString("/satellite/%1/").arg(editorId); + + // Toolbars + setupFileActions(); + setupEditActions(); + setupFormatActions(); + setupSettingsActions(); + + restoreState(settings.value(n + "state", 0).toByteArray()); + colorRichTextEditorBackground = QColor::fromString( settings.value(n + "colors/richTextEditorBackground", vymBaseColor.name()).toString()); colorRichTextForeground = QColor::fromString( settings.value(n + "colors/richTextForeground", vymForegroundColor.name()).toString()); + colorFGChanged(colorRichTextForeground); colorRichTextBackground = QColor::fromString( settings.value(n + "colors/richTextBackground", vymBaseColor.name()).toString()); + colorBGChanged(colorRichTextBackground); /* qDebug() << "TE::init" << scope; @@ -124,14 +136,6 @@ void TextEditor::init() qDebug() << " RTBG=" << colorRichTextBackground.name(); */ - // Toolbars - setupFileActions(); - setupEditActions(); - setupFormatActions(); - setupSettingsActions(); - - restoreState(settings.value(n + "state", 0).toByteArray()); - fileNameInt = ""; fixedFontInt = fixedFont; varFontInt = varFont; @@ -507,24 +511,47 @@ void TextEditor::setupFormatActions() formatToolBar->setStyleSheet(toolBarStyle); formatToolBar->setObjectName("noteEditorFormatToolBar"); - //QPixmap pix(16, 16); - //pix.fill(editor->textColor()); - //a = new QAction(pix, tr("&Text Color..."), this); - a = new QAction(tr("&Text Color..."), this); + a = new QAction(tr("&Color text using foreground color"), this); + switchboard.addAction(a, "Color text with foreground color", Qt::CTRL | Qt::Key_T, shortcutScope, tag); formatMenu->addAction(a); formatToolBar->addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(useTextFGColor())); + filledEditorRichTextActions << a; + actionUseTextFGColor = a; + + a = new QAction(tr("&Select text foreground color..."), this); + formatMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(selectTextFGColor())); filledEditorRichTextActions << a; - actionTextFGColor = a; + actionSelectTextFGColor = a; - //pix.fill(editor->textBackgroundColor()); - //a = new QAction(pix, tr("&Text background color..."), this); - a = new QAction(tr("&Text background color..."), this); + QToolButton *tb = new QToolButton; + tb->setArrowType(Qt::DownArrow); + tb->setDefaultAction(actionSelectTextFGColor); + formatToolBar->addWidget(tb); + tb->setFixedSize(22,44); + + a = new QAction(tr("&Mark text using background color..."), this); + switchboard.addAction(a, "Mark text using background color", Qt::CTRL | Qt::Key_M, shortcutScope, tag); formatMenu->addAction(a); formatToolBar->addAction(a); + connect(a, SIGNAL(triggered()), this, SLOT(useTextBGColor())); + filledEditorRichTextActions << a; + actionUseTextBGColor = a; + + a = new QAction(tr("&Select text background color..."), this); + formatMenu->addAction(a); connect(a, SIGNAL(triggered()), this, SLOT(selectTextBGColor())); filledEditorRichTextActions << a; - actionTextBGColor = a; + actionSelectTextBGColor = a; + + tb = new QToolButton; + tb->setArrowType(Qt::DownArrow); + tb->setDefaultAction(actionSelectTextBGColor); + formatToolBar->addWidget(tb); + tb->setFixedSize(22,44); + + formatMenu->addSeparator(); a = new QAction(QPixmap(QString(":/format-text-bold-%1.svg").arg(iconTheme)), tr("&Bold"), this); // a->setShortcutContext(Qt::WidgetWithChildrenShortcut); @@ -838,12 +865,16 @@ void TextEditor::deleteAll() editor->clear(); } -void TextEditor::textExportAs() +void TextEditor::textExportAs() // FIXME-2 Heading colors missing, BG color span missing { QString text, postfix; if (actionFormatRichText->isChecked()) { text = editor->toHtml(); postfix = ".html"; + QString fgcol = colorRichTextForeground.name(); + QString bgcol = colorRichTextEditorBackground.name(); + text.replace("white-space: pre-wrap;", "white-space: pre-wrap; color:" + fgcol + ";"); + text.replace("toPlainText(); postfix = ".txt"; @@ -862,6 +893,9 @@ void TextEditor::textExportAs() 0, QFileDialog::DontConfirmOverwrite); if (!fn.isEmpty()) { + +// Macs check for replacing existing file in native dialog +#ifndef Q_OS_MACOS QFile file(fn); if (file.exists()) { QMessageBox mb( @@ -874,6 +908,7 @@ void TextEditor::textExportAs() mb.exec(); if (mb.clickedButton() != overwriteButton) return; } +#endif fileNameInt = fn; @@ -994,6 +1029,11 @@ void TextEditor::textFamily(const QString &f) { editor->setFontFamily(f); } void TextEditor::textSize(const QString &p) { editor->setFontPointSize(p.toInt()); } +void TextEditor::useTextFGColor() +{ + editor->setTextColor( colorRichTextForeground); +} + void TextEditor::selectTextFGColor() { QColor col = QColorDialog::getColor( @@ -1004,6 +1044,13 @@ void TextEditor::selectTextFGColor() if (!col.isValid()) return; editor->setTextColor(col); + colorFGChanged(col); + colorRichTextForeground = col; +} + +void TextEditor::useTextBGColor() +{ + editor->setTextBackgroundColor(colorRichTextBackground); } void TextEditor::selectTextBGColor() @@ -1015,6 +1062,9 @@ void TextEditor::selectTextBGColor() QColorDialog::ShowAlphaChannel); if (!col.isValid()) return; + + colorRichTextBackground = col; + colorBGChanged(col); editor->setTextBackgroundColor(col); } @@ -1063,7 +1113,7 @@ void TextEditor::fontChanged(const QFont &f) actionTextUnderline->setChecked(f.underline()); } -void TextEditor::colorFGChanged(const QColor &c) +void TextEditor::colorFGChanged(const QColor &c) // FIXME-0 see also setRichTextForegroundColor { QImage image(":color-text.svg"); QPainter painter; @@ -1072,7 +1122,7 @@ void TextEditor::colorFGChanged(const QColor &c) painter.drawRect(0,110,128,128); painter.end(); - actionTextFGColor->setIcon(QPixmap::fromImage(image)); + actionUseTextFGColor->setIcon(QPixmap::fromImage(image)); } void TextEditor::colorBGChanged(const QColor &c) @@ -1084,7 +1134,7 @@ void TextEditor::colorBGChanged(const QColor &c) painter.drawRect(0,110,128,128); painter.end(); - actionTextBGColor->setIcon(QPixmap::fromImage(image)); + actionUseTextBGColor->setIcon(QPixmap::fromImage(image)); } void TextEditor::formatChanged(const QTextCharFormat &f) @@ -1093,8 +1143,8 @@ void TextEditor::formatChanged(const QTextCharFormat &f) if (!actionFormatRichText->isChecked()) return; fontChanged(f.font()); - colorFGChanged(f.foreground().color()); - colorBGChanged(f.background().color()); + // colorFGChanged(f.foreground().color()); // FIXME-0 + // colorBGChanged(f.background().color()); // FIXME-0 alignmentChanged(editor->alignment()); verticalAlignmentChanged(f.verticalAlignment()); } @@ -1175,7 +1225,7 @@ void TextEditor::updateActions() void TextEditor::setState(EditorState s) { - // qDebug() << "TE::setState" << s << editorName; + // qDebug() << "TE::setState" << s; QPalette p = qApp->palette(); QColor baseColor; state = s; @@ -1202,7 +1252,10 @@ void TextEditor::setState(EditorState s) baseColor = Qt::black; editor->setReadOnly(true); } + + // Just setting base color sometimes seems not enough... p.setColor(QPalette::Base, baseColor); + p.setColor(QPalette::Window, baseColor); editor->setPalette(p); updateActions(); @@ -1230,6 +1283,9 @@ void TextEditor::selectRichTextEditorBackgroundColor() QPixmap pix(16, 16); pix.fill(colorRichTextEditorBackground); actionActiveEditorBGColor->setIcon(pix); + + // Update color + setState(state); } void TextEditor::selectRichTextForegroundColor() @@ -1291,7 +1347,11 @@ void TextEditor::insertOrEditUrl(QTextCursor cursor) if (cursor.charFormat().isAnchor()) anchorEnd = pos; } +#if defined(QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) text = plainText.slice(anchorStart - 1, anchorEnd - anchorStart + 1); +#else + text = plainText.sliced(anchorStart - 1, anchorEnd - anchorStart + 1); +#endif } UrlDialog dia (this); diff --git a/src/texteditor.h b/src/texteditor.h index 75d2351..633d0cb 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -79,7 +79,9 @@ class TextEditor : public QMainWindow { void textItalic(); void textFamily(const QString &f); void textSize(const QString &p); + void useTextFGColor(); void selectTextFGColor(); + void useTextBGColor(); void selectTextBGColor(); void textAlign(QAction *); void textVAlign(); @@ -157,8 +159,10 @@ class TextEditor : public QMainWindow { *actionRichTextBGColor; QAction - *actionTextFGColor, - *actionTextBGColor, + *actionUseTextFGColor, + *actionSelectTextFGColor, + *actionUseTextBGColor, + *actionSelectTextBGColor, *actionTextBold, *actionTextUnderline, *actionTextItalic, *actionAlignSubScript, *actionAlignSuperScript, *actionAlignLeft, *actionAlignCenter, *actionAlignRight, diff --git a/src/tmp-parent-container.cpp b/src/tmp-parent-container.cpp index 62476ce..07b6965 100644 --- a/src/tmp-parent-container.cpp +++ b/src/tmp-parent-container.cpp @@ -24,12 +24,15 @@ void TmpParentContainer::init() // setPen(QPen(Qt::green)); // Uncomment for testing // TmpParentContainer defaults, should be overridden from MapDesign later - containerType = Container::TmpParent; + setContainerType(Container::TmpParent); setLayout(Container::FloatingReservedSpace); branchesContainer = new Container (); branchesContainer->setContainerType(Container::BranchesContainer); + // Stack moved branches vertically. The horizontal (left/right) alignment + // is set depending on orientation in TmpParentContainer::reposition(). + branchesContainer->setLayout(Container::Vertical); branchesContainer->setParentItem(this); // Different for BranchItem! } @@ -53,7 +56,6 @@ void TmpParentContainer::addToImagesContainer(Container *c) { if (!imagesContainer) { createImagesContainer(); - imagesContainer->setParentItem(this); // Different for BranchItem! } diff --git a/src/treeeditor.cpp b/src/treeeditor.cpp index c968567..4ebc797 100644 --- a/src/treeeditor.cpp +++ b/src/treeeditor.cpp @@ -107,7 +107,6 @@ void TreeEditor::contextMenuEvent(QContextMenuEvent *e) { void TreeEditor::closeWindow() { - qDebug() << __func__; // Close *all* TreeEditors in each VymView and update vym settings mainWindow->setTreeEditorsVisibility(false); } diff --git a/src/version.h b/src/version.h index 98e19f2..ec2c70d 100644 --- a/src/version.h +++ b/src/version.h @@ -1,17 +1,15 @@ #ifndef VERSION_H #define VERSION_H -#define __VYM_VERSION "2.9.604" -#define __VYM_BUILD_DATE "2027-01-20" +#define __VYM_VERSION "3.0.1" - -#define __VYM_NAME "VYMng" // FIXME "next generation" in in window title +#define __VYM_NAME "VYM" #define __VYM_HOME "http://www.insilmaril.de/vym" -// -//#define __VYM_CODE_QUALITY "Production" + +#define __VYM_CODE_QUALITY "Production" //#define __VYM_CODE_QUALITY "*Experimental*" -#define __VYM_CODE_QUALITY "*Beta*" -#define __VYM_CODENAME "Beta release of upcoming 3.0.0" -//#define __VYM_CODENAME "Debug version of upcoming 3.0.0" +//#define __VYM_CODE_QUALITY "*Beta*" + +#define __VYM_CODENAME "Save the climate day" #endif diff --git a/src/vym-wrapper.cpp b/src/vym-wrapper.cpp index ce99df6..d728c9e 100644 --- a/src/vym-wrapper.cpp +++ b/src/vym-wrapper.cpp @@ -30,13 +30,13 @@ VymWrapper::~VymWrapper() void VymWrapper::clearConsole() { mainWindow->clearScriptOutput(); } -bool VymWrapper::closeMapWithID(uint n) +bool VymWrapper::closeMapWithId(uint id) { - bool r = mainWindow->closeModelWithId(n); + bool r = mainWindow->closeModelWithId(id); if (!r) { mainWindow->abortScript( QJSValue::ReferenceError, - QString("Map '%1' not available.").arg(n)); + QString("VmWrapper::closeMapWithId Map '%1' not available.").arg(id)); return false; } // Remove progress counter while testing @@ -64,13 +64,13 @@ QObject *VymWrapper::currentMap() return mw; } -QObject *VymWrapper::mapWithId(uint n) +QObject *VymWrapper::mapWithId(uint id) { - VymModel *m = mainWindow->getModel(n); + VymModel *m = mainWindow->modelWithId(id); if (!m) { mainWindow->abortScript( QJSValue::ReferenceError, - QString("No model available with id=%1").arg(n)); + QString("No model available with id=%1").arg(id)); } return (QObject*)(m->getWrapper()); } @@ -148,7 +148,7 @@ void VymWrapper::gotoMap(uint n) if (!mainWindow->gotoModelWithId(n)) { mainWindow->abortScript( QJSValue::ReferenceError, - QString("Map '%1' not available.").arg(n)); + QString("VymWrapper::gotoMap Map '%1' not available.").arg(n)); return; } } @@ -227,7 +227,7 @@ void VymWrapper::selectQuickColor(int n) mainWindow->selectQuickColor(n); } -uint VymWrapper::currentMapID() +uint VymWrapper::currentMapId() { uint r = mainWindow->currentMapId(); mainWindow->setScriptResult(r); diff --git a/src/vym-wrapper.h b/src/vym-wrapper.h index 26fc176..78308b8 100644 --- a/src/vym-wrapper.h +++ b/src/vym-wrapper.h @@ -16,11 +16,11 @@ class VymWrapper : public QObject { public slots: void clearConsole(); - bool closeMapWithID(uint n); + bool closeMapWithId(uint n); QString currentColor(); Q_INVOKABLE QObject *currentMap(); Q_INVOKABLE QObject *mapWithId(uint n); - uint currentMapID(); + uint currentMapId(); void editHeading(); bool directoryIsEmpty(const QString &dirName); bool directoryExists(const QString &dirName); diff --git a/src/vymmodel.cpp b/src/vymmodel.cpp index 1b8a4ed..8f967c2 100644 --- a/src/vymmodel.cpp +++ b/src/vymmodel.cpp @@ -224,8 +224,8 @@ void VymModel::init() hideMode = TreeItem::HideNone; // Animation in MapEditor - zoomFactor = 1; - mapRotationInt = 0; + viewZoomFactorInt = 1; + viewRotationInt = 0; animDuration = 2000; animCurve = QEasingCurve::OutQuint; @@ -277,6 +277,21 @@ void VymModel::updateActions() mainWindow->updateActions(); } +void VymModel::closeAfterSaving() { + closeAfterSavingInt = true; +} + +bool VymModel::readyToClose() { + // Check for background processes before closing map in mainWindow + // (Currently only zipAgent for saving) + return zipAgent ? false : true; +} + +void VymModel::setSaveAsBackgroundProcess(bool b) +{ + saveAsBackgroundProcessInt = b; +} + bool VymModel::setData(const QModelIndex &, const QVariant &value, int role) { if (role != Qt::EditRole) @@ -329,10 +344,15 @@ QString VymModel::saveToDir(const QString &tmpdir, const QString &prefix, 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())); + mapAttr += xml.attribute("viewZoomFactor", + QString().setNum(mapEditor->zoomFactorTarget())); + mapAttr += xml.attribute("viewRotation", + QString().setNum(mapEditor->rotationTarget())); + QPointF viewport_center = mapEditor->mapToScene(mapEditor->viewport()->geometry().center()); + mapAttr += xml.attribute("viewCenterX", + QString().setNum(viewport_center.x())); + mapAttr += xml.attribute("viewCenterY", + QString().setNum(viewport_center.y())); } } header += xml.beginElement("vymmap", mapAttr); @@ -470,14 +490,12 @@ bool VymModel::loadMap(QString fname, const File::LoadMode &lmode, BranchItem *insertBranch, int insertPos) { - qDebug() << "a) Loading " << fname; - bool noError = true; - // Get updated zoomFactor, before applying one read from file in the end + // Get updated viewZoomFactor, before applying one read from file in the end if (mapEditor) { - zoomFactor = mapEditor->zoomFactorTarget(); - mapRotationInt = mapEditor->rotationTarget(); + viewZoomFactorInt = mapEditor->zoomFactorTarget(); + viewRotationInt = mapEditor->rotationTarget(); } BaseReader *reader; @@ -727,19 +745,15 @@ bool VymModel::loadMap(QString fname, const File::LoadMode &lmode, if (lmode != File::NewMap) emitUpdateQueries(); - qDebug() << "b) Loaded " << fname; if (mapEditor) { - mapEditor->setZoomFactorTarget(zoomFactor); - mapEditor->setRotationTarget(mapRotationInt); + mapEditor->setZoomFactorTarget(viewZoomFactorInt); + mapEditor->setRotationTarget(viewRotationInt); } - qDebug() << "c) Loaded " << fname; qApp->processEvents(); // Update view (scene()->update() is not enough) isLoadingInt = false; - qDebug() << "d) Loaded " << fname; - return noError; } @@ -809,7 +823,7 @@ bool VymModel::saveMap(const File::SaveMode &savemode) if (!f.rename(backupFileName)) { QMessageBox::warning( 0, tr("Save Error"), - tr("%1\ncould not be renamed before saving") + tr("%1\ncould not be renamed as backup file before saving") .arg(destPath)); } } @@ -898,11 +912,18 @@ bool VymModel::saveMap(const File::SaveMode &savemode) QString log = QString("Starting zipAgent to compress \"%1\" in zipDirInt = %2") .arg(mapFileName, zipDirInt.path()); logInfo(log, __func__); - zipAgent->startZip(); - } else + zipAgent->setBackgroundProcess(saveAsBackgroundProcessInt); + bool r = zipAgent->startZip(); + logInfo("Started zip to save map " + destPath + " Result: " + toS(r), __func__); // FIXME-3 debugging + if (!saveAsBackgroundProcessInt && !r) { + qDebug() << "ok3 Result: " << r; + logInfo("Problems starting zip as foreground process", __func__); + } + } else { mainWindow->statusMessage(tr("Saved %1").arg(saveFilePath)); + logInfo("Finishing saving unzipped map " + destPath, __func__); // FIXME-3 debugging + } - logInfo("Finishing saving map " + destPath, __func__); // FIXME-3 debugging // Restore original filepath outside of tmp zip dir setFilePath(saveFilePath); } @@ -944,6 +965,8 @@ void VymModel::zipFinished() zipAgent->deleteLater(); zipAgent = nullptr; + + // qDebug() << "VM::" << __func__ << path << name; } else logWarning("zipAgent == nullptr", __func__); @@ -951,10 +974,15 @@ void VymModel::zipFinished() mainWindow->statusMessage(tr("Saved %1").arg(filePath)); + if (closeAfterSavingInt) { + // Schedule for removal of tab in MainWindow + QTimer::singleShot(100, mainWindow, SLOT(closeSavedModels())); + return; + } + fileChangedTime = QFileInfo(destPath).lastModified(); updateActions(); - } ImageItem* VymModel::loadImage(BranchItem *parentBranch, const QStringList &imagePaths) @@ -1029,6 +1057,9 @@ void VymModel::saveImage(ImageItem *ii, QString fn) if (!fn.isEmpty()) { lastImageDir.setPath(fn.left(fn.lastIndexOf("/"))); + +// Macs check for replacing existing file in native dialog +#ifndef Q_OS_MACOS if (QFile(fn).exists()) { QMessageBox mb( QMessageBox::Warning, @@ -1036,16 +1067,17 @@ void VymModel::saveImage(ImageItem *ii, QString fn) tr("The file %1 exists already.\n" "Do you want to overwrite it?") .arg(fn)); - mb.addButton( + QPushButton *overwriteButton = mb.addButton( tr("Overwrite"), QMessageBox::AcceptRole); mb.addButton( tr("Cancel"), QMessageBox::RejectRole); mb.exec(); - if (mb.result() != QMessageBox::AcceptRole) + if (mb.clickedButton() != overwriteButton) return; } +#endif if (!ii->saveImage(fn)) QMessageBox::critical(0, tr("Critical Error"), tr("Couldn't save %1").arg(fn)); @@ -1193,15 +1225,32 @@ bool VymModel::addMapReplace(QString fpath, BranchItem *bi) return false; } + BranchItem *pbi = selbi->parentBranch(); + QString bv = setBranchVar(selbi); - QString pbv = setBranchVar(selbi->parentBranch(), "pb"); - QString uc = pbv + QString("map.loadBranchReplace(\"UNDO_PATH\", pb);"); QString rc = bv + QString("map.loadBranchReplace(\"REDO_PATH\", b);"); - QString comment = QString("Replace \"%1\" with \"%2\"").arg(selbi->headingText(), fpath); + QString comment = QString("Replace \"%1\" with \"%2\"").arg(selbi->headingText(), fpath); logAction(rc, comment, __func__); - saveState(uc, rc, comment, selbi->parentBranch(), selbi); + if (pbi == rootItem) { + // About to replace a MapCenter, save complete map instead of "parent" branch + // + // FIXME-4: addMapReplace() The path to the map is saved in history, + // the file might no longer be available when redo is performed + QString uc = QString("map.replaceTree(\"UNDO_PATH\");"); + QString bv = setBranchVar(selbi); + QString rc = bv + QString("map.loadBranchReplace(\"%1\", b);").arg(fpath); + saveState(uc, rc, comment, rootItem, selbi); + } else { + // Replace selected branch + QString pbv = setBranchVar(pbi, "pb"); + QString uc = pbv + QString("map.loadBranchReplace(\"UNDO_PATH\", pb);"); + QString bv = setBranchVar(selbi); + QString rc = bv + QString("map.loadBranchReplace(\"REDO_PATH\", b);"); + saveState(uc, rc, comment, pbi, selbi); + } + if (loadMap(fpath, File::ImportReplace, File::VymMap, 0x0000, selbi)) return true; @@ -1210,6 +1259,30 @@ bool VymModel::addMapReplace(QString fpath, BranchItem *bi) return false; } +bool VymModel::replaceTree(QString fpath) +{ + /* + // Only saveState if a branch is inserted + // Other data like XLink is only used for undo/redo operations and currently + // does not need a saveState + QString bv = setBranchVar(selbi); + QString uc = bv + QString("map.loadBranchReplace(\"UNDO_PATH\", b);"); + QString rc = bv + QString("b.loadBranchInsert(\"%1\", %2);").arg(fpath).arg(insertPos); + QString comment = QString("Add map %1 to \"%2\"").arg(fpath, selbi->headingText()); + + logAction(rc, comment, __func__); + + saveState(uc, rc, comment, selbi); + */ + + clear(); + if (loadMap(fpath, File::ImportAdd)) + return true; + else { + logWarning("Failed: Replacing tree with " + fpath, __func__); + return false; + } +} bool VymModel::removeVymLock() { if (vymLock.removeLockForced()) { @@ -1295,12 +1368,13 @@ bool VymModel::tryVymLock() return true; } -bool VymModel::renameMap(const QString &newPath) -// map is renamed before fileSaveAs() or from VymModelWrapper::saveSelection() -// Usually renamed back to original name again. Purpose here is to adapt the lockfile -// new name of map. -// Internally the paths in ImageItems pointing to zipDirInt do not need to be adapted. +bool VymModel::changeLock(const QString &newPath) { + // New lock is required in fileSaveAs(CompleteMap) + + if (zipAgent) + qWarning() << __func__ << " has still running zipAgent"; + QString oldPath = filePath; if (vymLock.getState() == VymLock::LockedByMyself || vymLock.getState() == VymLock::Undefined) { // vymModel owns the lockfile, try to create new lock @@ -1316,12 +1390,12 @@ bool VymModel::renameMap(const QString &newPath) if (!vymLock.releaseLock()) logWarning(QString("Failed to release lock for %1").arg(oldPath), __func__); vymLock = newLock; - setFilePath(newPath); + if (readonly) setReadOnly(false); return true; } - logWarning("Failed to rename map.", __func__); + logWarning("Failed to change lock file.", __func__); return false; } @@ -1527,7 +1601,7 @@ void VymModel::redo() undoSet.setValue("/history/curStep", QString::number(curStep)); undoSet.writeSettings(histPath); - mainWindow->updateHistory(undoSet); + mainWindow->updateHistory(this, undoSet); updateActions(); @@ -1657,7 +1731,7 @@ void VymModel::undo() undoSet.setValue("/history/curStep", QString::number(curStep)); undoSet.writeSettings(histPath); - mainWindow->updateHistory(undoSet); + mainWindow->updateHistory(this, undoSet); updateActions(); } @@ -1711,7 +1785,7 @@ void VymModel::resetHistory() stepsTotal = settings.value("/history/stepsTotal", 100).toInt(); undoSet.setValue("/history/stepsTotal", QString::number(stepsTotal)); - mainWindow->updateHistory(undoSet); + mainWindow->updateHistory(this, undoSet); } QString VymModel::setAttributeVar(AttributeItem* ai, QString varName) @@ -1778,14 +1852,17 @@ QString VymModel::saveState( return QString(); /* + */ if (debug) { qDebug() << "VM::saveState() for map " << mapName; qDebug() << " comment: " << comment; qDebug() << " Script: " << buildingUndoScript; qDebug() << " undoCom: " << undoCommand; qDebug() << " redoCom: " << redoCommand; + qDebug() << " undoItem: " << saveUndoItem; + qDebug() << " redoItem: " << saveRedoItem; + qDebug() << " rootItem: " << rootItem; } - */ if (buildingUndoScript) logInfo("// Building script: " + redoCommand + " " + comment, __func__); // FIXME-3 Use logDebug instead? Remove logging completely from saveState? @@ -1807,8 +1884,14 @@ QString VymModel::saveState( // FIXME-5 saveState: userFlags are not written, but still in memory. Could // lead to problem, if one day removed from userFlags toolbar AND memory if (saveUndoItem) { + bool completeTree = false; + if (saveUndoItem == rootItem) { + completeTree = true; + saveUndoItem = nullptr; + } + QString dataXML = saveToDir(historyPath, mapName + "-", FlagRowMaster::NoFlags, QPointF(), - false, false, false, saveUndoItem); + false, false, completeTree, saveUndoItem); QString xmlUndoPath = historyPath + "/undo.xml"; undoCommand.replace("UNDO_PATH", xmlUndoPath); @@ -1887,7 +1970,7 @@ QString VymModel::saveState( } */ - mainWindow->updateHistory(undoSet); + mainWindow->updateHistory(this, undoSet); setChanged(); @@ -1912,7 +1995,7 @@ QString VymModel::saveStateBranch( void VymModel::saveStateBeginScript(const QString &comment) { if (buildingUndoScript) - logWarning("Nested saveState scripts found", __func__); // FIXME-3 e.g. for setFrameAutoDesign... + logWarning(QString("Nested saveState scripts found \"%1\"").arg(comment), __func__); // FIXME-3 e.g. for setFrameAutoDesign... else { logDebug("Starting to build saveStateScript: '" + comment + "'", __func__); @@ -2664,10 +2747,9 @@ void VymModel::setFrameAutoDesign(const bool &useInnerFrame, const bool &newAuto { QList selbis = getSelectedBranches(bi); - foreach (BranchItem *selbi, selbis) { BranchContainer *bc = selbi->getBranchContainer(); - if (bc->frameAutoDesign(useInnerFrame) != newAutoDesign) { + if (bc->frameAutoDesign(useInnerFrame) != newAutoDesign || newAutoDesign == true) { QString uif = toS(useInnerFrame); QString b_undo = toS(!newAutoDesign); QString b_redo = toS(newAutoDesign); @@ -2680,13 +2762,13 @@ void VymModel::setFrameAutoDesign(const bool &useInnerFrame, const bool &newAuto saveStateBeginScript(comment); // setFrameAD, calls setFrame* functions - bc->setFrameAutoDesign(useInnerFrame, newAutoDesign); if (newAutoDesign) { setFrameType(useInnerFrame, mapDesignInt->frameType(useInnerFrame, selbi->depth()), selbi); setFramePenColor(useInnerFrame, mapDesignInt->framePenColor(useInnerFrame, selbi->depth()), selbi); setFramePenWidth(useInnerFrame, mapDesignInt->framePenWidth(useInnerFrame, selbi->depth()), selbi); setFrameBrushColor(useInnerFrame, mapDesignInt->frameBrushColor(useInnerFrame, selbi->depth()), selbi); } + bc->setFrameAutoDesign(useInnerFrame, newAutoDesign); emitDataChanged(selbi); branchPropertyEditor->updateControls(); @@ -2705,7 +2787,6 @@ void VymModel::setFrameType(const bool &useInnerFrame, const FrameContainer::Fra if (bc->frameType(useInnerFrame) == t) continue; - setFrameAutoDesign(useInnerFrame, false, selbi); QString uif = toS(useInnerFrame); @@ -2779,8 +2860,6 @@ void VymModel::setFramePenColor(const bool &useInnerFrame, const QColor &col, Br foreach (BranchItem *selbi, selbis) { BranchContainer *bc = selbi->getBranchContainer(); if (bc->frameType(useInnerFrame) != FrameContainer::NoFrame) { - setFrameAutoDesign(useInnerFrame, false, selbi); - QString uif = toS(useInnerFrame); QString colorNameOld = bc->framePenColor(useInnerFrame).name(); QString uc = QString("setFramePenColor (%1, \"%2\");").arg(uif, colorNameOld); @@ -2807,7 +2886,6 @@ void VymModel::setFrameBrushColor( foreach (BranchItem *selbi, selbis) { BranchContainer *bc = selbi->getBranchContainer(); if (bc->frameType(useInnerFrame) != FrameContainer::NoFrame) { - setFrameAutoDesign(useInnerFrame, false, selbi); QString uif = toS(useInnerFrame); QString colorNameOld = bc->framePenColor(useInnerFrame).name(); @@ -2834,8 +2912,6 @@ void VymModel::setFramePadding( foreach (BranchItem *selbi, selbis) { BranchContainer *bc = selbi->getBranchContainer(); if (i != bc->framePadding(useInnerFrame)) { - setFrameAutoDesign(useInnerFrame, false, selbi); - QString uif = toS(useInnerFrame); QString uc = QString("setFramePadding (%1, \"%2\");").arg(uif).arg(bc->framePadding(useInnerFrame)); QString rc = QString("setFramePadding (%1, \"%2\");").arg(uif).arg(i); @@ -2861,8 +2937,6 @@ void VymModel::setFramePenWidth( foreach (BranchItem *selbi, selbis) { BranchContainer *bc = selbi->getBranchContainer(); if (i != bc->framePenWidth(useInnerFrame)) { - setFrameAutoDesign(useInnerFrame, false, selbi); - QString uif = toS(useInnerFrame); QString uc = QString("setFramePenWidth (%1, \"%2\");").arg(uif).arg(bc->framePenWidth(useInnerFrame)); QString rc = QString("setFramePenWidth (%1, \"%2\");").arg(uif).arg(i); @@ -4671,6 +4745,9 @@ bool VymModel::relinkBranches(QList branches, BranchItem *dst, int endMoveRows(); emit layoutChanged(); + // Insert further branches after this one to keep their original order + num_dst = bi->num() + 1; + // Update upLink of BranchContainer to *parent* BC of destination bc->linkTo(dstBC); @@ -4733,6 +4810,48 @@ bool VymModel::relinkBranches(QList branches, BranchItem *dst, int return true; } +bool VymModel::moveSelectionToTarget(BranchItem *dst) +{ + if (!dst) + return false; + + QList branches = getSelectedBranches(); + if (branches.isEmpty()) + return false; + + // Find branch, which will be selected after moving. Makes it easier + // to quickly resort using the MoveTo function. + // Look for nearest sibling of first selection, which is not moved itself + BranchItem *nextSelection = nullptr; + BranchItem *pi = branches.first()->parentBranch(); + if (pi && pi != rootItem) { + int n = branches.first()->num(); + for (int i = n + 1; i < pi->branchCount() && !nextSelection; i++) + if (!branches.contains(pi->getBranchNum(i))) + nextSelection = pi->getBranchNum(i); + + for (int i = n - 1; i >= 0 && !nextSelection; i--) + if (!branches.contains(pi->getBranchNum(i))) + nextSelection = pi->getBranchNum(i); + + if (!nextSelection) + nextSelection = pi; + } + + if (!relinkBranches(branches, dst, -1)) + return false; + + if (nextSelection) + select(nextSelection); + + QString repeatAction = QString("m = vym.currentMap();"); + repeatAction += QString(" dst = m.findBranchById(\"%1\");").arg(dst->getUuid().toString()); + repeatAction += " m.moveSelectionToTarget(dst);"; + mainWindow->setRepeatAction(repeatAction); + + return true; +} + bool VymModel::relinkImage(ImageItem* image, TreeItem *dst_ti, int num_new) { if (!image) return false; @@ -5180,6 +5299,10 @@ bool VymModel::scrollBranch(BranchItem *bi) logAction(r, c, __func__); saveState(u, r, c); emitDataChanged(bi); + + if (mapEditor) + mapEditor->stopContainerAnimations(); + reposition(); return true; } @@ -5201,6 +5324,9 @@ bool VymModel::unscrollBranch(BranchItem *bi) saveState(u, r, c); emitDataChanged(bi); + if (mapEditor) + mapEditor->stopContainerAnimations(); + reposition(); return true; } @@ -5243,6 +5369,10 @@ void VymModel::unscrollSubtree(BranchItem *bi) } } updateActions(); + + if (mapEditor) + mapEditor->stopContainerAnimations(); + reposition(); } @@ -6446,7 +6576,7 @@ bool VymModel::exportLastAvailable(QString &description, QString &command, if (match.hasMatch()) { command = QString("vym.currentMap().exportMap([%1]);").arg(match.captured(1)); settings.setLocalValue(filePath, "/export/last/command", command); - qDebug() << "Rewriting last export command to version " << vymVersion << " format: " << command; + //qDebug() << "Rewriting last export command to version " << vymVersion << " format: " << command; } description = settings.localValue(filePath, "/export/last/description", "") @@ -6557,18 +6687,18 @@ void VymModel::exportMarkdown(const QString &fname, bool askName) void VymModel::registerMapEditor(QWidget *e) { mapEditor = (MapEditor *)e; } -void VymModel::setMapZoomFactor(const double &d) +void VymModel::setViewZoomFactor(const double &d) { if (!mapEditor) { qWarning() << __func__ << "mapEditor == nullptr"; return; } - zoomFactor = d; + viewZoomFactorInt = d; mapEditor->setZoomFactorTarget(d); } -void VymModel::setMapRotation(const double &a) +void VymModel::setViewRotation(const double &a) { if (!mapEditor) { qWarning() << __func__ << "mapEditor == nullptr"; @@ -6578,15 +6708,15 @@ void VymModel::setMapRotation(const double &a) if (a < 1) // Round to zero, otherwise selectionMode in MapEditor might be // "Geometric" when it should be "Classic" - mapRotationInt = 0; + viewRotationInt = 0; else - mapRotationInt = a; - mapEditor->setRotationTarget(mapRotationInt); + viewRotationInt = a; + mapEditor->setRotationTarget(viewRotationInt); } -void VymModel::setMapAnimDuration(const int &d) { animDuration = d; } +void VymModel::setViewAnimDuration(const int &d) { animDuration = d; } -void VymModel::setMapAnimCurve(const QEasingCurve &c) { animCurve = c; } +void VymModel::setViewAnimCurve(const QEasingCurve &c) { animCurve = c; } bool VymModel::centerOnID(const QString &id) { @@ -6605,9 +6735,9 @@ bool VymModel::centerOnID(const QString &id) c = ((MapItem*)ti)->getContainer(); p_center = c->mapToScene(c->rect().center()); } - if (zoomFactor > 0 ) { - mapEditor->setViewCenterTarget(p_center, zoomFactor, - mapRotationInt, animDuration, + if (viewZoomFactorInt > 0 ) { + mapEditor->setViewCenterTarget(p_center, viewZoomFactorInt, + viewRotationInt, animDuration, animCurve); return true; } @@ -6615,6 +6745,22 @@ bool VymModel::centerOnID(const QString &id) return false; } +void VymModel::setViewCenterTarget(const QPointF &p) +{ + viewCenterTargetInt = p; + hasViewCenterTargetInt = true; +} + +QPointF VymModel::viewCenterTarget() +{ + return viewCenterTargetInt; +} + +bool VymModel::hasViewCenterTarget() +{ + return hasViewCenterTargetInt; +} + void VymModel::setContextPos(QPointF p) { contextPos = p; @@ -6629,11 +6775,11 @@ void VymModel::unsetContextPos() void VymModel::reposition(bool force) { + //qDebug() << "VM::reposition start force=" << force << " repositionBlocked=" << repositionBlocked; + if (!force && repositionBlocked) return; - //qDebug() << "VM::reposition start force=" << force; - // Reposition containers BranchItem *bi; for (int i = 0; i < rootItem->branchCount(); i++) { @@ -6890,24 +7036,6 @@ void VymModel::setLinkColorHint(const LinkObj::ColorHint &newHint) logAction(rc, com, __func__); saveState(uc, rc, com); - BranchItem *cur = nullptr; - BranchItem *prev = nullptr; - nextBranch(cur, prev); - while (cur) { - BranchContainer *bc = cur->getBranchContainer(); - LinkObj *upLink = bc->getLink(); - if (upLink) - upLink->setLinkColorHint(newHint); - - // FIXME-4 setLinkColorHint: images currently use branch link color - for (int i = 0; i < cur->imageCount(); ++i) { - upLink = cur->getImageNum(i)->getImageContainer()->getLink(); - if (upLink) - upLink->setLinkColorHint(newHint); - } - nextBranch(cur, prev); - } - applyDesignRecursively(MapDesign::LinkStyleChanged, rootItem); reposition(); } @@ -7270,6 +7398,7 @@ void VymModel::setSelectionPenColor(QColor col) selPen.setColor(col); mapDesignInt->setSelectionPen(selPen); vymView->updateColors(); + updateSelection(selModel->selection(), QItemSelection()); } QColor VymModel::getSelectionPenColor() { @@ -7289,6 +7418,7 @@ void VymModel::setSelectionPenWidth(qreal w) selPen.setWidth(w); mapDesignInt->setSelectionPen(selPen); vymView->updateColors(); + updateSelection(selModel->selection(), QItemSelection()); } qreal VymModel::getSelectionPenWidth() { @@ -7310,6 +7440,7 @@ void VymModel::setSelectionBrushColor(QColor col) selBrush.setColor(col); mapDesignInt->setSelectionBrush(selBrush); vymView->updateColors(); + updateSelection(selModel->selection(), QItemSelection()); } QColor VymModel::getSelectionBrushColor() { @@ -7649,7 +7780,6 @@ void VymModel::appendSelectionToHistory() // FIXME-3 history unable to cope with void VymModel::emitShowSelection(bool scaled, bool rotated) { - //qDebug() << "VM::" << __func__ << "scaled=" << scaled << "rotated=" << rotated; if (!repositionBlocked) emit showSelection(scaled, rotated); } diff --git a/src/vymmodel.h b/src/vymmodel.h index bad7d1a..9bfdffc 100644 --- a/src/vymmodel.h +++ b/src/vymmodel.h @@ -88,8 +88,17 @@ class VymModel : public TreeModel { //////////////////////////////////////////// // Load/save //////////////////////////////////////////// + public: + void closeAfterSaving(); + bool readyToClose(); + void setSaveAsBackgroundProcess(bool); + + private: + bool closeAfterSavingInt = false; + private: bool zipped; // should map be zipped + bool saveAsBackgroundProcessInt = true; static int mapNum; // unique number for model used in save/undo File::FileType fileType; // type of file, e.g. vym, freemind... QString fileName; // short name of file (for tab) @@ -201,13 +210,14 @@ class VymModel : public TreeModel { void importDir(); bool addMapInsert(QString filepath, int pos = -1, BranchItem *bi = nullptr); bool addMapReplace(QString filepath, BranchItem *bi = nullptr); + bool replaceTree(QString filepath); private: bool removeVymLock(); public: bool tryVymLock(); - bool renameMap(const QString &newPath); //! Rename map and change lockfile + bool changeLock(const QString &newPath); //! Change lockfile to new path void setReadOnly(bool b); bool isReadOnly(); @@ -530,6 +540,15 @@ class VymModel : public TreeModel { bool relinkTo(const QString &dest, int num); + /*! \brief Move selected branches to target dst + + Relinks all selected branches to dst and afterwards selects a + branch near the original position, which makes it easier to + quickly resort several branches. The action can be repeated + with the "."-key. + */ + bool moveSelectionToTarget(BranchItem *dst); + public: void deleteSelection(ulong selID = 0); //!< Delete selection void deleteKeepChildren(BranchItem *bi = nullptr); //!< remove branch, but keep children @@ -687,15 +706,21 @@ class VymModel : public TreeModel { public: void registerMapEditor(QWidget *); - void setMapZoomFactor(const double &); - void setMapRotation(const double &); - void setMapAnimDuration(const int &d); - void setMapAnimCurve(const QEasingCurve &c); + void setViewZoomFactor(const double &); + void setViewRotation(const double &); + void setViewAnimDuration(const int &d); + void setViewAnimCurve(const QEasingCurve &c); bool centerOnID(const QString &id); + void setViewCenterTarget(const QPointF &p); // Save view center during load + QPointF viewCenterTarget(); + bool hasViewCenterTarget(); private: - double zoomFactor; - double mapRotationInt; + double viewZoomFactorInt; + double viewRotationInt; + QPointF viewCenterTargetInt; + bool hasViewCenterTargetInt = false; + int animDuration; QEasingCurve animCurve; @@ -928,6 +953,7 @@ class VymModel : public TreeModel { SlideModel *slideModel; bool blockSlideSelection; + public: //////////////////////////////////////////// // Logfile related //////////////////////////////////////////// diff --git a/src/vymmodelwrapper.cpp b/src/vymmodelwrapper.cpp index 4b53c01..9bc2218 100644 --- a/src/vymmodelwrapper.cpp +++ b/src/vymmodelwrapper.cpp @@ -362,6 +362,13 @@ bool VymModelWrapper::hasBackgroundImage() return r; } +bool VymModelWrapper::isBusy() +{ + bool r = modelInt->isBusy(); + mainWindow->setScriptResult(r); + return r; +} + bool VymModelWrapper::loadBackgroundImage(const QString &imagePath) { bool r =modelInt->loadBackgroundImage(imagePath); @@ -398,6 +405,17 @@ ItemListWrapper* VymModelWrapper::itemList() return new ItemListWrapper(modelInt); } +bool VymModelWrapper::moveSelectionToTarget(BranchWrapper *dst) +{ + if (!dst) { + mainWindow->abortScript( + QJSValue::GenericError, + "VymModelWrapper::moveSelectionToTarget(dst) dst is invalid"); + return false; + } + return modelInt->moveSelectionToTarget(dst->branchItem()); +} + void VymModelWrapper::moveSlideDown(int n) { if (!modelInt->moveSlideDown(n)) @@ -481,26 +499,24 @@ void VymModelWrapper::removeXLink(XLinkWrapper *xlw) modelInt->deleteXLink(xlw->xlink()); } -bool VymModelWrapper::saveSelection(const QString &filename) +bool VymModelWrapper::replaceTree(QString fileName) { - QString filename_org = modelInt->getFilePath(); // Restore filename later - if (!modelInt->renameMap(filename)) { - QString s = tr("Saving the selection in map failed:\nCouldn't rename map to %1").arg(filename); - QMessageBox::critical(0, - tr("Critical Error"), s); - mainWindow->abortScript(QJSValue::GenericError, s); - return false; - } + if (QDir::isRelativePath(fileName)) + fileName = QDir::currentPath() + "/" + fileName; + + bool r = modelInt->replaceTree(fileName); + mainWindow->setScriptResult(r); + return r; +} + +bool VymModelWrapper::saveSelection(const QString &fileName) +{ + QString fileName_org = modelInt->getFilePath(); // Restore fileName later + modelInt->setFilePath(fileName); bool r = modelInt->saveMap(File::PartOfMap); - if (!modelInt->renameMap(filename_org)) { - QString s = tr("Saving the selection in map failed:\nCouldn't rename map to %1").arg(filename); - QMessageBox::critical(0, - tr("Critical Error"), s); - mainWindow->abortScript(QJSValue::GenericError, s); - return false; - } + modelInt->setFilePath(fileName_org); return r; } @@ -603,13 +619,13 @@ void VymModelWrapper::setAnimCurve(int n) else { QEasingCurve c; c.setType((QEasingCurve::Type)n); - modelInt->setMapAnimCurve(c); + modelInt->setViewAnimCurve(c); } } void VymModelWrapper::setAnimDuration(int n) { - modelInt->setMapAnimDuration(n); + modelInt->setViewAnimDuration(n); } void VymModelWrapper::setAuthor(const QString &s) { modelInt->setMapAuthor(s); } @@ -659,11 +675,15 @@ void VymModelWrapper::setLinkStyle(const QString &style, int depth) QString("Could not set linkstyle to %1 with d=%2").arg(style, depth)); } -void VymModelWrapper::setRotationView(float a) { modelInt->setMapRotation(a); } +void VymModelWrapper::setRotationView(float a) { modelInt->setViewRotation(a); } void VymModelWrapper::setTitle(const QString &s) { modelInt->setMapTitle(s); } -void VymModelWrapper::setZoom(float z) { modelInt->setMapZoomFactor(z); } +void VymModelWrapper::setSaveAsBackgroundProcess(bool b){ + modelInt->setSaveAsBackgroundProcess(b); +} + +void VymModelWrapper::setZoom(float z) { modelInt->setViewZoomFactor(z); } void VymModelWrapper::setSelectionBrushColor(const QString &color) { diff --git a/src/vymmodelwrapper.h b/src/vymmodelwrapper.h index 137a2e0..49de599 100644 --- a/src/vymmodelwrapper.h +++ b/src/vymmodelwrapper.h @@ -47,9 +47,11 @@ class VymModelWrapper : public QObject { QString getSelectionString(); double getZoom(); bool hasBackgroundImage(); + bool isBusy(); bool loadBackgroundImage(const QString &imagePath); bool loadBranchReplace(QString filename, BranchWrapper *bw); bool loadDataInsert(QString filename, int pos = -1, BranchWrapper *bw = nullptr); + bool moveSelectionToTarget(BranchWrapper *dst); void moveSlideDown(int n); void moveSlideDown(); void moveSlideUp(int n); @@ -64,6 +66,7 @@ class VymModelWrapper : public QObject { void removeKeepChildren(BranchWrapper *bw); void removeSlide(int n); void removeXLink(XLinkWrapper *xlw); + bool replaceTree(QString filename); bool saveSelection(const QString &filename); bool select(const QString &s); Q_INVOKABLE AttributeWrapper* selectedAttribute(); @@ -82,11 +85,12 @@ class VymModelWrapper : public QObject { void setLinkStyle(const QString &style, int depth = -1); void setLinkColorHint(const QString &hint); void setRotationView(float a); - void setTitle(const QString &s); - void setZoom(float z); void setSelectionBrushColor(const QString &color); void setSelectionPenColor(const QString &color); void setSelectionPenWidth(const qreal &); + void setSaveAsBackgroundProcess(bool); + void setTitle(const QString &s); + void setZoom(float z); void sleep(int n); int slideCount(); void undo(); diff --git a/src/xml-vym.cpp b/src/xml-vym.cpp index b9490c1..65daf18 100644 --- a/src/xml-vym.cpp +++ b/src/xml-vym.cpp @@ -172,7 +172,7 @@ void VymReader::readMapDesignElement() QString k = xml.attributes().value("key").toString(); QString v = xml.attributes().value("val").toString(); QString d = xml.attributes().value("d").toString(); - if (!v.isEmpty()) { + if (!v.isEmpty() && (loadMode != File::ImportAdd && loadMode != File::ImportReplace)) { if (!model->mapDesign()->setElement(k, v, d)) { xml.raiseError(QString("MapDesign: Failed to set key %1 to %2").arg(k, v)); return; @@ -185,6 +185,9 @@ void VymReader::readMapDesignElement() void VymReader::readMapDesignCompatibleAttributes() { + if (loadMode == File::ImportAdd || loadMode == File::ImportReplace) + return; + // Reads attributes which before 2.9.13 used to be // in and now are in @@ -423,13 +426,6 @@ void VymReader::readBranchOrMapCenter(File::LoadMode loadModeBranch, int insertP xml.name() == QLatin1String("note")) readHeadingOrVymNote(); else if (xml.name() == QLatin1String("branch")) { - if (lastBranch && lastBranch->depth() < 3 && false) { // FIXME-2 Updates during load disabled for now. Too many selectionCHanges - // Some graphical repainting during loading of map - lastBranch->updateVisuals(); - model->select(lastBranch); - model->reposition(true); - } - // Going deeper we regard incoming data as "new", no inserts/replacements readBranchOrMapCenter(File::NewMap, -1); @@ -600,6 +596,14 @@ void VymReader::readHeadingOrVymNote() } lastMI->setHeading(vymtext); + + if (lastBranch && (lastBranch->depth() < 3 || branchesCounter % 100 == 0)) { // Update and process events once in a while + // Some graphical repainting during loading of map + lastBranch->updateVisuals(); + //model->select(lastBranch); + model->reposition(true); + } + } else { if (lastMI->hasTypeBranch()) { if (textType == "vymnote" || textType == "note" || textType == "htmlnote") @@ -762,72 +766,77 @@ void VymReader::readImage() Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("floatimage")); lastImage = model->createImage(lastBranch); - lastMI = lastImage; + QString orgName = attributeToString("originalName"); QString s; s = attributeToString("href"); if (!s.isEmpty()) { // Load Image if (!lastImage->load(parseHREF(s))) { - QMessageBox::warning(0, "Warning: ", - "Couldn't load image\n" + - parseHREF(s)); + QString err = "Couldn't load image \"" + parseHREF(s) + "\" " + + "originalName=\"" + orgName + "\" " + + "to branch \"" + lastBranch->headingText() + "\""; + QMessageBox::critical(0, "Critical: ", err); + model->logInfo(err, "VymReader::readImage()"); lastImage = nullptr; - return; } } - // Scale image - // scaleX and scaleY are no longer used since 2.7.509 and replaced by - // scaleFactor - float x = 1; - float y = 1; - bool okx, oky; - s = attributeToString("scaleX"); - if (!s.isEmpty()) { - x = s.toFloat(&okx); - if (!okx) { - xml.raiseError("Couldn't read scaleX of image"); - return; + if (lastImage) { + lastMI = lastImage; + + if (!orgName.isEmpty()) + lastImage->setOriginalFilename(orgName); + + // Scale image + // scaleX and scaleY are no longer used since 2.7.509 and replaced by + // scaleFactor + float x = 1; + float y = 1; + bool okx, oky; + s = attributeToString("scaleX"); + if (!s.isEmpty()) { + x = s.toFloat(&okx); + if (!okx) { + xml.raiseError("Couldn't read scaleX of image"); + return; + } } - } - s = attributeToString("scaleY"); - if (!s.isEmpty()) { - y = s.toFloat(&oky); - if (!oky) { - xml.raiseError("Couldn't read scaleY of image"); - return; + s = attributeToString("scaleY"); + if (!s.isEmpty()) { + y = s.toFloat(&oky); + if (!oky) { + xml.raiseError("Couldn't read scaleY of image"); + return; + } } - } - s = attributeToString("scale"); - if (!s.isEmpty()) { - x = s.toFloat(&okx); - if (!okx) { - xml.raiseError("Couldn't read scale of image"); - return; + s = attributeToString("scale"); + if (!s.isEmpty()) { + x = s.toFloat(&okx); + if (!okx) { + xml.raiseError("Couldn't read scale of image"); + return; + } } - } - s = attributeToString("scaleFactor"); // Legacy: Used in version < 2.9.518 - if (!s.isEmpty()) { - x = s.toFloat(&okx); - if (!okx) { - xml.raiseError("Couldn't read scaleFactor of image"); - return; + s = attributeToString("scaleFactor"); // Legacy: Used in version < 2.9.518 + if (!s.isEmpty()) { + x = s.toFloat(&okx); + if (!okx) { + xml.raiseError("Couldn't read scaleFactor of image"); + return; + } } - } - if (x != 1) - lastImage->setScale(x); + if (x != 1) + lastImage->setScale(x); - readOrnamentsAttr(); + readOrnamentsAttr(); - s = attributeToString("originalName"); - if (!s.isEmpty()) - lastImage->setOriginalFilename(s); + } // lastImage != nullptr while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("heading")) @@ -1069,7 +1078,7 @@ void VymReader::readVymMapAttr() } qreal r; - a = "mapZoomFactor"; + a = "viewZoomFactor"; s = xml.attributes().value(a).toString(); if (!s.isEmpty()) { r = s.toDouble(&ok); @@ -1077,10 +1086,10 @@ void VymReader::readVymMapAttr() xml.raiseError("Could not parse attribute" + a); return; } - model->setMapZoomFactor(r); + model->setViewZoomFactor(r); } - a = "mapRotation"; + a = "viewRotation"; s = xml.attributes().value(a).toString(); if (!s.isEmpty()) { r = s.toDouble(&ok); @@ -1088,7 +1097,27 @@ void VymReader::readVymMapAttr() xml.raiseError("Could not parse attribute " + a); return; } - model->setMapRotation(r); + model->setViewRotation(r); + } + + a = "viewCenterX"; + s = xml.attributes().value(a).toString(); + if (!s.isEmpty()) { + qreal x = s.toDouble(&ok); + if (!ok) { + xml.raiseError("Could not parse attribute " + a); + return; + } + a = "viewCenterY"; + s = xml.attributes().value(a).toString(); + if (!s.isEmpty()) { + qreal y = s.toDouble(&ok); + if (!ok) { + xml.raiseError("Could not parse attribute " + a); + return; + } + model->setViewCenterTarget(QPointF(x,y)); + } } readMapDesignCompatibleAttributes(); @@ -1343,6 +1372,8 @@ void VymReader::readFrameAttr() // Set all frame parameters via model model->setFrameAutoDesign(useInnerFrame, true, lastBranch); else { + bc->setFrameAutoDesign(useInnerFrame, false); + a = "frameType"; s = attributeToString(a); if (s.isEmpty()) @@ -1352,8 +1383,6 @@ void VymReader::readFrameAttr() // assuming that there is no "NoFrame" frame in the xml bc->setFrameType(useInnerFrame, s); - bc->setFrameAutoDesign(useInnerFrame, false); - a = "penColor"; s = attributeToString(a); if (!s.isEmpty()) diff --git a/src/zip-agent.cpp b/src/zip-agent.cpp index f7ad8bd..e1d184a 100644 --- a/src/zip-agent.cpp +++ b/src/zip-agent.cpp @@ -53,8 +53,9 @@ void ZipAgent::setBackgroundProcess(bool b) isBackgroundProcessInt = b; } -void ZipAgent::startZip() +bool ZipAgent::startZip() { + // Returns true on success connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(zipProcessFinished(int, QProcess::ExitStatus))); @@ -86,6 +87,7 @@ void ZipAgent::startZip() "The map could not be saved, please check if " "backup file is available or export as XML file!\n\n") + zipToolPath + args.join(" ")); + return false; } else { // zip could be started @@ -93,26 +95,23 @@ void ZipAgent::startZip() if (exitStatus() != QProcess::NormalExit) { QMessageBox::critical(0, QObject::tr("Critical Error"), QObject::tr("zip didn't exit normally")); + return false; } else { if (exitCode() > 0) { QMessageBox::critical( 0, QObject::tr("Critical Error"), QString("zip exit code: %1").arg(exitCode())); + return false; } } } - } else { - connect (this, SIGNAL(backgroundZipStarted()), mainWindow, SLOT(backgroundZipStarted())); - connect (this, SIGNAL(backgroundZipFinished()), mainWindow, SLOT(backgroundZipFinished())); - emit backgroundZipStarted(); - } - + } + return true; // Success } 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) diff --git a/src/zip-agent.h b/src/zip-agent.h index 312af1a..c48422b 100644 --- a/src/zip-agent.h +++ b/src/zip-agent.h @@ -19,7 +19,7 @@ class ZipAgent : public QProcess { static bool checkUnzipTool(); void setBackgroundProcess(bool); - void startZip(); + bool startZip(); void startUnzip(); QDir zipDir(); QString zipName(); diff --git a/styles/vym-dark.css b/styles/vym-dark.css deleted file mode 100644 index 51471ce..0000000 --- a/styles/vym-dark.css +++ /dev/null @@ -1,170 +0,0 @@ -html { - font-family:arial,sans-serif; -} - -body { - margin:0; - padding:10px; - font-family:arial, - sans-serif; - align:center; - background-color:#1B1E20; -} - -a, a:visited, a:link, a:active { - color:#666666; - text-decoration:none; -} - -a:hover { - text-decoration:underline; -} - -/* VYM specific elements*/ - -.vym-header{ - width:96%; - padding:2%; - margin-bottom:10px; - border:solid 1px black; - background-color:#f0f0f0; - text-align:center; - vertical-align:center; - font-size: 2em; -} -.vym-toc{ - background-color: #F9F9F9; - border: 1px solid #AAAAAA; - font-size: 95%; - padding: 5px -} -.vym-toc-title{ - background-color: #F9F9F9; - font-size: 100%; -} -.vym-toc-branch-0{ text-indent: 0em; } -.vym-toc-branch-1{ text-indent: 1em; } -.vym-toc-branch-2{ text-indent: 2em; } -.vym-toc-branch-3{ text-indent: 3em; } -.vym-toc-branch-4{ text-indent: 4em; } -.vym-toc-branch-5{ text-indent: 5em; } -.vym-toc-branch-6{ text-indent: 6em; } -.vym-toc-branch-7{ text-indent: 7em; } -.vym-toc-branch-8{ text-indent: 8em; } -.vym-toc-branch-9{ text-indent: 9em; } -.vym-toc-number{ } -.vym-toc-text{ } -.vym-imagemap{ - width:96%; - padding:2%; - margin-bottom:10px; - border: 0px; - text-align:center; - vertical-align:center; -} -.imagemap{ - border: 0px; -} -.vym-BoxBottom { - padding:10px; - font-size:0.7em; - border:solid 1px black; - margin:0; - background-color:#f0f0f0; -} -.vym-BoxBottomR -{ - padding-top:1em; - color:#676767; - text-align:right; -} -.vym-footer { - width:100%; - border:1; -} -.vym-footerL { font-size:0.7em; color:#676767; text-align:left; width:33%} -.vym-footerC { font-size:0.7em; color:#676767; text-align:center; width:33%} -.vym-footerR { font-size:0.7em; color:#676767; text-align:right; width:33%} - -.vym-url {} - -.vym-branch-0 { -} -.vym-branch-1{ -} -.vym-branch-2{ - font-size: small; - font-weight: normal; -} -.vym-branch-3{ - font-size: small; - font-weight: normal; -} -.vym-branch-4{ - font-size: small; - font-weight: normal; -} -.vym-branch-5{ - font-size: small; - font-weight: normal; -} -.vym-branch-6{ - font-size: small; - font-weight: normal; -} -.vym-branch-7{ - font-size: small; - font-weight: normal; -} - -.vym-branch-8{ - font-size: small; - font-weight: normal; -} -.vym-branch-9{ - font-size: small; - font-weight: normal; -} -.vym-note { - width:80%; - border: solid 1px black; - border-radius: 0.6em 0.6em 0.6em 0.6em; - border-color: #000000; - background-color: #eeeeee; - font-size: small; - font-weight: normal; - overflow: auto; - padding: 0em 1em; -} - -.vym-note-flag { - vertical-align:top; - width:30px; - height:30px; - background-image: url("flags/flag-note.png"); - background-repeat: no-repeat; - background-position: left top; -} - -.vym-note-paragraph { - margin-top: 0px; - margin-bottom: 1em; -} - -.vym-fixed-note-paragraph { - margin: 0; -} -.standardflag { - margin-left: 5px; -} - -.vym-list-ul-0 { - list-style-type: none; - list-style-position: inside; -} - -.vym-list-ul-1 { - list-style-type: none; - list-style-position: outside; -} - diff --git a/styles/vym.css b/styles/vym.css index f5d73ec..ba6cea0 100644 --- a/styles/vym.css +++ b/styles/vym.css @@ -8,7 +8,7 @@ body { font-family:arial, sans-serif; align:center; - background-color:#ffffff; + background-color:$MapBackgroundColor; } a, a:visited, a:link, a:active { @@ -125,28 +125,44 @@ a:hover { font-size: small; font-weight: normal; } -.vym-note { - width:80%; - border: solid 1px black; - border-radius: 0.6em 0.6em 0.6em 0.6em; +.vym-note { + width: 100%; + border: solid 1px black; + border-radius: 0.6em; border-color: #000000; - background-color: #eeeeee; + background-color: #eeeeee; font-size: small; font-weight: normal; - overflow: auto; padding: 0em 1em; } -.vym-note-flag { - vertical-align:top; - width:30px; - height:30px; - background-image: url("flags/flag-note.png"); - background-repeat: no-repeat; - background-position: left top; +.vym-note-button { + background-color: #8888cc; + color: #ffffff; + cursor: pointer; + padding: 0.3em 0.8em; + width: 80%; + border: none; + border-radius: 0.4em; + text-align: left; + font-size: small; + font-weight: bold; + margin-top: 0.4em; + display: block; +} + +.vym-note-button:hover { + background-color: #6666aa; +} + +.vym-note-collapsible { + width: 80%; + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease-out; } -.vym-note-paragraph { +.vym-note-paragraph { margin-top: 0px; margin-bottom: 1em; } diff --git a/test/vym-selftest.vys b/test/vym-selftest.vys index b65dcab..037b6b5 100644 --- a/test/vym-selftest.vys +++ b/test/vym-selftest.vys @@ -36,7 +36,7 @@ not_yet_ported_tests = [ ]; tests = all_tests; -// tests = ["modify_branches"]; +//tests = ["saving"]; var verbosity = 0; @@ -154,7 +154,7 @@ function initMap(mapPath) // FIXME not fully ported yet: files parameter missin */ if (vym.loadMap(currentMapPath)) { - let id = vym.currentMapID(); + let id = vym.currentMapId(); if (verbosity > 0) vym.print("# Loaded " + currentMapPath + " (id: " + id + " original: " + mapPath + ")"); @@ -171,13 +171,13 @@ function initMap(mapPath) // FIXME not fully ported yet: files parameter missin function closeCurrentMap() { - id = vym.currentMapID(); + id = vym.currentMapId(); name = vym.currentMap().getFileName(); - if(vym.closeMapWithID(id)) { + if(vym.closeMapWithId(id)) { if (verbosity > 0) vym.print("# Closed map \"" + name + "\" (id: #{id})"); } else { - vym.print("# Failed to close map with id = #{id}. CurrentMapID = #{id}"); + vym.print("# Failed to close map with id = #{id}. currentMapId = #{id}"); } } @@ -1466,6 +1466,7 @@ function test_saving() mapName = "test-saveSelection.vyp"; fn = testDir + "/" + mapName; + map.setSaveAsBackgroundProcess(false); ok = map.saveSelection(fn); expect("Saved selection successfully to '" + fn + "'", ok, true); diff --git a/test/vym-test-legacy.rb b/test/vym-test-legacy.rb index 17dfd8b..fa53758 100644 --- a/test/vym-test-legacy.rb +++ b/test/vym-test-legacy.rb @@ -101,7 +101,7 @@ def init_map( mapPath, files = []) end if @vym.loadMap (@currentMapPath) - id = @vym.currentMapID + id = @vym.currentMapId puts "# Loaded #{mapPath} -> #{@currentMapPath} (id: #{id})".light_black return @vym.map (id) end @@ -111,12 +111,12 @@ def init_map( mapPath, files = []) end def close_current_map - id = @vym.currentMapID - r = @vym.closeMapWithID(id) + id = @vym.currentMapId + r = @vym.closeMapWithId(id) if r puts "# Closed map (id: #{id})".light_black else - puts "# Failed to close map with id = #{id}. CurrentMapID = #{id}".red + puts "# Failed to close map with id = #{id}. currentMapId = #{id}".red end end diff --git a/test/vym-test.rb b/test/vym-test.rb index ddf387d..f10d9d5 100755 --- a/test/vym-test.rb +++ b/test/vym-test.rb @@ -101,7 +101,7 @@ def init_map( mapPath, files = []) end if @vym.loadMap (@currentMapPath) - id = @vym.currentMapID + id = @vym.currentMapId puts "# Loaded #{mapPath} -> #{@currentMapPath} (id: #{id})".blue return @vym.map (id) end @@ -111,12 +111,12 @@ def init_map( mapPath, files = []) end def close_current_map - id = @vym.currentMapID - r = @vym.closeMapWithID(id) + id = @vym.currentMapId + r = @vym.closeMapWithId(id) if r puts "# Closed map (id: #{id})".blue else - puts "# Failed to close map with id = #{id}. CurrentMapID = #{id}".red + puts "# Failed to close map with id = #{id}. currentMapId = #{id}".red end end diff --git a/tex/icons/camera-photo.pdf b/tex/icons/camera-photo.pdf new file mode 100644 index 0000000..31d0472 Binary files /dev/null and b/tex/icons/camera-photo.pdf differ diff --git a/tex/icons/converted-icons.txt b/tex/icons/converted-icons.txt new file mode 100644 index 0000000..bdb7136 --- /dev/null +++ b/tex/icons/converted-icons.txt @@ -0,0 +1 @@ +icons/classic/edit-delete.svg icons/edit-delete.pdf diff --git a/tex/icons/edit-delete.pdf b/tex/icons/edit-delete.pdf new file mode 100644 index 0000000..4199a64 Binary files /dev/null and b/tex/icons/edit-delete.pdf differ diff --git a/tex/icons/edit-find.pdf b/tex/icons/edit-find.pdf new file mode 100644 index 0000000..fec5735 Binary files /dev/null and b/tex/icons/edit-find.pdf differ diff --git a/tex/icons/edit-find.svg b/tex/icons/edit-find.svg new file mode 100644 index 0000000..c46b0c7 --- /dev/null +++ b/tex/icons/edit-find.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/tex/icons/formatrichtext.pdf b/tex/icons/formatrichtext.pdf new file mode 100644 index 0000000..a7c8816 Binary files /dev/null and b/tex/icons/formatrichtext.pdf differ diff --git a/tex/vym.tex b/tex/vym.tex index 2e64f81..ab95030 100644 --- a/tex/vym.tex +++ b/tex/vym.tex @@ -82,7 +82,7 @@ \title{ \includegraphics[width=8cm]{images/vym-logo-new.png} \\ VYM -- View Your Mind \\ - {\small Version 2.9.0} \\ + {\small Version 2.9.512} \\ { Usermanual } \author{\textcopyright Uwe Drechsel } } @@ -167,9 +167,9 @@ stimulates new associations. \subsubsection*{Your Brain} -In 1960 Prof. {\sc Roger Sperry} discovered that both hemispheres -of the human brain undertake different tasks (of course both of them -basically {\em can} do the same): +For many years it was believed that the left and the right side of the +brain undertake different tasks like the left side is responsible for +logical thinking and the right side for creativity: \begin{center} \begin{tabular}{|p{5.5cm}|p{5.5cm}|} \hline Left side & Right side \\ \hline @@ -194,12 +194,16 @@ basically {\em can} do the same): \end{itemize} \\ \hline \end{tabular} \end{center} -In our science oriented western society we have learned to mainly rely -on our left side of the brain, the "rational" one. In other cultures, -such as the native americans and other "old" cultures, the right side is -much more important. {\em Map} are just one way to stimulate the other -side and make use of additional resources we all have. +More recent research has shown that the two sides of the brain are much +more connected and neurologists are more sceptical about the idea of a +strict division of tasks between the two sides. The two sides of the +brain are much more interdependent and work together much more closely +than previously thought. +Anyway in our western culture we have learned to mainly rely on the +rational part of our brain. Laying out our thoughts in a {\em map} can +help to stimulate the other part and make use of additional resources we +all have. \subsection{Where could I use a {\em map}?} Here are some examples, how you can use those {\em maps} @@ -290,7 +294,7 @@ Here is a list of the available satellite windows, the {\em dockable} feature is explained in next section \ref{dockable}: \begin{itemize} \item Branch Property Window (see section \ref{propwindow}) - \item \includegraphics[width=0.5cm]{../icons/find.png} + \item \includegraphics[width=0.5cm]{icons/edit-find.pdf} Find window to search for text (dockable) \item \includegraphics[width=0.5cm]{../icons/headingeditor.png} Heading editor (dockable, features are the same as in the @@ -306,6 +310,9 @@ feature is explained in next section \ref{dockable}: \item \includegraphics[width=0.5cm]{../icons/taskeditor.png} Taskeditor (dockable, see section \ref {taskeditor}) \end{itemize} +Btw. all satellite windows can be opened by using the menu "View \ra Show \ra +{\em name of the window}" and with keyboard shortcuts, e.g. \key{CTRL+F} +for the Find window. Each satellite can be closed again by \key{CTRL+D}. \subsection{Dockable windows} \label{dockable} Beginning with \vym 1.13.0 some of the windows may be docked and become @@ -447,7 +454,7 @@ zoom. \subsubsection*{Find Function} \label{findwindow} Choose Edit \ra Find or just press \key{CTRL+F} to open -the Findwidget. The image below shows the findwidget above the +the Findi Window. The image below shows the Find Window above the noteeditor and the mapeditor: \begin{center} \maximage{images/find-window.png} @@ -842,7 +849,7 @@ Notes and also the headings of branches can either use a default font or all text attributes availabe in RichText, like bold, italic, colors, etc. To enable the latter, click the RichText button: \begin{center} - \includegraphics[width=0.5cm]{../icons/formatrichtext.png} + \includegraphics[width=0.5cm]{icons/formatrichtext.pdf} \end{center} \subsection{Fonts and how to switch them quickly} @@ -1028,7 +1035,7 @@ menu. The (currently) available action are: Select next slide \item - \includegraphics[width=0.5cm]{../icons/slide-camera.png} + \includegraphics[width=0.5cm]{../icons/classic/camera-photo.png} Create a new slide by snapshotting the current selection. The exact set of actions performed when selecting the new snapshot defined in a script called {\tt slideeditor-snapshot.vys}. The script is one of @@ -1040,7 +1047,7 @@ menu. The (currently) available action are: (More on scripting in appendix \ref{scripts}). \item - \includegraphics[width=0.5cm]{../icons/edittrash.png} + \includegraphics[width=0.5cm]{icons/edit-delete.pdf} Delete the current slide \item @@ -1646,19 +1653,18 @@ several maps at once. \section{Scripts} \label{scripts} \subsection{Overview} -Beginning with version 2.7.0 \vym is fully scriptable, though the -scripting support is still considered a {\em technical preview}. Some -parts still might change and improve in later versions. +\vym is fully scriptable. Beginning with version 3.0.0 the scripting +engine is based on QJSEngine, which is a JavaScript engine. Scripts are internally used for \begin{itemize} \item Undo and Redo \item Macros on function keys \item Slideshow \end{itemize} -In addition to the internal scriptengine, which is using QScript, -you can also use external ruby scripts, which communicate with \vym via -DBUS. Please note that the latter is currently only possible on Linux. -See also the examples in \ref{examplescripts}. +Older versions of \vym in addition to QJSEngine used the Ruby scripting +engine. This is still available in \vym, the commands are on Linux +accessible via DBUS. The Ruby engine is not available on Windows and +MacOS. The scripts within \vym are edited using the {\em script editor}: \begin{center} \label{scripteditor} @@ -1674,18 +1680,32 @@ installation directory and the subfolder {\tt demos/scripts/} and the macros in the macro tab of the script editor. \subsubsection{Macro to create a rounded rectangle frame} \begin{code} -// Macro Shift + F1: Frame background light red -function macro_shift_f1() +//! Helper function to toggle frame background color of a whole subtree + +function toggle_frame_subtree(color, msg) { map = vym.currentMap(); - status = "Background off"; - if (map.getFrameType() == "NoFrame") { - status = "Background light red"; + branches = map.selectedBranches(); + for (b of branches) { + // Make sure changes are saved + b.setFrameAutoDesign(false, false); + if (b.getFrameType(false) == "NoFrame" ) { + b.setFrameType (false, "RoundedRectangle"); + b.setFrameBrushColor(false, color); + vym.statusMessage(msg); + } else { + b.setFrameType (false, "NoFrame"); + vym.statusMessage("No frame for subtree"); + } } - toggle_frame ( map ); - map.setFrameBrushColor("#ffb3b4"); - statusMessage(status); } + +//! Macro Ctrl+Shift+F1: Toggle subtree frame background light red +function macro_ctrl_shift_f1() +{ + toggle_frame_subtree ( "#ffb3b4", "Subtree frame background light red" ); +} + \end{code} \subsubsection{Batch script to export all maps as images} @@ -1696,7 +1716,7 @@ with \$ vym --quit --run export-image.vys *.vym \end{code} -\subsubsection{Full scripting using ruby and DBUS} \label{dbus} +\subsubsection{Full scripting using ruby and DBUS (deprecated)} \label{dbus} Nearly every action in \vym can be controlled via DBUS (on Linux machines). You can have several \vym instances running at the same time, e.g. for production and development. Before controlling one, you need to