diff --git a/.github/workflows/build_ubuntu.yml b/.github/workflows/build_ubuntu.yml index 75a0fd9b..6bc16bfc 100644 --- a/.github/workflows/build_ubuntu.yml +++ b/.github/workflows/build_ubuntu.yml @@ -11,7 +11,7 @@ jobs: submodules: recursive - name: Install packages - run: sudo apt-get update && sudo apt-get install -y build-essential zlib1g-dev libhunspell-dev libqt5webkit5-dev qttools5-dev-tools qt5-default ccache + run: sudo apt-get update && sudo apt-get install -y build-essential zlib1g-dev libcurl4-gnutls-dev libhunspell-dev libqt5webkit5-dev qttools5-dev-tools qt5-default ccache - name: Build dependency - cmark-gfm run: cd deps/cmark-gfm && mkdir -v build && cd build && cmake -DCMARK_TESTS=OFF -DCMARK_SHARED=OFF .. && cmake --build . @@ -23,7 +23,7 @@ jobs: run: export M8R_GIT_PATH=`pwd` && cd build/make && M8R_CPU_CORES=4 ./test-lib-units.sh - name: Run QMake to build application - run: pwd ; qmake -r "CONFIG+=mfci" mindforger.pro + run: pwd ; qmake -r "CONFIG+=mfci" mindforger.pro - name: Run Make to build application run: make -j 4 diff --git a/.gitignore b/.gitignore index 61547164..b1a564c4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ Release/ Debug/ .vs/ .idea/ +.vscode/ .venv/ *.o *.a @@ -20,3 +21,8 @@ TEST_LOG*.* compile_commands.json .qmake.stash .DS_Store +deps/cmark-gfm +deps/mitie +deps/cmark-gfm +snapcraft.yaml +*.snap diff --git a/.gitmodules b/.gitmodules index 5402d0a8..ad167075 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "doc"] path = doc url = https://github.com/dvorka/mindforger-repository.git -[submodule "deps/mitie"] - path = deps/mitie - url = https://github.com/dvorka/MITIE.git [submodule "deps/cmark-gfm"] path = deps/cmark-gfm url = https://github.com/dvorka/cmark.git diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 587985f8..3d4c99c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contribute to MindForger -MindForger is free and open source software. Feel free to **contribute** - any help +MindForger is free and open source software. Feel free to **contribute** - any help with MindForger development will be **highly appreciated**! * **Bugs and Suggestions** @@ -13,33 +13,50 @@ with MindForger development will be **highly appreciated**! * Submit pull request/patch with implementation of a feature you missed. * **Integration** * How-to or code enabling integration with your (favorite) project. -* **Enhancements** +* **Enhancements** * Submit performance, efficiency and/or productivity enhancements suggestions (code, bug or docs) -* **Documentation** +* **Documentation** * Write a document, block post; create YouTube video, ... Don't hesitate to contact [me](mailto:martin.dvorak@mindforger.com). + +**Table of contents**: + +* [Code of Conduct](#code-of-conduct) +* [Styleguide: Git Commit Messages](#styleguide--git-commit-messages) +* [Styleguide: C++](#styleguide--c) +* [Styleguide: C++ Comments](#styleguide--c---comments) +* [Styleguide: Qt](#styleguide--qt) + + # Code of Conduct -This project and everyone participating in it is governed by the +This project and everyone participating in it is governed by the [MindForger Code of Conduct](./CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. + + # Styleguide: Git Commit Messages * Commit messages must provide concise change description. * Reference issues and pull requests related to the commit. * Close bugs with issue references in commit messages. * If possible, limit commit message length to 72 characters. + + # Styleguide: C++ Code style: - + * Use `.h` extension for header files. * Use `.cpp` extension for class files. -* Use `lower_case_with_unserscores` source code file names. +* Use `lower_case_with_underscores` source code file names. * Spaces, no tabs. * No trailing whitespaces. * Use `{}` with constructor having 0/1 parameter, () otherwise. * `CamelCase` class names (no underscores). * Lines to have at most 88 columns. -* See `/lib/src` source code for as code style reference. + - Guide in Qt Creator: `Tools` > `Options` > `Text editor` > `Display` > `Display right margin at column` = 88 +* 4 spaces indentation. +* Python's black like formatting. +* Use `/lib/src` source code as code style reference. Example of class `{}` style: @@ -54,8 +71,8 @@ public: ... void myFunction(int myParam) { ... } - - int myMultiLineFunction() const { + + int myMultiLineFunction() const { ... } @@ -78,7 +95,7 @@ bool MyClass::myFunction(const QString& myArg) } ``` -Example of how to format code to keep it under 88 columns: +Example of how to format code to keep it under 88 columns (Python's black style): ```cpp void MainWindowPresenter::doActionOrganizerMoveNoteToNextVisibleQuadrant(Note* note) @@ -87,8 +104,7 @@ void MainWindowPresenter::doActionOrganizerMoveNoteToNextVisibleQuadrant(Note* n doActionKanbanMoveNoteCommon( note, orloj->getKanban()->moveToNextVisibleColumn(note), - orloj - ); + orloj); } else { if(!EisenhowerMatrix::isEisenhowMatrixOrganizer( orloj->getOrganizer()->getOrganizer() @@ -99,19 +115,88 @@ void MainWindowPresenter::doActionOrganizerMoveNoteToNextVisibleQuadrant(Note* n doActionOrganizerMoveNoteCommon( note, orloj->getOrganizer()->moveToNextVisibleQuadrant(note), - orloj - ); + orloj); } else { statusBar->showError( "Notebooks/notes cannot be moved around quadrants of " - "Eisenhower Matrix" - ); + "Eisenhower Matrix"); } } } +``` + + +# Styleguide: C++ Comments +Comments should be used to explain tricky and/or +important code only. Don't use comments to explain +obvious things as comments might diverge from the +actual code (e.g. after code refactoring) and may +cause confusion. Make comments brief, consistent +and concise + +Code style: + +```cpp +/** + * @brief Brief class description. + * + * Detailed class description which may include + * `examples` of use, _ASCII diagrams_ or **bullet lists**. + * Do ~~not~~ worry. + * + * Code block: + * + * int codeBlockExampleVariable; + * + * @see Text (as sentence) or URL. + * @see [The link text](http://example.com/) + * @see [The link text](#MyOtherClass) + */ +class MyClass +{ + + int field; // brief field description in the lower case + /** + * @brief Another field. + * + * Field with a long description must be documented using + * this style of the comment. The text of description to be + * formed by sentences. Apart to that you can use any formatting + * syntax from below. + */ + int anotherField; + +public: + +... + /** + * @brief Brief method description. + * + * Detailed method description which may include + * examples of use, ASCII diagrams or bullet/numbered + * lists like: + * + * 1. The first item. + * 2. The second item with the reference of `field`. + * 3. The third item. + * + * @param myParam Parameter documentation as sentence(s). + * @return Return value description as sentence(s). + * + * @see [The link text](#MyOtherClass) + */ + void myMethod(int myParam) { ... } + +... + +} ``` + + # Styleguide: Qt * MindForger uses MVP pattern (see `main_window_presenter.h/.cpp`) * See `/src/qt` source code for a code style reference. + + diff --git a/CREDITS.md b/CREDITS.md index a91314b5..0ba2c552 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -12,13 +12,14 @@ Big thanks to 3rd party FOSS content authors: * Qt Company ([Qt](https://www.qt.io/) - lib and code) * GitHub ([CMark GFM](https://github.com/github/cmark-gfm) - Markdown rendering - lib) * Kevin Hendricks, Bjoern Jacke, Lázsló Németh ([Hunspell](https://github.com/hunspell/hunspell) - spellcheck - lib) +* Daniel Stenberg ([cURL](https://curl.se) - libcurl with GnuTLS flavor) +* Niels Lohmann ([json](https://github.com/nlohmann/json) - JSon for modern C++ library) * NetBSD Foundation (strptime - Windows port - lib) * Toni Ronkko (dirent - Windows port - lib) * Microsoft (getopt - Windows port - lib) * Jordan Russell ([jrsoftware.org](http://jrsoftware.org) - Windows installer framework) * Graeme Gott and Wereturtle ([Ghostwriter](https://github.com/wereturle/ghostwriter) - inspiration and code) * Christian Loose ([CuteMarkEd](https://cloose.github.io/CuteMarkEd/) - inspiration and code) -* Davis E. King ([MITIE](https://github.com/mit-nlp/MITIE) - AI/NLP library and tools for information extraction - library) * Jean-loup Gailly, Mark Adler ([Zlib](https://sourceforge.net/projects/gnuwin32/) - library) * David Parsons ([Discount](http://www.pell.portland.or.us/~orc/Code/discount/) - Markdown rendering - library used in the past) * Google ([Google C++ unit testing framework](https://github.com/google/googletest)) diff --git a/Changelog b/Changelog index fa041cd8..d2557523 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,47 @@ +2024-02-16 Martin Dvorak + + * Released v2.0.0 - a major release that removes unused features + and brings several new features like Wingman. + * Feature: Wingman brings OpenAI LLM integration allowing to + compose, rewrite, summarize, NER or fix grammar of notes. + * Feature: Notebook Tree view brings ability to organize Notebooks to + a tree (outline). + * Feature: Libraries bring ability to index external PDF files and generate + Notebooks which represent them in MindForger. Synchronization and removal + of the library (directory with files) is supported as well. + * Feature: Emojis dialog allowing to use Unicode-based emojis + in Notebooks and Notes names or text. + * Feature: CLI can newly search knowledge on the internet sites - like + Wikipedia, arXiv, or StackOverflow - on phrase which is the current + context (Notebook or Note name; selected text or text under the cursor) + in order to get more information about the phrase. + * Enhancement: CLI rewrite - help, search, knowledge search + (Wikipedia, arXiv, search engines) and commands. + * Enhancement: Limbo added to the application menu View/Limbo. + * Enhancement: Polished Preferences - Appearance refactored to Controls, + restart requirement highlighted. + * Enhancement: Added up and down button in O/N preview mode to move around + O's Ns while presenting a N. + * Enhancement: MindForger icon changed to GenAI style. + * Enhancement: menu refactoring impacting Scope, and Navigate and various + menu items. + * Fix: Missing OOTB Eisenhower Matrix is automatically added back to + the list of Organizers. + * Fix: Conflicting menu keyboard shortcuts resolution (e.g. Organizers view). + * Fix: Edit and Format menus re-enabled on single Markdown file configuration. + * Upgrade: new version(s) of Qt with enhanced security support + added - Qt 5.15.2 LTS is supported on macOS and Windows. + * Deprecation: dashboard view removed. + * Deprecation: experimental Mitie (NER) code removed (replaced by LLM integration). + +2023-01-15 Martin Dvorak + + * Released v1.55.0 - a minor release which fixes delete of a Note in + the Notebook view that now keeps selected an adjacent Note, improves + page up/page down navigation in table widgets, adds charset to + the exported HTML head, adds new Note templates, and renames Repository + to Workspace in the UI (source code kept intact). + 2022-03-07 Martin Dvorak * Released v1.54.0 - macOS fix release: Qt downgraded from 5.9.9 (security) diff --git a/KNOWN_ISSUES.md b/KNOWN_ISSUES.md index c89b3347..a15843ce 100644 --- a/KNOWN_ISSUES.md +++ b/KNOWN_ISSUES.md @@ -1,7 +1,25 @@ # Known Issues -MindForger known issues - see also -[GitHub issues](https://github.com/dvorka/mindforger/issues?q=is%3Aopen+is%3Aissue+label%3A%22bug+%3Alady_beetle%3A%22). +MindForger known issues - see [GitHub issues](https://github.com/dvorka/mindforger/issues?q=is%3Aopen+is%3Aissue+label%3A%22bug+%3Alady_beetle%3A%22) +for the complete list of bugs. + +# 2.0.0 + +* Autolinking can break MathJax code blocks/text integrity in Markdown text. +* Windows Server R2 2012: empty MF documentation repository in wrong location when MF is launched + at the end of installation. +* Notebook HTML export doesn't export local images: links to filesystem are kept intact, images + are not copied. +* Frontend memleaks. + +# 1.55.0 + +* Autolinking can break MathJax code blocks/text integrity in Markdown text. +* Windows Server R2 2012: empty MF documentation repository in wrong location when MF is launched + at the end of installation. +* Notebook HTML export doesn't export local images: links to filesystem are kept intact, images + are not copied. +* Frontend memleaks. # 1.54.0 @@ -69,7 +87,7 @@ MindForger known issues - see also # 1.49.0 -* Windows Server R2 2012: empty MF documentation repository in wrong location when MF is launched +* Windows Server R2 2012: empty MF documentation repository in wrong location when MF is launched at the end of installation. * macOS 10.13: WebEngine might be broken which causes HTML preview not to rendered (root cause is unclear). diff --git a/PAD.xml b/PAD.xml index e6ffb278..d29d444f 100644 --- a/PAD.xml +++ b/PAD.xml @@ -34,10 +34,10 @@ MindForger - 1.54.0 - 03 - 07 - 2022 + 2.0.0 + 01 + 30 + 2024 diff --git a/README.md b/README.md index 56c465a7..a0718d26 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,26 @@ follow on Twitter -Are you **drowning** in **information**, but **starving** for **knowledge**? Where do you keep your **private remarks** -like ideas, personal plans, gift tips, how-tos, dreams, business vision, finance strategy, auto -coaching notes? Loads of documents, sketches and remarks spread around the file system, cloud, -web and Post-it notes? Are you afraid of your knowledge **privacy**? Are you able to **find** them once you create them? +Are you **drowning** in **information**, but **starving** for **knowledge**? Where do you keep your **private remarks** +like ideas, personal plans, gift tips, how-tos, dreams, business vision, finance strategy, auto +coaching notes? Loads of documents, sketches and remarks spread around the file system, cloud, +web and Post-it notes? Are you afraid of your knowledge **privacy**? Are you able to **find** them once you create them? Do you know how are they mutually **related** when you read or write them? No? https://www.mindforger.com +## Thinking Notebook +![MindForger](http://www.mindforger.com/github/github-thinking-notebook.png) + +MindForger is human mind inspired personal knowledge management tool. + ## Markdown Editor ![MindForger](http://www.mindforger.com/github/github-markdown-ide.png?) -MindForger is open, free, well performing Markdown editor which respects your privacy and enables security. +MindForger is open, free, well performing Markdown editor / IDE which respects your privacy. -## Thinking Notebook -![MindForger](http://www.mindforger.com/github/github-thinking-notebook.png) - -MindForger is actually more than an editor or IDE - it's human mind inspired personal knowledge management tool. +## Features +MindForger **features overview**: [open](https://github.com/dvorka/mindforger?tab=GPL-2.0-1-ov-file#readme), [free](https://www.mindforger.com/#floss), [OpenAI GPT integrated](https://www.mindforger.com/#llm), knowledge manager, Markdown editor (math, diagrams, images, table of contents generator), [outliner](https://www.youtube.com/watch?v=LUqavHfKhnc&list=PLkTlgXXVRbUDdvysdslnAt_mU15oNPWNS&index=4), spell-check, [Markdown IDE](https://www.mindforger.com/#features) (multi-document workspace, section refactoring, cloning, scopes and stencils), [organizer](https://www.youtube.com/watch?v=Tje2mso7jNY&list=PLkTlgXXVRbUDdvysdslnAt_mU15oNPWNS&index=11) (Eisenhower matrix, Kanban), [knowledge graph navigator](https://www.youtube.com/watch?v=ZbQmZ1fKpxI&list=PLkTlgXXVRbUDdvysdslnAt_mU15oNPWNS&index=14), knowledge autolinking, think as you browse, think as you write, find by name/tag/text/regexp, find similar sections (associations), tagging, emojis, checklists, recent sections, [external section editor](https://www.youtube.com/watch?v=SLuvfDRyUrM&list=PLkTlgXXVRbUDdvysdslnAt_mU15oNPWNS&index=12), themes, internationalization, export (CSV with OHE for machine learning, HTML) and import (TWiki). ## Installation Install: @@ -72,17 +75,24 @@ Check also [packages](https://pkgs.org/search/?q=mindforger) for Linux and Unix. ## Documentation Read: -* [Why MindForger?](https://github.com/dvorka/mindforger/wiki/Getting-started#why-mindforger) +* [Getting started](https://github.com/dvorka/mindforger/wiki/Getting-started) * [Installation](https://github.com/dvorka/mindforger/wiki/Installation) * [User documentation](https://github.com/dvorka/mindforger/wiki/User-documentation) * [Developer documentation](https://github.com/dvorka/mindforger/wiki/Developer-documentation) * [Project history](https://github.com/dvorka/mindforger/wiki/History) * [FAQs](https://github.com/dvorka/mindforger/wiki/FAQs) -Check `man mindforger` +Watch: + +* [YouTube tutorials](https://www.youtube.com/playlist?list=PLkTlgXXVRbUDdvysdslnAt_mU15oNPWNS) + +Check: + +* `man mindforger` + ## In the News -Read about MindForger on [FOSSMint](https://www.fossmint.com/mindforger-notebook-and-markdown-ide/), [Fedora Magazine](https://fedoramagazine.org/4-try-copr-december-2018/), [UbuntuPIT](https://www.ubuntupit.com/mindforger-a-privacy-focused-thinking-notebook-and-markdown-ide-for-linux/), [AppImageHub](https://www.appimagehub.com/p/1257573/), [AwesomeOpenSource](https://awesomeopensource.com/project/dvorka/mindforger), [root.cz](https://www.root.cz/clanky/softwarova-sklizen-19-9-2018/) and [MOONGIFT.jp](https://www.moongift.jp/2018/12/mindforger-markdown%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%83%8A%E3%83%AC%E3%83%83%E3%82%B8%E3%83%99%E3%83%BC%E3%82%B9/). +Read about MindForger on [FOSSMint](https://www.fossmint.com/mindforger-notebook-and-markdown-ide/), [Fedora Magazine](https://fedoramagazine.org/4-try-copr-december-2018/), [UbuntuPIT](https://www.ubuntupit.com/mindforger-a-privacy-focused-thinking-notebook-and-markdown-ide-for-linux/), [AppImageHub](https://www.appimagehub.com/p/1257573/), [AwesomeOpenSource](https://awesomeopensource.com/project/dvorka/mindforger), [root.cz](https://www.root.cz/clanky/softwarova-sklizen-19-9-2018/) [(2024)](https://www.root.cz/clanky/softwarova-sklizen-7-2-2024-vytvarejte-commitovaci-zpravy-s-umelou-inteligenci/) and [MOONGIFT.jp](https://www.moongift.jp/2018/12/mindforger-markdown%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%83%8A%E3%83%AC%E3%83%83%E3%82%B8%E3%83%99%E3%83%BC%E3%82%B9/). ## Bugs and Feature Requests https://github.com/dvorka/mindforger/issues diff --git a/app/app.pro b/app/app.pro index 7a7c979e..89ff5c0b 100644 --- a/app/app.pro +++ b/app/app.pro @@ -1,6 +1,6 @@ # app.pro Qt project file for MindForger Qt-based frontend # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -23,6 +23,10 @@ message("Qt version: $$QT_VERSION") QT += widgets +win32 { + QT += network +} + mfdebug|mfunits { DEFINES += DO_MF_DEBUG } @@ -31,6 +35,10 @@ mfci { DEFINES += DO_MF_CI } +mfrc { + DEFINES += DO_MF_RC +} + # Hunspell spell check: # - Windows and Ubuntu Xenial require DEPRECATED Hunspell API # - Ubuntu Bionic and newer distros use NEW Hunspell API @@ -54,13 +62,8 @@ mfoldhunspell | equals(OS_DISTRO_VERSION, "Windows") | equals(OS_DISTRO_VERSION, message("Hunspell: configuring use of NEW API on OS: $$OS_DISTRO_VERSION") } -# Named Entity Recognition -mfner { - DEFINES += MF_NER -} - # webkit is supposed to be OBSOLETED by webengine, but webengine is disabled -# on Linux since Qt 5.9 due to its tragic performance > conditional compilation +# on Linux since Qt 5.9 due to its tragic performance -> conditional compilation # seems to be the only way: # - webkit on Linux # - webengine on Windows and macOS @@ -68,7 +71,6 @@ win32|macx|mfwebengine { DEFINES += MF_QT_WEB_ENGINE QT += webengine QT += webenginewidgets - } else { QT += webkit QT += webkitwidgets @@ -90,7 +92,8 @@ win32 { else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../lib/debug -lmindforger } else { # Linux and macOS - LIBS += -L$$OUT_PWD/../lib -lmindforger + # TODO split macOS + LIBS += -L$$OUT_PWD/../lib -lmindforger -lcurl } # Markdown to HTML: cmark-gfm (or nothing) @@ -120,17 +123,11 @@ win32 { } } -# NER library -mfner { - # MF links MITIE for AI/NLP/DL - LIBS += -L$$OUT_PWD/../deps/mitie/mitielib -lmitie -} - # Zlib win32 { INCLUDEPATH += $$PWD/../deps/zlib-win/include DEPENDPATH += $$PWD/../deps/zlib-win/include - + CONFIG(release, debug|release): LIBS += -L$$PWD/../deps/zlib-win/lib/ -lzlibwapi else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../deps/zlib-win/lib/ -lzlibwapi } else { @@ -187,9 +184,19 @@ INCLUDEPATH += ./src/qt/spelling # # - GCC: -std=c++0x ~ -std=c++11 # -# compiler options (qmake CONFIG+=mfnoccache ...) +# compiler and compiler options: +# - https://doc.qt.io/qt-6/qmake-variable-reference.html#qmake-cxx +# - QMAKE_CXX ... compiler +# - QMAKE_CXXFLAGS ... compiler options +# - compilation options ~ DEFINEs (qmake CONFIG+=mfnoccache ...) +# win32{ QMAKE_CXXFLAGS += /MP + + # DISABLED ccache as it causes compilation error: + # "C1090: PDB API call failed, error code '23'" when used + # when used w/ MS VS compiler: + # !mfnoccache { QMAKE_CXX = ccache $$QMAKE_CXX } } else { # linux and macos mfnoccache { @@ -231,7 +238,6 @@ HEADERS += \ ./src/qt/note_view_model.h \ ./src/qt/note_view_presenter.h \ ./src/qt/note_view.h \ - ./src/qt/note_edit_model.h \ ./src/qt/note_edit_presenter.h \ ./src/qt/look_n_feel.h \ ./src/qt/html_delegate.h \ @@ -277,6 +283,10 @@ HEADERS += \ src/qt/dialogs/add_library_dialog.h \ src/qt/dialogs/export_csv_file_dialog.h \ src/qt/dialogs/organizer_new_dialog.h \ + src/qt/dialogs/rm_library_dialog.h \ + src/qt/dialogs/run_tool_dialog.h \ + src/qt/dialogs/wingman_dialog.h \ + src/qt/dialogs/sync_library_dialog.h \ src/qt/dialogs/terminal_dialog.h \ src/qt/kanban_column_model.h \ src/qt/kanban_column_presenter.h \ @@ -292,6 +302,9 @@ HEADERS += \ src/qt/organizers_table_model.h \ src/qt/organizers_table_presenter.h \ src/qt/organizers_table_view.h \ + src/qt/outlines_map_model.h \ + src/qt/outlines_map_presenter.h \ + src/qt/outlines_map_view.h \ src/qt/qt_commons.h \ src/qt/spelling/abstract_dictionary.h \ src/qt/spelling/abstract_dictionary_provider.h \ @@ -307,8 +320,6 @@ HEADERS += \ src/qt/navigator_presenter.h \ src/qt/main_toolbar_view.h \ src/qt/dialogs/export_file_dialog.h \ - src/qt/dashboard_view.h \ - src/qt/dashboard_presenter.h \ src/qt/widgets/edit_buttons_panel.h \ src/qt/widgets/edit_name_panel.h \ src/qt/widgets/view_to_edit_buttons_panel.h \ @@ -320,14 +331,6 @@ HEADERS += \ win32|macx|mfwebengine { HEADERS += ./src/qt/web_engine_page_link_navigation_policy.h } -mfner { - HEADERS += \ - src/qt/dialogs/ner_choose_tag_types_dialog.h \ - src/qt/dialogs/ner_result_dialog.h \ - src/qt/ner_leaderboard_model.h \ - src/qt/ner_leaderboard_view.h \ - src/qt/ner_main_window_worker_thread.h -} SOURCES += \ ./src/qt/mindforger.cpp \ @@ -356,7 +359,6 @@ SOURCES += \ ./src/qt/note_view_model.cpp \ ./src/qt/note_view_presenter.cpp \ ./src/qt/note_view.cpp \ - ./src/qt/note_edit_model.cpp \ ./src/qt/note_edit_presenter.cpp \ ./src/qt/look_n_feel.cpp \ ./src/qt/html_delegate.cpp \ @@ -402,6 +404,10 @@ SOURCES += \ src/qt/dialogs/add_library_dialog.cpp \ src/qt/dialogs/export_csv_file_dialog.cpp \ src/qt/dialogs/organizer_new_dialog.cpp \ + src/qt/dialogs/rm_library_dialog.cpp \ + src/qt/dialogs/run_tool_dialog.cpp \ + src/qt/dialogs/wingman_dialog.cpp \ + src/qt/dialogs/sync_library_dialog.cpp \ src/qt/dialogs/terminal_dialog.cpp \ src/qt/kanban_column_model.cpp \ src/qt/kanban_column_presenter.cpp \ @@ -417,6 +423,9 @@ SOURCES += \ src/qt/organizers_table_model.cpp \ src/qt/organizers_table_presenter.cpp \ src/qt/organizers_table_view.cpp \ + src/qt/outlines_map_model.cpp \ + src/qt/outlines_map_presenter.cpp \ + src/qt/outlines_map_view.cpp \ src/qt/spelling/dictionary_manager.cpp \ src/qt/spelling/spell_checker.cpp \ src/qt/tags_table_model.cpp \ @@ -428,8 +437,6 @@ SOURCES += \ src/qt/navigator_presenter.cpp \ src/qt/main_toolbar_view.cpp \ src/qt/dialogs/export_file_dialog.cpp \ - src/qt/dashboard_view.cpp \ - src/qt/dashboard_presenter.cpp \ src/qt/widgets/edit_buttons_panel.cpp \ src/qt/widgets/edit_name_panel.cpp \ src/qt/widgets/view_to_edit_buttons_panel.cpp \ @@ -441,15 +448,6 @@ win32|macx|mfwebengine { SOURCES += ./src/qt/web_engine_page_link_navigation_policy.cpp } -mfner { - SOURCES += \ - src/qt/dialogs/ner_choose_tag_types_dialog.cpp \ - src/qt/dialogs/ner_result_dialog.cpp \ - src/qt/ner_leaderboard_model.cpp \ - src/qt/ner_leaderboard_view.cpp \ - src/qt/ner_main_window_worker_thread.cpp -} - win32 { HEADERS += \ ../deps/getopt/getopt.h @@ -466,7 +464,8 @@ TRANSLATIONS = \ ./resources/qt/translations/mindforger_nerd_en.ts \ ./resources/qt/translations/mindforger_nerd_cs.ts \ ./resources/qt/translations/mindforger_en.ts \ - ./resources/qt/translations/mindforger_cs.ts + ./resources/qt/translations/mindforger_cs.ts \ + ./resources/qt/translations/mindforger_zh_cn.ts RESOURCES += \ ./mf-resources.qrc @@ -512,5 +511,6 @@ win32 { message(DEFINES of app.pro build: $$DEFINES) message(QMAKE_EXTRA_TARGETS of app.pro build: $$QMAKE_EXTRA_TARGETS) message(QT of app.pro build: $$QT) +message(PATH is: $$(PATH)) # eof diff --git a/app/mf-resources.qrc b/app/mf-resources.qrc index 2d93f7ba..7466dece 100644 --- a/app/mf-resources.qrc +++ b/app/mf-resources.qrc @@ -24,6 +24,7 @@ resources/qt/translations/mindforger_en.qm resources/qt/translations/mindforger_nerd_cs.qm resources/qt/translations/mindforger_nerd_en.qm + resources/qt/translations/mindforger_zh_cn.ts resources/qt/css/dark.css @@ -47,6 +48,8 @@ resources/menu-icons/light_go-home.svg resources/menu-icons/light_tag.svg resources/menu-icons/light_tools-report-bug.svg + resources/menu-icons/light_wingman-green.svg + resources/menu-icons/light_wingman-gray.svg resources/menu-icons/light_view-fullscreen.svg resources/menu-icons/light_view-preview.svg resources/menu-icons/light_view-refresh.svg diff --git a/app/qnetwork-get-test.html b/app/qnetwork-get-test.html new file mode 100644 index 00000000..7b04333d --- /dev/null +++ b/app/qnetwork-get-test.html @@ -0,0 +1,23 @@ +{ + "id": "chatcmpl-8oIy1BN3YeHaGgc3AIaYcEsOWHXbG", + "object": "chat.completion", + "created": 1707000001, + "model": "gpt-3.5-turbo-0613", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Hello! How can I assist you today?" + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 18, + "completion_tokens": 9, + "total_tokens": 27 + }, + "system_fingerprint": null +} diff --git a/app/resources/icons/mindforger-bw.icns b/app/resources/icons/logo-bw/mindforger-bw.icns similarity index 100% rename from app/resources/icons/mindforger-bw.icns rename to app/resources/icons/logo-bw/mindforger-bw.icns diff --git a/app/resources/icons/mindforger-bw.ico b/app/resources/icons/logo-bw/mindforger-bw.ico similarity index 100% rename from app/resources/icons/mindforger-bw.ico rename to app/resources/icons/logo-bw/mindforger-bw.ico diff --git a/app/resources/icons/mindforger-bw.png b/app/resources/icons/logo-bw/mindforger-bw.png similarity index 100% rename from app/resources/icons/mindforger-bw.png rename to app/resources/icons/logo-bw/mindforger-bw.png diff --git a/app/resources/icons/mindforger128x128-bw.png b/app/resources/icons/logo-bw/mindforger128x128-bw.png similarity index 100% rename from app/resources/icons/mindforger128x128-bw.png rename to app/resources/icons/logo-bw/mindforger128x128-bw.png diff --git a/app/resources/icons/logo-genai/mindforger.ico b/app/resources/icons/logo-genai/mindforger.ico new file mode 100644 index 00000000..bc596811 Binary files /dev/null and b/app/resources/icons/logo-genai/mindforger.ico differ diff --git a/app/resources/icons/logo-genai/mindforger.png b/app/resources/icons/logo-genai/mindforger.png new file mode 100644 index 00000000..460d31ba Binary files /dev/null and b/app/resources/icons/logo-genai/mindforger.png differ diff --git a/app/resources/icons/logo-genai/mindforger.svg b/app/resources/icons/logo-genai/mindforger.svg new file mode 100644 index 00000000..ee9582a4 --- /dev/null +++ b/app/resources/icons/logo-genai/mindforger.svg @@ -0,0 +1,516 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/resources/icons/mindforger-uk.icns b/app/resources/icons/logo-uk/mindforger-uk.icns similarity index 100% rename from app/resources/icons/mindforger-uk.icns rename to app/resources/icons/logo-uk/mindforger-uk.icns diff --git a/app/resources/icons/mindforger-uk.ico b/app/resources/icons/logo-uk/mindforger-uk.ico similarity index 100% rename from app/resources/icons/mindforger-uk.ico rename to app/resources/icons/logo-uk/mindforger-uk.ico diff --git a/app/resources/icons/mindforger-uk.png b/app/resources/icons/logo-uk/mindforger-uk.png similarity index 100% rename from app/resources/icons/mindforger-uk.png rename to app/resources/icons/logo-uk/mindforger-uk.png diff --git a/app/resources/icons/mindforger128x128-uk.png b/app/resources/icons/logo-uk/mindforger128x128-uk.png similarity index 100% rename from app/resources/icons/mindforger128x128-uk.png rename to app/resources/icons/logo-uk/mindforger128x128-uk.png diff --git a/app/resources/icons/mindforger.ico b/app/resources/icons/mindforger.ico index 21f9a15d..bc596811 100644 Binary files a/app/resources/icons/mindforger.ico and b/app/resources/icons/mindforger.ico differ diff --git a/app/resources/icons/mindforger.png b/app/resources/icons/mindforger.png index 61d797e7..460d31ba 100644 Binary files a/app/resources/icons/mindforger.png and b/app/resources/icons/mindforger.png differ diff --git a/app/resources/icons/mindforger.svg b/app/resources/icons/mindforger.svg new file mode 100644 index 00000000..ee9582a4 --- /dev/null +++ b/app/resources/icons/mindforger.svg @@ -0,0 +1,516 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/resources/icons/mindforger128x128.png b/app/resources/icons/mindforger128x128.png index 571c02fe..460d31ba 100644 Binary files a/app/resources/icons/mindforger128x128.png and b/app/resources/icons/mindforger128x128.png differ diff --git a/app/resources/menu-icons/light_wingman-gray.svg b/app/resources/menu-icons/light_wingman-gray.svg new file mode 100644 index 00000000..c1b064c0 --- /dev/null +++ b/app/resources/menu-icons/light_wingman-gray.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/resources/menu-icons/light_wingman-green.svg b/app/resources/menu-icons/light_wingman-green.svg new file mode 100644 index 00000000..938ea899 --- /dev/null +++ b/app/resources/menu-icons/light_wingman-green.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/resources/qt/images/mindforger-icon-bw.png b/app/resources/qt/images/bw/mindforger-icon-bw.png similarity index 100% rename from app/resources/qt/images/mindforger-icon-bw.png rename to app/resources/qt/images/bw/mindforger-icon-bw.png diff --git a/app/resources/qt/images/genai/mindforger-icon.png b/app/resources/qt/images/genai/mindforger-icon.png new file mode 100644 index 00000000..460d31ba Binary files /dev/null and b/app/resources/qt/images/genai/mindforger-icon.png differ diff --git a/app/resources/qt/images/mindforger-icon.png b/app/resources/qt/images/mindforger-icon.png index 61d797e7..460d31ba 100644 Binary files a/app/resources/qt/images/mindforger-icon.png and b/app/resources/qt/images/mindforger-icon.png differ diff --git a/app/resources/qt/images/mindforger-icon-uk.png b/app/resources/qt/images/uk/mindforger-icon-uk.png similarity index 100% rename from app/resources/qt/images/mindforger-icon-uk.png rename to app/resources/qt/images/uk/mindforger-icon-uk.png diff --git a/app/resources/qt/translations/mindforger_cs.ts b/app/resources/qt/translations/mindforger_cs.ts index a1d44871..54e741ce 100644 --- a/app/resources/qt/translations/mindforger_cs.ts +++ b/app/resources/qt/translations/mindforger_cs.ts @@ -4,56 +4,76 @@ QObject - + Save Note - + Do you want to save changes? - + Discard changes - + &Discard changes - - + + Autosave - + Do not ask & autosave - + Continue editing - + Continue &editing - + Save - + &Save + + + Empty Phrase + + + + + Phrase to search/explain/process is empty. + + + + + Wingman Not Available + + + + + Wingman provider is either not configured or initialized - see MindForger Preferences (Wingman tab). + + SpellChecker @@ -124,675 +144,441 @@ - m8r + m8r::AddLibraryDialog - - Notebook tags: + + Directory - - Notebooks: + + Choose a directory (library) of PDF files to be indexed. MindForger +will create new notebook for every library file. Such notebook can be +used to easily open the library file and create library file related +notes. + +Choose new library source: - - &Open Notebook + + Library source path: - - &Find Note + + index PDF - - - - - &Cancel + + &Create Library and Index Documents - - Find Notebook by Tags + + &Cancel - - - General + + Add Document Library - - - Advanced + + Choose Directory + + + m8r::AssocLeaderboardModel - - Edit Note + + + Associations - - Name + + + % - - Organizer + + for ' - - View as + + ' + + + m8r::AssocLeaderboardPresenter - - Eisenhower Matrix + + Associations + + + m8r::CliAndBreadcrumbsPresenter - - Kanban + + Wingman help - - Notebook scope + + <html>Use the following commands:<pre><br>? ... help<br>/ ... find<br>@ ... knowledge recherche<br>> ... run a command<br>&nbsp;&nbsp;... or full-text search phrase</pre><br>Examples:<pre><br>/ find notebook by tag TODO<br>@arxiv LLM<br>> emojis</pre> - - Notebook + + Wingman: ? for help, / search, @ knowledge, > command, or type FTS phrase - - Clear + + Notebook not found - please specify tag search phrase (is empty) - - &Create + + Notebook not found - please specify name search phrase (is empty) - - Sort Notebooks by + + Unknown knowledge recherche source - use valid source like @wikipedia - - importance + + No command! + + + m8r::ConfigurationDialog - - urgency + + Application - - Filter by + + Viewer - - notebooks + + Editor - - notes + + Markdown - - notebooks and notes + + Navigator - - Find Notebook as Scope + + Mind - - New Organizer + + Wingman - - Preamble + + Adapt + + + m8r::ConfigurationDialog::AppTab - - Edit Notebook + + UI theme (<font color='#ff0000'>requires restart</font>) - - Specify number of rows and depth to generate + + Menu (<font color='#ff0000'>requires restart</font>) - - rows + + Show the following view on application start - - depth + + Application font size - 0 is system (<font color='#ff0000'>requires restart</font>) - - &Generate + + show toolbar - - Format Generator + + I don't need buttons - I know all keyboard shortcuts! - - show Notebooks/Notes modified or viewed in recent + + nerd terminology - - year(s) + + Appearance (<font color='#ff0000'>requires restart</font>) - - month(s) + + Controls - - day(s) + + Startup + + + m8r::ConfigurationDialog::EditorTab - - hour(s) + + Editor key binding - - minute(s) + + Editor font - - show Notebooks with the following tags + + Spell check dictionaries <a href='https://github.com/dvorka/mindforger/wiki/Installation#spell-check'>configuration documentation</a> - - &Set + + live spell check - - Scope Mind + + TABs as SPACEs - - New Notebook + + autosave Note on editor close - - Open a directory with Markdowns or MindForger repository + + TAB width - - Open Markdown file + + External editor command - - View Dashboard + + Editor + + + m8r::ConfigurationDialog::MarkdownTab - - View Eisenhower Matrix + + syntax highlighting - - View Eisenhower Matrices + + autocomplete text - - View Notebooks + + autocomplete lists, blocks and {([`_ characters - - View Knowledge Graph Navigator + + SPACE-based # in section escaping (HTML otherwise) - - View Tags + + Rendering - - View Recent Notes + + Autocompletion - - Add word to dictionary + + Escaping + + + m8r::ConfigurationDialog::MindTab - - Check spelling... + + save reads metadata - - - Hit ⌘↩ to add tag + + Async refresh interval (1 - 10.000ms) - - - Hit Ctrl+Enter to add tag + + Persistence - - Add Filter Tag + + Notifications + + + m8r::ConfigurationDialog::NavigatorTab - - Create New Tag + + Max graph nodes (150 by default) - - Remove Tag + + Knowledge Graph Navigator - m8r::AddLibraryDialog + m8r::ConfigurationDialog::ViewerTab - - Choose and find library source: + + HTML Viewer - - Directory + + Viewer theme CSS - - Library name: + + HTML zoom (100 is 100%, Ctrl + mouse wheel) - - Library source path: + + source code syntax highlighting support - - index PDF + + math support - - &Create Library and Index Documents + + whole notebook preview - - &Cancel + + double click HTML preview to edit - - Add Document Library + + Diagram support - - Choose Directory + + Find Custom CSS File - - - m8r::AssocLeaderboardModel - - - Associations + + HTML Viewer CSS - - - % - - - - - for ' - - - - - ' - - - - - m8r::AssocLeaderboardPresenter - - - Associations - - - - - m8r::CliAndBreadcrumbsPresenter - - - Notebook - - - - - Notebook not found: - - - - - No command! - - - - - m8r::ConfigurationDialog - - - Application - - - - - Viewer - - - - - Editor - - - - - Markdown - - - - - Navigator - - - - - Mind - - - - - Adapt - - - - - m8r::ConfigurationDialog::AppTab - - - UI theme (<font color='#ff0000'>requires restart</font>) - - - - - Show the following view on application start - - - - - show toolbar - - - - - I don't need buttons - I know all keyboard shortcuts! - - - - - nerd menu (requires restart) - - - - - Startup - - - - - Appearance - - - - - m8r::ConfigurationDialog::EditorTab - - - Editor key binding - - - - - Editor font - - - - - live spell check - - - - - Spell check dictionaries <a href='https://github.com/dvorka/mindforger-repository/blob/master/memory/mindforger/installation.md#spell-check-'>configuration documentation</a> - - - - - TABs as SPACEs - - - - - autosave Note on editor close - - - - - TAB width - - - - - External editor command - - - - - Editor - - - - - m8r::ConfigurationDialog::MarkdownTab - - - syntax highlighting - - - - - autocomplete text - - - - - autocomplete lists, blocks and {([`_ characters - - - - - SPACE-based # in section escaping (HTML otherwise) - - - - - Rendering - - - - - Autocompletion - - - - - Escaping - - - - - m8r::ConfigurationDialog::MindTab - - - save reads metadata - - - - - Async refresh interval (1 - 10.000ms) - - - - - Persistence - - - - - Notifications - - - - - m8r::ConfigurationDialog::NavigatorTab - - - Max graph nodes (150 by default) - - - - - Knowledge Graph Navigator + + Choose CSS File - m8r::ConfigurationDialog::ViewerTab - - - HTML Viewer - - - - - Viewer theme CSS - - - - - HTML zoom (100 is 100%, Ctrl + mouse wheel) - - - - - source code syntax highlighting support - - + m8r::ConfigurationDialog::WingmanTab - - math support + + LLM provider: - - whole notebook preview + + <html>Configure <a href='https://openai.com'>OpenAI</a> LLM provider: +<ul><li><a href='https://platform.openai.com/api-keys'>Generate</a> an OpenAI API key.</li><li>Set the API key:<br>a) either set the <b>%1</b> environment variable<br/>with the API key<br/>b) or paste the API key below to save it <font color='#ff0000'>unencrypted</font> to<br/><b>.mindforger.md</b> file in your home dir.</li><li><font color='#ff0000'>Restart</font> MindForger to apply the change.</li></ul> - - double click HTML preview to edit + + Clear OpenAI API Key - - Diagram support + + OpenAI API Key Cleared - - Find Custom CSS File + + API key has been cleared from the configuration. Please close the configuration dialog with the OK button and restart MindForger to apply this change. - - HTML Viewer CSS + + Data Privacy Warning - - Choose CSS File + + You have chosen OpenAI as your Wingman LLM provider. Therefore, your data will be sent to OpenAI servers for GPT processing when you use Wingman. - - - m8r::DashboardPresenter - - Do first + + Large language model (LLM) providers @@ -840,6 +626,19 @@ + + + Hit ⌘↩ to add tag + + + + + + Hit Ctrl+Enter to add tag + + + + @@ -847,11 +646,17 @@ + Create New Tag + + + Remove Tag + + Add Existing Tag @@ -1007,21 +812,54 @@ - m8r::FtsDialog + m8r::FindOutlineByTagDialog - - Text to &find: + + Notebook tags: - - - Match: + + Notebooks: - - &Exact + + &Open Notebook + + + + + &Find Note + + + + + &Cancel + + + + + Find Notebook by Tags + + + + + m8r::FtsDialog + + + Text to &find: + + + + + + Match: + + + + + &Exact @@ -1103,7 +941,7 @@ - copy image to repository + copy image to workspace @@ -1127,7 +965,7 @@ - + Choose File with Image @@ -1146,27 +984,27 @@ - Notebook + Note&book - Note + &Note - File + &File - Directory + &Directory - copy link target to repository + copy link target to workspace @@ -1241,1545 +1079,1720 @@ - - MindForger &Repository - - - - - Create a brand new MindForger repository... - - - - - + + Markdown &File - + Create a brand new Markdown file... - - &Directory with Markdowns or MindForger Repository - - - - - Learn knowledge by loading a MindForger repository or a directory with Markdown files... - - - - - Learn knowledge by loading a Markdown or MindForger file... - - - - + &Remind - - Re-learn recently opened MindForger repositories, Markdown repositories or files - - - - + Re&member - + Persist all Things in Memory - + &Think - + S&cope - + Don't show Notebooks and Notes older than... - - + + &Forget - + Limbo vs erase memory... - + Retain - - - Create backup archive of the current repository and store it in home directory - - &Adapt &Preferences - + Adapt Mind by setting your preferences... - + E&xit - + Leave application - + &Full-text Search - + Note full-text search - + Recall Note&book by Name - + Find Notebook by name - + Recall &Note by Name - + Find Note by name - + Find Notebook by tags - - Recall Note by &Tags - - - - + Find Note by tags - + Recall Library &Doc by Name - + Find Document by name - - Recall &Persons - - - - - Find persons using Named-entity recognition (NER) - - - - - Recall &Locations - - - - - Find locations using Named-entity recognition (NER) - - - - - Recall Organizations - - - - - Find organizations using Named-entity recognition (NER) - - - - - Recall Other Entities - - - - - Find miscellaneous entities using Named-entity recognition (NER) + + &Recall - - &Recall + + Open Home Notebook... - - Dashboard + + N&otebooks - - Open Home Notebook... + + Show list of Notebooks... - - N&otebooks + + Note&books Tree - - Show list of Notebooks... + + Show tree of Notebooks... - + &Tags - + Open Tag cloud... - + Knowledge Graph &Navigator - + Open knowledge graph Navigator... - + &Memory Dwell - + Open memory dwell... - - &CLI + + Ter&minal - - Ter&minal + + Run simple command line from current MindForger workspace... - + &Recent Notes - + View recently modified Notes... - + &Stencils - + List Notebook and Note stencils... - + List forgotten Notebooks and Notes... - - Ho&isting - - - - + D&istraction Free - + Toggle distraction free mode - + &Fullscreen - + Toggle fullscreen - + &View - + Str&etch edges e | mouse wheel - + Stretch knowledge graph edges - + &Sh&rink edge E | mouse wheel - + Shring knowledge graph edges - + Zoom &in z - + Zoom in knowledge graph - + Zoom &out Z - + Zoom out knowledge graph - + &Shuffle Space - + Shuffle knowledge graph - + + N&avigate + + + + + &New library + + + + + Add path to the directory with documents (PDF, txt, HTML)... + + + + + &Update library + + + + + Synchronize library source directory with MindForger notebook(s) which representlibrary resources... + + + + + &Delete library + + + + + Delete all Notebooks representing the library resources... + + + + &Edit ⌘↩ - + &Edit Alt-Enter - + Move Notebook/Note to Previous Column/Quadrant ⌘[ - + Move Notebook/Note to Next Column/Quadrant ⌘] - + Focus to Previous Column/Quadrant ⇧⇥ - + Focus to Next Column/Quadrant ⇥ - + &HTML - + Export Notebook to a file in HTML format - + &TWiki - + Import Notebook from an external TWiki file and restart MindForger - - Refactor Ctrl+R - - - - + &Undo Ctrl+Z - + Undo - + &Redo Ctrl+Shift+Z - + Redo - + Cu&t Ctrl+X - + Cut - + &Copy Ctrl+C - + Copy - + &Paste Ctrl+V - + Paste - - - - + + + + &Edit - - Run simple command line from current MindForger repository... + + Create backup archive of the current workspace and store it in home directory + + + + + Recall Note by T&ags - + Flashcard &Decks - + Show list of flashcard decks... - + Organiz&ers - + Open Eisenhower matrix and Kanban organizers... - + &Library Documents - + List Library documents... - - Li&mbo - - - - - &Know + + &Wingman - - &Wikipedia + + Emo&jis - - Find marked text on Wikipedia or open Wikipedia search + + Open dialog with emoji characters to be copy/pasted to names, descriptions and text... - &arXiv - - - - - Find marked text on arXiv or get article by ID - - - - - Str&etch edges + Li&mbo - - &Sh&rink edge + + &Find on Web - - Na&vigate + + Find Notebook or Note name; selected text or text under cursor on the web... - - Libr&ary + + Li&brary - - &Add library + + &CLI - - Add directory with documents, URL or other resource to library... + + Ho&ist - - &Deprecate library + + Str&etch edges - - Move a library resource with documents to limbo... + + &Sh&rink edge - + Flash&cards - + &Organizer - + Create new Organizer to prioritize your knowledge in Eisenhower Matrix style - + Edit current Organizer - you can also double click view to open the editor - + Make copy of the current Organizer - + &Delete - + Delete Organizer without undo - - + + Move Notebook/Note to &Previous Column/Quadrant Ctrl+Left - + Move Notebook/Note to previous column or quadrant... - - + + Move Notebook/Note to Ne&xt Column/Quadrant Ctrl+Right - + Move Notebook/Note to next column or quadrant... - - Move focus to previous column or quandrant... - - - - - Move focus to next column or quandrant... - - - - + Note&book - + E&xamine - + Turn Notebook to deck of flashcard and start active recall testing... - - E&xternal Editor Edit Ctrl+X + + &Promote - - Edit current Note in an external editor - use Preferences to configure the editor + + Promote Notebook - - &Forget Ctrl+D + + De&mote - - Save and Leave Ctrl+L + + Demote Notebook - - &Find Ctrl+Shift+F + + Move to &First - - &Live Preview + + Move the Notebook to be the first child of its parent - - Toggle live HTML preview + + Move &Up - - &Word Wrap + + Move the Notebook up - - &Swap Name/Description Focus + + Move the Notebook down - - Swap focus of N title and description editors + + Move to &Last - - Sp&ell Check + + Move the Notebook to be the last child of its parent - - Spell check Notebook or Note description + + E&xternal Editor Edit Ctrl+X - + + Edit current Note in an external editor - use Preferences to configure the editor + + + + + &Forget Ctrl+D + + + + + Save and Leave Ctrl+L + + + + + Move to F&irst Ctrl+Shift+Up + + + + + Move the Note to be the first child of its parent + + + + + Move &Up Ctrl+Up + + + + + Move the Note up + + + + + Move the Note down + + + + + Move to &Last Ctrl+Shift+Down + + + + + Move the Note to be the last child of its parent + + + + + Move to Notebook Ctrl+R + + + + + &Move to Notebook + + + + + Move the current Note to another Notebook... + + + + + &Find Ctrl+Shift+F + + + + + &Live Preview + + + + + Toggle live HTML preview + + + + + Swap focus of N title and description editors + + + + + Run an external tool to find, explain, process text under the cursor + + + + + Complete Link Ctrl+L + + + + + Spell check Notebook or Note description + + + + &Bold - + Format text as bold - + &Italic - + Format text as italic - + &Code - + Format text as inlined source code - + Comment - + Add comment to hide text in rendered HTML - + Lis&ts - + &Bulleted List - + &Numbered List - + &Task List - + Task List &Item - + Bl&ocks - + &Code Block - + &Math Block - + &Diagram Block - + Format code block as diagram (Mermaid) - + Diagrams - + &Flowchart - + Insert flowchart Mermaid diagram skeleton - + &Sequence Diagram - + Insert sequence Mermaid diagram skeleton - + &Class Diagram - + Insert class Mermaid diagram skeleton - + St&ate Diagram - + Insert state Mermaid diagram skeleton - + &Gantt Diagram - + Insert Gantt Mermaid diagram skeleton - + &Pie Diagram - + Insert pie Mermaid chart skeleton - + + in&tegrals + + + + + dot + + + + + ca&p + + + + + in + + + + &Strikethrough - + Format text as strikethrough - + + About &Qt + + + + &Keyboard - + Format text as keyboard input - + Math cheatsheet - + Open MathJax quick reference - + Math live preview - + Open MathJax live demo - + Mermaid dia&grams documentation - + Open Mermaid diagrams documentation - + Format block as bulleted list - + Format block as numbered list - - + + Format block as task list - + Format text block as source code - + Block &Quote - + Format text block as blockquote - + Timestam&p - + &Link - + Insert link to a document, image or file - + Insert image - + Tabl&es - + &Horizontal ruler - + Horizontal ruler - + &Format - - - - + + + + &New - + Create new Notebook to form new ideas, principles, combinations or applications - + Edit current Notebook - you can also double click view to open the editor - + Make &Home - + Import - - + + Make &Stencil - - + + Copy the current Notebook as to Stencil - - + C&lone - + Make copy of the current Notebook - + Forget Notebook and move it to Limbo - + E&xport - + &Forget Del - + Forget Note - + &Learn - + Toggle tag indicating whether to use the current Notebook as home - + &Import - + Think to suggest matching, similar and associated Notes while searching, reading and writing - + &Autolink - + Automatically inject links to relevant Notebooks and Notes when browsing HTML preview - + A&dapt - + &CSV - + Export all Notebooks/Markdown files as a single CSV file - + Recall Notebook by Ta&gs - - Open Dashboard... - - - - + &Home Notebook - + Activate command line interface... - + Create new Note to form new ideas, principles, combinations and applications - + Hoist/de-hoist Note to focus on Note being viewed or edited - + &Edit Ctrl+E - + Edit current Note - you can also double click view to open the editor - + Remember Ctrl+S - + Save Note being edited - + Leave Alt+Left - + Save leave editor of Note being changed - + &Promote Ctrl+Left - + Promote Note - + &Demote Ctrl+Right - + Demote Note - - F&irst Ctrl+Shift+Up + + E&xtract - - Move Note to be the first child of its parent + + Create new Note from the text selected in the current Note... - - &Up Ctrl+Up + + + &Clone - - Move Note up + + + &Workspace - - Do&wn Ctrl+Down + + Create a brand new MindForger workspace... - - Move Note down + + Learn knowledge by loading a MindForger workspace... - - &Last Ctrl+Shift+Down + + &Directory with Markdowns - - Move Note to be the last child of its parent + + Learn knowledge by loading a directory with Markdown files... - - &Refactor + + Learn knowledge by loading a Markdown file... - - Refactor Note to another Notebook... + + Re-learn recently opened MindForger workspaces, Markdown directories or files - - E&xtract + + Make a copy of the Note to this or other Notebook... - - Create new Note from the text selected in the current Note... + + Export Note to an external file in a supported format - - &Clone + + Import Note from an external file in a supported format - - Make a copy of the Note to this or other Notebook... + + &Note - - Export Note to an external file in a supported format + + + + + &Wingman GPT - - Import Note from an external file in a supported format + + Open Wingman dialog... - - &Note + + Move focus to previous column or quadrant... - - Search Note text + + Move focus to next column or quadrant... - - Find Next Ctrl+F + + Move D&own - - Search Note text again + + + &Summarize - - Toggle word wrap mode + + Ask Wingman to summarize text of the Notebook... - - Complete Link Ctrl+/ + + + &Explain - - Complete word being written by finding link to Notebook or Note + + Ask Wingman to explain the name of the Notebook... - - &Math + + &Find Tasks - - Format text as math (MathJax) + + Ask Wingman to find tasks in the Notebook text... - - MathJa&x + + + + &More prompts... - - &text + + + + Open Wingman chat... - - &fraction + + Move Dow&n Ctrl+Down - - &sum + + Ask Wingman to summarize text of the Note... - - s&quare root + + &Find Grammar Errors - - &integral + + Ask Wingman to find grammar errors in the Note text... - - integrals + + &Translate to English - - &alpha + + Ask Wingman to translate the Note text to English... - - &beta + + Search Note text - - &Gama + + Find Next Ctrl+F - - &Delta + + Search Note text again - - &bar + + W&ord Wrap - - &hat + + Toggle word wrap mode - - &dot + + Swap Nam&e/Description Focus - - &overrightarrow + + Complete word being written by finding link to Notebook or Note - - &cup + + &Spell Check - - &cap + + &Fix Grammar - - &empty set + + Ask Wingman to fix grammar errors in the selected text / word under the cursor... - - &in + + Ask Wingman to explain the word under the cursor / selected text... - - &not in + + Finish &Text - - T&able of Contents + + Ask Wingman to finish the text following the selected text / word under the cursor... - - Insert Notebook's table of contents + + &Rewrite Text - + + Ask Wingman to rewrite the text following the selected text / word under the cursor... + + + + + &Math + + + + + Format text as math (MathJax) + + + + + MathJa&x + + + + + &text + + + + + &fraction + + + + + &sum + + + + + s&quare root + + + + + &integral + + + + + &alpha + + + + + &beta + + + + + &Gama + + + + + &Delta + + + + + &bar + + + + + &hat + + + + + &overrightarrow + + + + + &cup + + + + + &empty set + + + + + &not in + + + + + T&able of Contents + + + + Insert current date and time - + Format text block as math (MathJax) - + + With&out tags + + + + + Insert Notebook's table of contents without tags + + + + + &With tags + + + + + Insert Notebook's table of contents with tags + + + + Ima&ge - + Insert table... - + &Documentation - + F1 - + Open MindForger documentation - + &Web - + Open MindForger web - + &Markdown tutorial - + Open Markdown tutorial - + Report &Bug or Request Feature - + Report bug or suggest an enhancement - + &Check for Updates - + Check for MindForger updates - - &About Qt - - - - + About Qt... - + &About MindForger - + About MindForger... - + &Help @@ -2791,748 +2804,779 @@ Main Toolbar - - - m8r::MainWindowPresenter - - - Cannot think - either Mind already dreaming or repository too big + + New Notebook - - Hyperlink %1 clicked... + + Open directory with Markdowns or Workspace - - Link target not found for relative link %1 + + Open Markdown file + + + + + View Eisenhower Matrices - - - New Repository Error + + View Notebooks - - Specified repository path already exists! + + View Knowledge Graph Navigator - - Failed to create empty repository! + + View Tags - - ERROR: repository created, but attempt to copy documentation and/or stencils failed + + View Recent Notes + + + m8r::MainWindowPresenter - - New Markdown File Error + + Cannot think - either Mind already dreaming or repository too big - - - - Specified file path already exists! + + Hyperlink %1 clicked... - - Cannot start sleeping - please wait until dreaming finishes and then try again + + Link target not found for relative link %1 + + + + + New Markdown File Error - - Learn Directory or MindForger Repository + + + + Specified file path already exists! - - Learn Markdown File + + Cannot start sleeping - please wait until dreaming finishes and then try again - - Learn + + Learn Markdown File - - This is neither valid MindForger/Markdown repository nor file. + + Learn - + Export Notebook to HTML - - + + Export - + Autolinked Notebooks and Notes - + Notebook Full-text Search - + Note Full-text Search - + Full-text Search - - - - + + + + Notebook - - + + Notebook not found - + Find Note by Tags in Notebook - - + + Find Note by Tags - - - + + + Note - + Export Memory to CSV - + Thing not found - - + + Note not found - + Refactored Note to Notebook ' - + Target Notebook not found - + Refactor Note - + Note to be refactored not specified! - + Find Note by Name in Notebook - + Find Note by Name - - - - - Initializing NER and predicting... + + image + + + + + Given path '%1' doesn't exist - target will not be copied, but link will be created - - - - - NER + + Saving pasted image data to file: '%1' - - - - - Memory NER not implemented yet. + + HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu - - Recognizing named entities... + + Wingman is talking to the GPT provider... - - Initializing NER and recognizing named entities... + + Wingman received an answer from the GPT provider - - Initializing (the first run only) NER and predicting... + + Wingman failed to receive an answer from the GPT provider - - - Named-entity Recognition + + + Wingman Action Error - - NER predicition finished + + Wingman's answer appended after selected text in the Note editor. - - No named entities recognized. + + Unable to append after selected text with Wingman's answer in non-edit perspective. - - Home Notebook is not defined! + + No answer from Wingman to append after selected text - run a prompt. - - image + + Wingman's answer replaced selected text in Notebook header. - - File copied to repository path '%1' + + Unable to replace Notebook header text - no text selected. - - Given path '%1' doesn't exist - target will not be copied, but link will be created + + Wingman's answer replaced selected text in Note text. - - Saving pasted image data to file: '%1' + + Unable to replace Note text - no text selected. - - HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu + + Unable to replace selected text with Wingman's answer in non-edit perspective. - + + No answer from Wingman to replace selected text - run a prompt. + + + + Edit Notebook - + Please open an Notebook to edit. - - + + New Note - + Failed to create new Note! - - + + Clone Notebook - + Failed to clone Notebook! - + Please open and Notebook to be cloned. - + Home tag toggled/removed - Notebook '%1' is no longer home - + Notebook '%1' successfully marked as home - + Make Notebook home - + Notebook can be marked as home only when viewed. - - + + Forget Notebook - + + Library already indexed - use 'Update library' action to synchronize documents. + + + + + Unable to index documents on library path - either memory directory doesn't exist or not in MindForger workspace mode. + + + + + Library synchronization + + + + + There are no libraries - nothing to synchronize. + + + + + Library deletion + + + + + There are no libraries - nothing to delete. + + + + + Delete Library + + + + + Do you really want to delete Notebooks which represent the library documents? + + + + Do you really want to forget ' - + ' Notebook? - + + Cannot think - either Mind already dreaming or workspace too big + + + + + + New Workspace Error + + + + + Specified workspace path already exists! + + + + + Failed to create empty workspace! + + + + + ERROR: workspace created, but attempt to copy documentation and/or stencils failed + + + + + Learn Directory or MindForger Workspace + + + + + This is neither valid MindForger/Markdown workspace nor file. + + + + + Home Notebook not set - use menu 'Notebooks/Make Home' + + + + + File copied to workspace path '%1' + + + + + Run Knowledge Tool Error + + + + + Unknown tool to run '%1'. + + + + + Open Knowledge Tool Dialog Error + + + + + Unable to construct URL to open for unknown tool '%1'. + + + + + Wingman's answer appended after selected text in the Notebook header. + + + + + Wingman's answer appended after the cursor in the Notebook header. + + + + + Wingman's answer appended after the cursor in the Note editor. + + + + 🔒 Notebook Write Error - + Notebook file is read-only and cannot be written: '%1' - + Do you really want to deprecate ' - + Notebook can be forgotten only when viewed. - - - + + + Export Error - + Unable to find Notebook to export! - + Import TWiki File - + Open and view a Notebook to create new Note. - + Edit Note - - + + Please select a Note to edit in the Notebook. - - + + Edit Note with External Editor Error - + External editor command is not configured in preferences (Editor tab). - - + + Edit Note with External Editor - + Running command: '%1' - + Running command: '%1'. Close external editor to return control back to MindForger. - + Delete Note - + Do you really want to delete note ' - + ' along with its child notes? - + Forget Note - + Please select a Note to forget. - - - + + + Extract Note - + Please select a text to extract. - + Failed to extract new Note! - + Please select a Note, edit it and select a text to extract. - - - + + + Clone Note - + Do you want to clone Note ' - + ' including its child notes?'? - + Failed to clone Note! - + Please select a Note to be cloned. - + Moved Note '%1' to be the first child - - - - + + + + Move Note - - - - + + + + Please select a Note to be moved. - + Moved up Note '%1' - + Moved down Note '%1' - + Moved Note '%1' to be the last child - + Promoted Note '%1' - + Promote Note - + Please select a Note to be promoted. - + Demoted Note '%1' - + Demote Note - + Please select a Note to be demoted. - - - + + + Add Library Error - + Library directory doesn't exist! - - Library already indexed - use update action to reindex documents. - - - - - Unable to index documents on library path - either memory directory doesn't exist or not in MindForger repository mode. - - - - + Organizer Update Error - + Eisenhower Matrix organizer is built-in and cannot be edited - please create or update a custom organizer. - + Organizer Clone Error - + Eisenhower Matrix organizer is built-in and cannot be cloned - please create or update a custom organizer. - + Forget Organizer - + ' Organizer? - + Delete Organizer - + Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can. - - About MindForger - - - - - m8r::MainWindowView - - - Thinking Notebook - - - - - m8r::NerChooseTagTypesDialog - - - Choose entity types to be extracted: - - - - - persons - - - - - locations - - - - - organizations - - - - - other entities - - - - - &Choose - - - - - &Cancel - - - - - Choose Entity Type - - - - - m8r::NerLeaderboardModel - - - Name - - - - - Type - - - - - Score - - - - - person + + View Limbo - - location + + Limbo directory with deleted Notebooks is available in the MindForger workspace, not if a Markdown is edited or a directory with markdowns is opened. - - organization + + Emojis - - misc + + About MindForger - m8r::NerResultDialog - - - Recognized named entities: - - - - - &Find Entity in Notes - - - - - &Cancel - - + m8r::MainWindowView - - Find Named Entities + + Thinking Notebook @@ -3588,62 +3632,80 @@ m8r::NewRepositoryDialog - - Repository name: + + Workspace name: - - Repository directory: + + Workspace directory: - - Repository to be created in: + + Workspace to be created in: - + Find Directory - + include stencils - + include documentation - + &New - + &Cancel - - Create New Repository + + Create New Workspace - - - mindforger-repository + + + mindforger-workspace - + Choose Directory + + m8r::NoteEditDialog + + + General + + + + + Advanced + + + + + Edit Note + + + m8r::NoteEditDialog::AdvancedTab @@ -3751,27 +3813,37 @@ m8r::NoteEditorView - + + Add word to dictionary + + + + + Check spelling... + + + + Exit Editor - + Do you really want to exit editor without saving? - + Full-text Search Result - + No matching text found. - + No spelling suggestions found @@ -3779,17 +3851,17 @@ m8r::NoteNewDialog - + General - + Advanced - + New Note @@ -3797,12 +3869,12 @@ m8r::NoteNewDialog::AdvancedTab - + File - + Location @@ -3821,32 +3893,37 @@ - + Note - + + &Emojis + + + + Edit or view after creation - + Type - + Progress - + Stencil - + Position @@ -3867,11 +3944,98 @@ m8r::OrganizerNewDialog + + Name + + + + Organizer + + View as + + + + + Eisenhower Matrix + + + + + Kanban + + + + + Notebook scope + + + + + Notebook + + + + + Clear + + + + + &Create + + + + + Sort Notebooks by + + + + + importance + + + + + urgency + + + + + Filter by + + + + + notebooks + + + + + notes + + + + + notebooks and notes + + + + + &Cancel + + + + + Find Notebook as Scope + + + + New Organizer @@ -3918,7 +4082,7 @@ m8r::OrganizersTableModel - + Organizers @@ -3926,549 +4090,970 @@ m8r::OrlojPresenter - + Eisenhower Matrix: - + Kanban: - + Organizer: ' - + Selected Organizer not found! - - No Organizer selected! + + No Organizer selected! + + + + + + + Selected Notebook not found! + + + + + + + No Notebook selected! + + + + + Selected Tag not found! + + + + + + No Tag selected! + + + + + Note '%1' %2 + + + + + + Note + + + + + Selected Notebook/Note not found! + + + + + + No Note selected! + + + + + m8r::OutlineHeaderEditDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + Edit Notebook + + + + + m8r::OutlineHeaderEditDialog::AdvancedTab + + + Metadata + + + + + Created + + + + + Last Modified + + + + + Last Read + + + + + Reads + + + + + Writes + + + + + File + + + + + Location + + + + + m8r::OutlineHeaderEditDialog::GeneralTab + + + Basic + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + m8r::OutlineHeaderEditDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineHeaderEditPresenter + + + Notebook '%1' successfully saved + + + + + Attempt to save data from UI to Notebook, but no Notebook is set. + + + + + m8r::OutlineNewDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + New Notebook + + + + + m8r::OutlineNewDialog::AdvancedTab + + + Expected file name + + + + + Location + + + + + m8r::OutlineNewDialog::GeneralTab + + + Basic + + + + + Name + + + + + Notebook + + + + + &Emojis + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + Stencil + + + + + m8r::OutlineNewDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineTreeModel + + + Notebook Outline + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlineView + + + Click this Notebook name to open its Markdown preview in the right panel + + + + + m8r::OutlinesMapModel + + + Notebooks Tree + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlinesTableModel + + + Notebooks + + + + + Importance + + + + + Urgency + + + + + Done + + + + + Ns + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::RecentFilesMenu + + + Clear Menu + + + + + m8r::RecentNotesTableModel + + + Recent Notes + + + + + Notebook + + + + + Rs + + + + + Ws + + + + + Read + + + + + Modified + + + + + m8r::RefactorNoteToOutlineDialog + + + Refactor - - Selected Notebook not found! + + Move Note to Notebook + + + m8r::RemoveLibraryDialog - - - No Notebook selected! + + Choose a library to be removed - this action will delete +Notebooks which represent documents from the library +directory. +Referenced documents will NOT be deleted. + - - Selected Tag not found! + + Choose library to delete: - - - No Tag selected! + + &Delete - - Note '%1' %2 + + &Cancel - - - Note + + Delete Document Library + + + m8r::RowsAndDepthDialog - - Selected Notebook/Note not found! + + Specify number of rows and depth to generate - - - No Note selected! + + rows - - - m8r::OutlineHeaderEditDialog::AdvancedTab - - Metadata + + depth - - Created + + &Generate - - Last Modified + + &Cancel - - Last Read + + Format Generator - - Reads + + Bulleted List Generator - - Writes + + Numbered List Generator - - File + + Tasklist Generator - - Location + + Block Quote Generator - m8r::OutlineHeaderEditDialog::GeneralTab + m8r::RunToolDialog - - Basic + + Phrase: - - Type + + Knowledge source: - - Importance + + Template: - - Urgency + + &Lookup - - Progress + + Lookup Knowledge - - - m8r::OutlineHeaderEditDialog::PreambleTab - - Text + + arXiv - - Preamble + + Wikipedia - - - m8r::OutlineHeaderEditPresenter - - Notebook '%1' successfully saved + + GitHub Repositories - - Attempt to save data from UI to Notebook, but no Notebook is set. + + GitHub Code - - - m8r::OutlineNewDialog - - General + + DuckDuckGo - - Preamble + + Google - - Advanced + + StackOverflow - - New Notebook + + CPP reference - - - m8r::OutlineNewDialog::AdvancedTab - - Expected file name + + Python documentation - - Location + + &Cancel - m8r::OutlineNewDialog::GeneralTab + m8r::ScopeDialog - - Basic + + show Notebooks/Notes modified or viewed in recent - - Name + + year(s) - - Notebook + + month(s) - - Type + + day(s) - - Importance + + hour(s) - - Urgency + + minute(s) - - Progress + + show Notebooks with the following tags - - Stencil + + &Set - - - m8r::OutlineNewDialog::PreambleTab - - Text + + &Cancel - - Preamble + + Scope Mind - m8r::OutlineTreeModel + m8r::SyncLibraryDialog - - Outline + + Choose a library directory to be synchronized - new notebook +will be created for every new document found in the library. +Existing MindForger notebooks for library documents which were +deleted, renamed or moved (i.e. their link to library document +is broken) will not be deprecated to protect your document-related +notes. Feel free to deprecate such notebook(s) yourself. + - - Done + + Choose library to update: - - Rs + + &Update - - Ws + + &Cancel - - Modified + + Update Document Library - m8r::OutlineView + m8r::TagsTableModel - - Click this Notebook name to open its Markdown preview in the right panel + + Tags + + + + + Ts - m8r::OutlinesTableModel + m8r::TerminalDialog - - Notebooks + + Terminal - - Importance + + Terminal Command Error + + + m8r::ViewToEditEditButtonsPanel - - Urgency + + View Notebook Header - - Done + + View Notebook - - Ns + + Show preview of Notebook name and its description - - Rs + + &Edit - - Ws + + Full / Header Notebook Preview - - Modified + + Whole Notebook &Preview - - - m8r::RecentFilesMenu - - Clear Menu + + Show whole Notebook preview or Notebook header preview - m8r::RecentNotesTableModel + m8r::WingmanDialog - - Recent Notes + + Wingman Chat - - Notebook + + + Prompt: - - Rs + + Use 'clear' or 'cls' to clear the chat window. Use 'exit', 'quit' or 'bye' to close the dialog. - - Ws + + &Run Prompt - - Read + + C&opy - - Modified + + Copy last answer to the clipboard - - - m8r::RefactorNoteToOutlineDialog - - Refactor + + &Append - - Refactor Note to Notebook + + Append the last Wingman answer to the Note text after the cursor - - - m8r::RowsAndDepthDialog - - Bulleted List Generator + + &Replace - - Numbered List Generator + + Replace (selected) Note text with the last Wingman answer - - Tasklist Generator + + Show Predefined &Prompts - - Block Quote Generator + + + Show &Context - - - m8r::TagsTableModel - - Tags + + Close - - Ts + + Context - - - m8r::TerminalDialog - - Terminal Command Error + + Type: - - - m8r::ViewToEditEditButtonsPanel - - View Notebook Header + + Name (#NAME): - - View Notebook + + Text (#TEXT): - - Show preview of Notebook name and its description + + notebook - - &Edit + + <Notebook text> - - Full / Header Notebook Preview + + <Note text> - - Whole Notebook &Preview + + Show &Predefined Prompts - - Show whole Notebook preview or Notebook header preview + + Predefined prompts: + + + + + Write Your &Prompt + + + + + Hide &Context + + + + + note main - + MindForger CANNOT be run from text console - set DISPLAY environment variable or run MindForger from GUI. - - MindForger repository or directory/file with Markdown(s) to open + + MindForger workspace or directory/file with Markdown(s) to open - + Use 'dark', 'light' or other GUI <theme>. - + theme - + Load configuration from given <file>. - - + + file - + Disable WebEngine security to allow loading of images on macOS. - + Disable WebEngine security by running single process on macOS. - + Disable WebEngine security by disabling sandbox on macOS. - + Disable WebEngine security by user data dir specification on macOS. - + Disable WebEngine security via site isolation trials on macOS. - + Disable WebEngine security via acess file from file on macOS. - - Error: Unable to find given repository/file to open - open MindForger without parameters and create it from menu Mind/New: ' + + Error: Unable to find given workspace/file to open - open MindForger without parameters and create it from menu Mind/New: ' - + Ignoring unknown GUI theme: ' diff --git a/app/resources/qt/translations/mindforger_en.qm b/app/resources/qt/translations/mindforger_en.qm index 9d6722c8..7a14041a 100644 Binary files a/app/resources/qt/translations/mindforger_en.qm and b/app/resources/qt/translations/mindforger_en.qm differ diff --git a/app/resources/qt/translations/mindforger_en.ts b/app/resources/qt/translations/mindforger_en.ts index ba0c700a..94f4875c 100644 --- a/app/resources/qt/translations/mindforger_en.ts +++ b/app/resources/qt/translations/mindforger_en.ts @@ -4,56 +4,76 @@ QObject - + Save Note - + Do you want to save changes? - + Discard changes - + &Discard changes - - + + Autosave - + Do not ask & autosave - + Continue editing - + Continue &editing - + Save - + &Save + + + Empty Phrase + + + + + Phrase to search/explain/process is empty. + + + + + Wingman Not Available + + + + + Wingman provider is either not configured or initialized - see MindForger Preferences (Wingman tab). + + SpellChecker @@ -124,676 +144,442 @@ - m8r + m8r::AddLibraryDialog - - Notebook tags: + + Directory - - Notebooks: + + Choose a directory (library) of PDF files to be indexed. MindForger +will create new notebook for every library file. Such notebook can be +used to easily open the library file and create library file related +notes. + +Choose new library source: - - &Open Notebook + + Library source path: - - &Find Note + + index PDF - - - - - &Cancel + + &Create Library and Index Documents - - Find Notebook by Tags + + &Cancel - - - General + + Add Document Library - - - Advanced + + Choose Directory + + + m8r::AssocLeaderboardModel - - Edit Note + + + Associations - - Name + + + % - - Organizer + + for ' - - View as + + ' + + + m8r::AssocLeaderboardPresenter - - Eisenhower Matrix + + Associations + + + m8r::CliAndBreadcrumbsPresenter - - Kanban + + Wingman help - - Notebook scope + + <html>Use the following commands:<pre><br>? ... help<br>/ ... find<br>@ ... knowledge recherche<br>> ... run a command<br>&nbsp;&nbsp;... or full-text search phrase</pre><br>Examples:<pre><br>/ find notebook by tag TODO<br>@arxiv LLM<br>> emojis</pre> - - Notebook + + Wingman: ? for help, / search, @ knowledge, > command, or type FTS phrase - - Clear + + Notebook not found - please specify tag search phrase (is empty) - - &Create + + Notebook not found - please specify name search phrase (is empty) - - Sort Notebooks by + + Unknown knowledge recherche source - use valid source like @wikipedia - - importance + + No command! + + + m8r::ConfigurationDialog - - urgency + + Application - - Filter by + + Viewer - - notebooks + + Editor - - notes + + Markdown - - notebooks and notes + + Navigator - - Find Notebook as Scope + + Mind - - New Organizer + + Wingman - - Preamble - + + Adapt + Preferences + Preferences + + + m8r::ConfigurationDialog::AppTab - - Edit Notebook + + UI theme (<font color='#ff0000'>requires restart</font>) - - Specify number of rows and depth to generate + + Menu (<font color='#ff0000'>requires restart</font>) - - rows + + Show the following view on application start - - depth + + Application font size - 0 is system (<font color='#ff0000'>requires restart</font>) - - &Generate + + show toolbar - - Format Generator + + I don't need buttons - I know all keyboard shortcuts! - - show Notebooks/Notes modified or viewed in recent + + nerd terminology - - year(s) + + Appearance (<font color='#ff0000'>requires restart</font>) - - month(s) + + Controls - - day(s) + + Startup + + + m8r::ConfigurationDialog::EditorTab - - hour(s) + + Editor key binding - - minute(s) + + Editor font - - show Notebooks with the following tags + + Spell check dictionaries <a href='https://github.com/dvorka/mindforger/wiki/Installation#spell-check'>configuration documentation</a> - - &Set + + live spell check - - Scope Mind + + TABs as SPACEs - - New Notebook + + autosave Note on editor close - - Open a directory with Markdowns or MindForger repository + + TAB width - - Open Markdown file + + External editor command - - View Dashboard + + Editor + + + m8r::ConfigurationDialog::MarkdownTab - - View Eisenhower Matrix + + syntax highlighting - - View Eisenhower Matrices + + autocomplete text - - View Notebooks + + autocomplete lists, blocks and {([`_ characters - - View Knowledge Graph Navigator + + SPACE-based # in section escaping (HTML otherwise) - - View Tags + + Rendering - - View Recent Notes + + Autocompletion - - Add word to dictionary + + Escaping + + + m8r::ConfigurationDialog::MindTab - - Check spelling... + + save reads metadata - - - Hit ⌘↩ to add tag + + Async refresh interval (1 - 10.000ms) - - - Hit Ctrl+Enter to add tag + + Persistence - - Add Filter Tag + + Notifications + + + m8r::ConfigurationDialog::NavigatorTab - - Create New Tag + + Max graph nodes (150 by default) - - Remove Tag + + Knowledge Graph Navigator - m8r::AddLibraryDialog + m8r::ConfigurationDialog::ViewerTab - - Choose and find library source: + + HTML Viewer - - Directory + + Viewer theme CSS - - Library name: + + HTML zoom (100 is 100%, Ctrl + mouse wheel) - - Library source path: + + source code syntax highlighting support - - index PDF + + math support - - &Create Library and Index Documents + + whole notebook preview - - &Cancel + + double click HTML preview to edit - - Add Document Library + + Diagram support - - Choose Directory + + Find Custom CSS File - - - m8r::AssocLeaderboardModel - - - Associations + + HTML Viewer CSS - - - % - - - - - for ' - - - - - ' - - - - - m8r::AssocLeaderboardPresenter - - - Associations - - - - - m8r::CliAndBreadcrumbsPresenter - - - Notebook - - - - - Notebook not found: - - - - - No command! - - - - - m8r::ConfigurationDialog - - - Application - - - - - Viewer - - - - - Editor - - - - - Markdown - - - - - Navigator - - - - - Mind - - - - - Adapt - Preferences - Preferences - - - - m8r::ConfigurationDialog::AppTab - - - UI theme (<font color='#ff0000'>requires restart</font>) - - - - - Show the following view on application start - - - - - show toolbar - - - - - I don't need buttons - I know all keyboard shortcuts! - - - - - nerd menu (requires restart) - - - - - Startup - - - - - Appearance - - - - - m8r::ConfigurationDialog::EditorTab - - - Editor key binding - - - - - Editor font - - - - - live spell check - - - - - Spell check dictionaries <a href='https://github.com/dvorka/mindforger-repository/blob/master/memory/mindforger/installation.md#spell-check-'>configuration documentation</a> - - - - - TABs as SPACEs - - - - - autosave Note on editor close - - - - - TAB width - - - - - External editor command - - - - - Editor - - - - - m8r::ConfigurationDialog::MarkdownTab - - - syntax highlighting - - - - - autocomplete text - - - - - autocomplete lists, blocks and {([`_ characters - - - - - SPACE-based # in section escaping (HTML otherwise) - - - - - Rendering - - - - - Autocompletion - - - - - Escaping - - - - - m8r::ConfigurationDialog::MindTab - - - save reads metadata - - - - - Async refresh interval (1 - 10.000ms) - - - - - Persistence - - - - - Notifications - - - - - m8r::ConfigurationDialog::NavigatorTab - - - Max graph nodes (150 by default) - - - - - Knowledge Graph Navigator + + Choose CSS File - m8r::ConfigurationDialog::ViewerTab - - - HTML Viewer - - - - - Viewer theme CSS - - - - - HTML zoom (100 is 100%, Ctrl + mouse wheel) - - - - - source code syntax highlighting support - - + m8r::ConfigurationDialog::WingmanTab - - math support + + LLM provider: - - whole notebook preview + + <html>Configure <a href='https://openai.com'>OpenAI</a> LLM provider: +<ul><li><a href='https://platform.openai.com/api-keys'>Generate</a> an OpenAI API key.</li><li>Set the API key:<br>a) either set the <b>%1</b> environment variable<br/>with the API key<br/>b) or paste the API key below to save it <font color='#ff0000'>unencrypted</font> to<br/><b>.mindforger.md</b> file in your home dir.</li><li><font color='#ff0000'>Restart</font> MindForger to apply the change.</li></ul> - - double click HTML preview to edit + + Clear OpenAI API Key - - Diagram support + + OpenAI API Key Cleared - - Find Custom CSS File + + API key has been cleared from the configuration. Please close the configuration dialog with the OK button and restart MindForger to apply this change. - - HTML Viewer CSS + + Data Privacy Warning - - Choose CSS File + + You have chosen OpenAI as your Wingman LLM provider. Therefore, your data will be sent to OpenAI servers for GPT processing when you use Wingman. - - - m8r::DashboardPresenter - - Do first + + Large language model (LLM) providers @@ -848,6 +634,19 @@ + + + Hit ⌘↩ to add tag + + + + + + Hit Ctrl+Enter to add tag + + + + @@ -855,11 +654,17 @@ + Create New Tag + + + Remove Tag + + Add Existing Tag @@ -1015,16 +820,49 @@ - m8r::FtsDialog + m8r::FindOutlineByTagDialog - - Text to &find: + + Notebook tags: - - - Match: + + Notebooks: + + + + + &Open Notebook + + + + + &Find Note + + + + + &Cancel + + + + + Find Notebook by Tags + + + + + m8r::FtsDialog + + + Text to &find: + + + + + + Match: @@ -1111,7 +949,7 @@ - copy image to repository + copy image to workspace @@ -1135,7 +973,7 @@ - + Choose File with Image @@ -1154,27 +992,27 @@ - Notebook + Note&book - Note + &Note - File + &File - Directory + &Directory - copy link target to repository + copy link target to workspace @@ -1236,7 +1074,7 @@ &Mind - Fi&le + Work&space @@ -1249,143 +1087,120 @@ - - MindForger &Repository - - - - - Create a brand new MindForger repository... - - - - - + + Markdown &File - + Create a brand new Markdown file... - - &Directory with Markdowns or MindForger Repository - - - - Learn knowledge by loading a MindForger repository or a directory with Markdown files... - Open MindForger repository or a directory with Markdown files... + Open MindForger repository or a directory with Markdown files... - Learn knowledge by loading a Markdown or MindForger file... - Open a Markdown or MindForger file... + Open a Markdown or MindForger file... - + &Remind &Recent - Re-learn recently opened MindForger repositories, Markdown repositories or files - Reopen recently opened MindForger repositories, Markdown repositories or files + Reopen recently opened MindForger repositories, Markdown repositories or files - + Re&member &Save - + Persist all Things in Memory - + &Think - + S&cope - + Don't show Notebooks and Notes older than... - - + + &Forget &Deprecate - + Limbo vs erase memory... - + Retain Reta&in - - - Create backup archive of the current repository and store it in home directory - - &Adapt &Preferences - + Adapt Mind by setting your preferences... - + E&xit - + Leave application - + &Full-text Search - + Note full-text search - + Recall Note&book by Name Find Note&book by Name - + Find Notebook by name - + Recall &Note by Name Find &Note by Name - + Find Note by name @@ -1394,1404 +1209,1634 @@ Find Notebook by T&ags - + Find Notebook by tags - Recall Note by &Tags - Find Note by &Tags + Find Note by &Tags - + Find Note by tags - + Recall Library &Doc by Name - + Find Library &Doc by Name - + Find Document by name - Recall &Persons - Find &Persons - - - - Find persons using Named-entity recognition (NER) - + Find &Persons - Recall &Locations - Find &Locations - - - - Find locations using Named-entity recognition (NER) - + Find &Locations - Recall Organizations - Find Organizations - - - - Find organizations using Named-entity recognition (NER) - + Find Organizations - Recall Other Entities - Find Other Entities - - - - Find miscellaneous entities using Named-entity recognition (NER) - + Find Other Entities - + &Recall F&ind - - Dashboard - - - - + Open Home Notebook... - + N&otebooks - + Show list of Notebooks... - + + Note&books Tree + + + + + Show tree of Notebooks... + + + + &Tags - + Open Tag cloud... - + Knowledge Graph &Navigator - + Open knowledge graph Navigator... - + &Memory Dwell - + Open memory dwell... - - &CLI + + Ter&minal - - Ter&minal + + Run simple command line from current MindForger workspace... - + &Recent Notes - + View recently modified Notes... - + &Stencils - + List Notebook and Note stencils... - + List forgotten Notebooks and Notes... - - Ho&isting - - - - + D&istraction Free - + Toggle distraction free mode - + &Fullscreen - + Toggle fullscreen - + &View - + Str&etch edges e | mouse wheel - + Stretch knowledge graph edges - + &Sh&rink edge E | mouse wheel - + Shring knowledge graph edges - + Zoom &in z - + Zoom in knowledge graph - + Zoom &out Z - + Zoom out knowledge graph - + &Shuffle Space - + Shuffle knowledge graph - + + N&avigate + + + + + &New library + + + + + Add path to the directory with documents (PDF, txt, HTML)... + + + + + &Update library + + + + + Synchronize library source directory with MindForger notebook(s) which representlibrary resources... + + + + + &Delete library + + + + + Delete all Notebooks representing the library resources... + + + + &Edit ⌘↩ - + &Edit Alt-Enter - + Move Notebook/Note to Previous Column/Quadrant ⌘[ - + Move Notebook/Note to Next Column/Quadrant ⌘] - + Focus to Previous Column/Quadrant ⇧⇥ - + Focus to Next Column/Quadrant ⇥ - + &HTML - + Export Notebook to a file in HTML format - + &TWiki - + Import Notebook from an external TWiki file and restart MindForger - - Refactor Ctrl+R - - - - + Search Note text - + Find Next Ctrl+F - + Search Note text again - + &Undo Ctrl+Z - + Undo - + &Redo Ctrl+Shift+Z - + Redo - + Cu&t Ctrl+X - + Cut - + &Copy Ctrl+C - + Copy - + &Paste Ctrl+V - + Paste - - - - + + + + &Edit - - Run simple command line from current MindForger repository... + + Create backup archive of the current workspace and store it in home directory - + + Recall Note by T&ags + Find Note by T&ags + + + Flashcard &Decks - + Show list of flashcard decks... - + Organiz&ers - + Open Eisenhower matrix and Kanban organizers... - + &Library Documents - + List Library documents... - - Li&mbo - - - - - &Know + + &Wingman - - &Wikipedia + + Emo&jis - - Find marked text on Wikipedia or open Wikipedia search + + Open dialog with emoji characters to be copy/pasted to names, descriptions and text... - &arXiv - - - - - Find marked text on arXiv or get article by ID - - - - - Str&etch edges + Li&mbo - - &Sh&rink edge + + &Find on Web - - Na&vigate + + Find Notebook or Note name; selected text or text under cursor on the web... - - Libr&ary + + Li&brary - - &Add library + + &CLI - - Add directory with documents, URL or other resource to library... + + Ho&ist - - &Deprecate library + + Str&etch edges - - Move a library resource with documents to limbo... + + &Sh&rink edge - + Flash&cards - + &Organizer - + Create new Organizer to prioritize your knowledge in Eisenhower Matrix style - + Edit current Organizer - you can also double click view to open the editor - + Make copy of the current Organizer - + &Delete - + Delete Organizer without undo - - + + Move Notebook/Note to &Previous Column/Quadrant Ctrl+Left - + Move Notebook/Note to previous column or quadrant... - - + + Move Notebook/Note to Ne&xt Column/Quadrant Ctrl+Right - + Move Notebook/Note to next column or quadrant... - - Move focus to previous column or quandrant... - - - - - Move focus to next column or quandrant... - - - - + Note&book - + E&xamine - + Turn Notebook to deck of flashcard and start active recall testing... - - E&xternal Editor Edit Ctrl+X + + &Promote - - Edit current Note in an external editor - use Preferences to configure the editor + + Promote Notebook - - &Forget Ctrl+D + + De&mote - - Save and Leave Ctrl+L + + Demote Notebook - - &Find Ctrl+Shift+F + + Move to &First - - &Live Preview + + Move the Notebook to be the first child of its parent - - Toggle live HTML preview + + Move &Up - - &Word Wrap + + Move the Notebook up - - &Swap Name/Description Focus + + Move the Notebook down - - Swap focus of N title and description editors + + Move to &Last - - Sp&ell Check + + Move the Notebook to be the last child of its parent - - Spell check Notebook or Note description + + E&xternal Editor Edit Ctrl+X - - &Bold + + Edit current Note in an external editor - use Preferences to configure the editor - - Format text as bold + + &Forget Ctrl+D - - &Italic + + Save and Leave Ctrl+L - - Format text as italic + + Move to F&irst Ctrl+Shift+Up - - &Code + + Move the Note to be the first child of its parent - - Format text as inlined source code + + Move &Up Ctrl+Up - + + Move the Note up + + + + + Move the Note down + + + + + Move to &Last Ctrl+Shift+Down + + + + + Move the Note to be the last child of its parent + + + + + Move to Notebook Ctrl+R + + + + + &Move to Notebook + + + + + Move the current Note to another Notebook... + + + + + &Find Ctrl+Shift+F + + + + + &Live Preview + + + + + Toggle live HTML preview + + + + + Swap focus of N title and description editors + + + + + Run an external tool to find, explain, process text under the cursor + + + + + Complete Link Ctrl+L + + + + + Spell check Notebook or Note description + + + + + &Bold + + + + + Format text as bold + + + + + &Italic + + + + + Format text as italic + + + + + &Code + + + + + Format text as inlined source code + + + + &Math - + Format text as math (MathJax) - + Comment - + Add comment to hide text in rendered HTML - + Lis&ts - + &Bulleted List - + &Numbered List - + &Task List - + Task List &Item - + Bl&ocks - + &Code Block - + &Math Block - + &Diagram Block - + Format code block as diagram (Mermaid) - + Diagrams - + &Flowchart - + Insert flowchart Mermaid diagram skeleton - + &Sequence Diagram - + Insert sequence Mermaid diagram skeleton - + &Class Diagram - + Insert class Mermaid diagram skeleton - + St&ate Diagram - + Insert state Mermaid diagram skeleton - + &Gantt Diagram - + Insert Gantt Mermaid diagram skeleton - + &Pie Diagram - + Insert pie Mermaid chart skeleton - + + in&tegrals + + + + + dot + + + + + ca&p + + + + + in + + + + &Strikethrough - + Format text as strikethrough - + + About &Qt + + + + &Keyboard - + Format text as keyboard input - + Math cheatsheet - + Open MathJax quick reference - + Math live preview - + Open MathJax live demo - + Mermaid dia&grams documentation - + Open Mermaid diagrams documentation - + Format block as bulleted list - + Format block as numbered list - - + + Format block as task list - + T&able of Contents - - Insert Notebook's table of contents - - - - + Insert current date and time - + Format text block as source code - + Format text block as math (MathJax) - + Block &Quote - + Format text block as blockquote - + &Link - + Insert link to a document, image or file - + Insert image - + Tabl&es - + &Horizontal ruler - + Horizontal ruler - + &Format - - - - + + + + &New - + Create new Notebook to form new ideas, principles, combinations or applications - + Edit current Notebook - you can also double click view to open the editor - + Make &Home - + Import - - + + Make &Stencil - - + + Copy the current Notebook as to Stencil - - + C&lone - + Make copy of the current Notebook - + Forget Notebook and move it to Limbo Delete Notebook and move it Limbo - + E&xport - + &Forget Del Delete Del - + Forget Note Delete Note - + &Learn &Open - + Toggle tag indicating whether to use the current Notebook as home - + &Import - + Think to suggest matching, similar and associated Notes while searching, reading and writing - + &Autolink - + Automatically inject links to relevant Notebooks and Notes when browsing HTML preview - + A&dapt &Preferences - + &CSV - + Export all Notebooks/Markdown files as a single CSV file - + Recall Notebook by Ta&gs Find Notebook by Ta&gs - - Open Dashboard... - - - - + &Home Notebook - + Activate command line interface... - + Create new Note to form new ideas, principles, combinations and applications - + Hoist/de-hoist Note to focus on Note being viewed or edited - + &Edit Ctrl+E - + Edit current Note - you can also double click view to open the editor - + Remember Ctrl+S Save Ctrl+S - + Save Note being edited - + Leave Alt+Left - + Save leave editor of Note being changed - + &Promote Ctrl+Left - + Promote Note - + &Demote Ctrl+Right - + Demote Note - - F&irst Ctrl+Shift+Up + + E&xtract - - Move Note to be the first child of its parent + + Create new Note from the text selected in the current Note... - - &Up Ctrl+Up + + + &Clone - - Move Note up + + + &Workspace - - Do&wn Ctrl+Down + + Create a brand new MindForger workspace... - - Move Note down + + Learn knowledge by loading a MindForger workspace... - - &Last Ctrl+Shift+Down + + &Directory with Markdowns - - Move Note to be the last child of its parent + + Learn knowledge by loading a directory with Markdown files... - - &Refactor + + Learn knowledge by loading a Markdown file... - - Refactor Note to another Notebook... + + Re-learn recently opened MindForger workspaces, Markdown directories or files - - E&xtract + + Make a copy of the Note to this or other Notebook... - - Create new Note from the text selected in the current Note... + + Export Note to an external file in a supported format - - &Clone + + Import Note from an external file in a supported format - - Make a copy of the Note to this or other Notebook... + + &Note - - Export Note to an external file in a supported format + + + + + &Wingman GPT - - Import Note from an external file in a supported format + + Open Wingman dialog... - - &Note + + Move focus to previous column or quadrant... - - Toggle word wrap mode + + Move focus to next column or quadrant... - - Complete Link Ctrl+/ + + Move D&own - - Complete word being written by finding link to Notebook or Note + + + &Summarize - - MathJa&x + + Ask Wingman to summarize text of the Notebook... - - &text + + + &Explain - - &fraction + + Ask Wingman to explain the name of the Notebook... - - &sum + + &Find Tasks - - s&quare root + + Ask Wingman to find tasks in the Notebook text... - - &integral + + + + &More prompts... - - integrals + + + + Open Wingman chat... - - &alpha + + Move Dow&n Ctrl+Down - - &beta + + Ask Wingman to summarize text of the Note... - - &Gama + + &Find Grammar Errors - - &Delta + + Ask Wingman to find grammar errors in the Note text... - - &bar + + &Translate to English - - &hat + + Ask Wingman to translate the Note text to English... - - &dot + + W&ord Wrap - - &overrightarrow + + Toggle word wrap mode - - &cup + + Swap Nam&e/Description Focus - - &cap + + Complete word being written by finding link to Notebook or Note - - &empty set + + &Spell Check - - &in + + &Fix Grammar - - &not in + + Ask Wingman to fix grammar errors in the selected text / word under the cursor... - - Timestam&p + + Ask Wingman to explain the word under the cursor / selected text... - - Ima&ge + + Finish &Text - - Insert table... + + Ask Wingman to finish the text following the selected text / word under the cursor... - - &Documentation + + &Rewrite Text - - F1 + + Ask Wingman to rewrite the text following the selected text / word under the cursor... - + + MathJa&x + + + + + &text + + + + + &fraction + + + + + &sum + + + + + s&quare root + + + + + &integral + + + + + &alpha + + + + + &beta + + + + + &Gama + + + + + &Delta + + + + + &bar + + + + + &hat + + + + + &overrightarrow + + + + + &cup + + + + + &empty set + + + + + &not in + + + + + With&out tags + + + + + Insert Notebook's table of contents without tags + + + + + &With tags + + + + + Insert Notebook's table of contents with tags + + + + + Timestam&p + + + + + Ima&ge + + + + + Insert table... + + + + + &Documentation + + + + + F1 + + + + Open MindForger documentation - + &Web - + Open MindForger web - + &Markdown tutorial - + Open Markdown tutorial - + Report &Bug or Request Feature - + Report bug or suggest an enhancement - + &Check for Updates - + Check for MindForger updates - - &About Qt - - - - + About Qt... - + &About MindForger - + About MindForger... - + &Help @@ -2803,748 +2848,783 @@ Main Toolbar - - - m8r::MainWindowPresenter - - - Cannot think - either Mind already dreaming or repository too big + + New Notebook - - Hyperlink %1 clicked... + + Open directory with Markdowns or Workspace - - Link target not found for relative link %1 + + Open Markdown file + + + + + View Eisenhower Matrices + + + + + View Notebooks - - - New Repository Error + + View Knowledge Graph Navigator + + + + + View Tags + + + + + View Recent Notes + + + m8r::MainWindowPresenter - - Specified repository path already exists! + + Cannot think - either Mind already dreaming or repository too big - - Failed to create empty repository! + + Hyperlink %1 clicked... - - ERROR: repository created, but attempt to copy documentation and/or stencils failed + + Link target not found for relative link %1 - + New Markdown File Error - - - + + + Specified file path already exists! - + Cannot start sleeping - please wait until dreaming finishes and then try again - Learn Directory or MindForger Repository - Open Directory or MindForger Repository + Open Directory or MindForger Repository - + Learn Markdown File Open Markdown File - + Learn Open - - This is neither valid MindForger/Markdown repository nor file. - - - - + Export Notebook to HTML - - + + Export - + Autolinked Notebooks and Notes - + Notebook Full-text Search - + Note Full-text Search - + Full-text Search - - - - + + + + Notebook - - + + Notebook not found - + Find Note by Tags in Notebook - - + + Find Note by Tags - - - + + + Note - + Export Memory to CSV - + Thing not found - - + + Note not found - + Refactored Note to Notebook ' - + Target Notebook not found - + Refactor Note - + Note to be refactored not specified! - + Find Note by Name in Notebook - + Find Note by Name - - - - - Initializing NER and predicting... + + image - - - - - NER + + Given path '%1' doesn't exist - target will not be copied, but link will be created - - - - - Memory NER not implemented yet. + + Saving pasted image data to file: '%1' - - Recognizing named entities... + + HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu - - Initializing NER and recognizing named entities... + + Wingman is talking to the GPT provider... - - Initializing (the first run only) NER and predicting... + + Wingman received an answer from the GPT provider - - - Named-entity Recognition + + Wingman failed to receive an answer from the GPT provider - - NER predicition finished + + + Wingman Action Error - - No named entities recognized. + + Wingman's answer appended after selected text in the Note editor. - - Home Notebook is not defined! + + Unable to append after selected text with Wingman's answer in non-edit perspective. - - image + + No answer from Wingman to append after selected text - run a prompt. - - File copied to repository path '%1' + + Wingman's answer replaced selected text in Notebook header. - - Given path '%1' doesn't exist - target will not be copied, but link will be created + + Unable to replace Notebook header text - no text selected. - - Saving pasted image data to file: '%1' + + Wingman's answer replaced selected text in Note text. - - HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu + + Unable to replace Note text - no text selected. - + + Unable to replace selected text with Wingman's answer in non-edit perspective. + + + + + No answer from Wingman to replace selected text - run a prompt. + + + + Edit Notebook - + Please open an Notebook to edit. - - + + New Note - + Failed to create new Note! - - + + Clone Notebook - + Failed to clone Notebook! - + Please open and Notebook to be cloned. - + Home tag toggled/removed - Notebook '%1' is no longer home - + Notebook '%1' successfully marked as home - + Make Notebook home - + Notebook can be marked as home only when viewed. - - + + Forget Notebook Deprecate Notebook - + + Library already indexed - use 'Update library' action to synchronize documents. + + + + + Unable to index documents on library path - either memory directory doesn't exist or not in MindForger workspace mode. + + + + + Library synchronization + + + + + There are no libraries - nothing to synchronize. + + + + + Library deletion + + + + + There are no libraries - nothing to delete. + + + + + Delete Library + + + + + Do you really want to delete Notebooks which represent the library documents? + + + + Do you really want to forget ' - + ' Notebook? - + + Cannot think - either Mind already dreaming or workspace too big + + + + + + New Workspace Error + + + + + Specified workspace path already exists! + + + + + Failed to create empty workspace! + + + + + ERROR: workspace created, but attempt to copy documentation and/or stencils failed + + + + + Learn Directory or MindForger Workspace + + + + + This is neither valid MindForger/Markdown workspace nor file. + + + + + Home Notebook not set - use menu 'Notebooks/Make Home' + + + + + File copied to workspace path '%1' + + + + + Run Knowledge Tool Error + + + + + Unknown tool to run '%1'. + + + + + Open Knowledge Tool Dialog Error + + + + + Unable to construct URL to open for unknown tool '%1'. + + + + + Wingman's answer appended after selected text in the Notebook header. + + + + + Wingman's answer appended after the cursor in the Notebook header. + + + + + Wingman's answer appended after the cursor in the Note editor. + + + + 🔒 Notebook Write Error - + Notebook file is read-only and cannot be written: '%1' - + Do you really want to deprecate ' - + Notebook can be forgotten only when viewed. - - - + + + Export Error - + Unable to find Notebook to export! - + Import TWiki File - + Open and view a Notebook to create new Note. - + Edit Note - - + + Please select a Note to edit in the Notebook. - - + + Edit Note with External Editor Error - + External editor command is not configured in preferences (Editor tab). - - + + Edit Note with External Editor - + Running command: '%1' - + Running command: '%1'. Close external editor to return control back to MindForger. - + Delete Note - + Do you really want to delete note ' - + ' along with its child notes? - + Forget Note Delete Note - + Please select a Note to forget. Please select a Note to delete. - - - + + + Extract Note - + Please select a text to extract. - + Failed to extract new Note! - + Please select a Note, edit it and select a text to extract. - - - + + + Clone Note - + Do you want to clone Note ' - + ' including its child notes?'? - + Failed to clone Note! - + Please select a Note to be cloned. - + Moved Note '%1' to be the first child - - - - + + + + Move Note - - - - + + + + Please select a Note to be moved. - + Moved up Note '%1' - + Moved down Note '%1' - + Moved Note '%1' to be the last child - + Promoted Note '%1' - + Promote Note - + Please select a Note to be promoted. - + Demoted Note '%1' - + Demote Note - + Please select a Note to be demoted. - - - + + + Add Library Error - + Library directory doesn't exist! - - Library already indexed - use update action to reindex documents. - - - - - Unable to index documents on library path - either memory directory doesn't exist or not in MindForger repository mode. - - - - + Organizer Update Error - + Eisenhower Matrix organizer is built-in and cannot be edited - please create or update a custom organizer. - + Organizer Clone Error - + Eisenhower Matrix organizer is built-in and cannot be cloned - please create or update a custom organizer. - + Forget Organizer - + ' Organizer? - + Delete Organizer - + Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can. - - About MindForger + + View Limbo - - - m8r::MainWindowView - - Thinking Notebook + + Limbo directory with deleted Notebooks is available in the MindForger workspace, not if a Markdown is edited or a directory with markdowns is opened. - - - m8r::NerChooseTagTypesDialog - - Choose entity types to be extracted: + + Emojis - - persons - - - - - locations - - - - - organizations - - - - - other entities - - - - - &Choose - - - - - &Cancel - - - - - Choose Entity Type - - - - - m8r::NerLeaderboardModel - - - Name - - - - - Type - - - - - Score - - - - - person - - - - - location - - - - - organization - - - - - misc + + About MindForger - m8r::NerResultDialog - - - Recognized named entities: - - - - - &Find Entity in Notes - - - - - &Cancel - - + m8r::MainWindowView - - Find Named Entities + + Thinking Notebook @@ -3600,62 +3680,80 @@ m8r::NewRepositoryDialog - - Repository name: + + Workspace name: - - Repository directory: + + Workspace directory: - - Repository to be created in: + + Workspace to be created in: - + Find Directory - + include stencils - + include documentation - + &New - + &Cancel - - Create New Repository + + Create New Workspace - - - mindforger-repository + + + mindforger-workspace - + Choose Directory + + m8r::NoteEditDialog + + + General + + + + + Advanced + + + + + Edit Note + + + m8r::NoteEditDialog::AdvancedTab @@ -3763,27 +3861,37 @@ m8r::NoteEditorView - + + Add word to dictionary + + + + + Check spelling... + + + + Exit Editor - + Do you really want to exit editor without saving? - + Full-text Search Result - + No matching text found. - + No spelling suggestions found @@ -3791,17 +3899,17 @@ m8r::NoteNewDialog - + General - + Advanced - + New Note @@ -3809,12 +3917,12 @@ m8r::NoteNewDialog::AdvancedTab - + File - + Location @@ -3833,32 +3941,37 @@ - + Note - + + &Emojis + + + + Edit or view after creation - + Type - + Progress - + Stencil - + Position @@ -3879,11 +3992,98 @@ m8r::OrganizerNewDialog + + Name + + + + Organizer + + View as + + + + + Eisenhower Matrix + + + + + Kanban + + + + + Notebook scope + + + + + Notebook + + + + + Clear + + + + + &Create + + + + + Sort Notebooks by + + + + + importance + + + + + urgency + + + + + Filter by + + + + + notebooks + + + + + notes + + + + + notebooks and notes + + + + + &Cancel + + + + + Find Notebook as Scope + + + + New Organizer @@ -3930,7 +4130,7 @@ m8r::OrganizersTableModel - + Organizers @@ -3938,549 +4138,970 @@ m8r::OrlojPresenter - + Eisenhower Matrix: - + Kanban: - + Organizer: ' - + Selected Organizer not found! - - No Organizer selected! + + No Organizer selected! + + + + + + + Selected Notebook not found! + + + + + + + No Notebook selected! + + + + + Selected Tag not found! + + + + + + No Tag selected! + + + + + Note '%1' %2 + + + + + + Note + + + + + Selected Notebook/Note not found! + + + + + + No Note selected! + + + + + m8r::OutlineHeaderEditDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + Edit Notebook + + + + + m8r::OutlineHeaderEditDialog::AdvancedTab + + + Metadata + + + + + Created + + + + + Last Modified + + + + + Last Read + + + + + Reads + + + + + Writes + + + + + File + + + + + Location + + + + + m8r::OutlineHeaderEditDialog::GeneralTab + + + Basic + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + m8r::OutlineHeaderEditDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineHeaderEditPresenter + + + Notebook '%1' successfully saved + + + + + Attempt to save data from UI to Notebook, but no Notebook is set. + + + + + m8r::OutlineNewDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + New Notebook + + + + + m8r::OutlineNewDialog::AdvancedTab + + + Expected file name + + + + + Location + + + + + m8r::OutlineNewDialog::GeneralTab + + + Basic + + + + + Name + + + + + Notebook + + + + + &Emojis + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + Stencil + + + + + m8r::OutlineNewDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineTreeModel + + + Notebook Outline + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlineView + + + Click this Notebook name to open its Markdown preview in the right panel + + + + + m8r::OutlinesMapModel + + + Notebooks Tree + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlinesTableModel + + + Notebooks + + + + + Importance + + + + + Urgency + + + + + Done + + + + + Ns + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::RecentFilesMenu + + + Clear Menu + + + + + m8r::RecentNotesTableModel + + + Recent Notes + + + + + Notebook + + + + + Rs + + + + + Ws + + + + + Read + + + + + Modified + + + + + m8r::RefactorNoteToOutlineDialog + + + Refactor - - Selected Notebook not found! + + Move Note to Notebook + + + m8r::RemoveLibraryDialog - - - No Notebook selected! + + Choose a library to be removed - this action will delete +Notebooks which represent documents from the library +directory. +Referenced documents will NOT be deleted. + - - Selected Tag not found! + + Choose library to delete: - - - No Tag selected! + + &Delete - - Note '%1' %2 + + &Cancel - - - Note + + Delete Document Library + + + m8r::RowsAndDepthDialog - - Selected Notebook/Note not found! + + Specify number of rows and depth to generate - - - No Note selected! + + rows - - - m8r::OutlineHeaderEditDialog::AdvancedTab - - Metadata + + depth - - Created + + &Generate - - Last Modified + + &Cancel - - Last Read + + Format Generator - - Reads + + Bulleted List Generator - - Writes + + Numbered List Generator - - File + + Tasklist Generator - - Location + + Block Quote Generator - m8r::OutlineHeaderEditDialog::GeneralTab + m8r::RunToolDialog - - Basic + + Phrase: - - Type + + Knowledge source: - - Importance + + Template: - - Urgency + + &Lookup - - Progress + + Lookup Knowledge - - - m8r::OutlineHeaderEditDialog::PreambleTab - - Text + + arXiv - - Preamble + + Wikipedia - - - m8r::OutlineHeaderEditPresenter - - Notebook '%1' successfully saved + + GitHub Repositories - - Attempt to save data from UI to Notebook, but no Notebook is set. + + GitHub Code - - - m8r::OutlineNewDialog - - General + + DuckDuckGo - - Preamble + + Google - - Advanced + + StackOverflow - - New Notebook + + CPP reference - - - m8r::OutlineNewDialog::AdvancedTab - - Expected file name + + Python documentation - - Location + + &Cancel - m8r::OutlineNewDialog::GeneralTab + m8r::ScopeDialog - - Basic + + show Notebooks/Notes modified or viewed in recent - - Name + + year(s) - - Notebook + + month(s) - - Type + + day(s) - - Importance + + hour(s) - - Urgency + + minute(s) - - Progress + + show Notebooks with the following tags - - Stencil + + &Set - - - m8r::OutlineNewDialog::PreambleTab - - Text + + &Cancel - - Preamble + + Scope Mind - m8r::OutlineTreeModel + m8r::SyncLibraryDialog - - Outline + + Choose a library directory to be synchronized - new notebook +will be created for every new document found in the library. +Existing MindForger notebooks for library documents which were +deleted, renamed or moved (i.e. their link to library document +is broken) will not be deprecated to protect your document-related +notes. Feel free to deprecate such notebook(s) yourself. + - - Done + + Choose library to update: - - Rs + + &Update - - Ws + + &Cancel - - Modified + + Update Document Library - m8r::OutlineView + m8r::TagsTableModel - - Click this Notebook name to open its Markdown preview in the right panel + + Tags + + + + + Ts - m8r::OutlinesTableModel + m8r::TerminalDialog - - Notebooks + + Terminal - - Importance + + Terminal Command Error + + + m8r::ViewToEditEditButtonsPanel - - Urgency + + View Notebook Header - - Done + + View Notebook - - Ns + + Show preview of Notebook name and its description - - Rs + + &Edit - - Ws + + Full / Header Notebook Preview - - Modified + + Whole Notebook &Preview - - - m8r::RecentFilesMenu - - Clear Menu + + Show whole Notebook preview or Notebook header preview - m8r::RecentNotesTableModel + m8r::WingmanDialog - - Recent Notes + + Wingman Chat - - Notebook + + + Prompt: - - Rs + + Use 'clear' or 'cls' to clear the chat window. Use 'exit', 'quit' or 'bye' to close the dialog. - - Ws + + &Run Prompt - - Read + + C&opy - - Modified + + Copy last answer to the clipboard - - - m8r::RefactorNoteToOutlineDialog - - Refactor + + &Append - - Refactor Note to Notebook + + Append the last Wingman answer to the Note text after the cursor - - - m8r::RowsAndDepthDialog - - Bulleted List Generator + + &Replace - - Numbered List Generator + + Replace (selected) Note text with the last Wingman answer - - Tasklist Generator + + Show Predefined &Prompts - - Block Quote Generator + + + Show &Context - - - m8r::TagsTableModel - - Tags + + Close - - Ts + + Context - - - m8r::TerminalDialog - - Terminal Command Error + + Type: - - - m8r::ViewToEditEditButtonsPanel - - View Notebook Header + + Name (#NAME): - - View Notebook + + Text (#TEXT): - - Show preview of Notebook name and its description + + notebook - - &Edit + + <Notebook text> - - Full / Header Notebook Preview + + <Note text> - - Whole Notebook &Preview + + Show &Predefined Prompts - - Show whole Notebook preview or Notebook header preview + + Predefined prompts: + + + + + Write Your &Prompt + + + + + Hide &Context + + + + + note main - + MindForger CANNOT be run from text console - set DISPLAY environment variable or run MindForger from GUI. - - MindForger repository or directory/file with Markdown(s) to open + + MindForger workspace or directory/file with Markdown(s) to open - + Use 'dark', 'light' or other GUI <theme>. - + theme - + Load configuration from given <file>. - - + + file - + Disable WebEngine security to allow loading of images on macOS. - + Disable WebEngine security by running single process on macOS. - + Disable WebEngine security by disabling sandbox on macOS. - + Disable WebEngine security by user data dir specification on macOS. - + Disable WebEngine security via site isolation trials on macOS. - + Disable WebEngine security via acess file from file on macOS. - - Error: Unable to find given repository/file to open - open MindForger without parameters and create it from menu Mind/New: ' + + Error: Unable to find given workspace/file to open - open MindForger without parameters and create it from menu Mind/New: ' - + Ignoring unknown GUI theme: ' diff --git a/app/resources/qt/translations/mindforger_nerd_cs.ts b/app/resources/qt/translations/mindforger_nerd_cs.ts index 5fef71fc..9504fdee 100644 --- a/app/resources/qt/translations/mindforger_nerd_cs.ts +++ b/app/resources/qt/translations/mindforger_nerd_cs.ts @@ -4,56 +4,76 @@ QObject - + Save Note - + Do you want to save changes? - + Discard changes - + &Discard changes - - + + Autosave - + Do not ask & autosave - + Continue editing - + Continue &editing - + Save - + &Save + + + Empty Phrase + + + + + Phrase to search/explain/process is empty. + + + + + Wingman Not Available + + + + + Wingman provider is either not configured or initialized - see MindForger Preferences (Wingman tab). + + SpellChecker @@ -124,4363 +144,4928 @@ - m8r + m8r::AddLibraryDialog - - Notebook tags: + + Directory - - Notebooks: + + Choose a directory (library) of PDF files to be indexed. MindForger +will create new notebook for every library file. Such notebook can be +used to easily open the library file and create library file related +notes. + +Choose new library source: - - &Open Notebook + + Library source path: - - &Find Note + + index PDF - - - - - &Cancel + + &Create Library and Index Documents - - Find Notebook by Tags + + &Cancel - - - General + + Add Document Library - - - Advanced + + Choose Directory + + + m8r::AssocLeaderboardModel - - Edit Note + + + Associations - - Name + + + % - - Organizer + + for ' - - View as + + ' + + + m8r::AssocLeaderboardPresenter - - Eisenhower Matrix + + Associations + + + m8r::CliAndBreadcrumbsPresenter - - Kanban + + Wingman help - - Notebook scope + + <html>Use the following commands:<pre><br>? ... help<br>/ ... find<br>@ ... knowledge recherche<br>> ... run a command<br>&nbsp;&nbsp;... or full-text search phrase</pre><br>Examples:<pre><br>/ find notebook by tag TODO<br>@arxiv LLM<br>> emojis</pre> - - Notebook + + Wingman: ? for help, / search, @ knowledge, > command, or type FTS phrase - - Clear + + Notebook not found - please specify tag search phrase (is empty) - - &Create + + Notebook not found - please specify name search phrase (is empty) - - Sort Notebooks by + + Unknown knowledge recherche source - use valid source like @wikipedia - - importance + + No command! + + + m8r::CliAndBreadcrumbsView - - urgency + Run + Spustí příkaz + Spustit + + + + m8r::ConfigurationDialog + + + Application - - Filter by + + Viewer - - notebooks + + Editor - - notes + + Markdown - - notebooks and notes + + Navigator - - Find Notebook as Scope + + Mind - - New Organizer + + Wingman - - Preamble + + Adapt + + + m8r::ConfigurationDialog::AppTab - - Edit Notebook + + UI theme (<font color='#ff0000'>requires restart</font>) - - Specify number of rows and depth to generate + + Menu (<font color='#ff0000'>requires restart</font>) - - rows + + Show the following view on application start - - depth + + Application font size - 0 is system (<font color='#ff0000'>requires restart</font>) - - &Generate + + show toolbar - - Format Generator + + I don't need buttons - I know all keyboard shortcuts! - - show Notebooks/Notes modified or viewed in recent + + nerd terminology - - year(s) + + Appearance (<font color='#ff0000'>requires restart</font>) - - month(s) + + Controls - - day(s) + + Startup + + + m8r::ConfigurationDialog::EditorTab - - hour(s) + + Editor key binding - - minute(s) + + Editor font - - show Notebooks with the following tags + + Spell check dictionaries <a href='https://github.com/dvorka/mindforger/wiki/Installation#spell-check'>configuration documentation</a> - - &Set + + live spell check - - Scope Mind + + TABs as SPACEs - - New Notebook + + autosave Note on editor close - - Open a directory with Markdowns or MindForger repository + + TAB width - - Open Markdown file + + External editor command - - View Dashboard + + Editor + + + m8r::ConfigurationDialog::MarkdownTab - - View Eisenhower Matrix + + syntax highlighting - - View Eisenhower Matrices + + autocomplete text - - View Notebooks + + autocomplete lists, blocks and {([`_ characters - - View Knowledge Graph Navigator + + SPACE-based # in section escaping (HTML otherwise) - - View Tags + + Rendering - - View Recent Notes + + Autocompletion - - Add word to dictionary + + Escaping + + + m8r::ConfigurationDialog::MindTab - - Check spelling... + + save reads metadata - - - Hit ⌘↩ to add tag + + Async refresh interval (1 - 10.000ms) - - - Hit Ctrl+Enter to add tag + + Persistence - - Add Filter Tag + + Notifications + + + m8r::ConfigurationDialog::NavigatorTab - - Create New Tag + + Max graph nodes (150 by default) - - Remove Tag + + Knowledge Graph Navigator - m8r::AddLibraryDialog + m8r::ConfigurationDialog::ViewerTab - - Choose and find library source: + + HTML Viewer - - Directory + + Viewer theme CSS - - Library name: + + HTML zoom (100 is 100%, Ctrl + mouse wheel) - - Library source path: + + source code syntax highlighting support - - index PDF + + math support - - &Create Library and Index Documents + + whole notebook preview - - &Cancel + + double click HTML preview to edit - - Add Document Library + + Diagram support - - Choose Directory + + Find Custom CSS File - - - m8r::AssocLeaderboardModel - - - Associations + + HTML Viewer CSS + + + + + Choose CSS File + + + + + m8r::ConfigurationDialog::WingmanTab + + + LLM provider: + + + + + <html>Configure <a href='https://openai.com'>OpenAI</a> LLM provider: +<ul><li><a href='https://platform.openai.com/api-keys'>Generate</a> an OpenAI API key.</li><li>Set the API key:<br>a) either set the <b>%1</b> environment variable<br/>with the API key<br/>b) or paste the API key below to save it <font color='#ff0000'>unencrypted</font> to<br/><b>.mindforger.md</b> file in your home dir.</li><li><font color='#ff0000'>Restart</font> MindForger to apply the change.</li></ul> + + + + + Clear OpenAI API Key + + + + + OpenAI API Key Cleared + + + + + API key has been cleared from the configuration. Please close the configuration dialog with the OK button and restart MindForger to apply this change. + + + + + Data Privacy Warning + + + + + You have chosen OpenAI as your Wingman LLM provider. Therefore, your data will be sent to OpenAI servers for GPT processing when you use Wingman. + + + + + Large language model (LLM) providers + + + + + m8r::EditButtonsPanel + + + Preview + + + + + Properties + + + + + Remember + + + + + Remember and Leave + + + + + Cancel + + + + + m8r::EditNamePanel + + + Name: + + + + + m8r::EditTagsPanel + + + Tags + + + + + + Hit ⌘↩ to add tag + + + + + + Hit Ctrl+Enter to add tag + + + + + + + + Add Filter Tag + + + + + + + Create New Tag + + + + + Remove Tag + + + + + Add Existing Tag + + + + + Unknown Tag + + + + + m8r::ExportCsvFileDialog + + + Create New Markdown File + + + + + File name: + + + + + Target directory: + + + + + File to be created: + + + + + Find Directory + + + + + export OHE (one hot encoded) tags + + + + + Minimum tag cardinality to be OHE exported: + + + + + Export + + + + + &Cancel + + + + + + name + + + + + Choose Directory + + + + + m8r::FindNoteByNameDialog + + + Note &name: + + + + + &Open Note + + + + + Find Note by Name + + + + + m8r::FindNoteByTagDialog + + + Notes: + + + + + Note tags: + + + + + Find Notebook + + + + + &Open Note + + + + + Find Note by Tags + + + + + m8r::FindOutlineByNameDialog + + + &Notebook name: + + + + + &ignore case + + + + + &keywords match + + + + + &current Notebook's Notes only + + + + + &Open Notebook + + + + + Find Notebook by Name + + + + + &Cancel + + + + + m8r::FindOutlineByTagDialog + + + Notebook tags: + + + + + Notebooks: + + + + + &Open Notebook + + + + + &Find Note - - - % + + &Cancel - - for ' + + Find Notebook by Tags + + + m8r::FtsDialog - - ' + + Text to &find: + + + + + + Match: + + + + + &Exact + + + + + + &Ignore case + + + + + &Whole words + + + + + &Reverse + + + + + &Regular expression + + + + + &Open + + + + + &Search + Hledat + + + + &Cancel + + + + + Full-text Search - m8r::AssocLeaderboardPresenter + m8r::FtsDialogPresenter - - Associations + + Full-text Search Result + + + + + No matching Notebook or Note found. + + + + + No Notebook selected! - m8r::CliAndBreadcrumbsPresenter + m8r::InsertImageDialog - - Notebook + + Alternate text: - - Notebook not found: + + Image file path or web address (URL): - - No command! + + File + + + + + copy image to workspace + + + + + &Insert + + + + + &Cancel + + + + + Insert Image + + + + + Image + + + + + Choose File with Image - m8r::CliAndBreadcrumbsView + m8r::InsertLinkDialog - Run - Spustí příkaz - Spustit + + Link text: + + + + + Notebook, Note, file path or web address: + + + + + Note&book + + + + + &Note + + + + + &File + + + + + &Directory + + + + + copy link target to workspace + + + + + &Insert + + + + + &Cancel + + + + + Find Notebook as Link Target + + + + + Find Note as Link Target + + + + + Insert Link + + + + + link + + + + + Choose File + + + + + Choose Directory + - m8r::ConfigurationDialog + m8r::KanbanColumnPresenter - - Application + + Selected Notebook/Note not found! - - Viewer + + No Notebook selected! + + + m8r::MainMenuView + + + Mind Hack + Myšlenkový hook + - - Editor + + Mind hacking and debugging hook - - Markdown + + + + + &New + &Nový + + + + &Learn + Naučit + + + + Re&member - - Navigator + + &Recall + + + + + &Think + Mysli + + + &Sleep + Spi + + + + + &Forget + Zapomeň + + + + Limbo vs erase memory... + + + + + Adapt Mind by setting your preferences... - - Mind - + + E&xit + Konec - - Adapt + + Leave application - - - m8r::ConfigurationDialog::AppTab - - UI theme (<font color='#ff0000'>requires restart</font>) - + + &Mind + &Mysl - - Show the following view on application start + + &Full-text Search - - show toolbar + + Note full-text search - - I don't need buttons - I know all keyboard shortcuts! + + Recall &Note by Name - - nerd menu (requires restart) + + Find Note by name - - Startup + + Find Note by tags - - Appearance + &Home + Domů + + + + &Memory Dwell - - - m8r::ConfigurationDialog::EditorTab - - Editor key binding + + &Recent Notes - - Editor font + + &Stencils - - live spell check + + Don't show Notebooks and Notes older than... - - Spell check dictionaries <a href='https://github.com/dvorka/mindforger-repository/blob/master/memory/mindforger/installation.md#spell-check-'>configuration documentation</a> + + Create backup archive of the current workspace and store it in home directory - - TABs as SPACEs + + Find Notebook by name - - autosave Note on editor close + + Find Notebook by tags - - TAB width + + Recall Note by T&ags - - External editor command + + Flashcard &Decks - - Editor + + Show list of flashcard decks... - - - m8r::ConfigurationDialog::MarkdownTab - - syntax highlighting + + Organiz&ers - - autocomplete text + + Open Eisenhower matrix and Kanban organizers... - - autocomplete lists, blocks and {([`_ characters + + N&otebooks - - SPACE-based # in section escaping (HTML otherwise) + + &Library Documents - - Rendering + + List Library documents... - - Autocompletion + + &CLI - - Escaping + + Li&mbo - - - m8r::ConfigurationDialog::MindTab - - save reads metadata + + Ho&ist - - Async refresh interval (1 - 10.000ms) + + Toggle distraction free mode - - Persistence + + &Fullscreen - - Notifications + + &View - - - m8r::ConfigurationDialog::NavigatorTab - - Max graph nodes (150 by default) + + Str&etch edges - - Knowledge Graph Navigator + + &Sh&rink edge - - - m8r::ConfigurationDialog::ViewerTab - - HTML Viewer + + Flash&cards - - Viewer theme CSS + + &Organizer - - HTML zoom (100 is 100%, Ctrl + mouse wheel) + + Create new Organizer to prioritize your knowledge in Eisenhower Matrix style - - source code syntax highlighting support + + Edit current Organizer - you can also double click view to open the editor - - math support + + Make copy of the current Organizer - - whole notebook preview + + &Delete - - double click HTML preview to edit + + Delete Organizer without undo - - Diagram support + + + Move Notebook/Note to &Previous Column/Quadrant Ctrl+Left - - Find Custom CSS File + + Move Notebook/Note to previous column or quadrant... - - HTML Viewer CSS + + + Move Notebook/Note to Ne&xt Column/Quadrant Ctrl+Right - - Choose CSS File + + Move Notebook/Note to next column or quadrant... - - - m8r::DashboardPresenter - - Do first + + Note&book - - - m8r::EditButtonsPanel - - Preview + + E&xamine - - Properties + + Turn Notebook to deck of flashcard and start active recall testing... - - Remember + + E&xternal Editor Edit Ctrl+X - - Remember and Leave + + Edit current Note in an external editor - use Preferences to configure the editor - - Cancel + + &Forget Ctrl+D - - - m8r::EditNamePanel - - Name: + + Save and Leave Ctrl+L - - - m8r::EditTagsPanel - - Tags + + Move to F&irst Ctrl+Shift+Up - - - - Add Filter Tag + + Move the Note to be the first child of its parent - - - Create New Tag + + Move &Up Ctrl+Up - - Add Existing Tag + + Move the Note up - - Unknown Tag + + Move the Note down - - - m8r::ExportCsvFileDialog - - Create New Markdown File + + Move to &Last Ctrl+Shift+Down - - File name: + + Move the Note to be the last child of its parent - - Target directory: + + Move to Notebook Ctrl+R - - File to be created: + + &Move to Notebook - - Find Directory + + Move the current Note to another Notebook... - - export OHE (one hot encoded) tags + + &Find Ctrl+Shift+F - - Minimum tag cardinality to be OHE exported: + + &Undo Ctrl+Z - - Export + + Undo - - &Cancel + + &Redo Ctrl+Shift+Z - - - name + + Redo - - Choose Directory + + Cu&t Ctrl+X - - - m8r::FindNoteByNameDialog - - Note &name: + + Cut - - &Open Note + + &Copy Ctrl+C - - Find Note by Name + + Copy - - - m8r::FindNoteByTagDialog - - Notes: + + &Paste Ctrl+V - - Note tags: + + Paste - - Find Notebook + + Swap Nam&e/Description Focus - - &Open Note + + Run an external tool to find, explain, process text under the cursor - - Find Note by Tags + + Complete Link Ctrl+L - - - m8r::FindOutlineByNameDialog - - &Notebook name: + + Spell check Notebook or Note description - - &ignore case + + With&out tags - - &keywords match + + Insert Notebook's table of contents without tags - - &current Notebook's Notes only + + &With tags - - &Open Notebook + + Insert Notebook's table of contents with tags - - Find Notebook by Name + + Math cheatsheet - - &Cancel + + Open MathJax quick reference - - - m8r::FtsDialog - - Text to &find: + + Math live preview - - - Match: + + Open MathJax live demo - - &Exact + + Mermaid dia&grams documentation - - - &Ignore case + + Open Mermaid diagrams documentation - - &Whole words + + + + + &Edit - - &Reverse + + &Bold - - &Regular expression + + Format text as bold - - &Open + + &Italic - - &Search - Hledat + + Format text as italic + - - &Cancel + + &Code - - Full-text Search + + Format text as inlined source code - - - m8r::FtsDialogPresenter - - Full-text Search Result + + &Strikethrough - - No matching Notebook or Note found. + + Format text as strikethrough - - No Notebook selected! + + &Keyboard - - - m8r::InsertImageDialog - - Alternate text: + + Format text as keyboard input - - Image file path or web address (URL): + + Format block as bulleted list - - File + + Format block as numbered list - - copy image to repository + + + Format block as task list - - &Insert + + Format text block as source code - - &Cancel + + Block &Quote - - Insert Image + + Format text block as blockquote - - Image + + Timestam&p - - Choose File with Image + + &Link - - - m8r::InsertLinkDialog - - Link text: + + Insert link to a document, image or file - - Notebook, Note, file path or web address: + + Insert image - - Notebook + + Tabl&es - - Note + + &Horizontal ruler - - File + + Horizontal ruler - - Directory - + + &Format + &Formát - - copy link target to repository + + Create new Notebook to form new ideas, principles, combinations or applications - - &Insert + + Edit current Notebook - you can also double click view to open the editor - - &Cancel + + Import - - Find Notebook as Link Target + + + Copy the current Notebook as to Stencil - - Find Note as Link Target + + Make copy of the current Notebook - - Insert Link + + Forget Notebook and move it to Limbo - - link + + &Forget Del - - Choose File + + Forget Note - - Choose Directory + + Make a copy of the Note to this or other Notebook... - - - m8r::KanbanColumnPresenter - - Selected Notebook/Note not found! + + Make &Home - - No Notebook selected! + + + Markdown &File - - - m8r::MainMenuView - - Mind Hack - Myšlenkový hook + + Create a brand new Markdown file... + - - Mind hacking and debugging hook + + &Remind - - - - - &New - &Nový + + Persist all Things in Memory + - - Create a brand new MindForger repository... + + S&cope - - &Learn - Naučit + + Retain + - - Re&member + + Recall Note&book by Name - - &Recall + + Recall Library &Doc by Name - - &Think - Mysli + + Find Document by name + - &Sleep - Spi + + Open Home Notebook... + - - - &Forget - Zapomeň + + Show list of Notebooks... + - - Limbo vs erase memory... + + Note&books Tree - - Create backup archive of the current repository and store it in home directory + + Show tree of Notebooks... - - Adapt Mind by setting your preferences... + + &Tags - - E&xit - Konec + + Open Tag cloud... + - - Leave application + + Knowledge Graph &Navigator - - &Mind - &Mysl + + Open knowledge graph Navigator... + - - &Full-text Search + + Open memory dwell... - - Note full-text search + + View recently modified Notes... - - Recall &Note by Name + + List Notebook and Note stencils... - - Find Note by name + + List forgotten Notebooks and Notes... - - Recall Note by &Tags + + D&istraction Free - - Find Note by tags + + Toggle fullscreen - &Home - Domů + + &New library + - - &Memory Dwell + + Add path to the directory with documents (PDF, txt, HTML)... - - &CLI + + &Update library - - &Recent Notes + + Synchronize library source directory with MindForger notebook(s) which representlibrary resources... - - &Stencils + + &Delete library - - Don't show Notebooks and Notes older than... + + Delete all Notebooks representing the library resources... - - Run simple command line from current MindForger repository... + + Toggle tag indicating whether to use the current Notebook as home - - Find Notebook by name + + + Make &Stencil - - Find Notebook by tags + + C&lone - - Flashcard &Decks + + E&xport + E&xport + + + + &Import - - Show list of flashcard decks... + + Think to suggest matching, similar and associated Notes while searching, reading and writing - - Organiz&ers + + &Autolink - - Open Eisenhower matrix and Kanban organizers... + + Automatically inject links to relevant Notebooks and Notes when browsing HTML preview - - N&otebooks + + A&dapt - - &Library Documents + + &CSV - - List Library documents... + + Export all Notebooks/Markdown files as a single CSV file - - Li&mbo + + Recall Notebook by Ta&gs - - Toggle distraction free mode + + &Home Notebook - - &Fullscreen + + Activate command line interface... - - &View + + Str&etch edges e | mouse wheel - - &Know + + Stretch knowledge graph edges - - &Wikipedia + + &Sh&rink edge E | mouse wheel - - Find marked text on Wikipedia or open Wikipedia search + + Shring knowledge graph edges - - &arXiv + + Zoom &in z - - Find marked text on arXiv or get article by ID + + Zoom in knowledge graph - - Str&etch edges + + Zoom &out Z - - &Sh&rink edge + + Zoom out knowledge graph - - Na&vigate + + &Shuffle Space - - Libr&ary + + Shuffle knowledge graph - - &Add library + + &HTML - - Add directory with documents, URL or other resource to library... + + Export Notebook to a file in HTML format - - &Deprecate library + + &TWiki - - Move a library resource with documents to limbo... + + Import Notebook from an external TWiki file and restart MindForger - - Flash&cards + + Create new Note to form new ideas, principles, combinations and applications - - &Organizer + + Hoist/de-hoist Note to focus on Note being viewed or edited - - Create new Organizer to prioritize your knowledge in Eisenhower Matrix style + + &Edit Ctrl+E - - Edit current Organizer - you can also double click view to open the editor + + Edit current Note - you can also double click view to open the editor - - Make copy of the current Organizer + + Remember Ctrl+S - - &Delete + + Save Note being edited - - Delete Organizer without undo + + Leave Alt+Left - - - Move Notebook/Note to &Previous Column/Quadrant Ctrl+Left + + Save leave editor of Note being changed - - Move Notebook/Note to previous column or quadrant... + + &Promote Ctrl+Left - - - Move Notebook/Note to Ne&xt Column/Quadrant Ctrl+Right + + Promote Note - - Move Notebook/Note to next column or quadrant... + + &Demote Ctrl+Right - - Move focus to previous column or quandrant... + + Demote Note - - Move focus to next column or quandrant... + + &Live Preview - - Note&book + + Toggle live HTML preview - - E&xamine + + E&xtract - - Turn Notebook to deck of flashcard and start active recall testing... + + Create new Note from the text selected in the current Note... - - E&xternal Editor Edit Ctrl+X + + + &Clone - - Edit current Note in an external editor - use Preferences to configure the editor + + + &Workspace - - &Forget Ctrl+D + + Create a brand new MindForger workspace... - - Save and Leave Ctrl+L + + Learn knowledge by loading a MindForger workspace... - - &Find Ctrl+Shift+F + + &Directory with Markdowns - - &Undo Ctrl+Z + + Learn knowledge by loading a directory with Markdown files... - - Undo + + Learn knowledge by loading a Markdown file... - - &Redo Ctrl+Shift+Z + + Re-learn recently opened MindForger workspaces, Markdown directories or files - - Redo + + &Wingman - - Cu&t Ctrl+X + + Ter&minal - - Cut + + Run simple command line from current MindForger workspace... - - &Copy Ctrl+C + + Emo&jis - - Copy + + Open dialog with emoji characters to be copy/pasted to names, descriptions and text... - - &Paste Ctrl+V + + N&avigate - - Paste + + Li&brary - - Sp&ell Check + + &Edit ⌘↩ - - Spell check Notebook or Note description + + &Edit Alt-Enter - - Math cheatsheet + + Move Notebook/Note to Previous Column/Quadrant ⌘[ - - Open MathJax quick reference + + Move Notebook/Note to Next Column/Quadrant ⌘] - - Math live preview + + Focus to Previous Column/Quadrant ⇧⇥ - - Open MathJax live demo + + Focus to Next Column/Quadrant ⇥ - - Mermaid dia&grams documentation + + &Promote - - Open Mermaid diagrams documentation + + Promote Notebook - - - - - &Edit + + De&mote - - &Bold + + Demote Notebook - - Format text as bold + + Move to &First - - &Italic + + Move the Notebook to be the first child of its parent - - Format text as italic + + Move &Up - - &Code + + Move the Notebook up - - Format text as inlined source code + + Move the Notebook down - - &Strikethrough + + Move to &Last - - Format text as strikethrough + + Move the Notebook to be the last child of its parent - - &Keyboard + + Export Note to an external file in a supported format - - Format text as keyboard input + + Import Note from an external file in a supported format - - Format block as bulleted list + + &Note - - Format block as numbered list + + + + + &Wingman GPT - - - Format block as task list + + Open Wingman dialog... - - Format text block as source code + + &Find on Web - - Block &Quote + + Find Notebook or Note name; selected text or text under cursor on the web... - - Format text block as blockquote + + Move focus to previous column or quadrant... - - Timestam&p + + Move focus to next column or quadrant... - - &Link + + Move D&own - - Insert link to a document, image or file + + + &Summarize - - Insert image + + Ask Wingman to summarize text of the Notebook... - - Tabl&es + + + &Explain - - &Horizontal ruler + + Ask Wingman to explain the name of the Notebook... - - Horizontal ruler + + &Find Tasks - - &Format - &Formát + + Ask Wingman to find tasks in the Notebook text... + - - Create new Notebook to form new ideas, principles, combinations or applications + + + + &More prompts... - - Edit current Notebook - you can also double click view to open the editor + + + + Open Wingman chat... - - Import + + Move Dow&n Ctrl+Down - - - Copy the current Notebook as to Stencil + + Ask Wingman to summarize text of the Note... - - Make copy of the current Notebook + + &Find Grammar Errors - - Forget Notebook and move it to Limbo + + Ask Wingman to find grammar errors in the Note text... - - &Forget Del + + &Translate to English - - Forget Note + + Ask Wingman to translate the Note text to English... - - Refactor Note to another Notebook... + + Search Note text - - Make a copy of the Note to this or other Notebook... + + Find Next Ctrl+F - - Make &Home + + Search Note text again - - MindForger &Repository + + W&ord Wrap - - - Markdown &File + + Toggle word wrap mode - - Create a brand new Markdown file... + + Swap focus of N title and description editors - - &Directory with Markdowns or MindForger Repository + + Complete word being written by finding link to Notebook or Note - - Learn knowledge by loading a MindForger repository or a directory with Markdown files... + + &Spell Check - - Learn knowledge by loading a Markdown or MindForger file... + + &Fix Grammar - - &Remind + + Ask Wingman to fix grammar errors in the selected text / word under the cursor... - - Re-learn recently opened MindForger repositories, Markdown repositories or files + + Ask Wingman to explain the word under the cursor / selected text... - - Persist all Things in Memory + + Finish &Text - - S&cope + + Ask Wingman to finish the text following the selected text / word under the cursor... - - Retain + + &Rewrite Text - - Recall Note&book by Name + + Ask Wingman to rewrite the text following the selected text / word under the cursor... - - Recall Library &Doc by Name + + &Math - - Find Document by name + + Format text as math (MathJax) - - Recall &Persons + + Comment - - Find persons using Named-entity recognition (NER) + + Add comment to hide text in rendered HTML - - Recall &Locations + + Lis&ts - - Find locations using Named-entity recognition (NER) + + &Bulleted List - - Recall Organizations + + &Numbered List - - Find organizations using Named-entity recognition (NER) + + &Task List - - Recall Other Entities + + Task List &Item - - Find miscellaneous entities using Named-entity recognition (NER) + + Bl&ocks - - Dashboard + + &Code Block - - Open Home Notebook... + + &Math Block - - Show list of Notebooks... + + &Diagram Block - - &Tags + + Format code block as diagram (Mermaid) - - Open Tag cloud... + + Diagrams - - Knowledge Graph &Navigator + + &Flowchart - - Open knowledge graph Navigator... + + Insert flowchart Mermaid diagram skeleton - - Open memory dwell... + + &Sequence Diagram - - View recently modified Notes... + + Insert sequence Mermaid diagram skeleton - - List Notebook and Note stencils... + + &Class Diagram - - List forgotten Notebooks and Notes... + + Insert class Mermaid diagram skeleton - - Ho&isting + + St&ate Diagram - - D&istraction Free + + Insert state Mermaid diagram skeleton - - Toggle fullscreen + + &Gantt Diagram - - Toggle tag indicating whether to use the current Notebook as home + + Insert Gantt Mermaid diagram skeleton - - - Make &Stencil + + &Pie Diagram - - - C&lone + + Insert pie Mermaid chart skeleton - - E&xport - E&xport - - - - &Import + + MathJa&x - - Think to suggest matching, similar and associated Notes while searching, reading and writing + + &text - - &Autolink + + &fraction - - Automatically inject links to relevant Notebooks and Notes when browsing HTML preview + + &sum - - A&dapt + + s&quare root - - &CSV + + &integral - - Export all Notebooks/Markdown files as a single CSV file + + &alpha - - Recall Notebook by Ta&gs + + &beta - - Open Dashboard... + + &Gama - - &Home Notebook + + &Delta - - Activate command line interface... + + &bar - - Str&etch edges e | mouse wheel + + &hat - - Stretch knowledge graph edges + + &overrightarrow - - &Sh&rink edge E | mouse wheel + + &cup - - Shring knowledge graph edges + + &empty set - - Zoom &in z + + &not in - - Zoom in knowledge graph + + T&able of Contents - - Zoom &out Z + + Insert current date and time - - Zoom out knowledge graph + + About &Qt - - &Shuffle Space + + Format text block as math (MathJax) - - Shuffle knowledge graph + + in&tegrals - - &HTML + + dot - - Export Notebook to a file in HTML format + + ca&p - - &TWiki + + in - - Import Notebook from an external TWiki file and restart MindForger + + Ima&ge - - Create new Note to form new ideas, principles, combinations and applications + + Insert table... - - Hoist/de-hoist Note to focus on Note being viewed or edited + + &Documentation - - &Edit Ctrl+E + + Open MindForger documentation - - Edit current Note - you can also double click view to open the editor + + &Web - - Remember Ctrl+S + + Open MindForger web - - Save Note being edited + + &Markdown tutorial - - Leave Alt+Left + + Open Markdown tutorial - - Save leave editor of Note being changed + + Report &Bug or Request Feature - - &Promote Ctrl+Left + + Report bug or suggest an enhancement - - Promote Note + + &Check for Updates - - &Demote Ctrl+Right + + Check for MindForger updates - - Demote Note + + About Qt... - - F&irst Ctrl+Shift+Up + + &About MindForger - - Move Note to be the first child of its parent - + + About MindForger... + O aplikaci MindForger - - &Up Ctrl+Up + + &Help - - Move Note up + + F1 + + + m8r::MainToolbarView - - Do&wn Ctrl+Down + + Main Toolbar - - Move Note down + + New Notebook - - &Last Ctrl+Shift+Down + + Open directory with Markdowns or Workspace - - Move Note to be the last child of its parent + + Open Markdown file - - &Refactor + + View Eisenhower Matrices - - &Live Preview + + View Notebooks - - Toggle live HTML preview + + View Knowledge Graph Navigator - - &Word Wrap + + View Tags - - E&xtract + + View Recent Notes + + + m8r::MainWindowPresenter - - Create new Note from the text selected in the current Note... + + Cannot think - either Mind already dreaming or repository too big - - &Clone + + Cannot start sleeping - please wait until dreaming finishes and then try again - - Ter&minal + + Learn - - &Edit ⌘↩ + + Full-text Search - - &Edit Alt-Enter + + + + Note - - Move Notebook/Note to Previous Column/Quadrant ⌘[ + + + Note not found - - Move Notebook/Note to Next Column/Quadrant ⌘] + + Refactor Note - - Focus to Previous Column/Quadrant ⇧⇥ + + Note to be refactored not specified! - - Focus to Next Column/Quadrant ⇥ + + Find Note by Name - - Refactor Ctrl+R + + + New Note - - Export Note to an external file in a supported format + + Failed to create new Note! - - Import Note from an external file in a supported format + + Hyperlink %1 clicked... - - &Note + + Export Memory to CSV - - Search Note text + + Autolinked Notebooks and Notes - - Find Next Ctrl+F + + Link target not found for relative link %1 - - Search Note text again + + New Markdown File Error - - Toggle word wrap mode + + + + Specified file path already exists! - - &Swap Name/Description Focus + + Learn Markdown File - - Swap focus of N title and description editors + + Notebook Full-text Search - - Complete Link Ctrl+/ + + Note Full-text Search - - Complete word being written by finding link to Notebook or Note + + + + + Notebook - - &Math + + + Notebook not found - - Format text as math (MathJax) + + Refactored Note to Notebook ' - - Comment + + Target Notebook not found - - Add comment to hide text in rendered HTML + + Find Note by Name in Notebook - - Lis&ts + + Home Notebook not set - use menu 'Notebooks/Make Home' - - &Bulleted List + + File copied to workspace path '%1' - - &Numbered List + + Wingman is talking to the GPT provider... - - &Task List + + Wingman received an answer from the GPT provider - - Task List &Item + + Wingman failed to receive an answer from the GPT provider - - Bl&ocks + + + Wingman Action Error - - &Code Block + + Wingman's answer appended after selected text in the Note editor. - - &Math Block + + Unable to append after selected text with Wingman's answer in non-edit perspective. - - &Diagram Block + + No answer from Wingman to append after selected text - run a prompt. - - Format code block as diagram (Mermaid) + + Wingman's answer replaced selected text in Notebook header. - - Diagrams + + Unable to replace Notebook header text - no text selected. - - &Flowchart + + Wingman's answer replaced selected text in Note text. - - Insert flowchart Mermaid diagram skeleton + + Unable to replace Note text - no text selected. - - &Sequence Diagram + + Unable to replace selected text with Wingman's answer in non-edit perspective. - - Insert sequence Mermaid diagram skeleton + + No answer from Wingman to replace selected text - run a prompt. - - &Class Diagram + + Edit Notebook - - Insert class Mermaid diagram skeleton + + Please open an Notebook to edit. - - St&ate Diagram + + + Clone Notebook - - Insert state Mermaid diagram skeleton + + Failed to clone Notebook! - - &Gantt Diagram + + Please open and Notebook to be cloned. - - Insert Gantt Mermaid diagram skeleton + + Notebook '%1' successfully marked as home - - &Pie Diagram + + Make Notebook home - - Insert pie Mermaid chart skeleton + + Notebook can be marked as home only when viewed. - - MathJa&x + + Library already indexed - use 'Update library' action to synchronize documents. - - &text + + Unable to index documents on library path - either memory directory doesn't exist or not in MindForger workspace mode. - - &fraction + + Library synchronization - - &sum + + There are no libraries - nothing to synchronize. - - s&quare root + + Library deletion - - &integral + + There are no libraries - nothing to delete. - - integrals + + Delete Library - - &alpha + + Do you really want to delete Notebooks which represent the library documents? - - &beta + + Do you really want to forget ' - - &Gama + + ' Notebook? - - &Delta + + Notebook can be forgotten only when viewed. - - &bar + + Open and view a Notebook to create new Note. - - &hat + + Edit Note - - &dot + + + Please select a Note to edit in the Notebook. - - &overrightarrow + + Find Note by Tags in Notebook - - &cup + + Export Notebook to HTML - - &cap + + + Export - - &empty set + + Cannot think - either Mind already dreaming or workspace too big - - &in + + + New Workspace Error - - &not in + + Specified workspace path already exists! - - T&able of Contents + + Failed to create empty workspace! - - Insert Notebook's table of contents + + ERROR: workspace created, but attempt to copy documentation and/or stencils failed - - Insert current date and time + + Learn Directory or MindForger Workspace - - Format text block as math (MathJax) + + This is neither valid MindForger/Markdown workspace nor file. - - Ima&ge + + Thing not found - - Insert table... + + + Find Note by Tags - - &Documentation + + image - - Open MindForger documentation + + Given path '%1' doesn't exist - target will not be copied, but link will be created - - &Web + + Saving pasted image data to file: '%1' - - Open MindForger web + + Run Knowledge Tool Error - - &Markdown tutorial + + Unknown tool to run '%1'. - - Open Markdown tutorial + + Open Knowledge Tool Dialog Error - - Report &Bug or Request Feature + + Unable to construct URL to open for unknown tool '%1'. - - Report bug or suggest an enhancement + + HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu - - &Check for Updates + + Wingman's answer appended after selected text in the Notebook header. - - Check for MindForger updates + + Wingman's answer appended after the cursor in the Notebook header. - - &About Qt + + Wingman's answer appended after the cursor in the Note editor. - - About Qt... + + 🔒 Notebook Write Error - - &About MindForger + + Notebook file is read-only and cannot be written: +'%1' - - About MindForger... - O aplikaci MindForger + + Home tag toggled/removed - Notebook '%1' is no longer home + - - &Help + + + Forget Notebook - - F1 + + Do you really want to deprecate ' - - - m8r::MainToolbarView - - Main Toolbar + + + + Export Error - - - m8r::MainWindowPresenter - - - Cannot think - either Mind already dreaming or repository too big + + Unable to find Notebook to export! - - Cannot start sleeping - please wait until dreaming finishes and then try again + + Import TWiki File - - Learn + + + Edit Note with External Editor Error - - This is neither valid MindForger/Markdown repository nor file. + + External editor command is not configured in preferences (Editor tab). - - Full-text Search + + + Edit Note with External Editor - - - - Note + + Running command: '%1' - - - Note not found + + Running command: '%1'. Close external editor to return control back to MindForger. - - Refactor Note + + Delete Note - - Note to be refactored not specified! + + Do you really want to delete note ' - - Find Note by Name + + ' along with its child notes? - - - New Note + + Forget Note - - Failed to create new Note! + + Please select a Note to forget. - - Hyperlink %1 clicked... + + + + Extract Note - - Export Memory to CSV + + Please select a text to extract. - - Autolinked Notebooks and Notes + + Failed to extract new Note! - - Link target not found for relative link %1 + + Please select a Note, edit it and select a text to extract. - - - New Repository Error + + + + Clone Note - - Specified repository path already exists! + + Do you want to clone Note ' - - Failed to create empty repository! + + ' including its child notes?'? - - ERROR: repository created, but attempt to copy documentation and/or stencils failed + + Failed to clone Note! - - New Markdown File Error + + Please select a Note to be cloned. - - - - Specified file path already exists! + + Moved Note '%1' to be the first child - - Learn Directory or MindForger Repository + + + + + Move Note - - Learn Markdown File + + + + + Please select a Note to be moved. - - Notebook Full-text Search + + Moved up Note '%1' - - Note Full-text Search + + Moved down Note '%1' - - - - - Notebook + + Moved Note '%1' to be the last child - - - Notebook not found + + Promoted Note '%1' - - Refactored Note to Notebook ' + + Promote Note - - Target Notebook not found + + Please select a Note to be promoted. - - Find Note by Name in Notebook + + Demoted Note '%1' - - Edit Notebook + + Demote Note - - Please open an Notebook to edit. + + Please select a Note to be demoted. - - - Clone Notebook + + + + Add Library Error - - Failed to clone Notebook! + + Library directory doesn't exist! - - Please open and Notebook to be cloned. + + Organizer Update Error - - Notebook '%1' successfully marked as home + + Eisenhower Matrix organizer is built-in and cannot be edited - please create or update a custom organizer. - - Make Notebook home + + Organizer Clone Error - - Notebook can be marked as home only when viewed. + + Eisenhower Matrix organizer is built-in and cannot be cloned - please create or update a custom organizer. - - Do you really want to forget ' + + Forget Organizer - - ' Notebook? + + ' Organizer? - - Notebook can be forgotten only when viewed. + + Delete Organizer - - Open and view a Notebook to create new Note. + + Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can. - - Edit Note + + View Limbo - - - Please select a Note to edit in the Notebook. + + Limbo directory with deleted Notebooks is available in the MindForger workspace, not if a Markdown is edited or a directory with markdowns is opened. - - Find Note by Tags in Notebook + + Emojis - - Export Notebook to HTML + + About MindForger + + + m8r::MainWindowView - - - Export + + Thinking Notebook + + + m8r::NewFileDialog - - Thing not found + + Target directory: - - - Find Note by Tags + + File to be created: - - - - - Initializing NER and predicting... + + Find Directory - - - - - NER + + &Cancel - - - - - Memory NER not implemented yet. + + Create New Markdown File - - Recognizing named entities... + + File name: - - Initializing NER and recognizing named entities... + + New - - Initializing (the first run only) NER and predicting... + + + name - - - Named-entity Recognition + + Choose Directory + + + m8r::NewRepositoryDialog - - NER predicition finished + + Workspace name: - - No named entities recognized. + + Workspace directory: - - Home Notebook is not defined! + + Workspace to be created in: - - image + + Find Directory - - File copied to repository path '%1' + + include stencils - - Given path '%1' doesn't exist - target will not be copied, but link will be created + + include documentation - - Saving pasted image data to file: '%1' - + + &New + &Nový - - HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu + + &Cancel - - 🔒 Notebook Write Error + + Create New Workspace - - Notebook file is read-only and cannot be written: -'%1' + + + mindforger-workspace - - Home tag toggled/removed - Notebook '%1' is no longer home + + Choose Directory + + + m8r::NoteEditDialog - - - Forget Notebook + + General - - Do you really want to deprecate ' + + Advanced - - - - Export Error + + Edit Note + + + m8r::NoteEditDialog::AdvancedTab - - Unable to find Notebook to export! + + Metadata - - Import TWiki File + + Created - - - Edit Note with External Editor Error + + Last Modified - - External editor command is not configured in preferences (Editor tab). + + Last Read - - - Edit Note with External Editor + + Reads - - Running command: '%1' + + Writes - - Running command: '%1'. Close external editor to return control back to MindForger. + + File - - Delete Note + + Location + + + m8r::NoteEditDialog::GeneralTab - - Do you really want to delete note ' + + Basic - - ' along with its child notes? + + Type - - Forget Note + + Progress - - Please select a Note to forget. + + Deadline - - - - Extract Note + + Deadline format: mm/dd/yy - - Please select a text to extract. + + Parent-child Relationship - - Failed to extract new Note! + + Composition - - Please select a Note, edit it and select a text to extract. + + Aggregation - - - - Clone Note + + Is-a + + + m8r::NoteEditPresenter - - Do you want to clone Note ' + + Note '%1' successfully saved - - ' including its child notes?'? + + Attempt to save data from UI to Note, but no Note is set. + + + m8r::NoteEditorView - - Failed to clone Note! + + Add word to dictionary - - Please select a Note to be cloned. + + Check spelling... - - Moved Note '%1' to be the first child + + Exit Editor - - - - - Move Note + + Do you really want to exit editor without saving? - - - - - Please select a Note to be moved. + + Full-text Search Result - - Moved up Note '%1' + + No matching text found. - - Moved down Note '%1' + + No spelling suggestions found + + + m8r::NoteNewDialog - - Moved Note '%1' to be the last child + + General - - Promoted Note '%1' + + Advanced - - Promote Note + + New Note + + + m8r::NoteNewDialog::AdvancedTab - - Please select a Note to be promoted. + + File - - Demoted Note '%1' + + Location + + + m8r::NoteNewDialog::GeneralTab - - Demote Note + + Basic - - Please select a Note to be demoted. + + Name - - - - Add Library Error + + + Note - - Library directory doesn't exist! + + &Emojis - - Library already indexed - use update action to reindex documents. + + Edit or view after creation - - Unable to index documents on library path - either memory directory doesn't exist or not in MindForger repository mode. + + Type - - Organizer Update Error + + Progress - - Eisenhower Matrix organizer is built-in and cannot be edited - please create or update a custom organizer. + + Stencil - - Organizer Clone Error + + Position + + + m8r::NotesTableModel - - Eisenhower Matrix organizer is built-in and cannot be cloned - please create or update a custom organizer. + + Note - - Forget Organizer + + Notebook + + + m8r::OrganizerNewDialog - - ' Organizer? + + Name - - Delete Organizer + + + Organizer - - Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can. + + View as - - About MindForger + + Eisenhower Matrix - - - m8r::MainWindowView - - Thinking Notebook + + Kanban - - - m8r::NerChooseTagTypesDialog - - Choose entity types to be extracted: + + Notebook scope - - persons + + Notebook - - locations + + Clear - - organizations + + &Create - - other entities + + Sort Notebooks by - - &Choose + + importance - - &Cancel + + urgency - - Choose Entity Type + + Filter by - - - m8r::NerLeaderboardModel - - Name + + notebooks - - Type + + notes - - Score + + notebooks and notes - - person + + &Cancel - - location + + Find Notebook as Scope - - organization + + + New Organizer - - misc + + Create - - - m8r::NerResultDialog - - Recognized named entities: + + Update - - &Find Entity in Notes + + Edit Organizer - - &Cancel + + New Organizer Error - - Find Named Entities + + Organizer must have non-empty name. - m8r::NewFileDialog + m8r::OrganizerQuadrantPresenter - - Target directory: + + Selected Notebook/Note not found! - - File to be created: + + No Notebook selected! + + + m8r::OrganizersTableModel - - Find Directory + + Organizers + + + m8r::OrlojPresenter - - &Cancel + + Eisenhower Matrix: - - Create New Markdown File + + Kanban: - - File name: + + Organizer: ' - - New + + Selected Organizer not found! - - - name + + No Organizer selected! - - Choose Directory + + + + Selected Notebook not found! - - - m8r::NewRepositoryDialog - - Repository name: + + + + No Notebook selected! - - Repository directory: + + Selected Tag not found! - - Repository to be created in: + + + No Tag selected! - - Find Directory + + Note '%1' %2 - - include stencils + + + Note - - include documentation + + Selected Notebook/Note not found! - - &New - &Nový + + + No Note selected! + + + + m8r::OutlineHeaderEditDialog - - &Cancel + + General - - Create New Repository + + Preamble - - - mindforger-repository + + Advanced - - Choose Directory + + Edit Notebook - m8r::NoteEditDialog::AdvancedTab + m8r::OutlineHeaderEditDialog::AdvancedTab - + Metadata - + Created - + Last Modified - + Last Read - + Reads - + Writes - + File - + Location - m8r::NoteEditDialog::GeneralTab + m8r::OutlineHeaderEditDialog::GeneralTab - + Basic - + Type - + + Importance + + + + + Urgency + + + + Progress + + + m8r::OutlineHeaderEditDialog::PreambleTab - - Deadline + + Text - - Deadline format: mm/dd/yy + + Preamble + + + m8r::OutlineHeaderEditPresenter - - Parent-child Relationship + + Notebook '%1' successfully saved - - Composition + + Attempt to save data from UI to Notebook, but no Notebook is set. + + + m8r::OutlineNewDialog - - Aggregation + + General - - Is-a + + Preamble + + + + + Advanced + + + + + New Notebook - m8r::NoteEditPresenter + m8r::OutlineNewDialog::AdvancedTab - - Note '%1' successfully saved + + Expected file name - - Attempt to save data from UI to Note, but no Note is set. + + Location - m8r::NoteEditorView + m8r::OutlineNewDialog::GeneralTab - - Exit Editor + + Basic - - Do you really want to exit editor without saving? + + Name - - Full-text Search Result + + Notebook - - No matching text found. + + &Emojis - - No spelling suggestions found + + Type - - - m8r::NoteNewDialog - - General + + Importance - - Advanced + + Urgency - - New Note + + Progress + + + + + Stencil - m8r::NoteNewDialog::AdvancedTab + m8r::OutlineNewDialog::PreambleTab - - File + + Text - - Location + + Preamble - m8r::NoteNewDialog::GeneralTab + m8r::OutlineTreeModel - - Basic + + Notebook Outline - - Name + + Done - - - Note + + Rs - - Edit or view after creation + + Ws - - Type + + Modified + + + m8r::OutlineView - - Progress + + Click this Notebook name to open its Markdown preview in the right panel + + + m8r::OutlinesMapModel - - Stencil + + Notebooks Tree - - Position + + Done - - - m8r::NotesTableModel - - Note + + Rs - - Notebook + + Ws - - - m8r::OrganizerNewDialog - - Organizer + + Modified + + + m8r::OutlinesTableModel - - New Organizer + + Notebooks - - Create + + Importance - - Update + + Urgency - - Edit Organizer + + Done - - New Organizer Error + + Ns - - Organizer must have non-empty name. + + Rs - - - m8r::OrganizerQuadrantPresenter - - Selected Notebook/Note not found! + + Ws - - No Notebook selected! + + Modified - m8r::OrganizersTableModel + m8r::RecentFilesMenu - - Organizers + + Clear Menu - m8r::OrlojPresenter + m8r::RecentNotesTableModel - - Eisenhower Matrix: + + Recent Notes - - Kanban: + + Notebook - - Organizer: ' + + Rs - - Selected Organizer not found! + + Ws + + + + + Read - - No Organizer selected! + + Modified + + + + + m8r::RefactorNoteToOutlineDialog + + + Refactor - - Selected Notebook not found! + + Move Note to Notebook + + + m8r::RemoveLibraryDialog - - - No Notebook selected! + + Choose a library to be removed - this action will delete +Notebooks which represent documents from the library +directory. +Referenced documents will NOT be deleted. + - - Selected Tag not found! + + Choose library to delete: - - - No Tag selected! + + &Delete - - Note '%1' %2 + + &Cancel - - - Note + + Delete Document Library + + + m8r::RowsAndDepthDialog - - Selected Notebook/Note not found! + + Specify number of rows and depth to generate - - - No Note selected! + + rows - - - m8r::OutlineHeaderEditDialog::AdvancedTab - - Metadata + + depth - - Created + + &Generate - - Last Modified + + &Cancel - - Last Read + + Format Generator - - Reads + + Bulleted List Generator - - Writes + + Numbered List Generator - - File + + Tasklist Generator - - Location + + Block Quote Generator - m8r::OutlineHeaderEditDialog::GeneralTab + m8r::RunToolDialog - - Basic + + Phrase: - - Type + + Knowledge source: - - Importance + + Template: - - Urgency + + &Lookup - - Progress + + Lookup Knowledge - - - m8r::OutlineHeaderEditDialog::PreambleTab - - Text + + arXiv - - Preamble + + Wikipedia - - - m8r::OutlineHeaderEditPresenter - - Notebook '%1' successfully saved + + GitHub Repositories - - Attempt to save data from UI to Notebook, but no Notebook is set. + + GitHub Code - - - m8r::OutlineNewDialog - - General + + DuckDuckGo - - Preamble + + Google - - Advanced + + StackOverflow - - New Notebook + + CPP reference - - - m8r::OutlineNewDialog::AdvancedTab - - Expected file name + + Python documentation - - Location + + &Cancel - m8r::OutlineNewDialog::GeneralTab + m8r::ScopeDialog - - Basic + + show Notebooks/Notes modified or viewed in recent - - Name + + year(s) - - Notebook + + month(s) - - Type + + day(s) - - Importance + + hour(s) - - Urgency + + minute(s) - - Progress + + show Notebooks with the following tags - - Stencil + + &Set - - - m8r::OutlineNewDialog::PreambleTab - - Text + + &Cancel - - Preamble + + Scope Mind - m8r::OutlineTreeModel + m8r::SyncLibraryDialog - - Outline + + Choose a library directory to be synchronized - new notebook +will be created for every new document found in the library. +Existing MindForger notebooks for library documents which were +deleted, renamed or moved (i.e. their link to library document +is broken) will not be deprecated to protect your document-related +notes. Feel free to deprecate such notebook(s) yourself. + - - Done + + Choose library to update: - - Rs + + &Update - - Ws + + &Cancel - - Modified + + Update Document Library - m8r::OutlineView + m8r::TagsTableModel - - Click this Notebook name to open its Markdown preview in the right panel + + Tags + + + + + Ts - m8r::OutlinesTableModel + m8r::TerminalDialog - - Notebooks + + Terminal - - Importance + + Terminal Command Error + + + m8r::ViewToEditEditButtonsPanel - - Urgency + + View Notebook Header - - Done + + View Notebook - - Ns + + Show preview of Notebook name and its description - - Rs + + &Edit - - Ws + + Full / Header Notebook Preview - - Modified + + Whole Notebook &Preview - - - m8r::RecentFilesMenu - - Clear Menu + + Show whole Notebook preview or Notebook header preview - m8r::RecentNotesTableModel + m8r::WingmanDialog - - Recent Notes + + Wingman Chat - - Notebook + + + Prompt: - - Rs + + Use 'clear' or 'cls' to clear the chat window. Use 'exit', 'quit' or 'bye' to close the dialog. - - Ws + + &Run Prompt - - Read + + C&opy - - Modified + + Copy last answer to the clipboard - - - m8r::RefactorNoteToOutlineDialog - - Refactor + + &Append - - Refactor Note to Notebook + + Append the last Wingman answer to the Note text after the cursor - - - m8r::RowsAndDepthDialog - - Bulleted List Generator + + &Replace - - Numbered List Generator + + Replace (selected) Note text with the last Wingman answer - - Tasklist Generator + + Show Predefined &Prompts - - Block Quote Generator + + + Show &Context - - - m8r::TagsTableModel - - Tags + + Close - - Ts + + Context - - - m8r::TerminalDialog - - Terminal Command Error + + Type: - - - m8r::ViewToEditEditButtonsPanel - - View Notebook Header + + Name (#NAME): - - View Notebook + + Text (#TEXT): - - Show preview of Notebook name and its description + + notebook - - &Edit + + <Notebook text> - - Full / Header Notebook Preview + + <Note text> - - Whole Notebook &Preview + + Show &Predefined Prompts - - Show whole Notebook preview or Notebook header preview + + Predefined prompts: + + + + + Write Your &Prompt + + + + + Hide &Context + + + + + note main - + MindForger CANNOT be run from text console - set DISPLAY environment variable or run MindForger from GUI. - - MindForger repository or directory/file with Markdown(s) to open + + MindForger workspace or directory/file with Markdown(s) to open - + Use 'dark', 'light' or other GUI <theme>. - + theme - + Load configuration from given <file>. - - + + file - + Disable WebEngine security to allow loading of images on macOS. - + Disable WebEngine security by running single process on macOS. - + Disable WebEngine security by disabling sandbox on macOS. - + Disable WebEngine security by user data dir specification on macOS. - + Disable WebEngine security via site isolation trials on macOS. - + Disable WebEngine security via acess file from file on macOS. - - Error: Unable to find given repository/file to open - open MindForger without parameters and create it from menu Mind/New: ' + + Error: Unable to find given workspace/file to open - open MindForger without parameters and create it from menu Mind/New: ' - + Ignoring unknown GUI theme: ' diff --git a/app/resources/qt/translations/mindforger_nerd_en.ts b/app/resources/qt/translations/mindforger_nerd_en.ts index 306f273b..a3636fd8 100644 --- a/app/resources/qt/translations/mindforger_nerd_en.ts +++ b/app/resources/qt/translations/mindforger_nerd_en.ts @@ -4,56 +4,76 @@ QObject - + Save Note - + Do you want to save changes? - + Discard changes - + &Discard changes - - + + Autosave - + Do not ask & autosave - + Continue editing - + Continue &editing - + Save - + &Save + + + Empty Phrase + + + + + Phrase to search/explain/process is empty. + + + + + Wingman Not Available + + + + + Wingman provider is either not configured or initialized - see MindForger Preferences (Wingman tab). + + SpellChecker @@ -124,675 +144,441 @@ - m8r + m8r::AddLibraryDialog - - Notebook tags: + + Directory - - Notebooks: + + Choose a directory (library) of PDF files to be indexed. MindForger +will create new notebook for every library file. Such notebook can be +used to easily open the library file and create library file related +notes. + +Choose new library source: - - &Open Notebook + + Library source path: - - &Find Note + + index PDF - - - - - &Cancel + + &Create Library and Index Documents - - Find Notebook by Tags + + &Cancel - - - General + + Add Document Library - - - Advanced + + Choose Directory + + + m8r::AssocLeaderboardModel - - Edit Note + + + Associations - - Name + + + % - - Organizer + + for ' - - View as + + ' + + + m8r::AssocLeaderboardPresenter - - Eisenhower Matrix + + Associations + + + m8r::CliAndBreadcrumbsPresenter - - Kanban + + Wingman help - - Notebook scope + + <html>Use the following commands:<pre><br>? ... help<br>/ ... find<br>@ ... knowledge recherche<br>> ... run a command<br>&nbsp;&nbsp;... or full-text search phrase</pre><br>Examples:<pre><br>/ find notebook by tag TODO<br>@arxiv LLM<br>> emojis</pre> - - Notebook + + Wingman: ? for help, / search, @ knowledge, > command, or type FTS phrase - - Clear + + Notebook not found - please specify tag search phrase (is empty) - - &Create + + Notebook not found - please specify name search phrase (is empty) - - Sort Notebooks by + + Unknown knowledge recherche source - use valid source like @wikipedia - - importance + + No command! + + + m8r::ConfigurationDialog - - urgency + + Application - - Filter by + + Viewer - - notebooks + + Editor - - notes + + Markdown - - notebooks and notes + + Navigator - - Find Notebook as Scope + + Mind - - New Organizer + + Wingman - - Preamble + + Adapt + + + m8r::ConfigurationDialog::AppTab - - Edit Notebook + + UI theme (<font color='#ff0000'>requires restart</font>) - - Specify number of rows and depth to generate + + Menu (<font color='#ff0000'>requires restart</font>) - - rows + + Show the following view on application start - - depth + + Application font size - 0 is system (<font color='#ff0000'>requires restart</font>) - - &Generate + + show toolbar - - Format Generator + + I don't need buttons - I know all keyboard shortcuts! - - show Notebooks/Notes modified or viewed in recent + + nerd terminology - - year(s) + + Appearance (<font color='#ff0000'>requires restart</font>) - - month(s) + + Controls - - day(s) + + Startup + + + m8r::ConfigurationDialog::EditorTab - - hour(s) + + Editor key binding - - minute(s) + + Editor font - - show Notebooks with the following tags + + Spell check dictionaries <a href='https://github.com/dvorka/mindforger/wiki/Installation#spell-check'>configuration documentation</a> - - &Set + + live spell check - - Scope Mind + + TABs as SPACEs - - New Notebook + + autosave Note on editor close - - Open a directory with Markdowns or MindForger repository + + TAB width - - Open Markdown file + + External editor command - - View Dashboard + + Editor + + + m8r::ConfigurationDialog::MarkdownTab - - View Eisenhower Matrix + + syntax highlighting - - View Eisenhower Matrices + + autocomplete text - - View Notebooks + + autocomplete lists, blocks and {([`_ characters - - View Knowledge Graph Navigator + + SPACE-based # in section escaping (HTML otherwise) - - View Tags + + Rendering - - View Recent Notes + + Autocompletion - - Add word to dictionary + + Escaping + + + m8r::ConfigurationDialog::MindTab - - Check spelling... + + save reads metadata - - - Hit ⌘↩ to add tag + + Async refresh interval (1 - 10.000ms) - - - Hit Ctrl+Enter to add tag + + Persistence - - Add Filter Tag + + Notifications + + + m8r::ConfigurationDialog::NavigatorTab - - Create New Tag + + Max graph nodes (150 by default) - - Remove Tag + + Knowledge Graph Navigator - m8r::AddLibraryDialog + m8r::ConfigurationDialog::ViewerTab - - Choose and find library source: + + HTML Viewer - - Directory + + Viewer theme CSS - - Library name: + + HTML zoom (100 is 100%, Ctrl + mouse wheel) - - Library source path: + + source code syntax highlighting support - - index PDF + + math support - - &Create Library and Index Documents + + whole notebook preview - - &Cancel + + double click HTML preview to edit - - Add Document Library + + Diagram support - - Choose Directory + + Find Custom CSS File - - - m8r::AssocLeaderboardModel - - - Associations + + HTML Viewer CSS - - - % - - - - - for ' - - - - - ' - - - - - m8r::AssocLeaderboardPresenter - - - Associations - - - - - m8r::CliAndBreadcrumbsPresenter - - - Notebook - - - - - Notebook not found: - - - - - No command! - - - - - m8r::ConfigurationDialog - - - Application - - - - - Viewer - - - - - Editor - - - - - Markdown - - - - - Navigator - - - - - Mind - - - - - Adapt - - - - - m8r::ConfigurationDialog::AppTab - - - UI theme (<font color='#ff0000'>requires restart</font>) - - - - - Show the following view on application start - - - - - show toolbar - - - - - I don't need buttons - I know all keyboard shortcuts! - - - - - nerd menu (requires restart) - - - - - Startup - - - - - Appearance - - - - - m8r::ConfigurationDialog::EditorTab - - - Editor key binding - - - - - Editor font - - - - - live spell check - - - - - Spell check dictionaries <a href='https://github.com/dvorka/mindforger-repository/blob/master/memory/mindforger/installation.md#spell-check-'>configuration documentation</a> - - - - - TABs as SPACEs - - - - - autosave Note on editor close - - - - - TAB width - - - - - External editor command - - - - - Editor - - - - - m8r::ConfigurationDialog::MarkdownTab - - - syntax highlighting - - - - - autocomplete text - - - - - autocomplete lists, blocks and {([`_ characters - - - - - SPACE-based # in section escaping (HTML otherwise) - - - - - Rendering - - - - - Autocompletion - - - - - Escaping - - - - - m8r::ConfigurationDialog::MindTab - - - save reads metadata - - - - - Async refresh interval (1 - 10.000ms) - - - - - Persistence - - - - - Notifications - - - - - m8r::ConfigurationDialog::NavigatorTab - - - Max graph nodes (150 by default) - - - - - Knowledge Graph Navigator + + Choose CSS File - m8r::ConfigurationDialog::ViewerTab - - - HTML Viewer - - - - - Viewer theme CSS - - - - - HTML zoom (100 is 100%, Ctrl + mouse wheel) - - - - - source code syntax highlighting support - - + m8r::ConfigurationDialog::WingmanTab - - math support + + LLM provider: - - whole notebook preview + + <html>Configure <a href='https://openai.com'>OpenAI</a> LLM provider: +<ul><li><a href='https://platform.openai.com/api-keys'>Generate</a> an OpenAI API key.</li><li>Set the API key:<br>a) either set the <b>%1</b> environment variable<br/>with the API key<br/>b) or paste the API key below to save it <font color='#ff0000'>unencrypted</font> to<br/><b>.mindforger.md</b> file in your home dir.</li><li><font color='#ff0000'>Restart</font> MindForger to apply the change.</li></ul> - - double click HTML preview to edit + + Clear OpenAI API Key - - Diagram support + + OpenAI API Key Cleared - - Find Custom CSS File + + API key has been cleared from the configuration. Please close the configuration dialog with the OK button and restart MindForger to apply this change. - - HTML Viewer CSS + + Data Privacy Warning - - Choose CSS File + + You have chosen OpenAI as your Wingman LLM provider. Therefore, your data will be sent to OpenAI servers for GPT processing when you use Wingman. - - - m8r::DashboardPresenter - - Do first + + Large language model (LLM) providers @@ -840,6 +626,19 @@ + + + Hit ⌘↩ to add tag + + + + + + Hit Ctrl+Enter to add tag + + + + @@ -847,11 +646,17 @@ + Create New Tag + + + Remove Tag + + Add Existing Tag @@ -1007,21 +812,54 @@ - m8r::FtsDialog + m8r::FindOutlineByTagDialog - - Text to &find: + + Notebook tags: - - - Match: + + Notebooks: - - &Exact + + &Open Notebook + + + + + &Find Note + + + + + &Cancel + + + + + Find Notebook by Tags + + + + + m8r::FtsDialog + + + Text to &find: + + + + + + Match: + + + + + &Exact @@ -1103,7 +941,7 @@ - copy image to repository + copy image to workspace @@ -1127,7 +965,7 @@ - + Choose File with Image @@ -1146,27 +984,27 @@ - Notebook + Note&book - Note + &Note - File + &File - Directory + &Directory - copy link target to repository + copy link target to workspace @@ -1236,66 +1074,56 @@ - - - - + + + + &New - - Create a brand new MindForger repository... - - - - + &Learn - + Re&member - + &Recall - + &Think - - + + &Forget - + Limbo vs erase memory... - - Create backup archive of the current repository and store it in home directory - - - - + Adapt Mind by setting your preferences... - + E&xit - + Leave application @@ -1305,2230 +1133,2446 @@ &Mind - + &Full-text Search - + Note full-text search - + Recall &Note by Name - + Find Note by name - - Recall Note by &Tags - - - - + Find Note by tags - + &Memory Dwell - - &CLI - - - - + &Recent Notes - + &Stencils - + Don't show Notebooks and Notes older than... - - Run simple command line from current MindForger repository... + + Create backup archive of the current workspace and store it in home directory - + Find Notebook by name - + Find Notebook by tags - + + Recall Note by T&ags + + + + Flashcard &Decks - + Show list of flashcard decks... - + Organiz&ers - + Open Eisenhower matrix and Kanban organizers... - + N&otebooks - + &Library Documents - + List Library documents... - - Li&mbo - - - - - Toggle distraction free mode + + &CLI - - &Fullscreen + + Li&mbo - - &View + + Ho&ist - - &Know + + Toggle distraction free mode - - &Wikipedia + + &Fullscreen - - Find marked text on Wikipedia or open Wikipedia search + + &View - - &arXiv + + Str&etch edges - - Find marked text on arXiv or get article by ID + + &Sh&rink edge - - Str&etch edges + + Flash&cards - - &Sh&rink edge + + &Organizer - - Na&vigate + + Create new Organizer to prioritize your knowledge in Eisenhower Matrix style - - Libr&ary + + Edit current Organizer - you can also double click view to open the editor - - &Add library + + Make copy of the current Organizer - - Add directory with documents, URL or other resource to library... + + &Delete - - &Deprecate library + + Delete Organizer without undo - - Move a library resource with documents to limbo... + + + Move Notebook/Note to &Previous Column/Quadrant Ctrl+Left - - Flash&cards + + Move Notebook/Note to previous column or quadrant... - - &Organizer + + + Move Notebook/Note to Ne&xt Column/Quadrant Ctrl+Right - - Create new Organizer to prioritize your knowledge in Eisenhower Matrix style + + Move Notebook/Note to next column or quadrant... - - Edit current Organizer - you can also double click view to open the editor + + Note&book - - Make copy of the current Organizer + + E&xamine - - &Delete + + Turn Notebook to deck of flashcard and start active recall testing... - - Delete Organizer without undo + + E&xternal Editor Edit Ctrl+X - - - Move Notebook/Note to &Previous Column/Quadrant Ctrl+Left + + Edit current Note in an external editor - use Preferences to configure the editor - - Move Notebook/Note to previous column or quadrant... + + &Forget Ctrl+D - - - Move Notebook/Note to Ne&xt Column/Quadrant Ctrl+Right + + Save and Leave Ctrl+L - - Move Notebook/Note to next column or quadrant... + + Move to F&irst Ctrl+Shift+Up - - Move focus to previous column or quandrant... + + Move the Note to be the first child of its parent - - Move focus to next column or quandrant... + + Move &Up Ctrl+Up - - Note&book + + Move the Note up - - E&xamine + + Move the Note down - - Turn Notebook to deck of flashcard and start active recall testing... + + Move to &Last Ctrl+Shift+Down - - E&xternal Editor Edit Ctrl+X + + Move the Note to be the last child of its parent - - Edit current Note in an external editor - use Preferences to configure the editor + + Move to Notebook Ctrl+R - - &Forget Ctrl+D + + &Move to Notebook - - Save and Leave Ctrl+L + + Move the current Note to another Notebook... - + &Find Ctrl+Shift+F - + &Undo Ctrl+Z - + Undo - + &Redo Ctrl+Shift+Z - + Redo - + Cu&t Ctrl+X - + Cut - + &Copy Ctrl+C - + Copy - + &Paste Ctrl+V - + Paste - - Sp&ell Check + + Swap Nam&e/Description Focus + + + + + Run an external tool to find, explain, process text under the cursor + + + + + Complete Link Ctrl+L - + Spell check Notebook or Note description - + + With&out tags + + + + + Insert Notebook's table of contents without tags + + + + + &With tags + + + + + Insert Notebook's table of contents with tags + + + + Math cheatsheet - + Open MathJax quick reference - + Math live preview - + Open MathJax live demo - + Mermaid dia&grams documentation - + Open Mermaid diagrams documentation - - - - + + + + &Edit - + &Bold - + Format text as bold - + &Italic - + Format text as italic - + &Code - + Format text as inlined source code - + &Strikethrough - + Format text as strikethrough - + &Keyboard - + Format text as keyboard input - + Format block as bulleted list - + Format block as numbered list - - + + Format block as task list - + Format text block as source code - + Block &Quote - + Format text block as blockquote - + Timestam&p - + &Link - + Insert link to a document, image or file - + Insert image - + Tabl&es - + &Horizontal ruler - + Horizontal ruler - + &Format - + Create new Notebook to form new ideas, principles, combinations or applications - + Edit current Notebook - you can also double click view to open the editor - + Import - - + + Copy the current Notebook as to Stencil - + Make copy of the current Notebook - + Forget Notebook and move it to Limbo - + &Forget Del - + Forget Note - - Refactor Note to another Notebook... - - - - + Make a copy of the Note to this or other Notebook... - + Make &Home - - MindForger &Repository - - - - - + + Markdown &File - + Create a brand new Markdown file... - - &Directory with Markdowns or MindForger Repository - - - - - Learn knowledge by loading a MindForger repository or a directory with Markdown files... - - - - - Learn knowledge by loading a Markdown or MindForger file... - - - - + &Remind - - Re-learn recently opened MindForger repositories, Markdown repositories or files - - - - + Persist all Things in Memory - + S&cope - + Retain - + Recall Note&book by Name - + Recall Library &Doc by Name - + Find Document by name - - Recall &Persons + + Open Home Notebook... - - Find persons using Named-entity recognition (NER) + + Show list of Notebooks... - - Recall &Locations + + Note&books Tree - - Find locations using Named-entity recognition (NER) + + Show tree of Notebooks... - - Recall Organizations + + &Tags - - Find organizations using Named-entity recognition (NER) + + Open Tag cloud... - - Recall Other Entities + + Knowledge Graph &Navigator - - Find miscellaneous entities using Named-entity recognition (NER) + + Open knowledge graph Navigator... - - Dashboard + + Open memory dwell... - - Open Home Notebook... - - - - - Show list of Notebooks... - - - - - &Tags + + View recently modified Notes... - - Open Tag cloud... + + List Notebook and Note stencils... - - Knowledge Graph &Navigator + + List forgotten Notebooks and Notes... - - Open knowledge graph Navigator... + + D&istraction Free - - Open memory dwell... + + Toggle fullscreen - - View recently modified Notes... + + &New library - - List Notebook and Note stencils... + + Add path to the directory with documents (PDF, txt, HTML)... - - List forgotten Notebooks and Notes... + + &Update library - - Ho&isting + + Synchronize library source directory with MindForger notebook(s) which representlibrary resources... - - D&istraction Free + + &Delete library - - Toggle fullscreen + + Delete all Notebooks representing the library resources... - + Toggle tag indicating whether to use the current Notebook as home - - + + Make &Stencil - - + C&lone - + E&xport - + &Import - + Think to suggest matching, similar and associated Notes while searching, reading and writing - + &Autolink - + Automatically inject links to relevant Notebooks and Notes when browsing HTML preview - + A&dapt - + &CSV - + Export all Notebooks/Markdown files as a single CSV file - + Recall Notebook by Ta&gs - - Open Dashboard... - - - - + &Home Notebook - + Activate command line interface... - + Str&etch edges e | mouse wheel - + Stretch knowledge graph edges - + &Sh&rink edge E | mouse wheel - + Shring knowledge graph edges - + Zoom &in z - + Zoom in knowledge graph - + Zoom &out Z - + Zoom out knowledge graph - + &Shuffle Space - + Shuffle knowledge graph - + &HTML - + Export Notebook to a file in HTML format - + &TWiki - + Import Notebook from an external TWiki file and restart MindForger - + Create new Note to form new ideas, principles, combinations and applications - + Hoist/de-hoist Note to focus on Note being viewed or edited - + &Edit Ctrl+E - + Edit current Note - you can also double click view to open the editor - + Remember Ctrl+S - + Save Note being edited - + Leave Alt+Left - + Save leave editor of Note being changed - + &Promote Ctrl+Left - + Promote Note - + &Demote Ctrl+Right - + Demote Note - - F&irst Ctrl+Shift+Up + + &Live Preview - - Move Note to be the first child of its parent + + Toggle live HTML preview - - &Up Ctrl+Up + + E&xtract - - Move Note up + + Create new Note from the text selected in the current Note... - - Do&wn Ctrl+Down + + + &Clone - - Move Note down + + + &Workspace - - &Last Ctrl+Shift+Down + + Create a brand new MindForger workspace... - - Move Note to be the last child of its parent + + Learn knowledge by loading a MindForger workspace... - - &Refactor + + &Directory with Markdowns - - &Live Preview + + Learn knowledge by loading a directory with Markdown files... - - Toggle live HTML preview + + Learn knowledge by loading a Markdown file... - - &Word Wrap + + Re-learn recently opened MindForger workspaces, Markdown directories or files - - E&xtract + + &Wingman - - Create new Note from the text selected in the current Note... + + Ter&minal - - &Clone + + Run simple command line from current MindForger workspace... - - Ter&minal + + Emo&jis - - &Edit ⌘↩ + + Open dialog with emoji characters to be copy/pasted to names, descriptions and text... + N&avigate + + + + + Li&brary + + + + + &Edit ⌘↩ + + + + &Edit Alt-Enter - + Move Notebook/Note to Previous Column/Quadrant ⌘[ - + Move Notebook/Note to Next Column/Quadrant ⌘] - + Focus to Previous Column/Quadrant ⇧⇥ - + Focus to Next Column/Quadrant ⇥ - - Refactor Ctrl+R + + &Promote - - Export Note to an external file in a supported format + + Promote Notebook - - Import Note from an external file in a supported format + + De&mote - - &Note + + Demote Notebook - - Search Note text + + Move to &First - - Find Next Ctrl+F + + Move the Notebook to be the first child of its parent - - Search Note text again + + Move &Up - - Toggle word wrap mode + + Move the Notebook up - - &Swap Name/Description Focus + + Move the Notebook down - - Swap focus of N title and description editors + + Move to &Last - - Complete Link Ctrl+/ + + Move the Notebook to be the last child of its parent - - Complete word being written by finding link to Notebook or Note + + Export Note to an external file in a supported format - - &Math + + Import Note from an external file in a supported format - - Format text as math (MathJax) + + &Note - - Comment + + + + + &Wingman GPT - - Add comment to hide text in rendered HTML + + Open Wingman dialog... - - Lis&ts + + &Find on Web - - &Bulleted List + + Find Notebook or Note name; selected text or text under cursor on the web... - - &Numbered List + + Move focus to previous column or quadrant... - - &Task List + + Move focus to next column or quadrant... - - Task List &Item + + Move D&own - - Bl&ocks + + + &Summarize - - &Code Block + + Ask Wingman to summarize text of the Notebook... - - &Math Block + + + &Explain - - &Diagram Block + + Ask Wingman to explain the name of the Notebook... - - Format code block as diagram (Mermaid) + + &Find Tasks - - Diagrams + + Ask Wingman to find tasks in the Notebook text... - - &Flowchart + + + + &More prompts... - - Insert flowchart Mermaid diagram skeleton + + + + Open Wingman chat... - - &Sequence Diagram + + Move Dow&n Ctrl+Down - - Insert sequence Mermaid diagram skeleton + + Ask Wingman to summarize text of the Note... - - &Class Diagram + + &Find Grammar Errors - - Insert class Mermaid diagram skeleton + + Ask Wingman to find grammar errors in the Note text... - - St&ate Diagram + + &Translate to English - - Insert state Mermaid diagram skeleton + + Ask Wingman to translate the Note text to English... - - &Gantt Diagram + + Search Note text - - Insert Gantt Mermaid diagram skeleton + + Find Next Ctrl+F - - &Pie Diagram + + Search Note text again - - Insert pie Mermaid chart skeleton + + W&ord Wrap - - MathJa&x + + Toggle word wrap mode - - &text + + Swap focus of N title and description editors - - &fraction + + Complete word being written by finding link to Notebook or Note - - &sum + + &Spell Check - - s&quare root + + &Fix Grammar - - &integral + + Ask Wingman to fix grammar errors in the selected text / word under the cursor... - - integrals + + Ask Wingman to explain the word under the cursor / selected text... - - &alpha + + Finish &Text - - &beta + + Ask Wingman to finish the text following the selected text / word under the cursor... - - &Gama + + &Rewrite Text - - &Delta + + Ask Wingman to rewrite the text following the selected text / word under the cursor... - - &bar + + &Math - - &hat + + Format text as math (MathJax) - - &dot + + Comment - - &overrightarrow + + Add comment to hide text in rendered HTML - - &cup + + Lis&ts - - &cap + + &Bulleted List - - &empty set + + &Numbered List - - &in + + &Task List - - &not in + + Task List &Item - - T&able of Contents + + Bl&ocks - - Insert Notebook's table of contents + + &Code Block - - Insert current date and time + + &Math Block - - Format text block as math (MathJax) + + &Diagram Block - - Ima&ge + + Format code block as diagram (Mermaid) - - Insert table... + + Diagrams - &Documentation + &Flowchart - F1 + Insert flowchart Mermaid diagram skeleton - - Open MindForger documentation + + &Sequence Diagram - - &Web + + Insert sequence Mermaid diagram skeleton - - Open MindForger web + + &Class Diagram - - &Markdown tutorial + + Insert class Mermaid diagram skeleton - - Open Markdown tutorial + + St&ate Diagram - - Report &Bug or Request Feature + + Insert state Mermaid diagram skeleton - - Report bug or suggest an enhancement + + &Gantt Diagram - - &Check for Updates + + Insert Gantt Mermaid diagram skeleton - - Check for MindForger updates + + &Pie Diagram - - &About Qt + + Insert pie Mermaid chart skeleton - - About Qt... + + MathJa&x - - &About MindForger + + &text - About MindForger... + &fraction - &Help + &sum - - - m8r::MainToolbarView - - Main Toolbar + + s&quare root - - - m8r::MainWindowPresenter - - - Cannot think - either Mind already dreaming or repository too big + + &integral - - Cannot start sleeping - please wait until dreaming finishes and then try again + + &alpha - - Learn + + &beta - - This is neither valid MindForger/Markdown repository nor file. + + &Gama - - Full-text Search + + &Delta - - - - Note + + &bar - - - Note not found + + &hat - - Refactor Note + + &overrightarrow - - Note to be refactored not specified! + + &cup - - Find Note by Name + + &empty set - - - New Note + + &not in - - Failed to create new Note! + + T&able of Contents - - Hyperlink %1 clicked... + + Insert current date and time - - Export Memory to CSV + + About &Qt - - Autolinked Notebooks and Notes + + Format text block as math (MathJax) - - Link target not found for relative link %1 + + in&tegrals - - - New Repository Error + + dot - - Specified repository path already exists! + + ca&p - - Failed to create empty repository! + + in - - ERROR: repository created, but attempt to copy documentation and/or stencils failed + + Ima&ge - - New Markdown File Error + + Insert table... - - - - Specified file path already exists! + + &Documentation - - Learn Directory or MindForger Repository + + F1 - - Learn Markdown File + + Open MindForger documentation - - Notebook Full-text Search + + &Web - - Note Full-text Search + + Open MindForger web - - - - - Notebook + + &Markdown tutorial - - - Notebook not found + + Open Markdown tutorial - - Refactored Note to Notebook ' + + Report &Bug or Request Feature - - Target Notebook not found + + Report bug or suggest an enhancement - - Find Note by Name in Notebook + + &Check for Updates - - Edit Notebook + + Check for MindForger updates - - Please open an Notebook to edit. + + About Qt... - - - Clone Notebook + + &About MindForger - - Failed to clone Notebook! + + About MindForger... - - Please open and Notebook to be cloned. + + &Help + + + m8r::MainToolbarView - - Notebook '%1' successfully marked as home + + Main Toolbar - - Make Notebook home + + New Notebook - - Notebook can be marked as home only when viewed. + + Open directory with Markdowns or Workspace - - Do you really want to forget ' + + Open Markdown file - - ' Notebook? + + View Eisenhower Matrices - - Notebook can be forgotten only when viewed. + + View Notebooks - - Open and view a Notebook to create new Note. + + View Knowledge Graph Navigator - - Edit Note + + View Tags - - - Please select a Note to edit in the Notebook. + + View Recent Notes + + + m8r::MainWindowPresenter - - Find Note by Tags in Notebook + + Cannot think - either Mind already dreaming or repository too big - - Export Notebook to HTML + + Cannot start sleeping - please wait until dreaming finishes and then try again - - - Export + + Learn - - Thing not found + + Full-text Search - - - Find Note by Tags + + + + Note - - - - - Initializing NER and predicting... + + + Note not found - - - - - NER + + Refactor Note - - - - - Memory NER not implemented yet. + + Note to be refactored not specified! - - Recognizing named entities... + + Find Note by Name - - Initializing NER and recognizing named entities... + + + New Note - - Initializing (the first run only) NER and predicting... + + Failed to create new Note! - - - Named-entity Recognition + + Hyperlink %1 clicked... - - NER predicition finished + + Export Memory to CSV - - No named entities recognized. + + Autolinked Notebooks and Notes - - Home Notebook is not defined! + + Link target not found for relative link %1 - - image + + New Markdown File Error - - File copied to repository path '%1' + + + + Specified file path already exists! - - Given path '%1' doesn't exist - target will not be copied, but link will be created + + Learn Markdown File - - Saving pasted image data to file: '%1' + + Notebook Full-text Search - - HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu + + Note Full-text Search - - 🔒 Notebook Write Error + + + + + Notebook - - Notebook file is read-only and cannot be written: -'%1' + + + Notebook not found - - Home tag toggled/removed - Notebook '%1' is no longer home + + Refactored Note to Notebook ' - - - Forget Notebook + + Target Notebook not found - - Do you really want to deprecate ' + + Find Note by Name in Notebook - - - - Export Error + + Home Notebook not set - use menu 'Notebooks/Make Home' - - Unable to find Notebook to export! + + File copied to workspace path '%1' - - Import TWiki File + + Wingman is talking to the GPT provider... - - - Edit Note with External Editor Error + + Wingman received an answer from the GPT provider - - External editor command is not configured in preferences (Editor tab). + + Wingman failed to receive an answer from the GPT provider - - - Edit Note with External Editor + + + Wingman Action Error - - Running command: '%1' + + Wingman's answer appended after selected text in the Note editor. - - Running command: '%1'. Close external editor to return control back to MindForger. + + Unable to append after selected text with Wingman's answer in non-edit perspective. - - Delete Note + + No answer from Wingman to append after selected text - run a prompt. - - Do you really want to delete note ' + + Wingman's answer replaced selected text in Notebook header. - - ' along with its child notes? + + Unable to replace Notebook header text - no text selected. - - Forget Note + + Wingman's answer replaced selected text in Note text. - - Please select a Note to forget. + + Unable to replace Note text - no text selected. - - - - Extract Note + + Unable to replace selected text with Wingman's answer in non-edit perspective. - - Please select a text to extract. + + No answer from Wingman to replace selected text - run a prompt. - - Failed to extract new Note! + + Edit Notebook - - Please select a Note, edit it and select a text to extract. + + Please open an Notebook to edit. - - - - Clone Note + + + Clone Notebook - - Do you want to clone Note ' + + Failed to clone Notebook! - - ' including its child notes?'? + + Please open and Notebook to be cloned. - - Failed to clone Note! + + Notebook '%1' successfully marked as home - - Please select a Note to be cloned. + + Make Notebook home - - Moved Note '%1' to be the first child + + Notebook can be marked as home only when viewed. - - - - - Move Note + + Library already indexed - use 'Update library' action to synchronize documents. - - - - - Please select a Note to be moved. + + Unable to index documents on library path - either memory directory doesn't exist or not in MindForger workspace mode. - - Moved up Note '%1' + + Library synchronization - - Moved down Note '%1' + + There are no libraries - nothing to synchronize. - - Moved Note '%1' to be the last child + + Library deletion - - Promoted Note '%1' + + There are no libraries - nothing to delete. - - Promote Note + + Delete Library - - Please select a Note to be promoted. + + Do you really want to delete Notebooks which represent the library documents? - - Demoted Note '%1' + + Do you really want to forget ' - - Demote Note + + ' Notebook? - - Please select a Note to be demoted. + + Notebook can be forgotten only when viewed. - - - - Add Library Error + + Open and view a Notebook to create new Note. - - Library directory doesn't exist! + + Edit Note - - Library already indexed - use update action to reindex documents. + + + Please select a Note to edit in the Notebook. - - Unable to index documents on library path - either memory directory doesn't exist or not in MindForger repository mode. + + Find Note by Tags in Notebook - - Organizer Update Error + + Export Notebook to HTML - - Eisenhower Matrix organizer is built-in and cannot be edited - please create or update a custom organizer. + + + Export - - Organizer Clone Error + + Cannot think - either Mind already dreaming or workspace too big - - Eisenhower Matrix organizer is built-in and cannot be cloned - please create or update a custom organizer. + + + New Workspace Error - - Forget Organizer + + Specified workspace path already exists! - - ' Organizer? + + Failed to create empty workspace! - - Delete Organizer + + ERROR: workspace created, but attempt to copy documentation and/or stencils failed - - Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can. + + Learn Directory or MindForger Workspace - - About MindForger + + This is neither valid MindForger/Markdown workspace nor file. - - - m8r::MainWindowView - - Thinking Notebook + + Thing not found - - - m8r::NerChooseTagTypesDialog - - Choose entity types to be extracted: + + + Find Note by Tags - - persons + + image - - locations + + Given path '%1' doesn't exist - target will not be copied, but link will be created - - organizations + + Saving pasted image data to file: '%1' - - other entities + + Run Knowledge Tool Error - - &Choose + + Unknown tool to run '%1'. - - &Cancel + + Open Knowledge Tool Dialog Error - - Choose Entity Type + + Unable to construct URL to open for unknown tool '%1'. - - - m8r::NerLeaderboardModel - - Name + + HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu - - Type + + Wingman's answer appended after selected text in the Notebook header. - - Score + + Wingman's answer appended after the cursor in the Notebook header. - - person + + Wingman's answer appended after the cursor in the Note editor. - - location + + 🔒 Notebook Write Error - - organization + + Notebook file is read-only and cannot be written: +'%1' - - misc + + Home tag toggled/removed - Notebook '%1' is no longer home - - - m8r::NerResultDialog - - Recognized named entities: + + + Forget Notebook - - &Find Entity in Notes + + Do you really want to deprecate ' - - &Cancel + + + + Export Error + + + + + Unable to find Notebook to export! + + + + + Import TWiki File + + + + + + Edit Note with External Editor Error + + + + + External editor command is not configured in preferences (Editor tab). + + + + + + Edit Note with External Editor + + + + + Running command: '%1' + + + + + Running command: '%1'. Close external editor to return control back to MindForger. + + + + + Delete Note + + + + + Do you really want to delete note ' + + + + + ' along with its child notes? + + + + + Forget Note + + + + + Please select a Note to forget. + + + + + + + Extract Note + + + + + Please select a text to extract. + + + + + Failed to extract new Note! + + + + + Please select a Note, edit it and select a text to extract. + + + + + + + Clone Note + + + + + Do you want to clone Note ' + + + + + ' including its child notes?'? + + + + + Failed to clone Note! + + + + + Please select a Note to be cloned. + + + + + Moved Note '%1' to be the first child + + + + + + + + Move Note + + + + + + + + Please select a Note to be moved. + + + + + Moved up Note '%1' + + + + + Moved down Note '%1' + + + + + Moved Note '%1' to be the last child + + + + + Promoted Note '%1' + + + + + Promote Note + + + + + Please select a Note to be promoted. + + + + + Demoted Note '%1' + + + + + Demote Note + + + + + Please select a Note to be demoted. + + + + + + + Add Library Error + + + + + Library directory doesn't exist! + + + + + Organizer Update Error + + + + + Eisenhower Matrix organizer is built-in and cannot be edited - please create or update a custom organizer. + + + + + Organizer Clone Error + + + + + Eisenhower Matrix organizer is built-in and cannot be cloned - please create or update a custom organizer. + + + + + Forget Organizer + + + + + ' Organizer? + + + + + Delete Organizer + + + + + Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can. + + + + + View Limbo - - Find Named Entities + + Limbo directory with deleted Notebooks is available in the MindForger workspace, not if a Markdown is edited or a directory with markdowns is opened. + + + + + Emojis + + + + + About MindForger + + + + + m8r::MainWindowView + + + Thinking Notebook @@ -3584,62 +3628,80 @@ m8r::NewRepositoryDialog - - Repository name: + + Workspace name: - - Repository directory: + + Workspace directory: - - Repository to be created in: + + Workspace to be created in: - + Find Directory - + include stencils - + include documentation - + &New - + &Cancel - - Create New Repository + + Create New Workspace - - - mindforger-repository + + + mindforger-workspace - + Choose Directory + + m8r::NoteEditDialog + + + General + + + + + Advanced + + + + + Edit Note + + + m8r::NoteEditDialog::AdvancedTab @@ -3747,27 +3809,37 @@ m8r::NoteEditorView - + + Add word to dictionary + + + + + Check spelling... + + + + Exit Editor - + Do you really want to exit editor without saving? - + Full-text Search Result - + No matching text found. - + No spelling suggestions found @@ -3775,17 +3847,17 @@ m8r::NoteNewDialog - + General - + Advanced - + New Note @@ -3793,12 +3865,12 @@ m8r::NoteNewDialog::AdvancedTab - + File - + Location @@ -3817,32 +3889,37 @@ - + Note - + + &Emojis + + + + Edit or view after creation - + Type - + Progress - + Stencil - + Position @@ -3863,18 +3940,105 @@ m8r::OrganizerNewDialog + + Name + + + + Organizer - - New Organizer + + View as - - Create + + Eisenhower Matrix + + + + + Kanban + + + + + Notebook scope + + + + + Notebook + + + + + Clear + + + + + &Create + + + + + Sort Notebooks by + + + + + importance + + + + + urgency + + + + + Filter by + + + + + notebooks + + + + + notes + + + + + notebooks and notes + + + + + &Cancel + + + + + Find Notebook as Scope + + + + + + New Organizer + + + + + Create @@ -3914,7 +4078,7 @@ m8r::OrganizersTableModel - + Organizers @@ -3922,549 +4086,970 @@ m8r::OrlojPresenter - + Eisenhower Matrix: - + Kanban: - + Organizer: ' - + Selected Organizer not found! - - No Organizer selected! + + No Organizer selected! + + + + + + + Selected Notebook not found! + + + + + + + No Notebook selected! + + + + + Selected Tag not found! + + + + + + No Tag selected! + + + + + Note '%1' %2 + + + + + + Note + + + + + Selected Notebook/Note not found! + + + + + + No Note selected! + + + + + m8r::OutlineHeaderEditDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + Edit Notebook + + + + + m8r::OutlineHeaderEditDialog::AdvancedTab + + + Metadata + + + + + Created + + + + + Last Modified + + + + + Last Read + + + + + Reads + + + + + Writes + + + + + File + + + + + Location + + + + + m8r::OutlineHeaderEditDialog::GeneralTab + + + Basic + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + m8r::OutlineHeaderEditDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineHeaderEditPresenter + + + Notebook '%1' successfully saved + + + + + Attempt to save data from UI to Notebook, but no Notebook is set. + + + + + m8r::OutlineNewDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + New Notebook + + + + + m8r::OutlineNewDialog::AdvancedTab + + + Expected file name + + + + + Location + + + + + m8r::OutlineNewDialog::GeneralTab + + + Basic + + + + + Name + + + + + Notebook + + + + + &Emojis + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + Stencil + + + + + m8r::OutlineNewDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineTreeModel + + + Notebook Outline + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlineView + + + Click this Notebook name to open its Markdown preview in the right panel + + + + + m8r::OutlinesMapModel + + + Notebooks Tree + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlinesTableModel + + + Notebooks + + + + + Importance + + + + + Urgency + + + + + Done + + + + + Ns + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::RecentFilesMenu + + + Clear Menu + + + + + m8r::RecentNotesTableModel + + + Recent Notes + + + + + Notebook + + + + + Rs + + + + + Ws + + + + + Read + + + + + Modified + + + + + m8r::RefactorNoteToOutlineDialog + + + Refactor - - Selected Notebook not found! + + Move Note to Notebook + + + m8r::RemoveLibraryDialog - - - No Notebook selected! + + Choose a library to be removed - this action will delete +Notebooks which represent documents from the library +directory. +Referenced documents will NOT be deleted. + - - Selected Tag not found! + + Choose library to delete: - - - No Tag selected! + + &Delete - - Note '%1' %2 + + &Cancel - - - Note + + Delete Document Library + + + m8r::RowsAndDepthDialog - - Selected Notebook/Note not found! + + Specify number of rows and depth to generate - - - No Note selected! + + rows - - - m8r::OutlineHeaderEditDialog::AdvancedTab - - Metadata + + depth - - Created + + &Generate - - Last Modified + + &Cancel - - Last Read + + Format Generator - - Reads + + Bulleted List Generator - - Writes + + Numbered List Generator - - File + + Tasklist Generator - - Location + + Block Quote Generator - m8r::OutlineHeaderEditDialog::GeneralTab + m8r::RunToolDialog - - Basic + + Phrase: - - Type + + Knowledge source: - - Importance + + Template: - - Urgency + + &Lookup - - Progress + + Lookup Knowledge - - - m8r::OutlineHeaderEditDialog::PreambleTab - - Text + + arXiv - - Preamble + + Wikipedia - - - m8r::OutlineHeaderEditPresenter - - Notebook '%1' successfully saved + + GitHub Repositories - - Attempt to save data from UI to Notebook, but no Notebook is set. + + GitHub Code - - - m8r::OutlineNewDialog - - General + + DuckDuckGo - - Preamble + + Google - - Advanced + + StackOverflow - - New Notebook + + CPP reference - - - m8r::OutlineNewDialog::AdvancedTab - - Expected file name + + Python documentation - - Location + + &Cancel - m8r::OutlineNewDialog::GeneralTab + m8r::ScopeDialog - - Basic + + show Notebooks/Notes modified or viewed in recent - - Name + + year(s) - - Notebook + + month(s) - - Type + + day(s) - - Importance + + hour(s) - - Urgency + + minute(s) - - Progress + + show Notebooks with the following tags - - Stencil + + &Set - - - m8r::OutlineNewDialog::PreambleTab - - Text + + &Cancel - - Preamble + + Scope Mind - m8r::OutlineTreeModel + m8r::SyncLibraryDialog - - Outline + + Choose a library directory to be synchronized - new notebook +will be created for every new document found in the library. +Existing MindForger notebooks for library documents which were +deleted, renamed or moved (i.e. their link to library document +is broken) will not be deprecated to protect your document-related +notes. Feel free to deprecate such notebook(s) yourself. + - - Done + + Choose library to update: - - Rs + + &Update - - Ws + + &Cancel - - Modified + + Update Document Library - m8r::OutlineView + m8r::TagsTableModel - - Click this Notebook name to open its Markdown preview in the right panel + + Tags + + + + + Ts - m8r::OutlinesTableModel + m8r::TerminalDialog - - Notebooks + + Terminal - - Importance + + Terminal Command Error + + + m8r::ViewToEditEditButtonsPanel - - Urgency + + View Notebook Header - - Done + + View Notebook - - Ns + + Show preview of Notebook name and its description - - Rs + + &Edit - - Ws + + Full / Header Notebook Preview - - Modified + + Whole Notebook &Preview - - - m8r::RecentFilesMenu - - Clear Menu + + Show whole Notebook preview or Notebook header preview - m8r::RecentNotesTableModel + m8r::WingmanDialog - - Recent Notes + + Wingman Chat - - Notebook + + + Prompt: - - Rs + + Use 'clear' or 'cls' to clear the chat window. Use 'exit', 'quit' or 'bye' to close the dialog. - - Ws + + &Run Prompt - - Read + + C&opy - - Modified + + Copy last answer to the clipboard - - - m8r::RefactorNoteToOutlineDialog - - Refactor + + &Append - - Refactor Note to Notebook + + Append the last Wingman answer to the Note text after the cursor - - - m8r::RowsAndDepthDialog - - Bulleted List Generator + + &Replace - - Numbered List Generator + + Replace (selected) Note text with the last Wingman answer - - Tasklist Generator + + Show Predefined &Prompts - - Block Quote Generator + + + Show &Context - - - m8r::TagsTableModel - - Tags + + Close - - Ts + + Context - - - m8r::TerminalDialog - - Terminal Command Error + + Type: - - - m8r::ViewToEditEditButtonsPanel - - View Notebook Header + + Name (#NAME): - - View Notebook + + Text (#TEXT): - - Show preview of Notebook name and its description + + notebook - - &Edit + + <Notebook text> - - Full / Header Notebook Preview + + <Note text> - - Whole Notebook &Preview + + Show &Predefined Prompts - - Show whole Notebook preview or Notebook header preview + + Predefined prompts: + + + + + Write Your &Prompt + + + + + Hide &Context + + + + + note main - + MindForger CANNOT be run from text console - set DISPLAY environment variable or run MindForger from GUI. - - MindForger repository or directory/file with Markdown(s) to open + + MindForger workspace or directory/file with Markdown(s) to open - + Use 'dark', 'light' or other GUI <theme>. - + theme - + Load configuration from given <file>. - - + + file - + Disable WebEngine security to allow loading of images on macOS. - + Disable WebEngine security by running single process on macOS. - + Disable WebEngine security by disabling sandbox on macOS. - + Disable WebEngine security by user data dir specification on macOS. - + Disable WebEngine security via site isolation trials on macOS. - + Disable WebEngine security via acess file from file on macOS. - - Error: Unable to find given repository/file to open - open MindForger without parameters and create it from menu Mind/New: ' + + Error: Unable to find given workspace/file to open - open MindForger without parameters and create it from menu Mind/New: ' - + Ignoring unknown GUI theme: ' diff --git a/app/resources/qt/translations/mindforger_zh_cn.qm b/app/resources/qt/translations/mindforger_zh_cn.qm new file mode 100644 index 00000000..be8d9143 Binary files /dev/null and b/app/resources/qt/translations/mindforger_zh_cn.qm differ diff --git a/app/resources/qt/translations/mindforger_zh_cn.ts b/app/resources/qt/translations/mindforger_zh_cn.ts new file mode 100644 index 00000000..92ce3df1 --- /dev/null +++ b/app/resources/qt/translations/mindforger_zh_cn.ts @@ -0,0 +1,5109 @@ + + + + + QObject + + + Save Note + + + + + Do you want to save changes? + + + + + Discard changes + + + + + &Discard changes + + + + + + Autosave + + + + + Do not ask & autosave + + + + + Continue editing + + + + + Continue &editing + + + + + Save + + + + + &Save + + + + + Empty Phrase + + + + + Phrase to search/explain/process is empty. + + + + + Wingman Not Available + + + + + Wingman provider is either not configured or initialized - see MindForger Preferences (Wingman tab). + + + + + SpellChecker + + + Check Spelling + + + + + &Add + + + + + &Ignore + + + + + I&gnore All + + + + + &Change + + + + + C&hange All + + + + + Not in dictionary: + + + + + Change to: + + + + + Checking spelling... + + + + + Cancel + + + + + Please wait + + + + + Continue checking at beginning of file? + + + + + Spell check complete. + + + + + m8r::AddLibraryDialog + + + Directory + + + + + Choose a directory (library) of PDF files to be indexed. MindForger +will create new notebook for every library file. Such notebook can be +used to easily open the library file and create library file related +notes. + +Choose new library source: + + + + + Library source path: + + + + + index PDF + + + + + &Create Library and Index Documents + + + + + &Cancel + + + + + Add Document Library + + + + + Choose Directory + + + + + m8r::AssocLeaderboardModel + + + + Associations + + + + + + % + + + + + for ' + + + + + ' + + + + + m8r::AssocLeaderboardPresenter + + + Associations + + + + + m8r::CliAndBreadcrumbsPresenter + + + Wingman help + + + + + <html>Use the following commands:<pre><br>? ... help<br>/ ... find<br>@ ... knowledge recherche<br>> ... run a command<br>&nbsp;&nbsp;... or full-text search phrase</pre><br>Examples:<pre><br>/ find notebook by tag TODO<br>@arxiv LLM<br>> emojis</pre> + + + + + Wingman: ? for help, / search, @ knowledge, > command, or type FTS phrase + + + + + Notebook not found - please specify tag search phrase (is empty) + + + + + Notebook not found - please specify name search phrase (is empty) + + + + + Unknown knowledge recherche source - use valid source like @wikipedia + + + + + No command! + + + + + m8r::ConfigurationDialog + + + Application + + + + + Viewer + + + + + Editor + + + + + Markdown + + + + + Navigator + + + + + Mind + + + + + Wingman + + + + + Adapt + Preferences + Preferences + + + + m8r::ConfigurationDialog::AppTab + + + UI theme (<font color='#ff0000'>requires restart</font>) + + + + + Menu (<font color='#ff0000'>requires restart</font>) + + + + + Show the following view on application start + + + + + Application font size - 0 is system (<font color='#ff0000'>requires restart</font>) + + + + + show toolbar + + + + + I don't need buttons - I know all keyboard shortcuts! + + + + + nerd terminology + + + + + Appearance (<font color='#ff0000'>requires restart</font>) + + + + + Controls + + + + + Startup + + + + + m8r::ConfigurationDialog::EditorTab + + + Editor key binding + + + + + Editor font + + + + + Spell check dictionaries <a href='https://github.com/dvorka/mindforger/wiki/Installation#spell-check'>configuration documentation</a> + + + + + live spell check + + + + + TABs as SPACEs + + + + + autosave Note on editor close + + + + + TAB width + + + + + External editor command + + + + + Editor + + + + + m8r::ConfigurationDialog::MarkdownTab + + + syntax highlighting + + + + + autocomplete text + + + + + autocomplete lists, blocks and {([`_ characters + + + + + SPACE-based # in section escaping (HTML otherwise) + + + + + Rendering + + + + + Autocompletion + + + + + Escaping + + + + + m8r::ConfigurationDialog::MindTab + + + save reads metadata + + + + + Async refresh interval (1 - 10.000ms) + + + + + Persistence + + + + + Notifications + + + + + m8r::ConfigurationDialog::NavigatorTab + + + Max graph nodes (150 by default) + + + + + Knowledge Graph Navigator + + + + + m8r::ConfigurationDialog::ViewerTab + + + HTML Viewer + + + + + Viewer theme CSS + + + + + HTML zoom (100 is 100%, Ctrl + mouse wheel) + + + + + source code syntax highlighting support + + + + + math support + + + + + whole notebook preview + + + + + double click HTML preview to edit + + + + + Diagram support + + + + + Find Custom CSS File + + + + + HTML Viewer CSS + + + + + Choose CSS File + + + + + m8r::ConfigurationDialog::WingmanTab + + + LLM provider: + + + + + <html>Configure <a href='https://openai.com'>OpenAI</a> LLM provider: +<ul><li><a href='https://platform.openai.com/api-keys'>Generate</a> an OpenAI API key.</li><li>Set the API key:<br>a) either set the <b>%1</b> environment variable<br/>with the API key<br/>b) or paste the API key below to save it <font color='#ff0000'>unencrypted</font> to<br/><b>.mindforger.md</b> file in your home dir.</li><li><font color='#ff0000'>Restart</font> MindForger to apply the change.</li></ul> + + + + + Clear OpenAI API Key + + + + + OpenAI API Key Cleared + + + + + API key has been cleared from the configuration. Please close the configuration dialog with the OK button and restart MindForger to apply this change. + + + + + Data Privacy Warning + + + + + You have chosen OpenAI as your Wingman LLM provider. Therefore, your data will be sent to OpenAI servers for GPT processing when you use Wingman. + + + + + Large language model (LLM) providers + + + + + m8r::EditButtonsPanel + + + Preview + + + + + Properties + + + + + Remember + Save + + + + Remember and Leave + Save && Leave + + + + Cancel + + + + + m8r::EditNameAndButtonsPanel + + Remember + Save + + + + m8r::EditNamePanel + + + Name: + + + + + m8r::EditTagsPanel + + + Tags + + + + + + Hit ⌘↩ to add tag + + + + + + Hit Ctrl+Enter to add tag + + + + + + + + Add Filter Tag + + + + + + + Create New Tag + + + + + Remove Tag + + + + + Add Existing Tag + + + + + Unknown Tag + + + + + m8r::ExportCsvFileDialog + + + Create New Markdown File + + + + + File name: + + + + + Target directory: + + + + + File to be created: + + + + + Find Directory + + + + + export OHE (one hot encoded) tags + + + + + Minimum tag cardinality to be OHE exported: + + + + + Export + + + + + &Cancel + + + + + + name + + + + + Choose Directory + + + + + m8r::FindNoteByNameDialog + + + Note &name: + + + + + &Open Note + + + + + Find Note by Name + + + + + m8r::FindNoteByTagDialog + + + Notes: + + + + + Note tags: + + + + + Find Notebook + + + + + &Open Note + + + + + Find Note by Tags + + + + + m8r::FindOutlineByNameDialog + + + &Notebook name: + + + + + &ignore case + + + + + &keywords match + + + + + &current Notebook's Notes only + + + + + &Open Notebook + + + + + &Cancel + + + + + Find Notebook by Name + + + + + m8r::FindOutlineByTagDialog + + + Notebook tags: + + + + + Notebooks: + + + + + &Open Notebook + + + + + &Find Note + + + + + &Cancel + + + + + Find Notebook by Tags + + + + + m8r::FtsDialog + + + Text to &find: + + + + + + Match: + + + + + &Exact + + + + + + &Ignore case + + + + + &Whole words + + + + + &Reverse + + + + + &Regular expression + + + + + &Open + + + + + &Search + + + + + &Cancel + + + + + Full-text Search + + + + + m8r::FtsDialogPresenter + + + Full-text Search Result + + + + + No matching Notebook or Note found. + + + + + No Notebook selected! + + + + + m8r::InsertImageDialog + + + Alternate text: + + + + + Image file path or web address (URL): + + + + + File + + + + + copy image to workspace + + + + + &Insert + + + + + &Cancel + + + + + Insert Image + + + + + Image + + + + + Choose File with Image + + + + + m8r::InsertLinkDialog + + + Link text: + + + + + Notebook, Note, file path or web address: + + + + + Note&book + + + + + &Note + + + + + &File + + + + + &Directory + + + + + copy link target to workspace + + + + + &Insert + + + + + &Cancel + + + + + Find Notebook as Link Target + + + + + Find Note as Link Target + + + + + Insert Link + + + + + link + + + + + Choose File + + + + + Choose Directory + + + + + m8r::KanbanColumnPresenter + + + Selected Notebook/Note not found! + + + + + No Notebook selected! + + + + + m8r::MainMenuView + + + &Mind + Fi&le + + + + Mind Hack + + + + + Mind hacking and debugging hook + + + + + + Markdown &File + + + + + Create a brand new Markdown file... + + + + Learn knowledge by loading a MindForger repository or a directory with Markdown files... + Open MindForger repository or a directory with Markdown files... + + + Learn knowledge by loading a Markdown or MindForger file... + Open a Markdown or MindForger file... + + + + &Remind + &Recent + + + Re-learn recently opened MindForger repositories, Markdown repositories or files + Reopen recently opened MindForger repositories, Markdown repositories or files + + + + Re&member + &Save + + + + Persist all Things in Memory + + + + + &Think + + + + + S&cope + + + + + Don't show Notebooks and Notes older than... + + + + + + &Forget + &Deprecate + + + + Limbo vs erase memory... + + + + + Retain + Reta&in + + + &Adapt + &Preferences + + + + Adapt Mind by setting your preferences... + + + + + E&xit + + + + + Leave application + + + + + &Full-text Search + + + + + Note full-text search + + + + + Recall Note&book by Name + Find Note&book by Name + + + + Find Notebook by name + + + + + Recall &Note by Name + Find &Note by Name + + + + Find Note by name + + + + Recall Notebook by T&ags + Find Notebook by T&ags + + + + Find Notebook by tags + + + + Recall Note by &Tags + Find Note by &Tags + + + + Find Note by tags + + + + + Recall Library &Doc by Name + + + + + Find Document by name + + + + Recall &Persons + Find &Persons + + + Recall &Locations + Find &Locations + + + Recall Organizations + Find Organizations + + + Recall Other Entities + Find Other Entities + + + + &Recall + F&ind + + + + Open Home Notebook... + + + + + N&otebooks + + + + + Show list of Notebooks... + + + + + Note&books Tree + + + + + Show tree of Notebooks... + + + + + &Tags + + + + + Open Tag cloud... + + + + + Knowledge Graph &Navigator + + + + + Open knowledge graph Navigator... + + + + + &Memory Dwell + + + + + Open memory dwell... + + + + + Ter&minal + + + + + Run simple command line from current MindForger workspace... + + + + + &Recent Notes + + + + + View recently modified Notes... + + + + + &Stencils + + + + + List Notebook and Note stencils... + + + + + List forgotten Notebooks and Notes... + + + + + D&istraction Free + + + + + Toggle distraction free mode + + + + + &Fullscreen + + + + + Toggle fullscreen + + + + + &View + + + + + Str&etch edges e | mouse wheel + + + + + Stretch knowledge graph edges + + + + + &Sh&rink edge E | mouse wheel + + + + + Shring knowledge graph edges + + + + + Zoom &in z + + + + + Zoom in knowledge graph + + + + + Zoom &out Z + + + + + Zoom out knowledge graph + + + + + &Shuffle Space + + + + + Shuffle knowledge graph + + + + + N&avigate + + + + + &New library + + + + + Add path to the directory with documents (PDF, txt, HTML)... + + + + + &Update library + + + + + Synchronize library source directory with MindForger notebook(s) which representlibrary resources... + + + + + &Delete library + + + + + Delete all Notebooks representing the library resources... + + + + + &Edit ⌘↩ + + + + + &Edit Alt-Enter + + + + + Move Notebook/Note to Previous Column/Quadrant ⌘[ + + + + + Move Notebook/Note to Next Column/Quadrant ⌘] + + + + + Focus to Previous Column/Quadrant ⇧⇥ + + + + + Focus to Next Column/Quadrant ⇥ + + + + + &HTML + + + + + Export Notebook to a file in HTML format + + + + + &TWiki + + + + + Import Notebook from an external TWiki file and restart MindForger + + + + + Search Note text + + + + + Find Next Ctrl+F + + + + + Search Note text again + + + + + &Undo Ctrl+Z + + + + + Undo + + + + + &Redo Ctrl+Shift+Z + + + + + Redo + + + + + Cu&t Ctrl+X + + + + + Cut + + + + + &Copy Ctrl+C + + + + + Copy + + + + + &Paste Ctrl+V + + + + + Paste + + + + + + + + &Edit + + + + + Create backup archive of the current workspace and store it in home directory + + + + + Recall Note by T&ags + + + + + Flashcard &Decks + + + + + Show list of flashcard decks... + + + + + Organiz&ers + + + + + Open Eisenhower matrix and Kanban organizers... + + + + + &Library Documents + + + + + List Library documents... + + + + + &Wingman + + + + + Emo&jis + + + + + Open dialog with emoji characters to be copy/pasted to names, descriptions and text... + + + + + Li&mbo + + + + + &Find on Web + + + + + Find Notebook or Note name; selected text or text under cursor on the web... + + + + + Li&brary + + + + + &CLI + + + + + Ho&ist + + + + + Str&etch edges + + + + + &Sh&rink edge + + + + + Flash&cards + + + + + &Organizer + + + + + Create new Organizer to prioritize your knowledge in Eisenhower Matrix style + + + + + Edit current Organizer - you can also double click view to open the editor + + + + + Make copy of the current Organizer + + + + + &Delete + + + + + Delete Organizer without undo + + + + + + Move Notebook/Note to &Previous Column/Quadrant Ctrl+Left + + + + + Move Notebook/Note to previous column or quadrant... + + + + + + Move Notebook/Note to Ne&xt Column/Quadrant Ctrl+Right + + + + + Move Notebook/Note to next column or quadrant... + + + + + Note&book + + + + + E&xamine + + + + + Turn Notebook to deck of flashcard and start active recall testing... + + + + + &Promote + + + + + Promote Notebook + + + + + De&mote + + + + + Demote Notebook + + + + + Move to &First + + + + + Move the Notebook to be the first child of its parent + + + + + Move &Up + + + + + Move the Notebook up + + + + + Move the Notebook down + + + + + Move to &Last + + + + + Move the Notebook to be the last child of its parent + + + + + E&xternal Editor Edit Ctrl+X + + + + + Edit current Note in an external editor - use Preferences to configure the editor + + + + + &Forget Ctrl+D + + + + + Save and Leave Ctrl+L + + + + + Move to F&irst Ctrl+Shift+Up + + + + + Move the Note to be the first child of its parent + + + + + Move &Up Ctrl+Up + + + + + Move the Note up + + + + + Move the Note down + + + + + Move to &Last Ctrl+Shift+Down + + + + + Move the Note to be the last child of its parent + + + + + Move to Notebook Ctrl+R + + + + + &Move to Notebook + + + + + Move the current Note to another Notebook... + + + + + &Find Ctrl+Shift+F + + + + + &Live Preview + + + + + Toggle live HTML preview + + + + + Swap focus of N title and description editors + + + + + Run an external tool to find, explain, process text under the cursor + + + + + Complete Link Ctrl+L + + + + + Spell check Notebook or Note description + + + + + &Bold + + + + + Format text as bold + + + + + &Italic + + + + + Format text as italic + + + + + &Code + + + + + Format text as inlined source code + + + + + &Math + + + + + Format text as math (MathJax) + + + + + Comment + + + + + Add comment to hide text in rendered HTML + + + + + Lis&ts + + + + + &Bulleted List + + + + + &Numbered List + + + + + &Task List + + + + + Task List &Item + + + + + Bl&ocks + + + + + &Code Block + + + + + &Math Block + + + + + &Diagram Block + + + + + Format code block as diagram (Mermaid) + + + + + Diagrams + + + + + &Flowchart + + + + + Insert flowchart Mermaid diagram skeleton + + + + + &Sequence Diagram + + + + + Insert sequence Mermaid diagram skeleton + + + + + &Class Diagram + + + + + Insert class Mermaid diagram skeleton + + + + + St&ate Diagram + + + + + Insert state Mermaid diagram skeleton + + + + + &Gantt Diagram + + + + + Insert Gantt Mermaid diagram skeleton + + + + + &Pie Diagram + + + + + Insert pie Mermaid chart skeleton + + + + + in&tegrals + + + + + dot + + + + + ca&p + + + + + in + + + + + &Strikethrough + + + + + Format text as strikethrough + + + + + About &Qt + + + + + &Keyboard + + + + + Format text as keyboard input + + + + + Math cheatsheet + + + + + Open MathJax quick reference + + + + + Math live preview + + + + + Open MathJax live demo + + + + + Mermaid dia&grams documentation + + + + + Open Mermaid diagrams documentation + + + + + Format block as bulleted list + + + + + Format block as numbered list + + + + + + Format block as task list + + + + + T&able of Contents + + + + + Insert current date and time + + + + + Format text block as source code + + + + + Format text block as math (MathJax) + + + + + Block &Quote + + + + + Format text block as blockquote + + + + + &Link + + + + + Insert link to a document, image or file + + + + + Insert image + + + + + Tabl&es + + + + + &Horizontal ruler + + + + + Horizontal ruler + + + + + &Format + + + + + + + + &New + + + + + Create new Notebook to form new ideas, principles, combinations or applications + + + + + Edit current Notebook - you can also double click view to open the editor + + + + + Make &Home + + + + + Import + + + + + + Make &Stencil + + + + + + Copy the current Notebook as to Stencil + + + + + C&lone + + + + + Make copy of the current Notebook + + + + + Forget Notebook and move it to Limbo + Delete Notebook and move it Limbo + + + + E&xport + + + + + &Forget Del + Delete Del + + + + Forget Note + Delete Note + + + + &Learn + &Open + + + + Toggle tag indicating whether to use the current Notebook as home + + + + + &Import + + + + + Think to suggest matching, similar and associated Notes while searching, reading and writing + + + + + &Autolink + + + + + Automatically inject links to relevant Notebooks and Notes when browsing HTML preview + + + + + A&dapt + &Preferences + + + + &CSV + + + + + Export all Notebooks/Markdown files as a single CSV file + + + + + Recall Notebook by Ta&gs + Find Notebook by Ta&gs + + + + &Home Notebook + + + + + Activate command line interface... + + + + + Create new Note to form new ideas, principles, combinations and applications + + + + + Hoist/de-hoist Note to focus on Note being viewed or edited + + + + + &Edit Ctrl+E + + + + + Edit current Note - you can also double click view to open the editor + + + + + Remember Ctrl+S + Save Ctrl+S + + + + Save Note being edited + + + + + Leave Alt+Left + + + + + Save leave editor of Note being changed + + + + + &Promote Ctrl+Left + + + + + Promote Note + + + + + &Demote Ctrl+Right + + + + + Demote Note + + + + + E&xtract + + + + + Create new Note from the text selected in the current Note... + + + + + + &Clone + + + + + + &Workspace + + + + + Create a brand new MindForger workspace... + + + + + Learn knowledge by loading a MindForger workspace... + + + + + &Directory with Markdowns + + + + + Learn knowledge by loading a directory with Markdown files... + + + + + Learn knowledge by loading a Markdown file... + + + + + Re-learn recently opened MindForger workspaces, Markdown directories or files + + + + + Make a copy of the Note to this or other Notebook... + + + + + Export Note to an external file in a supported format + + + + + Import Note from an external file in a supported format + + + + + &Note + + + + + + + + &Wingman GPT + + + + + Open Wingman dialog... + + + + + Move focus to previous column or quadrant... + + + + + Move focus to next column or quadrant... + + + + + Move D&own + + + + + + &Summarize + + + + + Ask Wingman to summarize text of the Notebook... + + + + + + &Explain + + + + + Ask Wingman to explain the name of the Notebook... + + + + + &Find Tasks + + + + + Ask Wingman to find tasks in the Notebook text... + + + + + + + &More prompts... + + + + + + + Open Wingman chat... + + + + + Move Dow&n Ctrl+Down + + + + + Ask Wingman to summarize text of the Note... + + + + + &Find Grammar Errors + + + + + Ask Wingman to find grammar errors in the Note text... + + + + + &Translate to English + + + + + Ask Wingman to translate the Note text to English... + + + + + W&ord Wrap + + + + + Toggle word wrap mode + + + + + Swap Nam&e/Description Focus + + + + + Complete word being written by finding link to Notebook or Note + + + + + &Spell Check + + + + + &Fix Grammar + + + + + Ask Wingman to fix grammar errors in the selected text / word under the cursor... + + + + + Ask Wingman to explain the word under the cursor / selected text... + + + + + Finish &Text + + + + + Ask Wingman to finish the text following the selected text / word under the cursor... + + + + + &Rewrite Text + + + + + Ask Wingman to rewrite the text following the selected text / word under the cursor... + + + + + MathJa&x + + + + + &text + + + + + &fraction + + + + + &sum + + + + + s&quare root + + + + + &integral + + + + + &alpha + + + + + &beta + + + + + &Gama + + + + + &Delta + + + + + &bar + + + + + &hat + + + + + &overrightarrow + + + + + &cup + + + + + &empty set + + + + + &not in + + + + + With&out tags + + + + + Insert Notebook's table of contents without tags + + + + + &With tags + + + + + Insert Notebook's table of contents with tags + + + + + Timestam&p + + + + + Ima&ge + + + + + Insert table... + + + + + &Documentation + + + + + F1 + + + + + Open MindForger documentation + + + + + &Web + + + + + Open MindForger web + + + + + &Markdown tutorial + + + + + Open Markdown tutorial + + + + + Report &Bug or Request Feature + + + + + Report bug or suggest an enhancement + + + + + &Check for Updates + + + + + Check for MindForger updates + + + + + About Qt... + + + + + &About MindForger + + + + + About MindForger... + + + + + &Help + + + + + m8r::MainToolbarView + + + Main Toolbar + + + + + New Notebook + + + + + Open directory with Markdowns or Workspace + + + + + Open Markdown file + + + + + View Eisenhower Matrices + + + + + View Notebooks + + + + + View Knowledge Graph Navigator + + + + + View Tags + + + + + View Recent Notes + + + + + m8r::MainWindowPresenter + + + Cannot think - either Mind already dreaming or repository too big + + + + + Hyperlink %1 clicked... + + + + + Link target not found for relative link %1 + + + + + New Markdown File Error + + + + + + + Specified file path already exists! + + + + + Cannot start sleeping - please wait until dreaming finishes and then try again + + + + Learn Directory or MindForger Repository + Open Directory or MindForger Repository + + + + Learn Markdown File + Open Markdown File + + + + Learn + Open + + + + Export Notebook to HTML + + + + + + Export + + + + + Autolinked Notebooks and Notes + + + + + Notebook Full-text Search + + + + + Note Full-text Search + + + + + Full-text Search + + + + + + + + Notebook + + + + + + Notebook not found + + + + + Find Note by Tags in Notebook + + + + + + Find Note by Tags + + + + + + + Note + + + + + Export Memory to CSV + + + + + Thing not found + + + + + + Note not found + + + + + Refactored Note to Notebook ' + + + + + Target Notebook not found + + + + + Refactor Note + + + + + Note to be refactored not specified! + + + + + Find Note by Name in Notebook + + + + + Find Note by Name + + + + + image + + + + + Given path '%1' doesn't exist - target will not be copied, but link will be created + + + + + Saving pasted image data to file: '%1' + + + + + HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu + + + + + Wingman is talking to the GPT provider... + + + + + Wingman received an answer from the GPT provider + + + + + Wingman failed to receive an answer from the GPT provider + + + + + + Wingman Action Error + + + + + Wingman's answer appended after selected text in the Note editor. + + + + + Unable to append after selected text with Wingman's answer in non-edit perspective. + + + + + No answer from Wingman to append after selected text - run a prompt. + + + + + Wingman's answer replaced selected text in Notebook header. + + + + + Unable to replace Notebook header text - no text selected. + + + + + Wingman's answer replaced selected text in Note text. + + + + + Unable to replace Note text - no text selected. + + + + + Unable to replace selected text with Wingman's answer in non-edit perspective. + + + + + No answer from Wingman to replace selected text - run a prompt. + + + + + Edit Notebook + + + + + Please open an Notebook to edit. + + + + + + New Note + + + + + Failed to create new Note! + + + + + + Clone Notebook + + + + + Failed to clone Notebook! + + + + + Please open and Notebook to be cloned. + + + + + Home tag toggled/removed - Notebook '%1' is no longer home + + + + + Notebook '%1' successfully marked as home + + + + + Make Notebook home + + + + + Notebook can be marked as home only when viewed. + + + + + + Forget Notebook + Deprecate Notebook + + + + Library already indexed - use 'Update library' action to synchronize documents. + + + + + Unable to index documents on library path - either memory directory doesn't exist or not in MindForger workspace mode. + + + + + Library synchronization + + + + + There are no libraries - nothing to synchronize. + + + + + Library deletion + + + + + There are no libraries - nothing to delete. + + + + + Delete Library + + + + + Do you really want to delete Notebooks which represent the library documents? + + + + + Do you really want to forget ' + + + + + ' Notebook? + + + + + Cannot think - either Mind already dreaming or workspace too big + + + + + + New Workspace Error + + + + + Specified workspace path already exists! + + + + + Failed to create empty workspace! + + + + + ERROR: workspace created, but attempt to copy documentation and/or stencils failed + + + + + Learn Directory or MindForger Workspace + + + + + This is neither valid MindForger/Markdown workspace nor file. + + + + + Home Notebook not set - use menu 'Notebooks/Make Home' + + + + + File copied to workspace path '%1' + + + + + Run Knowledge Tool Error + + + + + Unknown tool to run '%1'. + + + + + Open Knowledge Tool Dialog Error + + + + + Unable to construct URL to open for unknown tool '%1'. + + + + + Wingman's answer appended after selected text in the Notebook header. + + + + + Wingman's answer appended after the cursor in the Notebook header. + + + + + Wingman's answer appended after the cursor in the Note editor. + + + + + 🔒 Notebook Write Error + + + + + Notebook file is read-only and cannot be written: +'%1' + + + + + Do you really want to deprecate ' + + + + + Notebook can be forgotten only when viewed. + + + + + + + Export Error + + + + + Unable to find Notebook to export! + + + + + Import TWiki File + + + + + Open and view a Notebook to create new Note. + + + + + Edit Note + + + + + + Please select a Note to edit in the Notebook. + + + + + + Edit Note with External Editor Error + + + + + External editor command is not configured in preferences (Editor tab). + + + + + + Edit Note with External Editor + + + + + Running command: '%1' + + + + + Running command: '%1'. Close external editor to return control back to MindForger. + + + + + Delete Note + + + + + Do you really want to delete note ' + + + + + ' along with its child notes? + + + + + Forget Note + Delete Note + + + + Please select a Note to forget. + Please select a Note to delete. + + + + + + Extract Note + + + + + Please select a text to extract. + + + + + Failed to extract new Note! + + + + + Please select a Note, edit it and select a text to extract. + + + + + + + Clone Note + + + + + Do you want to clone Note ' + + + + + ' including its child notes?'? + + + + + Failed to clone Note! + + + + + Please select a Note to be cloned. + + + + + Moved Note '%1' to be the first child + + + + + + + + Move Note + + + + + + + + Please select a Note to be moved. + + + + + Moved up Note '%1' + + + + + Moved down Note '%1' + + + + + Moved Note '%1' to be the last child + + + + + Promoted Note '%1' + + + + + Promote Note + + + + + Please select a Note to be promoted. + + + + + Demoted Note '%1' + + + + + Demote Note + + + + + Please select a Note to be demoted. + + + + + + + Add Library Error + + + + + Library directory doesn't exist! + + + + + Organizer Update Error + + + + + Eisenhower Matrix organizer is built-in and cannot be edited - please create or update a custom organizer. + + + + + Organizer Clone Error + + + + + Eisenhower Matrix organizer is built-in and cannot be cloned - please create or update a custom organizer. + + + + + Forget Organizer + + + + + ' Organizer? + + + + + Delete Organizer + + + + + Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can. + + + + + View Limbo + + + + + Limbo directory with deleted Notebooks is available in the MindForger workspace, not if a Markdown is edited or a directory with markdowns is opened. + + + + + Emojis + + + + + About MindForger + + + + + m8r::MainWindowView + + + Thinking Notebook + + + + + m8r::NewFileDialog + + + Target directory: + + + + + File to be created: + + + + + Find Directory + + + + + &Cancel + + + + + Create New Markdown File + + + + + File name: + + + + + New + + + + + + name + + + + + Choose Directory + + + + + m8r::NewRepositoryDialog + + + Workspace name: + + + + + Workspace directory: + + + + + Workspace to be created in: + + + + + Find Directory + + + + + include stencils + + + + + include documentation + + + + + &New + + + + + &Cancel + + + + + Create New Workspace + + + + + + mindforger-workspace + + + + + Choose Directory + + + + + m8r::NoteEditDialog + + + General + + + + + Advanced + + + + + Edit Note + + + + + m8r::NoteEditDialog::AdvancedTab + + + Metadata + + + + + Created + + + + + Last Modified + + + + + Last Read + + + + + Reads + + + + + Writes + + + + + File + + + + + Location + + + + + m8r::NoteEditDialog::GeneralTab + + + Basic + + + + + Type + + + + + Progress + + + + + Deadline + + + + + Deadline format: mm/dd/yy + + + + + Parent-child Relationship + + + + + Composition + + + + + Aggregation + + + + + Is-a + + + + + m8r::NoteEditPresenter + + + Note '%1' successfully saved + + + + + Attempt to save data from UI to Note, but no Note is set. + + + + + m8r::NoteEditorView + + + Add word to dictionary + + + + + Check spelling... + + + + + Exit Editor + + + + + Do you really want to exit editor without saving? + + + + + Full-text Search Result + + + + + No matching text found. + + + + + No spelling suggestions found + + + + + m8r::NoteNewDialog + + + General + + + + + Advanced + + + + + New Note + + + + + m8r::NoteNewDialog::AdvancedTab + + + File + + + + + Location + + + + + m8r::NoteNewDialog::GeneralTab + + + Basic + + + + + Name + + + + + + Note + + + + + &Emojis + + + + + Edit or view after creation + + + + + Type + + + + + Progress + + + + + Stencil + + + + + Position + + + + + m8r::NotesTableModel + + + Note + + + + + Notebook + + + + + m8r::OrganizerNewDialog + + + Name + + + + + + Organizer + + + + + View as + + + + + Eisenhower Matrix + + + + + Kanban + + + + + Notebook scope + + + + + Notebook + + + + + Clear + + + + + &Create + + + + + Sort Notebooks by + + + + + importance + + + + + urgency + + + + + Filter by + + + + + notebooks + + + + + notes + + + + + notebooks and notes + + + + + &Cancel + + + + + Find Notebook as Scope + + + + + + New Organizer + + + + + Create + + + + + Update + + + + + Edit Organizer + + + + + New Organizer Error + + + + + Organizer must have non-empty name. + + + + + m8r::OrganizerQuadrantPresenter + + + Selected Notebook/Note not found! + + + + + No Notebook selected! + + + + + m8r::OrganizersTableModel + + + Organizers + + + + + m8r::OrlojPresenter + + + Eisenhower Matrix: + + + + + Kanban: + + + + + Organizer: ' + + + + + Selected Organizer not found! + + + + + No Organizer selected! + + + + + + + Selected Notebook not found! + + + + + + + No Notebook selected! + + + + + Selected Tag not found! + + + + + + No Tag selected! + + + + + Note '%1' %2 + + + + + + Note + + + + + Selected Notebook/Note not found! + + + + + + No Note selected! + + + + + m8r::OutlineHeaderEditDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + Edit Notebook + + + + + m8r::OutlineHeaderEditDialog::AdvancedTab + + + Metadata + + + + + Created + + + + + Last Modified + + + + + Last Read + + + + + Reads + + + + + Writes + + + + + File + + + + + Location + + + + + m8r::OutlineHeaderEditDialog::GeneralTab + + + Basic + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + m8r::OutlineHeaderEditDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineHeaderEditPresenter + + + Notebook '%1' successfully saved + + + + + Attempt to save data from UI to Notebook, but no Notebook is set. + + + + + m8r::OutlineNewDialog + + + General + + + + + Preamble + + + + + Advanced + + + + + New Notebook + + + + + m8r::OutlineNewDialog::AdvancedTab + + + Expected file name + + + + + Location + + + + + m8r::OutlineNewDialog::GeneralTab + + + Basic + + + + + Name + + + + + Notebook + + + + + &Emojis + + + + + Type + + + + + Importance + + + + + Urgency + + + + + Progress + + + + + Stencil + + + + + m8r::OutlineNewDialog::PreambleTab + + + Text + + + + + Preamble + + + + + m8r::OutlineTreeModel + + + Notebook Outline + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlineView + + + Click this Notebook name to open its Markdown preview in the right panel + + + + + m8r::OutlinesMapModel + + + Notebooks Tree + + + + + Done + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::OutlinesTableModel + + + Notebooks + + + + + Importance + + + + + Urgency + + + + + Done + + + + + Ns + + + + + Rs + + + + + Ws + + + + + Modified + + + + + m8r::RecentFilesMenu + + + Clear Menu + + + + + m8r::RecentNotesTableModel + + + Recent Notes + + + + + Notebook + + + + + Rs + + + + + Ws + + + + + Read + + + + + Modified + + + + + m8r::RefactorNoteToOutlineDialog + + + Refactor + + + + + Move Note to Notebook + + + + + m8r::RemoveLibraryDialog + + + Choose a library to be removed - this action will delete +Notebooks which represent documents from the library +directory. +Referenced documents will NOT be deleted. + + + + + + Choose library to delete: + + + + + &Delete + + + + + &Cancel + + + + + Delete Document Library + + + + + m8r::RowsAndDepthDialog + + + Specify number of rows and depth to generate + + + + + rows + + + + + depth + + + + + &Generate + + + + + &Cancel + + + + + Format Generator + + + + + Bulleted List Generator + + + + + Numbered List Generator + + + + + Tasklist Generator + + + + + Block Quote Generator + + + + + m8r::RunToolDialog + + + Phrase: + + + + + Knowledge source: + + + + + Template: + + + + + &Lookup + + + + + Lookup Knowledge + + + + + arXiv + + + + + Wikipedia + + + + + GitHub Repositories + + + + + GitHub Code + + + + + DuckDuckGo + + + + + Google + + + + + StackOverflow + + + + + CPP reference + + + + + Python documentation + + + + + &Cancel + + + + + m8r::ScopeDialog + + + show Notebooks/Notes modified or viewed in recent + + + + + year(s) + + + + + month(s) + + + + + day(s) + + + + + hour(s) + + + + + minute(s) + + + + + show Notebooks with the following tags + + + + + &Set + + + + + &Cancel + + + + + Scope Mind + + + + + m8r::SyncLibraryDialog + + + Choose a library directory to be synchronized - new notebook +will be created for every new document found in the library. +Existing MindForger notebooks for library documents which were +deleted, renamed or moved (i.e. their link to library document +is broken) will not be deprecated to protect your document-related +notes. Feel free to deprecate such notebook(s) yourself. + + + + + + Choose library to update: + + + + + &Update + + + + + &Cancel + + + + + Update Document Library + + + + + m8r::TagsTableModel + + + Tags + + + + + Ts + + + + + m8r::TerminalDialog + + + Terminal + + + + + Terminal Command Error + + + + + m8r::ViewToEditEditButtonsPanel + + + View Notebook Header + + + + + View Notebook + + + + + Show preview of Notebook name and its description + + + + + &Edit + + + + + Full / Header Notebook Preview + + + + + Whole Notebook &Preview + + + + + Show whole Notebook preview or Notebook header preview + + + + + m8r::WingmanDialog + + + Wingman Chat + + + + + + Prompt: + + + + + Use 'clear' or 'cls' to clear the chat window. Use 'exit', 'quit' or 'bye' to close the dialog. + + + + + &Run Prompt + + + + + C&opy + + + + + Copy last answer to the clipboard + + + + + &Append + + + + + Append the last Wingman answer to the Note text after the cursor + + + + + &Replace + + + + + Replace (selected) Note text with the last Wingman answer + + + + + Show Predefined &Prompts + + + + + + Show &Context + + + + + Close + + + + + Context + + + + + Type: + + + + + Name (#NAME): + + + + + Text (#TEXT): + + + + + notebook + + + + + <Notebook text> + + + + + <Note text> + + + + + Show &Predefined Prompts + + + + + Predefined prompts: + + + + + Write Your &Prompt + + + + + Hide &Context + + + + + note + + + + + main + + + MindForger CANNOT be run from text console - set DISPLAY environment variable or run MindForger from GUI. + + + + + MindForger workspace or directory/file with Markdown(s) to open + + + + + Use 'dark', 'light' or other GUI <theme>. + + + + + theme + + + + + Load configuration from given <file>. + + + + + + file + + + + + Disable WebEngine security to allow loading of images on macOS. + + + + + Disable WebEngine security by running single process on macOS. + + + + + Disable WebEngine security by disabling sandbox on macOS. + + + + + Disable WebEngine security by user data dir specification on macOS. + + + + + Disable WebEngine security via site isolation trials on macOS. + + + + + Disable WebEngine security via acess file from file on macOS. + + + + + Error: Unable to find given workspace/file to open - open MindForger without parameters and create it from menu Mind/New: ' + + + + + Ignoring unknown GUI theme: ' + + + + diff --git a/app/src/qt/assoc_leaderboard_model.cpp b/app/src/qt/assoc_leaderboard_model.cpp index e1a47dfd..c2db3f10 100644 --- a/app/src/qt/assoc_leaderboard_model.cpp +++ b/app/src/qt/assoc_leaderboard_model.cpp @@ -1,7 +1,7 @@ /* assoc_leaderboard_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/assoc_leaderboard_model.h b/app/src/qt/assoc_leaderboard_model.h index b9392198..0599f5d7 100644 --- a/app/src/qt/assoc_leaderboard_model.h +++ b/app/src/qt/assoc_leaderboard_model.h @@ -1,7 +1,7 @@ /* assoc_leaderboard_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/assoc_leaderboard_presenter.cpp b/app/src/qt/assoc_leaderboard_presenter.cpp index d0e9d2e2..fc169ffe 100644 --- a/app/src/qt/assoc_leaderboard_presenter.cpp +++ b/app/src/qt/assoc_leaderboard_presenter.cpp @@ -1,7 +1,7 @@ /* assoc_leaderboard_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/assoc_leaderboard_presenter.h b/app/src/qt/assoc_leaderboard_presenter.h index 8bf9a13d..28110f53 100644 --- a/app/src/qt/assoc_leaderboard_presenter.h +++ b/app/src/qt/assoc_leaderboard_presenter.h @@ -1,7 +1,7 @@ /* assoc_leaderboard_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/assoc_leaderboard_view.cpp b/app/src/qt/assoc_leaderboard_view.cpp index ce4c58fd..800a3090 100644 --- a/app/src/qt/assoc_leaderboard_view.cpp +++ b/app/src/qt/assoc_leaderboard_view.cpp @@ -1,7 +1,7 @@ /* assoc_leaderboard_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/assoc_leaderboard_view.h b/app/src/qt/assoc_leaderboard_view.h index 6194e3c6..300f1673 100644 --- a/app/src/qt/assoc_leaderboard_view.h +++ b/app/src/qt/assoc_leaderboard_view.h @@ -1,7 +1,7 @@ /* assoc_leaderboard_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/cli_n_breadcrumbs_presenter.cpp b/app/src/qt/cli_n_breadcrumbs_presenter.cpp index e1132028..b1a417cb 100644 --- a/app/src/qt/cli_n_breadcrumbs_presenter.cpp +++ b/app/src/qt/cli_n_breadcrumbs_presenter.cpp @@ -1,7 +1,7 @@ /* cli_n_breadcrumbs_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -31,7 +31,7 @@ CliAndBreadcrumbsPresenter::CliAndBreadcrumbsPresenter( // widgets view->setVisible(Configuration::getInstance().isUiShowBreadcrump()); - // wire signals + // wire signals (view events to presenter handlers) QObject::connect( view->cli, SIGNAL(returnPressed()), this, SLOT(executeCommand())); @@ -40,16 +40,71 @@ CliAndBreadcrumbsPresenter::CliAndBreadcrumbsPresenter( this, SLOT(handleCliTextChanged(QString))); } + void CliAndBreadcrumbsPresenter::handleCliTextChanged(const QString& text) { // IMPROVE remove parameter text if it's not needed UNUSED_ARG(text); + // TODO use status bar + QString command = view->getCommand(); + MF_DEBUG("CLI text changed to: '" << command.toStdString() << "'" << endl); if(command.size()) { - if(command.startsWith(CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME)) { - QString prefix(QString::fromStdString( - command.toStdString().substr(CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME.size()-1))); + MF_DEBUG(" handling:" << endl); + if(command.startsWith(CliAndBreadcrumbsView::CHAR_HELP)) { + MF_DEBUG(" HELP" << endl); + QMessageBox::information( + &mainPresenter->getView(), + tr("Wingman help"), + tr( + // IMPROVE consider prefix,
separator and colors/bold + "" + "Use the following commands:" + "
"
+                    "
? ... help" + "
/ ... find" + "
@ ... knowledge recherche" + "
> ... run a command" + //"
: ... chat with workspace, Notebook or Note" + "
  ... or full-text search phrase" + "
" + "
Examples:" + "
"
+                    "
/ find notebook by tag TODO" + "
@arxiv LLM" + "
> emojis" + //"
: explain in simple terms SELECTED" + "
" + ) + ); + view->setCommand(""); + mainPresenter->getStatusBar()->showInfo( + tr("Wingman: ? for help, / search, @ knowledge, > command, or type FTS phrase")); + return; + } else if(command.startsWith(CliAndBreadcrumbsView::CHAR_FIND)) { + MF_DEBUG(" / HELP find" << endl); + if(command.size()<=2) { + view->updateCompleterModel(CliAndBreadcrumbsView::HELP_FIND_CMDS); + } + return; + } else if(command.startsWith(CliAndBreadcrumbsView::CHAR_KNOW)) { + MF_DEBUG(" @ HELP knowledge" << endl); + if(command.size()<=2) { + view->updateCompleterModel(view->HELP_KNOW_CMDS); + } + return; + } else if(command.startsWith(CliAndBreadcrumbsView::CHAR_CMD)) { + MF_DEBUG(" > HELP command" << endl); + if(command.size()<=2) { + view->updateCompleterModel(CliAndBreadcrumbsView::HELP_CMD_CMDS); + } + return; + } else if(command.startsWith(CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME)) { + QString prefix( + QString::fromStdString( + command.toStdString().substr( + CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME.size()-1))); if(prefix.size()) { mainPresenter->getStatusBar()->showInfo(prefix); if(prefix.size()==1) { @@ -67,78 +122,102 @@ void CliAndBreadcrumbsPresenter::handleCliTextChanged(const QString& text) outlineNamesCompletion << qs; } } - view->updateCompleterModel(&outlineNamesCompletion); + view->updateCompleterModel( + CliAndBreadcrumbsView::DEFAULT_CMDS, + &outlineNamesCompletion); } else { + // TODO NOT handled } } else { - view->updateCompleterModel(); + MF_DEBUG(" FALLBACK (default CMDs)" << endl); + view->updateCompleterModel( + CliAndBreadcrumbsView::DEFAULT_CMDS); } return; } + MF_DEBUG(" NO HANDLING (FTS phrase OR lost focus)" << endl); + return; + } else { // empty command + MF_DEBUG(" EMPTY command > NO handling" << endl); + return; } - - // fallback - view->forceFtsHistoryCompletion(); } // TODO i18n void CliAndBreadcrumbsPresenter::executeCommand() { QString command = view->getCommand(); + MF_DEBUG("CLI command EXEC: '" << command.toStdString() << "'" << endl); if(command.size()) { view->addCompleterItem(command); - if(command.startsWith(CliAndBreadcrumbsView::CMD_FTS)) { - executeFts(command); - view->showBreadcrumb(); - return; - } if(command.startsWith(CliAndBreadcrumbsView::CMD_LIST_OUTLINES)) { + MF_DEBUG(" executing: list outlines" << endl); executeListOutlines(); view->showBreadcrumb(); return; - } - if(command.startsWith(CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME)) { + } else if(command.startsWith(CliAndBreadcrumbsView::CMD_EMOJIS)) { + MF_DEBUG(" executing: emojis" << endl); + mainPresenter->doActionEmojisDialog(); + return; + } else if(command.startsWith(CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_TAG)) { string name = command.toStdString().substr( - CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME.size()); - unique_ptr> outlines = mind->findOutlineByNameFts(name); - if(!outlines || !outlines->size()) { - // IMPROVE memory leak if outlines && !outlines->size() - QString firstCompletion = view->getFirstCompletion(); - if(firstCompletion.size()) { - name = view->getFirstCompletion().toStdString().substr( - CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME.size() - ); - outlines = mind->findOutlineByNameFts(name); - } + CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_TAG.size()); + MF_DEBUG(" executing: find O by tag '" << name << "'" << endl); + if(name.size()) { + mainPresenter->doActionFindOutlineByTag(name); + } else { + mainPresenter->getStatusBar()->showInfo(tr("Notebook not found - please specify tag search phrase (is empty)")); } - if(outlines && outlines->size()) { - mainPresenter->getOrloj()->showFacetOutline(outlines->front()); - // TODO efficient - mainPresenter->getStatusBar()->showInfo(tr("Notebook ")+QString::fromStdString(outlines->front()->getName())); + return; + } else if(command.startsWith(CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME)) { + string name = command.toStdString().substr( + CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME.size()); + MF_DEBUG(" executing: find O by name '" << name << "'" << endl); + if(name.size()) { + mainPresenter->doActionFindOutlineByName(name); } else { - mainPresenter->getStatusBar()->showInfo(tr("Notebook not found: ") += QString(name.c_str())); + mainPresenter->getStatusBar()->showInfo(tr("Notebook not found - please specify name search phrase (is empty)")); } - view->showBreadcrumb(); + // status handling examples: + // mainPresenter->getStatusBar()->showInfo(tr("Notebook ")+QString::fromStdString(outlines->front()->getName())); + // mainPresenter->getStatusBar()->showInfo(tr("Notebook not found: ") += QString(name.c_str())); return; + } else + // knowledge lookup in the CLI: + // - @wikipedia ... opens tool dialog with Wikipedi SELECTED in the dropdown + // - @wikipedia llm ... opens directly https://wikipedia.org + if(command.startsWith(CliAndBreadcrumbsView::CHAR_KNOW)) { + for(auto c:view->HELP_KNOW_CMDS) { + QString toolId = command.mid(1, c.size()-1); + if(command.startsWith(c)) { + QString phrase = command.mid(1 + c.size()); + MF_DEBUG( + " executing: knowledge recherche of phrase '" + << phrase.toStdString() + << "' using command '" + << c.toStdString() << "' and tool '" + << toolId.toStdString() << "'" << endl); + if(phrase.size() > 1) { + mainPresenter->doActionOpenRunToolDialog(phrase, toolId, false); + mainPresenter->handleRunTool(); + } else { + // search phrase is empty + mainPresenter->doActionOpenRunToolDialog(phrase, toolId); + } + return; + } + } + // ELSE: unknown @unknown knowledge recherche tool do FTS as fallback + mainPresenter->getStatusBar()->showInfo(tr("Unknown knowledge recherche source - use valid source like @wikipedia")); + } else { + mainPresenter->doFts(view->getCommand(), true); } - - // do FTS as fallback - mainPresenter->doFts(view->getCommand(), true); } else { mainPresenter->getStatusBar()->showError(tr("No command!")); } } -void CliAndBreadcrumbsPresenter::executeFts(QString& command) -{ - string searchedString = command.toStdString().substr( - CliAndBreadcrumbsView::CMD_FTS.size()); - if(!searchedString.empty()) { - mainPresenter->doFts(QString::fromStdString(searchedString), true); - } -} - void CliAndBreadcrumbsPresenter::executeListOutlines() { mainPresenter->getOrloj()->showFacetOutlineList(mind->getOutlines()); diff --git a/app/src/qt/cli_n_breadcrumbs_presenter.h b/app/src/qt/cli_n_breadcrumbs_presenter.h index f66923d8..dce5be4b 100644 --- a/app/src/qt/cli_n_breadcrumbs_presenter.h +++ b/app/src/qt/cli_n_breadcrumbs_presenter.h @@ -1,7 +1,7 @@ /* cli_n_breadcrumbs_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -50,11 +50,13 @@ class CliAndBreadcrumbsPresenter : public QObject void executeListOutlines(); void executeListNotes(); - void executeFts(QString& command); private slots: - void executeCommand(); + /** + * @brief key pressed handler of the CLI edit line + */ void handleCliTextChanged(const QString& text); + void executeCommand(); }; } diff --git a/app/src/qt/cli_n_breadcrumbs_view.cpp b/app/src/qt/cli_n_breadcrumbs_view.cpp index 2da1a3c5..be40a553 100644 --- a/app/src/qt/cli_n_breadcrumbs_view.cpp +++ b/app/src/qt/cli_n_breadcrumbs_view.cpp @@ -1,7 +1,7 @@ /* cli_n_breadcrumbs_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -20,18 +20,37 @@ namespace m8r { +// "Enter a prompt - \"? .\" for help, \"> .\" to chat (Alt-x), \"/ .\" run command (Ctrl-/), or type a phrase to find." +constexpr const auto CLI_HELP_SHADOW_TEXT + = "Enter a prompt, command or phrase - type ? for help."; + + CliView::CliView(CliAndBreadcrumbsView* cliAndBreadcrumps, QWidget* parent) - : QLineEdit(parent) + : QLineEdit(parent), + PALETTE_DISABLED_TEXT(this->palette()), + PALETTE_ENABLED_TEXT(this->palette()), + PALETTE_ERROR_TEXT(this->palette()) { this->cliAndBreadcrumps = cliAndBreadcrumps; + + PALETTE_DISABLED_TEXT.setColor( + QPalette::Text, + QColor(125, 125, 125)); + + PALETTE_ENABLED_TEXT.setColor( + QPalette::Text, + LookAndFeels::getInstance().getCliTextColor()); + + PALETTE_ERROR_TEXT.setColor( + QPalette::Text, + QColor(125, 0, 0)); + #if !defined(__APPLE__) // changing pallette @ macOS w/ dark model @ Qt 5.15.x+ causes edit line to be unreadable - - QPalette* palette = new QPalette(); - palette->setColor(QPalette::Text, LookAndFeels::getInstance().getCliTextColor()); - setPalette(*palette); + setPalette(PALETTE_ENABLED_TEXT); #endif - setToolTip("Run command: type . for available commands, type search string for FTS, Alt-x to activate."); + + setToolTip(CLI_HELP_SHADOW_TEXT); } void CliView::keyPressEvent(QKeyEvent* event) @@ -47,18 +66,103 @@ void CliView::keyPressEvent(QKeyEvent* event) QLineEdit::keyPressEvent(event); } +void CliView::focusInEvent(QFocusEvent* event) +{ + MF_DEBUG("CLI: on focus acquired" << std::endl); + + if(text() == CLI_HELP_SHADOW_TEXT) { + clear(); + } + + QLineEdit::focusInEvent(event); +} + +void CliView::focusOutEvent(QFocusEvent* event) +{ + MF_DEBUG("CLI: on focus lost" << std::endl); + + if(text().size() == 0) { + setText(CLI_HELP_SHADOW_TEXT); + } + + QLineEdit::focusOutEvent(event); +} + /* - * CliAndBreadcrumbsView + * CLI and breadcrumbs view. */ -const QString CliAndBreadcrumbsView::CMD_FTS = ".fts "; -const QString CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME = ".find outline by name "; -const QString CliAndBreadcrumbsView::CMD_LIST_OUTLINES = ".list outlines"; +const QStringList CliAndBreadcrumbsView::EMPTY_CMDS = QStringList(); + +// help + +const QString CliAndBreadcrumbsView::CHAR_HELP + = "?"; + +const QString CliAndBreadcrumbsView::CMD_HELP_HELP + = "? ... ? for help"; +const QString CliAndBreadcrumbsView::CMD_HELP_SEARCH + = "? / to search"; +const QString CliAndBreadcrumbsView::CMD_HELP_KNOWLEDGE + = "? @ for knowledge recherche"; +const QString CliAndBreadcrumbsView::CMD_HELP_CMD + = "? > to run a command"; +const QString CliAndBreadcrumbsView::CMD_HELP_FTS + = "? full-text search phrase"; + +const QStringList CliAndBreadcrumbsView::HELP_CMDS = QStringList() + << CMD_HELP_HELP + << CMD_HELP_SEARCH + // << CMD_HELP_KNOWLEDGE + << CMD_HELP_CMD + // << CMD_HELP_CHAT + // << CMD_HELP_FTS + ; + +const QString CliAndBreadcrumbsView::CHAR_FIND + = "/"; + +const QString CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_NAME + = "/ find notebook by name "; +const QString CliAndBreadcrumbsView::CMD_FIND_NOTE_BY_NAME + = "/ find note by name "; +const QString CliAndBreadcrumbsView::CMD_FIND_OUTLINE_BY_TAG + = "/ find notebook by tag "; +const QString CliAndBreadcrumbsView::CMD_FIND_NOTE_BY_TAG + = "/ find note by tag "; + +const QStringList CliAndBreadcrumbsView::HELP_FIND_CMDS = QStringList() + << CMD_FIND_OUTLINE_BY_NAME + << CMD_FIND_OUTLINE_BY_TAG +// << CMD_FIND_NOTE_BY_NAME +// << CMD_FIND_NOTE_BY_TAG + ; + +const QString CliAndBreadcrumbsView::CHAR_KNOW + = "@"; + +const QString CliAndBreadcrumbsView::CHAR_CMD + = ">"; + +const QString CliAndBreadcrumbsView::CMD_HOME + = "> home"; // go to home O +const QString CliAndBreadcrumbsView::CMD_EMOJIS + = "> emojis"; +const QString CliAndBreadcrumbsView::CMD_TERMINAL + = "> terminal"; +const QString CliAndBreadcrumbsView::CMD_LIST_OUTLINES + = "> list notebooks"; + +const QStringList CliAndBreadcrumbsView::HELP_CMD_CMDS = QStringList() +// << CMD_HOME +// << CMD_TERMINAL + << CMD_EMOJIS + << CMD_LIST_OUTLINES + ; // TODO migrate all commands to constants const QStringList CliAndBreadcrumbsView::DEFAULT_CMDS = QStringList() /* - << CMD_HELP << CMD_EXIT // home tools //<< "home" @@ -87,7 +191,6 @@ const QStringList CliAndBreadcrumbsView::DEFAULT_CMDS = QStringList() // TODO new outline // TODO new note */ - << CMD_FTS << CMD_LIST_OUTLINES << CMD_FIND_OUTLINE_BY_NAME ; @@ -97,6 +200,11 @@ CliAndBreadcrumbsView::CliAndBreadcrumbsView(QWidget* parent, bool zenMode) : QWidget(parent), zenMode{zenMode} { + HELP_KNOW_CMDS = QStringList(); + for(const auto& toolName:KnowledgeTool::getToolIds()) { + HELP_KNOW_CMDS << (CHAR_KNOW + QString::fromStdString(toolName)); + } + setFixedHeight(this->fontMetrics().height()*1.5); QHBoxLayout* layout = new QHBoxLayout(this); @@ -111,30 +219,56 @@ CliAndBreadcrumbsView::CliAndBreadcrumbsView(QWidget* parent, bool zenMode) } layout->addWidget(breadcrumbsLabel); - cli = new CliView(this, parent); - cliCompleter = new QCompleter(new QStandardItemModel{}, parent); - cliCompleter->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); - cliCompleter->setCompletionMode(QCompleter::PopupCompletion); - cli->setCompleter(cliCompleter); + this->cli = new CliView(this, parent); + this->cliCompleter = new QCompleter(new QStandardItemModel{}, parent); + this->cliCompleter->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); + this->cliCompleter->setCompletionMode(QCompleter::PopupCompletion); + this->cli->setCompleter(cliCompleter); + this->cli->setText(CLI_HELP_SHADOW_TEXT); layout->addWidget(cli); showBreadcrumb(); } +void CliAndBreadcrumbsView::showCli(bool selectAll) +{ + MF_DEBUG("CLI view: SHOW (select ALL = " << std::boolalpha << selectAll << ")" << std::endl); + + // if help presents, then clear it AND change color + if(cli->text().startsWith(CLI_HELP_SHADOW_TEXT)) { + cli->clear(); + } +#if !defined(__APPLE__) + setPalette(this->cli->PALETTE_ENABLED_TEXT); +#endif + + // show + show(); + cli->setFocus(); + if(selectAll) { + cli->selectAll(); + } +} + void appendToStandardModel(const QStringList& list, QStandardItemModel* completerModel) { for(const auto& i:list) { QStandardItem* item = new QStandardItem(i); + + // TODO icons are not shown on certain platforms (Linux/x86) + /* if(i.startsWith(".")) { item->setIcon(QIcon(":/menu-icons/cli.svg")); } else { item->setIcon(QIcon(":/menu-icons/find.svg")); } - // IMPROVE item->setToolTip("tool tip"); + */ + + // TODO IMPROVE item->setToolTip("tool tip"); completerModel->appendRow(item); } } -void CliAndBreadcrumbsView::updateCompleterModel(const QStringList* list) +void CliAndBreadcrumbsView::updateCompleterModel(const QStringList& helpList, const QStringList* list) { QStandardItemModel* completerModel=(QStandardItemModel*)cliCompleter->model(); if(completerModel==nullptr) { @@ -154,12 +288,12 @@ void CliAndBreadcrumbsView::updateCompleterModel(const QStringList* list) if(list!=nullptr) { appendToStandardModel(*list, completerModel); } - appendToStandardModel(DEFAULT_CMDS, completerModel); + appendToStandardModel(helpList, completerModel); } void CliAndBreadcrumbsView::forceFtsHistoryCompletion() { - updateCompleterModel(); + updateCompleterModel(DEFAULT_CMDS); // ensure completion is shown despite there is NO filtering character cliCompleter->complete(); @@ -218,15 +352,4 @@ void CliAndBreadcrumbsView::showBreadcrumb() } } -void CliAndBreadcrumbsView::showCli(bool selectAll) -{ - show(); - cli->setFocus(); - if(selectAll) { - cli->selectAll(); - } - updateCompleterModel(); - cliCompleter->complete(); -} - } // m8r namespace diff --git a/app/src/qt/cli_n_breadcrumbs_view.h b/app/src/qt/cli_n_breadcrumbs_view.h index 8b60cc58..dd2536a6 100644 --- a/app/src/qt/cli_n_breadcrumbs_view.h +++ b/app/src/qt/cli_n_breadcrumbs_view.h @@ -1,7 +1,7 @@ /* cli_n_breadcrumbs_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,11 +23,15 @@ #include "look_n_feel.h" #include "cli_n_breadcrumbs_presenter.h" +#include "../../lib/src/config/configuration.h" namespace m8r { class CliAndBreadcrumbsView; +/** + * @brief Custom line edit with key and color handling. + */ class CliView : public QLineEdit { Q_OBJECT @@ -35,9 +39,18 @@ class CliView : public QLineEdit private: CliAndBreadcrumbsView* cliAndBreadcrumps; +protected: + virtual void focusInEvent(QFocusEvent*) override; + virtual void focusOutEvent(QFocusEvent*) override; + public: + QPalette PALETTE_DISABLED_TEXT; + QPalette PALETTE_ENABLED_TEXT; + QPalette PALETTE_ERROR_TEXT; + explicit CliView(CliAndBreadcrumbsView* cliAndBreadcrumps, QWidget* parent); void keyPressEvent(QKeyEvent* event) override; + signals: void keyReleased(QKeyEvent* event); }; @@ -49,37 +62,86 @@ class CliAndBreadcrumbsView : public QWidget friend class CliAndBreadcrumbsPresenter; private: - static const QStringList DEFAULT_CMDS; - // IMPROVE horizontal container w/ buttons names and / labels to navigate easily up/down QLabel* breadcrumbsLabel; CliView* cli; QCompleter* cliCompleter; + QStringList cliCompleterHistoryList; bool zenMode; public: - static const QString CMD_FTS; + static const QStringList DEFAULT_CMDS; // TODO remove + + static const QStringList EMPTY_CMDS; + + // help + + static const QString CHAR_HELP; + + static const QString CMD_HELP_HELP; + static const QString CMD_HELP_SEARCH; + static const QString CMD_HELP_KNOWLEDGE; + static const QString CMD_HELP_CMD; + static const QString CMD_HELP_CHAT; + static const QString CMD_HELP_FTS; + + static const QStringList HELP_CMDS; + + // search + + static const QString CHAR_FIND; + static const QString CMD_FIND_OUTLINE_BY_NAME; + static const QString CMD_FIND_OUTLINE_BY_TAG; + static const QString CMD_FIND_NOTE_BY_NAME; + static const QString CMD_FIND_NOTE_BY_TAG; + + static const QStringList HELP_FIND_CMDS; + + // knowledge + + static const QString CHAR_KNOW; + + QStringList HELP_KNOW_CMDS; + + // command + + static const QString CHAR_CMD; + + static const QString CMD_HOME; + static const QString CMD_EMOJIS; + static const QString CMD_TERMINAL; static const QString CMD_LIST_OUTLINES; + static const QStringList HELP_CMD_CMDS; + + // chat + + static const QString CHAR_CHAT; + public: explicit CliAndBreadcrumbsView(QWidget* parent, bool zenMode=true); + /** + * @brief Keyboard shortcut handler (Alt-x). + */ + void showCli(bool selectAll=true); + void addCompleterItem(const QString& item) { cliCompleterHistoryList.insert(0, item); } - void updateCompleterModel(const QStringList* list=nullptr); + void updateCompleterModel(const QStringList& helpList, const QStringList* list=nullptr); void forceFtsHistoryCompletion(); QString getFirstCompletion() const; void setBreadcrumbPath(const QString& path); void setCommand(const char* command); const QString getCommand() const; void show(); + void complete() { cliCompleter->complete(); } void hide(); void showBreadcrumb(); - void showCli(bool selectAll=true); }; } diff --git a/app/src/qt/dashboard/dashboardlet_welcome.cpp b/app/src/qt/dashboard/dashboardlet_welcome.cpp deleted file mode 100644 index a63ee5f3..00000000 --- a/app/src/qt/dashboard/dashboardlet_welcome.cpp +++ /dev/null @@ -1,6 +0,0 @@ -/* -#include -QTextBrowser *tb = new QTextBrowser(this); -tb->setOpenExternalLinks(true); -tb->setHtml(htmlString); - */ diff --git a/app/src/qt/dashboard_presenter.cpp b/app/src/qt/dashboard_presenter.cpp deleted file mode 100644 index e91b590d..00000000 --- a/app/src/qt/dashboard_presenter.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - dashboard_presenter.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "dashboard_presenter.h" - -namespace m8r { - -using namespace std; - -DashboardPresenter::DashboardPresenter(DashboardView* view, OrlojPresenter* orloj) - : config(Configuration::getInstance()) -{ - this->view = view; - - doFirstDashboardletPresenter = new OrganizerQuadrantPresenter( - view->getDoFirstDashboardlet(), - orloj, - tr("Do first") - ); - outlinesDashboardletPresenter = new OutlinesTablePresenter( - view->getOutlinesDashboardlet(), - orloj->getMainPresenter()->getHtmlRepresentation() - ); - navigatorDashboardletPresenter = new NavigatorPresenter( - view->getNavigatorDashboardlet(), - this, - orloj->getMind()->getKnowledgeGraph() - ); - recentDashboardletPresenter = new RecentNotesTablePresenter( - view->getRecentDashboardlet(), - orloj->getMainPresenter()->getHtmlRepresentation() - ); - tagsDashboardletPresenter = new TagsTablePresenter( - view->getTagsDashboardlet(), - orloj->getMainPresenter()->getHtmlRepresentation() - ); -} - -DashboardPresenter::~DashboardPresenter() -{ -} - -void DashboardPresenter::refresh( - const vector& os, - const vector& ns, - const map& ts, - int bytes, - MindStatistics* stats) -{ - // IMPROVE set size based on system resolution/zoom - view->getWelcomeDashboardlet()->setHtml( - QString( - "" - "" - "
 
" - "

We are MindForger!

" - "MindForger is personal " - "thinking notebook " - "and Markdown editor:" - "" - "Tips:" - "
    " - "
  • Return to this dashboard with Ctrl-Shift-d.
  • " - "
  • List notebooks/Markdown files with Ctrl-Shift-o.
  • " - "
  • Open item in a table listing with " - "double-click or ENTER.
  • " - "
  • Edit note with HTML preview double-click or " - "Ctrl-e.
  • " - "
  • Zoom note HTML preview with Ctrl-mouse wheel " - "or scroll.
  • " - "
" - "Statistics:" - "
    " - "
  • " + stringFormatIntAsUs(os.size()) + " notebooks, " - "" + stringFormatIntAsUs(ns.size()) + " notes, " - "" + stringFormatIntAsUs(ts.size()) + " tags and " - "" + stringFormatIntAsUs(bytes) + " bytes.
  • " - "
  • Most used notebook: " + QString::fromStdString(stats->mostReadOutline?stats->mostReadOutline->getName():"") + ".
  • " - "
  • Most used note: " + QString::fromStdString(stats->mostReadNote?stats->mostReadNote->getName():"") + " in " - "" + QString::fromStdString(stats->mostReadNote?stats->mostReadNote->getOutline()->getName():"") + ".
  • " - // TODO RD vs. WR: "
  • - Most written notebook: " + QString::fromStdString(stats->mostWrittenOutline?stats->mostWrittenOutline->getName():"") + ".
  • " - // TODO RD vs. WR: "
  • - Most written note: " + QString::fromStdString(stats->mostWrittenNote?stats->mostWrittenNote->getName():"") + ".
  • " - "
  • Most used tag:  " - "" + QString::fromStdString(stats->mostUsedTag?stats->mostUsedTag->getName():"") + " .
  • " - // TODO O w/ most Ns - "
" - "
" - )); - - vector doFirstOs; - if(os.size()) { - for(Outline* o:os) { - if(o->getUrgency()>2) { - if(o->getImportance()>2) { - doFirstOs.push_back(o->getOutlineDescriptorAsNote()); - } - } - } - } - doFirstDashboardletPresenter->refresh(doFirstOs, true, true, true); - - outlinesDashboardletPresenter->refresh(os); - recentDashboardletPresenter->refresh(ns); - // IMPROVE: consider showing recent O: navigatorDashboardletPresenter->showInitialView(ns[0]->getOutline()); - navigatorDashboardletPresenter->showInitialView(); - tagsDashboardletPresenter->refresh(ts); - - view->setMindForgerMode( - doFirstOs.size() > 0 - && - config.getActiveRepository()->getType() - == - Repository::RepositoryType::MINDFORGER); - - view->getRecentDashboardlet()->setFocus(); -} - -} // m8r namespace diff --git a/app/src/qt/dashboard_presenter.h b/app/src/qt/dashboard_presenter.h deleted file mode 100644 index 1f4f63b7..00000000 --- a/app/src/qt/dashboard_presenter.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - dashboard_presenter.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8RUI_DASHBOARD_PRESENTER_H -#define M8RUI_DASHBOARD_PRESENTER_H - -#include - -#include - -#include "gear/qutils.h" -#include "orloj_presenter.h" -#include "dashboard_view.h" -#include "organizer_quadrant_presenter.h" -#include "recent_notes_table_presenter.h" -#include "navigator_presenter.h" -#include "tags_table_presenter.h" -#include "outlines_table_view.h" - -namespace m8r { - -class OrganizerQuadrantPresenter; -class OrlojPresenter; -class OutlinesTablePresenter; - -class DashboardPresenter : public QObject -{ - Q_OBJECT - -private: - DashboardView* view; - - Configuration& config; - - OrganizerQuadrantPresenter* doFirstDashboardletPresenter; - OrganizerQuadrantPresenter* doSoonDashboardletPresenter; - RecentNotesTablePresenter* recentDashboardletPresenter; - NavigatorPresenter* navigatorDashboardletPresenter; - TagsTablePresenter* tagsDashboardletPresenter; - OutlinesTablePresenter* outlinesDashboardletPresenter; - -public: - explicit DashboardPresenter(DashboardView* view, OrlojPresenter* orloj); - DashboardPresenter(const DashboardPresenter&) = delete; - DashboardPresenter(const DashboardPresenter&&) = delete; - DashboardPresenter &operator=(const DashboardPresenter&) = delete; - DashboardPresenter &operator=(const DashboardPresenter&&) = delete; - ~DashboardPresenter(); - - DashboardView* getView() { return view; } - - void refresh( - const std::vector& os, - const std::vector& ns, - const std::map& ts, - int bytes, - MindStatistics* stats - ); - - RecentNotesTablePresenter* getRecentNotesPresenter() { return recentDashboardletPresenter; } - TagsTablePresenter* getTagsPresenter() { return tagsDashboardletPresenter; } - OutlinesTablePresenter* getOutlinesPresenter() { return outlinesDashboardletPresenter; } -}; - -} -#endif // M8RUI_DASHBOARD_PRESENTER_H diff --git a/app/src/qt/dashboard_view.cpp b/app/src/qt/dashboard_view.cpp deleted file mode 100644 index d6ffca33..00000000 --- a/app/src/qt/dashboard_view.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - organizer_view.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "dashboard_view.h" - -namespace m8r { - -DashboardView::DashboardView(QWidget* parent) - : QSplitter{Qt::Horizontal, parent}, - isMindForgerRepository(false) -{ - left = new QSplitter{Qt::Vertical, this}; - left->setStretchFactor(0, 1); - left->setStretchFactor(1, 1); - - middle = new QSplitter{Qt::Vertical, this}; - middle->setStretchFactor(0, 1); - middle->setStretchFactor(1, 1); - - right = new QSplitter{Qt::Vertical, this}; - right->setStretchFactor(0, 1); - right->setStretchFactor(1, 1); - - // welcome - welcomeDashboardlet = new QTextBrowser(left); - welcomeDashboardlet->setOpenExternalLinks(true); - left->addWidget(welcomeDashboardlet); - - // recent - recentDashboardlet = new RecentNotesTableView(left, true); - left->addWidget(recentDashboardlet); - - // organizer quadrants - doFirstDashboardlet = new OrganizerQuadrantView(middle); - middle->addWidget(doFirstDashboardlet); - - // tags - tagsDashboardlet = new TagsTableView(middle); - middle->addWidget(tagsDashboardlet); - - // navigator - navigatorDashboardlet = new NavigatorView(right, true); - // IMPROVE should go to resize event - int windowHeight=parent->parentWidget()->parentWidget()->size().height(); - navigatorDashboardlet->setFixedHeight(windowHeight); - right->addWidget(navigatorDashboardlet); - - // outlines - outlinesDashboardlet = new OutlinesTableView(right, true); - right->addWidget(outlinesDashboardlet); - - // self ~ horizontal splitter - setStretchFactor(0, 1); - setStretchFactor(1, 1); - setStretchFactor(2, 1); - - addWidget(left); - addWidget(middle); - addWidget(right); -} - -void DashboardView::setMindForgerMode(bool isMindForgerRepository) -{ - this->isMindForgerRepository = isMindForgerRepository; - if(isMindForgerRepository) { - middle->setVisible(true); - } else { - middle->setVisible(false); - } -} - -void DashboardView::resizeEvent(QResizeEvent* event) -{ - UNUSED_ARG(event); - - int normalizedWidth = width()/fontMetrics().averageCharWidth(); - if(!isMindForgerRepository || normalizedWidth < SIMPLIFIED_VIEW_THRESHOLD_WIDTH) { - middle->setVisible(false); - } else { - middle->setVisible(true); - } - - QSplitter::resizeEvent(event); -} - -DashboardView::~DashboardView() -{ -} - -} // m8r namespace diff --git a/app/src/qt/dashboard_view.h b/app/src/qt/dashboard_view.h deleted file mode 100644 index 1ad47960..00000000 --- a/app/src/qt/dashboard_view.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - dashboard_view.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8RUI_DASHBOARD_VIEW_H -#define M8RUI_DASHBOARD_VIEW_H - -#include - -#include "organizer_quadrant_view.h" -#include "recent_notes_table_view.h" -#include "navigator/navigator_view.h" -#include "tags_table_view.h" -#include "outlines_table_view.h" - -namespace m8r { - -/** - * @brief Dashboard - */ -class DashboardView : public QSplitter -{ - Q_OBJECT - -private: - // if view is width < threshold columns, then shows simplified view w/o Mind-related columns - static constexpr int SIMPLIFIED_VIEW_THRESHOLD_WIDTH = 75*2; - - bool isMindForgerRepository; - - QSplitter* left; - QSplitter* middle; - QSplitter* right; - - QTextBrowser* welcomeDashboardlet; - OrganizerQuadrantView* doFirstDashboardlet; - OrganizerQuadrantView* doSoonDashboardlet; - NavigatorView* navigatorDashboardlet; - RecentNotesTableView* recentDashboardlet; - TagsTableView* tagsDashboardlet; - OutlinesTableView* outlinesDashboardlet; - -public: - explicit DashboardView(QWidget* parent); - DashboardView(const DashboardView&) = delete; - DashboardView(const DashboardView&&) = delete; - DashboardView &operator=(const DashboardView&) = delete; - DashboardView &operator=(const DashboardView&&) = delete; - ~DashboardView(); - - void setMindForgerMode(bool isMindForgerRepository); - - QTextBrowser* getWelcomeDashboardlet() { return welcomeDashboardlet; } - OrganizerQuadrantView* getDoFirstDashboardlet() { return doFirstDashboardlet; } - OutlinesTableView* getOutlinesDashboardlet() { return outlinesDashboardlet; } - NavigatorView* getNavigatorDashboardlet() { return navigatorDashboardlet; } - RecentNotesTableView* getRecentDashboardlet() { return recentDashboardlet; } - TagsTableView* getTagsDashboardlet() { return tagsDashboardlet; } - -protected: - void resizeEvent(QResizeEvent* event) override; -}; - -} -#endif // M8RUI_DASHBOARD_VIEW_H diff --git a/app/src/qt/dialogs/add_library_dialog.cpp b/app/src/qt/dialogs/add_library_dialog.cpp index 54fd7695..7724f9bf 100644 --- a/app/src/qt/dialogs/add_library_dialog.cpp +++ b/app/src/qt/dialogs/add_library_dialog.cpp @@ -1,7 +1,7 @@ /* add_library_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -26,11 +26,16 @@ AddLibraryDialog::AddLibraryDialog(QWidget* parent) : QDialog(parent) { // widgets - findLibrarySourceLabel = new QLabel{tr("Choose and find library source:"), parent}; + findLibrarySourceLabel = new QLabel{ + tr( + "Choose a directory (library) of PDF files to be indexed. MindForger\n" + "will create new notebook for every library file. Such notebook can be\n" + "used to easily open the library file and create library file related\n" + "notes.\n\n" + "Choose new library source:"), + parent}; findDirectoryButton = new QPushButton{tr("Directory")}; - libraryNameLabel = new QLabel{tr("Library name:"), parent}; - libraryNameEdit = new QLineEdit{parent}; uriLabel = new QLabel{tr("Library source path:"), parent}; uriEdit = new QLineEdit{parent}; @@ -44,8 +49,12 @@ AddLibraryDialog::AddLibraryDialog(QWidget* parent) closeButton = new QPushButton{tr("&Cancel")}; // signals - QObject::connect(findDirectoryButton, SIGNAL(clicked()), this, SLOT(handleFindDirectory())); - QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); + QObject::connect( + findDirectoryButton, SIGNAL(clicked()), + this, SLOT(handleFindDirectory())); + QObject::connect( + closeButton, SIGNAL(clicked()), + this, SLOT(close())); // assembly QVBoxLayout* mainLayout = new QVBoxLayout{}; @@ -54,8 +63,6 @@ AddLibraryDialog::AddLibraryDialog(QWidget* parent) srcButtonLayout->addWidget(findDirectoryButton); srcButtonLayout->addStretch(); mainLayout->addLayout(srcButtonLayout); - mainLayout->addWidget(libraryNameLabel); - mainLayout->addWidget(libraryNameEdit); mainLayout->addWidget(uriLabel); mainLayout->addWidget(uriEdit); mainLayout->addWidget(pdfCheckBox); @@ -77,6 +84,13 @@ AddLibraryDialog::AddLibraryDialog(QWidget* parent) AddLibraryDialog::~AddLibraryDialog() { + delete findLibrarySourceLabel; + delete uriLabel; + delete uriEdit; + delete findDirectoryButton; + delete pdfCheckBox; + delete createButton; + delete closeButton; } void AddLibraryDialog::show() @@ -87,7 +101,10 @@ void AddLibraryDialog::show() void AddLibraryDialog::handleFindDirectory() { QString homeDirectory - = QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory); + = QStandardPaths::locate( + QStandardPaths::HomeLocation, + QString(), + QStandardPaths::LocateDirectory); QFileDialog fileDialog{this}; fileDialog.setWindowTitle(tr("Choose Directory")); diff --git a/app/src/qt/dialogs/add_library_dialog.h b/app/src/qt/dialogs/add_library_dialog.h index 1a84ee8c..bb0d843e 100644 --- a/app/src/qt/dialogs/add_library_dialog.h +++ b/app/src/qt/dialogs/add_library_dialog.h @@ -1,7 +1,7 @@ /* add_library_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -44,8 +44,6 @@ class AddLibraryDialog : public QDialog std::vector notes; QLabel* findLibrarySourceLabel; - QLabel* libraryNameLabel; - QLineEdit* libraryNameEdit; QLabel* uriLabel; QLineEdit* uriEdit; @@ -68,7 +66,6 @@ class AddLibraryDialog : public QDialog void show(); QPushButton* getCreateButton() const { return createButton; } - QString getLibraryNameText() const { return libraryNameEdit->text(); } QString getLibraryUriText() const { return uriEdit->text(); } bool isIndexPdf() const { return pdfCheckBox->isChecked(); } diff --git a/app/src/qt/dialogs/configuration_dialog.cpp b/app/src/qt/dialogs/configuration_dialog.cpp index df147ef0..0db15217 100644 --- a/app/src/qt/dialogs/configuration_dialog.cpp +++ b/app/src/qt/dialogs/configuration_dialog.cpp @@ -1,7 +1,7 @@ /* configuration_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -33,20 +33,25 @@ ConfigurationDialog::ConfigurationDialog(QWidget* parent) markdownTab = new MarkdownTab{this}; navigatorTab = new NavigatorTab{this}; mindTab = new MindTab{this}; + wingmanTab = new WingmanTab{this}; tabWidget->addTab(appTab, tr("Application")); + tabWidget->addTab(wingmanTab, tr("Wingman")); tabWidget->addTab(viewerTab, tr("Viewer")); tabWidget->addTab(editorTab, tr("Editor")); tabWidget->addTab(markdownTab, tr("Markdown")); - tabWidget->addTab(navigatorTab, tr("Navigator")); tabWidget->addTab(mindTab, tr("Mind")); + tabWidget->addTab(navigatorTab, tr("Navigator")); buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); // signals - QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &ConfigurationDialog::saveSlot); + QObject::connect( + buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + QObject::connect( + buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + QObject::connect( + buttonBox, &QDialogButtonBox::accepted, this, &ConfigurationDialog::saveSlot); QVBoxLayout* mainLayout = new QVBoxLayout{this}; mainLayout->addWidget(tabWidget); @@ -72,6 +77,7 @@ void ConfigurationDialog::show() markdownTab->refresh(); navigatorTab->refresh(); mindTab->refresh(); + wingmanTab->refresh(); QDialog::show(); } @@ -84,6 +90,7 @@ void ConfigurationDialog::saveSlot() markdownTab->save(); navigatorTab->save(); mindTab->save(); + wingmanTab->save(); emit saveConfigSignal(); } @@ -95,7 +102,10 @@ void ConfigurationDialog::saveSlot() ConfigurationDialog::AppTab::AppTab(QWidget *parent) : QWidget(parent), config(Configuration::getInstance()) { - themeLabel = new QLabel(tr("UI theme (requires restart)")+":", this); + themeLabel = new QLabel( + tr("UI theme (requires restart)")+":", this); + menuLabel = new QLabel( + tr("Menu (requires restart)")+":", this); themeCombo = new QComboBox{this}; themeCombo->addItem(QString{UI_THEME_LIGHT}); #ifndef __APPLE__ @@ -113,10 +123,8 @@ ConfigurationDialog::AppTab::AppTab(QWidget *parent) startupLabel = new QLabel(tr("Show the following view on application start")+":", this); startupCombo = new QComboBox{this}; -#ifdef MF_DEPRECATED - startupCombo->addItem(QString{START_TO_DASHBOARD}); -#endif startupCombo->addItem(QString{START_TO_OUTLINES}); + startupCombo->addItem(QString{START_TO_OUTLINES_TREE}); startupCombo->addItem(QString{START_TO_TAGS}); startupCombo->addItem(QString{START_TO_RECENT}); #ifdef MF_BUG @@ -125,10 +133,17 @@ ConfigurationDialog::AppTab::AppTab(QWidget *parent) #endif startupCombo->addItem(QString{START_TO_HOME_OUTLINE}); + appFontSizeLabel = new QLabel( + tr("Application font size - 0 is system (requires restart)")+":", this); + appFontSizeSpin = new QSpinBox(this); + appFontSizeSpin->setMinimum(0); + appFontSizeSpin->setMaximum(68); + showToolbarCheck = new QCheckBox(tr("show toolbar"), this); showToolbarCheck->setChecked(true); - uiExpertModeCheck = new QCheckBox(tr("I don't need buttons - I know all keyboard shortcuts!"), this); - nerdMenuCheck = new QCheckBox(tr("nerd menu (requires restart)"), this); + uiExpertModeCheck = new QCheckBox( + tr("I don't need buttons - I know all keyboard shortcuts!"), this); + nerdMenuCheck = new QCheckBox(tr("nerd terminology"), this); // assembly QVBoxLayout* startupLayout = new QVBoxLayout{this}; @@ -140,15 +155,25 @@ ConfigurationDialog::AppTab::AppTab(QWidget *parent) QVBoxLayout* appearanceLayout = new QVBoxLayout{this}; appearanceLayout->addWidget(themeLabel); appearanceLayout->addWidget(themeCombo); - appearanceLayout->addWidget(showToolbarCheck); - appearanceLayout->addWidget(uiExpertModeCheck); + appearanceLayout->addWidget(appFontSizeLabel); + appearanceLayout->addWidget(appFontSizeSpin); + appearanceLayout->addWidget(menuLabel); appearanceLayout->addWidget(nerdMenuCheck); - QGroupBox* appearanceGroup = new QGroupBox{tr("Appearance"), this}; + QGroupBox* appearanceGroup = new QGroupBox{ + tr("Appearance (requires restart)"), + this}; appearanceGroup->setLayout(appearanceLayout); + QVBoxLayout* controlsLayout = new QVBoxLayout{this}; + controlsLayout->addWidget(showToolbarCheck); + controlsLayout->addWidget(uiExpertModeCheck); + QGroupBox* controlsGroup = new QGroupBox{tr("Controls"), this}; + controlsGroup->setLayout(controlsLayout); + QVBoxLayout* boxesLayout = new QVBoxLayout{this}; boxesLayout->addWidget(startupGroup); boxesLayout->addWidget(appearanceGroup); + boxesLayout->addWidget(controlsGroup); boxesLayout->addStretch(); setLayout(boxesLayout); } @@ -157,6 +182,8 @@ ConfigurationDialog::AppTab::~AppTab() { delete themeLabel; delete themeCombo; + delete appFontSizeLabel; + delete appFontSizeSpin; delete startupLabel; delete startupCombo; delete showToolbarCheck; @@ -173,6 +200,7 @@ void ConfigurationDialog::AppTab::refresh() themeCombo->setCurrentIndex(i); } showToolbarCheck->setChecked(config.isUiShowToolbar()); + appFontSizeSpin->setValue(config.getUiAppFontSize()); uiExpertModeCheck->setChecked(config.isUiExpertMode()); nerdMenuCheck->setChecked(config.isUiNerdTargetAudience()); } @@ -182,6 +210,7 @@ void ConfigurationDialog::AppTab::save() config.setStartupView(startupCombo->itemText(startupCombo->currentIndex()).toStdString()); config.setUiThemeName(themeCombo->itemText(themeCombo->currentIndex()).toStdString()); config.setUiShowToolbar(showToolbarCheck->isChecked()); + config.setUiAppFontSize(appFontSizeSpin->value()); config.setUiExpertMode(uiExpertModeCheck->isChecked()); config.setUiNerdTargetAudience(nerdMenuCheck->isChecked()); } @@ -190,7 +219,7 @@ void ConfigurationDialog::AppTab::save() * Viewer tab */ -ConfigurationDialog::ViewerTab::ViewerTab(QWidget *parent) +ConfigurationDialog::ViewerTab::ViewerTab(QWidget* parent) : QWidget(parent), config(Configuration::getInstance()) { zoomLabel = new QLabel(tr("HTML zoom (100 is 100%, Ctrl + mouse wheel)")+":", this); @@ -198,11 +227,13 @@ ConfigurationDialog::ViewerTab::ViewerTab(QWidget *parent) zoomSpin->setMinimum(25); zoomSpin->setMaximum(500); - srcCodeHighlightSupportCheck = new QCheckBox{tr("source code syntax highlighting support"), this}; + srcCodeHighlightSupportCheck = new QCheckBox{ + tr("source code syntax highlighting support"), this}; mathSupportCheck = new QCheckBox{tr("math support"), this}; fullOPreviewCheck = new QCheckBox{tr("whole notebook preview"), this}; - doubleClickViewerToEditCheck = new QCheckBox{tr("double click HTML preview to edit"), this}; + doubleClickViewerToEditCheck = new QCheckBox{ + tr("double click HTML preview to edit"), this}; diagramSupportLabel = new QLabel(tr("Diagram support")+":", this); diagramSupportCombo = new QComboBox{this}; @@ -367,7 +398,7 @@ ConfigurationDialog::EditorTab::EditorTab(QWidget *parent) editorSpellCheckHelp = new QLabel( tr("Spell check dictionaries configuration documentation" ), this @@ -643,6 +674,129 @@ void ConfigurationDialog::MindTab::save() config.setDistributorSleepInterval(distributorSleepIntervalSpin->value()); } +/* + * Wingman tab + */ + +ConfigurationDialog::WingmanTab::WingmanTab(QWidget* parent) + : QWidget(parent), + openAiComboLabel{"OpenAI"}, + config(Configuration::getInstance()) +{ + llmProvidersLabel = new QLabel(tr("LLM provider:"), this); + llmProvidersCombo = new QComboBox{this}; + QObject::connect( + llmProvidersCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(handleComboBoxChanged(int)) + ); + + llmHelpLabel = new QLabel( + tr( + "Configure OpenAI LLM provider:\n" + "
    " + "
  • Generate an OpenAI API key.
  • " + "
  • Set the API key:" + "
    a) either set the %1 environment variable
    " + "with the API key
    " + "b) or paste the API key below to save it unencrypted to
    " + ".mindforger.md file in your home dir.
  • " + "
  • Restart MindForger to apply the change.
  • " + "
" + ).arg(ENV_VAR_OPENAI_API_KEY)); + llmHelpLabel->setVisible(!config.canWingmanOpenAi()); + openAiApiKeyEdit = new QLineEdit(this); + openAiApiKeyEdit->setVisible(!config.canWingmanOpenAi()); + clearOpenAiApiKeyButton = new QPushButton(tr("Clear OpenAI API Key"), this); + if(config.getWingmanOpenAiApiKey().size() == 0) { + clearOpenAiApiKeyButton->setVisible(false); + } + + // assembly + QVBoxLayout* nLayout = new QVBoxLayout{this}; + nLayout->addWidget(llmProvidersLabel); + nLayout->addWidget(llmProvidersCombo); + nLayout->addWidget(llmHelpLabel); + nLayout->addWidget(openAiApiKeyEdit); + nLayout->addWidget(clearOpenAiApiKeyButton); + QGroupBox* nGroup = new QGroupBox{tr("Large language model (LLM) providers"), this}; + nGroup->setLayout(nLayout); + + QVBoxLayout* boxesLayout = new QVBoxLayout{this}; + boxesLayout->addWidget(nGroup); + boxesLayout->addStretch(); + setLayout(boxesLayout); + + QObject::connect( + clearOpenAiApiKeyButton, SIGNAL(clicked()), + this, SLOT(clearOpenAiApiKeySlot())); + +} + +void ConfigurationDialog::WingmanTab::clearOpenAiApiKeySlot() +{ + openAiApiKeyEdit->clear(); + QMessageBox::information( + this, + tr("OpenAI API Key Cleared"), + tr( + "API key has been cleared from the configuration. " + "Please close the configuration dialog with the OK button " + "and restart MindForger to apply this change.") + ); +} + +void ConfigurationDialog::WingmanTab::handleComboBoxChanged(int index) { + string comboItemLabel{llmProvidersCombo->itemText(index).toStdString()}; + MF_DEBUG("WingmanTab::handleComboBoxChange: '" << comboItemLabel << "'" << endl); + if(this->isVisible() && comboItemLabel == openAiComboLabel) { + QMessageBox::warning( + this, + tr("Data Privacy Warning"), + tr( + "You have chosen OpenAI as your Wingman LLM provider. " + "Therefore, your data will be sent to OpenAI servers " + "for GPT processing when you use Wingman.")); + } +} + +ConfigurationDialog::WingmanTab::~WingmanTab() +{ + delete llmProvidersLabel; + delete llmProvidersCombo; + delete llmHelpLabel; +} + +void ConfigurationDialog::WingmanTab::refresh() +{ + // refresh LLM providers combo + llmProvidersCombo->clear(); + llmProvidersCombo->addItem(""); // disable Wingman +#ifdef MF_WIP + if(config.canWingmanMock()) { + llmProvidersCombo->addItem( + QString{"Mock"}, WingmanLlmProviders::WINGMAN_PROVIDER_MOCK); + } +#endif + if(config.canWingmanOpenAi()) { + llmProvidersCombo->addItem( + QString::fromStdString(openAiComboLabel), WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI); + } + openAiApiKeyEdit->setText(QString::fromStdString(config.getWingmanOpenAiApiKey())); + // set the last selected provider + llmProvidersCombo->setCurrentIndex( + llmProvidersCombo->findData(config.getWingmanLlmProvider())); +} + + +void ConfigurationDialog::WingmanTab::save() +{ + // get LLM provider enum value from llmProvidersCombo + WingmanLlmProviders llmProvider = static_cast( + llmProvidersCombo->itemData(llmProvidersCombo->currentIndex()).toInt()); + config.setWingmanLlmProvider(llmProvider); + config.setWingmanOpenAiApiKey(openAiApiKeyEdit->text().toStdString()); +} + /* * Navigator tab */ diff --git a/app/src/qt/dialogs/configuration_dialog.h b/app/src/qt/dialogs/configuration_dialog.h index b70de021..203d27d5 100644 --- a/app/src/qt/dialogs/configuration_dialog.h +++ b/app/src/qt/dialogs/configuration_dialog.h @@ -1,7 +1,7 @@ /* configuration_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -38,6 +38,7 @@ class ConfigurationDialog : public QDialog class MarkdownTab; class NavigatorTab; class MindTab; + class WingmanTab; private: QTabWidget* tabWidget; @@ -47,6 +48,7 @@ class ConfigurationDialog : public QDialog MarkdownTab* markdownTab; NavigatorTab* navigatorTab; MindTab* mindTab; + WingmanTab* wingmanTab; QDialogButtonBox *buttonBox; @@ -64,10 +66,43 @@ class ConfigurationDialog : public QDialog private slots: void saveSlot(); + signals: void saveConfigSignal(); }; +/** + * @brief Wingman tab. + */ +class ConfigurationDialog::WingmanTab : public QWidget +{ + Q_OBJECT + +private: + const std::string openAiComboLabel; + + Configuration& config; + + QLabel* llmProvidersLabel; + QComboBox* llmProvidersCombo; + + QLabel* llmHelpLabel; + QLineEdit* openAiApiKeyEdit; + QPushButton* clearOpenAiApiKeyButton; + +public: + explicit WingmanTab(QWidget* parent); + ~WingmanTab(); + + // there and back is handled by Dialog's access to this class & Config singleton + void refresh(); + void save(); + +private slots: + void handleComboBoxChanged(int index); + void clearOpenAiApiKeySlot(); +}; + /** * @brief Mind tab. */ @@ -103,8 +138,12 @@ class ConfigurationDialog::AppTab : public QWidget Configuration& config; QLabel* themeLabel; + QLabel* menuLabel; QComboBox* themeCombo; + QLabel* appFontSizeLabel; + QSpinBox* appFontSizeSpin; + QLabel* startupLabel; QComboBox* startupCombo; diff --git a/app/src/qt/dialogs/export_csv_file_dialog.cpp b/app/src/qt/dialogs/export_csv_file_dialog.cpp index 608bdf6e..194e330c 100644 --- a/app/src/qt/dialogs/export_csv_file_dialog.cpp +++ b/app/src/qt/dialogs/export_csv_file_dialog.cpp @@ -1,7 +1,7 @@ /* export_csv_file_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/export_csv_file_dialog.h b/app/src/qt/dialogs/export_csv_file_dialog.h index 3178705b..c92b3704 100644 --- a/app/src/qt/dialogs/export_csv_file_dialog.h +++ b/app/src/qt/dialogs/export_csv_file_dialog.h @@ -1,7 +1,7 @@ /* export_csv_file_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/export_file_dialog.cpp b/app/src/qt/dialogs/export_file_dialog.cpp index b8a7d609..93b36888 100644 --- a/app/src/qt/dialogs/export_file_dialog.cpp +++ b/app/src/qt/dialogs/export_file_dialog.cpp @@ -1,7 +1,7 @@ /* export_file_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/export_file_dialog.h b/app/src/qt/dialogs/export_file_dialog.h index 8d82cc23..5c155cd5 100644 --- a/app/src/qt/dialogs/export_file_dialog.h +++ b/app/src/qt/dialogs/export_file_dialog.h @@ -1,7 +1,7 @@ /* export_file_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/find_note_by_name_dialog.cpp b/app/src/qt/dialogs/find_note_by_name_dialog.cpp index ebe8d5d1..d81dd2d6 100644 --- a/app/src/qt/dialogs/find_note_by_name_dialog.cpp +++ b/app/src/qt/dialogs/find_note_by_name_dialog.cpp @@ -1,7 +1,7 @@ /* find_note_by_name_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/find_note_by_name_dialog.h b/app/src/qt/dialogs/find_note_by_name_dialog.h index 63f37729..e7edf7fe 100644 --- a/app/src/qt/dialogs/find_note_by_name_dialog.h +++ b/app/src/qt/dialogs/find_note_by_name_dialog.h @@ -1,7 +1,7 @@ /* find_note_by_name_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/find_note_by_tag_dialog.cpp b/app/src/qt/dialogs/find_note_by_tag_dialog.cpp index 69fb90dc..78c90cb9 100644 --- a/app/src/qt/dialogs/find_note_by_tag_dialog.cpp +++ b/app/src/qt/dialogs/find_note_by_tag_dialog.cpp @@ -1,7 +1,7 @@ /* find_note_by_tag_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -31,7 +31,7 @@ FindNoteByTagDialog::FindNoteByTagDialog(Ontology& ontology, QWidget *parent) outlinesGroup->setTitle(tr("Notes:")); editTagsGroup->setTitle(tr("Note tags:")); switchOutlineNoteDialogsButton->setText(tr("Find Notebook")); - findButton->setText(tr("&Open Note")); + findButton->setText(tr("&Open Note")); // dialog setWindowTitle(tr("Find Note by Tags")); diff --git a/app/src/qt/dialogs/find_note_by_tag_dialog.h b/app/src/qt/dialogs/find_note_by_tag_dialog.h index 0370b31d..01d4deea 100644 --- a/app/src/qt/dialogs/find_note_by_tag_dialog.h +++ b/app/src/qt/dialogs/find_note_by_tag_dialog.h @@ -1,7 +1,7 @@ /* find_note_by_tag_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/find_outline_by_name_dialog.cpp b/app/src/qt/dialogs/find_outline_by_name_dialog.cpp index a9f535ee..e5a82b52 100644 --- a/app/src/qt/dialogs/find_outline_by_name_dialog.cpp +++ b/app/src/qt/dialogs/find_outline_by_name_dialog.cpp @@ -1,7 +1,7 @@ /* find_outline_by_name_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/find_outline_by_name_dialog.h b/app/src/qt/dialogs/find_outline_by_name_dialog.h index 1407f1d3..10c049b3 100644 --- a/app/src/qt/dialogs/find_outline_by_name_dialog.h +++ b/app/src/qt/dialogs/find_outline_by_name_dialog.h @@ -1,7 +1,7 @@ /* find_outline_by_name_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/find_outline_by_tag_dialog.cpp b/app/src/qt/dialogs/find_outline_by_tag_dialog.cpp index 30fe9f69..c4f5b3e0 100644 --- a/app/src/qt/dialogs/find_outline_by_tag_dialog.cpp +++ b/app/src/qt/dialogs/find_outline_by_tag_dialog.cpp @@ -1,7 +1,7 @@ /* find_outline_by_tag.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -74,7 +74,7 @@ FindOutlineByTagDialog::FindOutlineByTagDialog(Ontology& ontology, QWidget *pare // signals QObject::connect(editTagsGroup, SIGNAL(signalTagSelectionChanged()), this, SLOT(handleTagsChanged())); - // dialog + // dialog setWindowTitle(tr("Find Notebook by Tags")); // height is set to make sure listview gets enough lines resize(fontMetrics().averageCharWidth()*55, fontMetrics().height()*30); @@ -88,7 +88,9 @@ FindOutlineByTagDialog::~FindOutlineByTagDialog() delete closeButton; } -void FindOutlineByTagDialog::show(vector& outlines, vector* tags, vector* customizedNames) +void FindOutlineByTagDialog::show( + vector& outlines, vector* tags, vector* customizedNames, const string& searchPhrase +) { choice = nullptr; // tags are changed > need to be refreshed @@ -122,7 +124,12 @@ void FindOutlineByTagDialog::show(vector& outlines, vector* editTagsGroup->slotAddTag(); } } - editTagsGroup->getLineEdit()->clear(); + + if(searchPhrase.size()) { + editTagsGroup->getLineEdit()->setText(QString::fromStdString(searchPhrase)); + } else { + editTagsGroup->getLineEdit()->clear(); + } editTagsGroup->getLineEdit()->setFocus(); QDialog::show(); } diff --git a/app/src/qt/dialogs/find_outline_by_tag_dialog.h b/app/src/qt/dialogs/find_outline_by_tag_dialog.h index 9316b6d7..6e874a80 100644 --- a/app/src/qt/dialogs/find_outline_by_tag_dialog.h +++ b/app/src/qt/dialogs/find_outline_by_tag_dialog.h @@ -1,7 +1,7 @@ /* find_outline_by_tag.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -74,7 +74,9 @@ class FindOutlineByTagDialog : public QDialog void show( std::vector& outlines, std::vector* tags=nullptr, - std::vector* customizedNames=nullptr); + std::vector* customizedNames=nullptr, + const std::string& searchPhrase="" + ); signals: void searchFinished(); diff --git a/app/src/qt/dialogs/fts_dialog.cpp b/app/src/qt/dialogs/fts_dialog.cpp index 8d5d78b8..df0cc98e 100644 --- a/app/src/qt/dialogs/fts_dialog.cpp +++ b/app/src/qt/dialogs/fts_dialog.cpp @@ -1,7 +1,7 @@ /* fts_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/fts_dialog.h b/app/src/qt/dialogs/fts_dialog.h index ca4a5129..f3d6b6e1 100644 --- a/app/src/qt/dialogs/fts_dialog.h +++ b/app/src/qt/dialogs/fts_dialog.h @@ -1,7 +1,7 @@ /* fts_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/fts_dialog_presenter.cpp b/app/src/qt/dialogs/fts_dialog_presenter.cpp index 6060c650..f3590333 100644 --- a/app/src/qt/dialogs/fts_dialog_presenter.cpp +++ b/app/src/qt/dialogs/fts_dialog_presenter.cpp @@ -1,7 +1,7 @@ /* fts_dialog_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/fts_dialog_presenter.h b/app/src/qt/dialogs/fts_dialog_presenter.h index e8ba0249..4eadd644 100644 --- a/app/src/qt/dialogs/fts_dialog_presenter.h +++ b/app/src/qt/dialogs/fts_dialog_presenter.h @@ -1,7 +1,7 @@ /* fts_dialog_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/insert_image_dialog.cpp b/app/src/qt/dialogs/insert_image_dialog.cpp index ea3bda75..a927b46a 100644 --- a/app/src/qt/dialogs/insert_image_dialog.cpp +++ b/app/src/qt/dialogs/insert_image_dialog.cpp @@ -1,7 +1,7 @@ /* insert_image_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -30,7 +30,7 @@ InsertImageDialog::InsertImageDialog(QWidget* parent) pathEdit = new QLineEdit{}; findFileButton = new QPushButton{tr("File")}; - copyToRepoCheckBox = new QCheckBox{tr("copy image to repository")}; + copyToRepoCheckBox = new QCheckBox{tr("copy image to workspace")}; copyToRepoCheckBox->setChecked(true); copyToRepoCheckBox->setEnabled(true); @@ -45,14 +45,14 @@ InsertImageDialog::InsertImageDialog(QWidget* parent) // assembly QVBoxLayout* mainLayout = new QVBoxLayout{}; - mainLayout->addWidget(alternateTextLabel); - mainLayout->addWidget(alternateTextEdit); - mainLayout->addWidget(pathLabel); - mainLayout->addWidget(pathEdit); QHBoxLayout* srcButtonLayout = new QHBoxLayout{}; srcButtonLayout->addWidget(findFileButton); srcButtonLayout->addStretch(); mainLayout->addLayout(srcButtonLayout); + mainLayout->addWidget(alternateTextLabel); + mainLayout->addWidget(alternateTextEdit); + mainLayout->addWidget(pathLabel); + mainLayout->addWidget(pathEdit); mainLayout->addWidget(copyToRepoCheckBox); QHBoxLayout* buttonLayout = new QHBoxLayout{}; @@ -77,8 +77,7 @@ InsertImageDialog::~InsertImageDialog() void InsertImageDialog::show() { alternateTextEdit->setText(tr("Image")); - alternateTextEdit->selectAll(); - alternateTextEdit->setFocus(); + findFileButton->setFocus(); pathEdit->clear(); QDialog::show(); diff --git a/app/src/qt/dialogs/insert_image_dialog.h b/app/src/qt/dialogs/insert_image_dialog.h index 12b226cd..21253c78 100644 --- a/app/src/qt/dialogs/insert_image_dialog.h +++ b/app/src/qt/dialogs/insert_image_dialog.h @@ -1,7 +1,7 @@ /* insert_image_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/insert_link_dialog.cpp b/app/src/qt/dialogs/insert_link_dialog.cpp index d933213c..14a42e3b 100644 --- a/app/src/qt/dialogs/insert_link_dialog.cpp +++ b/app/src/qt/dialogs/insert_link_dialog.cpp @@ -1,7 +1,7 @@ /* insert_link_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -31,12 +31,12 @@ InsertLinkDialog::InsertLinkDialog(QWidget* parent) pathLabel = new QLabel{tr("Notebook, Note, file path or web address:")}; pathEdit = new QLineEdit{}; - findOutlineButton = new QPushButton{tr("Notebook")}; - findNoteButton = new QPushButton{tr("Note")}; - findFileButton = new QPushButton{tr("File")}; - findDirectoryButton = new QPushButton{tr("Directory")}; + findOutlineButton = new QPushButton{tr("Note&book")}; + findNoteButton = new QPushButton{tr("&Note")}; + findFileButton = new QPushButton{tr("&File")}; + findDirectoryButton = new QPushButton{tr("&Directory")}; - copyToRepoCheckBox = new QCheckBox{tr("copy link target to repository")}; + copyToRepoCheckBox = new QCheckBox{tr("copy link target to workspace")}; copyToRepoCheckBox->setChecked(true); copyToRepoCheckBox->setEnabled(true); diff --git a/app/src/qt/dialogs/insert_link_dialog.h b/app/src/qt/dialogs/insert_link_dialog.h index 53799f73..2b6ab022 100644 --- a/app/src/qt/dialogs/insert_link_dialog.h +++ b/app/src/qt/dialogs/insert_link_dialog.h @@ -1,7 +1,7 @@ /* insert_link_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/ner_choose_tag_types_dialog.cpp b/app/src/qt/dialogs/ner_choose_tag_types_dialog.cpp deleted file mode 100644 index 61684e22..00000000 --- a/app/src/qt/dialogs/ner_choose_tag_types_dialog.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - ner_choose_tag_types_dialog.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "ner_choose_tag_types_dialog.h" - -namespace m8r { - -NerChooseTagTypesDialog::NerChooseTagTypesDialog(QWidget* parent) - : QDialog(parent) -{ - // widgets - label = new QLabel{tr("Choose entity types to be extracted:")}; - - personsCheckBox = new QCheckBox{tr("persons")}; - locationsCheckBox = new QCheckBox{tr("locations")}; - organizationsCheckBox = new QCheckBox{tr("organizations")}; - miscCheckBox = new QCheckBox{tr("other entities")}; - - chooseButton = new QPushButton{tr("&Choose")}; - chooseButton->setDefault(true); - - closeButton = new QPushButton{tr("&Cancel")}; - - // signals - connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); - connect(personsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotChooseButtonEnable(int))); - connect(locationsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotChooseButtonEnable(int))); - connect(organizationsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotChooseButtonEnable(int))); - connect(miscCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotChooseButtonEnable(int))); - - // assembly - QVBoxLayout* mainLayout = new QVBoxLayout{}; - mainLayout->addWidget(label); - mainLayout->addWidget(personsCheckBox); - mainLayout->addWidget(locationsCheckBox); - mainLayout->addWidget(organizationsCheckBox); - mainLayout->addWidget(miscCheckBox); - - QHBoxLayout* buttonLayout = new QHBoxLayout{}; - buttonLayout->addStretch(1); - buttonLayout->addWidget(closeButton); - buttonLayout->addWidget(chooseButton); - buttonLayout->addStretch(); - - mainLayout->addLayout(buttonLayout); - setLayout(mainLayout); - - // dialog - setWindowTitle(tr("Choose Entity Type")); - resize(fontMetrics().averageCharWidth()*35, height()); - setModal(true); -} - -NerChooseTagTypesDialog::~NerChooseTagTypesDialog() -{ -} - -void NerChooseTagTypesDialog::slotChooseButtonEnable(int state) -{ - UNUSED_ARG(state); - - if(personsCheckBox->isChecked() || locationsCheckBox->isChecked() || organizationsCheckBox->isChecked() || miscCheckBox->isChecked()) { - chooseButton->setEnabled(true); - } else { - chooseButton->setEnabled(false); - } -} - -} // m8r namespace diff --git a/app/src/qt/dialogs/ner_choose_tag_types_dialog.h b/app/src/qt/dialogs/ner_choose_tag_types_dialog.h deleted file mode 100644 index 79279897..00000000 --- a/app/src/qt/dialogs/ner_choose_tag_types_dialog.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - ner_choose_tag_types_dialog.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8RUI_NER_CHOOSE_TAG_TYPES_DIALOG_H -#define M8RUI_NER_CHOOSE_TAG_TYPES_DIALOG_H - -#include - -#include "../../lib/src/gear/lang_utils.h" -#include "../../lib/src/debug.h" - -namespace m8r { - -class NerChooseTagTypesDialog : public QDialog -{ - Q_OBJECT - -private: - QLabel* label; - // IMPROVE tag types are hardcoded - allow loading them dynamically for generic NER models - QCheckBox* personsCheckBox; - QCheckBox* locationsCheckBox; - QCheckBox* organizationsCheckBox; - QCheckBox* miscCheckBox; - QPushButton* chooseButton; - QPushButton* closeButton; - -public: - explicit NerChooseTagTypesDialog(QWidget* parent); - NerChooseTagTypesDialog(const NerChooseTagTypesDialog&) = delete; - NerChooseTagTypesDialog(const NerChooseTagTypesDialog&&) = delete; - NerChooseTagTypesDialog &operator=(const NerChooseTagTypesDialog&) = delete; - NerChooseTagTypesDialog &operator=(const NerChooseTagTypesDialog&&) = delete; - ~NerChooseTagTypesDialog(); - - void clearCheckboxes() { - personsCheckBox->setChecked(false); - locationsCheckBox->setChecked(false); - organizationsCheckBox->setChecked(false); - miscCheckBox->setChecked(false); - } - - QCheckBox* getPersonsCheckbox() const { return personsCheckBox; } - QCheckBox* getLocationsCheckbox() const { return locationsCheckBox; } - QCheckBox* getOrganizationsCheckbox() const { return organizationsCheckBox; } - QCheckBox* getMiscCheckbox() const { return miscCheckBox; } - - QPushButton* getChooseButton() const { return chooseButton; } - - void show() { slotChooseButtonEnable(0); QDialog::show(); } - -private slots: - void slotChooseButtonEnable(int); -}; - -} -#endif // M8RUI_NER_CHOOSE_TAG_TYPES_DIALOG_H diff --git a/app/src/qt/dialogs/ner_result_dialog.cpp b/app/src/qt/dialogs/ner_result_dialog.cpp deleted file mode 100644 index df6b8368..00000000 --- a/app/src/qt/dialogs/ner_result_dialog.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - ner_result_dialog.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "ner_result_dialog.h" - -namespace m8r { - -using namespace std; - -NerResultDialog::NerResultDialog(QWidget* parent) - : QDialog(parent) -{ - // widgets - leaderboardModel = new NerLeaderboardModel(this); - leaderboardView = new NerLeaderboardView(this); - leaderboardView->setModel(leaderboardModel); - - label = new QLabel{tr("Recognized named entities:")}; - - findButton = new QPushButton{tr("&Find Entity in Notes")}; - findButton->setDefault(true); - findButton->setEnabled(false); - - closeButton = new QPushButton{tr("&Cancel")}; - - // signals - QObject::connect(findButton, SIGNAL(clicked()), this, SLOT(handleChoice())); - QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); - QObject::connect( - leaderboardView->selectionModel(), - SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), - this, - SLOT(slotRowSelected(const QItemSelection&, const QItemSelection&))); - - // assembly - QVBoxLayout *mainLayout = new QVBoxLayout{}; - mainLayout->addWidget(label); - mainLayout->addWidget(leaderboardView); - - QHBoxLayout *buttonLayout = new QHBoxLayout{}; - buttonLayout->addStretch(1); - buttonLayout->addWidget(closeButton); - buttonLayout->addWidget(findButton); - buttonLayout->addStretch(); - - mainLayout->addLayout(buttonLayout); - setLayout(mainLayout); - - // dialog - setWindowTitle(tr("Find Named Entities")); - // height is set to make sure listview gets enough lines - resize(fontMetrics().averageCharWidth()*75, fontMetrics().height()*30); - setModal(true); -} - -NerResultDialog::~NerResultDialog() -{ - delete label; - delete leaderboardView; - delete leaderboardModel; - delete closeButton; -} - -void NerResultDialog::show(std::vector& entities) -{ - choice.clear(); - leaderboardModel->removeAllRows(); - - if(entities.size()) { - for(NerNamedEntity& e:entities) { - leaderboardModel->addRow(e.name, e.type, e.score); - } - } - - QDialog::show(); - - leaderboardView->sortByColumn(2, Qt::SortOrder::DescendingOrder); -} - -void NerResultDialog::handleChoice() -{ - QDialog::close(); - emit choiceFinished(); -} - -void NerResultDialog::slotRowSelected(const QItemSelection& selected, const QItemSelection& deselected) -{ - Q_UNUSED(deselected); - - QModelIndexList indices = selected.indexes(); - if(indices.size()) { - const QModelIndex& index = indices.at(0); - QStandardItem* item = leaderboardModel->itemFromIndex(index); - choice = item->text().toStdString(); - if(choice.size()) { - findButton->setEnabled(true); - } else { - findButton->setEnabled(false); - } - } -} - -} // m8r namespace diff --git a/app/src/qt/dialogs/ner_result_dialog.h b/app/src/qt/dialogs/ner_result_dialog.h deleted file mode 100644 index f9e29ace..00000000 --- a/app/src/qt/dialogs/ner_result_dialog.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - ner_result_dialog.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8RUI_NER_RESULT_DIALOG_H -#define M8RUI_NER_RESULT_DIALOG_H - -#include - -#include "../../../../lib/src/mind/ai/nlp/ner_named_entity.h" - -#include "../ner_leaderboard_model.h" -#include "../ner_leaderboard_view.h" - -#include "../../../../lib/src/debug.h" - -namespace m8r { - -class NerResultDialog : public QDialog -{ - Q_OBJECT - -private: - std::string choice; - - QLabel* label; - NerLeaderboardModel* leaderboardModel; - NerLeaderboardView* leaderboardView; - QPushButton* closeButton; - QPushButton* findButton; - -public: - explicit NerResultDialog(QWidget* parent); - NerResultDialog(const NerResultDialog&) = delete; - NerResultDialog(const NerResultDialog&&) = delete; - NerResultDialog &operator=(const NerResultDialog&) = delete; - NerResultDialog &operator=(const NerResultDialog&&) = delete; - ~NerResultDialog(); - - QPushButton* getFindButton() const { return findButton; } - std::string getChoice() const { return choice; } - - void show(std::vector& entities); - -signals: - void choiceFinished(); - -private slots: - void handleChoice(); - void slotRowSelected(const QItemSelection& selected, const QItemSelection& deselected); -}; - -} -#endif // M8RUI_NER_RESULT_DIALOG_H diff --git a/app/src/qt/dialogs/new_file_dialog.cpp b/app/src/qt/dialogs/new_file_dialog.cpp index 330174ce..fa571ef9 100644 --- a/app/src/qt/dialogs/new_file_dialog.cpp +++ b/app/src/qt/dialogs/new_file_dialog.cpp @@ -1,7 +1,7 @@ /* new_file_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/new_file_dialog.h b/app/src/qt/dialogs/new_file_dialog.h index af5c5e68..0c4857e9 100644 --- a/app/src/qt/dialogs/new_file_dialog.h +++ b/app/src/qt/dialogs/new_file_dialog.h @@ -1,7 +1,7 @@ /* new_file_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/new_repository_dialog.cpp b/app/src/qt/dialogs/new_repository_dialog.cpp index 7b3c62d1..c271c22a 100644 --- a/app/src/qt/dialogs/new_repository_dialog.cpp +++ b/app/src/qt/dialogs/new_repository_dialog.cpp @@ -1,7 +1,7 @@ /* new_repository_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,14 +23,16 @@ namespace m8r { NewRepositoryDialog::NewRepositoryDialog(QWidget* parent) : QDialog(parent) { - homeDirectory = QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory); + homeDirectory = QStandardPaths::locate( + QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory + ); // widgets - repositoryNameLabel = new QLabel{tr("Repository name:")}; + repositoryNameLabel = new QLabel{tr("Workspace name:")}; repositoryNameEdit = new QLineEdit{}; - dirLabel = new QLabel{tr("Repository directory:")}; + dirLabel = new QLabel{tr("Workspace directory:")}; dirEdit = new QLineEdit{}; - pathLabel = new QLabel{tr("Repository to be created in:")}; + pathLabel = new QLabel{tr("Workspace to be created in:")}; pathEdit = new QLineEdit{}; pathEdit->setEnabled(false); @@ -45,11 +47,26 @@ NewRepositoryDialog::NewRepositoryDialog(QWidget* parent) closeButton = new QPushButton{tr("&Cancel")}; // signals - QObject::connect(repositoryNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(refreshPath())); - QObject::connect(dirEdit, SIGNAL(textChanged(const QString&)), this, SLOT(refreshPath())); - QObject::connect(findDirectoryButton, SIGNAL(clicked()), this, SLOT(handleFindDirectory())); - QObject::connect(newButton, SIGNAL(clicked()), this, SLOT(close())); - QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); + QObject::connect( + repositoryNameEdit, SIGNAL(textChanged(const QString&)), + this, SLOT(refreshPath()) + ); + QObject::connect( + dirEdit, SIGNAL(textChanged(const QString&)), + this, SLOT(refreshPath()) + ); + QObject::connect( + findDirectoryButton, SIGNAL(clicked()), + this, SLOT(handleFindDirectory()) + ); + QObject::connect( + newButton, SIGNAL(clicked()), + this, SLOT(close()) + ); + QObject::connect( + closeButton, SIGNAL(clicked()), + this, SLOT(close()) + ); // assembly QVBoxLayout* mainLayout = new QVBoxLayout{}; @@ -76,7 +93,7 @@ NewRepositoryDialog::NewRepositoryDialog(QWidget* parent) setLayout(mainLayout); // dialog - setWindowTitle(tr("Create New Repository")); + setWindowTitle(tr("Create New Workspace")); resize(fontMetrics().averageCharWidth()*60, height()); setModal(true); } @@ -87,7 +104,7 @@ NewRepositoryDialog::~NewRepositoryDialog() void NewRepositoryDialog::show() { - repositoryNameEdit->setText(tr("mindforger-repository")); + repositoryNameEdit->setText(tr("mindforger-workspace")); repositoryNameEdit->selectAll(); repositoryNameEdit->setFocus(); dirEdit->setText(homeDirectory); @@ -105,7 +122,9 @@ void NewRepositoryDialog::refreshPath() // dir QString directory{dirEdit->text()}; if(directory.isEmpty()) { - directory = QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory); + directory = QStandardPaths::locate( + QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory + ); } if(!directory.endsWith(FILE_PATH_SEPARATOR)) { directory.append(FILE_PATH_SEPARATOR); @@ -113,7 +132,7 @@ void NewRepositoryDialog::refreshPath() // name QString name{repositoryNameEdit->text()}; if(name.isEmpty()) { - name = tr("mindforger-repository"); + name = tr("mindforger-workspace"); } else { name = QString::fromStdString(normalizeToNcName(name.toStdString(),'-')); } @@ -126,7 +145,9 @@ void NewRepositoryDialog::refreshPath() void NewRepositoryDialog::handleFindDirectory() { QString homeDirectory - = QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory); + = QStandardPaths::locate( + QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory + ); QFileDialog fileDialog{this}; fileDialog.setWindowTitle(tr("Choose Directory")); diff --git a/app/src/qt/dialogs/new_repository_dialog.h b/app/src/qt/dialogs/new_repository_dialog.h index 5591939d..316289ba 100644 --- a/app/src/qt/dialogs/new_repository_dialog.h +++ b/app/src/qt/dialogs/new_repository_dialog.h @@ -1,7 +1,7 @@ /* new_repository_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/note_edit_dialog.cpp b/app/src/qt/dialogs/note_edit_dialog.cpp index c89ee77e..c3fd1c5b 100644 --- a/app/src/qt/dialogs/note_edit_dialog.cpp +++ b/app/src/qt/dialogs/note_edit_dialog.cpp @@ -1,7 +1,7 @@ /* note_edit_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/note_edit_dialog.h b/app/src/qt/dialogs/note_edit_dialog.h index 4231387d..db407401 100644 --- a/app/src/qt/dialogs/note_edit_dialog.h +++ b/app/src/qt/dialogs/note_edit_dialog.h @@ -1,7 +1,7 @@ /* note_edit_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/note_new_dialog.cpp b/app/src/qt/dialogs/note_new_dialog.cpp index e0eacb94..0a1c16ce 100644 --- a/app/src/qt/dialogs/note_new_dialog.cpp +++ b/app/src/qt/dialogs/note_new_dialog.cpp @@ -1,7 +1,7 @@ /* note_new_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -34,6 +34,8 @@ NoteNewDialog::GeneralTab::GeneralTab(Ontology& ontology, QWidget *parent) nameLabel = new QLabel(tr("Name")+":", this), nameEdit = new QLineEdit(tr("Note"), this); + emojisButton = new QPushButton(tr("&Emojis"), this); + // moving edit tags to this position changes TAB ORDER ~ it's selected as 2nd field editTagsGroup = new EditTagsPanel{MfWidgetMode::CREATE_MODE, ontology, this}; editTagsGroup->refreshOntologyTags(); @@ -58,7 +60,13 @@ NoteNewDialog::GeneralTab::GeneralTab(Ontology& ontology, QWidget *parent) // assembly QVBoxLayout* basicLayout = new QVBoxLayout{this}; basicLayout->addWidget(nameLabel); - basicLayout->addWidget(nameEdit); + + QWidget* eji = new QWidget{this}; + QHBoxLayout* nameLayout = new QHBoxLayout{eji}; + nameLayout->addWidget(nameEdit); + nameLayout->addWidget(emojisButton); + basicLayout->addWidget(eji); + basicLayout->addWidget(positionLabel); basicLayout->addWidget(positionCombo); basicLayout->addWidget(viewEditLabel); @@ -231,6 +239,11 @@ int NoteNewDialog::getProgress() const return generalTab->getProgressSpin()->value(); } +QPushButton* NoteNewDialog::getEmojisButton() const +{ + return generalTab->getEmojisButton(); +} + void NoteNewDialog::show( const QString& path, vector& stencils, diff --git a/app/src/qt/dialogs/note_new_dialog.h b/app/src/qt/dialogs/note_new_dialog.h index 87e16474..4de43ff9 100644 --- a/app/src/qt/dialogs/note_new_dialog.h +++ b/app/src/qt/dialogs/note_new_dialog.h @@ -1,7 +1,7 @@ /* note_new_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -50,7 +50,7 @@ class NoteNewDialog : public QDialog GeneralTab* generalTab; AdvancedTab* advancedTab; - QDialogButtonBox *buttonBox; + QDialogButtonBox* buttonBox; public: explicit NoteNewDialog(Ontology& ontology, QWidget* parent); @@ -65,6 +65,7 @@ class NoteNewDialog : public QDialog const NoteType* getNoteType() const; const std::vector& getTags() const; int getProgress() const; + QPushButton* getEmojisButton() const; bool isPositionBelow() const; bool isPositionAbove() const { return !isPositionBelow(); } bool isOpenInEditor() const; @@ -88,6 +89,7 @@ class NoteNewDialog::GeneralTab : public QWidget QLabel* nameLabel; QLineEdit* nameEdit; + QPushButton* emojisButton; QLabel* typeLabel; QComboBox* typeCombo; QLabel* progressLabel; @@ -109,6 +111,7 @@ class NoteNewDialog::GeneralTab : public QWidget QComboBox* getTypeCombo() const { return typeCombo; } const std::vector& getTags() { return editTagsGroup->getTags(); } QSpinBox* getProgressSpin() const { return progressSpin; } + QPushButton* getEmojisButton() const { return emojisButton; } QComboBox* getStencilCombo() const { return stencilCombo; } QComboBox* getPositionCombo() const { return positionCombo; } QComboBox* getViewEditCombo() const { return viewEditCombo; } diff --git a/app/src/qt/dialogs/organizer_new_dialog.cpp b/app/src/qt/dialogs/organizer_new_dialog.cpp index 1c0acf41..26ab28bc 100644 --- a/app/src/qt/dialogs/organizer_new_dialog.cpp +++ b/app/src/qt/dialogs/organizer_new_dialog.cpp @@ -1,7 +1,7 @@ /* new_organizer_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -142,7 +142,7 @@ OrganizerNewDialog::OrganizerNewDialog(Ontology& ontology, QWidget* parent) this, SLOT(handleChangeTypeCombo(QString)) ); - // dialog + // dialog setWindowTitle(tr("New Organizer")); // make dialog big enough (FTS dialog based size) resize(fontMetrics().averageCharWidth()*90, fontMetrics().height()*35); diff --git a/app/src/qt/dialogs/organizer_new_dialog.h b/app/src/qt/dialogs/organizer_new_dialog.h index 9d27665b..1a4fc2d4 100644 --- a/app/src/qt/dialogs/organizer_new_dialog.h +++ b/app/src/qt/dialogs/organizer_new_dialog.h @@ -1,7 +1,7 @@ /* organizer_new_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -118,7 +118,7 @@ class OrganizerNewDialog : public QDialog std::set& getLowerRightChosenTags(std::set& tags) const { return lowerRightTags->getTagsAsStringSet(tags); } - int getFilterBy() const { + int getFilterBy() const { return this->filterByCombo->currentData().toInt(); } int getSortBy() const { diff --git a/app/src/qt/dialogs/outline_header_edit_dialog.cpp b/app/src/qt/dialogs/outline_header_edit_dialog.cpp index 1036fee6..12fcf3f3 100644 --- a/app/src/qt/dialogs/outline_header_edit_dialog.cpp +++ b/app/src/qt/dialogs/outline_header_edit_dialog.cpp @@ -1,7 +1,7 @@ /* outline_header_edit_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/outline_header_edit_dialog.h b/app/src/qt/dialogs/outline_header_edit_dialog.h index d484e00b..18e06661 100644 --- a/app/src/qt/dialogs/outline_header_edit_dialog.h +++ b/app/src/qt/dialogs/outline_header_edit_dialog.h @@ -1,7 +1,7 @@ /* outline_header_edit_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/outline_new_dialog.cpp b/app/src/qt/dialogs/outline_new_dialog.cpp index 1d04e06a..c6f81f08 100644 --- a/app/src/qt/dialogs/outline_new_dialog.cpp +++ b/app/src/qt/dialogs/outline_new_dialog.cpp @@ -1,7 +1,7 @@ /* outline_new_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -35,6 +35,8 @@ OutlineNewDialog::GeneralTab::GeneralTab(Ontology& ontology, QWidget *parent) nameLabel = new QLabel(tr("Name")+":", this); nameEdit = new QLineEdit(tr("Notebook"), this); + emojisButton = new QPushButton(tr("&Emojis"), this); + typeLabel = new QLabel(tr("Type")+":", this); typeCombo = new QComboBox{this}; @@ -58,7 +60,13 @@ OutlineNewDialog::GeneralTab::GeneralTab(Ontology& ontology, QWidget *parent) // assembly QVBoxLayout* basicLayout = new QVBoxLayout{this}; basicLayout->addWidget(nameLabel); - basicLayout->addWidget(nameEdit); + + QWidget* eji = new QWidget{this}; + QHBoxLayout* nameLayout = new QHBoxLayout{eji}; + nameLayout->addWidget(nameEdit); + nameLayout->addWidget(emojisButton); + basicLayout->addWidget(eji); + basicLayout->addWidget(typeLabel); basicLayout->addWidget(typeCombo); QWidget* wiu = new QWidget{this}; @@ -302,6 +310,11 @@ int OutlineNewDialog::getProgress() const return generalTab->getProgressSpin()->value(); } +QPushButton* OutlineNewDialog::getEmojisButton() const +{ + return generalTab->getEmojisButton(); +} + const std::vector& OutlineNewDialog::getTags() const { return generalTab->getTags(); diff --git a/app/src/qt/dialogs/outline_new_dialog.h b/app/src/qt/dialogs/outline_new_dialog.h index 39aa332c..8332d177 100644 --- a/app/src/qt/dialogs/outline_new_dialog.h +++ b/app/src/qt/dialogs/outline_new_dialog.h @@ -1,7 +1,7 @@ /* outline_new_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -73,6 +73,7 @@ class OutlineNewDialog : public QDialog int8_t getImportance() const; int8_t getUrgency() const; int getProgress() const; + QPushButton* getEmojisButton() const; const std::vector& getTags() const; void show( @@ -96,6 +97,7 @@ class OutlineNewDialog::GeneralTab : public QWidget QLabel* nameLabel; QLineEdit* nameEdit; + QPushButton* emojisButton; QLabel* typeLabel; QComboBox* typeCombo; QLabel* importanceLabel; @@ -119,6 +121,7 @@ class OutlineNewDialog::GeneralTab : public QWidget UrgencyComboBox* getUrgencyCombo() const { return urgencyCombo; } QComboBox* getStencilCombo() const { return stencilCombo; } QSpinBox* getProgressSpin() const { return progressSpin; } + QPushButton* getEmojisButton() const { return emojisButton; } const std::vector& getTags() { return editTagsGroup->getTags(); } void showFacet(Repository::RepositoryType repositoryType); diff --git a/app/src/qt/dialogs/refactor_note_to_outline_dialog.cpp b/app/src/qt/dialogs/refactor_note_to_outline_dialog.cpp index 4d7cff02..94ae4d26 100644 --- a/app/src/qt/dialogs/refactor_note_to_outline_dialog.cpp +++ b/app/src/qt/dialogs/refactor_note_to_outline_dialog.cpp @@ -1,7 +1,7 @@ /* refactor_note_to_outline_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -26,7 +26,7 @@ RefactorNoteToOutlineDialog::RefactorNoteToOutlineDialog(QWidget *parent) findButton->setText(tr("Refactor")); // dialog - setWindowTitle(tr("Refactor Note to Notebook")); + setWindowTitle(tr("Move Note to Notebook")); } RefactorNoteToOutlineDialog::~RefactorNoteToOutlineDialog() diff --git a/app/src/qt/dialogs/refactor_note_to_outline_dialog.h b/app/src/qt/dialogs/refactor_note_to_outline_dialog.h index 1fd64bc1..08c13ffb 100644 --- a/app/src/qt/dialogs/refactor_note_to_outline_dialog.h +++ b/app/src/qt/dialogs/refactor_note_to_outline_dialog.h @@ -1,7 +1,7 @@ /* refactor_note_to_outline_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/rm_library_dialog.cpp b/app/src/qt/dialogs/rm_library_dialog.cpp new file mode 100644 index 00000000..51bec0d9 --- /dev/null +++ b/app/src/qt/dialogs/rm_library_dialog.cpp @@ -0,0 +1,111 @@ +/* + sync_library_dialog.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "rm_library_dialog.h" + +using namespace std; + +namespace m8r { + +RemoveLibraryDialog::RemoveLibraryDialog(QWidget* parent) + : QDialog(parent), + libsToRemove() +{ + // widgets + findLibrarySourceLabel = new QLabel{ + tr( + "Choose a library to be removed - this action will delete\n" + "Notebooks which represent documents from the library\n" + "directory.\n" + "Referenced documents will NOT be deleted.\n" + ), + parent}; + + librariesLabel = new QLabel{tr("Choose library to delete: ")}; + libraryPathsCombo = new QComboBox{this}; + + // IMPROVE disable/enable find button if text/path is valid: freedom vs validation + rmButton = new QPushButton{tr("&Delete")}; + rmButton->setDefault(true); + closeButton = new QPushButton{tr("&Cancel")}; + + // signals + QObject::connect( + closeButton, SIGNAL(clicked()), + this, SLOT(close())); + + // assembly + QVBoxLayout* mainLayout = new QVBoxLayout{}; + mainLayout->addWidget(findLibrarySourceLabel); + mainLayout->addWidget(librariesLabel); + mainLayout->addWidget(libraryPathsCombo); + + QHBoxLayout* buttonLayout = new QHBoxLayout{}; + buttonLayout->addStretch(1); + buttonLayout->addWidget(closeButton); + buttonLayout->addWidget(rmButton); + buttonLayout->addStretch(); + + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + // dialog + setWindowTitle(tr("Delete Document Library")); + resize(fontMetrics().averageCharWidth()*55, height()); + setModal(true); +} + +void RemoveLibraryDialog::addLibraryToRemove(FilesystemInformationSource* libSrc) +{ + libsToRemove.push_back(libSrc); + libraryPathsCombo->addItem(QString::fromStdString(libSrc->getPath())); +} + +RemoveLibraryDialog::~RemoveLibraryDialog() +{ + delete findLibrarySourceLabel; + delete librariesLabel; + delete libraryPathsCombo; + delete rmButton; + delete closeButton; +} + +void RemoveLibraryDialog::reset() { + libraryPathsCombo->clear(); + for(FilesystemInformationSource* libToRemove:libsToRemove) { + delete libToRemove; + } + libsToRemove.clear(); +} + +string RemoveLibraryDialog::getLibraryMfPathForLocator(string& locator) { + for(FilesystemInformationSource* libToRemove:libsToRemove) { + if(locator == libToRemove->getPath()) { + return libToRemove->getMfPath(); + } + } + + return string{}; +} + +void RemoveLibraryDialog::show() +{ + QDialog::show(); +} + +} // m8r namespace diff --git a/app/src/qt/dialogs/rm_library_dialog.h b/app/src/qt/dialogs/rm_library_dialog.h new file mode 100644 index 00000000..43fab3e2 --- /dev/null +++ b/app/src/qt/dialogs/rm_library_dialog.h @@ -0,0 +1,69 @@ +/* +rm_library_dialog.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_RM_LIBRARY_DIALOG_H +#define M8RUI_RM_LIBRARY_DIALOG_H + +#include + +#include "../../lib/src/model/outline.h" +#include "../../lib/src/config/repository.h" +#include "../../lib/src/mind/dikw/filesystem_information.h" + +#include + +namespace m8r { + +/** + * @brief Synchronize document library dialog. + * + * The dialog is instantiated in main window presenter. + */ +class RemoveLibraryDialog : public QDialog +{ + Q_OBJECT + +private: + QLabel* findLibrarySourceLabel; + QLabel* librariesLabel; + QComboBox* libraryPathsCombo; + + QPushButton* rmButton; + QPushButton* closeButton; + + std::vector libsToRemove; + +public: + explicit RemoveLibraryDialog(QWidget* parent); + RemoveLibraryDialog(const RemoveLibraryDialog&) = delete; + RemoveLibraryDialog(const RemoveLibraryDialog&&) = delete; + RemoveLibraryDialog& operator=(const RemoveLibraryDialog&) = delete; + RemoveLibraryDialog& operator=(const RemoveLibraryDialog&&) = delete; + ~RemoveLibraryDialog(); + + void reset(); + std::string getLibraryMfPathForLocator(std::string& locator); + void show(); + + QPushButton* getRemoveButton() const { return rmButton; } + QComboBox* getLibraryPathsCombo() const { return libraryPathsCombo; } + void addLibraryToRemove(FilesystemInformationSource* libSrc); +}; + +} +#endif // M8RUI_RM_LIBRARY_DIALOG_H diff --git a/app/src/qt/dialogs/rows_and_depth_dialog.cpp b/app/src/qt/dialogs/rows_and_depth_dialog.cpp index fbccc850..9a4059e1 100644 --- a/app/src/qt/dialogs/rows_and_depth_dialog.cpp +++ b/app/src/qt/dialogs/rows_and_depth_dialog.cpp @@ -1,7 +1,7 @@ /* rows_and_depth_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/rows_and_depth_dialog.h b/app/src/qt/dialogs/rows_and_depth_dialog.h index 18150135..83c4f67a 100644 --- a/app/src/qt/dialogs/rows_and_depth_dialog.h +++ b/app/src/qt/dialogs/rows_and_depth_dialog.h @@ -1,7 +1,7 @@ /* rows_and_depth_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/run_tool_dialog.cpp b/app/src/qt/dialogs/run_tool_dialog.cpp new file mode 100644 index 00000000..dae204be --- /dev/null +++ b/app/src/qt/dialogs/run_tool_dialog.cpp @@ -0,0 +1,146 @@ +/* + run_tool_dialog.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "run_tool_dialog.h" + +namespace m8r { + +using namespace std; + +RunToolDialog::RunToolDialog(QWidget* parent) + : QDialog(parent) +{ + // UI + phraseLabel = new QLabel{tr("Phrase:"), parent}; + phraseEdit = new QLineEdit{parent}; + + toolLabel = new QLabel{tr("Knowledge source:"), parent}; + toolCombo = new QComboBox{this}; + for(string toolId: KnowledgeTool::getToolIds()) { + toolCombo->addItem( + getToolNameForToolId(toolId), + QString::fromStdString(toolId)); + } + + templateLabel = new QLabel{tr("Template:"), parent}; + templateEdit = new QLineEdit{parent}; + + // IMPROVE disable/enable find button if text/path is valid: freedom vs validation + runButton = new QPushButton{tr("&Lookup")}; + runButton->setDefault(true); + closeButton = new QPushButton{tr("&Cancel")}; + + // signals + QObject::connect( + closeButton, SIGNAL(clicked()), + this, SLOT(close())); + + // assembly + QVBoxLayout* mainLayout = new QVBoxLayout{}; + mainLayout->addWidget(phraseLabel); + mainLayout->addWidget(phraseEdit); + mainLayout->addWidget(toolLabel); + mainLayout->addWidget(toolCombo); + mainLayout->addWidget(templateLabel); + mainLayout->addWidget(templateEdit); + + QHBoxLayout* buttonLayout = new QHBoxLayout{}; + buttonLayout->addStretch(1); + buttonLayout->addWidget(closeButton); + buttonLayout->addWidget(runButton); + buttonLayout->addStretch(); + + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + // signals + QObject::connect( + toolCombo, SIGNAL(currentIndexChanged(QString)), + this, SLOT(handleChangeToolCombo(QString)) + ); + + // dialog + setWindowTitle(tr("Lookup Knowledge")); + resize(fontMetrics().averageCharWidth()*55, height()); + setModal(true); +} + +RunToolDialog::~RunToolDialog() +{ +} + +QString RunToolDialog::getToolNameForToolId(std::string toolId) const +{ + if(KnowledgeTool::ARXIV == toolId) { + return tr("arXiv"); + } else if(KnowledgeTool::WIKIPEDIA == toolId) { + return tr("Wikipedia"); + } else if(KnowledgeTool::GH_REPOS == toolId) { + return tr("GitHub Repositories"); + } else if(KnowledgeTool::GH_CODE == toolId) { + return tr("GitHub Code"); + } else if(KnowledgeTool::DUCKDUCKGO == toolId) { + return tr("DuckDuckGo"); + } else if(KnowledgeTool::GOOGLE == toolId) { + return tr("Google"); + } else if(KnowledgeTool::STACK_OVERFLOW == toolId) { + return tr("StackOverflow"); + } else if(KnowledgeTool::CPP == toolId) { + return tr("CPP reference"); + } else if(KnowledgeTool::PYTHON == toolId) { + return tr("Python documentation"); + } + + // no suitable name available + return QString::fromStdString(toolId); +} + +bool RunToolDialog::selectToolById(std::string toolId) { + MF_DEBUG( + "RunToolDialog::selectToolById(" << toolId << ") in variantData: " << std::endl); + + QVariant desiredValue = QVariant::fromValue( + QString::fromStdString(toolId)); + int index = this->toolCombo->findData(desiredValue, Qt::UserRole); + if(index != -1) { + this->toolCombo->setCurrentIndex(index); + return true; + } + + MF_DEBUG( + "ERROR: RunToolDialog::setSelectedToolId() - toolId '" + << toolId << "' not found!" << std::endl); + return false; +} + +void RunToolDialog::show() +{ + QDialog::show(); +} + +void RunToolDialog::handleChangeToolCombo(const QString& text) +{ + MF_DEBUG("Tool changed: " << text.toStdString() << endl); + + this->templateEdit->setText( + QString::fromStdString( + KnowledgeTool::getUrlTemplateForToolId( + text.toStdString()))); +} + +} // m8r namespace diff --git a/app/src/qt/dialogs/run_tool_dialog.h b/app/src/qt/dialogs/run_tool_dialog.h new file mode 100644 index 00000000..79d7febc --- /dev/null +++ b/app/src/qt/dialogs/run_tool_dialog.h @@ -0,0 +1,88 @@ +/* + run_tool_dialog.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_RUN_TOOL_DIALOG_H +#define M8RUI_RUN_TOOL_DIALOG_H + +#include + +#include "../../lib/src/config/configuration.h" + +#include "../model_meta_definitions.h" + +namespace m8r { + +class RunToolDialog : public QDialog +{ + Q_OBJECT + +private: + + QLabel* phraseLabel; + QLineEdit* phraseEdit; + + QLabel* toolLabel; + QComboBox* toolCombo; + + QLabel* templateLabel; + QLineEdit* templateEdit; + + QPushButton* runButton; + QPushButton* closeButton; + +public: + explicit RunToolDialog(QWidget* parent); + RunToolDialog(const RunToolDialog&) = delete; + RunToolDialog(const RunToolDialog&&) = delete; + RunToolDialog& operator =(const RunToolDialog&) = delete; + RunToolDialog& operator =(const RunToolDialog&&) = delete; + ~RunToolDialog(); + + QString getToolNameForToolId(std::string toolId) const; + + void show(); + + QPushButton* getRunButton() const { return runButton; } + QString getSelectedTool() const { + return this->toolCombo->itemText( + this->toolCombo->currentIndex() + ); + } + std::string getSelectedToolId() const { + int currentIndex = this->toolCombo->currentIndex(); + QVariant variantData = this->toolCombo->itemData(currentIndex, Qt::UserRole); + return variantData.toString().toStdString(); + } + bool selectToolById(std::string toolId); + QString getTemplateText() const { + return this->templateEdit->text(); + } + QString getPhraseText() const { return phraseEdit->text(); } + void setPhraseText(QString phrase) { + this->phraseEdit->setText(phrase); + } + void setTemplateText(QString templateText) { + this->templateEdit->setText(templateText); + } + +private slots: + void handleChangeToolCombo(const QString& text); +}; + +} +#endif // M8RUI_RUN_TOOL_DIALOG_H diff --git a/app/src/qt/dialogs/scope_dialog.cpp b/app/src/qt/dialogs/scope_dialog.cpp index 892f7c95..0ba4f4a1 100644 --- a/app/src/qt/dialogs/scope_dialog.cpp +++ b/app/src/qt/dialogs/scope_dialog.cpp @@ -1,7 +1,7 @@ /* scope_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/scope_dialog.h b/app/src/qt/dialogs/scope_dialog.h index 95bd47b3..ccdb9155 100644 --- a/app/src/qt/dialogs/scope_dialog.h +++ b/app/src/qt/dialogs/scope_dialog.h @@ -1,7 +1,7 @@ /* scope_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/sync_library_dialog.cpp b/app/src/qt/dialogs/sync_library_dialog.cpp new file mode 100644 index 00000000..c3daee96 --- /dev/null +++ b/app/src/qt/dialogs/sync_library_dialog.cpp @@ -0,0 +1,88 @@ +/* + sync_library_dialog.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "sync_library_dialog.h" + +using namespace std; + +namespace m8r { + +SyncLibraryDialog::SyncLibraryDialog(QWidget* parent) + : QDialog(parent) +{ + // widgets + findLibrarySourceLabel = new QLabel{ + tr( + "Choose a library directory to be synchronized - new notebook\n" + "will be created for every new document found in the library.\n" + "Existing MindForger notebooks for library documents which were\n" + "deleted, renamed or moved (i.e. their link to library document\n" + "is broken) will not be deprecated to protect your document-related\n" + "notes. Feel free to deprecate such notebook(s) yourself.\n" + ), + parent}; + + librariesLabel = new QLabel{tr("Choose library to update: ")}; + libraryPathsCombo = new QComboBox{this}; + + // IMPROVE disable/enable find button if text/path is valid: freedom vs validation + syncButton = new QPushButton{tr("&Update")}; + syncButton->setDefault(true); + closeButton = new QPushButton{tr("&Cancel")}; + + // signals + QObject::connect( + closeButton, SIGNAL(clicked()), + this, SLOT(close())); + + // assembly + QVBoxLayout* mainLayout = new QVBoxLayout{}; + mainLayout->addWidget(findLibrarySourceLabel); + mainLayout->addWidget(librariesLabel); + mainLayout->addWidget(libraryPathsCombo); + + QHBoxLayout* buttonLayout = new QHBoxLayout{}; + buttonLayout->addStretch(1); + buttonLayout->addWidget(closeButton); + buttonLayout->addWidget(syncButton); + buttonLayout->addStretch(); + + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + // dialog + setWindowTitle(tr("Update Document Library")); + resize(fontMetrics().averageCharWidth()*55, height()); + setModal(true); +} + +SyncLibraryDialog::~SyncLibraryDialog() +{ + delete findLibrarySourceLabel; + delete librariesLabel; + delete libraryPathsCombo; + delete syncButton; + delete closeButton; +} + +void SyncLibraryDialog::show() +{ + QDialog::show(); +} + +} // m8r namespace diff --git a/app/src/qt/dialogs/sync_library_dialog.h b/app/src/qt/dialogs/sync_library_dialog.h new file mode 100644 index 00000000..cba0738a --- /dev/null +++ b/app/src/qt/dialogs/sync_library_dialog.h @@ -0,0 +1,69 @@ +/* +sync_library_dialog.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_SYNC_LIBRARY_DIALOG_H +#define M8RUI_SYNC_LIBRARY_DIALOG_H + +#include + +#include "../../lib/src/model/outline.h" +#include "../../lib/src/config/repository.h" + +#include + +namespace m8r { + +/** + * @brief Synchronize document library dialog. + * + * The dialog is instantiated in main window presenter. + */ +class SyncLibraryDialog : public QDialog +{ + Q_OBJECT + +private: + QLabel* findLibrarySourceLabel; + QLabel* librariesLabel; + QComboBox* libraryPathsCombo; + + QPushButton* syncButton; + QPushButton* closeButton; + +public: + explicit SyncLibraryDialog(QWidget* parent); + SyncLibraryDialog(const SyncLibraryDialog&) = delete; + SyncLibraryDialog(const SyncLibraryDialog&&) = delete; + SyncLibraryDialog& operator=(const SyncLibraryDialog&) = delete; + SyncLibraryDialog& operator=(const SyncLibraryDialog&&) = delete; + ~SyncLibraryDialog(); + + void reset() { + libraryPathsCombo->clear(); + } + void show(); + + QPushButton* getSyncButton() const { return syncButton; } + QComboBox* getLibraryPathsCombo() const { return libraryPathsCombo; } + void addLibraryToSync(std::string libraryPath) { + libraryPathsCombo->addItem(QString::fromStdString(libraryPath)); + } +}; + +} +#endif // M8RUI_SYNC_LIBRARY_DIALOG_H diff --git a/app/src/qt/dialogs/terminal_dialog.cpp b/app/src/qt/dialogs/terminal_dialog.cpp index 1ce52fd0..7135e246 100644 --- a/app/src/qt/dialogs/terminal_dialog.cpp +++ b/app/src/qt/dialogs/terminal_dialog.cpp @@ -1,7 +1,7 @@ /* terminal_dialog.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -25,6 +25,8 @@ using namespace std; TerminalDialog::TerminalDialog(QWidget* parent) : QDialog(parent) { + setWindowTitle(tr("Terminal")); + cmdEdit = new MyLineEdit(this, this); cmdCompleter = new QCompleter(new QStandardItemModel(cmdEdit), this); @@ -162,7 +164,7 @@ void TerminalDialog::runCommand() // TODO _popen WINDOWS #ifdef _WIN32 FILE* pipe = _popen(cmd.c_str(), "r"); - # else + #else FILE* pipe = popen(cmd.c_str(), "r"); #endif if(!pipe) { diff --git a/app/src/qt/dialogs/terminal_dialog.h b/app/src/qt/dialogs/terminal_dialog.h index 56f6283e..eb9dd9ce 100644 --- a/app/src/qt/dialogs/terminal_dialog.h +++ b/app/src/qt/dialogs/terminal_dialog.h @@ -1,7 +1,7 @@ /* terminal_dialog.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/dialogs/wingman_dialog.cpp b/app/src/qt/dialogs/wingman_dialog.cpp new file mode 100644 index 00000000..b49241be --- /dev/null +++ b/app/src/qt/dialogs/wingman_dialog.cpp @@ -0,0 +1,488 @@ +/* + wingman_dialog.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "wingman_dialog.h" + +namespace m8r { + +using namespace std; + +const string COLOR_PROMPT_GREEN{"#00bb00"}; +const string COLOR_PROMPT_BLUE{"#00aaaa"}; +const string COLOR_PROMPT_GRAY{"#777777"}; + +WingmanDialog::WingmanDialog(QWidget* parent) +: QDialog(parent), + firstRun{true}, + mode{WingmanDialogModes::WINGMAN_DIALOG_MODE_TEXT}, + context{}, + lastAnswer{} +{ + setWindowTitle(tr("Wingman Chat")); + + promptsLabel = new QLabel{tr("Prompt:"), parent}; + + predefinedPromptsCombo = new QComboBox{this}; + predefinedPromptsCombo->hide(); + + cmdEdit = new MyLineEdit(this, this); + cmdEdit->setToolTip( + tr( + "Use 'clear' or 'cls' to clear the chat window." + " Use 'exit', 'quit' or 'bye' to close the dialog.")); + QPalette p = cmdEdit->palette(); + p.setColor(QPalette::Text, QColor(COLOR_PROMPT_GREEN.c_str())); + cmdEdit->setPalette(p); + + cmdCompleter = new QCompleter(new QStandardItemModel(cmdEdit), this); + cmdCompleter->setCompletionMode(QCompleter::CompletionMode::InlineCompletion); + cmdCompleter->setCaseSensitivity(Qt::CaseInsensitive); + QStandardItemModel* cmdCompleterModel = + dynamic_cast(cmdCompleter->model()); + if(cmdCompleterModel) { + completerCommands.clear(); + // prompts based on the context + + completerCommands << QString::fromStdString("exit"); + completerCommands << QString::fromStdString("quit"); + completerCommands << QString::fromStdString("bye"); + + for(auto c:completerCommands) { + cmdCompleterModel->appendRow(new QStandardItem(c)); + } + } + + cmdEdit->setCompleter(cmdCompleter); + + chatWindow = new QTextEdit(this); + chatWindow->setReadOnly(true); + + askButton = new QPushButton(tr("&Run Prompt"), this); + copyButton = new QPushButton(tr("C&opy"), this); + copyButton->setToolTip(tr("Copy last answer to the clipboard")); + appendButton = new QPushButton(tr("&Append"), this); + appendButton->setToolTip(tr("Append the last Wingman answer to the Note text after the cursor")); + replaceButton = new QPushButton(tr("&Replace"), this); + replaceButton->setToolTip(tr("Replace (selected) Note text with the last Wingman answer")); + togglePromptSourceButton = new QPushButton(tr("Show Predefined &Prompts"), this); + toggleContextButton = new QPushButton(tr("Show &Context"), this); + closeButton = new QPushButton(tr("Close"), this); + + // GROUP: context + contextGroup = new QGroupBox{tr("Context"), this}; + + contextTypeLabel = new QLabel{tr("Type:"), parent}; + contextTypeEdit = new QLineEdit{parent}; + contextTypeEdit->setReadOnly(true); + + contextNameLabel = new QLabel{tr("Name (#NAME):"), parent}; + contextNameEdit = new QLineEdit{parent}; + contextNameEdit->setReadOnly(true); + + contextLabel = new QLabel{tr("Text (#TEXT):"), parent}; + contextEdit = new QLineEdit{parent}; + contextEdit->setReadOnly(true); + + progressBar = new QProgressBar(this); + progressBar->setTextVisible(true); + progressBar->setMinimum(0); + progressBar->setMaximum(100); + progressBar->hide(); + + QHBoxLayout* contentLayout = new QHBoxLayout{this}; + QWidget* cw1 = new QWidget{this}; + QVBoxLayout* contentLayout1 = new QVBoxLayout{cw1}; + contentLayout1->addWidget(contextNameLabel); + contentLayout1->addWidget(contextNameEdit); + contentLayout->addWidget(cw1); + QWidget* cw2 = new QWidget{this}; + QVBoxLayout* contentLayout2 = new QVBoxLayout{cw2}; + contentLayout2->addWidget(contextLabel); + contentLayout2->addWidget(contextEdit); + contentLayout->addWidget(cw2); + QWidget* cw3 = new QWidget{this}; + QVBoxLayout* contentLayout3 = new QVBoxLayout{cw3}; + contentLayout3->addWidget(contextTypeLabel); + contentLayout3->addWidget(contextTypeEdit); + contentLayout->addWidget(cw3); + contextGroup->setLayout(contentLayout); + contextGroup->hide(); + + // assembly + QHBoxLayout* buttonLayout = new QHBoxLayout{}; + //buttonLayout->addStretch(1); + buttonLayout->addWidget(closeButton); + buttonLayout->addWidget(toggleContextButton); + buttonLayout->addWidget(togglePromptSourceButton); + buttonLayout->addStretch(1); + buttonLayout->addWidget(copyButton); + buttonLayout->addWidget(appendButton); + buttonLayout->addWidget(replaceButton); + buttonLayout->addWidget(askButton); + buttonLayout->addStretch(); + + QVBoxLayout* layout = new QVBoxLayout{this}; + layout->addWidget(chatWindow); + layout->addWidget(promptsLabel); + layout->addWidget(predefinedPromptsCombo); + layout->addWidget(cmdEdit); + layout->addWidget(progressBar); + layout->addLayout(buttonLayout); + layout->addWidget(contextGroup); + setLayout(layout); + + resize(fontMetrics().averageCharWidth()*100, fontMetrics().height()*35); + + this->initForMode(mode); + chatWindow->clear(); + + // signals + QObject::connect( + closeButton, SIGNAL(clicked()), + this, SLOT(close())); + QObject::connect( + togglePromptSourceButton, SIGNAL(clicked()), + this, SLOT(handleTogglePromptSource())); + QObject::connect( + toggleContextButton, SIGNAL(clicked()), + this, SLOT(handleToggleContextGroup())); + QObject::connect( + askButton, SIGNAL(clicked()), + this, SLOT(handleRunPrompt())); + QObject::connect( + copyButton, SIGNAL(clicked()), + this, SLOT(handleCopyLastAnswer())); +} + +WingmanDialog::~WingmanDialog() +{ + delete promptsLabel; + delete predefinedPromptsCombo; + delete cmdEdit; + delete chatWindow; + delete askButton; + delete togglePromptSourceButton; + delete toggleContextButton; + delete closeButton; + delete contextGroup; // deletes children automatically +} + +void WingmanDialog::initForMode(WingmanDialogModes mode) +{ + this->mode=mode; + + predefinedPromptsCombo->clear(); + vector* prompts{}; + + switch(mode) { + case WingmanDialogModes::WINGMAN_DIALOG_MODE_OUTLINE: + prompts = &outlinePrompts; + contextTypeEdit->setText(tr("notebook")); + contextEdit->setText(tr("")); + appendButton->hide(); + replaceButton->hide(); + break; + case WingmanDialogModes::WINGMAN_DIALOG_MODE_NOTE: + prompts = ¬ePrompts; + contextTypeEdit->setText(tr("note")); + contextEdit->setText(tr("")); + appendButton->hide(); + replaceButton->hide(); + break; + case WingmanDialogModes::WINGMAN_DIALOG_MODE_TEXT: + prompts = &textPrompts; + contextNameEdit->clear(); + contextEdit->clear(); + appendButton->show(); + replaceButton->show(); + break; + } + + for(QString prompt:*prompts) { + predefinedPromptsCombo->addItem(prompt); + } +} + +void WingmanDialog::setContextText(QString context) { + this->context=context; + + int limit{25}; + if(context.length()>limit) { + context=context.mid(0, limit).append("..."); + } + this->contextEdit->setText(context); +} + +QString WingmanDialog::getContextText() const { + return context; +} + +void WingmanDialog::setup( + WingmanDialogModes contextType, + QString& contextName, + QString& context, + const vector& predefinedOPrompts, + const vector& predefinedNPrompts, + const vector& predefinedTPrompts +) { + outlinePrompts.clear(); + for(string prompt:predefinedOPrompts) { + outlinePrompts.push_back(QString::fromStdString(prompt)); + } + notePrompts.clear(); + for(string prompt:predefinedNPrompts) { + notePrompts.push_back(QString::fromStdString(prompt)); + } + textPrompts.clear(); + for(string prompt:predefinedTPrompts) { + textPrompts.push_back(QString::fromStdString(prompt)); + } + + this->initForMode(contextType); + + setContextText(context); + setContextNameText(contextName); + + cmdEdit->clear(); +} + +void WingmanDialog::show( + WingmanDialogModes contextType, + QString& contextName, + QString& context, + const vector& predefinedOPrompts, + const vector& predefinedNPrompts, + const vector& predefinedTPrompts +) { + this->setup( + contextType, + contextName, + context, + predefinedOPrompts, + predefinedNPrompts, + predefinedTPrompts + ); + + cmdEdit->setFocus(); + + setModal(true); + QDialog::show(); +} + +string WingmanDialog::getPrompt() +{ + if(predefinedPromptsCombo->isVisible()) { + return predefinedPromptsCombo->currentText().toStdString(); + } else { + return cmdEdit->text().toStdString(); + } +} + +void WingmanDialog::setPrompt(const std::string& prompt) +{ + cmdEdit->setText(QString::fromStdString(prompt)); +} + +string WingmanDialog::getChatPromptPrefix(bool error) +{ + string prompt{}; + + if(!firstRun) { + prompt.append("
"); + } else { + firstRun=false; + } + + if(contextTypeEdit->text().size()>0) { + string promptDescriptor{ + "[context type: " + contextTypeEdit->text().toStdString() + + ", context name: " + contextNameEdit->text().toStdString() + + "]" + }; + + prompt.append( + "" + + promptDescriptor + + "" + + "
" + ); + } + + prompt.append("> "); + + return prompt; +} + +void WingmanDialog::appendPromptToChat(const std::string& prompt) +{ + chatWindow->insertHtml( + QString::fromStdString( + getChatPromptPrefix( + false)) + + QString::fromStdString( + "" + + prompt + + "" + "

" + )); + + chatWindow->moveCursor(QTextCursor::End); + chatWindow->ensureCursorVisible(); +} + +void WingmanDialog::appendAnswerToChat( + const string& answer, + const string& answerDescriptor, + const WingmanDialogModes& contextType, + bool error +) { + this->lastAnswer=answer; + + string contextTypeString; + switch(contextType) { + case WingmanDialogModes::WINGMAN_DIALOG_MODE_OUTLINE: + contextTypeString = "outline"; + break; + case WingmanDialogModes::WINGMAN_DIALOG_MODE_NOTE: + contextTypeString = "note"; + break; + default: + contextTypeString = "text"; + break; + } + + const string errorPrefix{"ERROR: "}; + const string errorSuffix{""}; + + chatWindow->insertHtml( + QString::fromStdString( + "
" + "" + "" + "wingman@" + contextTypeString + + "" + + ":" + "
" + "
" + + (error?errorPrefix:"") + + answer + + (error?errorSuffix:"") + + "
" + + "
" + + "" + + answerDescriptor + + "" + + "
" + )); + + chatWindow->moveCursor(QTextCursor::End); + chatWindow->ensureCursorVisible(); +} + +void WingmanDialog::runPrompt() +{ + // TODO help + if(cmdEdit->text() == QString::fromStdString("clear") + || cmdEdit->text() == QString::fromStdString("cls") + ) { + chatWindow->clear(); + } else if(cmdEdit->text() == QString::fromStdString("exit") + || cmdEdit->text() == QString::fromStdString("quit") + || cmdEdit->text() == QString::fromStdString("bye") + ) { + QDialog::close(); + } else { + string prompt = getPrompt(); + + appendPromptToChat(prompt); + + // add command to completer + QStandardItemModel* completerModel + = dynamic_cast(cmdCompleter->model()); + if(!completerModel) { + completerModel = new QStandardItemModel(); + } + completerModel->insertRow( + 0, new QStandardItem(cmdEdit->text()) + ); + + // run prompt by sending SIGNAL to main window presenter + MF_DEBUG("RUNNING prompt from the CHAT dialog: '" << prompt << "'" << endl); + emit signalRunWingman(); + MF_DEBUG("SIGNAL to RUN prompt sent" << endl); + } + + cmdEdit->clear(); + MF_DEBUG("Chat prompt dispatched" << endl); +} + +void WingmanDialog::handleRunPrompt() +{ + MF_DEBUG("SLOT handle: run" << endl); + + runPrompt(); +} + +void WingmanDialog::handleCopyLastAnswer() +{ + MF_DEBUG("SLOT handle: copy" << endl); + + // get a pointer to the clipboard + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(QString::fromStdString(this->lastAnswer)); +} + +void WingmanDialog::handleTogglePromptSource() +{ + MF_DEBUG("SLOT handle: toggle" << endl); + + if(predefinedPromptsCombo->isVisible()) { + predefinedPromptsCombo->hide(); + promptsLabel->setText(tr("Prompt:")); + cmdEdit->show(); + cmdEdit->setFocus(); + togglePromptSourceButton->setText(tr("Show &Predefined Prompts")); + } else { + cmdEdit->hide(); + promptsLabel->setText(tr("Predefined prompts:")); + predefinedPromptsCombo->show(); + predefinedPromptsCombo->setFocus(); + togglePromptSourceButton->setText(tr("Write Your &Prompt")); + } +} + +void WingmanDialog::handleToggleContextGroup() +{ + MF_DEBUG("SLOT handle: toggle context" << endl); + + if(contextGroup->isVisible()) { + contextGroup->hide(); + toggleContextButton->setText(tr("Show &Context")); + } else { + contextGroup->show(); + toggleContextButton->setText(tr("Hide &Context")); + } +} + +} // m8r namespace diff --git a/app/src/qt/dialogs/wingman_dialog.h b/app/src/qt/dialogs/wingman_dialog.h new file mode 100644 index 00000000..5ecc71a0 --- /dev/null +++ b/app/src/qt/dialogs/wingman_dialog.h @@ -0,0 +1,235 @@ +/* + chat_dialog.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_WINGMAN_DIALOG_H +#define M8RUI_WINGMAN_DIALOG_H + + +#include +#include +#include +#include + +#include "../../lib/src/debug.h" +#include "../../lib/src/gear/file_utils.h" +#include "../../lib/src/gear/string_utils.h" + +#include + +namespace m8r { + +enum WingmanDialogModes { + WINGMAN_DIALOG_MODE_OUTLINE, + WINGMAN_DIALOG_MODE_NOTE, + WINGMAN_DIALOG_MODE_TEXT +}; + +class WingmanDialog : public QDialog // TODO rename to WingmanDialog +{ + Q_OBJECT + + class MyLineEdit : public QLineEdit + { + private: + WingmanDialog* chatDialog; + public: + explicit MyLineEdit(WingmanDialog* chatDialog, QWidget* parent) + : QLineEdit(parent), + chatDialog(chatDialog) + {} + virtual void keyPressEvent(QKeyEvent* event) override { + switch(event->key()) { + case Qt::Key_Return: // Qt::Key_Enter is keypad Enter + chatDialog->runPrompt(); + setFocus(); + return; + } + + // continue event dispatch (completer needs to get the event) + QLineEdit::keyPressEvent(event); + } + }; + +private: + std::vector outlinePrompts; + std::vector notePrompts; + std::vector textPrompts; + + bool firstRun; + WingmanDialogModes mode; + QString context; + QString lastPromptLabel; + std::string lastAnswer; + + QTextEdit* chatWindow; + + QLabel* promptsLabel; + + MyLineEdit* cmdEdit; + QCompleter* cmdCompleter; + QStringList completerCommands; + + QComboBox* predefinedPromptsCombo; + + QPushButton* askButton; + QPushButton* copyButton; + QPushButton* appendButton; + QPushButton* replaceButton; + + QPushButton* togglePromptSourceButton; + QPushButton* toggleContextButton; + QPushButton* closeButton; + + QGroupBox* contextGroup; + QLabel* contextTypeLabel; + QLineEdit* contextTypeEdit; + QLabel* contextNameLabel; + QLineEdit* contextNameEdit; + QLabel* contextLabel; + QLineEdit* contextEdit; + + QProgressBar* progressBar; + bool cmdEditVisibilityCache; + bool predefPromptsVisibilityCache; + +public: + explicit WingmanDialog(QWidget* parent); + WingmanDialog(const WingmanDialog&) = delete; + WingmanDialog(const WingmanDialog&&) = delete; + WingmanDialog& operator =(const WingmanDialog&) = delete; + WingmanDialog& operator =(const WingmanDialog&&) = delete; + ~WingmanDialog(); + + void initForMode(WingmanDialogModes mode); + WingmanDialogModes getMode() const { return mode; } + void setMode(WingmanDialogModes mode) { this->mode=mode; } + + void appendPromptToChat(const std::string& prompt); + void appendAnswerToChat( + const std::string& answer, + const std::string& answerDescriptor, + const WingmanDialogModes& contextType, + bool error=false); + + void setPromptsLabel(const QString& label) { + lastPromptLabel = promptsLabel->text(); + promptsLabel->setText(label); + } + void setLastPromptLabel() { + promptsLabel->setText(lastPromptLabel); + } + + std::string getPrompt(); + void setPrompt(const std::string& prompt); + void selectPrompt() { + if(cmdEdit->isVisible() && !cmdEdit->text().isEmpty()) { + cmdEdit->setFocus(); + cmdEdit->selectAll(); + } + } + /** + * @brief Get the last answer as a Markdown string. + * + * The answer is typically pasted or appended to the Note editor, + * which uses Markdown format (not HTML), so the answer is converted + * to Markdown format. + */ + std::string getLastAnswer() { + if(this->lastAnswer.find("
") != std::string::npos) { + std::string decodedAnswer{this->lastAnswer}; + replaceAll("
", "\n", decodedAnswer); + return decodedAnswer; + } + + return this->lastAnswer; + } + + QPushButton* getAppendButton() const { return appendButton; } + QPushButton* getReplaceButton() const { return replaceButton; } + + WingmanDialogModes getContextType() const { + return this->mode; + } + void setContextNameText(QString contextName) { + this->contextNameEdit->setText(contextName); + } + QString getContextNameText() const { + return this->contextNameEdit->text(); + } + void setContextText(QString context); + QString getContextText() const; + + void setup( + WingmanDialogModes contextType, + QString& contextName, + QString& context, + const std::vector& predefinedOPrompts, + const std::vector& predefinedNPrompts, + const std::vector& predefinedTPrompts); + void show( + WingmanDialogModes contextType, + QString& contextName, + QString& context, + const std::vector& predefinedOPrompts, + const std::vector& predefinedNPrompts, + const std::vector& predefinedTPrompts); + void show() { + setModal(true); + QDialog::show(); + } + + void resetProgress(int maximum) { + progressBar->setValue(0); + progressBar->setMinimum(0); + progressBar->setMaximum(maximum); + progressBar->setValue(0); + } + void setProgressValue(int progress) { + progressBar->setValue(progress); + } + void setProgressVisible(bool visible) { + if(visible) { + predefPromptsVisibilityCache = predefinedPromptsCombo->isVisible(); + cmdEditVisibilityCache = cmdEdit->isVisible(); + predefinedPromptsCombo->setVisible(false); + cmdEdit->setVisible(false); + } else { + predefinedPromptsCombo->setVisible(predefPromptsVisibilityCache); + cmdEdit->setVisible(cmdEditVisibilityCache); + } + + progressBar->setVisible(visible); + } + +private: + void runPrompt(); + std::string getChatPromptPrefix(bool error=false); + +signals: + void signalRunWingman(); + +private slots: + void handleRunPrompt(); + void handleCopyLastAnswer(); + void handleTogglePromptSource(); + void handleToggleContextGroup(); + +}; + +} +#endif // M8RUI_WINGMAN_DIALOG_H diff --git a/app/src/qt/exceptions.h b/app/src/qt/exceptions.h index f0eabfc0..001c9d61 100644 --- a/app/src/qt/exceptions.h +++ b/app/src/qt/exceptions.h @@ -1,7 +1,7 @@ /* exceptions.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/gear/apple_utils.h b/app/src/qt/gear/apple_utils.h index cec09db0..ede5d5be 100644 --- a/app/src/qt/gear/apple_utils.h +++ b/app/src/qt/gear/apple_utils.h @@ -1,7 +1,7 @@ /* apple_utils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/gear/async_task_notifications_distributor.cpp b/app/src/qt/gear/async_task_notifications_distributor.cpp index ca084b66..b7849d43 100644 --- a/app/src/qt/gear/async_task_notifications_distributor.cpp +++ b/app/src/qt/gear/async_task_notifications_distributor.cpp @@ -1,7 +1,7 @@ /* async_task_notifications_distributor.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -57,7 +57,7 @@ AsyncTaskNotificationsDistributor::~AsyncTaskNotificationsDistributor() // TODO refactor this function to multiple methods to make it more structured void AsyncTaskNotificationsDistributor::run() { - // avoid re-calculation of TayW word learderboards if it's not needed + // avoid re-calculation of TayW word leaderboards if it's not needed QString lastTayWords{}; Outline* lastTayWOutline{}; Note* lastTayWNote{}; @@ -67,6 +67,35 @@ void AsyncTaskNotificationsDistributor::run() while(true) { msleep(static_cast(sleepInterval)); + + + /* + + // Wingman: send queued chat request to configured LLM provider + // TODO Task* task = new Task{TaskType::CHAT, chatRequest}; + if(false) { + // TODO check wingman not null + auto chatRequestsQueue = mwp->getMind()->getWingman()->taskQueue(); + MF_DEBUG("AsyncTaskDistributor: AWAKE w/ " << chatRequestsQueue.size() << " chat requests" << endl); + + while(chatRequestsQueue.size()) { + auto llmChatTask = chatRequestsQueue.pop(); + MF_DEBUG("AsyncTaskDistributor: chat request '" << chatRequest << "'" << endl); + mwp->getMind()->getWingman()->chat( + llmChatTask + ); + + // TODO send signal to main window presenter to show chat result + emit showStatusBarInfo( + // TODO "Associated Notes for Notebook '"+QString::fromStdString(mwp->getOrloj()->getOutlineView()->getCurrentOutline()->getName())+"'..."); + emit handleAppendLlmResponseToChatDialog(llmChatTask); + } + } + + */ + + + // live preview refresh if((++livePreviewMultiplier)%3==0 && @@ -74,7 +103,7 @@ void AsyncTaskNotificationsDistributor::run() && mwp->getOrloj()->isAspectActive(OrlojPresenterFacetAspect::ASPECT_LIVE_PREVIEW)) { - MF_DEBUG("Task distributor: refresh O or N preview"); + MF_DEBUG("AsyncTaskDistributor: refresh O or N preview"); emit signalRefreshCurrentNotePreview(); // hit counter can be cleared, because associations are not visible if live preview is active @@ -83,7 +112,7 @@ void AsyncTaskNotificationsDistributor::run() } #ifdef MF_DEBUG_ASYNC_TASKS - MF_DEBUG("AsyncDistributor[" << datetimeNow() << "]: wake up w/ associations need " << (int)mwp->getMind()->needForAssociations() << endl); + MF_DEBUG("AsyncTaskDistributor[" << datetimeNow() << "]: wake up w/ associations need " << (int)mwp->getMind()->needForAssociations() << endl); #endif if(mwp->getMind()->needForAssociations() || @@ -94,7 +123,7 @@ void AsyncTaskNotificationsDistributor::run() mwp->getOrloj()->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)))) { #ifdef MF_DEBUG_ASYNC_TASKS - MF_DEBUG("AsyncDistributor: calculating associations..." << Configuration::getInstance().isUiLiveNotePreview() << endl); + MF_DEBUG("AsyncTaskDistributor: calculating associations..." << Configuration::getInstance().isUiLiveNotePreview() << endl); #endif mwp->getMind()->meditateAssociations(); diff --git a/app/src/qt/gear/async_task_notifications_distributor.h b/app/src/qt/gear/async_task_notifications_distributor.h index c63f581a..30ae8ceb 100644 --- a/app/src/qt/gear/async_task_notifications_distributor.h +++ b/app/src/qt/gear/async_task_notifications_distributor.h @@ -1,7 +1,7 @@ /* async_task_notifications_distributor.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -44,8 +44,8 @@ class MainWindowPresenter; * accessible. * * Summary: distributor gets or pulls tasks, executes them (in its own thread i.e. it - * doesn't block Qt main thread) and notifies result using signals to Qt frontend (which - * ensures asynchronous dispatch). + * doesn't block Qt main thread) and notifies about result availability using signals + * to Qt frontend (which ensures asynchronous dispatch). */ class AsyncTaskNotificationsDistributor : public QThread { @@ -121,7 +121,6 @@ class AsyncTaskNotificationsDistributor : public QThread void signalRefreshCurrentNotePreview(); public slots: - void slotConfigurationUpdated(); }; diff --git a/app/src/qt/gear/qutils.cpp b/app/src/qt/gear/qutils.cpp index 76ea56d8..50270bc8 100644 --- a/app/src/qt/gear/qutils.cpp +++ b/app/src/qt/gear/qutils.cpp @@ -1,7 +1,7 @@ /* qutils.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/gear/qutils.h b/app/src/qt/gear/qutils.h index 1f9868c4..13fcc6c5 100644 --- a/app/src/qt/gear/qutils.h +++ b/app/src/qt/gear/qutils.h @@ -1,7 +1,7 @@ /* qutils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/html_delegate.cpp b/app/src/qt/html_delegate.cpp index e129fdb9..09040f6b 100644 --- a/app/src/qt/html_delegate.cpp +++ b/app/src/qt/html_delegate.cpp @@ -1,7 +1,7 @@ /* html_delegate.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/html_delegate.h b/app/src/qt/html_delegate.h index c08fa5e9..cb90bef2 100644 --- a/app/src/qt/html_delegate.h +++ b/app/src/qt/html_delegate.h @@ -1,7 +1,7 @@ /* html_delegate.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/i18nl10n.cpp b/app/src/qt/i18nl10n.cpp index 4ad45b08..bc16c9a6 100644 --- a/app/src/qt/i18nl10n.cpp +++ b/app/src/qt/i18nl10n.cpp @@ -1,7 +1,7 @@ /* i18n.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/i18nl10n.h b/app/src/qt/i18nl10n.h index d92997c5..d434ad7a 100644 --- a/app/src/qt/i18nl10n.h +++ b/app/src/qt/i18nl10n.h @@ -1,7 +1,7 @@ /* i18nl10n.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_column_model.cpp b/app/src/qt/kanban_column_model.cpp index c76e4525..e5aab28a 100644 --- a/app/src/qt/kanban_column_model.cpp +++ b/app/src/qt/kanban_column_model.cpp @@ -1,7 +1,7 @@ /* kanban_column_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_column_model.h b/app/src/qt/kanban_column_model.h index 6932687d..bd4eef8d 100644 --- a/app/src/qt/kanban_column_model.h +++ b/app/src/qt/kanban_column_model.h @@ -1,7 +1,7 @@ /* kanban_column_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_column_presenter.cpp b/app/src/qt/kanban_column_presenter.cpp index d4964f55..54ddf756 100644 --- a/app/src/qt/kanban_column_presenter.cpp +++ b/app/src/qt/kanban_column_presenter.cpp @@ -1,7 +1,7 @@ /* kanban_column_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_column_presenter.h b/app/src/qt/kanban_column_presenter.h index 689e29d1..e1ba986d 100644 --- a/app/src/qt/kanban_column_presenter.h +++ b/app/src/qt/kanban_column_presenter.h @@ -1,7 +1,7 @@ /* kanban_column_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_column_view.cpp b/app/src/qt/kanban_column_view.cpp index 29b0efde..181e691c 100644 --- a/app/src/qt/kanban_column_view.cpp +++ b/app/src/qt/kanban_column_view.cpp @@ -1,7 +1,7 @@ /* kanban_column_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_column_view.h b/app/src/qt/kanban_column_view.h index 0df5b25c..105b1a42 100644 --- a/app/src/qt/kanban_column_view.h +++ b/app/src/qt/kanban_column_view.h @@ -1,7 +1,7 @@ /* kanban_column_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_presenter.cpp b/app/src/qt/kanban_presenter.cpp index 148e265c..d63e7596 100644 --- a/app/src/qt/kanban_presenter.cpp +++ b/app/src/qt/kanban_presenter.cpp @@ -1,7 +1,7 @@ /* kanban_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_presenter.h b/app/src/qt/kanban_presenter.h index 5d135deb..9e63780e 100644 --- a/app/src/qt/kanban_presenter.h +++ b/app/src/qt/kanban_presenter.h @@ -1,7 +1,7 @@ /* kanban_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_view.cpp b/app/src/qt/kanban_view.cpp index d1b07882..3868cb2d 100644 --- a/app/src/qt/kanban_view.cpp +++ b/app/src/qt/kanban_view.cpp @@ -1,7 +1,7 @@ /* kanban_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/kanban_view.h b/app/src/qt/kanban_view.h index 8413eefc..c0822e79 100644 --- a/app/src/qt/kanban_view.h +++ b/app/src/qt/kanban_view.h @@ -1,7 +1,7 @@ /* kanban_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/left_toolbar_view.cpp b/app/src/qt/left_toolbar_view.cpp new file mode 100644 index 00000000..7e5ec487 --- /dev/null +++ b/app/src/qt/left_toolbar_view.cpp @@ -0,0 +1,56 @@ +/* + left_toolbar_view.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "left_toolbar_view.h" + +namespace m8r { + +LeftToolbarView::LeftToolbarView(MainWindowView* mainWindowView) + : QToolBar{tr("Tool Bar"), mainWindowView}, + mainWindow{mainWindowView} +{ + actionLeftToolbarArxiv = addAction( + QIcon(":/icons/adapt.svg"), + "Open arXiv and find papers related to the current context... (Alt-1)"); + + actionLeftToolbarWikipedia = addAction( + QIcon(":/icons/adapt.svg"), + "Open Wikipedia and find entries related to the current context... (Alt-2)"); + + actionLeftToolbarStackOverflow = addAction( + QIcon(":/icons/adapt.svg"), + "Open StackOverflow and find entries related to the current context... (Alt-3)"); + + actionLeftToolbarDuckDuckGo = addAction( + QIcon(":/icons/adapt.svg"), + "Open DuckDuckGo and find entries related to the current context... (Alt-5)"); + + actionLeftToolbarGitHub = addAction( + QIcon(":/icons/adapt.svg"), + "Open GitHub and find entries related to the current context... (Alt-6)"); + + actionLeftToolbarBard = addAction( + QIcon(":/icons/adapt.svg"), + "Open Bard and chat about the current context... (Alt-7)"); +} + +LeftToolbarView::~LeftToolbarView() +{ +} + +} // m8r namespace diff --git a/app/src/qt/left_toolbar_view.h b/app/src/qt/left_toolbar_view.h new file mode 100644 index 00000000..a45e46bc --- /dev/null +++ b/app/src/qt/left_toolbar_view.h @@ -0,0 +1,73 @@ +/* + left_toolbar_view.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_LEFT_TOOLBAR_VIEW_H +#define M8RUI_LEFT_TOOLBAR_VIEW_H + +#include + +#include "main_window_view.h" + +namespace m8r { + +class MainWindowView; + +class LeftToolbarView : public QToolBar +{ + Q_OBJECT + + MainWindowView* mainWindow; + +public: + QAction* actionLeftToolbarArxiv; + QAction* actionLeftToolbarWikipedia; + QAction* actionLeftToolbarStackOverflow; + QAction* actionLeftToolbarDuckDuckGo; + QAction* actionLeftToolbarGitHub; + QAction* actionLeftToolbarBard; + + // IMPORTANT: hide event hidden as it was causing undesired configuration + // changes and toolbar hiding on Qt's spontaneous hide/show events. Citation + // from Qt doc: + // + // "Note: A widget receives spontaneous show and hide events when its mapping + // status is changed by the window system, e.g. a spontaneous hide event when + // the user minimizes the window, and a spontaneous show event when the window + // is restored again. After receiving a spontaneous hide event, a widget is + // still considered visible in the sense of isVisible()." + // + // Even use of this->isVisible() within the event didn't fixed the problem. + // + // @see https://github.com/dvorka/mindforger/issues/1437 + // + // void hideEvent(QHideEvent *) override; + +public: + explicit LeftToolbarView(MainWindowView* mainWindowView); + LeftToolbarView(const LeftToolbarView&) = delete; + LeftToolbarView(const LeftToolbarView&&) = delete; + LeftToolbarView &operator=(const LeftToolbarView&) = delete; + LeftToolbarView &operator=(const LeftToolbarView&&) = delete; + ~LeftToolbarView(); + +signals: + void signalLeftToolbarVisibilityChanged(bool visibility); +}; + +} +#endif // M8RUI_LEFT_TOOLBAR_VIEW_H diff --git a/app/src/qt/look_n_feel.cpp b/app/src/qt/look_n_feel.cpp index d0712481..104579ac 100644 --- a/app/src/qt/look_n_feel.cpp +++ b/app/src/qt/look_n_feel.cpp @@ -1,7 +1,7 @@ /* look_n_feel.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -102,7 +102,8 @@ void LookAndFeels::setDarkTheme() editorLink.setRgb(0x00,0xFF,0xFF); editorList.setRgb(0x00,0x99,0x00); editorTaskDone.setRgb(0x00,0x99,0x00); - editorTaskWip.setRgb(0x99,0x00,0x00); + editorTaskWip.setRgb(0xFF,0xA5,0x00); + editorTaskTodo.setRgb(0x99,0x00,0x00); editorCodeblock.setRgb(0x99,0x99,0x99); editorHtmlTag.setRgb(0xAA,0x00,0xAA); editorHtmlEntity.setRgb(0xAA,0x00,0xAA); diff --git a/app/src/qt/look_n_feel.h b/app/src/qt/look_n_feel.h index 5844a512..f8311f9e 100644 --- a/app/src/qt/look_n_feel.h +++ b/app/src/qt/look_n_feel.h @@ -1,7 +1,7 @@ /* look_n_feel.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -82,6 +82,7 @@ class LookAndFeels : public HtmlColorsRepresentation QColor editorList; QColor editorTaskDone; QColor editorTaskWip; + QColor editorTaskTodo; QColor editorHtmlTag; QColor editorHtmlEntity; QColor editorHtmlAttrName; @@ -148,6 +149,7 @@ class LookAndFeels : public HtmlColorsRepresentation QColor& getEditorList() { return editorList; } QColor& getEditorTaskDone() { return editorTaskDone; } QColor& getEditorTaskWip() { return editorTaskWip; } + QColor& getEditorTaskTodo() { return editorTaskTodo; } QColor& getEditorCodeblock() { return editorCodeblock; } QColor& getEditorHtmlTag() { return editorHtmlTag; } QColor& getEditorHtmlEntity() { return editorHtmlEntity; } diff --git a/app/src/qt/main_menu_presenter.cpp b/app/src/qt/main_menu_presenter.cpp index 6c6eef65..5635c4a0 100644 --- a/app/src/qt/main_menu_presenter.cpp +++ b/app/src/qt/main_menu_presenter.cpp @@ -1,7 +1,7 @@ /* main_menu_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -29,63 +29,55 @@ MainMenuPresenter::MainMenuPresenter(MainWindowPresenter* mwp) // menu: mind QObject::connect( view->actionMindNewRepository, SIGNAL(triggered()), - mwp, SLOT(doActionMindNewRepository()) - ); + mwp, SLOT(doActionMindNewRepository())); QObject::connect( view->actionMindNewFile, SIGNAL(triggered()), - mwp, SLOT(doActionMindNewFile()) - ); + mwp, SLOT(doActionMindNewFile())); + QObject::connect( + view->actionMindWingman, SIGNAL(triggered()), + mwp, SLOT(handleActionWingman())); + QObject::connect( + view->actionMindTool, SIGNAL(triggered()), + mwp, SLOT(doActionRunToolDialogAnywhere())); QObject::connect( view->actionMindThink, SIGNAL(triggered()), - mwp, SLOT(doActionMindToggleThink()) - ); + mwp, SLOT(doActionMindToggleThink())); QObject::connect( view->actionMindAutolink, SIGNAL(triggered()), - mwp, SLOT(doActionMindToggleAutolink()) - ); + mwp, SLOT(doActionMindToggleAutolink())); + QObject::connect( + view->actionMindLearnDirectory, SIGNAL(triggered()), + mwp, SLOT(doActionMindLearnRepository())); QObject::connect( view->actionMindLearnRepository, SIGNAL(triggered()), - mwp, SLOT(doActionMindLearnRepository()) - ); + mwp, SLOT(doActionMindLearnRepository())); QObject::connect( view->actionMindLearnFile, SIGNAL(triggered()), - mwp, SLOT(doActionMindLearnFile()) - ); + mwp, SLOT(doActionMindLearnFile())); for(auto& r:config.getRepositories()) { view->submenuMindRelearn->addFile(QString::fromStdString(r.first)); } QObject::connect( view->submenuMindRelearn, SIGNAL(recentFileTriggered(QString)), - mwp, SLOT(doActionMindRelearn(QString)) - ); + mwp, SLOT(doActionMindRelearn(QString))); QObject::connect( view->actionMindScope, SIGNAL(triggered()), - mwp, SLOT(doActionMindTimeTagScope()) - ); + mwp, SLOT(doActionMindTimeTagScope())); QObject::connect( view->actionMindRemember, SIGNAL(triggered()), - mwp, SLOT(doActionMindRemember()) - ); + mwp, SLOT(doActionMindRemember())); QObject::connect( view->actionMindPreferences, SIGNAL(triggered()), - mwp, SLOT(doActionMindPreferences()) - ); - QObject::connect( - view->actionViewTerminal, SIGNAL(triggered()), - mwp, SLOT(doActionViewTerminal()) - ); + mwp, SLOT(doActionMindPreferences())); QObject::connect( view->actionMindSnapshot, SIGNAL(triggered()), - mwp, SLOT(doActionMindSnapshot()) - ); + mwp, SLOT(doActionMindSnapshot())); QObject::connect( view->actionMindExportCsv, SIGNAL(triggered()), - mwp, SLOT(doActionMindCsvExport()) - ); + mwp, SLOT(doActionMindCsvExport())); QObject::connect( view->actionExit, SIGNAL(triggered()), - mwp, SLOT(doActionExit()) - ); + mwp, SLOT(doActionExit())); #ifdef DO_MF_DEBUG QObject::connect(view->actionMindHack, SIGNAL(triggered()), mwp, SLOT(doActionMindHack())); #endif @@ -96,18 +88,18 @@ MainMenuPresenter::MainMenuPresenter(MainWindowPresenter* mwp) QObject::connect(view->actionFindNoteByName, SIGNAL(triggered()), mwp, SLOT(doActionFindNoteByName())); QObject::connect(view->actionFindOutlineByTag, SIGNAL(triggered()), mwp, SLOT(doActionFindOutlineByTag())); QObject::connect(view->actionFindNoteByTag, SIGNAL(triggered()), mwp, SLOT(doActionFindNoteByTag())); -#ifdef MF_NER - QObject::connect(view->actionFindNerPersons, SIGNAL(triggered()), mwp, SLOT(doActionFindNerPersons())); - QObject::connect(view->actionFindNerLocations, SIGNAL(triggered()), mwp, SLOT(doActionFindNerLocations())); - QObject::connect(view->actionFindNerOrganizations, SIGNAL(triggered()), mwp, SLOT(doActionFindNerOrganizations())); - QObject::connect(view->actionFindNerMisc, SIGNAL(triggered()), mwp, SLOT(doActionFindNerMisc())); -#endif // menu: view - QObject::connect(view->actionViewDashboard, SIGNAL(triggered()), mwp, SLOT(doActionViewDashboard())); + QObject::connect( + view->actionViewTerminal, SIGNAL(triggered()), + mwp, SLOT(doActionViewTerminal())); + QObject::connect( + view->actionViewLimbo, SIGNAL(triggered()), + mwp, SLOT(doActionViewLimbo())); QObject::connect(view->actionViewHome, SIGNAL(triggered()), mwp, SLOT(doActionViewHome())); QObject::connect(view->actionViewOrganizers, SIGNAL(triggered()), mwp, SLOT(doActionViewOrganizers())); QObject::connect(view->actionViewOutlines, SIGNAL(triggered()), mwp, SLOT(doActionViewOutlines())); + QObject::connect(view->actionViewOutlinesMap, SIGNAL(triggered()), mwp, SLOT(doActionViewOutlinesMap())); QObject::connect(view->actionViewTags, SIGNAL(triggered()), mwp, SLOT(doActionViewTagCloud())); QObject::connect(view->actionViewNavigator, SIGNAL(triggered()), mwp, SLOT(doActionViewKnowledgeGraphNavigator())); QObject::connect(view->actionViewCli, SIGNAL(triggered()), mwp, SLOT(doActionCli())); @@ -120,16 +112,10 @@ MainMenuPresenter::MainMenuPresenter(MainWindowPresenter* mwp) // IMPROVE complete edge shrinking & zooming (skipped as shortcut/mouse wheel is the much more reasonable) QObject::connect(view->actionNavigatorShuffle, SIGNAL(triggered()), mwp, SLOT(doActionNavigatorShuffle())); - // menu: Knowledge -#ifdef MF_WIP_KNOW - QObject::connect(view->actionKnowledgeWikipedia, SIGNAL(triggered()), mwp, SLOT(doActionKnowledgeWikipedia())); - QObject::connect(view->actionKnowledgeArxiv, SIGNAL(triggered()), mwp, SLOT(doActionKnowledgeArxiv())); -#endif - // menu: Library -#ifdef MF_WIP QObject::connect(view->actionLibraryAdd, SIGNAL(triggered()), mwp, SLOT(doActionLibraryNew())); -#endif + QObject::connect(view->actionLibrarySync, SIGNAL(triggered()), mwp, SLOT(doActionLibrarySync())); + QObject::connect(view->actionLibraryDeprecate, SIGNAL(triggered()), mwp, SLOT(doActionLibraryRm())); // menu: Organizer QObject::connect( @@ -167,12 +153,72 @@ MainMenuPresenter::MainMenuPresenter(MainWindowPresenter* mwp) QObject::connect( view->actionOutlineClone, SIGNAL(triggered()), mwp, SLOT(doActionOutlineClone())); + QObject::connect( + view->actionOutlinePromote, SIGNAL(triggered()), + mwp, SLOT(doActionNotePromote())); + QObject::connect( + view->actionOutlineDemote, SIGNAL(triggered()), + mwp, SLOT(doActionNoteDemote())); + QObject::connect( + view->actionOutlineFirst, SIGNAL(triggered()), + mwp, SLOT(doActionNoteFirst())); + QObject::connect( + view->actionOutlineUp, SIGNAL(triggered()), + mwp, SLOT(doActionNoteUp())); + QObject::connect( + view->actionOutlineDown, SIGNAL(triggered()), + mwp, SLOT(doActionNoteDown())); + QObject::connect( + view->actionOutlineLast, SIGNAL(triggered()), + mwp, SLOT(doActionNoteLast())); QObject::connect( view->actionOutlineHtmlExport, SIGNAL(triggered()), mwp, SLOT(doActionOutlineHtmlExport())); QObject::connect( view->actionOutlineTWikiImport, SIGNAL(triggered()), mwp, SLOT(doActionOutlineTWikiImport())); + // wingman: Outline + QObject::connect( + view->actionOutlineWingmanSummarize, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanOSummarize())); + QObject::connect( + view->actionOutlineWingmanExplain, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanOExplain())); + QObject::connect( + view->actionOutlineWingmanFind, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanOFind())); + QObject::connect( + view->actionOutlineWingmanMore, SIGNAL(triggered()), + mwp, SLOT(handleActionWingman())); + // wingman: Note + QObject::connect( + view->actionNoteWingmanSummarize, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanNSummarize())); + QObject::connect( + view->actionNoteWingmanFixGrammar, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanNFixGrammar())); + QObject::connect( + view->actionNoteWingmanRewrite, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanNRewrite())); + QObject::connect( + view->actionNoteWingmanMore, SIGNAL(triggered()), + mwp, SLOT(handleActionWingman())); + // wingman: Text (Edit) + QObject::connect( + view->actionEditWingmanFixGrammar, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanEFixGrammar())); + QObject::connect( + view->actionEditWingmanExplain, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanEExplain())); + QObject::connect( + view->actionEditWingmanFinishText, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanEFinishText())); + QObject::connect( + view->actionEditWingmanRewriteText, SIGNAL(triggered()), + mwp, SLOT(doActionWingmanERewriteText())); + QObject::connect( + view->actionEditWingmanMore, SIGNAL(triggered()), + mwp, SLOT(handleActionWingman())); // menu: Note QObject::connect( @@ -240,6 +286,9 @@ MainMenuPresenter::MainMenuPresenter(MainWindowPresenter* mwp) mwp, SLOT(doActionSpellCheck())); // menu: format + QObject::connect( + view->actionFormatEmojis, SIGNAL(triggered()), + mwp, SLOT(doActionEmojisDialog())); QObject::connect(view->actionFormatBold, SIGNAL(triggered()), mwp, SLOT(doActionFormatBold())); QObject::connect(view->actionFormatItalic, SIGNAL(triggered()), mwp, SLOT(doActionFormatItalic())); QObject::connect(view->actionFormatCode, SIGNAL(triggered()), mwp, SLOT(doActionFormatCode())); @@ -270,7 +319,8 @@ MainMenuPresenter::MainMenuPresenter(MainWindowPresenter* mwp) QObject::connect(view->actionFormatListNumber, SIGNAL(triggered()), mwp, SLOT(doActionFormatListNumber())); QObject::connect(view->actionFormatListTask, SIGNAL(triggered()), mwp, SLOT(doActionFormatListTask())); QObject::connect(view->actionFormatListTaskItem, SIGNAL(triggered()), mwp, SLOT(doActionFormatListTaskItem())); - QObject::connect(view->actionFormatToc, SIGNAL(triggered()), mwp, SLOT(doActionFormatToc())); + QObject::connect(view->actionFormatTocWithoutTags, SIGNAL(triggered()), mwp, SLOT(doActionFormatTocWithoutTags())); + QObject::connect(view->actionFormatTocWithTags, SIGNAL(triggered()), mwp, SLOT(doActionFormatTocWithTags())); QObject::connect(view->actionFormatTimestamp, SIGNAL(triggered()), mwp, SLOT(doActionFormatTimestamp())); QObject::connect(view->actionFormatCodeBlock, SIGNAL(triggered()), mwp, SLOT(doActionFormatCodeBlock())); QObject::connect(view->actionFormatMathBlock, SIGNAL(triggered()), mwp, SLOT(doActionFormatMathBlock())); @@ -319,19 +369,20 @@ MainMenuPresenter::~MainMenuPresenter() // TODO deletes: actions } -void MainMenuPresenter::showFacetDashboard() -{ - view->showFacetOutlineList(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY); -} - void MainMenuPresenter::showFacetOrganizerList() { - view->showFacetOrganizerList(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY); + view->showFacetOrganizerList( + config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY, + config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER + ); } void MainMenuPresenter::showFacetOrganizer() { - view->showFacetOrganizerView(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY); + view->showFacetOrganizerView( + config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY, + config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER + ); } void MainMenuPresenter::showFacetNavigator() @@ -339,19 +390,36 @@ void MainMenuPresenter::showFacetNavigator() view->showFacetNavigator(); } +void MainMenuPresenter::showFacetOutlinesMap() +{ + view->showFacetOutlinesMap( + config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY, + config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER + ); +} + void MainMenuPresenter::showFacetOutlineList() { - view->showFacetOutlineList(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY); + view->showFacetOutlineList( + config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY, + config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER + ); } void MainMenuPresenter::showFacetOutlineView() { - view->showFacetOutlineView(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY); + view->showFacetOutlineView( + config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY, + config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER + ); } void MainMenuPresenter::showFacetNoteEdit() { - view->showFacetNoteEdit(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY); + view->showFacetNoteEdit( + config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY, + config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER + ); } void MainMenuPresenter::showFacetMindThink() diff --git a/app/src/qt/main_menu_presenter.h b/app/src/qt/main_menu_presenter.h index 66333f80..8f252876 100644 --- a/app/src/qt/main_menu_presenter.h +++ b/app/src/qt/main_menu_presenter.h @@ -1,7 +1,7 @@ /* main_menu_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -55,11 +55,11 @@ class MainMenuPresenter : public QObject MainMenuView* getView() { return view; } - void showFacetDashboard(); void showFacetOrganizerList(); void showFacetOrganizer(); void showFacetNavigator(); + void showFacetOutlinesMap(); void showFacetOutlineList(); void showFacetOutlineView(); void showFacetNoteEdit(); diff --git a/app/src/qt/main_menu_view.cpp b/app/src/qt/main_menu_view.cpp index c365120c..a28d450e 100644 --- a/app/src/qt/main_menu_view.cpp +++ b/app/src/qt/main_menu_view.cpp @@ -1,7 +1,7 @@ -/* + /* main_menu_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -36,33 +36,58 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionMindHack->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_Z)); #endif - // new/devise... new MD repository + // new/devise... new Workspaces (MD repository) submenuMindNew = menuMind->addMenu(QIcon(":/menu-icons/new.svg"), "&New"); - actionMindNewRepository = new QAction(tr("MindForger &Repository"), mainWindow); - actionMindNewRepository->setStatusTip(tr("Create a brand new MindForger repository...")); + actionMindNewRepository = new QAction(tr("&Workspace"), mainWindow); + actionMindNewRepository->setStatusTip( + tr("Create a brand new MindForger workspace...") + ); submenuMindNew->addAction(actionMindNewRepository); actionMindNewFile = new QAction(tr("Markdown &File"), mainWindow); actionMindNewFile->setStatusTip(tr("Create a brand new Markdown file...")); submenuMindNew->addAction(actionMindNewFile); - // learn... from a repository, Markdown or TXT file + // learn... from a workspace, Markdown or TXT file submenuMindLearn = menuMind->addMenu(QIcon(":/menu-icons/open.svg"), tr("&Learn")); - actionMindLearnRepository = new QAction(tr("&Directory with Markdowns or MindForger Repository"), mainWindow); - actionMindLearnRepository->setStatusTip(tr("Learn knowledge by loading a MindForger repository or a directory with Markdown files...")); + actionMindLearnRepository = new QAction( + tr("&Workspace"), mainWindow + ); + actionMindLearnRepository->setStatusTip( + tr("Learn knowledge by loading a MindForger workspace...") + ); submenuMindLearn->addAction(actionMindLearnRepository); + actionMindLearnDirectory = new QAction( + tr("&Directory with Markdowns"), mainWindow + ); + actionMindLearnDirectory->setStatusTip( + tr("Learn knowledge by loading a directory with Markdown files...") + ); + submenuMindLearn->addAction(actionMindLearnDirectory); actionMindLearnFile = new QAction(tr("Markdown &File"), mainWindow); - actionMindLearnFile->setStatusTip(tr("Learn knowledge by loading a Markdown or MindForger file...")); + actionMindLearnFile->setStatusTip( + tr("Learn knowledge by loading a Markdown file...") + ); submenuMindLearn->addAction(actionMindLearnFile); // re-learn/remind ... recent repositories and files submenuMindRelearn = new RecentFilesMenu(tr("&Remind"), mainWindow); - submenuMindRelearn->setStatusTip(tr("Re-learn recently opened MindForger repositories, Markdown repositories or files")); + submenuMindRelearn->setStatusTip( + tr( + "Re-learn recently opened MindForger workspaces, " + "Markdown directories or files") + ); submenuMindRelearn->setEnabled(false); // remember... by flushing caches, saving unsaved Ns, saving Os/Ns with changed read metadata, ... actionMindRemember = new QAction(QIcon(":/menu-icons/save.svg"), tr("Re&member"), mainWindow); actionMindRemember->setStatusTip(tr("Persist all Things in Memory")); + // TODO remove this menu item > make it Configuration option in Mind menu (Limbo or erase) + // forget ... move to Limbo or erase + actionMindForget = new QAction(QIcon(":/menu-icons/delete.svg"), tr("&Forget"), mainWindow); + actionMindForget->setStatusTip(tr("Limbo vs erase memory...")); + actionMindForget->setEnabled(false); + // recall ... smart *combined* (semantic) mind search using FTS/associations/... to find O or N //actionMindRecall = new QAction(tr("&Recall"), mainWindow); // IMPROVE show memory dwell as a base for reminding a note @@ -79,27 +104,63 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) #ifdef MF_MD_2_HTML_CMARK actionMindAutolink->setCheckable(true); actionMindAutolink->setStatusTip(tr("Automatically inject links to relevant Notebooks and Notes when browsing HTML preview")); - actionMindAutolink->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_A)); + actionMindAutolink->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_L)); #else actionMindAutolink->setVisible(false); #endif + actionMindWingman = new QAction(QIcon(":/menu-icons/wingman-green.svg"), tr("&Wingman GPT"), mainWindow); + actionMindWingman->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Slash)); + actionMindWingman->setStatusTip(tr("Open Wingman dialog...")); + + actionMindTool = new QAction(QIcon(":/menu-icons/find.svg"), tr("&Find on Web"), mainWindow); + actionMindTool->setShortcut(QKeySequence(Qt::ALT+Qt::Key_1)); + actionMindTool->setStatusTip(tr("Find Notebook or Note name; selected text or text under cursor on the web...")); + // scope ... don't show any N/O older than 1Y/3M/... actionMindScope = new QAction(QIcon(":/menu-icons/filter.svg"), tr("S&cope"), mainWindow); actionMindScope->setStatusTip(tr("Don't show Notebooks and Notes older than...")); - // TODO remove this menu item > make it Configuration option in Mind menu (Limbo or erase) - // forget ... move to Limbo or erase - actionMindForget = new QAction(QIcon(":/menu-icons/delete.svg"), tr("&Forget"), mainWindow); - actionMindForget->setStatusTip(tr("Limbo vs erase memory...")); - actionMindForget->setEnabled(false); + // SUBMENU: library + submenuMindLibrary = menuMind->addMenu(QIcon(":/menu-icons/copy.svg"), tr("Li&brary")); + // library: add + actionLibraryAdd = new QAction( + QIcon(":/menu-icons/new.svg"), tr("&New library"), mainWindow); + actionLibraryAdd->setStatusTip( + tr("Add path to the directory with documents (PDF, txt, HTML)...")); + // choose library > determine library src directory > re-index src directory + // show side-by-side comparison: ONLY in src / ACTION <.del> / ONLY in MF + // - includes synchronization in one on another direction + // - decisions executed AFTER user clicks DO IT button (not while editing dialog) + actionLibrarySync= new QAction( + QIcon(":/menu-icons/edit.svg"), + tr("&Update library"), + mainWindow); + actionLibrarySync->setStatusTip( + tr( + "Synchronize library source directory with MindForger notebook(s) which represent" + "library resources...")); + // library: deprecate + actionLibraryDeprecate = new QAction( + QIcon(":/menu-icons/delete.svg"), tr("&Delete library"), mainWindow); + actionLibraryDeprecate->setStatusTip(tr( + "Delete all Notebooks representing the library resources...")); + // assemble Library sub-menu + submenuMindLibrary->addAction(actionLibraryAdd); + submenuMindLibrary->addAction(actionLibrarySync); + submenuMindLibrary->addAction(actionLibraryDeprecate); // dream ... sanity, integrity, detox, inference, assoc discovery, ... //actionMindDream = new QAction(tr("&Dream"), mainWindow); //actionMindDream->setStatusTip(tr("Tidy up, clean, re-infer, check and optimize Memory which is otherwise done on your inactivity")); actionMindSnapshot = new QAction(QIcon(":/menu-icons/pin.svg"), tr("Retain"), mainWindow); - actionMindSnapshot->setStatusTip(tr("Create backup archive of the current repository and store it in home directory")); + actionMindSnapshot->setStatusTip( + tr( + "Create backup archive of the current workspace and " + "store it in home directory" + ) + ); actionMindSnapshot->setEnabled(false); // TODO submenu: printer, HTML, PDF @@ -120,18 +181,22 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuMind->addMenu(submenuMindNew); menuMind->addMenu(submenuMindLearn); menuMind->addMenu(submenuMindRelearn); - menuMind->addAction(actionMindScope); - menuMind->addAction(actionMindThink); - menuMind->addAction(actionMindAutolink); menuMind->addAction(actionMindRemember); #ifdef MF_WIP menuMind->addAction(actionMindSnapshot); + menuMind->addAction(actionMindForget); #endif + menuMind->addSeparator(); + menuMind->addAction(actionMindThink); + menuMind->addAction(actionMindAutolink); + menuMind->addAction(actionMindWingman); + menuMind->addAction(actionMindTool); + menuMind->addAction(actionMindScope); + menuMind->addSeparator(); + menuMind->addMenu(submenuMindLibrary); + menuMind->addSeparator(); menuMind->addAction(actionMindPreferences); -#ifdef MF_WIP - menuMind->addAction(actionMindForget); menuMind->addSeparator(); -#endif menuMind->addMenu(submenuMindExport); menuMind->addSeparator(); menuMind->addAction(actionExit); @@ -150,64 +215,45 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) #endif actionFindFts->setStatusTip(tr("Note full-text search")); - actionFindOutlineByName = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall Note&book by Name"), mainWindow); + actionFindOutlineByName = new QAction( + QIcon(":/menu-icons/find.svg"), tr("Recall Note&book by Name"), mainWindow); actionFindOutlineByName->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_B)); actionFindOutlineByName->setStatusTip(tr("Find Notebook by name")); - actionFindNoteByName = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall &Note by Name"), mainWindow); + actionFindNoteByName = new QAction( + QIcon(":/menu-icons/find.svg"), tr("Recall &Note by Name"), mainWindow); actionFindNoteByName->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_N)); actionFindNoteByName->setStatusTip(tr("Find Note by name")); - actionFindOutlineByTag = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall Notebook by Ta&gs"), mainWindow); + actionFindOutlineByTag = new QAction( + QIcon(":/menu-icons/find.svg"), tr("Recall Notebook by Ta&gs"), mainWindow); actionFindOutlineByTag->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_X)); actionFindOutlineByTag->setStatusTip(tr("Find Notebook by tags")); - actionFindNoteByTag = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall Note by &Tags"), mainWindow); - actionFindNoteByTag->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_T)); + actionFindNoteByTag = new QAction( + QIcon(":/menu-icons/find.svg"), tr("Recall Note by T&ags"), mainWindow); + actionFindNoteByTag->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_A)); actionFindNoteByTag->setStatusTip(tr("Find Note by tags")); #ifdef MF_WIP - actionFindDocByName = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall Library &Doc by Name"), mainWindow); + actionFindDocByName = new QAction( + QIcon(":/menu-icons/find.svg"), tr("Recall Library &Doc by Name"), mainWindow); actionFindDocByName->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_D)); actionFindDocByName->setStatusTip(tr("Find Document by name")); #endif -#ifdef MF_NER - actionFindNerPersons = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall &Persons"), mainWindow); - actionFindNerPersons->setStatusTip(tr("Find persons using Named-entity recognition (NER)")); - - actionFindNerLocations = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall &Locations"), mainWindow); - actionFindNerLocations->setStatusTip(tr("Find locations using Named-entity recognition (NER)")); - - actionFindNerOrganizations = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall Organizations"), mainWindow); - actionFindNerOrganizations->setStatusTip(tr("Find organizations using Named-entity recognition (NER)")); - - actionFindNerMisc = new QAction(QIcon(":/menu-icons/find.svg"), tr("Recall Other Entities"), mainWindow); - actionFindNerMisc->setStatusTip(tr("Find miscellaneous entities using Named-entity recognition (NER)")); -#endif - menuFind = qMenuBar->addMenu(tr("&Recall")); menuFind->addAction(actionFindFts); menuFind->addAction(actionFindOutlineByName); menuFind->addAction(actionFindNoteByName); menuFind->addAction(actionFindOutlineByTag); - menuFind->addAction(actionFindNoteByTag); + menuFind->addAction(actionFindNoteByTag); #ifdef MF_WIP menuFind->addAction(actionFindDocByName); #endif -#ifdef MF_NER - menuFind->addSeparator(); - menuFind->addAction(actionFindNerPersons); - menuFind->addAction(actionFindNerLocations); - menuFind->addAction(actionFindNerOrganizations); - menuFind->addAction(actionFindNerMisc); -#endif // menu: view - actionViewDashboard = new QAction(QIcon(":/menu-icons/dashboard.svg"), tr("Dashboard"), mainWindow); - actionViewDashboard->setStatusTip(tr("Open Dashboard...")); - actionViewHome = new QAction(QIcon(":/menu-icons/home.svg"), tr("&Home Notebook"), mainWindow); actionViewHome->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_H)); actionViewHome->setStatusTip(tr("Open Home Notebook...")); @@ -224,9 +270,15 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionViewOutlines->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_O)); actionViewOutlines->setStatusTip(tr("Show list of Notebooks...")); + actionViewOutlinesMap = new QAction(QIcon(":/menu-icons/dashboard.svg"), tr("Note&books Tree"), mainWindow); + actionViewOutlinesMap->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_T)); + actionViewOutlinesMap->setStatusTip(tr("Show tree of Notebooks...")); + +#ifdef MF_WIP actionViewLibraryDocs = new QAction(QIcon(":/menu-icons/copy.svg"), tr("&Library Documents"), mainWindow); actionViewLibraryDocs->setStatusTip(tr("List Library documents...")); - actionViewLibraryDocs->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_L)); + //actionViewLibraryDocs->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_)); +#endif actionViewTags = new QAction(QIcon(":/menu-icons/tag.svg"), tr("&Tags"), mainWindow); actionViewTags->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_G)); @@ -244,8 +296,12 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionViewCli->setShortcut(QKeySequence(Qt::ALT+Qt::Key_X)); actionViewCli->setStatusTip(tr("Activate command line interface...")); - actionViewTerminal = new QAction(QIcon(":/menu-icons/terminal.svg"), tr("Ter&minal"), mainWindow); - actionViewTerminal->setStatusTip(tr("Run simple command line from current MindForger repository...")); + actionViewTerminal = new QAction( + QIcon(":/menu-icons/terminal.svg"), tr("Ter&minal"), mainWindow + ); + actionViewTerminal->setStatusTip( + tr("Run simple command line from current MindForger workspace...") + ); actionViewRecentNotes = new QAction( QIcon(":/menu-icons/open-recent.svg"), @@ -255,42 +311,45 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionViewRecentNotes->setStatusTip(tr("View recently modified Notes...")); actionViewRecentNotes->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_R)); - actionViewStencils = new QAction(QIcon(":/menu-icons/stencil.svg"), tr("&Stencils"), mainWindow); + actionViewStencils = new QAction( + QIcon(":/menu-icons/stencil.svg"), tr("&Stencils"), mainWindow); // Outline/Note marked w/ tag stencil is MOVED among stencils (NOT indexed/searched/...) // + Stencil view allows making a stencil outline again // + Note stencils are notes in a given Outline actionViewStencils->setStatusTip(tr("List Notebook and Note stencils...")); actionViewStencils->setEnabled(false); - actionViewLimbo = new QAction(QIcon(":/menu-icons/limbo.svg"), tr("Li&mbo"), mainWindow); + actionViewLimbo = new QAction( + QIcon(":/menu-icons/limbo.svg"), tr("Li&mbo"), mainWindow); actionViewLimbo->setStatusTip(tr("List forgotten Notebooks and Notes...")); - actionViewLimbo->setEnabled(false); - // TODO same handler as Help/Documentation - open dir w/ limbo files + actionViewLimbo->setEnabled(true); - actionViewHoist = new QAction(QIcon(":/menu-icons/hoisting.svg"), tr("Ho&isting"), mainWindow); + actionViewHoist = new QAction( + QIcon(":/menu-icons/hoisting.svg"), tr("Ho&ist"), mainWindow); actionViewHoist->setCheckable(true); actionViewHoist->setChecked(false); actionViewHoist->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_I)); - actionViewHoist->setStatusTip(tr("Hoist/de-hoist Note to focus on Note being viewed or edited")); + actionViewHoist->setStatusTip( + tr("Hoist/de-hoist Note to focus on Note being viewed or edited")); - actionViewDistractionFree = new QAction(QIcon(":/menu-icons/off.svg"), tr("D&istraction Free"), mainWindow); + actionViewDistractionFree = new QAction( + QIcon(":/menu-icons/off.svg"), tr("D&istraction Free"), mainWindow); actionViewDistractionFree->setShortcut(QKeySequence(Qt::Key_F5)); actionViewDistractionFree->setStatusTip(tr("Toggle distraction free mode")); actionViewDistractionFree->setEnabled(false); - actionViewFullscreen = new QAction(QIcon(":/menu-icons/fullscreen.svg"), tr("&Fullscreen"), mainWindow); + actionViewFullscreen = new QAction( + QIcon(":/menu-icons/fullscreen.svg"), tr("&Fullscreen"), mainWindow); actionViewFullscreen->setShortcut(QKeySequence(Qt::Key_F11)); actionViewFullscreen->setStatusTip(tr("Toggle fullscreen")); menuView = qMenuBar->addMenu(tr("&View")); -#ifdef MF_WIP - menuView->addAction(actionViewDashboard); -#endif menuView->addAction(actionViewHome); #ifdef MF_WIP menuView->addAction(actionViewDecks); #endif menuView->addAction(actionViewOrganizers); + menuView->addAction(actionViewOutlinesMap); menuView->addAction(actionViewOutlines); #ifdef MF_WIP menuView->addAction(actionViewLibraryDocs); @@ -298,12 +357,12 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuView->addAction(actionViewTags); menuView->addAction(actionViewNavigator); menuView->addAction(actionViewCli); - menuView->addAction(actionViewTerminal); #ifdef MF_WIP + menuView->addAction(actionViewTerminal); menuView->addAction(actionViewStencils); menuView->addAction(actionViewDwell); - menuView->addAction(actionViewLimbo); #endif + menuView->addAction(actionViewLimbo); menuView->addSeparator(); menuView->addAction(actionViewRecentNotes); menuView->addSeparator(); @@ -313,20 +372,6 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) #endif menuView->addAction(actionViewFullscreen); - // menu: knowledge -#ifdef MF_WIP_KNOW - menuKnowledge = qMenuBar->addMenu(tr("&Know")); - - actionKnowledgeWikipedia = new QAction(QIcon(":/menu-icons/link.svg"), tr("&Wikipedia"), mainWindow); - actionKnowledgeWikipedia->setStatusTip(tr("Find marked text on Wikipedia or open Wikipedia search")); - - actionKnowledgeArxiv = new QAction(QIcon(":/menu-icons/link.svg"), tr("&arXiv"), mainWindow); - actionKnowledgeArxiv->setStatusTip(tr("Find marked text on arXiv or get article by ID")); - - menuKnowledge->addAction(actionKnowledgeWikipedia); - menuKnowledge->addAction(actionKnowledgeArxiv); -#endif - // menu: navigator #ifdef __APPLE__ actionNavigatorEdgesStretch = new QAction(tr("Str&etch edges"), mainWindow); @@ -351,7 +396,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionNavigatorShuffle = new QAction(tr("&Shuffle\tSpace"), mainWindow); actionNavigatorShuffle->setStatusTip(tr("Shuffle knowledge graph")); - menuNavigator = qMenuBar->addMenu(tr("Na&vigate")); + menuNavigator = qMenuBar->addMenu(tr("N&avigate")); menuNavigator->addAction(actionNavigatorEdgesStretch); menuNavigator->addAction(actionNavigatorEdgesShrink); menuNavigator->addSeparator(); @@ -361,21 +406,6 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuNavigator->addAction(actionNavigatorShuffle); menuNavigator->setEnabled(false); - // menu: library -#ifdef MF_WIP - menuLibrary = qMenuBar->addMenu(tr("Libr&ary")); - - actionLibraryAdd = new QAction(QIcon(":/menu-icons/new.svg"), tr("&Add library"), mainWindow); - actionLibraryAdd->setStatusTip(tr("Add directory with documents, URL or other resource to library...")); - - actionLibraryDeprecate = new QAction(QIcon(":/menu-icons/delete.svg"), tr("&Deprecate library"), mainWindow); - actionLibraryDeprecate->setStatusTip(tr("Move a library resource with documents to limbo...")); - actionLibraryDeprecate->setDisabled(true); - - menuLibrary->addAction(actionLibraryAdd); - // menuLibrary->addAction(actionLibraryDeprecate); -#endif - // menu: flashcards #ifdef MF_WIP menuFlashcards = qMenuBar->addMenu(tr("Flash&cards")); @@ -440,7 +470,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) #endif mainWindow ); - actionOrganizerFocusPrevious->setStatusTip(tr("Move focus to previous column or quandrant...")); + actionOrganizerFocusPrevious->setStatusTip(tr("Move focus to previous column or quadrant...")); actionOrganizerFocusNext = new QAction( QIcon(":/menu-icons/right.svg"), @@ -452,7 +482,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) #endif mainWindow ); - actionOrganizerFocusNext->setStatusTip(tr("Move focus to next column or quandrant...")); + actionOrganizerFocusNext->setStatusTip(tr("Move focus to next column or quadrant...")); menuOrganizer->addAction(actionOrganizerNew); menuOrganizer->addAction(actionOrganizerEdit); @@ -491,7 +521,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionOutlineStencil->setStatusTip(tr("Copy the current Notebook as to Stencil")); actionOutlineStencil->setEnabled(false); - actionOutlineClone = new QAction(QIcon(":/menu-icons/copy.svg"), tr("C&lone"), mainWindow); + actionOutlineClone = new QAction(QIcon(":/menu-icons/copy.svg"), tr("&Clone"), mainWindow); actionOutlineClone->setStatusTip(tr("Make copy of the current Notebook")); actionOutlineArtExamine= new QAction(QIcon(":/menu-icons/on.svg"), tr("E&xamine"), mainWindow); @@ -500,6 +530,29 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionOutlineForget = new QAction(QIcon(":/menu-icons/delete.svg"), tr("&Forget"), mainWindow); actionOutlineForget->setStatusTip(tr("Forget Notebook and move it to Limbo")); + actionOutlinePromote = new QAction(QIcon(":/menu-icons/left.svg"), tr("&Promote"), mainWindow); + actionOutlinePromote->setStatusTip(tr("Promote Notebook")); + + actionOutlineDemote = new QAction(QIcon(":/menu-icons/right.svg"), tr("De&mote"), mainWindow); + actionOutlineDemote->setStatusTip(tr("Demote Notebook")); + + actionOutlineFirst = new QAction( + QIcon(":/menu-icons/top.svg"), tr("Move to &First"), + mainWindow); + actionOutlineFirst->setStatusTip(tr("Move the Notebook to be the first child of its parent")); + + actionOutlineUp = new QAction( + QIcon(":/menu-icons/up.svg"), tr("Move &Up"), mainWindow); + actionOutlineUp->setStatusTip(tr("Move the Notebook up")); + + actionOutlineDown = new QAction( + QIcon(":/menu-icons/down.svg"), tr("Move D&own"), mainWindow); + actionOutlineDown->setStatusTip(tr("Move the Notebook down")); + + actionOutlineLast = new QAction( + QIcon(":/menu-icons/bottom.svg"), tr("Move to &Last"), mainWindow); + actionOutlineLast->setStatusTip(tr("Move the Notebook to be the last child of its parent")); + submenuOutlineExport = menuOutline->addMenu(QIcon(":/menu-icons/export.svg"), "E&xport"); actionOutlineHtmlExport = new QAction(tr("&HTML"), mainWindow); actionOutlineHtmlExport->setStatusTip(tr("Export Notebook to a file in HTML format")); @@ -512,15 +565,38 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionOutlineTWikiImport->setStatusTip(tr("Import Notebook from an external TWiki file and restart MindForger")); submenuOutlineImport->addAction(actionOutlineTWikiImport); + submenuOutlineWingman = menuOutline->addMenu(QIcon(":/menu-icons/wingman-green.svg"), tr("&Wingman GPT")); + actionOutlineWingmanSummarize = new QAction(tr("&Summarize"), mainWindow); + actionOutlineWingmanSummarize->setStatusTip(tr("Ask Wingman to summarize text of the Notebook...")); + submenuOutlineWingman->addAction(actionOutlineWingmanSummarize); + actionOutlineWingmanExplain = new QAction(tr("&Explain"), mainWindow); + actionOutlineWingmanExplain->setStatusTip(tr("Ask Wingman to explain the name of the Notebook...")); + submenuOutlineWingman->addAction(actionOutlineWingmanExplain); + actionOutlineWingmanFind = new QAction(tr("&Find Tasks"), mainWindow); + actionOutlineWingmanFind->setStatusTip(tr("Ask Wingman to find tasks in the Notebook text...")); + submenuOutlineWingman->addAction(actionOutlineWingmanFind); + actionOutlineWingmanMore = new QAction(tr("&More prompts..."), mainWindow); + actionOutlineWingmanMore->setStatusTip(tr("Open Wingman chat...")); + submenuOutlineWingman->addAction(actionOutlineWingmanMore); + menuOutline->addAction(actionOutlineNew); menuOutline->addAction(actionOutlineEdit); menuOutline->addAction(actionOutlineForget); menuOutline->addSeparator(); + menuOutline->addAction(actionOutlinePromote); + menuOutline->addAction(actionOutlineDemote); + menuOutline->addSeparator(); + menuOutline->addAction(actionOutlineFirst); + menuOutline->addAction(actionOutlineUp); + menuOutline->addAction(actionOutlineDown); + menuOutline->addAction(actionOutlineLast); + menuOutline->addSeparator(); menuOutline->addAction(actionOutlineHome); #ifdef MF_WIP menuOutline->addAction(actionOutlineStencil); #endif - menuOutline->addAction(actionOutlineClone); + menuOutline->addMenu(submenuOutlineWingman); + menuOutline->addAction(actionOutlineClone); menuOutline->addSeparator(); #ifdef MF_WIP menuOutline->addAction(actionOutlineArtExamine); @@ -530,6 +606,8 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuOutline->addMenu(submenuOutlineExport); // menu: Note + menuNote = qMenuBar->addMenu(tr("&Note")); + #ifdef __APPLE__ actionNoteNew = new QAction(QIcon(":/menu-icons/new.svg"), tr("&New"), mainWindow); actionNoteNew->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_N)); @@ -572,28 +650,35 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionNoteDemote = new QAction(QIcon(":/menu-icons/right.svg"), tr("&Demote\tCtrl+Right"), mainWindow); actionNoteDemote->setStatusTip(tr("Demote Note")); - actionNoteFirst = new QAction(QIcon(":/menu-icons/top.svg"), tr("F&irst\tCtrl+Shift+Up"), mainWindow); - actionNoteFirst->setStatusTip(tr("Move Note to be the first child of its parent")); + actionNoteFirst = new QAction( + QIcon(":/menu-icons/top.svg"), tr("Move to F&irst\tCtrl+Shift+Up"), + mainWindow); + actionNoteFirst->setStatusTip(tr("Move the Note to be the first child of its parent")); - actionNoteUp = new QAction(QIcon(":/menu-icons/up.svg"), tr("&Up\tCtrl+Up"), mainWindow); - actionNoteUp->setStatusTip(tr("Move Note up")); + actionNoteUp = new QAction( + QIcon(":/menu-icons/up.svg"), tr("Move &Up\tCtrl+Up"), mainWindow); + actionNoteUp->setStatusTip(tr("Move the Note up")); - actionNoteDown = new QAction(QIcon(":/menu-icons/down.svg"), tr("Do&wn\tCtrl+Down"), mainWindow); - actionNoteDown->setStatusTip(tr("Move Note down")); + actionNoteDown = new QAction( + QIcon(":/menu-icons/down.svg"), tr("Move Dow&n\tCtrl+Down"), mainWindow); + actionNoteDown->setStatusTip(tr("Move the Note down")); - actionNoteLast = new QAction(QIcon(":/menu-icons/bottom.svg"), tr("&Last\tCtrl+Shift+Down"), mainWindow); - actionNoteLast->setStatusTip(tr("Move Note to be the last child of its parent")); + actionNoteLast = new QAction( + QIcon(":/menu-icons/bottom.svg"), + tr("Move to &Last\tCtrl+Shift+Down"), + mainWindow); + actionNoteLast->setStatusTip(tr("Move the Note to be the last child of its parent")); actionNoteRefactor = new QAction( QIcon(":/menu-icons/refactor.svg"), #ifdef __APPLE__ - tr("Refactor\tCtrl+R"), + tr("Move to Notebook\tCtrl+R"), #else - tr("&Refactor"), + tr("&Move to Notebook"), #endif mainWindow ); - actionNoteRefactor->setStatusTip(tr("Refactor Note to another Notebook...")); + actionNoteRefactor->setStatusTip(tr("Move the current Note to another Notebook...")); actionNoteStencil = new QAction( QIcon(":/menu-icons/stencil.svg"), @@ -614,7 +699,20 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionNoteImport->setStatusTip(tr("Import Note from an external file in a supported format")); actionNoteImport->setEnabled(false); - menuNote = qMenuBar->addMenu(tr("&Note")); + submenuNoteWingman = menuNote->addMenu(QIcon(":/menu-icons/wingman-green.svg"), tr("&Wingman GPT")); + actionNoteWingmanSummarize = new QAction(tr("&Summarize"), mainWindow); + actionNoteWingmanSummarize->setStatusTip(tr("Ask Wingman to summarize text of the Note...")); + submenuNoteWingman->addAction(actionNoteWingmanSummarize); + actionNoteWingmanFixGrammar = new QAction(tr("&Find Grammar Errors"), mainWindow); + actionNoteWingmanFixGrammar->setStatusTip(tr("Ask Wingman to find grammar errors in the Note text...")); + submenuNoteWingman->addAction(actionNoteWingmanFixGrammar); + actionNoteWingmanRewrite = new QAction(tr("&Translate to English"), mainWindow); + actionNoteWingmanRewrite->setStatusTip(tr("Ask Wingman to translate the Note text to English...")); + submenuNoteWingman->addAction(actionNoteWingmanRewrite); + actionNoteWingmanMore = new QAction(tr("&More prompts..."), mainWindow); + actionNoteWingmanMore->setStatusTip(tr("Open Wingman chat...")); + submenuNoteWingman->addAction(actionNoteWingmanMore); + menuNote->addAction(actionNoteNew); menuNote->addAction(actionNoteEdit); menuNote->addAction(actionNoteExternalEdit); @@ -630,11 +728,12 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuNote->addAction(actionNoteDown); menuNote->addAction(actionNoteLast); menuNote->addSeparator(); + menuNote->addMenu(submenuNoteWingman); + menuNote->addAction(actionNoteClone); menuNote->addAction(actionNoteRefactor); #ifdef MF_WIP menuNote->addAction(actionNoteStencil); #endif - menuNote->addAction(actionNoteClone); #ifdef MF_WIP menuNote->addSeparator(); menuNote->addAction(actionNoteExport); @@ -643,6 +742,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuNote->setEnabled(false); // menu: edit + menuEdit = qMenuBar->addMenu(tr("&Edit")); actionEditFind = new QAction(QIcon(":/menu-icons/find.svg"), tr("&Find\tCtrl+Shift+F"), mainWindow); actionEditFind->setStatusTip(tr("Search Note text")); @@ -670,22 +770,41 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionEditLiveNotePreview->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_P)); actionEditLiveNotePreview->setStatusTip(tr("Toggle live HTML preview")); - actionEditWordWrap = new QAction(QIcon(":/menu-icons/word-wrap.svg"), tr("&Word Wrap"), mainWindow); + actionEditWordWrap = new QAction(QIcon(":/menu-icons/word-wrap.svg"), tr("W&ord Wrap"), mainWindow); actionEditWordWrap->setStatusTip(tr("Toggle word wrap mode")); - actionEditNameDescFocusSwap = new QAction(QIcon(":/menu-icons/up.svg"), tr("&Swap Name/Description Focus"), mainWindow); + actionEditNameDescFocusSwap = new QAction(QIcon(":/menu-icons/up.svg"), tr("Swap Nam&e/Description Focus"), mainWindow); actionEditNameDescFocusSwap->setStatusTip(tr("Swap focus of N title and description editors")); actionEditExtract = new QAction(QIcon(":/menu-icons/cut.svg"), tr("E&xtract"), mainWindow); actionEditExtract->setStatusTip(tr("Create new Note from the text selected in the current Note...")); - actionEditComplete = new QAction(QIcon(":/menu-icons/on.svg"), tr("Complete Link\tCtrl+/"), mainWindow); + actionEditWingman = new QAction(QIcon(":/menu-icons/on.svg"), tr("&Wingman"), mainWindow); // \tCtrl+/ + actionEditWingman->setStatusTip(tr("Run an external tool to find, explain, process text under the cursor")); + + actionEditComplete = new QAction(QIcon(":/menu-icons/link.svg"), tr("Complete Link\tCtrl+L"), mainWindow); actionEditComplete->setStatusTip(tr("Complete word being written by finding link to Notebook or Note")); - actionEditSpellCheck = new QAction(QIcon(":/menu-icons/paste.svg"), tr("Sp&ell Check"), mainWindow); + actionEditSpellCheck = new QAction(QIcon(":/menu-icons/paste.svg"), tr("&Spell Check"), mainWindow); actionEditSpellCheck->setStatusTip(tr("Spell check Notebook or Note description")); - menuEdit = qMenuBar->addMenu(tr("&Edit")); + submenuEditWingman = menuEdit->addMenu(QIcon(":/menu-icons/wingman-green.svg"), tr("&Wingman GPT")); + actionEditWingmanFixGrammar = new QAction(tr("&Fix Grammar"), mainWindow); + actionEditWingmanFixGrammar->setStatusTip(tr("Ask Wingman to fix grammar errors in the selected text / word under the cursor...")); + submenuEditWingman->addAction(actionEditWingmanFixGrammar); + actionEditWingmanExplain = new QAction(tr("&Explain"), mainWindow); + actionEditWingmanExplain->setStatusTip(tr("Ask Wingman to explain the word under the cursor / selected text...")); + submenuEditWingman->addAction(actionEditWingmanExplain); + actionEditWingmanFinishText = new QAction(tr("Finish &Text"), mainWindow); + actionEditWingmanFinishText->setStatusTip(tr("Ask Wingman to finish the text following the selected text / word under the cursor...")); + submenuEditWingman->addAction(actionEditWingmanFinishText); + actionEditWingmanRewriteText = new QAction(tr("&Rewrite Text"), mainWindow); + actionEditWingmanRewriteText->setStatusTip(tr("Ask Wingman to rewrite the text following the selected text / word under the cursor...")); + submenuEditWingman->addAction(actionEditWingmanRewriteText); + actionEditWingmanMore = new QAction(tr("&More prompts..."), mainWindow); + actionEditWingmanMore->setStatusTip(tr("Open Wingman chat...")); + submenuEditWingman->addAction(actionEditWingmanMore); + menuEdit->addAction(actionEditFind); menuEdit->addAction(actionEditFindNext); menuEdit->addSeparator(); @@ -700,6 +819,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuEdit->addAction(actionEditWordWrap); menuEdit->addAction(actionEditNameDescFocusSwap); menuEdit->addSeparator(); + menuEdit->addMenu(submenuEditWingman); menuEdit->addAction(actionEditComplete); menuEdit->addAction(actionEditExtract); menuEdit->addSeparator(); @@ -821,7 +941,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) submenuFormatMathJax->addSeparator(); actionFormatMathInt = new QAction(tr("&integral"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathInt); - actionFormatMathIiint = new QAction(tr("integrals"), mainWindow); + actionFormatMathIiint = new QAction(tr("in&tegrals"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathIiint); submenuFormatMathJax->addSeparator(); actionFormatMathAlpha = new QAction(tr("&alpha"), mainWindow); @@ -837,18 +957,18 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) submenuFormatMathJax->addAction(actionFormatMathBar); actionFormatMathHat = new QAction(tr("&hat"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathHat); - actionFormatMathDot = new QAction(tr("&dot"), mainWindow); + actionFormatMathDot = new QAction(tr("dot"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathDot); actionFormatMathOverrightarrow = new QAction(tr("&overrightarrow"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathOverrightarrow); submenuFormatMathJax->addSeparator(); actionFormatMathCup = new QAction(tr("&cup"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathCup); - actionFormatMathCap = new QAction(tr("&cap"), mainWindow); + actionFormatMathCap = new QAction(tr("ca&p"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathCap); actionFormatMathEmptyset = new QAction(tr("&empty set"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathEmptyset); - actionFormatMathIn = new QAction(tr("&in"), mainWindow); + actionFormatMathIn = new QAction(tr("in"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathIn); actionFormatMathNotin = new QAction(tr("¬ in"), mainWindow); submenuFormatMathJax->addAction(actionFormatMathNotin); @@ -856,8 +976,14 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionFormatStrikethrough = new QAction(tr("&Strikethrough"), mainWindow); actionFormatStrikethrough->setStatusTip(tr("Format text as strikethrough")); - actionFormatToc = new QAction(tr("T&able of Contents"), mainWindow); - actionFormatToc ->setStatusTip(tr("Insert Notebook's table of contents")); + // toc + submenuFormatToc = menuFormat->addMenu(tr("T&able of Contents")); + actionFormatTocWithoutTags = new QAction(tr("With&out tags"), mainWindow); + actionFormatTocWithoutTags ->setStatusTip(tr("Insert Notebook's table of contents without tags")); + submenuFormatToc->addAction(actionFormatTocWithoutTags); + actionFormatTocWithTags = new QAction(tr("&With tags"), mainWindow); + actionFormatTocWithTags ->setStatusTip(tr("Insert Notebook's table of contents with tags")); + submenuFormatToc->addAction(actionFormatTocWithTags); actionFormatTimestamp = new QAction(tr("Timestam&p"), mainWindow); actionFormatTimestamp ->setStatusTip(tr("Insert current date and time")); @@ -880,6 +1006,11 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionFormatHr = new QAction(tr("&Horizontal ruler"), mainWindow); actionFormatHr->setStatusTip(tr("Horizontal ruler")); + actionFormatEmojis = new QAction(tr("Emo&jis"), mainWindow); + actionFormatEmojis->setStatusTip( + tr("Open dialog with emoji characters to be copy/pasted to names, descriptions and text...") + ); + menuFormat->addAction(actionFormatBold); menuFormat->addAction(actionFormatItalic); menuFormat->addAction(actionFormatCode); @@ -888,7 +1019,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuFormat->addAction(actionFormatKeyboard); menuFormat->addAction(actionFormatComment); menuFormat->addSeparator(); - menuFormat->addAction(actionFormatToc); + menuFormat->addMenu(submenuFormatToc); menuFormat->addMenu(submenuFormatLists); menuFormat->addMenu(submenuFormatBlocks); menuFormat->addMenu(submenuFormatDiagrams); @@ -896,6 +1027,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) menuFormat->addMenu(submenuFormatMathJax); menuFormat->addAction(actionFormatTimestamp); menuFormat->addAction(actionFormatHr); + menuFormat->addAction(actionFormatEmojis); menuFormat->addSeparator(); menuFormat->addAction(actionFormatLink); menuFormat->addAction(actionFormatImage); @@ -903,7 +1035,8 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) // menu: help - actionHelpDocumentation = new QAction(QIcon(":/menu-icons/help.svg"), tr("&Documentation"), mainWindow); + actionHelpDocumentation = new QAction( + QIcon(":/menu-icons/help.svg"), tr("&Documentation"), mainWindow); actionHelpDocumentation->setShortcut(tr("F1")); actionHelpDocumentation->setStatusTip(tr("Open MindForger documentation")); @@ -928,7 +1061,7 @@ MainMenuView::MainMenuView(MainWindowView& mainWindowView) actionHelpCheckForUpdates = new QAction(QIcon(":/menu-icons/download.svg"), tr("&Check for Updates"), mainWindow); actionHelpCheckForUpdates->setStatusTip(tr("Check for MindForger updates")); - actionHelpAboutQt = new QAction(QIcon(":/menu-icons/about_qt.svg"), tr("&About Qt"), mainWindow); + actionHelpAboutQt = new QAction(QIcon(":/menu-icons/about_qt.svg"), tr("About &Qt"), mainWindow); actionHelpAboutQt->setStatusTip(tr("About Qt...")); actionHelpAbout = new QAction(QIcon(":/menu-icons/write.svg"), tr("&About MindForger"), mainWindow); @@ -967,6 +1100,8 @@ void MainMenuView::showAllMenuItems() { menuMind->setEnabled(true); // autolink: leave as is - it's not that simple as it's status, not just action + actionMindScope->setEnabled(true); + submenuMindLibrary->setEnabled(true); actionExit->setEnabled(true); menuFind->setEnabled(true); @@ -975,24 +1110,26 @@ void MainMenuView::showAllMenuItems() actionFindOutlineByTag->setEnabled(true); actionFindNoteByName->setEnabled(true); actionFindNoteByTag->setEnabled(true); +#ifdef MF_WIP + actionFindDocByName->setEnabled(true); +#endif menuView->setEnabled(true); - actionViewDashboard->setEnabled(true); actionViewHome->setEnabled(true); actionViewOrganizers->setEnabled(true); + actionViewOutlinesMap->setEnabled(true); actionViewOutlines->setEnabled(true); actionViewTags->setEnabled(true); actionViewNavigator->setEnabled(true); +#ifdef MF_WIP + actionViewLibraryDocs->setEnabled(true); + actionViewDecks->setEnabled(true); +#endif actionViewLimbo->setEnabled(true); actionViewRecentNotes->setEnabled(true); -#ifdef MF_WIP - menuLibrary->setEnabled(true); - actionLibraryAdd->setEnabled(true); - // TODO to be implemented - actionLibraryDeprecate->setEnabled(false); -#endif + actionLibraryDeprecate->setEnabled(true); #ifdef MF_WIP menuFlashcards->setEnabled(true); @@ -1014,8 +1151,23 @@ void MainMenuView::showAllMenuItems() actionOutlineClone->setEnabled(true); actionOutlineHome->setEnabled(true); actionOutlineForget->setEnabled(true); + submenuOutlineWingman->setEnabled(true); menuOutline->setEnabled(true); + actionOutlineEdit->setEnabled(true); + actionOutlineClone->setEnabled(true); + actionOutlineHome->setEnabled(true); + actionOutlineForget->setEnabled(true); + actionOutlineUp->setEnabled(true); + actionOutlineDown->setEnabled(true); + actionOutlineFirst->setEnabled(true); + actionOutlineLast->setEnabled(true); + actionOutlinePromote->setEnabled(true); + actionOutlineDemote->setEnabled(true); + actionOutlineHome->setEnabled(true); +#ifdef MF_WIP + actionOutlineArtExamine->setEnabled(true); +#endif submenuOutlineExport->setEnabled(true); menuNote->setEnabled(true); @@ -1036,7 +1188,54 @@ void MainMenuView::showAllMenuItems() mainWindow->getToolBar()->setEnabled(true); } -void MainMenuView::showFacetOrganizerList(bool repositoryMode) +void MainMenuView::showModeAwareFacet(bool repositoryMode, bool mfMode) +{ + if(!repositoryMode) { + submenuMindLibrary->setEnabled(false); + menuView->setEnabled(false); + menuOutline->setEnabled(false); + menuEdit->setEnabled(false); + menuFormat->setEnabled(false); + + actionMindScope->setEnabled(false); + + actionFindOutlineByName->setEnabled(false); + actionFindOutlineByTag->setEnabled(false); + } + if(!mfMode) { + submenuMindLibrary->setEnabled(false); +#ifdef MF_WIP + menuFlashcards->setEnabled(false); +#endif + + actionMindScope->setEnabled(false); + + actionViewHome->setEnabled(false); + actionViewOrganizers->setEnabled(false); + actionViewOutlinesMap->setEnabled(false); +#ifdef MF_WIP + actionViewLibraryDocs->setEnabled(false); +#endif + actionViewTags->setEnabled(false); + actionViewLimbo->setEnabled(false); +#ifdef MF_WIP + actionViewDecks->setEnabled(false); +#endif + + actionFindOutlineByTag->setEnabled(false); + actionFindNoteByTag->setEnabled(false); +#ifdef MF_WIP + actionFindDocByName->setEnabled(false); +#endif + + actionOutlineHome->setEnabled(false); +#ifdef MF_WIP + actionOutlineArtExamine->setEnabled(false); +#endif + } +} + +void MainMenuView::showFacetOrganizerList(bool repositoryMode, bool mfMode) { showAllMenuItems(); @@ -1048,62 +1247,60 @@ void MainMenuView::showFacetOrganizerList(bool repositoryMode) actionOrganizerMovePrevious->setEnabled(false); actionOrganizerMoveNext->setEnabled(false); -#ifdef MF_WIP_KNOW - menuKnowledge->setEnabled(false); -#endif + submenuMindLibrary->setEnabled(false); menuNavigator->setEnabled(false); -#ifdef MF_WIP - menuLibrary->setEnabled(false); -#endif menuOutline->setEnabled(false); menuNote->setEnabled(false); menuEdit->setEnabled(false); menuFormat->setEnabled(false); submenuOutlineExport->setEnabled(false); - if(!repositoryMode) { - menuView->setEnabled(false); - menuFormat->setEnabled(false); - - actionFindOutlineByName->setEnabled(false); - actionFindOutlineByTag->setEnabled(false); - } + showModeAwareFacet(repositoryMode, mfMode); } -void MainMenuView::showFacetOrganizerView(bool repositoryMode) +void MainMenuView::showFacetOrganizerView(bool repositoryMode, bool mfMode) { showAllMenuItems(); -#ifdef MF_WIP_KNOW - menuKnowledge->setEnabled(false); -#endif + submenuMindLibrary->setEnabled(false); menuNavigator->setEnabled(false); -#ifdef MF_WIP - menuLibrary->setEnabled(false); -#endif menuOutline->setEnabled(false); menuNote->setEnabled(false); menuEdit->setEnabled(false); menuFormat->setEnabled(false); submenuOutlineExport->setEnabled(false); - if(!repositoryMode) { - menuView->setEnabled(false); - menuFormat->setEnabled(false); - - actionFindOutlineByName->setEnabled(false); - actionFindOutlineByTag->setEnabled(false); - } + showModeAwareFacet(repositoryMode, mfMode); } -void MainMenuView::showFacetOutlineList(bool repositoryMode) +void MainMenuView::showFacetOutlineList(bool repositoryMode, bool mfMode) { showAllMenuItems(); + menuNavigator->setEnabled(false); + menuOrganizer->setEnabled(false); + menuEdit->setEnabled(false); + menuFormat->setEnabled(false); + menuNote->setEnabled(false); + submenuOutlineExport->setEnabled(false); + actionOutlineEdit->setEnabled(false); actionOutlineClone->setEnabled(false); actionOutlineHome->setEnabled(false); actionOutlineForget->setEnabled(false); + actionOutlineUp->setEnabled(false); + actionOutlineDown->setEnabled(false); + actionOutlineFirst->setEnabled(false); + actionOutlineLast->setEnabled(false); + actionOutlinePromote->setEnabled(false); + actionOutlineDemote->setEnabled(false); + + showModeAwareFacet(repositoryMode, mfMode); +} + +void MainMenuView::showFacetOutlinesMap(bool repositoryMode, bool mfMode) +{ + showAllMenuItems(); menuNavigator->setEnabled(false); menuOrganizer->setEnabled(false); @@ -1112,50 +1309,39 @@ void MainMenuView::showFacetOutlineList(bool repositoryMode) menuNote->setEnabled(false); submenuOutlineExport->setEnabled(false); - if(!repositoryMode) { - menuView->setEnabled(false); - menuOutline->setEnabled(false); - menuEdit->setEnabled(false); - menuFormat->setEnabled(false); - - actionFindOutlineByName->setEnabled(false); - actionFindOutlineByTag->setEnabled(false); - } + showModeAwareFacet(repositoryMode, mfMode); } -void MainMenuView::showFacetOutlineView(bool repositoryMode) +void MainMenuView::showFacetOutlineView(bool repositoryMode, bool mfMode) { showAllMenuItems(); + submenuMindLibrary->setEnabled(false); menuNavigator->setEnabled(false); -#ifdef MF_WIP - menuLibrary->setEnabled(false); -#endif menuOrganizer->setEnabled(false); menuEdit->setEnabled(false); menuFormat->setEnabled(false); - if(!repositoryMode) { - menuView->setEnabled(false); - menuOutline->setEnabled(false); - menuEdit->setEnabled(false); - menuFormat->setEnabled(false); + actionOutlineUp->setEnabled(false); + actionOutlineDown->setEnabled(false); + actionOutlineFirst->setEnabled(false); + actionOutlineLast->setEnabled(false); + actionOutlinePromote->setEnabled(false); + actionOutlineDemote->setEnabled(false); - actionFindOutlineByName->setEnabled(false); - actionFindOutlineByTag->setEnabled(false); - } + submenuOutlineWingman->setEnabled(false); + + showModeAwareFacet(repositoryMode, mfMode); } -void MainMenuView::showFacetNoteEdit(bool repositoryMode) +void MainMenuView::showFacetNoteEdit(bool repositoryMode, bool mfMode) { showAllMenuItems(); menuMind->setEnabled(false); + submenuMindLibrary->setEnabled(false); actionExit->setEnabled(false); -#ifdef MF_WIP - menuLibrary->setEnabled(false); -#endif menuOrganizer->setEnabled(false); actionOrganizerNew->setEnabled(false); actionOrganizerEdit->setEnabled(false); @@ -1173,7 +1359,6 @@ void MainMenuView::showFacetNoteEdit(bool repositoryMode) actionFindNoteByTag->setEnabled(false); menuView->setEnabled(false); - actionViewDashboard->setEnabled(false); actionViewHome->setEnabled(false); actionViewOrganizers->setEnabled(false); actionViewOutlines->setEnabled(false); @@ -1203,12 +1388,11 @@ void MainMenuView::showFacetNoteEdit(bool repositoryMode) mainWindow->getToolBar()->setEnabled(false); - if(!repositoryMode) { - menuView->setEnabled(false); - menuOutline->setEnabled(false); + showModeAwareFacet(repositoryMode, mfMode); - actionFindOutlineByName->setEnabled(false); - actionFindOutlineByTag->setEnabled(false); + if(!repositoryMode) { + menuEdit->setEnabled(true); + menuFormat->setEnabled(true); } } @@ -1236,6 +1420,12 @@ void MainMenuView::showFacetNavigator() { showAllMenuItems(); +#ifdef MF_WIP + menuFlashcards->setEnabled(false); +#endif + + menuOrganizer->setEnabled(false); + menuOutline->setEnabled(false); menuNote->setEnabled(false); menuEdit->setEnabled(false); menuFormat->setEnabled(false); diff --git a/app/src/qt/main_menu_view.h b/app/src/qt/main_menu_view.h index edc773d1..e31d09b3 100644 --- a/app/src/qt/main_menu_view.h +++ b/app/src/qt/main_menu_view.h @@ -1,7 +1,7 @@ /* main_menu.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -48,12 +48,8 @@ class MainMenuView : public QObject QMenu* menuMind; QMenu* menuFind; QMenu* menuView; -#ifdef MF_WIP_KNOW - QMenu* menuKnowledge; -#endif QMenu* menuNavigator; #ifdef MF_WIP - QMenu* menuLibrary; QMenu* menuFlashcards; #endif QMenu* menuOrganizer; @@ -61,6 +57,9 @@ class MainMenuView : public QObject QMenu* menuNote; QMenu* menuEdit; QMenu* menuFormat; +#ifdef MF_WIP + QMenu* menuTools; +#endif QMenu* menuHelp; #ifdef DO_MF_DEBUG @@ -71,15 +70,22 @@ class MainMenuView : public QObject QAction* actionMindNewRepository; QAction* actionMindNewFile; QMenu* submenuMindLearn; + QAction* actionMindLearnDirectory; QAction* actionMindLearnRepository; QAction* actionMindLearnFile; RecentFilesMenu* submenuMindRelearn; QAction* actionMindRemember; QAction* actionMindThink; QAction* actionMindAutolink; + QAction* actionMindWingman; + QAction* actionMindTool; QAction* actionMindScope; QAction* actionMindForget; QAction* actionMindSnapshot; + QMenu* submenuMindLibrary; + QAction* actionLibraryAdd; + QAction* actionLibrarySync; + QAction* actionLibraryDeprecate; QAction* actionMindPreferences; QMenu* submenuMindExport; QAction* actionMindExportCsv; @@ -94,20 +100,16 @@ class MainMenuView : public QObject #ifdef MF_WIP QAction* actionFindDocByName; #endif -#ifdef MF_NER - QAction* actionFindNerPersons; - QAction* actionFindNerLocations; - QAction* actionFindNerOrganizations; - QAction* actionFindNerMisc; -#endif // menu: View - QAction* actionViewDashboard; QAction* actionViewHome; QAction* actionViewDecks; QAction* actionViewOrganizers; QAction* actionViewOutlines; + QAction* actionViewOutlinesMap; +#ifdef MF_WIP QAction* actionViewLibraryDocs; +#endif QAction* actionViewTags; QAction* actionViewNavigator; QAction* actionViewDwell; @@ -123,10 +125,6 @@ class MainMenuView : public QObject QAction* actionKnowledgeWikipedia; QAction* actionKnowledgeArxiv; - // menu: Library - QAction* actionLibraryAdd; - QAction* actionLibraryDeprecate; - // menu: Organizer QAction* actionOrganizerNew; QAction* actionOrganizerEdit; @@ -152,10 +150,21 @@ class MainMenuView : public QObject QAction* actionOutlineClone; QAction* actionOutlineArtExamine; QAction* actionOutlineForget; + QAction* actionOutlinePromote; + QAction* actionOutlineDemote; + QAction* actionOutlineFirst; + QAction* actionOutlineUp; + QAction* actionOutlineDown; + QAction* actionOutlineLast; QMenu* submenuOutlineExport; QAction* actionOutlineHtmlExport; QMenu* submenuOutlineImport; QAction* actionOutlineTWikiImport; + QMenu* submenuOutlineWingman; + QAction* actionOutlineWingmanSummarize; + QAction* actionOutlineWingmanExplain; + QAction* actionOutlineWingmanFind; + QAction* actionOutlineWingmanMore; // menu: Note QAction* actionNoteNew; @@ -176,6 +185,11 @@ class MainMenuView : public QObject QAction* actionNoteClone; QAction* actionNoteExport; QAction* actionNoteImport; + QMenu* submenuNoteWingman; + QAction* actionNoteWingmanSummarize; + QAction* actionNoteWingmanFixGrammar; + QAction* actionNoteWingmanRewrite; + QAction* actionNoteWingmanMore; // menu: Edit QAction* actionEditFind; @@ -189,8 +203,15 @@ class MainMenuView : public QObject QAction* actionEditWordWrap; QAction* actionEditNameDescFocusSwap; QAction* actionEditExtract; + QAction* actionEditWingman; QAction* actionEditComplete; QAction* actionEditSpellCheck; + QMenu* submenuEditWingman; + QAction* actionEditWingmanFixGrammar; + QAction* actionEditWingmanExplain; + QAction* actionEditWingmanFinishText; + QAction* actionEditWingmanRewriteText; + QAction* actionEditWingmanMore; // menu: Format QAction* actionFormatBold; @@ -202,6 +223,9 @@ class MainMenuView : public QObject QAction* actionFormatCode; QAction* actionFormatCodeBlock; QMenu* submenuFormatMathJax; + QMenu* submenuFormatToc; + QAction* actionFormatTocWithoutTags; + QAction* actionFormatTocWithTags; QMenu* submenuFormatLists; QMenu* submenuFormatBlocks; QMenu* submenuFormatDiagrams; @@ -241,7 +265,7 @@ class MainMenuView : public QObject QAction* actionFormatImage; QAction* actionFormatTable; QAction* actionFormatHr; - QAction* actionFormatToc; + QAction* actionFormatEmojis; QAction* actionFormatTimestamp; // menu: Help @@ -258,6 +282,8 @@ class MainMenuView : public QObject QAction* actionHelpAboutQt; QAction* actionHelpAbout; + void showModeAwareFacet(bool repositoryMode, bool mfMode); + public: MainMenuView(MainWindowView& mainWindow); MainMenuView(const MainMenuView&) = delete; @@ -266,11 +292,12 @@ class MainMenuView : public QObject MainMenuView &operator=(const MainMenuView&&) = delete; virtual ~MainMenuView(); - void showFacetOrganizerList(bool repositoryMode=true); - void showFacetOrganizerView(bool repositoryMode=true); - void showFacetOutlineList(bool repositoryMode=true); - void showFacetOutlineView(bool repositoryMode=true); - void showFacetNoteEdit(bool repositoryMode=true); + void showFacetOrganizerList(bool repositoryMode=true, bool mfMode=true); + void showFacetOrganizerView(bool repositoryMode=true, bool mfMode=true); + void showFacetOutlinesMap(bool repositoryMode=true, bool mfMode=true); + void showFacetOutlineList(bool repositoryMode=true, bool mfMode=true); + void showFacetOutlineView(bool repositoryMode=true, bool mfMode=true); + void showFacetNoteEdit(bool repositoryMode=true, bool mfMode=true); void showFacetMindThink(); void showFacetMindSleep(); diff --git a/app/src/qt/main_toolbar_view.cpp b/app/src/qt/main_toolbar_view.cpp index 803cbfae..efbcec92 100644 --- a/app/src/qt/main_toolbar_view.cpp +++ b/app/src/qt/main_toolbar_view.cpp @@ -1,7 +1,7 @@ /* main_toolbar_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -25,9 +25,10 @@ MainToolbarView::MainToolbarView(MainWindowView* mainWindowView) { // TOOLBAR: L&F driven toolbar icons - dark vs. light - actionFindFts = addAction( - QIcon(":/icons/find-fts.svg"), - "Full-text search"); + // REMOVED: button preceding the CLI + //actionFindFts = addAction( + // QIcon(":/icons/find-fts.svg"), + // "Full-text search"); cli = new CliAndBreadcrumbsView{this}; addWidget(cli); @@ -43,7 +44,7 @@ MainToolbarView::MainToolbarView(MainWindowView* mainWindowView) actionOpenRepository = addAction( QIcon(":/icons/open-repository.svg"), - tr("Open a directory with Markdowns or MindForger repository")); + tr("Open directory with Markdowns or Workspace")); actionOpenFile = addAction( QIcon(":/icons/open-file.svg"), tr("Open Markdown file")); @@ -56,20 +57,9 @@ MainToolbarView::MainToolbarView(MainWindowView* mainWindowView) addSeparator(); -#ifdef MF_DEPRECATED - actionViewDashboard = addAction( - QIcon(":/icons/dashboard.svg"), - tr("View Dashboard")); -#endif -#ifdef ONE_ORGANIZER - actionViewEisenhower = addAction( - QIcon(":/icons/view-eisenhower.svg"), - tr("View Eisenhower Matrix")); -#else actionViewOrganizers = addAction( QIcon(":/icons/view-eisenhower.svg"), tr("View Eisenhower Matrices")); -#endif actionViewOutlines = addAction( QIcon(":/icons/view-outlines.svg"), tr("View Notebooks")); diff --git a/app/src/qt/main_toolbar_view.h b/app/src/qt/main_toolbar_view.h index f0bccf4c..668602b1 100644 --- a/app/src/qt/main_toolbar_view.h +++ b/app/src/qt/main_toolbar_view.h @@ -1,7 +1,7 @@ /* main_toolbar_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -41,19 +41,11 @@ class MainToolbarView : public QToolBar QAction* actionNewOutlineOrNote; QAction* actionOpenRepository; QAction* actionOpenFile; -#ifdef MF_DEPRECATED - QAction* actionViewDashboard; -#endif QAction* actionViewOutlines; -#ifdef OLD_EISENHOWER - QAction* actionViewEisenhower; -#else QAction* actionViewOrganizers; -#endif QAction* actionViewNavigator; QAction* actionViewTags; QAction* actionViewRecentNotes; - QAction* actionFindFts; QAction* actionHomeOutline; QAction* actionThink; QAction* actionScope; diff --git a/app/src/qt/main_window_presenter.cpp b/app/src/qt/main_window_presenter.cpp index 58dc2cea..b0eb99b2 100644 --- a/app/src/qt/main_window_presenter.cpp +++ b/app/src/qt/main_window_presenter.cpp @@ -1,7 +1,7 @@ /* main_window_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -18,6 +18,8 @@ */ #include "main_window_presenter.h" +#include + #include "kanban_column_presenter.h" using namespace std; @@ -45,22 +47,29 @@ MainWindowPresenter::MainWindowPresenter(MainWindowView& view) // assemble presenters w/ UI statusBar = new StatusBarPresenter{view.getStatusBar(), mind}; - mainMenu = new MainMenuPresenter{this}; view.getOrloj()->setMainMenu(mainMenu->getView()); + mainMenu = new MainMenuPresenter{ + this}; view.getOrloj()->setMainMenu(mainMenu->getView()); cli = new CliAndBreadcrumbsPresenter{this, view.getCli(), mind}; orloj = new OrlojPresenter{this, view.getOrloj(), mind}; // initialize components newLibraryDialog = new AddLibraryDialog{&view}; + syncLibraryDialog = new SyncLibraryDialog{&view}; + rmLibraryDialog = new RemoveLibraryDialog(&view); + runToolDialog = new RunToolDialog{&view}; + wingmanDialog = new WingmanDialog{&view}; scopeDialog = new ScopeDialog{mind->getOntology(), &view}; newOrganizerDialog = new OrganizerNewDialog{mind->getOntology(), &view}; - newOutlineDialog = new OutlineNewDialog{QString::fromStdString(config.getMemoryPath()), mind->getOntology(), &view}; + newOutlineDialog = new OutlineNewDialog{ + QString::fromStdString(config.getMemoryPath()), mind->getOntology(), &view}; newNoteDialog = new NoteNewDialog{mind->remind().getOntology(), &view}; ftsDialog = new FtsDialog{&view}; ftsDialogPresenter = new FtsDialogPresenter(ftsDialog, mind, orloj); findOutlineByNameDialog = new FindOutlineByNameDialog{&view}; findThingByNameDialog = new FindOutlineByNameDialog{&view}; findNoteByNameDialog = new FindNoteByNameDialog{&view}; - findOutlineByTagDialog = new FindOutlineByTagDialog{mind->remind().getOntology(), &view}; + findOutlineByTagDialog = new FindOutlineByTagDialog{ + mind->remind().getOntology(), &view}; findNoteByTagDialog = new FindNoteByTagDialog{mind->remind().getOntology(), &view}; refactorNoteToOutlineDialog = new RefactorNoteToOutlineDialog{&view}; configDialog = new ConfigurationDialog{&view}; @@ -84,38 +93,78 @@ MainWindowPresenter::MainWindowPresenter(MainWindowView& view) QString::fromStdString(File::EXTENSION_CSV), &view ); -#ifdef MF_NER - nerChooseTagsDialog = new NerChooseTagTypesDialog(&view); - nerResultDialog = new NerResultDialog(&view); -#endif + // show/hide widgets based on configuration handleMindPreferences(); // wire signals - QObject::connect(newLibraryDialog->getCreateButton(), SIGNAL(clicked()), this, SLOT(handleNewLibrary())); - QObject::connect(scopeDialog->getSetButton(), SIGNAL(clicked()), this, SLOT(handleMindScope())); - QObject::connect(newOutlineDialog, SIGNAL(accepted()), this, SLOT(handleOutlineNew())); - QObject::connect(newNoteDialog, SIGNAL(accepted()), this, SLOT(handleNoteNew())); - QObject::connect(findOutlineByNameDialog, SIGNAL(searchFinished()), this, SLOT(handleFindOutlineByName())); - QObject::connect(findThingByNameDialog, SIGNAL(searchFinished()), this, SLOT(handleFindThingByName())); - QObject::connect(findNoteByNameDialog, SIGNAL(searchFinished()), this, SLOT(handleFindNoteByName())); - QObject::connect(findOutlineByTagDialog, SIGNAL(searchFinished()), this, SLOT(handleFindOutlineByTag())); - QObject::connect(findOutlineByTagDialog, SIGNAL(switchDialogs(bool)), this, SLOT(doSwitchFindByTagDialog(bool))); - QObject::connect(findNoteByTagDialog, SIGNAL(searchFinished()), this, SLOT(handleFindNoteByTag())); - QObject::connect(findNoteByTagDialog, SIGNAL(switchDialogs(bool)), this, SLOT(doSwitchFindByTagDialog(bool))); - QObject::connect(newOrganizerDialog, SIGNAL(createFinished()), this, SLOT(handleCreateOrganizer())); - QObject::connect(refactorNoteToOutlineDialog, SIGNAL(searchFinished()), this, SLOT(handleRefactorNoteToOutline())); - QObject::connect(insertImageDialog->getInsertButton(), SIGNAL(clicked()), this, SLOT(handleFormatImage())); - QObject::connect(insertLinkDialog->getInsertButton(), SIGNAL(clicked()), this, SLOT(handleFormatLink())); - QObject::connect(rowsAndDepthDialog->getGenerateButton(), SIGNAL(clicked()), this, SLOT(handleRowsAndDepth())); - QObject::connect(newRepositoryDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleMindNewRepository())); - QObject::connect(newFileDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleMindNewFile())); - QObject::connect(exportOutlineToHtmlDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleOutlineHtmlExport())); - QObject::connect(exportMemoryToCsvDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleMindCsvExport())); QObject::connect( - orloj->getDashboard()->getView()->getNavigatorDashboardlet(), SIGNAL(clickToSwitchFacet()), - this, SLOT(doActionViewKnowledgeGraphNavigator()) - ); + wingmanDialog, SIGNAL(signalRunWingman()), + this, SLOT(slotRunWingmanFromDialog())); + QObject::connect( + wingmanDialog->getAppendButton(), SIGNAL(clicked()), + this, SLOT(slotWingmanAppendFromDialog())); + QObject::connect( + wingmanDialog->getReplaceButton(), SIGNAL(clicked()), + this, SLOT(slotWingmanReplaceFromDialog())); + QObject::connect( + // TODO remove / comment + runToolDialog->getRunButton(), SIGNAL(clicked()), + this, SLOT(handleRunTool())); + QObject::connect( + newLibraryDialog->getCreateButton(), SIGNAL(clicked()), + this, SLOT(handleNewLibrary())); + QObject::connect( + syncLibraryDialog->getSyncButton(), SIGNAL(clicked()), + this, SLOT(handleSyncLibrary())); + QObject::connect( + rmLibraryDialog->getRemoveButton(), SIGNAL(clicked()), + this, SLOT(handleRmLibrary())); + QObject::connect( + scopeDialog->getSetButton(), SIGNAL(clicked()), this, SLOT(handleMindScope())); + QObject::connect( + newOutlineDialog, SIGNAL(accepted()), this, SLOT(handleOutlineNew())); + QObject::connect( + newNoteDialog, SIGNAL(accepted()), + this, SLOT(handleNoteNew())); + QObject::connect( + newNoteDialog->getEmojisButton(), SIGNAL(clicked()), + this, SLOT(doActionEmojisDialog())); + QObject::connect( + newOutlineDialog->getEmojisButton(), SIGNAL(clicked()), + this, SLOT(doActionEmojisDialog())); + QObject::connect( + findOutlineByNameDialog, SIGNAL(searchFinished()), this, SLOT(handleFindOutlineByName())); + QObject::connect( + findThingByNameDialog, SIGNAL(searchFinished()), this, SLOT(handleFindThingByName())); + QObject::connect( + findNoteByNameDialog, SIGNAL(searchFinished()), this, SLOT(handleFindNoteByName())); + QObject::connect( + findOutlineByTagDialog, SIGNAL(searchFinished()), this, SLOT(handleFindOutlineByTag())); + QObject::connect( + findOutlineByTagDialog, SIGNAL(switchDialogs(bool)), this, SLOT(doSwitchFindByTagDialog(bool))); + QObject::connect( + findNoteByTagDialog, SIGNAL(searchFinished()), this, SLOT(handleFindNoteByTag())); + QObject::connect( + findNoteByTagDialog, SIGNAL(switchDialogs(bool)), this, SLOT(doSwitchFindByTagDialog(bool))); + QObject::connect( + newOrganizerDialog, SIGNAL(createFinished()), this, SLOT(handleCreateOrganizer())); + QObject::connect( + refactorNoteToOutlineDialog, SIGNAL(searchFinished()), this, SLOT(handleRefactorNoteToOutline())); + QObject::connect( + insertImageDialog->getInsertButton(), SIGNAL(clicked()), this, SLOT(handleFormatImage())); + QObject::connect( + insertLinkDialog->getInsertButton(), SIGNAL(clicked()), this, SLOT(handleFormatLink())); + QObject::connect( + rowsAndDepthDialog->getGenerateButton(), SIGNAL(clicked()), this, SLOT(handleRowsAndDepth())); + QObject::connect( + newRepositoryDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleMindNewRepository())); + QObject::connect( + newFileDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleMindNewFile())); + QObject::connect( + exportOutlineToHtmlDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleOutlineHtmlExport())); + QObject::connect( + exportMemoryToCsvDialog->getNewButton(), SIGNAL(clicked()), this, SLOT(handleMindCsvExport())); QObject::connect( orloj->getNoteEdit()->getView()->getNoteEditor(), SIGNAL(signalDnDropUrl(QString)), this, SLOT(doActionFormatLinkOrImage(QString)) @@ -132,23 +181,20 @@ MainWindowPresenter::MainWindowPresenter(MainWindowView& view) orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor(), SIGNAL(signalPasteImageData(QImage)), this, SLOT(doActionEditPasteImageData(QImage)) ); - // wire toolbar signals - QObject::connect(view.getToolBar()->actionNewOutlineOrNote, SIGNAL(triggered()), this, SLOT(doActionOutlineOrNoteNew())); - QObject::connect(view.getToolBar()->actionOpenRepository, SIGNAL(triggered()), this, SLOT(doActionMindLearnRepository())); + QObject::connect( + view.getToolBar()->actionNewOutlineOrNote, SIGNAL(triggered()), + this, SLOT(doActionOutlineOrNoteNew()) + ); + QObject::connect( + view.getToolBar()->actionOpenRepository, SIGNAL(triggered()), + this, SLOT(doActionMindLearnRepository()) + ); QObject::connect(view.getToolBar()->actionOpenFile, SIGNAL(triggered()), this, SLOT(doActionMindLearnFile())); -#ifdef MF_DEPRECATED - QObject::connect(view.getToolBar()->actionViewDashboard, SIGNAL(triggered()), this, SLOT(doActionViewDashboard())); -#endif -#ifdef ONE_ORGANIZER - QObject::connect(view.getToolBar()->actionViewEisenhower, SIGNAL(triggered()), this, SLOT(doActionViewOrganizer())); -#else QObject::connect(view.getToolBar()->actionViewOrganizers, SIGNAL(triggered()), this, SLOT(doActionViewOrganizers())); -#endif QObject::connect(view.getToolBar()->actionViewOutlines, SIGNAL(triggered()), this, SLOT(doActionViewOutlines())); QObject::connect(view.getToolBar()->actionViewNavigator, SIGNAL(triggered()), this, SLOT(doActionViewKnowledgeGraphNavigator())); QObject::connect(view.getToolBar()->actionViewTags, SIGNAL(triggered()), this, SLOT(doActionViewTagCloud())); QObject::connect(view.getToolBar()->actionViewRecentNotes, SIGNAL(triggered()), this, SLOT(doActionViewRecentNotes())); - QObject::connect(view.getToolBar()->actionFindFts, SIGNAL(triggered()), this, SLOT(doActionFts())); QObject::connect(view.getToolBar()->actionHomeOutline, SIGNAL(triggered()), this, SLOT(doActionViewHome())); QObject::connect(view.getToolBar()->actionThink, SIGNAL(triggered()), this, SLOT(doActionMindToggleThink())); QObject::connect(view.getToolBar()->actionScope, SIGNAL(triggered()), this, SLOT(doActionMindTimeTagScope())); @@ -162,21 +208,11 @@ MainWindowPresenter::MainWindowPresenter(MainWindowView& view) this, SLOT(slotMainToolbarVisibilityChanged(bool)) ); - -#ifdef MF_NER - QObject::connect(nerChooseTagsDialog->getChooseButton(), SIGNAL(clicked()), this, SLOT(handleFindNerEntities())); - QObject::connect(nerResultDialog, SIGNAL(choiceFinished()), this, SLOT(handleFtsNerEntity())); -#endif - // async task 2 GUI events distributor distributor = new AsyncTaskNotificationsDistributor(this); // setup callback for cleanup when it finishes QObject::connect(distributor, SIGNAL(finished()), distributor, SLOT(deleteLater())); distributor->start(); -#ifdef MF_NER - // NER worker - nerWorker = nullptr; -#endif // send signal to components to be updated on a configuration change QObject::connect(configDialog, SIGNAL(saveConfigSignal()), this, SLOT(handleMindPreferences())); @@ -204,8 +240,8 @@ MainWindowPresenter::~MainWindowPresenter() //if(findNoteByNameDialog) delete findNoteByNameDialog; if(insertImageDialog) delete insertImageDialog; if(newLibraryDialog) delete newLibraryDialog; + if(wingmanDialog) delete wingmanDialog; - // TODO deletes delete this->mdConfigRepresentation; delete this->mdRepositoryConfigRepresentation; delete this->mdDocumentRepresentation; @@ -236,10 +272,10 @@ void MainWindowPresenter::showInitialView() orloj->showFacetOutlineList(mind->getOutlines()); } } else if(config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER) { - if(!string{START_TO_DASHBOARD}.compare(config.getStartupView())) { - orloj->showFacetDashboard(); - } else if(!string{START_TO_OUTLINES}.compare(config.getStartupView())) { + if(!string{START_TO_OUTLINES}.compare(config.getStartupView())) { orloj->showFacetOutlineList(mind->getOutlines()); + } else if(!string{START_TO_OUTLINES_TREE}.compare(config.getStartupView())) { + orloj->showFacetOutlinesMap(mind->outlinesMapGet()); } else if(!string{START_TO_TAGS}.compare(config.getStartupView())) { orloj->showFacetTagCloud(); } else if(!string{START_TO_RECENT}.compare(config.getStartupView())) { @@ -279,12 +315,18 @@ void MainWindowPresenter::showInitialView() orloj->showFacetOutlineList(mind->getOutlines()); } - view.setFileOrDirectory(QString::fromStdString(config.getActiveRepository()->getPath())); + view.setFileOrDirectory( + QString::fromStdString(config.getActiveRepository()->getPath()) + ); // config > menu mainMenu->showFacetMindAutolink(config.isAutolinking()); mainMenu->showFacetLiveNotePreview(config.isUiLiveNotePreview()); - orloj->setAspect(config.isUiLiveNotePreview()?OrlojPresenterFacetAspect::ASPECT_LIVE_PREVIEW:OrlojPresenterFacetAspect::ASPECT_NONE); + orloj->setAspect( + config.isUiLiveNotePreview() + ?OrlojPresenterFacetAspect::ASPECT_LIVE_PREVIEW + :OrlojPresenterFacetAspect::ASPECT_NONE + ); // move Mind to configured state if(config.getDesiredMindState()==Configuration::MindState::THINKING) { @@ -293,14 +335,21 @@ void MainWindowPresenter::showInitialView() if(f.wait_for(chrono::microseconds(0)) == future_status::ready) { if(!f.get()) { mainMenu->showFacetMindSleep(); - statusBar->showError(tr("Cannot think - either Mind already dreaming or repository too big")); + statusBar->showError( + tr( + "Cannot think - either Mind already dreaming or " + "workspace too big" + ) + ); } statusBar->showMindStatistics(); } else { statusBar->showMindStatistics(); // ask notifications distributor to repaint status bar later AsyncTaskNotificationsDistributor::Task* task - = new AsyncTaskNotificationsDistributor::Task{f,AsyncTaskNotificationsDistributor::TaskType::DREAM_TO_THINK}; + = new AsyncTaskNotificationsDistributor::Task{ + f, + AsyncTaskNotificationsDistributor::TaskType::DREAM_TO_THINK}; distributor->add(task); } } @@ -467,7 +516,7 @@ void MainWindowPresenter::handleNoteViewLinkClicked(const QUrl& url) #ifdef DO_MF_DEBUG void MainWindowPresenter::doActionMindHack() { - MF_DEBUG("[MindHack] Current facet: " << orloj->getFacet() << endl); + MF_DEBUG("MindHack" << endl); } #endif @@ -479,14 +528,26 @@ void MainWindowPresenter::doActionMindNewRepository() void MainWindowPresenter::handleMindNewRepository() { // if directory exists, then fail - if(isDirectoryOrFileExists(newRepositoryDialog->getRepositoryPath().toStdString().c_str())) { - QMessageBox::critical(&view, tr("New Repository Error"), tr("Specified repository path already exists!")); + if(isDirectoryOrFileExists( + newRepositoryDialog->getRepositoryPath().toStdString().c_str()) + ) { + QMessageBox::critical( + &view, + tr("New Workspace Error"), + tr("Specified workspace path already exists!") + ); return; } // create repository - if(!config.getInstaller()->createEmptyMindForgerRepository(newRepositoryDialog->getRepositoryPath().toStdString())) { - QMessageBox::critical(&view, tr("New Repository Error"), tr("Failed to create empty repository!")); + if(!config.getInstaller()->createEmptyMindForgerRepository( + newRepositoryDialog->getRepositoryPath().toStdString()) + ) { + QMessageBox::critical( + &view, + tr("New Workspace Error"), + tr("Failed to create empty workspace!") + ); return; } @@ -496,7 +557,12 @@ void MainWindowPresenter::handleMindNewRepository() newRepositoryDialog->isCopyStencils(), newRepositoryDialog->getRepositoryPath().toStdString().c_str() )) { - statusBar->showError(tr("ERROR: repository created, but attempt to copy documentation and/or stencils failed")); + statusBar->showError( + tr( + "ERROR: workspace created, but attempt to copy documentation " + "and/or stencils failed" + ) + ); } // open new repository @@ -549,7 +615,9 @@ void MainWindowPresenter::doActionMindThink() statusBar->showMindStatistics(); // ask notifications distributor to repaint status bar later AsyncTaskNotificationsDistributor::Task* task - = new AsyncTaskNotificationsDistributor::Task{f,AsyncTaskNotificationsDistributor::TaskType::DREAM_TO_THINK}; + = new AsyncTaskNotificationsDistributor::Task{ + f, + AsyncTaskNotificationsDistributor::TaskType::DREAM_TO_THINK}; distributor->add(task); } } @@ -648,13 +716,18 @@ void MainWindowPresenter::doActionToggleLiveNotePreview() void MainWindowPresenter::doActionMindLearnRepository() { QString homeDirectory - = QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory); + = QStandardPaths::locate( + QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory + ); QFileDialog learnDialog{&view}; - learnDialog.setWindowTitle(tr("Learn Directory or MindForger Repository")); - // learnDialog.setFileMode(QFileDialog::Directory|QFileDialog::ExistingFiles); not supported, therefore + learnDialog.setWindowTitle(tr("Learn Directory or MindForger Workspace")); + // learnDialog.setFileMode(QFileDialog::Directory|QFileDialog::ExistingFiles); + // not supported, therefore + // > + // ASK user: directory/repository or file (choice) // > - // ASK user: directory/repository or file (choice) > open dialog configured as required + // open dialog configured as required learnDialog.setFileMode(QFileDialog::Directory); learnDialog.setDirectory(homeDirectory); learnDialog.setViewMode(QFileDialog::Detail); @@ -706,7 +779,7 @@ void MainWindowPresenter::doActionMindRelearn(QString path) QMessageBox::critical( &view, tr("Learn"), - tr("This is neither valid MindForger/Markdown repository nor file.")); + tr("This is neither valid MindForger/Markdown workspace nor file.")); } } @@ -785,7 +858,7 @@ void MainWindowPresenter::slotMainToolbarVisibilityChanged(bool visibility) mdConfigRepresentation->save(config); } -void MainWindowPresenter::doActionFindOutlineByName() +void MainWindowPresenter::doActionFindOutlineByName(const std::string& phrase) { // IMPROVE rebuild model ONLY if dirty i.e. an outline name was changed on save vector os{mind->getOutlines()}; @@ -793,12 +866,22 @@ void MainWindowPresenter::doActionFindOutlineByName() vector es{os.begin(),os.end()}; findOutlineByNameDialog->show(es); + if(phrase.size()) { + findOutlineByNameDialog->setSearchedString(QString::fromStdString(phrase)); + } } void MainWindowPresenter::handleFindOutlineByName() { if(findOutlineByNameDialog->getChoice()) { - orloj->showFacetOutline((Outline*)findOutlineByNameDialog->getChoice()); + Outline* o = (Outline*)findOutlineByNameDialog->getChoice(); + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + orloj->getOutlinesMap()->selectRowByOutlineKey(o->getKey()); + return; + } else { + orloj->showFacetOutline(o); + } + // IMPROVE make this more efficient statusBar->showInfo(QString(tr("Notebook "))+QString::fromStdString(findOutlineByNameDialog->getChoice()->getName())); } else { @@ -821,14 +904,14 @@ void MainWindowPresenter::handleFindThingByName() } } -void MainWindowPresenter::doActionFindOutlineByTag() +void MainWindowPresenter::doActionFindOutlineByTag(const string& tag) { // IMPROVE rebuild model ONLY if dirty i.e. an outline name was changed on save vector os{mind->getOutlines()}; Outline::sortByName(os); vector outlines{os.begin(),os.end()}; - findOutlineByTagDialog->show(outlines); + findOutlineByTagDialog->show(outlines, nullptr, nullptr, tag); } void MainWindowPresenter::handleFindOutlineByTag() @@ -862,7 +945,7 @@ void MainWindowPresenter::doActionFindNoteByTag() void MainWindowPresenter::doTriggerFindNoteByTag(const Tag* tag) { findNoteByTagDialog->setWindowTitle(tr("Find Note by Tags")); - findNoteByTagDialog->clearScope(); + findNoteByTagDialog->clearScope(); vector allNotes{}; mind->getAllNotes(allNotes); vector tags{}; @@ -982,175 +1065,13 @@ void MainWindowPresenter::handleFindNoteByName() } } -#ifdef MF_NER - -void MainWindowPresenter::doActionFindNerPersons() -{ - if(orloj->isFacetActiveOutlineManagement()) { - nerChooseTagsDialog->clearCheckboxes(); - nerChooseTagsDialog->getPersonsCheckbox()->setChecked(true); - nerChooseTagsDialog->show(); - } else { - statusBar->showInfo(tr("Initializing NER and predicting...")); - QMessageBox::critical(&view, tr("NER"), tr("Memory NER not implemented yet.")); - } -} -void MainWindowPresenter::doActionFindNerLocations() -{ - if(orloj->isFacetActiveOutlineManagement()) { - nerChooseTagsDialog->clearCheckboxes(); - nerChooseTagsDialog->getLocationsCheckbox()->setChecked(true); - nerChooseTagsDialog->show(); - } else { - statusBar->showInfo(tr("Initializing NER and predicting...")); - QMessageBox::critical(&view, tr("NER"), tr("Memory NER not implemented yet.")); - } -} -void MainWindowPresenter::doActionFindNerOrganizations() -{ - if(orloj->isFacetActiveOutlineManagement()) { - nerChooseTagsDialog->clearCheckboxes(); - nerChooseTagsDialog->getOrganizationsCheckbox()->setChecked(true); - nerChooseTagsDialog->show(); - } else { - statusBar->showInfo(tr("Initializing NER and predicting...")); - QMessageBox::critical(&view, tr("NER"), tr("Memory NER not implemented yet.")); - } -} -void MainWindowPresenter::doActionFindNerMisc() -{ - if(orloj->isFacetActiveOutlineManagement()) { - nerChooseTagsDialog->clearCheckboxes(); - nerChooseTagsDialog->getMiscCheckbox()->setChecked(true); - nerChooseTagsDialog->show(); - } else { - statusBar->showInfo(tr("Initializing NER and predicting...")); - QMessageBox::critical(&view, tr("NER"), tr("Memory NER not implemented yet.")); - } -} - -NerMainWindowWorkerThread* MainWindowPresenter::startNerWorkerThread( - Mind* m, - OrlojPresenter* o, - int f, - std::vector* r, - QDialog* d) -{ - QThread* thread = new QThread; - NerMainWindowWorkerThread* worker - = new NerMainWindowWorkerThread(thread, m, o, f, r, d); - - // signals - worker->moveToThread(thread); - // TODO implement dialog w/ error handling - QObject::connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); - QObject::connect(thread, SIGNAL(started()), worker, SLOT(process())); - // open dialog to choose from result(s) - QObject::connect(worker, SIGNAL(finished()), this, SLOT(handleChooseNerEntityResult())); - // worker's finished signal quits thread ~ thread CANNOT be reused - QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit())); - // schedule thread for automatic deletion by Qt - I delete worker myself - //QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); - QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - thread->start(); - - return worker; -} - -// handleFindNerPerson() -> handleChooseNerEntityResult() -> handleFtsNerEntity() -void MainWindowPresenter::handleFindNerEntities() -{ - nerChooseTagsDialog->hide(); - - int entityFilter{}; - entityFilter = - (nerChooseTagsDialog->getPersonsCheckbox()->isChecked()?NerNamedEntityType::PERSON:0) | - (nerChooseTagsDialog->getLocationsCheckbox()->isChecked()?NerNamedEntityType::LOCATION:0) | - (nerChooseTagsDialog->getOrganizationsCheckbox()->isChecked()?NerNamedEntityType::ORGANIZATION:0) | - (nerChooseTagsDialog->getMiscCheckbox()->isChecked()?NerNamedEntityType::MISC:0); - - MF_DEBUG("Named-entity type filter: " << entityFilter << endl); - - vector* result - = new vector{}; - if(mind->isNerInitilized()) { - statusBar->showInfo(tr("Recognizing named entities...")); - - mind->recognizePersons(orloj->getOutlineView()->getCurrentOutline(), entityFilter, *result); - - chooseNerEntityResult(result); - } else { - statusBar->showInfo(tr("Initializing NER and recognizing named entities...")); - - // launch async worker - QDialog* progressDialog - = new QDialog{&view}; - nerWorker - = startNerWorkerThread(mind, orloj, entityFilter, result, progressDialog); - - // show PROGRESS dialog - will be closed by worker - QVBoxLayout* mainLayout = new QVBoxLayout{}; - QLabel* l = new QLabel{tr(" Initializing (the first run only) NER and predicting... ")}; - mainLayout->addWidget(l); - progressDialog->setLayout(mainLayout); - progressDialog->setWindowTitle(tr("Named-entity Recognition")); - //progressDialog->resize(fontMetrics().averageCharWidth()*35, height()); - //progressDialog->setModal(true); - progressDialog->update(); - progressDialog->activateWindow(); - progressDialog->show(); - // dialog is deleted by worker thread - } -} - -void MainWindowPresenter::chooseNerEntityResult(vector* nerEntities) -{ - MF_DEBUG("Showing NER results to choose one entity for FTS..." << endl); - statusBar->showInfo(tr("NER predicition finished")); - - if(nerEntities && nerEntities->size()) { - nerResultDialog->show(*nerEntities); - } else { - QMessageBox::information(&view, tr("Named-entity Recognition"), tr("No named entities recognized.")); - } -} - -void MainWindowPresenter::handleChooseNerEntityResult() -{ - vector* nerEntities = nerWorker->getResult(); - chooseNerEntityResult(nerEntities); - - // cleanup: thread is deleted by Qt (deleteLater() signal) - delete nerEntities; - delete nerWorker; -} - -void MainWindowPresenter::handleFtsNerEntity() -{ - if(nerResultDialog->getChoice().size()) { - executeFts( - nerResultDialog->getChoice(), - false, - orloj->getOutlineView()->getCurrentOutline()); - } -} - -#endif - void MainWindowPresenter::doActionViewRecentNotes() { vector notes{}; - mind->getAllNotes(notes, true, true); + mind->getAllNotes(notes, true, config.isRecentIncludeOs()); orloj->showFacetRecentNotes(notes); } -void MainWindowPresenter::doActionViewDashboard() -{ - if(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY) { - orloj->showFacetDashboard(); - } -} - void MainWindowPresenter::sortAndSaveOrganizersConfig() { if(config.hasRepositoryConfiguration()) { @@ -1161,8 +1082,12 @@ void MainWindowPresenter::sortAndSaveOrganizersConfig() void MainWindowPresenter::doActionViewOrganizers() { - if(config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY) { - orloj->showFacetOrganizerList(config.getRepositoryConfiguration().getOrganizers()); + if(config.getActiveRepository()->getMode() + == Repository::RepositoryMode::REPOSITORY + ) { + orloj->showFacetOrganizerList( + config.getRepositoryConfiguration().getOrganizers() + ); } } @@ -1188,7 +1113,9 @@ bool MainWindowPresenter::doActionViewHome() orloj->showFacetOutline(homeOutline.at(0)); return true; } else { - statusBar->showInfo(tr("Home Notebook is not defined!")); + statusBar->showInfo( + tr("Home Notebook not set - use menu 'Notebooks/Make Home'") + ); return false; } } @@ -1202,6 +1129,16 @@ void MainWindowPresenter::doActionViewOutlines() } } +void MainWindowPresenter::doActionViewOutlinesMap() +{ + if(config.getActiveRepository()->getType()==Repository::RepositoryType::MINDFORGER + && + config.getActiveRepository()->getMode()==Repository::RepositoryMode::REPOSITORY) + { + orloj->showFacetOutlinesMap(mind->outlinesMapGet()); + } +} + void MainWindowPresenter::doActionViewTagCloud() { orloj->showFacetTagCloud(); @@ -1470,12 +1407,12 @@ void MainWindowPresenter::doActionFormatListTaskItem() } } -void MainWindowPresenter::doActionFormatToc() +void MainWindowPresenter::doActionFormatToc(bool withTags) { if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE) || orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) { - string* text = mdRepresentation->toc(orloj->getOutlineView()->getCurrentOutline()); + string* text = mdRepresentation->toc(orloj->getOutlineView()->getCurrentOutline(), withTags); if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) { orloj->getNoteEdit()->getView()->getNoteEditor()->insertMarkdownText(QString::fromStdString(*text)); @@ -1487,6 +1424,16 @@ void MainWindowPresenter::doActionFormatToc() } } +void MainWindowPresenter::doActionFormatTocWithTags() +{ + this->doActionFormatToc(true); +} + +void MainWindowPresenter::doActionFormatTocWithoutTags() +{ + this->doActionFormatToc(false); +} + // IMPROVE: consolidate methods which just insert a (semi)static string void MainWindowPresenter::doActionFormatTimestamp() { @@ -1755,7 +1702,9 @@ void MainWindowPresenter::copyLinkOrImageToRepository(const string& srcPath, QSt pathToDirectoryAndFile(path.toStdString(), d, f); path = QString::fromStdString(f); - statusBar->showInfo(tr("File copied to repository path '%1'").arg(path.toStdString().c_str())); + statusBar->showInfo( + tr("File copied to workspace path '%1'").arg(path.toStdString().c_str()) + ); } else { // fallback: create link, but don't copy path = insertLinkDialog->getPathText(); @@ -1795,9 +1744,118 @@ void MainWindowPresenter::doActionEditPasteImageData(QImage image) injectImageLinkToEditor(path, QString{"image"}); } +void MainWindowPresenter::doActionRunToolDialogAnywhere() +{ + QString phrase{}; + QString toolId{KnowledgeTool::WIKIPEDIA}; + + doActionOpenRunToolDialog(phrase, toolId, true); +} + +void MainWindowPresenter::doActionOpenRunToolDialog( + QString& phrase, + QString& toolId, + bool openDialog +) { + MF_DEBUG("SIGNAL handled: open run tool dialog..." << endl); + + // if phrase is empty, then use active context + if(phrase.isEmpty()) { + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) { + phrase = orloj->getNoteEdit()->getView()->getNoteEditor()->getToolPhrase(); + } else if( + orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE) + || orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER) + ) { + Outline* o = orloj->getOutlineView()->getCurrentOutline(); + if(o) { + phrase = QString::fromStdString(o->getName()); + } + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_NOTE)) { + Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + if(note) { + phrase = QString::fromStdString(note->getName()); + } + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) { + phrase = orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor()->getToolPhrase(); + } + else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_LIST_OUTLINES)) { + int row = orloj->getOutlinesTable()->getCurrentRow(); + if(row != OutlinesTablePresenter::NO_ROW) { + QStandardItem* item + = orloj->getOutlinesTable()->getModel()->item(row); + if(item) { + Outline* outline = item->data(Qt::UserRole + 1).value(); + phrase = QString::fromStdString(outline->getName()); + } + } + } + } + this->runToolDialog->setPhraseText(phrase); + + if(!this->runToolDialog->selectToolById(toolId.toStdString())) { + QMessageBox::critical( + &view, + tr("Run Knowledge Tool Error"), + tr("Unknown tool to run '%1'.").arg(toolId)); + return; + } + QString templateText = + QString::fromStdString( + KnowledgeTool::getUrlTemplateForToolId( + this->runToolDialog->getSelectedToolId())); + if(templateText.length() == 0) { + QMessageBox::critical( + &view, + tr("Open Knowledge Tool Dialog Error"), + tr("Unable to construct URL to open for unknown tool '%1'.").arg(toolId)); + return; + } + this->runToolDialog->setTemplateText(templateText); + + if(openDialog) { + this->runToolDialog->show(); + } +} + +void MainWindowPresenter::handleRunTool() +{ + this->runToolDialog->hide(); + + string selectedTool{ + this->runToolDialog->getSelectedTool().toStdString() + }; + + QString phrase=this->runToolDialog->getPhraseText(); + if(phrase.length() == 0) { + QMessageBox msgBox{ + QMessageBox::Critical, + QObject::tr("Empty Phrase"), + QObject::tr("Phrase to search/explain/process is empty.") + }; + msgBox.exec(); + return; + } + + // get & check template text validity + QString templateText = this->runToolDialog->getTemplateText(); + + // phrase replace @ template > get command, if invalid, then fallback + QString command = templateText.replace( + QString::fromStdString(KnowledgeTool::TOOL_PHRASE), phrase + ); + + // RUN tool + QDesktopServices::openUrl(QUrl{command}); +} + void MainWindowPresenter::statusInfoPreviewFlickering() { - statusBar->showInfo(QString(tr("HTML Note preview flickering can be eliminated by disabling math and diagrams in Preferences menu"))); + statusBar->showInfo( + QString( + tr( + "HTML Note preview flickering can be eliminated by disabling math " + "and diagrams in Preferences menu"))); } /* @@ -1906,6 +1964,347 @@ void MainWindowPresenter::doActionOutlineNew() ); } +bool MainWindowPresenter::checkWingmanAvailability() +{ + if(!config.isWingman()) { + QMessageBox msgBox{ + QMessageBox::Critical, + QObject::tr("Wingman Not Available"), + QObject::tr( + "Wingman provider is either not configured or " + "initialized - see MindForger Preferences (Wingman tab).") + }; + msgBox.exec(); + return false; + } + + return true; +} + +void MainWindowPresenter::handleWingmanMenuAction(const std::string& prompt) +{ + if(!checkWingmanAvailability()) { + return; + } + + handleActionWingman(false); + this->wingmanDialog->setPrompt(prompt); + this->wingmanDialog->appendPromptToChat(prompt); + slotRunWingmanFromDialog(true); +} + +void MainWindowPresenter::handleActionWingman(bool showDialog) +{ + MF_DEBUG("SIGNAL handled: WINGMAN CHAT dialog requests PROMPT run..." << endl); + + if(!checkWingmanAvailability()) { + return; + } + + // get PHRASE from the active context: + // - N editor: get word under cursor OR selected text + // - N tree: get N name + // - O tree: get O name + // - ... + QString contextTextName{}; + QString contextText{}; + WingmanDialogModes contextType{WingmanDialogModes::WINGMAN_DIALOG_MODE_TEXT}; + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) { + contextText = orloj->getNoteEdit()->getView()->getNoteEditor()->getToolPhrase(); + contextType = WingmanDialogModes::WINGMAN_DIALOG_MODE_TEXT; + } else if( + orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE) + || orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER) + ) { + Outline* o = orloj->getOutlineView()->getCurrentOutline(); + if(o) { + contextTextName = QString::fromStdString(o->getName()); + string contextTextStr{}; + auto oFormat = o->getFormat(); + o->setFormat(MarkdownDocument::Format::MARKDOWN); + mdRepresentation->to(o, &contextTextStr); + o->setFormat(oFormat); + contextText = QString::fromStdString(contextTextStr); + contextType = WingmanDialogModes::WINGMAN_DIALOG_MODE_OUTLINE; + } + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_NOTE)) { + Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + if(note) { + contextTextName = QString::fromStdString(note->getName()); + string contextTextStr{}; + mdRepresentation->to(note, &contextTextStr); + contextText = QString::fromStdString(contextTextStr); + contextType = WingmanDialogModes::WINGMAN_DIALOG_MODE_NOTE; + } + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) { + contextText = orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor()->getToolPhrase(); + contextType = WingmanDialogModes::WINGMAN_DIALOG_MODE_TEXT; + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_LIST_OUTLINES)) { + int row = orloj->getOutlinesTable()->getCurrentRow(); + if(row != OutlinesTablePresenter::NO_ROW) { + QStandardItem* item + = orloj->getOutlinesTable()->getModel()->item(row); + if(item) { + Outline* o = item->data(Qt::UserRole + 1).value(); + if(o) { + contextTextName = QString::fromStdString(o->getName()); + string contextTextStr{}; + auto oFormat = o->getFormat(); + o->setFormat(MarkdownDocument::Format::MARKDOWN); + mdRepresentation->to(o, &contextTextStr); + o->setFormat(oFormat); + contextText = QString::fromStdString(contextTextStr); + contextType = WingmanDialogModes::WINGMAN_DIALOG_MODE_OUTLINE; + } + } + } + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + int row = orloj->getOutlinesMap()->getCurrentRow(); + if(row != OutlinesTablePresenter::NO_ROW) { + QStandardItem* item + = orloj->getOutlinesMap()->getModel()->item(row); + if(item) { + Note* note = item->data(Qt::UserRole + 1).value(); + if(note) { + contextTextName = QString::fromStdString(note->getName()); + string contextTextStr{}; + mdRepresentation->to(note, &contextTextStr); + contextText = QString::fromStdString(contextTextStr); + contextType = WingmanDialogModes::WINGMAN_DIALOG_MODE_OUTLINE; + } + } + } + } + + if(showDialog) { + this->wingmanDialog->show( + contextType, + contextTextName, + contextText, + mind->getWingman()->getPredefinedOPrompts(), + mind->getWingman()->getPredefinedNPrompts(), + mind->getWingman()->getPredefinedTPrompts() + ); + } else { + this->wingmanDialog->setup( + contextType, + contextTextName, + contextText, + mind->getWingman()->getPredefinedOPrompts(), + mind->getWingman()->getPredefinedNPrompts(), + mind->getWingman()->getPredefinedTPrompts() + ); + } +} + +void MainWindowPresenter::slotRunWingmanFromDialog(bool showDialog) +{ + bool runAsynchronously = true; + + // pull prompt from the dialog & prepare prompt from the dialog + string prompt = this->wingmanDialog->getPrompt(); + + replaceAll( + CTX_INCLUDE_NAME, + this->wingmanDialog->getContextNameText().toStdString(), + prompt); + replaceAll( + CTX_INCLUDE_TEXT, + this->wingmanDialog->getContextText().toStdString(), + prompt); + + if(showDialog) { + this->wingmanDialog->show(); + } + + // RUN Wingman + QString promptLabel{QString(tr("Wingman is talking to the GPT provider..."))}; + this->wingmanDialog->setPromptsLabel(promptLabel); + statusBar->showInfo(promptLabel); + + // run + CommandWingmanChat commandWingmanChat{ + prompt, + "", + WingmanStatusCode::WINGMAN_STATUS_CODE_OK, + "", + "", + 0, + 0, + "" + }; + // measure time + auto start = std::chrono::high_resolution_clock::now(); + if(runAsynchronously) { + const int progressStep = 100; // 100ms + const int progressLimit = progressStep*10*30; // 30s + int progress = 0; + + // hint maximum: progressLimit to show progress steps, 0 to show animated + this->wingmanDialog->resetProgress(0); + this->wingmanDialog->setProgressVisible(true); + + QFuture future = QtConcurrent::run( + this->mind, + &Mind::wingmanChat, + commandWingmanChat); + + // wait for the future to finish + QFutureWatcher futureWatcher{}; + futureWatcher.setFuture(future); + // blocking wait: futureWatcher.waitForFinished(); + + // hint: the purpose of progress is not to cancel the run in case of time out, + // but just to visualize a progress... + while(!futureWatcher.isFinished() && progress < progressLimit) { + MF_DEBUG( + progress << "/" << progressLimit << + " Wingman is talking to the GPT provider..." << endl + ); + QApplication::processEvents(); + QThread::msleep(progressStep); // portable sleep + progress += progressStep; + this->wingmanDialog->setProgressValue(progress); + } + this->wingmanDialog->setProgressValue(progressLimit); + + commandWingmanChat = future.result(); + + // HIDE progress dialog + this->wingmanDialog->setProgressVisible(false); + + // check the result + if (future.isFinished()) { + statusBar->showInfo(QString(tr("Wingman received an answer from the GPT provider"))); + } else { + statusBar->showError(QString(tr("Wingman failed to receive an answer from the GPT provider"))); + + // PUSH answer to the chat dialog + this->wingmanDialog->appendAnswerToChat( + "Wingman failed to get answer from the GPT provider.

"+commandWingmanChat.answerMarkdown, + "", + this->wingmanDialog->getContextType(), + true + ); + + return; + } + } else { + mind->wingmanChat(commandWingmanChat); + } + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end - start); + // wingmanProgressDialog->hide(); + string answerDescriptor{ + "[model: " + commandWingmanChat.answerLlmModel + + ", tokens (prompt/answer): " + + std::to_string(commandWingmanChat.promptTokens) + "/" + std::to_string(commandWingmanChat.answerTokens) + + ", time: " + + std::to_string(duration.count()) + + "s, status: " + + (commandWingmanChat.status==WingmanStatusCode::WINGMAN_STATUS_CODE_OK?"OK":"ERROR") + + "]" + }; + + // PUSH answer to the chat dialog + if(WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR == commandWingmanChat.status) { + this->wingmanDialog->appendAnswerToChat( + commandWingmanChat.errorMessage, + answerDescriptor, + this->wingmanDialog->getContextType(), + true + ); + } else { + this->wingmanDialog->appendAnswerToChat( + commandWingmanChat.answerMarkdown, + answerDescriptor, + this->wingmanDialog->getContextType() + ); + } + + this->wingmanDialog->setLastPromptLabel(); + this->wingmanDialog->selectPrompt(); +} + +void MainWindowPresenter::slotWingmanAppendFromDialog() +{ + if(this->wingmanDialog->getLastAnswer().length()) { + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) { + if(orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor()->getSelectedText().size()) { + orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor()->appendAfterSelectedText( + this->wingmanDialog->getLastAnswer()); + statusBar->showInfo(QString(tr("Wingman's answer appended after selected text in the Notebook header."))); + } else{ + orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor()->appendAfterCursor( + this->wingmanDialog->getLastAnswer()); + statusBar->showInfo(QString(tr("Wingman's answer appended after the cursor in the Notebook header."))); + } + this->wingmanDialog->hide(); + return; + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) { + if(orloj->getNoteEdit()->getView()->getNoteEditor()->getSelectedText().size()) { + orloj->getNoteEdit()->getView()->getNoteEditor()->appendAfterSelectedText( + this->wingmanDialog->getLastAnswer()); + statusBar->showInfo(QString(tr("Wingman's answer appended after selected text in the Note editor."))); + } else{ + orloj->getNoteEdit()->getView()->getNoteEditor()->appendAfterCursor( + this->wingmanDialog->getLastAnswer()); + statusBar->showInfo(QString(tr("Wingman's answer appended after the cursor in the Note editor."))); + } + this->wingmanDialog->hide(); + return; + } else { + statusBar->showInfo( + QString( + tr("Unable to append after selected text with Wingman's answer in non-edit perspective."))); + return; + } + } + statusBar->showInfo(QString(tr("No answer from Wingman to append after selected text - run a prompt."))); +} + +void MainWindowPresenter::slotWingmanReplaceFromDialog() +{ + if(this->wingmanDialog->getLastAnswer().length()) { + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER)) { + if(orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor()->getSelectedText().size()) { + orloj->getOutlineHeaderEdit()->getView()->getHeaderEditor()->replaceSelectedText( + this->wingmanDialog->getLastAnswer()); + statusBar->showInfo(QString(tr("Wingman's answer replaced selected text in Notebook header."))); + this->wingmanDialog->hide(); + } else{ + QMessageBox::critical( + &view, + tr("Wingman Action Error"), + tr("Unable to replace Notebook header text - no text selected.") + ); + } + return; + } else if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE)) { + if(orloj->getNoteEdit()->getView()->getNoteEditor()->getSelectedText().size()) { + orloj->getNoteEdit()->getView()->getNoteEditor()->replaceSelectedText( + this->wingmanDialog->getLastAnswer()); + statusBar->showInfo(QString(tr("Wingman's answer replaced selected text in Note text."))); + this->wingmanDialog->hide(); + } else{ + QMessageBox::critical( + &view, + tr("Wingman Action Error"), + tr("Unable to replace Note text - no text selected.") + ); + } + return; + } else { + statusBar->showInfo( + QString( + tr("Unable to replace selected text with Wingman's answer in non-edit perspective."))); + return; + } + } + statusBar->showInfo(QString(tr("No answer from Wingman to replace selected text - run a prompt."))); +} + void MainWindowPresenter::doActionOutlineOrNoteNew() { if(orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER) @@ -1913,7 +2312,7 @@ void MainWindowPresenter::doActionOutlineOrNoteNew() orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_NOTE) || orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE)) - { + { doActionNoteNew(); } else { doActionOutlineNew(); @@ -1997,7 +2396,7 @@ bool MainWindowPresenter::withWriteableOutline(const std::string& outlineKey) } void MainWindowPresenter::handleNoteNew() -{ +{ int offset = orloj->getOutlineView()->getOutlineTree()->getCurrentRow(); if(offset == OutlineTreePresenter::NO_ROW) { @@ -2350,7 +2749,7 @@ void MainWindowPresenter::doActionNoteExternalEdit() "Error: unable to run external editor as C++ command processor " "is not available" }; - MF_DEBUG(errorMessage); + MF_DEBUG(errorMessage << endl); statusBar->showError(errorMessage); QMessageBox::critical( &view, @@ -2467,9 +2866,34 @@ void MainWindowPresenter::doActionNoteForget() QAbstractButton* choosen = msgBox.clickedButton(); if(yes == choosen) { + // delete selected row & SELECT and adjacent row: + // - row is always deleted INCLUDING children + // - adjacent row must be identified BEFORE deleting the row + // consider the following scenarios: + // - N is the first row in O + // > row 0 w/ chidlren will be deleted and new row 0 + // will be selected AFTER the delete (if any N remains in O) + // - there are Ns above row to be deleted + // > simplest scenario - N above N to be deleted will be selected + // - N is the last N in O, it has children and it is deleted including children + // > no row is selected in this case + + Note* adjacentNote = nullptr; + if(orloj->getOutlineView()->getOutlineTree()->getModel()->rowCount() > 1) { + adjacentNote = orloj->getOutlineView()->getOutlineTree()->getAdjacentNote(); + } + Outline* outline = mind->noteForget(note); mind->remember(outline); orloj->showFacetOutline(orloj->getOutlineView()->getCurrentOutline()); + + if(orloj->getOutlineView()->getOutlineTree()->getModel()->rowCount()) { + if(adjacentNote) { + orloj->getOutlineView()->selectRowByNote(adjacentNote); + } else { + orloj->getOutlineView()->getOutlineTree()->selectRow(0); + } + } } return; } @@ -2479,7 +2903,7 @@ void MainWindowPresenter::doActionNoteForget() void MainWindowPresenter::doActionNoteExtract() { - // TODO distinquish HEADER and NOTE - different places from where to get text + // TODO distinguish HEADER and NOTE - different places from where to get text if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER) || orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE) @@ -2577,20 +3001,61 @@ void MainWindowPresenter::doActionNoteClone() } } +void MainWindowPresenter::doActionOutlineShow() +{ + orloj->showFacetOutline(orloj->getOutlineView()->getCurrentOutline()); +} + +void MainWindowPresenter::selectNoteInOutlineTree(Note* note, Outline::Patch& patch, bool onUp) +{ + QModelIndex idx; + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + if(onUp) { + idx = orloj->getOutlinesMap()->getModel()->index(patch.start, 0); + } else { + idx = orloj->getOutlinesMap()->getModel()->index(note->getOutline()->getNoteOffset(note), 0); + } + + orloj->getOutlinesMap()->getView()->setCurrentIndex(idx); + } else { + if(onUp) { + idx = orloj->getOutlineView()->getOutlineTree()->getView()->model()->index(patch.start, 0); + } else { + idx = orloj->getOutlineView()->getOutlineTree()->getView()->model()->index(note->getOutline()->getNoteOffset(note), 0); + } + orloj->getOutlineView()->getOutlineTree()->getView()->setCurrentIndex(idx); + } +} + void MainWindowPresenter::doActionNoteFirst() { - Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + Note* note{}; + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + note = orloj->getOutlinesMap()->getCurrentNote(); + } else { + note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + } + if(note && withWriteableOutline(note->getOutline()->getKey())) { // IMPROVE consider patch once in class (cross functions) Outline::Patch patch{Outline::Patch::Diff::NO,0,0}; // explicit initialization required by older GCC versions mind->noteFirst(note, &patch); if(patch.diff != Outline::Patch::Diff::NO) { - mind->remind().remember(note->getOutline()); - orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + mind->outlinesMapRemember(); + } else { + mind->remind().remember(note->getOutline()); + } + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + orloj->getOutlinesMap()->refresh(note->getOutline(), &patch); + } else { + orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + } + // select Note in the tree - QModelIndex idx - = orloj->getOutlineView()->getOutlineTree()->getView()->model()->index(patch.start, 0); - orloj->getOutlineView()->getOutlineTree()->getView()->setCurrentIndex(idx); + this->selectNoteInOutlineTree(note, patch, true); statusBar->showInfo(QString(tr("Moved Note '%1' to be the first child")).arg(note->getName().c_str())); } } else { @@ -2600,18 +3065,33 @@ void MainWindowPresenter::doActionNoteFirst() void MainWindowPresenter::doActionNoteUp() { - Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + Note* note{}; + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + note = orloj->getOutlinesMap()->getCurrentNote(); + } else { + note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + } + if(note && withWriteableOutline(note->getOutline()->getKey())) { // IMPROVE consider patch once in class (cross functions) Outline::Patch patch{Outline::Patch::Diff::NO,0,0}; // explicit initialization required by older GCC versions mind->noteUp(note, &patch); if(patch.diff != Outline::Patch::Diff::NO) { - mind->remind().remember(note->getOutline()); - orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + mind->outlinesMapRemember(); + } else { + mind->remind().remember(note->getOutline()); + } + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + orloj->getOutlinesMap()->refresh(note->getOutline(), &patch); + } else { + orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + } + // select Note in the tree - QModelIndex idx - = orloj->getOutlineView()->getOutlineTree()->getView()->model()->index(patch.start, 0); - orloj->getOutlineView()->getOutlineTree()->getView()->setCurrentIndex(idx); + this->selectNoteInOutlineTree(note, patch, true); statusBar->showInfo(QString(tr("Moved up Note '%1'")).arg(note->getName().c_str())); } } else { @@ -2621,18 +3101,33 @@ void MainWindowPresenter::doActionNoteUp() void MainWindowPresenter::doActionNoteDown() { - Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + Note* note{}; + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + note = orloj->getOutlinesMap()->getCurrentNote(); + } else { + note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + } + if(note && withWriteableOutline(note->getOutline()->getKey())) { // IMPROVE consider patch once in class (cross functions) Outline::Patch patch{Outline::Patch::Diff::NO,0,0}; // explicit initialization required by older GCC versions mind->noteDown(note, &patch); if(patch.diff != Outline::Patch::Diff::NO) { - mind->remind().remember(note->getOutline()); - orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + mind->outlinesMapRemember(); + } else { + mind->remind().remember(note->getOutline()); + } + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + orloj->getOutlinesMap()->refresh(note->getOutline(), &patch); + } else { + orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + } + // select Note in the tree - QModelIndex idx - = orloj->getOutlineView()->getOutlineTree()->getView()->model()->index(note->getOutline()->getNoteOffset(note), 0); - orloj->getOutlineView()->getOutlineTree()->getView()->setCurrentIndex(idx); + this->selectNoteInOutlineTree(note, patch, false); statusBar->showInfo(QString(tr("Moved down Note '%1'").arg(note->getName().c_str()))); } } else { @@ -2642,18 +3137,33 @@ void MainWindowPresenter::doActionNoteDown() void MainWindowPresenter::doActionNoteLast() { - Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + Note* note{}; + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + note = orloj->getOutlinesMap()->getCurrentNote(); + } else { + note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + } + if(note && withWriteableOutline(note->getOutline()->getKey())) { // IMPROVE consider patch once in class (cross functions) Outline::Patch patch{Outline::Patch::Diff::NO,0,0}; // explicit initialization required by older GCC versions mind->noteLast(note, &patch); if(patch.diff != Outline::Patch::Diff::NO) { - mind->remind().remember(note->getOutline()); - orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + mind->outlinesMapRemember(); + } else { + mind->remind().remember(note->getOutline()); + } + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + orloj->getOutlinesMap()->refresh(note->getOutline(), &patch); + } else { + orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + } + // select Note in the tree - QModelIndex idx - = orloj->getOutlineView()->getOutlineTree()->getView()->model()->index(note->getOutline()->getNoteOffset(note), 0); - orloj->getOutlineView()->getOutlineTree()->getView()->setCurrentIndex(idx); + this->selectNoteInOutlineTree(note, patch, false); statusBar->showInfo(QString(tr("Moved Note '%1' to be the last child")).arg(note->getName().c_str())); } } else { @@ -2661,21 +3171,33 @@ void MainWindowPresenter::doActionNoteLast() } } -void MainWindowPresenter::doActionOutlineShow() -{ - orloj->showFacetOutline(orloj->getOutlineView()->getCurrentOutline()); -} - void MainWindowPresenter::doActionNotePromote() { - Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + Note* note{}; + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + note = orloj->getOutlinesMap()->getCurrentNote(); + } else { + note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + } + if(note && withWriteableOutline(note->getOutline()->getKey())) { // IMPROVE consider patch once in class (cross functions) Outline::Patch patch{Outline::Patch::Diff::NO,0,0}; // explicit initialization required by older GCC versions mind->notePromote(note, &patch); if(patch.diff != Outline::Patch::Diff::NO) { - mind->remind().remember(note->getOutline()); - orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + mind->outlinesMapRemember(); + } else { + mind->remind().remember(note->getOutline()); + } + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + orloj->getOutlinesMap()->refresh(note->getOutline(), &patch); + } else { + orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + } + statusBar->showInfo(QString(tr("Promoted Note '%1'")).arg(note->getName().c_str())); } } else { @@ -2685,14 +3207,31 @@ void MainWindowPresenter::doActionNotePromote() void MainWindowPresenter::doActionNoteDemote() { - Note* note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + Note* note{}; + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + note = orloj->getOutlinesMap()->getCurrentNote(); + } else { + note = orloj->getOutlineView()->getOutlineTree()->getCurrentNote(); + } + if(note && withWriteableOutline(note->getOutline()->getKey())) { // IMPROVE consider patch once in class (cross functions) Outline::Patch patch{Outline::Patch::Diff::NO,0,0}; // explicit initialization required by older GCC versions mind->noteDemote(note, &patch); - mind->remind().remember(note->getOutline()); - orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); if(patch.diff != Outline::Patch::Diff::NO) { + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + mind->outlinesMapRemember(); + } else { + mind->remind().remember(note->getOutline()); + } + + if(orloj->isFacetActive(OrlojPresenterFacets::FACET_MAP_OUTLINES)) { + orloj->getOutlinesMap()->refresh(note->getOutline(), &patch); + } else { + orloj->getOutlineView()->getOutlineTree()->refresh(note->getOutline(), &patch); + } + statusBar->showInfo(QString(tr("Demoted Note '%1'")).arg(note->getName().c_str())); } } else { @@ -2818,16 +3357,6 @@ void MainWindowPresenter::doActionViewTerminal() terminalDialog->show(); } -void MainWindowPresenter::doActionKnowledgeWikipedia() -{ - QDesktopServices::openUrl(QUrl{"https://en.wikipedia.org/"}); -} - -void MainWindowPresenter::doActionKnowledgeArxiv() -{ - QDesktopServices::openUrl(QUrl{"https://arxiv.org/search/cs"}); -} - void MainWindowPresenter::doActionLibraryNew() { newLibraryDialog->show(); @@ -2846,13 +3375,9 @@ void MainWindowPresenter::handleNewLibrary() return; } - // TODO check that it's new path (SAFE library update is different operation) - newLibraryDialog->hide(); - // TODO add library to repository configuration - - // TODO index library documents + // index library documents FilesystemInformationSource informationSource{ uri, *orloj->getMind(), @@ -2866,7 +3391,7 @@ void MainWindowPresenter::handleNewLibrary() QMessageBox::critical( &view, tr("Add Library Error"), - tr("Library already indexed - use update action to reindex documents.") + tr("Library already indexed - use 'Update library' action to synchronize documents.") ); return; } @@ -2875,7 +3400,7 @@ void MainWindowPresenter::handleNewLibrary() &view, tr("Add Library Error"), tr("Unable to index documents on library path - either memory directory " - "doesn't exist or not in MindForger repository mode." + "doesn't exist or not in MindForger workspace mode." ) ); return; @@ -2889,6 +3414,121 @@ void MainWindowPresenter::handleNewLibrary() orloj->showFacetOutlineList(mind->getOutlines()); } +void MainWindowPresenter::doActionLibrarySync() +{ + syncLibraryDialog->reset(); + + // determine existing library dirs + vector srcs + = FilesystemInformationSource::findInformationSources( + config, + *orloj->getMind(), + *mdDocumentRepresentation); + + if(srcs.size()) { + for(FilesystemInformationSource* src:srcs) { + syncLibraryDialog->addLibraryToSync(src->getPath()); + + delete src; + } + + syncLibraryDialog->show(); + } else { + QMessageBox::information( + &view, + tr("Library synchronization"), + tr("There are no libraries - nothing to synchronize.") + ); + } +} + +void MainWindowPresenter::handleSyncLibrary() +{ + syncLibraryDialog->hide(); + + string librarySrcDir + = syncLibraryDialog->getLibraryPathsCombo()->currentText().toStdString(); + + FilesystemInformationSource informationSource{ + librarySrcDir, + *orloj->getMind(), + *mdDocumentRepresentation, + }; + + informationSource.indexToMemory(*config.getActiveRepository(), true); + + rmLibraryDialog->reset(); +} + + +void MainWindowPresenter::doActionLibraryRm() +{ + rmLibraryDialog->reset(); + + // determine existing library dirs + vector srcs + = FilesystemInformationSource::findInformationSources( + config, + *orloj->getMind(), + *mdDocumentRepresentation); + + if(srcs.size()) { + for(FilesystemInformationSource* src:srcs) { + rmLibraryDialog->addLibraryToRemove(src); + } + + rmLibraryDialog->show(); + } else { + QMessageBox::information( + &view, + tr("Library deletion"), + tr("There are no libraries - nothing to delete.") + ); + } +} + +void MainWindowPresenter::handleRmLibrary() +{ + rmLibraryDialog->hide(); + + string librarySrcDir + = rmLibraryDialog->getLibraryPathsCombo()->currentText().toStdString(); + + // confirm removal of MF directory + QMessageBox msgBox{ + QMessageBox::Question, + tr("Delete Library"), + tr("Do you really want to delete Notebooks which represent the library documents?") + }; + QPushButton* yes = msgBox.addButton("&Yes", QMessageBox::YesRole); +#ifdef __APPLE__ + yes->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Y)); + yes->setToolTip("⌘Y"); + + QPushButton* no = +#endif + msgBox.addButton("&No", QMessageBox::NoRole); +#ifdef __APPLE__ + no->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_N)); + no->setToolTip("⌘N"); +#endif + msgBox.exec(); + + QAbstractButton* choosen = msgBox.clickedButton(); + if(yes == choosen) { + // purge library directory + string mfLibraryPath{rmLibraryDialog->getLibraryMfPathForLocator(librarySrcDir)}; + removeDirectoryRecursively(mfLibraryPath.c_str()); + + // reload the whole workspace + doActionMindRelearn( + QString::fromStdString(config.getActiveRepository()->getPath()) + ); + } + + rmLibraryDialog->reset(); +} + void MainWindowPresenter::doActionOrganizerNew() { newOrganizerDialog->show(mind->getOutlines()); @@ -2903,11 +3543,11 @@ void MainWindowPresenter::handleCreateOrganizer() Organizer* o{nullptr}; if(newOrganizerDialog->getOrganizerToEdit()) { - MF_DEBUG("Updating organizer..."); + MF_DEBUG("Updating organizer..." << endl); o = newOrganizerDialog->getOrganizerToEdit(); o->setName(newOrganizerDialog->getOrganizerName().toStdString()); } else { - MF_DEBUG("Creating organizer..."); + MF_DEBUG("Creating organizer..." << endl); if(Organizer::OrganizerType::EISENHOWER_MATRIX == newOrganizerDialog->getOrganizerType()) { o = new EisenhowerMatrix( newOrganizerDialog->getOrganizerName().toStdString() @@ -2956,7 +3596,7 @@ void MainWindowPresenter::handleCreateOrganizer() // add organizer & save configuration if(!newOrganizerDialog->getOrganizerToEdit()) { - config.getRepositoryConfiguration().addOrganizer(o); + config.getRepositoryConfiguration().addOrganizer(o); } sortAndSaveOrganizersConfig(); @@ -3183,27 +3823,52 @@ void MainWindowPresenter::doActionOrganizerForget() choice = QMessageBox::question( &view, tr("Forget Organizer"), - tr("Do you really want to forget '") + QString::fromStdString(o->getName()) + tr("' Organizer?") + tr("Do you really want to forget '") + + QString::fromStdString(o->getName()) + tr("' Organizer?") ); if (choice == QMessageBox::Yes) { config.getRepositoryConfiguration().removeOrganizer(o); getConfigRepresentation()->save(config); - orloj->showFacetOrganizerList(config.getRepositoryConfiguration().getOrganizers()); + orloj->showFacetOrganizerList( + config.getRepositoryConfiguration().getOrganizers()); } // else do nothing } else { QMessageBox::critical( &view, tr("Delete Organizer"), - tr("Eisenhower Matrix is built-in and cannot be deleted - only custom organizers can.") + tr( + "Eisenhower Matrix is built-in and cannot be deleted - only custom " + "organizers can.") + ); + } +} + + +void MainWindowPresenter::doActionViewLimbo() +{ + if(config.getActiveRepository()->getMode() + ==Repository::RepositoryMode::REPOSITORY + && config.getActiveRepository()->getType() + ==Repository::RepositoryType::MINDFORGER + ) { + QString path{"file://"}; + path.append(config.getLimboPath().c_str()); + QDesktopServices::openUrl(QUrl{path}); + } else { + QMessageBox::information( + &view, + tr("View Limbo"), + tr( + "Limbo directory with deleted Notebooks is available in " + "the MindForger workspace, not if a Markdown is edited or a directory " + "with markdowns is opened.") ); } } void MainWindowPresenter::doActionHelpDocumentation() { - QDesktopServices::openUrl( - QUrl{"https://github.com/dvorka/mindforger-repository/blob/master/memory/mindforger/index.md"} - ); + QDesktopServices::openUrl(QUrl{"https://github.com/dvorka/mindforger/wiki"}); } void MainWindowPresenter::doActionHelpWeb() @@ -3237,7 +3902,9 @@ void MainWindowPresenter::doActionHelpMathLivePreview() void MainWindowPresenter::doActionHelpMathQuickReference() { QDesktopServices::openUrl( - QUrl{"https://math.meta.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference"} + QUrl{ + "https://math.meta.stackexchange.com/questions/5020" + "/mathjax-basic-tutorial-and-quick-reference"} ); } @@ -3255,6 +3922,49 @@ void MainWindowPresenter::doActionHelpCheckForUpdates() ); } +void MainWindowPresenter::doActionEmojisDialog() +{ + // IMPROVE load emojis from the main MF configuration file + QMessageBox::information( + &view, + QString{tr("Emojis")}, + QString{ + "" + "Copy character from below to paste it:" + "
" + "
Emoji:" + "
🐞 🚀 🌟 🔧 🧪 📚 🔗 ⛑ 🚧 ❗ ❌ ✔" + "
📌 ✂️ 📎 📋 📝 📅 📈 🖼️" + "
🔴 🔵 🟣 🟢 🔮 ♥ 💙 💛 💚 🚫 🎯 ⚽ ⚙️" + "
🙂 😃 🥶 🥰 🐻 🐸 🤖 💩 👻 🎉 💣 ☠️" + "
🦑 🐙 👾 🐉" + "
💪 👍 🤞 🤙 👌 🙏 🤦" + "
🛠 🔧 🔨 💎 🛡 💥 🔥 🧬 🧙‍ 🧠 🔋 ⦀" + "
🚀 🛸 📡 🌊 🎖 🍔 🥋 💍 🥔 🎨 🌻 🌲" + "
📣 📢 🧲 🏁 🚩 💯" + "
" + "
Greek alphabet:" + "
Α α, Β β, Γ γ, Δ δ, Ε ε," + "
Ζ ζ, Η η, Θ θ, Ι ι, Κ κ," + "
Λ λ, Μ μ, Ν ν, Ξ ξ, Ο ο," + "
Π π, Ρ ρ, Σ σ/ς, Τ τ, Υ υ," + "
Φ φ, Χ χ, Ψ ψ, Ω ω" + "
" + "
Math and statistics:" + "
x̄" + "
" + "
Physics:" + "
°" + "
" + "
More special unicode characters:" + "" + }); +} + + void MainWindowPresenter::doActionHelpAboutMindForger() { // IMPROVE move this to view: remove this method and route signal to MainWindowView @@ -3280,7 +3990,7 @@ void MainWindowPresenter::doActionHelpAboutMindForger() "
Contact me at <martin.dvorak@mindforger.com>" " or see www.mindforger.com for more information." "
" - "
Copyright (C) 2016-2022 Martin Dvorak and contributors." + "
Copyright (C) 2016-2024 Martin Dvorak and contributors." }); } diff --git a/app/src/qt/main_window_presenter.h b/app/src/qt/main_window_presenter.h index e1f95350..892714fd 100644 --- a/app/src/qt/main_window_presenter.h +++ b/app/src/qt/main_window_presenter.h @@ -1,7 +1,7 @@ /* main_window_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -19,6 +19,8 @@ #ifndef M8RUI_MAIN_WINDOW_PRESENTER_H #define M8RUI_MAIN_WINDOW_PRESENTER_H +#include + #include "../../lib/src/mind/mind.h" #include "../../lib/src/mind/ai/autolinking_preprocessor.h" #include "../../lib/src/mind/dikw/filesystem_information.h" @@ -30,14 +32,15 @@ #include "main_menu_presenter.h" #include "gear/async_task_notifications_distributor.h" -#ifdef MF_NER - #include "ner_main_window_worker_thread.h" -#endif #include "cli_n_breadcrumbs_presenter.h" #include "orloj_presenter.h" #include "status_bar_presenter.h" #include "dialogs/add_library_dialog.h" +#include "dialogs/sync_library_dialog.h" +#include "dialogs/rm_library_dialog.h" +#include "dialogs/run_tool_dialog.h" +#include "dialogs/wingman_dialog.h" #include "dialogs/organizer_new_dialog.h" #include "dialogs/outline_new_dialog.h" #include "dialogs/note_new_dialog.h" @@ -57,8 +60,6 @@ #include "dialogs/terminal_dialog.h" #include "dialogs/export_csv_file_dialog.h" #include "dialogs/export_file_dialog.h" -#include "dialogs/ner_choose_tag_types_dialog.h" -#include "dialogs/ner_result_dialog.h" #include #include @@ -88,6 +89,7 @@ class FtsDialogPresenter; * and code conventions. * */ +// TODO rename to AppWindowPresenter class MainWindowPresenter : public QObject { Q_OBJECT @@ -104,9 +106,6 @@ class MainWindowPresenter : public QObject Mind* mind; AsyncTaskNotificationsDistributor* distributor; -#ifdef MF_NER - NerMainWindowWorkerThread* nerWorker; -#endif MarkdownOutlineRepresentation* mdRepresentation; HtmlOutlineRepresentation* htmlRepresentation; @@ -120,6 +119,10 @@ class MainWindowPresenter : public QObject StatusBarPresenter* statusBar; AddLibraryDialog* newLibraryDialog; + SyncLibraryDialog* syncLibraryDialog; + RemoveLibraryDialog* rmLibraryDialog; + RunToolDialog* runToolDialog; + WingmanDialog* wingmanDialog; ScopeDialog* scopeDialog; OrganizerNewDialog* newOrganizerDialog; OutlineNewDialog* newOutlineDialog; @@ -141,8 +144,6 @@ class MainWindowPresenter : public QObject NewFileDialog* newFileDialog; ExportFileDialog* exportOutlineToHtmlDialog; ExportCsvFileDialog* exportMemoryToCsvDialog; - NerChooseTagTypesDialog *nerChooseTagsDialog; - NerResultDialog* nerResultDialog; public: explicit MainWindowPresenter(MainWindowView& view); @@ -169,26 +170,23 @@ class MainWindowPresenter : public QObject // function Mind* getMind() const { return mind; } - // dashboard(s) + // hey hello! void showInitialView(); // N view void handleNoteViewLinkClicked(const QUrl& url); - // NER - NerMainWindowWorkerThread* startNerWorkerThread( - Mind* m, - OrlojPresenter* o, - int f, - std::vector* r, - QDialog* d - ); - public slots: // mind #ifdef DO_MF_DEBUG void doActionMindHack(); #endif + // wingman: dialog + void handleActionWingman(bool showDialog=true); + void slotRunWingmanFromDialog(bool showDialog=false); + void slotWingmanAppendFromDialog(); + void slotWingmanReplaceFromDialog(); + // workspace void doActionMindNewRepository(); void handleMindNewRepository(); void doActionMindNewFile(); @@ -212,47 +210,39 @@ public slots: // recall void doActionFts(); void doFts(const QString& pattern, bool doSearch=false); - void doActionFindOutlineByName(); + void doActionFindOutlineByName(const std::string& phrase=""); void handleFindOutlineByName(); void handleFindThingByName(); void doActionFindNoteByName(); void handleFindNoteByName(); - void doActionFindOutlineByTag(); + void doActionFindOutlineByTag(const std::string& tag=""); void handleFindOutlineByTag(); void doActionFindNoteByTag(); void doTriggerFindNoteByTag(const m8r::Tag* tag); void doSwitchFindByTagDialog(bool toFindNotesByTag); void handleFindNoteByTag(); -#ifdef MF_NER - void doActionFindNerPersons(); - void doActionFindNerLocations(); - void doActionFindNerOrganizations(); - void doActionFindNerMisc(); - void handleFindNerEntities(); - void chooseNerEntityResult(vector*); - void handleChooseNerEntityResult(); - void handleFtsNerEntity(); -#endif // view - void doActionViewDashboard(); void sortAndSaveOrganizersConfig(); void doActionViewOrganizers(); void doActionViewOrganizer(); void doActionViewTagCloud(); bool doActionViewHome(); void doActionViewOutlines(); + void doActionViewOutlinesMap(); void doActionViewRecentNotes(); void doActionViewKnowledgeGraphNavigator(); void doActionCli(); void doActionViewTerminal(); + void doActionViewLimbo(); void doActionViewDistractionFree(); void doActionViewFullscreen(); - // knowledge - void doActionKnowledgeArxiv(); - void doActionKnowledgeWikipedia(); // library void doActionLibraryNew(); void handleNewLibrary(); + void doActionLibrarySync(); + void handleSyncLibrary(); + void doActionLibraryRm(); + void handleRmLibrary(); // organizer void doActionOrganizerNew(); void handleCreateOrganizer(); @@ -297,10 +287,12 @@ public slots: void doActionFormatListNumber(); void doActionFormatListTask(); void doActionFormatListTaskItem(); - void doActionFormatToc(); + void doActionFormatToc(bool withTags); + void doActionFormatTocWithTags(); + void doActionFormatTocWithoutTags(); void doActionFormatTimestamp(); void doActionFormatCodeBlock(); - void doActionFormatMathBlock(); + void doActionFormatMathBlock(); void doActionFormatDiagramBlock(); void doActionFormatDiagramPie(); void doActionFormatDiagramFlow(); @@ -328,6 +320,21 @@ public slots: void doActionOutlineHtmlExport(); void handleOutlineHtmlExport(); void doActionOutlineTWikiImport(); + bool checkWingmanAvailability(); + void handleWingmanMenuAction(const std::string& prompt); + void doActionWingmanOSummarize() { handleWingmanMenuAction(PROMPT_SUMMARIZE); } + void doActionWingmanOExplain() { handleWingmanMenuAction(PROMPT_EXPLAIN_LIKE_5); } + void doActionWingmanOFind() { handleWingmanMenuAction(PROMPT_FIND_TASKS); } + + void doActionWingmanNSummarize() { handleWingmanMenuAction(PROMPT_SUMMARIZE); } + void doActionWingmanNFixGrammar() { handleWingmanMenuAction(PROMPT_FIND_GRAMMAR); } + void doActionWingmanNRewrite() { handleWingmanMenuAction(PROMPT_TRANSLATE_EN); } + + void doActionWingmanEFixGrammar() { handleWingmanMenuAction(PROMPT_FIX_GRAMMAR); } + void doActionWingmanEExplain() { handleWingmanMenuAction(PROMPT_EXPLAIN_LIKE_5_TXT); } + void doActionWingmanEFinishText() { handleWingmanMenuAction(PROMPT_COMPLETE_TEXT); } + void doActionWingmanERewriteText() { handleWingmanMenuAction(PROMPT_REWRITE_FORMALLY); } + // Note void doActionNoteNew(); bool withWriteableOutline(const std::string& outlineKey); @@ -337,6 +344,7 @@ public slots: void doActionOutlineShow(); void doActionNoteEdit(); void doActionNoteExternalEdit(); + void selectNoteInOutlineTree(Note* note, Outline::Patch& patch, bool onUp); void doActionNoteFirst(); void doActionNoteUp(); void doActionNotePromote(); @@ -354,6 +362,9 @@ public slots: void doActionEditFindAgain(); void doActionEditWordWrapToggle(); void doActionEditPasteImageData(QImage image); + void doActionRunToolDialogAnywhere(); + void doActionOpenRunToolDialog(QString& phrase, QString& toolId, bool showDialog=true); + void handleRunTool(); void doActionToggleLiveNotePreview(); void doActionNameDescFocusSwap(); void doActionSpellCheck(); @@ -366,6 +377,7 @@ public slots: void doActionHelpDiagrams(); void doActionHelpReportBug(); void doActionHelpCheckForUpdates(); + void doActionEmojisDialog(); void doActionHelpAboutMindForger(); void slotHandleFts(); diff --git a/app/src/qt/main_window_view.cpp b/app/src/qt/main_window_view.cpp index 9c88dcd3..e5ec0c7e 100644 --- a/app/src/qt/main_window_view.cpp +++ b/app/src/qt/main_window_view.cpp @@ -1,7 +1,7 @@ /* main_window_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -24,7 +24,16 @@ MainWindowView::MainWindowView(LookAndFeels& lookAndFeel) : QMainWindow(nullptr), // main window has no parent - it is destroyed by main MF class lookAndFeel(lookAndFeel) { - windowTitleSkeleton = "MindForger - "+tr("Thinking Notebook")+" - "+MINDFORGER_VERSION; +#ifdef MF_LLAMA_CPP + #define MINDFORGER_GPT " GPT" +#else + #define MINDFORGER_GPT "" +#endif + windowTitleSkeleton + = "MindForger" MINDFORGER_GPT " - " + +tr("Thinking Notebook")+" - " + +MINDFORGER_VERSION; + setWindowTitle(windowTitleSkeleton); toolBarView = new MainToolbarView{this}; diff --git a/app/src/qt/main_window_view.h b/app/src/qt/main_window_view.h index 3e269f3c..b407d4f6 100644 --- a/app/src/qt/main_window_view.h +++ b/app/src/qt/main_window_view.h @@ -1,7 +1,7 @@ /* main_window_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/mindforger.cpp b/app/src/qt/mindforger.cpp index 799f4a2a..f64e3a3f 100644 --- a/app/src/qt/mindforger.cpp +++ b/app/src/qt/mindforger.cpp @@ -41,13 +41,15 @@ using namespace m8r::filesystem; * * ``` * $ mindforger - * ... lookup repository as follows - * 1. configured in ~/.mindforger, + * ... looks up repository as follows + * 1. repository configured in ~/.mindforger, * 2. specified by environment variable MINDFORGER_REPOSITORY, - * 3. check existence of MindForger repository in default location i.e. ~/mindforger-repository - * 4. create new MindForger repository in default location i.e. ~/mindforger-repository + * 3. checks existence of MindForger repository in default location + * i.e. ~/mindforger-repository + * 4. creates new MindForger repository in default location + * i.e. ~/mindforger-repository * $ mindforger ~/my-mf-repository - * ... MindForger repository + * ... start MindForger with given repository * $ mindforger ~/books/marathon-training * ... directory structure w/ Markdowns * $ mindforger ~/my-mf-repository/memory/plans.md @@ -78,7 +80,8 @@ using namespace m8r::filesystem; * -h * ``` * - * Terminal CLI commands proposal: + * Terminal CLI commands proposal + * (Docker inspiration > switch entity and action): * * ``` * $ mindforger --command LIST outlines @@ -127,42 +130,53 @@ int main(int argc, char* argv[]) // default terminal macOS environment: TERM=xterm-256color DISPLAY= #endif - // Stupid & ugly: QWebEngine @ macOS requires extra parameter(s) to - // allow access to local files (like images) to QApplication (security). - // Parameter differ Qt version to Qt version as diffent versions - // bundle different Chromium versions. - // - // Qt 5.9.9 - // --disable-web-security ... same origin // - // Qt 5.15.2 ~ Chrome 83 ~ I did NOT find params to enable filesystem access - // --user-data-dir= ... user data dir - // --disable-web-security ... same origin - // --disable-site-isolation-trials + // SECURITY: WebKit vs WebEngine in Qt // - // QApplication args assembly: - // - order in ^ examples matters + // Stupid & ugly: QWebEngine @ macOS/Win requires extra parameter(s) to + // allow access to local files (like images) to QApplication (security). + // MindForger generates HTML from Markdown and uses QWebEngine to render it, + // so it needs to allow access to files (like images) references from the HTML. + // Qt parameters to QWebEngine differ Qt version to Qt version as different + // versions bundle different Chromium versions. (Qt uses QWebKit on Linux) // - // Additional hints: - // - HTML is rendered by QWebEngine on macOS - // - QWebEngine is Chromium wrapper - // https://doc.qt.io/qt-5/qtwebengine-overview.html - // https://doc.qt.io/qt-5/qtwebengine-features.html + // Qt 5.9.9 + // * --disable-web-security ... same origin // - // Debugging: + // Qt 5.15.2 + // * --disable-web-security ... can go AWAY + // * base URL: file:// // - // - DEBUG_WEBENGINE_SECURITY_QT_5_15 -//#define DEBUG_WEBENGINE_SECURITY_QT_5_15 + // If DESPERATE in the future, then get SHA which edited this line from Git history. + // (it removed code which can debug WebEngine security parameters on macOS/Win) // // Resources: - // - https://doc.qt.io/qt-5/qtwebengine-index.html - // - https://doc.qt.io/qt-5/qtwebengine-debugging.html#using-command-line-arguments - // - https://wiki.qt.io/QtWebEngine/ChromiumVersions - // - https://stackoverflow.com/questions/35432749/disable-web-security-in-chrome-48 - // ^ changes in required parameters with disable-web-security + // * https://github.com/dvorka/mindforger/issues/1506 + // explanation of the problem and solution + // * https://github.com/dvorka/mindforger/compare/dev/1.55.1...shlemiel:mindforger_poc0:dev/1.55.1 + // POC of the solution (what to change for Qt 5.15.0+): + // - note_view.h (baseURL) and outline_header_view.h (baseURL) QUrl from "" to "file://" // -#if defined(__APPLE__) || defined(_WIN32) - #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + // Additional resources: + // - QWebEngine as Chromium wrapper: + // - https://doc.qt.io/qt-5/qtwebengine-index.html + // - https://doc.qt.io/qt-5/qtwebengine-overview.html + // - https://doc.qt.io/qt-5/qtwebengine-features.html + // - QWebEngine debugging: + // - https://doc.qt.io/qt-5/qtwebengine-debugging.html#using-command-line-arguments + // - https://wiki.qt.io/QtWebEngine/ChromiumVersions + // - Chromium command line: + // - switches: + // - --disable-web-security + // - --allow-file-access-from-files + // - --no-sandbox + // - --user-data-dir + // - --single-process + // - --disable-site-isolation-trials + // - https://stackoverflow.com/questions/35432749/disable-web-security-in-chrome-48 + // ^ changes in required parameters with disable-web-security + +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) && (defined(__APPLE__) || defined(_WIN32)) char ARG_DISABLE_WEB_SECURITY[] = "--disable-web-security"; int newArgc = argc + 1 + 1; char** newArgv = new char*[static_cast(newArgc)]; @@ -172,79 +186,27 @@ int main(int argc, char* argv[]) newArgv[i] = argv[i-1]; } newArgv[newArgc-1] = nullptr; - #else - // IMPROVE: new Chromium @ QWebEngine requires more parameters, but - // I didn't find working configuration which would allow loading - // of images on macOS BigSur - char ARG_DISABLE_WEB_SECURITY[] = "--disable-web-security"; - char ARG_USER_DATA_DIR[] = "--user-data-dir=/Users/dvorka/tmp"; - char ARG_SINGLE_PROCESS[] = "--single-process"; - char ARG_NO_SANDBOX[] = "--no-sandbox"; - char ARG_DISABLE_ISOLATION_TRIALS[] = "--disable-site-isolation-trials"; - char ARG_ALLOW_FILE_ACCESS_FROM_FILES[] = "--allow-file-access-from-files"; - - #ifdef DEBUG_WEBENGINE_SECURITY_QT_5_15 - int newArgc = 6; - char** newArgv = new char*[static_cast(newArgc)]; - newArgv[0] = argv[0]; - newArgv[1] = "--args"; - newArgv[2] = ARG_USER_DATA_DIR; - newArgv[3] = ARG_DISABLE_WEB_SECURITY; - newArgv[4] = "/Users/dvorka/mf-devel/mf-copy"; - newArgv[5] = NULL; - - #else // DEBUG_WEBENGINE_SECURITY_QT_5_15 - char* injectWebEngineArgv[] = { - ARG_USER_DATA_DIR, - ARG_DISABLE_WEB_SECURITY, - ARG_DISABLE_ISOLATION_TRIALS, - ARG_SINGLE_PROCESS, - ARG_NO_SANDBOX, - ARG_ALLOW_FILE_ACCESS_FROM_FILES - }; - int injectWebEngineArgc = 6; - - int newArgc = argc + injectWebEngineArgc + 1; - char** newArgv = new char*[static_cast(newArgc)]; - newArgv[0] = argv[0]; - int i=1; - for (int v=0; v|]", QCoreApplication::translate( "main", - "MindForger repository or directory/file with Markdown(s) to open" + "MindForger workspace or directory/file with Markdown(s) to open" ) ); QCommandLineOption themeOption(QStringList() << "t" << "theme", @@ -274,8 +236,8 @@ int main(int argc, char* argv[]) ); parser.addOption(configPathOption); -#if defined(__APPLE__) || defined(_WIN32) - // command line options passed to WebEngine to disable security + #if defined(__APPLE__) || defined(_WIN32) + // command line options which might be passed to WebEngine to control the security QCommandLineOption macosDisableSecurityOption(QStringList() << "S" << "disable-web-security", QCoreApplication::translate("main", "Disable WebEngine security to allow loading of images on macOS.") ); @@ -304,8 +266,9 @@ int main(int argc, char* argv[]) QCoreApplication::translate("main", "Disable WebEngine security via acess file from file on macOS.") ); parser.addOption(macosAcessFileFromFile); - #endif -#endif + #endif // >= 5.15.0 + #endif // APPLE or WIN + QCommandLineOption versionOption=parser.addVersionOption(); QCommandLineOption helpOption=parser.addHelpOption(); // process the actual command line arguments given by the user @@ -338,11 +301,6 @@ int main(int argc, char* argv[]) } } // else there are no parameters and options > simply load GUI -# else // DEBUG_WEBENGINE_SECURITY_QT_5_15 - QString configurationFilePath{"/Users/dvorka/.mindforger.md"}; - QString themeOptionValue{}; - std::string useRepository{}; -#endif // DEBUG_WEBENGINE_SECURITY_QT_5_15 // load configuration m8r::MarkdownConfigurationRepresentation mdConfigRepresentation{}; @@ -366,7 +324,9 @@ int main(int argc, char* argv[]) m8r::MarkdownRepositoryConfigurationRepresentation mdRepositoryCfgRepresentation{}; if(!useRepository.empty()) { - m8r::Repository* r = m8r::RepositoryIndexer::getRepositoryForPath(useRepository); + m8r::Repository* r = m8r::RepositoryIndexer::getRepositoryForPath( + useRepository + ); if(r) { config.setActiveRepository( config.addRepository(r), mdRepositoryCfgRepresentation @@ -374,11 +334,13 @@ int main(int argc, char* argv[]) } else { if(config.createEmptyMarkdownFile(useRepository)) { r = m8r::RepositoryIndexer::getRepositoryForPath(useRepository); - config.setActiveRepository(config.addRepository(r), mdRepositoryCfgRepresentation); + config.setActiveRepository( + config.addRepository(r), mdRepositoryCfgRepresentation + ); } else { cerr << QCoreApplication::translate( "main", - "Error: Unable to find given repository/file " + "Error: Unable to find given workspace/file " "to open - open MindForger without parameters " "and create it from menu Mind/New: '" ).toUtf8().constData() @@ -515,6 +477,29 @@ int main(int argc, char* argv[]) } // mdConfigRepresentation->save(config); + // set application font family and size + // QFont font("Arial", 25); + // mindforgerApplication.setFont(font); + MF_DEBUG( + "Qt boot MindForger application font:" << endl << + " family: " << mindforgerApplication.font().family().toStdString() << endl << + " pixel size: " << mindforgerApplication.font().pixelSize() << endl << + " point size: " << mindforgerApplication.font().pointSize() << endl); + if(config.getUiAppFontSize()) { + MF_DEBUG("Setting application font size to: " << config.getUiAppFontSize() << endl); + QFont font( + mindforgerApplication.font().family(), + config.getUiAppFontSize() + ); + mindforgerApplication.setFont(font); + + MF_DEBUG( + "AFTER MindForger application font reconfiguration:" << endl << + " family: " << mindforgerApplication.font().family().toStdString() << endl << + " pixel size: " << mindforgerApplication.font().pixelSize() << endl << + " point size: " << mindforgerApplication.font().pointSize() << endl); + } + // initialize and start UI m8r::MainWindowView mainWindowView(lookAndFeels); m8r::MainWindowPresenter mainWindowPresenter(mainWindowView); diff --git a/app/src/qt/model_meta_definitions.h b/app/src/qt/model_meta_definitions.h index 6d581c8c..1e1d4e6e 100644 --- a/app/src/qt/model_meta_definitions.h +++ b/app/src/qt/model_meta_definitions.h @@ -1,7 +1,7 @@ /* model_meta_definitions.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/navigator/edge.cpp b/app/src/qt/navigator/edge.cpp index 8189800f..25605dcb 100644 --- a/app/src/qt/navigator/edge.cpp +++ b/app/src/qt/navigator/edge.cpp @@ -1,7 +1,7 @@ /* edge.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/navigator/edge.h b/app/src/qt/navigator/edge.h index 7f9ee39b..919f3152 100644 --- a/app/src/qt/navigator/edge.h +++ b/app/src/qt/navigator/edge.h @@ -1,7 +1,7 @@ /* edge.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/navigator/navigator_view.cpp b/app/src/qt/navigator/navigator_view.cpp index 10e53a45..67759f0c 100644 --- a/app/src/qt/navigator/navigator_view.cpp +++ b/app/src/qt/navigator/navigator_view.cpp @@ -1,7 +1,7 @@ /* mind-navigator.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/navigator/navigator_view.h b/app/src/qt/navigator/navigator_view.h index 3f7bfa61..b72d3447 100644 --- a/app/src/qt/navigator/navigator_view.h +++ b/app/src/qt/navigator/navigator_view.h @@ -1,7 +1,7 @@ /* mind_navigator.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -130,7 +130,7 @@ class NavigatorView : public QGraphicsView void itemMoved(); - void iWasSelected(NavigatorNode* selectedNode); + void iWasSelected(NavigatorNode* selectedNode); void refreshOnNextTimerTick(KnowledgeSubGraph* subgraph) { std::lock_guard criticalSection{refreshMutex}; diff --git a/app/src/qt/navigator/node.cpp b/app/src/qt/navigator/node.cpp index bdc7b9a6..6e17e75c 100644 --- a/app/src/qt/navigator/node.cpp +++ b/app/src/qt/navigator/node.cpp @@ -1,7 +1,7 @@ /* node.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/navigator/node.h b/app/src/qt/navigator/node.h index 45a4d6d4..4155dd2b 100644 --- a/app/src/qt/navigator/node.h +++ b/app/src/qt/navigator/node.h @@ -1,7 +1,7 @@ /* node.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/navigator_presenter.cpp b/app/src/qt/navigator_presenter.cpp index ba4018ac..c3fc29fe 100644 --- a/app/src/qt/navigator_presenter.cpp +++ b/app/src/qt/navigator_presenter.cpp @@ -1,7 +1,7 @@ /* navigator_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/navigator_presenter.h b/app/src/qt/navigator_presenter.h index d7a1abd2..f337a5ed 100644 --- a/app/src/qt/navigator_presenter.h +++ b/app/src/qt/navigator_presenter.h @@ -1,7 +1,7 @@ /* navigator_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/ner_leaderboard_model.cpp b/app/src/qt/ner_leaderboard_model.cpp deleted file mode 100644 index 3bc82cc0..00000000 --- a/app/src/qt/ner_leaderboard_model.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - ner_leaderboard_model.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "ner_leaderboard_model.h" - -namespace m8r { - -using namespace std; - -NerLeaderboardModel::NerLeaderboardModel(QWidget* parent) - : QStandardItemModel(parent) -{ - setColumnCount(3); - setRowCount(0); -} - -NerLeaderboardModel::~NerLeaderboardModel() -{ -} - -void NerLeaderboardModel::removeAllRows() -{ - QStandardItemModel::clear(); - - QStringList tableHeader; - tableHeader - << tr("Name") - << tr("Type") - << tr("Score"); - - // IMPROVE set tooltips: items w/ tooltips instead of just strings - setHorizontalHeaderLabels(tableHeader); -} - -void NerLeaderboardModel::addRow(string& entityName, NerNamedEntityType entityType, float score) -{ - QList items; - QStandardItem* item; - - QString html{}; - html += QString::fromStdString(entityName); - - // item - item = new QStandardItem(html); - item->setToolTip(html); - items += item; - - html.clear(); - switch(entityType) { - case NerNamedEntityType::PERSON: - html += tr("person"); - break; - case NerNamedEntityType::LOCATION: - html += tr("location"); - break; - case NerNamedEntityType::ORGANIZATION: - html += tr("organization"); - break; - case NerNamedEntityType::MISC: - html += tr("misc"); - break; - } - - item = new QStandardItem(html); - item->setToolTip(html); - items += item; - - html.clear(); - if(score>0.29) { - html += ""; - } - score = ROUND_FLOAT(score, 1000); - html += QString::number(score); - if(score>0.29) { - html += ""; - } - item = new QStandardItem(html); - item->setData(QVariant::fromValue(score)); - items += item; - - appendRow(items); -} - -} // m8r namespace diff --git a/app/src/qt/ner_leaderboard_model.h b/app/src/qt/ner_leaderboard_model.h deleted file mode 100644 index 10e9d27f..00000000 --- a/app/src/qt/ner_leaderboard_model.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - ner_leaderboard_model.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8RUI_NER_LEADERBOARD_MODEL_H -#define M8RUI_NER_LEADERBOARD_MODEL_H - -#include - -#include "../../../lib/src/mind/ai/nlp/ner_named_entity.h" -#include "../../../lib/src/gear/lang_utils.h" - -namespace m8r { - -class NerLeaderboardModel : public QStandardItemModel -{ - Q_OBJECT - -public: - explicit NerLeaderboardModel(QWidget* parent); - NerLeaderboardModel(const NerLeaderboardModel&) = delete; - NerLeaderboardModel(const NerLeaderboardModel&&) = delete; - NerLeaderboardModel &operator=(const NerLeaderboardModel&) = delete; - NerLeaderboardModel &operator=(const NerLeaderboardModel&&) = delete; - ~NerLeaderboardModel(); - - void removeAllRows(); - void addRow(std::string& entityName, NerNamedEntityType entityType, float score); -}; - -} -#endif // M8RUI_NER_LEADERBOARD_MODEL_H diff --git a/app/src/qt/ner_leaderboard_view.cpp b/app/src/qt/ner_leaderboard_view.cpp deleted file mode 100644 index 049bba9f..00000000 --- a/app/src/qt/ner_leaderboard_view.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - ner_leaderboard_view.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "ner_leaderboard_view.h" - -namespace m8r { - -NerLeaderboardView::NerLeaderboardView(QWidget* parent) - : QTableView(parent) -{ - verticalHeader()->setVisible(false); - // BEFARE this kills performance: verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - - // IMPORTANT this must b in constructors - causes CPU high consuption loop if in an event handler - verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); - - setSortingEnabled(true); - - setEditTriggers(QAbstractItemView::NoEditTriggers); - setSelectionBehavior(QAbstractItemView::SelectRows); - setSelectionMode(QAbstractItemView::SingleSelection); - - // ensure HTML cells rendering - HtmlDelegate* delegate = new HtmlDelegate(); - setItemDelegate(delegate); -} - -void NerLeaderboardView::resizeEvent(QResizeEvent* event) -{ - MF_DEBUG("NerLeaderboardView::resizeEvent " << event << std::endl); - - if(horizontalHeader()->length() > 0) { - // ensure that 1st column gets the remaining space from others - horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - } - verticalHeader()->setDefaultSectionSize(fontMetrics().height()*1.5); - - // type - this->setColumnWidth(1, this->fontMetrics().averageCharWidth()*15); - // % - this->setColumnWidth(2, this->fontMetrics().averageCharWidth()*12); - - QTableView::resizeEvent(event); -} - -} // m8r namespace diff --git a/app/src/qt/ner_leaderboard_view.h b/app/src/qt/ner_leaderboard_view.h deleted file mode 100644 index 01f2cfb4..00000000 --- a/app/src/qt/ner_leaderboard_view.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - ner_leaderboard_view.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8RUI_NER_LEADERBOARD_VIEW_H -#define M8RUI_NER_LEADERBOARD_VIEW_H - -#include - -#include "html_delegate.h" - -namespace m8r { - -class NerLeaderboardView : public QTableView -{ - Q_OBJECT - -public: - explicit NerLeaderboardView(QWidget* parent); - NerLeaderboardView(const NerLeaderboardView&) = delete; - NerLeaderboardView(const NerLeaderboardView&&) = delete; - NerLeaderboardView &operator=(const NerLeaderboardView&) = delete; - NerLeaderboardView &operator=(const NerLeaderboardView&&) = delete; - virtual ~NerLeaderboardView() override {} - - virtual void resizeEvent(QResizeEvent* event) override; -}; - -} -#endif // M8RUI_NER_LEADERBOARD_VIEW_H diff --git a/app/src/qt/ner_main_window_worker_thread.cpp b/app/src/qt/ner_main_window_worker_thread.cpp deleted file mode 100644 index f01ca207..00000000 --- a/app/src/qt/ner_main_window_worker_thread.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - ner_main_window_worker_thread.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "ner_main_window_worker_thread.h" - -namespace m8r { - -NerMainWindowWorkerThread::~NerMainWindowWorkerThread() -{ - delete progressDialog; -} - -void NerMainWindowWorkerThread::process() -{ - mind->recognizePersons(orloj->getOutlineView()->getCurrentOutline(), entityFilter, *result); - - progressDialog->hide(); - - MF_DEBUG("NER initialization and prediction WORKER finished" << endl); - emit finished(); -} - -} // m8r namespace diff --git a/app/src/qt/ner_main_window_worker_thread.h b/app/src/qt/ner_main_window_worker_thread.h deleted file mode 100644 index 9a99ac65..00000000 --- a/app/src/qt/ner_main_window_worker_thread.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - ner_main_window_worker_thread.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8RUI_NER_MAIN_WINDOW_WORKER_THREAD_H -#define M8RUI_NER_MAIN_WINDOW_WORKER_THREAD_H - -#include - -#include - -#include "orloj_presenter.h" - -namespace m8r { - -class OrlojPresenter; - -/** - * @brief NER worker thread class. - * - * IMPORTANT: remember that QThread subclassing is ANTIPATTERN - QThread is just envelope. - * - * IMPORTANT: NEVER allocate heap objects (using new) in the constructor of the QObject - * class as this allocation is then performed on the main thread and not on the - * new QThread instance, meaning that the newly created object is then owned by the - * main thread and not the QThread instance. This will make your code fail to work. - * Instead, allocate such resources in the main function slot such as process() in - * this case as when that is called the object will be on the new thread instance - * and thus it will own the resource. - */ -class NerMainWindowWorkerThread : public QObject -{ - Q_OBJECT - - // just (parent) thread handle allowing to delete it when worker finishes - QThread* thread; - - Mind* mind; - OrlojPresenter* orloj; - int entityFilter; - std::vector* result; - QDialog* progressDialog; - -public: - explicit NerMainWindowWorkerThread( - QThread* t, - Mind* m, - OrlojPresenter* o, - int f, - std::vector* r, - QDialog* d) - { - this->thread = t; - this->mind = m; - this->orloj = o; - this->entityFilter = f; - this->result = r; - this->progressDialog = d; - } - NerMainWindowWorkerThread(const NerMainWindowWorkerThread&) = delete; - NerMainWindowWorkerThread(const NerMainWindowWorkerThread&&) = delete; - NerMainWindowWorkerThread &operator=(const NerMainWindowWorkerThread&) = delete; - NerMainWindowWorkerThread &operator=(const NerMainWindowWorkerThread&&) = delete; - ~NerMainWindowWorkerThread(); - - std::vector* getResult() { return result; } - -public slots: - void process(); - -signals: - void finished(); - void error(QString error); -}; - -} -#endif // M8RUI_NER_MAIN_WINDOW_WORKER_THREAD_H diff --git a/app/src/qt/note_edit_highlighter.cpp b/app/src/qt/note_edit_highlighter.cpp index 51d2d857..c0f05b54 100644 --- a/app/src/qt/note_edit_highlighter.cpp +++ b/app/src/qt/note_edit_highlighter.cpp @@ -1,7 +1,7 @@ /* note_edit_highlighter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -65,7 +65,8 @@ NoteEditHighlighter::NoteEditHighlighter(QPlainTextEdit* noteEditorView) addRegex(UnorderedList, "^(:? )*[\\*\\+\\-] "); addRegex(OrderedList, "^(:? )*\\d\\d?\\. "); addRegex(TaskDoneItem, "^(:? )*[\\*\\+\\-] \\[x\\]"); - addRegex(TaskWipItem, "^(:? )*[\\*\\+\\-] \\[ \\]"); + addRegex(TaskWipItem, "^(:? )*[\\*\\+\\-] \\[w\\]"); + addRegex(TaskTodoItem, "^(:? )*[\\*\\+\\-] \\[ \\]"); // formats boldFormat.setForeground(lookAndFeels.getEditorBold()); @@ -80,6 +81,7 @@ NoteEditHighlighter::NoteEditHighlighter(QPlainTextEdit* noteEditorView) listFormat.setForeground(lookAndFeels.getEditorList()); taskDoneFormat.setForeground(lookAndFeels.getEditorTaskDone()); taskWipFormat.setForeground(lookAndFeels.getEditorTaskWip()); + taskTodoFormat.setForeground(lookAndFeels.getEditorTaskTodo()); codeBlockFormat.setForeground(lookAndFeels.getEditorCodeblock()); mathBlockFormat.setForeground(lookAndFeels.getEditorCodeblock()); @@ -205,6 +207,9 @@ void NoteEditHighlighter::highlightPatterns(const QString& text) case TaskDoneItem: setFormat(index, length, taskDoneFormat); break; + case TaskTodoItem: + setFormat(index, length, taskTodoFormat); + break; case TaskWipItem: setFormat(index, length, taskWipFormat); break; diff --git a/app/src/qt/note_edit_highlighter.h b/app/src/qt/note_edit_highlighter.h index 49c6b0c3..fa414560 100644 --- a/app/src/qt/note_edit_highlighter.h +++ b/app/src/qt/note_edit_highlighter.h @@ -1,7 +1,7 @@ /* note_edit_highlighter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -45,6 +45,7 @@ class NoteEditHighlighter : public QSyntaxHighlighter UnorderedList, TaskDoneItem, TaskWipItem, + TaskTodoItem, OrderedList, HtmlTag, @@ -79,6 +80,7 @@ class NoteEditHighlighter : public QSyntaxHighlighter QTextCharFormat listFormat; QTextCharFormat taskDoneFormat; QTextCharFormat taskWipFormat; + QTextCharFormat taskTodoFormat; QTextCharFormat codeBlockFormat; QTextCharFormat mathBlockFormat; diff --git a/app/src/qt/note_edit_presenter.cpp b/app/src/qt/note_edit_presenter.cpp index 6792b234..aa14756f 100644 --- a/app/src/qt/note_edit_presenter.cpp +++ b/app/src/qt/note_edit_presenter.cpp @@ -1,7 +1,7 @@ /* note_edit_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -63,7 +63,7 @@ void NoteEditPresenter::setNote(Note* note) string mdDescription{}; mwp->getMarkdownRepresentation()->toDescription(note, &mdDescription); - view->setNote(note, mdDescription); + view->setNote(note, mdDescription); } void NoteEditPresenter::slotKeyPressed() diff --git a/app/src/qt/note_edit_presenter.h b/app/src/qt/note_edit_presenter.h index 4b104b50..49cb2b14 100644 --- a/app/src/qt/note_edit_presenter.h +++ b/app/src/qt/note_edit_presenter.h @@ -1,7 +1,7 @@ /* note_edit_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/note_edit_view.cpp b/app/src/qt/note_edit_view.cpp index 77d39e10..1c2ff8e7 100644 --- a/app/src/qt/note_edit_view.cpp +++ b/app/src/qt/note_edit_view.cpp @@ -1,7 +1,7 @@ /* note_edit_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -42,16 +42,19 @@ NoteEditView::NoteEditView(QWidget* parent) // signals #ifdef __APPLE__ new QShortcut( - QKeySequence(Qt::CTRL+Qt::Key_L), + QKeySequence(Qt::CTRL+Qt::Key_D), this, SLOT(slotSaveAndCloseEditor())); #else + // TODO leak? new QShortcut( QKeySequence(Qt::ALT+Qt::Key_Left), this, SLOT(slotSaveAndCloseEditor())); #endif + // TODO leak? new QShortcut( QKeySequence(Qt::CTRL+Qt::Key_G), this, SLOT(slotCloseEditor())); + // TODO leak? new QShortcut( #if __APPLE__ QKeySequence(Qt::CTRL+Qt::Key_Return), @@ -59,6 +62,7 @@ NoteEditView::NoteEditView(QWidget* parent) QKeySequence(Qt::ALT+Qt::Key_Return), #endif this, SLOT(slotOpenNotePropertiesEditor())); + // TODO leak? new QShortcut( QKeySequence(Qt::CTRL+Qt::Key_S), this, SLOT(slotSaveNote())); diff --git a/app/src/qt/note_edit_view.h b/app/src/qt/note_edit_view.h index 54afb426..cbe9bdd5 100644 --- a/app/src/qt/note_edit_view.h +++ b/app/src/qt/note_edit_view.h @@ -1,7 +1,7 @@ /* note_edit_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/note_editor_view.cpp b/app/src/qt/note_editor_view.cpp index f15cd37e..90518ce1 100644 --- a/app/src/qt/note_editor_view.cpp +++ b/app/src/qt/note_editor_view.cpp @@ -1,7 +1,7 @@ /* note_editor_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -102,7 +102,7 @@ NoteEditorView::NoteEditorView(QWidget* parent) ); // shortcut signals new QShortcut( - QKeySequence(QKeySequence(Qt::CTRL+Qt::Key_Slash)), + QKeySequence(QKeySequence(Qt::CTRL+Qt::Key_L)), this, SLOT(slotStartLinkCompletion()) ); @@ -201,6 +201,26 @@ void NoteEditorView::dragMoveEvent(QDragMoveEvent* event) event->acceptProposedAction(); } +void NoteEditorView::replaceSelectedText(const std::string& text) +{ + QTextCursor cursor = textCursor(); + cursor.removeSelectedText(); + cursor.insertText(QString::fromStdString(text)); + setTextCursor(cursor); +} + +void NoteEditorView::appendAfterSelectedText(const std::string& phrase) +{ + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.insertText(" " + QString::fromStdString(phrase)); +} + +void NoteEditorView::appendAfterCursor(const std::string& phrase) +{ + textCursor().insertText(QString::fromStdString(phrase)); +} + /* * Formatting */ @@ -405,13 +425,15 @@ void NoteEditorView::keyPressEvent(QKeyEvent* event) break; } } else { - switch(event->key()) { + switch(event->key()) { case Qt::Key_Escape: { // completer menu not visible - exit editor ~ Cancel QMessageBox msgBox{ QMessageBox::Question, tr("Exit Editor"), - tr("Do you really want to exit editor without saving?") + tr("Do you really want to exit editor without saving?"), + {}, + parent }; QPushButton* yes = msgBox.addButton("&Yes", QMessageBox::YesRole); #ifdef __APPLE__ @@ -558,6 +580,29 @@ void NoteEditorView::performTextCompletion(const QString& completionPrefix) completer->complete(rect); } +/** + * @brief Get phrase to be used by a tool (arXiv, GPT, Wikipedia, ...) + * + * Either return selected text or word under the cursor. + * + * @return phrase text + */ +QString NoteEditorView::getToolPhrase() +{ + QString phrase{}; + + // if there is no selection, attempt to select the word under the cursor + if(textCursor().selectedText().size() == 0) { + // select the word under cursor + QTextCursor cursor = textCursor(); + cursor.select(QTextCursor::WordUnderCursor); + setTextCursor(cursor); + } + + // get PHRASE from selection + return QString{textCursor().selectedText()}; +} + void NoteEditorView::slotStartLinkCompletion() { const QString completionPrefix = getCompletionPrefix(); diff --git a/app/src/qt/note_editor_view.h b/app/src/qt/note_editor_view.h index 17a05c81..2d9c3eaf 100644 --- a/app/src/qt/note_editor_view.h +++ b/app/src/qt/note_editor_view.h @@ -1,7 +1,7 @@ /* note_editor_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -100,6 +100,9 @@ class NoteEditorView : public QPlainTextEdit // formatting QString getSelectedText() const { return textCursor().selectedText(); } + void replaceSelectedText(const std::string &text); + void appendAfterSelectedText(const std::string& phrase); + void appendAfterCursor(const std::string& phrase); void wrapSelectedText(const QString &tag) { wrapSelectedText(tag,""); } void wrapSelectedText(const QString &tag, const QString &endTag); void removeSelectedText() { textCursor().removeSelectedText(); } @@ -122,6 +125,9 @@ class NoteEditorView : public QPlainTextEdit void clearHitCounter() { hitCounter=0; } int getHitCounter() const { return hitCounter; } + // tools + QString getToolPhrase(); + // autocomplete protected: virtual void mousePressEvent(QMouseEvent* event) override; diff --git a/app/src/qt/note_smart_editor.cpp b/app/src/qt/note_smart_editor.cpp index f429e50b..20df1336 100644 --- a/app/src/qt/note_smart_editor.cpp +++ b/app/src/qt/note_smart_editor.cpp @@ -1,7 +1,7 @@ /* note_smart_editor.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -401,10 +401,18 @@ bool NoteSmartEditor::completePairChars(QKeyEvent* event) { textEdit.moveCursor(QTextCursor::PreviousCharacter); return true; */ - case Qt::Key_Underscore: - textEdit.textCursor().insertText("__"); - textEdit.moveCursor(QTextCursor::PreviousCharacter); - return true; + case Qt::Key_Underscore: { + // complete __ only if cursor is preceded by SPACE + QString lastChar = getLastChar(); + if(isAtTheBeginningOfLine() + || (lastChar.size() && lastChar[0] == ' ') + ) { + textEdit.textCursor().insertText("__"); + textEdit.moveCursor(QTextCursor::PreviousCharacter); + return true; + } + return false; + } case Qt::Key_AsciiTilde: textEdit.textCursor().insertText("~~"); textEdit.moveCursor(QTextCursor::PreviousCharacter); diff --git a/app/src/qt/note_smart_editor.h b/app/src/qt/note_smart_editor.h index f4eea43c..f5bc37b3 100644 --- a/app/src/qt/note_smart_editor.h +++ b/app/src/qt/note_smart_editor.h @@ -1,7 +1,7 @@ /* note_smart_editor.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/note_view.cpp b/app/src/qt/note_view.cpp index 0c0dbeec..a903dc4a 100644 --- a/app/src/qt/note_view.cpp +++ b/app/src/qt/note_view.cpp @@ -1,7 +1,7 @@ /* note_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/note_view.h b/app/src/qt/note_view.h index 17c8d2ba..f4cf5906 100644 --- a/app/src/qt/note_view.h +++ b/app/src/qt/note_view.h @@ -1,7 +1,7 @@ /* note_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -95,7 +95,12 @@ class NoteView : public QWidget void setZoomFactor(qreal factor) { noteViewer->setZoomFactor(factor); } + // IMPORTANT: file:// base URL is IMPORTANT for QtWebEngine to load local images on Qt >=5.12.0 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) && (defined(__APPLE__) || defined(_WIN32)) + void setHtml(const QString& html, const QUrl& baseUrl = QUrl("file://")) { +#else void setHtml(const QString& html, const QUrl& baseUrl = QUrl()) { +#endif noteViewer->setHtml(html, baseUrl); } void giveViewerFocus() { diff --git a/app/src/qt/note_view_model.cpp b/app/src/qt/note_view_model.cpp index c41c2171..bb4f02f1 100644 --- a/app/src/qt/note_view_model.cpp +++ b/app/src/qt/note_view_model.cpp @@ -1,7 +1,7 @@ /* note_view_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/note_view_model.h b/app/src/qt/note_view_model.h index 1b9bc117..8d655115 100644 --- a/app/src/qt/note_view_model.h +++ b/app/src/qt/note_view_model.h @@ -1,7 +1,7 @@ /* note_view_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/note_view_presenter.cpp b/app/src/qt/note_view_presenter.cpp index 1b9a3e52..4c1f7268 100644 --- a/app/src/qt/note_view_presenter.cpp +++ b/app/src/qt/note_view_presenter.cpp @@ -1,7 +1,7 @@ /* note_view_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -148,7 +148,7 @@ void NoteViewPresenter::slotLinkClicked(const QUrl& url) } void NoteViewPresenter::slotEditNote() -{ +{ orloj->showFacetNoteEdit(this->currentNote); } diff --git a/app/src/qt/note_view_presenter.h b/app/src/qt/note_view_presenter.h index 774ee67d..d5f6635a 100644 --- a/app/src/qt/note_view_presenter.h +++ b/app/src/qt/note_view_presenter.h @@ -1,7 +1,7 @@ /* note_view_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/notes_table_model.cpp b/app/src/qt/notes_table_model.cpp index 8bef420f..68518006 100644 --- a/app/src/qt/notes_table_model.cpp +++ b/app/src/qt/notes_table_model.cpp @@ -1,7 +1,7 @@ /* notes_table_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/notes_table_model.h b/app/src/qt/notes_table_model.h index 0cfe0d30..228d3fea 100644 --- a/app/src/qt/notes_table_model.h +++ b/app/src/qt/notes_table_model.h @@ -1,7 +1,7 @@ /* notes_table_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/notes_table_presenter.cpp b/app/src/qt/notes_table_presenter.cpp index 6837c921..eed8602d 100644 --- a/app/src/qt/notes_table_presenter.cpp +++ b/app/src/qt/notes_table_presenter.cpp @@ -1,7 +1,7 @@ /* notes_table_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/notes_table_presenter.h b/app/src/qt/notes_table_presenter.h index 33f40169..0a4588db 100644 --- a/app/src/qt/notes_table_presenter.h +++ b/app/src/qt/notes_table_presenter.h @@ -1,7 +1,7 @@ /* notes_table_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/notes_table_view.cpp b/app/src/qt/notes_table_view.cpp index c9569dee..85180b21 100644 --- a/app/src/qt/notes_table_view.cpp +++ b/app/src/qt/notes_table_view.cpp @@ -1,7 +1,7 @@ /* notes_table_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/notes_table_view.h b/app/src/qt/notes_table_view.h index 7a95d3e5..ec0aaeaa 100644 --- a/app/src/qt/notes_table_view.h +++ b/app/src/qt/notes_table_view.h @@ -1,7 +1,7 @@ /* notes_table_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_presenter.cpp b/app/src/qt/organizer_presenter.cpp index f07d24fd..545020c7 100644 --- a/app/src/qt/organizer_presenter.cpp +++ b/app/src/qt/organizer_presenter.cpp @@ -1,7 +1,7 @@ /* organizer_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_presenter.h b/app/src/qt/organizer_presenter.h index fcbcfd20..ee3b4b41 100644 --- a/app/src/qt/organizer_presenter.h +++ b/app/src/qt/organizer_presenter.h @@ -1,7 +1,7 @@ /* organizer_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_quadrant_model.cpp b/app/src/qt/organizer_quadrant_model.cpp index 3d106b48..ba978e7a 100644 --- a/app/src/qt/organizer_quadrant_model.cpp +++ b/app/src/qt/organizer_quadrant_model.cpp @@ -1,7 +1,7 @@ /* organizer_quadrant_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -93,7 +93,8 @@ void OrganizerQuadrantModel::addRow( // item item = new QStandardItem(html); item->setToolTip(html); - // TODO under which ROLE this is > I should declare CUSTOM role (user+1 as constant) + // TODO under which ROLE this is > I should declare CUSTOM role + // (user+1 as constant) item->setData(QVariant::fromValue(note)); items += item; } else { @@ -104,7 +105,8 @@ void OrganizerQuadrantModel::addRow( // item item = new QStandardItem(html); item->setToolTip(html); - // TODO under which ROLE this is > I should declare CUSTOM role (user+1 as constant) + // TODO under which ROLE this is > I should declare CUSTOM role + // (user+1 as constant) item->setData(QVariant::fromValue(note)); items += item; } diff --git a/app/src/qt/organizer_quadrant_model.h b/app/src/qt/organizer_quadrant_model.h index 3722012b..0f9201dc 100644 --- a/app/src/qt/organizer_quadrant_model.h +++ b/app/src/qt/organizer_quadrant_model.h @@ -1,7 +1,7 @@ /* organizer_quadrant_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_quadrant_presenter.cpp b/app/src/qt/organizer_quadrant_presenter.cpp index 848f2fbd..d8efbc24 100644 --- a/app/src/qt/organizer_quadrant_presenter.cpp +++ b/app/src/qt/organizer_quadrant_presenter.cpp @@ -1,7 +1,7 @@ /* organizer_quadrant_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -111,8 +111,9 @@ void OrganizerQuadrantPresenter::slotShowSelectedNote() } } -void OrganizerQuadrantPresenter::slotShowNote(const QItemSelection& selected, const QItemSelection& deselected) -{ +void OrganizerQuadrantPresenter::slotShowNote( + const QItemSelection& selected, const QItemSelection& deselected +) { Q_UNUSED(deselected); QModelIndexList indices = selected.indexes(); diff --git a/app/src/qt/organizer_quadrant_presenter.h b/app/src/qt/organizer_quadrant_presenter.h index 34443e23..dd9ccf30 100644 --- a/app/src/qt/organizer_quadrant_presenter.h +++ b/app/src/qt/organizer_quadrant_presenter.h @@ -1,7 +1,7 @@ /* organizer_quadrant_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_quadrant_view.cpp b/app/src/qt/organizer_quadrant_view.cpp index 77b81dda..1a60b9a7 100644 --- a/app/src/qt/organizer_quadrant_view.cpp +++ b/app/src/qt/organizer_quadrant_view.cpp @@ -1,7 +1,7 @@ /* organizer_quadrant_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_quadrant_view.h b/app/src/qt/organizer_quadrant_view.h index 8327695a..b7962ed0 100644 --- a/app/src/qt/organizer_quadrant_view.h +++ b/app/src/qt/organizer_quadrant_view.h @@ -1,7 +1,7 @@ /* organizer_quadrant_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_view.cpp b/app/src/qt/organizer_view.cpp index b00d8bc6..119ac3af 100644 --- a/app/src/qt/organizer_view.cpp +++ b/app/src/qt/organizer_view.cpp @@ -1,7 +1,7 @@ /* organizer_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizer_view.h b/app/src/qt/organizer_view.h index a4ac80e9..caadecdc 100644 --- a/app/src/qt/organizer_view.h +++ b/app/src/qt/organizer_view.h @@ -1,7 +1,7 @@ /* organizer_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizers_table_model.cpp b/app/src/qt/organizers_table_model.cpp index 6b0b4813..e5651041 100644 --- a/app/src/qt/organizers_table_model.cpp +++ b/app/src/qt/organizers_table_model.cpp @@ -1,7 +1,7 @@ /* organizers_table_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,7 +23,9 @@ namespace m8r { using namespace std; -OrganizersTableModel::OrganizersTableModel(QObject* parent, HtmlOutlineRepresentation* htmlRepresentation) +OrganizersTableModel::OrganizersTableModel( + QObject* parent, HtmlOutlineRepresentation* htmlRepresentation +) : QStandardItemModel(parent), htmlRepresentation(htmlRepresentation) { setColumnCount(1); diff --git a/app/src/qt/organizers_table_model.h b/app/src/qt/organizers_table_model.h index 286b36c8..668067e9 100644 --- a/app/src/qt/organizers_table_model.h +++ b/app/src/qt/organizers_table_model.h @@ -1,7 +1,7 @@ /* organizers_table_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -33,7 +33,9 @@ class OrganizersTableModel : public QStandardItemModel public: HtmlOutlineRepresentation* htmlRepresentation; - explicit OrganizersTableModel(QObject* parent, HtmlOutlineRepresentation* htmlRepresentation); + explicit OrganizersTableModel( + QObject* parent, HtmlOutlineRepresentation* htmlRepresentation + ); OrganizersTableModel(const OrganizersTableModel&) = delete; OrganizersTableModel(const OrganizersTableModel&&) = delete; OrganizersTableModel &operator=(const OrganizersTableModel&) = delete; diff --git a/app/src/qt/organizers_table_presenter.cpp b/app/src/qt/organizers_table_presenter.cpp index 5d8eaeea..4ba4f8a9 100644 --- a/app/src/qt/organizers_table_presenter.cpp +++ b/app/src/qt/organizers_table_presenter.cpp @@ -1,7 +1,7 @@ /* organizers_table_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,8 +22,9 @@ namespace m8r { using namespace std; -OrganizersTablePresenter::OrganizersTablePresenter(OrganizersTableView* view, HtmlOutlineRepresentation* htmlRepresentation) -{ +OrganizersTablePresenter::OrganizersTablePresenter( + OrganizersTableView* view, HtmlOutlineRepresentation* htmlRepresentation +) { this->view = view; this->model = new OrganizersTableModel(this, htmlRepresentation); this->view->setModel(this->model); diff --git a/app/src/qt/organizers_table_presenter.h b/app/src/qt/organizers_table_presenter.h index d40ac4df..89aa6d78 100644 --- a/app/src/qt/organizers_table_presenter.h +++ b/app/src/qt/organizers_table_presenter.h @@ -1,7 +1,7 @@ /* organizers_table_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -41,7 +41,9 @@ class OrganizersTablePresenter : public QObject static const int NO_ROW = -1; public: - explicit OrganizersTablePresenter(OrganizersTableView* view, HtmlOutlineRepresentation* htmlRepresentation); + explicit OrganizersTablePresenter( + OrganizersTableView* view, HtmlOutlineRepresentation* htmlRepresentation + ); OrganizersTablePresenter(const OrganizersTablePresenter&) = delete; OrganizersTablePresenter(const OrganizersTablePresenter&&) = delete; OrganizersTablePresenter &operator=(const OrganizersTablePresenter&) = delete; diff --git a/app/src/qt/organizers_table_view.cpp b/app/src/qt/organizers_table_view.cpp index eed75370..0a7b46e8 100644 --- a/app/src/qt/organizers_table_view.cpp +++ b/app/src/qt/organizers_table_view.cpp @@ -1,7 +1,7 @@ /* organizers_table_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/organizers_table_view.h b/app/src/qt/organizers_table_view.h index ba2815d1..0d2ea5ed 100644 --- a/app/src/qt/organizers_table_view.h +++ b/app/src/qt/organizers_table_view.h @@ -1,7 +1,7 @@ /* organizers_table_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/orloj_presenter.cpp b/app/src/qt/orloj_presenter.cpp index 90a64974..fb3f00f9 100644 --- a/app/src/qt/orloj_presenter.cpp +++ b/app/src/qt/orloj_presenter.cpp @@ -1,7 +1,7 @@ /* outline_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -24,23 +24,24 @@ using namespace std; namespace m8r { -OrlojPresenter::OrlojPresenter(MainWindowPresenter* mainPresenter, - OrlojView* view, - Mind* mind) - : activeFacet{OrlojPresenterFacets::FACET_NONE}, - config{Configuration::getInstance()}, - skipEditNoteCheck{false} +OrlojPresenter::OrlojPresenter( + MainWindowPresenter* mainPresenter, + OrlojView* view, + Mind* mind +) : activeFacet{OrlojPresenterFacets::FACET_NONE}, + config{Configuration::getInstance()}, + skipEditNoteCheck{false} { this->mainPresenter = mainPresenter; this->view = view; this->mind = mind; - this->dashboardPresenter = new DashboardPresenter(view->getDashboard(), this); this->organizersTablePresenter = new OrganizersTablePresenter(view->getOrganizersTable(), mainPresenter->getHtmlRepresentation()); this->organizerPresenter = new OrganizerPresenter(view->getOrganizer(), this); this->kanbanPresenter = new KanbanPresenter(view->getKanban(), this); this->tagCloudPresenter = new TagsTablePresenter(view->getTagCloud(), mainPresenter->getHtmlRepresentation()); this->outlinesTablePresenter = new OutlinesTablePresenter(view->getOutlinesTable(), mainPresenter->getHtmlRepresentation()); + this->outlinesMapPresenter = new OutlinesMapPresenter(view->getOutlinesMap(), mainPresenter, this); this->recentNotesTablePresenter = new RecentNotesTablePresenter(view->getRecentNotesTable(), mainPresenter->getHtmlRepresentation()); this->outlineViewPresenter = new OutlineViewPresenter(view->getOutlineView(), this); this->outlineHeaderViewPresenter = new OutlineHeaderViewPresenter(view->getOutlineHeaderView(), this); @@ -68,10 +69,10 @@ OrlojPresenter::OrlojPresenter(MainWindowPresenter* mainPresenter, this, SLOT(slotShowSelectedOutline())); QObject::connect( - view->getDashboard()->getOutlinesDashboardlet(), - SIGNAL(signalShowSelectedOutline()), + view->getOutlinesMapTable(), + SIGNAL(signalMapShowSelectedOutline()), this, - SLOT(slotShowSelectedOutline())); + SLOT(slotMapShowSelectedOutline())); QObject::connect( view->getOutlinesTable(), SIGNAL(signalFindOutlineByName()), @@ -89,22 +90,12 @@ OrlojPresenter::OrlojPresenter(MainWindowPresenter* mainPresenter, SIGNAL(signalShowSelectedRecentNote()), this, SLOT(slotShowSelectedRecentNote())); - QObject::connect( - view->getDashboard()->getRecentDashboardlet(), - SIGNAL(signalShowSelectedRecentNote()), - this, - SLOT(slotShowSelectedRecentNote())); // hit ENTER in Tags to view Recall by Tag detail QObject::connect( view->getTagCloud(), SIGNAL(signalShowDialogForTag()), this, SLOT(slotShowSelectedTagRecallDialog())); - QObject::connect( - view->getDashboard()->getTagsDashboardlet(), - SIGNAL(signalShowDialogForTag()), - this, - SLOT(slotShowSelectedTagRecallDialog())); // navigator QObject::connect( navigatorPresenter, SIGNAL(signalOutlineSelected(Outline*)), @@ -123,44 +114,85 @@ OrlojPresenter::OrlojPresenter(MainWindowPresenter* mainPresenter, #endif // editor getting data from the backend QObject::connect( - view->getNoteEdit()->getNoteEditor(), SIGNAL(signalGetLinksForPattern(QString)), - this, SLOT(slotGetLinksForPattern(QString))); + view->getNoteEdit()->getNoteEditor(), + SIGNAL(signalGetLinksForPattern(QString)), + this, + SLOT(slotGetLinksForPattern(QString))); QObject::connect( - this, SIGNAL(signalLinksForPattern(QString, std::vector*)), - view->getNoteEdit()->getNoteEditor(), SLOT(slotPerformLinkCompletion(QString, std::vector*))); + this, + SIGNAL(signalLinksForPattern(QString, std::vector*)), + view->getNoteEdit()->getNoteEditor(), + SLOT(slotPerformLinkCompletion(QString, std::vector*))); QObject::connect( - view->getOutlineHeaderEdit()->getHeaderEditor(), SIGNAL(signalGetLinksForPattern(QString)), - this, SLOT(slotGetLinksForPattern(QString))); + view->getOutlineHeaderEdit()->getHeaderEditor(), + SIGNAL(signalGetLinksForPattern(QString)), + this, + SLOT(slotGetLinksForPattern(QString))); QObject::connect( - this, SIGNAL(signalLinksForHeaderPattern(QString, std::vector*)), - view->getOutlineHeaderEdit()->getHeaderEditor(), SLOT(slotPerformLinkCompletion(QString, std::vector*))); + this, + SIGNAL(signalLinksForHeaderPattern(QString, std::vector*)), + view->getOutlineHeaderEdit()->getHeaderEditor(), + SLOT(slotPerformLinkCompletion(QString, std::vector*))); QObject::connect( - outlineHeaderEditPresenter->getView()->getButtonsPanel(), SIGNAL(signalShowLivePreview()), - mainPresenter, SLOT(doActionToggleLiveNotePreview())); + outlineHeaderEditPresenter->getView()->getButtonsPanel(), + SIGNAL(signalShowLivePreview()), + mainPresenter, + SLOT(doActionToggleLiveNotePreview())); QObject::connect( - noteEditPresenter->getView()->getButtonsPanel(), SIGNAL(signalShowLivePreview()), - mainPresenter, SLOT(doActionToggleLiveNotePreview())); + noteEditPresenter->getView()->getButtonsPanel(), + SIGNAL(signalShowLivePreview()), + mainPresenter, + SLOT(doActionToggleLiveNotePreview())); // intercept Os table column sorting QObject::connect( - view->getOutlinesTable()->horizontalHeader(), SIGNAL(sectionClicked(int)), - this, SLOT(slotOutlinesTableSorted(int))); + view->getOutlinesTable()->horizontalHeader(), + SIGNAL(sectionClicked(int)), + this, + SLOT(slotOutlinesTableSorted(int))); // toggle full O HTML preview QObject::connect( - view->getOutlineHeaderView()->getEditPanel()->getFullOPreviewButton(), SIGNAL(clicked()), - this, SLOT(slotToggleFullOutlinePreview())); + view->getOutlineHeaderView()->getEditPanel()->getFullOPreviewButton(), + SIGNAL(clicked()), + this, + SLOT(slotToggleFullOutlinePreview())); + // ^ and v @ O header/N view panel + QObject::connect( + view->getOutlineHeaderView()->getEditPanel()->getNextNoteButton(), + SIGNAL(clicked()), + outlineViewPresenter->getOutlineTree(), + SLOT(slotSelectPreviousRow())); + QObject::connect( + view->getOutlineHeaderView()->getEditPanel()->getLastNoteButton(), + SIGNAL(clicked()), + outlineViewPresenter->getOutlineTree(), + SLOT(slotSelectNextRow())); + QObject::connect( + view->getNoteView()->getButtonsPanel()->getNextNoteButton(), + SIGNAL(clicked()), + outlineViewPresenter->getOutlineTree(), + SLOT(slotSelectPreviousRow())); + QObject::connect( + view->getNoteView()->getButtonsPanel()->getLastNoteButton(), + SIGNAL(clicked()), + outlineViewPresenter->getOutlineTree(), + SLOT(slotSelectNextRow())); // show O header @ N QObject::connect( - view->getNoteView()->getButtonsPanel()->getShowOutlineHeaderButton(), SIGNAL(clicked()), - this, SLOT(slotShowOutlineHeader())); + view->getNoteView()->getButtonsPanel()->getShowOutlineHeaderButton(), + SIGNAL(clicked()), + this, + SLOT(slotShowOutlineHeader())); } -int dialogSaveOrCancel() +int dialogSaveOrCancel(QWidget* view) { // l10n by moving this dialog either to Qt class OR view class QMessageBox msgBox{ QMessageBox::Question, QObject::tr("Save Note"), - QObject::tr("Do you want to save changes?") + QObject::tr("Do you want to save changes?"), + {}, + view }; QPushButton* discard = msgBox.addButton( @@ -231,26 +263,6 @@ void OrlojPresenter::showFacetRecentNotes(const vector& notes) mainPresenter->getStatusBar()->showMindStatistics(); } -void OrlojPresenter::showFacetDashboard() { - setFacet(OrlojPresenterFacets::FACET_DASHBOARD); - - vector allNotes{}; - mind->getAllNotes(allNotes, true, true); - map allTags{}; - mind->getTagsCardinality(allTags); - - dashboardPresenter->refresh( - mind->getOutlines(), - allNotes, - allTags, - mind->remind().getOutlineMarkdownsSize(), - mind->getStatistics() - ); - view->showFacetDashboard(); - mainPresenter->getMainMenu()->showFacetDashboard(); - mainPresenter->getStatusBar()->showMindStatistics(); -} - void OrlojPresenter::showFacetOrganizerList(const vector& organizers) { setFacet(OrlojPresenterFacets::FACET_LIST_ORGANIZERS); @@ -348,6 +360,25 @@ void OrlojPresenter::showFacetOutlineList(const vector& outlines) mainPresenter->getStatusBar()->showMindStatistics(); } +void OrlojPresenter::showFacetOutlinesMap(Outline* outlinesMap) +{ + setFacet(OrlojPresenterFacets::FACET_MAP_OUTLINES); + outlinesMapPresenter->refresh(outlinesMap); + view->showFacetOutlinesMap(); + mainPresenter->getMainMenu()->showFacetOutlinesMap(); + mainPresenter->getStatusBar()->showMindStatistics(); + + // give focus to the component + auto componentView = view->getOutlinesMapTable(); + componentView->setFocus(); + // give focus to the first row in the view + if(componentView->model()->rowCount() > 0) { + componentView->setCurrentIndex( + componentView->model()->index(0, 0) + ); + } +} + void OrlojPresenter::slotShowOutlines() { showFacetOutlineList(mind->getOutlines()); @@ -445,6 +476,40 @@ void OrlojPresenter::showFacetOutline(Outline* outline) mainPresenter->getStatusBar()->showInfo(QString("Notebook '%1' %2").arg(outline->getName().c_str()).arg(outline->getKey().c_str())); } +void OrlojPresenter::slotMapShowSelectedOutline() +{ + MF_DEBUG(" -> signal HANDLER @ OrlojPresenter: show O " << activeFacet << std::endl); + if(activeFacet == OrlojPresenterFacets::FACET_MAP_OUTLINES){ + int row = outlinesMapPresenter->getCurrentRow(); + MF_DEBUG(" current row: " << row << std::endl); + if(row != OutlinesTablePresenter::NO_ROW) { + QStandardItem* item = outlinesMapPresenter->getModel()->item(row); + MF_DEBUG(" Item: " << item << std::endl); + if(item) { + Note* noteForOutline = item->data(Qt::UserRole + 1).value(); + MF_DEBUG(" N for O: " << noteForOutline << endl); + if(noteForOutline + && noteForOutline->getLinks().size() > 0 + && noteForOutline->getLinks().at(0)->getUrl().size() > 0 + ) { + MF_DEBUG(" Getting O: " << noteForOutline->getLinks().at(0)->getUrl() << endl); + Outline* outline = mind->remind().getOutline(noteForOutline->getLinks().at(0)->getUrl()); + if(outline) { + showFacetOutline(outline); + return; + } else { + mainPresenter->getStatusBar()->showInfo(QString(tr("Selected Notebook not found!"))); + } + } + return; + } else { + mainPresenter->getStatusBar()->showInfo(QString(tr("Selected Notebook not found!"))); + } + } + mainPresenter->getStatusBar()->showInfo(QString(tr("No Notebook selected!"))); + } +} + void OrlojPresenter::slotShowSelectedOutline() { if(activeFacet!=OrlojPresenterFacets::FACET_ORGANIZER @@ -456,19 +521,9 @@ void OrlojPresenter::slotShowSelectedOutline() activeFacet!=OrlojPresenterFacets::FACET_RECENT_NOTES ) { - int row; - if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) { - row = dashboardPresenter->getOutlinesPresenter()->getCurrentRow(); - } else { - row = outlinesTablePresenter->getCurrentRow(); - } + int row = outlinesTablePresenter->getCurrentRow(); if(row != OutlinesTablePresenter::NO_ROW) { - QStandardItem* item; - if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) { - item = dashboardPresenter->getOutlinesPresenter()->getModel()->item(row); - } else { - item = outlinesTablePresenter->getModel()->item(row); - } + QStandardItem* item = outlinesTablePresenter->getModel()->item(row); // TODO introduce name my user role - replace constant with my enum name > do it for whole file e.g. MfDataRole if(item) { Outline* outline = item->data(Qt::UserRole + 1).value(); @@ -523,26 +578,14 @@ void OrlojPresenter::showFacetTagCloud() void OrlojPresenter::slotShowSelectedTagRecallDialog() { - if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD - || - activeFacet == OrlojPresenterFacets::FACET_DASHBOARD - ) - { - int row; - if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) { - row = dashboardPresenter->getTagsPresenter()->getCurrentRow(); - } else { - row = tagCloudPresenter->getCurrentRow(); - } + if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD) { + int row = tagCloudPresenter->getCurrentRow(); if(row != OutlinesTablePresenter::NO_ROW) { QStandardItem* item; switch(activeFacet) { case OrlojPresenterFacets::FACET_TAG_CLOUD: item = tagCloudPresenter->getModel()->item(row); break; - case OrlojPresenterFacets::FACET_DASHBOARD: - item = dashboardPresenter->getTagsPresenter()->getModel()->item(row); - break; default: item = nullptr; } @@ -563,21 +606,11 @@ void OrlojPresenter::slotShowTagRecallDialog(const QItemSelection& selected, con { Q_UNUSED(deselected); - if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD - || - activeFacet == OrlojPresenterFacets::FACET_DASHBOARD - ) - { + if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD) { QModelIndexList indices = selected.indexes(); if(indices.size()) { const QModelIndex& index = indices.at(0); - QStandardItem* item; - // TODO if 2 switch - if(activeFacet == OrlojPresenterFacets::FACET_TAG_CLOUD) { - item = tagCloudPresenter->getModel()->itemFromIndex(index); - } else { - item = dashboardPresenter->getTagsPresenter()->getModel()->itemFromIndex(index); - } + QStandardItem* item = tagCloudPresenter->getModel()->itemFromIndex(index); // TODO introduce name my user role - replace constant with my enum name > do it for whole file e.g. MfDataRole const Tag* tag = item->data(Qt::UserRole + 1).value(); mainPresenter->doTriggerFindNoteByTag(tag); @@ -750,7 +783,7 @@ bool OrlojPresenter::avoidDataLossOnNoteEdit() if(Configuration::getInstance().isUiEditorAutosave()) { decision = OrlojButtonRoles::SAVE_ROLE; } else { - decision = dialogSaveOrCancel(); + decision = dialogSaveOrCancel(view); } switch(decision) { @@ -774,7 +807,7 @@ bool OrlojPresenter::avoidDataLossOnNoteEdit() return true; } } else if(activeFacet == OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER) { - int decision = dialogSaveOrCancel(); + int decision = dialogSaveOrCancel(view); switch(decision) { case OrlojButtonRoles::DISCARD_ROLE: // do nothing @@ -895,26 +928,14 @@ void OrlojPresenter::slotGetLinksForPattern(const QString& pattern) void OrlojPresenter::slotShowSelectedRecentNote() { - if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES - || - activeFacet == OrlojPresenterFacets::FACET_DASHBOARD - ) - { - int row; - if(activeFacet==OrlojPresenterFacets::FACET_DASHBOARD) { - row = dashboardPresenter->getRecentNotesPresenter()->getCurrentRow(); - } else { - row = recentNotesTablePresenter->getCurrentRow(); - } + if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES) { + int row = recentNotesTablePresenter->getCurrentRow(); if(row != RecentNotesTablePresenter::NO_ROW) { QStandardItem* item; switch(activeFacet) { case OrlojPresenterFacets::FACET_RECENT_NOTES: item = recentNotesTablePresenter->getModel()->item(row); break; - case OrlojPresenterFacets::FACET_DASHBOARD: - item = dashboardPresenter->getRecentNotesPresenter()->getModel()->item(row); - break; default: item = nullptr; } @@ -942,20 +963,11 @@ void OrlojPresenter::slotShowRecentNote(const QItemSelection& selected, const QI { Q_UNUSED(deselected); - if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES - || - activeFacet == OrlojPresenterFacets::FACET_DASHBOARD - ) - { + if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES) { QModelIndexList indices = selected.indexes(); if(indices.size()) { const QModelIndex& index = indices.at(0); - QStandardItem* item; - if(activeFacet == OrlojPresenterFacets::FACET_RECENT_NOTES) { - item = recentNotesTablePresenter->getModel()->itemFromIndex(index); - } else { - item = dashboardPresenter->getRecentNotesPresenter()->getModel()->itemFromIndex(index); - } + QStandardItem* item = recentNotesTablePresenter->getModel()->itemFromIndex(index); // TODO make my role constant const Note* note = item->data(Qt::UserRole + 1).value(); diff --git a/app/src/qt/orloj_presenter.h b/app/src/qt/orloj_presenter.h index 6119cc16..b46edf57 100644 --- a/app/src/qt/orloj_presenter.h +++ b/app/src/qt/orloj_presenter.h @@ -1,7 +1,7 @@ /* outline_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,7 +27,6 @@ #include #include "orloj_view.h" -#include "dashboard_presenter.h" #include "organizers_table_presenter.h" #include "organizer_presenter.h" #include "kanban_presenter.h" @@ -35,6 +34,7 @@ #include "recent_notes_table_presenter.h" #include "main_window_presenter.h" #include "outlines_table_presenter.h" +#include "outlines_map_presenter.h" #include "notes_table_presenter.h" #include "outline_view_presenter.h" #include "outline_header_view_presenter.h" @@ -45,7 +45,6 @@ namespace m8r { -class DashboardPresenter; class OrganizersTablePresenter; class OrganizerPresenter; class KanbanPresenter; @@ -56,6 +55,7 @@ class NoteEditPresenter; class OutlineHeaderViewPresenter; class OutlineHeaderEditPresenter; class OutlineViewPresenter; +class OutlinesMapPresenter; class OrlojView; enum OrlojPresenterFacets { @@ -71,9 +71,9 @@ enum OrlojPresenterFacets { FACET_TAG_CLOUD, // 9 FACET_RECENT_NOTES, // 10 FACET_NAVIGATOR, // 11 - FACET_DASHBOARD, // 12 - FACET_LIST_ORGANIZERS, // 13 - FACET_KANBAN // 14 + FACET_LIST_ORGANIZERS, // 12 + FACET_KANBAN, // 13 + FACET_MAP_OUTLINES // 14 }; // aspect modifies facet @@ -107,12 +107,12 @@ class OrlojPresenter : public QObject Configuration& config; Mind* mind; - DashboardPresenter* dashboardPresenter; OrganizersTablePresenter* organizersTablePresenter; OrganizerPresenter* organizerPresenter; KanbanPresenter* kanbanPresenter; TagsTablePresenter* tagCloudPresenter; OutlinesTablePresenter* outlinesTablePresenter; + OutlinesMapPresenter* outlinesMapPresenter; RecentNotesTablePresenter* recentNotesTablePresenter; OutlineViewPresenter* outlineViewPresenter; OutlineHeaderViewPresenter* outlineHeaderViewPresenter; @@ -132,12 +132,12 @@ class OrlojPresenter : public QObject Mind* getMind() { return mind; } OrlojView* getView() const { return view; } - DashboardPresenter* getDashboard() const { return dashboardPresenter; } OrganizerPresenter* getOrganizer() const { return organizerPresenter; } KanbanPresenter* getKanban() const { return kanbanPresenter; } NavigatorPresenter* getNavigator() const { return navigatorPresenter; } MainWindowPresenter* getMainPresenter() const { return mainPresenter; } OutlinesTablePresenter* getOutlinesTable() const { return outlinesTablePresenter; } + OutlinesMapPresenter* getOutlinesMap() const { return outlinesMapPresenter; } RecentNotesTablePresenter* getRecentNotesTable() const { return recentNotesTablePresenter; } OutlineViewPresenter* getOutlineView() const { return outlineViewPresenter; } OutlineHeaderViewPresenter* getOutlineHeaderView() const { return outlineHeaderViewPresenter; } @@ -184,7 +184,6 @@ class OrlojPresenter : public QObject */ void onFacetChange(const OrlojPresenterFacets targetFacet) const; - void showFacetDashboard(); void showFacetOrganizerList(const std::vector& organizers); void showFacetEisenhowerMatrix( Organizer* organizer, @@ -200,6 +199,7 @@ class OrlojPresenter : public QObject ); void showFacetTagCloud(); void showFacetOutlineList(const std::vector& outlines); + void showFacetOutlinesMap(Outline* outlinesMap); void showFacetRecentNotes(const std::vector& notes); void showFacetKnowledgeGraphNavigator(); void showFacetFtsResult(std::vector* result); @@ -222,6 +222,7 @@ public slots: void slotShowSelectedOrganizer(); void slotShowOutlines(); void slotShowSelectedOutline(); + void slotMapShowSelectedOutline(); void slotShowOutline(const QItemSelection& selected, const QItemSelection& deselected); void slotShowOutlineHeader(); void slotShowNote(const QItemSelection& selected, const QItemSelection& deselected); diff --git a/app/src/qt/orloj_view.cpp b/app/src/qt/orloj_view.cpp index c5d39a03..4ebcdc07 100644 --- a/app/src/qt/orloj_view.cpp +++ b/app/src/qt/orloj_view.cpp @@ -1,7 +1,7 @@ /* orloj_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -25,9 +25,6 @@ using namespace std; OrlojView::OrlojView(QWidget* parent) : QSplitter(Qt::Horizontal, parent) { - dashboard = new DashboardView(this); - addWidget(dashboard); - organizersTable = new OrganizersTableView(this); addWidget(organizersTable); @@ -43,6 +40,9 @@ OrlojView::OrlojView(QWidget* parent) outlinesTable = new OutlinesTableView(this); addWidget(outlinesTable); + outlinesMap = new OutlinesMapView(this); + addWidget(outlinesMap); + recentNotesTable = new RecentNotesTableView(this); addWidget(recentNotesTable); @@ -97,12 +97,6 @@ void OrlojView::fiftyFifty() setSizes(sizes); } -void OrlojView::showFacetDashboard() -{ - QSet v; v << dashboard; - hideChildren(v); -} - void OrlojView::showFacetOrganizers() { QSet v; v << organizersTable; @@ -133,6 +127,12 @@ void OrlojView::showFacetOutlines() hideChildren(v); } +void OrlojView::showFacetOutlinesMap() +{ + QSet v; v << outlinesMap; + hideChildren(v); +} + void OrlojView::showFacetOutlinesDetail() { QSet v; v << outlinesTable << outlineView; diff --git a/app/src/qt/orloj_view.h b/app/src/qt/orloj_view.h index 236584d6..fe5c90f0 100644 --- a/app/src/qt/orloj_view.h +++ b/app/src/qt/orloj_view.h @@ -1,7 +1,7 @@ /* orloj_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,12 +21,12 @@ #include -#include "dashboard_view.h" #include "organizers_table_view.h" #include "organizer_view.h" #include "kanban_view.h" #include "tags_table_view.h" #include "outlines_table_view.h" +#include "outlines_map_view.h" #include "notes_table_view.h" #include "recent_notes_table_view.h" #include "outline_view_splitter.h" @@ -61,12 +61,12 @@ class OrlojView : public QSplitter Q_OBJECT private: - DashboardView* dashboard; OrganizersTableView* organizersTable; OrganizerView* organizer; KanbanView* kanban; TagsTableView* tagCloud; OutlinesTableView* outlinesTable; + OutlinesMapView* outlinesMap; RecentNotesTableView* recentNotesTable; OutlineViewSplitter* outlineView; OutlineHeaderView* outlineHeaderView; @@ -85,12 +85,13 @@ class OrlojView : public QSplitter OrlojView &operator=(const OrlojView&&) = delete; virtual ~OrlojView() {}; - DashboardView* getDashboard() const { return dashboard; } OrganizerView* getOrganizer() const { return organizer; } OrganizersTableView* getOrganizersTable() const { return organizersTable; } KanbanView* getKanban() const { return kanban; } TagsTableView* getTagCloud() const { return tagCloud; } OutlinesTableView* getOutlinesTable() const { return outlinesTable; } + OutlinesMapView* getOutlinesMapTable() const { return outlinesMap; } + OutlinesMapView* getOutlinesMap() const { return outlinesMap; } RecentNotesTableView* getRecentNotesTable() const { return recentNotesTable; } OutlineViewSplitter* getOutlineView() const { return outlineView; } OutlineHeaderView* getOutlineHeaderView() const { return outlineHeaderView; } @@ -101,11 +102,6 @@ class OrlojView : public QSplitter void setMainMenu(MainMenuView* menuView) { this->menuView=menuView; } - /** - * @brief Dashboard - */ - void showFacetDashboard(); - /** * @brief List of Organizers */ @@ -131,6 +127,11 @@ class OrlojView : public QSplitter */ void showFacetOutlines(); + /** + * @brief Tree of Outlines + */ + void showFacetOutlinesMap(); + /** * @brief Outline detail: name and tree of Notes */ diff --git a/app/src/qt/outline_header_edit_presenter.cpp b/app/src/qt/outline_header_edit_presenter.cpp index d556fddd..e0307bbc 100644 --- a/app/src/qt/outline_header_edit_presenter.cpp +++ b/app/src/qt/outline_header_edit_presenter.cpp @@ -1,7 +1,7 @@ /* outline_header_edit_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_header_edit_presenter.h b/app/src/qt/outline_header_edit_presenter.h index 6b6a2691..442a52a3 100644 --- a/app/src/qt/outline_header_edit_presenter.h +++ b/app/src/qt/outline_header_edit_presenter.h @@ -1,7 +1,7 @@ /* outline_header_edit_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_header_edit_view.cpp b/app/src/qt/outline_header_edit_view.cpp index 8b7d8fff..cb032cea 100644 --- a/app/src/qt/outline_header_edit_view.cpp +++ b/app/src/qt/outline_header_edit_view.cpp @@ -1,7 +1,7 @@ /* outline_header_edit_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -40,7 +40,7 @@ OutlineHeaderEditView::OutlineHeaderEditView(QWidget* parent) // signals #ifdef __APPLE__ new QShortcut( - QKeySequence(Qt::CTRL+Qt::Key_L), + QKeySequence(Qt::CTRL+Qt::Key_D), this, SLOT(slotSaveAndCloseEditor())); #else new QShortcut( @@ -59,7 +59,7 @@ OutlineHeaderEditView::OutlineHeaderEditView(QWidget* parent) this, SLOT(slotOpenOutlineHeaderPropertiesEditor())); new QShortcut( QKeySequence(Qt::CTRL+Qt::Key_S), - this, SLOT(slotSaveOutlineHeader())); + this, SLOT(slotSaveOutlineHeader())); QObject::connect( bottomButtonsPanel->getRememberButton(), SIGNAL(clicked()), this, SLOT(slotSaveOutlineHeader())); diff --git a/app/src/qt/outline_header_edit_view.h b/app/src/qt/outline_header_edit_view.h index c62082b7..d6cf9720 100644 --- a/app/src/qt/outline_header_edit_view.h +++ b/app/src/qt/outline_header_edit_view.h @@ -1,7 +1,7 @@ /* outline_header_edit_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_header_view.cpp b/app/src/qt/outline_header_view.cpp index 3d5a0896..89156333 100644 --- a/app/src/qt/outline_header_view.cpp +++ b/app/src/qt/outline_header_view.cpp @@ -1,7 +1,7 @@ /* outline_header_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_header_view.h b/app/src/qt/outline_header_view.h index fd8a38f7..fa12b57d 100644 --- a/app/src/qt/outline_header_view.h +++ b/app/src/qt/outline_header_view.h @@ -1,7 +1,7 @@ /* outline_header_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -96,7 +96,11 @@ class OutlineHeaderView : public QWidget void setZoomFactor(qreal factor) { headerViewer->setZoomFactor(factor); } +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) && (defined(__APPLE__) || defined(_WIN32)) + void setHtml(const QString& html, const QUrl& baseUrl = QUrl("file://")) { +#else void setHtml(const QString& html, const QUrl& baseUrl = QUrl()) { +#endif headerViewer->setHtml(html, baseUrl); } void giveViewerFocus() { diff --git a/app/src/qt/outline_header_view_model.cpp b/app/src/qt/outline_header_view_model.cpp index 5861230b..7f9a2008 100644 --- a/app/src/qt/outline_header_view_model.cpp +++ b/app/src/qt/outline_header_view_model.cpp @@ -1,7 +1,7 @@ /* outline_header_view_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_header_view_model.h b/app/src/qt/outline_header_view_model.h index 6e424fe3..900e945b 100644 --- a/app/src/qt/outline_header_view_model.h +++ b/app/src/qt/outline_header_view_model.h @@ -1,7 +1,7 @@ /* outline_header_view_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_header_view_presenter.cpp b/app/src/qt/outline_header_view_presenter.cpp index 3b8b8e51..895818de 100644 --- a/app/src/qt/outline_header_view_presenter.cpp +++ b/app/src/qt/outline_header_view_presenter.cpp @@ -1,7 +1,7 @@ /* outline_header_view_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -156,8 +156,9 @@ void OutlineHeaderViewPresenter::slotEditOutlineHeaderDoubleClick() } } -void OutlineHeaderViewPresenter::slotRefreshHeaderLeaderboardByValue(AssociatedNotes* associations) -{ +void OutlineHeaderViewPresenter::slotRefreshHeaderLeaderboardByValue( + AssociatedNotes* associations +) { if(orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE_HEADER) || orloj->isFacetActive(OrlojPresenterFacets::FACET_VIEW_OUTLINE) diff --git a/app/src/qt/outline_header_view_presenter.h b/app/src/qt/outline_header_view_presenter.h index 437028cf..790d729b 100644 --- a/app/src/qt/outline_header_view_presenter.h +++ b/app/src/qt/outline_header_view_presenter.h @@ -1,7 +1,7 @@ /* outline_header_view_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_tree_model.cpp b/app/src/qt/outline_tree_model.cpp index 9be45de6..a68be6fe 100644 --- a/app/src/qt/outline_tree_model.cpp +++ b/app/src/qt/outline_tree_model.cpp @@ -1,7 +1,7 @@ /* outline_tree_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -39,7 +39,7 @@ void OutlineTreeModel::removeAllRows() QStringList tableHeader; tableHeader - << tr("Outline") // tree of Notes is in fact Notebook's outline + << tr("Notebook Outline") // tree of Notes is in fact Notebook's outline << tr("Done") << tr("Rs") << tr("Ws") diff --git a/app/src/qt/outline_tree_model.h b/app/src/qt/outline_tree_model.h index 43affd86..1a71c301 100644 --- a/app/src/qt/outline_tree_model.h +++ b/app/src/qt/outline_tree_model.h @@ -1,7 +1,7 @@ /* outline_tree_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_tree_presenter.cpp b/app/src/qt/outline_tree_presenter.cpp index ddee3c2a..16e7d6b0 100644 --- a/app/src/qt/outline_tree_presenter.cpp +++ b/app/src/qt/outline_tree_presenter.cpp @@ -1,7 +1,7 @@ /* outline_tree_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,8 +22,9 @@ namespace m8r { using namespace std; -OutlineTreePresenter::OutlineTreePresenter(OutlineTreeView* view, MainWindowPresenter* mwp, QObject* parent) - : QObject(parent) +OutlineTreePresenter::OutlineTreePresenter( + OutlineTreeView* view, MainWindowPresenter* mwp, QObject* parent +) : QObject(parent) { this->view = view; this->model = new OutlineTreeModel{view, mwp->getHtmlRepresentation()}; @@ -35,17 +36,35 @@ OutlineTreePresenter::OutlineTreePresenter(OutlineTreeView* view, MainWindowPres this->view->setItemDelegate(delegate); // signals - QObject::connect(view, SIGNAL(signalSelectNextRow()), this, SLOT(slotSelectNextRow())); - QObject::connect(view, SIGNAL(signalSelectPreviousRow()), this, SLOT(slotSelectPreviousRow())); + QObject::connect( + view, SIGNAL(signalSelectNextRow()), + this, SLOT(slotSelectNextRow())); + QObject::connect( + view, SIGNAL(signalSelectPreviousRow()), + this, SLOT(slotSelectPreviousRow())); - QObject::connect(view, SIGNAL(signalOutlineShow()), mwp, SLOT(doActionOutlineShow())); + QObject::connect( + view, SIGNAL(signalOutlineShow()), + mwp, SLOT(doActionOutlineShow())); - QObject::connect(view, SIGNAL(signalChangePromote()), mwp, SLOT(doActionNotePromote())); - QObject::connect(view, SIGNAL(signalChangeDemote()), mwp, SLOT(doActionNoteDemote())); - QObject::connect(view, SIGNAL(signalChangeFirst()), mwp, SLOT(doActionNoteFirst())); - QObject::connect(view, SIGNAL(signalChangeUp()), mwp, SLOT(doActionNoteUp())); - QObject::connect(view, SIGNAL(signalChangeDown()), mwp, SLOT(doActionNoteDown())); - QObject::connect(view, SIGNAL(signalChangeLast()), mwp, SLOT(doActionNoteLast())); + QObject::connect( + view, SIGNAL(signalChangePromote()), + mwp, SLOT(doActionNotePromote())); + QObject::connect( + view, SIGNAL(signalChangeDemote()), + mwp, SLOT(doActionNoteDemote())); + QObject::connect( + view, SIGNAL(signalChangeFirst()), + mwp, SLOT(doActionNoteFirst())); + QObject::connect( + view, SIGNAL(signalChangeUp()), + mwp, SLOT(doActionNoteUp())); + QObject::connect( + view, SIGNAL(signalChangeDown()), + mwp, SLOT(doActionNoteDown())); + QObject::connect( + view, SIGNAL(signalChangeLast()), + mwp, SLOT(doActionNoteLast())); QObject::connect( view, SIGNAL(signalOutlineOrNoteEdit()), @@ -53,8 +72,12 @@ OutlineTreePresenter::OutlineTreePresenter(OutlineTreeView* view, MainWindowPres QObject::connect( view, SIGNAL(signalOutlineOrNoteExternalEdit()), mwp, SLOT(doActionNoteExternalEdit())); - QObject::connect(view, SIGNAL(signalEdit()), mwp, SLOT(doActionNoteEdit())); - QObject::connect(view, SIGNAL(signalForget()), mwp, SLOT(doActionNoteForget())); + QObject::connect( + view, SIGNAL(signalEdit()), + mwp, SLOT(doActionNoteEdit())); + QObject::connect( + view, SIGNAL(signalForget()), + mwp, SLOT(doActionNoteForget())); } OutlineTreePresenter::~OutlineTreePresenter() @@ -126,13 +149,17 @@ void OutlineTreePresenter::refresh(Note* note) } } -void OutlineTreePresenter::insertAndSelect(Note* note) +void OutlineTreePresenter::selectRow(int row) { - int row = model->insertNote(note); view->scrollTo(model->index(row, 0)); view->selectRow(row); } +void OutlineTreePresenter::insertAndSelect(Note* note) +{ + this->selectRow(model->insertNote(note)); +} + void OutlineTreePresenter::clearSelection() { view->clearSelection(); @@ -166,18 +193,32 @@ Note* OutlineTreePresenter::getCurrentNote() const // IMPROVE constant w/ a name if(row != -1) { return model->item(row)->data().value(); - } else { - return nullptr; } + + return nullptr; } -void OutlineTreePresenter::slotSelectNextRow() +/** + * @brief Get adjacent N - adjacent above or below N. + * + * @return adjacent note or NULL if no such N. + */ +Note* OutlineTreePresenter::getAdjacentNote() const { int row = getCurrentRow(); - if(row < model->rowCount()-1) { - QModelIndex nextIndex = model->index(row+1, 0); - view->setCurrentIndex(nextIndex); + if(row != NO_ROW) { + if(row > 0) { + return model->item(row-1)->data().value(); + } + // ELSE row == 0 and child row cannot be selected + // as its not clear upfront whether/how many + // children will be deleted + // therefore it is expected that this function + // returns nullptr, so that row 0 can be selected + // AFTER N is deleted (if any row is remaining in O) } + + return nullptr; } void OutlineTreePresenter::slotSelectPreviousRow() @@ -189,4 +230,13 @@ void OutlineTreePresenter::slotSelectPreviousRow() } } +void OutlineTreePresenter::slotSelectNextRow() +{ + int row = getCurrentRow(); + if(row < model->rowCount()-1) { + QModelIndex nextIndex = model->index(row+1, 0); + view->setCurrentIndex(nextIndex); + } +} + } // m8r namespace diff --git a/app/src/qt/outline_tree_presenter.h b/app/src/qt/outline_tree_presenter.h index f9171ff5..7e01cdb7 100644 --- a/app/src/qt/outline_tree_presenter.h +++ b/app/src/qt/outline_tree_presenter.h @@ -1,7 +1,7 @@ /* outline_tree_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -59,6 +59,7 @@ class OutlineTreePresenter : public QObject void refresh(Outline* outline, Outline::Patch* patch=nullptr); void refresh(Note* note); + void selectRow(int row); void insertAndSelect(Note* note); void clearSelection(); @@ -67,6 +68,7 @@ class OutlineTreePresenter : public QObject int getCurrentRow() const; Note* getCurrentNote() const; + Note* getAdjacentNote() const; ~OutlineTreePresenter(); diff --git a/app/src/qt/outline_tree_view.cpp b/app/src/qt/outline_tree_view.cpp index 1be6a981..c31ac27f 100644 --- a/app/src/qt/outline_tree_view.cpp +++ b/app/src/qt/outline_tree_view.cpp @@ -1,7 +1,7 @@ /* outline_tree_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -104,19 +104,19 @@ void OutlineTreeView::keyPressEvent(QKeyEvent* event) emit signalSelectNextRow(); break; case Qt::Key_Home: - MF_DEBUG(" OutlineTreeView::keyPressEvent HOME" << endl); + MF_DEBUG(" OutlineTreeView::keyPressEvent HOME" << std::endl); if(this->model()->rowCount() > 0) { this->selectRow(0); } return; case Qt::Key_End: - MF_DEBUG(" OutlineTreeView::keyPressEvent END" << endl); + MF_DEBUG(" OutlineTreeView::keyPressEvent END" << std::endl); if(this->model()->rowCount() > 0) { this->selectRow(this->model()->rowCount()-1); } return; case Qt::Key_PageUp: { - MF_DEBUG(" OutlineTreeView::keyPressEvent PAGE_UP" << endl); + MF_DEBUG(" OutlineTreeView::keyPressEvent PAGE_UP" << std::endl); // get currently selected row QModelIndexList indices = selectionModel()->selection().indexes(); // no indexes > no row > no selection @@ -134,7 +134,7 @@ void OutlineTreeView::keyPressEvent(QKeyEvent* event) return; } case Qt::Key_PageDown: { - MF_DEBUG(" OutlineTreeView::keyPressEvent PAGE_DOWN" << endl); + MF_DEBUG(" OutlineTreeView::keyPressEvent PAGE_DOWN" << std::endl); // get currently selected row QModelIndexList indices = selectionModel()->selection().indexes(); // no indexes > no row > no selection diff --git a/app/src/qt/outline_tree_view.h b/app/src/qt/outline_tree_view.h index 763ab940..6fb61155 100644 --- a/app/src/qt/outline_tree_view.h +++ b/app/src/qt/outline_tree_view.h @@ -1,7 +1,7 @@ /* outline_tree_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -84,7 +84,9 @@ class OutlineTreeView : public QTableView virtual void keyPressEvent(QKeyEvent* event) override; virtual void mouseDoubleClickEvent(QMouseEvent* event) override; virtual void resizeEvent(QResizeEvent* event) override; - void refreshNotes(const QModelIndex& from, const QModelIndex& to) { dataChanged(from, to); } + void refreshNotes(const QModelIndex& from, const QModelIndex& to) { + dataChanged(from, to); + } signals: void signalOutlineShow(); diff --git a/app/src/qt/outline_view.cpp b/app/src/qt/outline_view.cpp index d07c705c..de2c4662 100644 --- a/app/src/qt/outline_view.cpp +++ b/app/src/qt/outline_view.cpp @@ -1,7 +1,7 @@ /* outline_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_view.h b/app/src/qt/outline_view.h index f537bfcd..e85c95a9 100644 --- a/app/src/qt/outline_view.h +++ b/app/src/qt/outline_view.h @@ -1,7 +1,7 @@ /* outline_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_view_presenter.cpp b/app/src/qt/outline_view_presenter.cpp index 0f5e27f0..34b1bbc3 100644 --- a/app/src/qt/outline_view_presenter.cpp +++ b/app/src/qt/outline_view_presenter.cpp @@ -1,7 +1,7 @@ /* outline_view_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_view_presenter.h b/app/src/qt/outline_view_presenter.h index 1dbb5c63..6d4c324e 100644 --- a/app/src/qt/outline_view_presenter.h +++ b/app/src/qt/outline_view_presenter.h @@ -1,7 +1,7 @@ /* outline_view_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_view_splitter.cpp b/app/src/qt/outline_view_splitter.cpp index e0974944..e6b70736 100644 --- a/app/src/qt/outline_view_splitter.cpp +++ b/app/src/qt/outline_view_splitter.cpp @@ -1,7 +1,7 @@ /* outline_view_splitter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outline_view_splitter.h b/app/src/qt/outline_view_splitter.h index 7fcd3cdc..e8e25631 100644 --- a/app/src/qt/outline_view_splitter.h +++ b/app/src/qt/outline_view_splitter.h @@ -1,7 +1,7 @@ /* outline_view_splitter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outlines_map_model.cpp b/app/src/qt/outlines_map_model.cpp new file mode 100644 index 00000000..d94d608b --- /dev/null +++ b/app/src/qt/outlines_map_model.cpp @@ -0,0 +1,190 @@ +/* + outlines_map_model.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "outlines_map_model.h" + +#include + +#define NO_INDEX -1 + +using namespace std; + +namespace m8r { + +OutlinesMapModel::OutlinesMapModel(QObject *parent, HtmlOutlineRepresentation* htmlRepresentation) + : QStandardItemModel(parent), htmlRepresentation(htmlRepresentation) +{ + setColumnCount(5); + setRowCount(0); +} + +void OutlinesMapModel::removeAllRows() +{ + QStandardItemModel::clear(); + + QStringList tableHeader; + tableHeader + << tr("Notebooks Tree") // tree of Notebooks ~ mind map of Notebooks + << tr("Done") + << tr("Rs") + << tr("Ws") + << tr("Modified"); + setHorizontalHeaderLabels(tableHeader); +} + +void OutlinesMapModel::createNameText(string& html, Note* note) +{ + for(auto depth=0; depthgetDepth(); depth++) { + html += "    "; + } + html += note->getName(); + + htmlRepresentation->tagsToHtml(note->getTags(), html); + // IMPROVE make showing of type configurable + htmlRepresentation->noteTypeToHtml(note->getType(), html); +} + +void OutlinesMapModel::createRowFor(Note* note, QList& rowItems) +{ + // name + string name{}; + name.reserve(200); + createNameText(name, note); + QStandardItem* noteItem = new QStandardItem{QString::fromStdString(name)}; + // TODO declare custom role + noteItem->setData(QVariant::fromValue(note), Qt::UserRole + 1); + rowItems += noteItem; + // % + QString s{}; + if(note->getProgress()) { + s.clear(); + s += QString::number(note->getProgress()); + s += "%"; + rowItems += new QStandardItem{s}; + } else { + rowItems += new QStandardItem{""}; + } + // rd/wr + rowItems += new QStandardItem{QString::number(note->getReads())}; + rowItems += new QStandardItem{QString::number(note->getRevision())}; + // pretty + s = note->getModifiedPretty().c_str(); + rowItems += new QStandardItem{s}; +} + + +void OutlinesMapModel::addNote(Note* note) +{ + QList items; + createRowFor(note, items); + appendRow(items); +} + +int OutlinesMapModel::insertNote(Note* note) +{ + if(note) { + QList items; + createRowFor(note, items); + int offset = note->getOutline()->getNoteOffset(note); + insertRow(offset, items); + return offset; + } else { + return 0; + } +} + +int OutlinesMapModel::getRowByNote(const Note* note) +{ + for(int row = 0; rowdata().value() == note) { + return row; + } + } + return NO_INDEX; +} + +int OutlinesMapModel::getRowByOutlineKey(const string& outlineKey) +{ + for(int row = 0; rowdata().value(); + Link* oLink = n->getLinkByName(LINK_NAME_OUTLINE_KEY); + if(oLink) { + string oKey{oLink->getUrl()}; + if(oKey == outlineKey) { + return row; + } + } + } + return NO_INDEX; +} + +void OutlinesMapModel::refresh(Note* note, int row, bool set) +{ + if(row > NO_INDEX) { + if(set) { + // TODO declare custom role + item(row,0)->setData(QVariant::fromValue(note), Qt::UserRole + 1); + } + + string s{}; + s.reserve(100); + createNameText(s, note); + // refresh content + item(row,0)->setText(QString::fromStdString(s)); + + if(note->getProgress()) { + s.clear(); + s += std::to_string(note->getProgress()); + s += "%"; + item(row,1)->setText(QString::fromStdString(s)); + } else { + item(row,1)->setText(""); + } + + item(row,2)->setText(QString::number(note->getReads())); + item(row,3)->setText(QString::number(note->getRevision())); + item(row,4)->setText(QString::fromStdString(note->getModifiedPretty())); + + QModelIndex from = createIndex(row, 0, item(row,0)); + QModelIndex to = createIndex(row, 3, item(row,3)); + + // notify widget about changes + emit dataChanged(from,to); + } +} + +void OutlinesMapModel::refresh(Note* note, QModelIndexList selection) +{ + int row = NO_INDEX; + + // determine row number by note attached to the row - selection or iteration + if(selection.size()) { + // TODO declare custom role + if(item(selection[0].row())->data(Qt::UserRole + 1).value() == note) { + row = selection[0].row(); + } + } + if(row <= NO_INDEX) { + // IMPROVE UI note that has both Note and QStandardItem refs + row = getRowByNote(note); + } + + refresh(note, row); +} + +} // m8r namespace diff --git a/app/src/qt/outlines_map_model.h b/app/src/qt/outlines_map_model.h new file mode 100644 index 00000000..2412b7ad --- /dev/null +++ b/app/src/qt/outlines_map_model.h @@ -0,0 +1,65 @@ +/* + outlines_map_model.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_OUTLINES_MAP_MODEL_H +#define M8RUI_OUTLINES_MAP_MODEL_H + +#include + +#include + +#include "../../lib/src/model/note.h" +#include "../../lib/src/representations/html/html_outline_representation.h" + +#include "notes_table_model.h" +#include "gear/qutils.h" + +namespace m8r { + +class OutlinesMapModel : public QStandardItemModel +{ + Q_OBJECT + +private: + HtmlOutlineRepresentation* htmlRepresentation; + QList noselection; + +public: + OutlinesMapModel(QObject *parent, HtmlOutlineRepresentation* htmlRepresentation); + OutlinesMapModel(const OutlinesMapModel&) = delete; + OutlinesMapModel(const OutlinesMapModel&&) = delete; + OutlinesMapModel &operator=(const OutlinesMapModel&) = delete; + OutlinesMapModel &operator=(const OutlinesMapModel&&) = delete; + + void removeAllRows(); + void addNote(Note* note); + int insertNote(Note* note); + int getRowByNote(const Note* note); + int getRowByOutlineKey(const std::string& outlineKey); + void refresh(Note* note) { refresh(note, noselection); } + void refresh(Note* note, int row, bool set=false); + void refresh(Note* note, QModelIndexList selection); + +private: + void createNameText(std::string& name, Note* note); + void createRowFor(Note* note, QList& rowItems); +}; + +} + +#endif // M8RUI_OUTLINES_MAP_MODEL_H diff --git a/app/src/qt/outlines_map_presenter.cpp b/app/src/qt/outlines_map_presenter.cpp new file mode 100644 index 00000000..02a3e2a9 --- /dev/null +++ b/app/src/qt/outlines_map_presenter.cpp @@ -0,0 +1,244 @@ +/* + outlines_map_presenter.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "outlines_map_presenter.h" + +namespace m8r { + +using namespace std; + +OutlinesMapPresenter::OutlinesMapPresenter( + OutlinesMapView* view, MainWindowPresenter* mwp, QObject* parent +) : QObject(parent) +{ + this->view = view; + this->model = new OutlinesMapModel{view, mwp->getHtmlRepresentation()}; + this->view->setModel(this->model); + this->mind = mwp->getMind(); + + // ensure HTML cells rendering + HtmlDelegate* delegate = new HtmlDelegate{}; + this->view->setItemDelegate(delegate); + + // signals + QObject::connect( + view, SIGNAL(signalSelectNextRow()), + this, SLOT(slotSelectNextRow())); + QObject::connect( + view, SIGNAL(signalSelectPreviousRow()), + this, SLOT(slotSelectPreviousRow())); + + QObject::connect( + view, SIGNAL(signalChangePromote()), + mwp, SLOT(doActionNotePromote())); + QObject::connect( + view, SIGNAL(signalChangeDemote()), + mwp, SLOT(doActionNoteDemote())); + QObject::connect( + view, SIGNAL(signalChangeFirst()), + mwp, SLOT(doActionNoteFirst())); + QObject::connect( + view, SIGNAL(signalChangeUp()), + mwp, SLOT(doActionNoteUp())); + QObject::connect( + view, SIGNAL(signalChangeDown()), + mwp, SLOT(doActionNoteDown())); + QObject::connect( + view, SIGNAL(signalChangeLast()), + mwp, SLOT(doActionNoteLast())); + + // TODO signals to be re-written and re-wired + /* + QObject::connect( + view, SIGNAL(signalOutlineShow()), + mwp, SLOT(doActionOutlineShow())); + QObject::connect( + view, SIGNAL(signalOutlineOrNoteEdit()), + mwp, SLOT(doActionOutlineOrNoteEdit())); + QObject::connect( + view, SIGNAL(signalOutlineOrNoteExternalEdit()), + mwp, SLOT(doActionNoteExternalEdit())); + QObject::connect( + view, SIGNAL(signalEdit()), + mwp, SLOT(doActionNoteEdit())); + QObject::connect( + view, SIGNAL(signalForget()), + mwp, SLOT(doActionNoteForget())); + */ +} + +OutlinesMapPresenter::~OutlinesMapPresenter() +{ + if(model) delete model; +} + +void OutlinesMapPresenter::refresh(Outline* outline, Outline::Patch* patch) +{ + // If FORGET aspect is used, then only VIEW is filtered, but operations are performed + // on the non-filtered O's Ns. UI view serves just as a FILTER of what can be changed. + // Therefore anything special is needed on the backend. + // Unfortunately PATCH will NOT help if VIEW is filtered and everyhing must be + // refreshed. + if(outline) { + if(patch) { + const vector& notes = outline->getNotes(); + switch(patch->diff) { + case Outline::Patch::Diff::CHANGE: + for(unsigned int i=patch->start; i<=patch->start+patch->count; i++) { + model->refresh(notes[i], i, false); + } + break; + case Outline::Patch::Diff::MOVE: + for(unsigned int i=patch->start; i<=patch->start+patch->count; i++) { + model->refresh(notes[i], i, true); + } + break; + default: + break; + } + } else { + model->removeAllRows(); + for(Note* note:outline->getNotes()) { + model->addNote(note); + } + } + + // forget / time scope: hide view rows ~ there is full model, I just hide what's visible > patch should work + if(mind->getScopeAspect().isEnabled()) { + vector parents; + for(size_t i=0; igetNotesCount(); i++) { + if(mind->getScopeAspect().isInScope(outline->getNotes()[i])) { + // N's parents + parents.clear(); + outline->getNotePathToRoot(i, parents); + if(parents.size()) { + for(size_t p=0; pshowRow(parents[p]); + } + } + // N + view->showRow(i); + } else { + view->hideRow(i); + } + } + } + } +} + +void OutlinesMapPresenter::refresh(Note* note) +{ + QItemSelectionModel *select = view->selectionModel(); + if(select->hasSelection()) { + model->refresh(note, select->selectedRows()); + } else { + model->refresh(note); + } +} + +void OutlinesMapPresenter::selectRow(int row) +{ + view->scrollTo(model->index(row, 0)); + view->selectRow(row); +} + +void OutlinesMapPresenter::insertAndSelect(Note* note) +{ + this->selectRow(model->insertNote(note)); +} + +void OutlinesMapPresenter::clearSelection() +{ + view->clearSelection(); +} + +void OutlinesMapPresenter::selectRowByOutlineKey(const string& outlineKey) +{ + if(outlineKey.size()) { + int row = model->getRowByOutlineKey(outlineKey); + if(row >= 0) { + view->selectRow(row); + view->scrollTo(model->index(row, 0)); + return; + } + } + view->clearSelection(); +} + +int OutlinesMapPresenter::getCurrentRow() const +{ + QModelIndexList indexes = view->selectionModel()->selection().indexes(); + for(int i=0; iitem(row)->data().value(); + } + + return nullptr; +} + +/** + * @brief Get adjacent N - adjacent above or below N. + * + * @return adjacent note or NULL if no such N. + */ +Note* OutlinesMapPresenter::getAdjacentNote() const +{ + int row = getCurrentRow(); + if(row != NO_ROW) { + if(row > 0) { + return model->item(row-1)->data().value(); + } + // ELSE row == 0 and child row cannot be selected + // as its not clear upfront whether/how many + // children will be deleted + // therefore it is expected that this function + // returns nullptr, so that row 0 can be selected + // AFTER N is deleted (if any row is remaining in O) + } + + return nullptr; +} + +void OutlinesMapPresenter::slotSelectPreviousRow() +{ + int row = getCurrentRow(); + if(row) { + QModelIndex previousIndex = model->index(row-1, 0); + view->setCurrentIndex(previousIndex); + } +} + +void OutlinesMapPresenter::slotSelectNextRow() +{ + int row = getCurrentRow(); + if(row < model->rowCount()-1) { + QModelIndex nextIndex = model->index(row+1, 0); + view->setCurrentIndex(nextIndex); + } +} + +} // m8r namespace diff --git a/app/src/qt/outlines_map_presenter.h b/app/src/qt/outlines_map_presenter.h new file mode 100644 index 00000000..158d43cb --- /dev/null +++ b/app/src/qt/outlines_map_presenter.h @@ -0,0 +1,116 @@ +/* + outlines_map_presenter.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_OUTLINES_MAP_PRESENTER_H +#define M8RUI_OUTLINES_MAP_PRESENTER_H + +#include + +#include "../../lib/src/model/outline.h" +#include "../../lib/src/mind/mind.h" + +#include + +#include "orloj_presenter.h" +#include "outlines_map_view.h" +#include "outlines_map_model.h" + +namespace m8r { + +class OrlojPresenter; + +/** + * @brief The Outlines map presenter. + * + * Outlines map ~ tree of Outlines is in fact ~ mind map of Outlines + */ +// +// MVP assembly: View / Model / Presenter: +// +// view <- new View +// presenter <- new Presenter(view) + new Model(view) +// model <- presenter.model +// +// Integration: +// +// orlojView <- new View() +// orlojPresenter <- presenter +// +// Materialization / view: +// +// menu ... MainMenuView::actionViewOutlinesMap +// -> @ MainMenuPresenter +// -> MainWindowPresenter::doActionViewOutlinesMap() +// ... generate virtual O from Os headers +// -> OrlojPresenter::showFacetOutlinesMap( virtualO ) +// +// Signals: +// +// - emit: OutlinesMapView +// ... OK ~ view is the source of signals +// - wire: OutlinesMapPresenter +// ... OK ~ this is where code belongs & it's presenter's role in MVP +// - slot: MainWindowPresenter +// ... OK ~ this is where are presenters are instantiated +// +class OutlinesMapPresenter : public QObject +{ + Q_OBJECT + +public: + static const int NO_ROW = -1; + +private: + OutlinesMapView* view; + OutlinesMapModel* model; + + Mind* mind; + +public: + explicit OutlinesMapPresenter( + OutlinesMapView* view, MainWindowPresenter* mwp, QObject* parent); + OutlinesMapPresenter(const OutlinesMapPresenter&) = delete; + OutlinesMapPresenter(const OutlinesMapPresenter&&) = delete; + OutlinesMapPresenter &operator=(const OutlinesMapPresenter&) = delete; + OutlinesMapPresenter &operator=(const OutlinesMapPresenter&&) = delete; + + OutlinesMapView* getView() const { return view; } + OutlinesMapModel* getModel() const { return model; } + + void refresh(Outline* outline, Outline::Patch* patch=nullptr); + void refresh(Note* note); + void selectRow(int row); + void insertAndSelect(Note* note); + + void clearSelection(); + void focus() { view->setFocus(); } + void selectRowByOutlineKey(const std::string &outlineKey); + + int getCurrentRow() const; + Note* getCurrentNote() const; + Note* getAdjacentNote() const; + + ~OutlinesMapPresenter(); + +public slots: + void slotSelectNextRow(); + void slotSelectPreviousRow(); +}; + +} +#endif // M8RUI_OUTLINES_MAP_PRESENTER_H diff --git a/app/src/qt/outlines_map_view.cpp b/app/src/qt/outlines_map_view.cpp new file mode 100644 index 00000000..8e86d0aa --- /dev/null +++ b/app/src/qt/outlines_map_view.cpp @@ -0,0 +1,219 @@ +/* + outlines_map_view.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "outlines_map_view.h" + +namespace m8r { + +OutlinesMapView::OutlinesMapView(QWidget* parent) + : QTableView(parent) +{ + verticalHeader()->setVisible(false); + + // BEFARE: this kills performance in case of big(ger) tables + // verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + + setSortingEnabled(false); + + setEditTriggers(QAbstractItemView::NoEditTriggers); + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::SingleSelection); + // disable TAB and Ctrl+O up/down navigation (Ctrl+O no longer bound) + setTabKeyNavigation(false); + + verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); +} + +void OutlinesMapView::keyPressEvent(QKeyEvent* event) +{ + // leave note view navigation +#ifndef __APPLE__ + if(event->modifiers() & Qt::AltModifier) { + if(event->key()==Qt::Key_Left) { + emit signalFromOutlinesMapToOutlines(); + } + } else { +#endif + // up/down/promote/demote note tree changes + if(event->modifiers() & Qt::ControlModifier){ + if(event->modifiers() & Qt::ShiftModifier) { + switch(event->key()) { + case Qt::Key_Up: + emit signalChangeFirst(); + break; + case Qt::Key_Down: + emit signalChangeLast(); + break; + } + } else { + switch(event->key()) { +#ifndef __APPLE__ + case Qt::Key_Up: + emit signalChangeUp(); + break; + case Qt::Key_Down: + emit signalChangeDown(); + break; + case Qt::Key_Left: + emit signalChangePromote(); + break; + case Qt::Key_Right: + emit signalChangeDemote(); + break; +#else + case Qt::Key_L: + emit signalFromOutlinesMapToOutlines(); + break; + case Qt::Key_D: + emit signalForget(); + break; +#endif + case Qt::Key_E: + emit signalOutlineOrNoteEdit(); + break; + case Qt::Key_X: + emit signalOutlineOrNoteExternalEdit(); + break; + } + } + } else { + // up/down note tree navigation + switch(event->key()) { + case Qt::Key_Escape: + emit signalOutlineShow(); + break; + case Qt::Key_Up: + emit signalSelectPreviousRow(); + break; + case Qt::Key_Down: + emit signalSelectNextRow(); + break; + case Qt::Key_Home: + MF_DEBUG(" OutlinesMapView::keyPressEvent HOME" << std::endl); + if(this->model()->rowCount() > 0) { + this->selectRow(0); + } + return; + case Qt::Key_End: + MF_DEBUG(" OutlinesMapView::keyPressEvent END" << std::endl); + if(this->model()->rowCount() > 0) { + this->selectRow(this->model()->rowCount()-1); + } + return; + case Qt::Key_PageUp: { + MF_DEBUG(" OutlinesMapView::keyPressEvent PAGE_UP" << std::endl); + // get currently selected row + QModelIndexList indices = selectionModel()->selection().indexes(); + // no indexes > no row > no selection + for(int i=0; iselectRow(newRow); + } + // no row selected + return; + } + case Qt::Key_PageDown: { + MF_DEBUG(" OutlinesMapView::keyPressEvent PAGE_DOWN" << std::endl); + // get currently selected row + QModelIndexList indices = selectionModel()->selection().indexes(); + // no indexes > no row > no selection + for(int i=0; i this->model()->rowCount()-1) { + newRow = this->model()->rowCount()-1; + } + // select row + this->selectRow(newRow); + } + // no row selected + return; + } + case Qt::Key_Return: + case Qt::Key_Right: + MF_DEBUG(" OutlinesMapView: SIGNAL show O ->" << std::endl); + emit signalMapShowSelectedOutline(); + break; +#ifndef __APPLE__ + case Qt::Key_Delete: + emit signalForget(); + break; +#endif + case Qt::Key_Left: + // TODO this can be signal that I already have for openning Os list + signalFromOutlinesMapToOutlines(); + break; + } + } +#ifndef __APPLE__ + } +#endif + + QWidget::keyPressEvent(event); +} + +void OutlinesMapView::mouseDoubleClickEvent(QMouseEvent* event) +{ + Q_UNUSED(event); + + // double click to N opens it + emit signalMapShowSelectedOutline(); +} + +void OutlinesMapView::resizeEvent(QResizeEvent* event) +{ + MF_DEBUG("OutlinesMapView::resizeEvent " << event << std::endl); + + if(horizontalHeader()->length() > 0) { + // ensure that 1st column gets the remaining space from others + horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + } + verticalHeader()->setDefaultSectionSize(fontMetrics().height()*1.5); + + int normalizedWidth = width()/fontMetrics().averageCharWidth(); + if(normalizedWidth < SIMPLIFIED_VIEW_THRESHOLD_WIDTH) { + this->setColumnHidden(1, true); + this->setColumnHidden(2, true); + this->setColumnHidden(3, true); + } else { + if(this->isColumnHidden(1)) { + this->setColumnHidden(1, false); + this->setColumnHidden(2, false); + this->setColumnHidden(3, false); + } + // progress + this->setColumnWidth(1, this->fontMetrics().averageCharWidth()*6); + // rd/wr + this->setColumnWidth(2, this->fontMetrics().averageCharWidth()*5); + this->setColumnWidth(3, this->fontMetrics().averageCharWidth()*5); + } + + // pretty + this->setColumnWidth(4, this->fontMetrics().averageCharWidth()*12); + + QTableView::resizeEvent(event); +} + +} // m8r namespace diff --git a/app/src/qt/outlines_map_view.h b/app/src/qt/outlines_map_view.h new file mode 100644 index 00000000..0be06a61 --- /dev/null +++ b/app/src/qt/outlines_map_view.h @@ -0,0 +1,114 @@ +/* + outlines_map_view.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8RUI_OUTLINES_MAP_VIEW_H +#define M8RUI_OUTLINES_MAP_VIEW_H + +#include "../../lib/src/gear/lang_utils.h" +#include "../lib/src/debug.h" + +#include + +#include "qt_commons.h" + +namespace m8r { + +class OutlinesMapView; + +class OutlinesMapViewItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + OutlinesMapViewItemDelegate(QObject* outlinesMapView) + : QStyledItemDelegate(outlinesMapView) + { + installEventFilter(this); + } + + /** + * If you want to FILTER the event out, i.e. STOP it being + * handled further, then return TRUE; otherwise return FALSE. + * + * Event filter must be installed in constructor. + */ + bool eventFilter(QObject* obj, QEvent* event) override + { + if(event->type() == QEvent::KeyPress) { + return true; + } else { + return QStyledItemDelegate::eventFilter(obj, event); + } + } + + QWidget *createEditor( + QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const override + { + QWidget *result = QStyledItemDelegate::createEditor(parent, option, index); + result->installEventFilter(new OutlinesMapViewItemDelegate(parent)); + return result; + } +}; + +class OutlinesMapView : public QTableView +{ + Q_OBJECT + +private: + // if view is width < threshold columns, then shows simplified view w/o Mind-related columns + static constexpr int SIMPLIFIED_VIEW_THRESHOLD_WIDTH = 75; + +public: + explicit OutlinesMapView(QWidget* parent); + OutlinesMapView(const OutlinesMapView&) = delete; + OutlinesMapView(const OutlinesMapView&&) = delete; + OutlinesMapView &operator=(const OutlinesMapView&) = delete; + OutlinesMapView &operator=(const OutlinesMapView&&) = delete; + + virtual void keyPressEvent(QKeyEvent* event) override; + virtual void mouseDoubleClickEvent(QMouseEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; + void refreshNotes(const QModelIndex& from, const QModelIndex& to) { + dataChanged(from, to); + } + +signals: + void signalOutlineShow(); + + void signalFromOutlinesMapToOutlines(); + + void signalSelectNextRow(); + void signalSelectPreviousRow(); + + void signalChangeUp(); + void signalChangeDown(); + void signalChangePromote(); + void signalChangeDemote(); + void signalChangeFirst(); + void signalChangeLast(); + + void signalOutlineOrNoteEdit(); // O or N edit + void signalOutlineOrNoteExternalEdit(); // O or N edit + void signalMapShowSelectedOutline(); + void signalForget(); +}; + +} +#endif // M8RUI_OUTLINES_MAP_VIEW_H diff --git a/app/src/qt/outlines_table_model.cpp b/app/src/qt/outlines_table_model.cpp index ac37f557..b408f97b 100644 --- a/app/src/qt/outlines_table_model.cpp +++ b/app/src/qt/outlines_table_model.cpp @@ -1,7 +1,7 @@ /* notes_table_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outlines_table_model.h b/app/src/qt/outlines_table_model.h index 2f5e035c..61359fea 100644 --- a/app/src/qt/outlines_table_model.h +++ b/app/src/qt/outlines_table_model.h @@ -1,7 +1,7 @@ /* outlines_table_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outlines_table_presenter.cpp b/app/src/qt/outlines_table_presenter.cpp index 285f805c..18c4224d 100644 --- a/app/src/qt/outlines_table_presenter.cpp +++ b/app/src/qt/outlines_table_presenter.cpp @@ -1,7 +1,7 @@ /* outlines_table_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outlines_table_presenter.h b/app/src/qt/outlines_table_presenter.h index 35ceafc6..8158f02c 100644 --- a/app/src/qt/outlines_table_presenter.h +++ b/app/src/qt/outlines_table_presenter.h @@ -1,7 +1,7 @@ /* outlines_table_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outlines_table_view.cpp b/app/src/qt/outlines_table_view.cpp index a41e3ee3..0af98891 100644 --- a/app/src/qt/outlines_table_view.cpp +++ b/app/src/qt/outlines_table_view.cpp @@ -1,7 +1,7 @@ /* outlines_table_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/outlines_table_view.h b/app/src/qt/outlines_table_view.h index 221a3127..5f26177c 100644 --- a/app/src/qt/outlines_table_view.h +++ b/app/src/qt/outlines_table_view.h @@ -1,7 +1,7 @@ /* outlines_table_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/palette.h b/app/src/qt/palette.h index 826dbe77..49b06751 100644 --- a/app/src/qt/palette.h +++ b/app/src/qt/palette.h @@ -1,7 +1,7 @@ /* palette.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,9 +22,9 @@ Comments gray #777 Help green #008C00 Hover dark gray #36393D - MR blue #356AA0 + MR blue #356AA0 - Web 2.0 colors: + Web 2.0 colors: Shiny silver [#EEEEEE] Reddit white [#FFFFFF] Magnolia Mag.nolia [#F9F7ED] @@ -46,7 +46,7 @@ Basecamp Green [#6BBA70] Mozilla Blue [#3F4C6B] Digg Blue [#356AA0] - Last.fm Crimson [#D01F3C] + Last.fm Crimson [#D01F3C] */ #ifndef M8RUI_PALETTE_H #define M8RUI_PALETTE_H diff --git a/app/src/qt/qt_commons.h b/app/src/qt/qt_commons.h index 001ef42e..11a60254 100644 --- a/app/src/qt/qt_commons.h +++ b/app/src/qt/qt_commons.h @@ -1,7 +1,7 @@ /* qt_commons.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/recent_notes_table_model.cpp b/app/src/qt/recent_notes_table_model.cpp index eddd713c..a148657d 100644 --- a/app/src/qt/recent_notes_table_model.cpp +++ b/app/src/qt/recent_notes_table_model.cpp @@ -1,7 +1,7 @@ /* recent_notes_table_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/recent_notes_table_model.h b/app/src/qt/recent_notes_table_model.h index d74085e3..d1ac0ba8 100644 --- a/app/src/qt/recent_notes_table_model.h +++ b/app/src/qt/recent_notes_table_model.h @@ -1,7 +1,7 @@ /* recent_notes_table_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/recent_notes_table_presenter.cpp b/app/src/qt/recent_notes_table_presenter.cpp index 249f000d..228baa74 100644 --- a/app/src/qt/recent_notes_table_presenter.cpp +++ b/app/src/qt/recent_notes_table_presenter.cpp @@ -1,7 +1,7 @@ /* recent_notes_table_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,7 +23,7 @@ namespace m8r { using namespace std; RecentNotesTablePresenter::RecentNotesTablePresenter(RecentNotesTableView* view, HtmlOutlineRepresentation* htmlRepresentation) -{ +{ this->view = view; this->model = new RecentNotesTableModel(this, htmlRepresentation); this->view->setModel(this->model); @@ -46,7 +46,7 @@ void RecentNotesTablePresenter::refresh(const vector& notes) int uiLimit = Configuration::getInstance().getRecentNotesUiLimit(); for(Note* n:notes) { if(uiLimit) uiLimit--; else break; - model->addRow(n); + model->addRow(n); } } diff --git a/app/src/qt/recent_notes_table_presenter.h b/app/src/qt/recent_notes_table_presenter.h index ae53d8f9..62611f97 100644 --- a/app/src/qt/recent_notes_table_presenter.h +++ b/app/src/qt/recent_notes_table_presenter.h @@ -1,7 +1,7 @@ /* recent_notes_table_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/recent_notes_table_view.cpp b/app/src/qt/recent_notes_table_view.cpp index 3bd23616..757534bb 100644 --- a/app/src/qt/recent_notes_table_view.cpp +++ b/app/src/qt/recent_notes_table_view.cpp @@ -1,7 +1,7 @@ /* recent_notes_table_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/recent_notes_table_view.h b/app/src/qt/recent_notes_table_view.h index d76fde0d..b630b87b 100644 --- a/app/src/qt/recent_notes_table_view.h +++ b/app/src/qt/recent_notes_table_view.h @@ -1,7 +1,7 @@ /* recent_notes_table_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/spelling/dictionary_manager.cpp b/app/src/qt/spelling/dictionary_manager.cpp index bd0e2c60..b32b52e6 100644 --- a/app/src/qt/spelling/dictionary_manager.cpp +++ b/app/src/qt/spelling/dictionary_manager.cpp @@ -1,7 +1,7 @@ /*********************************************************************** * * Copyright (C) 2009, 2010, 2011, 2012, 2013 Graeme Gott - * Copyright (C) 2021-2022 Martin Dvorak + * Copyright (C) 2021-2024 Martin Dvorak * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/qt/spelling/dictionary_manager.h b/app/src/qt/spelling/dictionary_manager.h index e58529dd..3d5796ff 100644 --- a/app/src/qt/spelling/dictionary_manager.h +++ b/app/src/qt/spelling/dictionary_manager.h @@ -1,7 +1,7 @@ /*********************************************************************** * * Copyright (C) 2009, 2010, 2011, 2012, 2013 Graeme Gott - * Copyright (C) 2021-2022 Martin Dvorak + * Copyright (C) 2021-2024 Martin Dvorak * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/qt/spelling/dictionary_provider_hunspell.cpp b/app/src/qt/spelling/dictionary_provider_hunspell.cpp index 0dc77f13..0bde6940 100644 --- a/app/src/qt/spelling/dictionary_provider_hunspell.cpp +++ b/app/src/qt/spelling/dictionary_provider_hunspell.cpp @@ -2,7 +2,7 @@ * * Copyright (C) 2009, 2010, 2011, 2012, 2013 Graeme Gott * Copyright (C) 2014-2020 wereturtle - * Copyright (C) 2021-2022 Martin Dvorak + * Copyright (C) 2021-2024 Martin Dvorak * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/qt/status_bar_presenter.cpp b/app/src/qt/status_bar_presenter.cpp index 312aea01..846b489a 100644 --- a/app/src/qt/status_bar_presenter.cpp +++ b/app/src/qt/status_bar_presenter.cpp @@ -1,7 +1,7 @@ /* status_bar_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/status_bar_presenter.h b/app/src/qt/status_bar_presenter.h index 00b2f9a2..0100d71f 100644 --- a/app/src/qt/status_bar_presenter.h +++ b/app/src/qt/status_bar_presenter.h @@ -1,7 +1,7 @@ /* status_bar_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/status_bar_view.cpp b/app/src/qt/status_bar_view.cpp index 36769a05..1d4a2eec 100644 --- a/app/src/qt/status_bar_view.cpp +++ b/app/src/qt/status_bar_view.cpp @@ -1,7 +1,7 @@ /* status_bar_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/status_bar_view.h b/app/src/qt/status_bar_view.h index 0f6228db..80081c8d 100644 --- a/app/src/qt/status_bar_view.h +++ b/app/src/qt/status_bar_view.h @@ -1,7 +1,7 @@ /* status_bar_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/tags_table_model.cpp b/app/src/qt/tags_table_model.cpp index d6ac5713..b33d862b 100644 --- a/app/src/qt/tags_table_model.cpp +++ b/app/src/qt/tags_table_model.cpp @@ -1,7 +1,7 @@ /* tags_table_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/tags_table_model.h b/app/src/qt/tags_table_model.h index e405ea85..eefb09c3 100644 --- a/app/src/qt/tags_table_model.h +++ b/app/src/qt/tags_table_model.h @@ -1,7 +1,7 @@ /* tags_table_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/tags_table_presenter.cpp b/app/src/qt/tags_table_presenter.cpp index b145ca57..15761109 100644 --- a/app/src/qt/tags_table_presenter.cpp +++ b/app/src/qt/tags_table_presenter.cpp @@ -1,7 +1,7 @@ /* tags_table_presenter.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/tags_table_presenter.h b/app/src/qt/tags_table_presenter.h index c0ec35f4..0d51c215 100644 --- a/app/src/qt/tags_table_presenter.h +++ b/app/src/qt/tags_table_presenter.h @@ -1,7 +1,7 @@ /* tags_table_presenter.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/tags_table_view.cpp b/app/src/qt/tags_table_view.cpp index 9fbad45b..e279bec5 100644 --- a/app/src/qt/tags_table_view.cpp +++ b/app/src/qt/tags_table_view.cpp @@ -1,7 +1,7 @@ /* tags_table_view.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/tags_table_view.h b/app/src/qt/tags_table_view.h index 23a5ab06..c8067d66 100644 --- a/app/src/qt/tags_table_view.h +++ b/app/src/qt/tags_table_view.h @@ -1,7 +1,7 @@ /* tags_table_view.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/web_engine_page_link_navigation_policy.cpp b/app/src/qt/web_engine_page_link_navigation_policy.cpp index 6c76e368..1487eb85 100644 --- a/app/src/qt/web_engine_page_link_navigation_policy.cpp +++ b/app/src/qt/web_engine_page_link_navigation_policy.cpp @@ -1,7 +1,7 @@ /* web_engine_page_link_navigation_policy.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/web_engine_page_link_navigation_policy.h b/app/src/qt/web_engine_page_link_navigation_policy.h index b363e7a7..30c4690e 100644 --- a/app/src/qt/web_engine_page_link_navigation_policy.h +++ b/app/src/qt/web_engine_page_link_navigation_policy.h @@ -1,7 +1,7 @@ /* web_engine_page_link_navigation_policy.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/edit_buttons_panel.cpp b/app/src/qt/widgets/edit_buttons_panel.cpp index a35d217b..4f772b89 100644 --- a/app/src/qt/widgets/edit_buttons_panel.cpp +++ b/app/src/qt/widgets/edit_buttons_panel.cpp @@ -1,7 +1,7 @@ /* edit_buttons_panel.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -48,7 +48,7 @@ EditButtonsPanel::EditButtonsPanel(MfWidgetMode mode, QWidget* parent) rememberAndLeaveButton = new QPushButton{tr("Remember and Leave"), this}; #ifdef __APPLE__ - rememberAndLeaveButton->setToolTip("⌘L"); + rememberAndLeaveButton->setToolTip("⌘D"); // like DONE (⌘L used for link completion in N editor) #else rememberAndLeaveButton->setToolTip("Alt+Left"); #endif diff --git a/app/src/qt/widgets/edit_buttons_panel.h b/app/src/qt/widgets/edit_buttons_panel.h index 2e9825bf..cd9dbb92 100644 --- a/app/src/qt/widgets/edit_buttons_panel.h +++ b/app/src/qt/widgets/edit_buttons_panel.h @@ -1,7 +1,7 @@ /* edit_buttons_panel.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/edit_name_panel.cpp b/app/src/qt/widgets/edit_name_panel.cpp index 146ea445..64ba7cce 100644 --- a/app/src/qt/widgets/edit_name_panel.cpp +++ b/app/src/qt/widgets/edit_name_panel.cpp @@ -1,7 +1,7 @@ /* edit_name_panel.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/edit_name_panel.h b/app/src/qt/widgets/edit_name_panel.h index 9e88ec4a..a580a47d 100644 --- a/app/src/qt/widgets/edit_name_panel.h +++ b/app/src/qt/widgets/edit_name_panel.h @@ -1,7 +1,7 @@ /* edit_name_panel.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/edit_tags_panel.cpp b/app/src/qt/widgets/edit_tags_panel.cpp index e5ab5869..27393d90 100644 --- a/app/src/qt/widgets/edit_tags_panel.cpp +++ b/app/src/qt/widgets/edit_tags_panel.cpp @@ -1,7 +1,7 @@ /* edit_tags_panel.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/edit_tags_panel.h b/app/src/qt/widgets/edit_tags_panel.h index 650c4080..d900e855 100644 --- a/app/src/qt/widgets/edit_tags_panel.h +++ b/app/src/qt/widgets/edit_tags_panel.h @@ -1,7 +1,7 @@ /* edit_tags_panel.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -74,6 +74,9 @@ class EditTagsPanel : public QGroupBox ~EditTagsPanel(); QLineEdit* getLineEdit() const { return lineEdit; } + void setTagToFind(const std::string& tagAsText) { + lineEdit->setText(QString::fromStdString(tagAsText)); + } void clearTagList(); void refreshOntologyTags(); void refresh(const std::vector* noteTags); diff --git a/app/src/qt/widgets/importance_combo_box.cpp b/app/src/qt/widgets/importance_combo_box.cpp index 0ccfea00..45081b5f 100644 --- a/app/src/qt/widgets/importance_combo_box.cpp +++ b/app/src/qt/widgets/importance_combo_box.cpp @@ -1,7 +1,7 @@ /* importance_combo_box.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/importance_combo_box.h b/app/src/qt/widgets/importance_combo_box.h index a1b35fda..ce1071d7 100644 --- a/app/src/qt/widgets/importance_combo_box.h +++ b/app/src/qt/widgets/importance_combo_box.h @@ -1,7 +1,7 @@ /* importance_combo_box.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/labeled_edit_line_panel.cpp b/app/src/qt/widgets/labeled_edit_line_panel.cpp index f45c379b..6cf3fedd 100644 --- a/app/src/qt/widgets/labeled_edit_line_panel.cpp +++ b/app/src/qt/widgets/labeled_edit_line_panel.cpp @@ -1,7 +1,7 @@ /* labeled_edit_line_panel.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/labeled_edit_line_panel.h b/app/src/qt/widgets/labeled_edit_line_panel.h index da682280..aeb3606b 100644 --- a/app/src/qt/widgets/labeled_edit_line_panel.h +++ b/app/src/qt/widgets/labeled_edit_line_panel.h @@ -1,7 +1,7 @@ /* labeled_edit_line_panel.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/line_number_panel.cpp b/app/src/qt/widgets/line_number_panel.cpp index fd2c791f..d350bc0a 100644 --- a/app/src/qt/widgets/line_number_panel.cpp +++ b/app/src/qt/widgets/line_number_panel.cpp @@ -1,7 +1,7 @@ /* line_number_panel.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/line_number_panel.h b/app/src/qt/widgets/line_number_panel.h index 0ba275eb..2e46da66 100644 --- a/app/src/qt/widgets/line_number_panel.h +++ b/app/src/qt/widgets/line_number_panel.h @@ -1,7 +1,7 @@ /* line_number_panel.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/mf_widgets.cpp b/app/src/qt/widgets/mf_widgets.cpp index 6c02807a..7e5173e9 100644 --- a/app/src/qt/widgets/mf_widgets.cpp +++ b/app/src/qt/widgets/mf_widgets.cpp @@ -1,7 +1,7 @@ /* mf_widgets.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/mf_widgets.h b/app/src/qt/widgets/mf_widgets.h index 16b1267a..096fc3f4 100644 --- a/app/src/qt/widgets/mf_widgets.h +++ b/app/src/qt/widgets/mf_widgets.h @@ -1,7 +1,7 @@ /* mf_widgets.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/urgency_combo_box.cpp b/app/src/qt/widgets/urgency_combo_box.cpp index c9edf3a8..74b7cba4 100644 --- a/app/src/qt/widgets/urgency_combo_box.cpp +++ b/app/src/qt/widgets/urgency_combo_box.cpp @@ -1,7 +1,7 @@ /* urgency_combo_box.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/urgency_combo_box.h b/app/src/qt/widgets/urgency_combo_box.h index a816a190..7b6aa732 100644 --- a/app/src/qt/widgets/urgency_combo_box.h +++ b/app/src/qt/widgets/urgency_combo_box.h @@ -1,7 +1,7 @@ /* urgency_combo_box.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/app/src/qt/widgets/view_to_edit_buttons_panel.cpp b/app/src/qt/widgets/view_to_edit_buttons_panel.cpp index 20abac11..ccec0550 100644 --- a/app/src/qt/widgets/view_to_edit_buttons_panel.cpp +++ b/app/src/qt/widgets/view_to_edit_buttons_panel.cpp @@ -1,7 +1,7 @@ /* view_to_edit_buttons_panel.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,8 +22,9 @@ namespace m8r { using namespace std; -ViewToEditEditButtonsPanel::ViewToEditEditButtonsPanel(MfWidgetMode mode, QWidget* parent) - : QWidget(parent), +ViewToEditEditButtonsPanel::ViewToEditEditButtonsPanel( + MfWidgetMode mode, QWidget* parent +) : QWidget(parent), mode(mode) { layout = new QHBoxLayout{this}; @@ -51,7 +52,8 @@ ViewToEditEditButtonsPanel::ViewToEditEditButtonsPanel(MfWidgetMode mode, QWidge if(MfWidgetMode::OUTLINE_MODE == mode) { #ifdef __APPLE__ - toggleFullOPreviewButton = new QPushButton{tr("Full / Header Notebook Preview"), this}; + toggleFullOPreviewButton = new QPushButton{ + tr("Full / Header Notebook Preview"), this}; // IMPROVE editButton->setToolTip("⌘+P"); #else toggleFullOPreviewButton = new QPushButton{tr("Whole Notebook &Preview"), this}; @@ -62,6 +64,12 @@ ViewToEditEditButtonsPanel::ViewToEditEditButtonsPanel(MfWidgetMode mode, QWidge layout->addWidget(toggleFullOPreviewButton); } + + lastNoteButton = new QPushButton{"↓", this}; + layout->addWidget(lastNoteButton); + nextNoteButton = new QPushButton{"↑", this}; + layout->addWidget(nextNoteButton); + layout->addWidget(editButton); setLayout(layout); diff --git a/app/src/qt/widgets/view_to_edit_buttons_panel.h b/app/src/qt/widgets/view_to_edit_buttons_panel.h index 746e4308..03e2a12e 100644 --- a/app/src/qt/widgets/view_to_edit_buttons_panel.h +++ b/app/src/qt/widgets/view_to_edit_buttons_panel.h @@ -1,7 +1,7 @@ /* view_to_edit_buttons_panel.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -36,6 +36,8 @@ class ViewToEditEditButtonsPanel : public QWidget QPushButton* showOutlineHeaderButton; QPushButton* editButton; QPushButton* toggleFullOPreviewButton; + QPushButton* nextNoteButton; + QPushButton* lastNoteButton; // expert mode (no buttons) setting @ frontend bool expertMode; @@ -55,6 +57,8 @@ class ViewToEditEditButtonsPanel : public QWidget QPushButton* getShowOutlineHeaderButton() const { return showOutlineHeaderButton; } QPushButton* getEditButton() const { return editButton; } QPushButton* getFullOPreviewButton() const { return toggleFullOPreviewButton; } + QPushButton* getNextNoteButton() const { return nextNoteButton; } + QPushButton* getLastNoteButton() const { return lastNoteButton; } }; } diff --git a/app/test/qt/mindforger-gui-tests.pro b/app/test/qt/mindforger-gui-tests.pro index 92bcd2db..01555c61 100644 --- a/app/test/qt/mindforger-gui-tests.pro +++ b/app/test/qt/mindforger-gui-tests.pro @@ -1,6 +1,6 @@ # mindforger-gui-unit-tests.pro MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -91,7 +91,6 @@ HEADERS += \ ../../src/qt/note_view_model.h \ ../../src/qt/note_view_presenter.h \ ../../src/qt/note_view.h \ - ../../src/qt/note_edit_model.h \ ../../src/qt/note_edit_presenter.h \ ../../src/qt/look_n_feel.h \ ../../src/qt/html_delegate.h \ @@ -189,7 +188,6 @@ SOURCES += \ ../../src/qt/note_view_model.cpp \ ../../src/qt/note_view_presenter.cpp \ ../../src/qt/note_view.cpp \ - ../../src/qt/note_edit_model.cpp \ ../../src/qt/note_edit_presenter.cpp \ ../../src/qt/look_n_feel.cpp \ ../../src/qt/html_delegate.cpp \ diff --git a/appveyor.yml b/appveyor.yml index 759711ce..a4867e56 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ # appveyor.yml AppVeyor CI configuration file for MindForger # -# Copyright (C) 2016-2022 +# Copyright (C) 2016-2024 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -version: 1.53.{build} +version: 2.0.{build} skip_commits: files: @@ -36,9 +36,9 @@ platform: x64 # build Configuration, i.e. Debug, Release, etc. configuration: Release -cache: +cache: - c:\cache - - C:\Program Files\googletest-distribution + - C:\Program Files\googletest-distribution # check https://www.appveyor.com/docs/windows-images-software for updates install: @@ -47,9 +47,9 @@ install: - set PATH=%PATH%;%QT_DIR%\bin - set M8R_HOME=%APPVEYOR_BUILD_FOLDER% - if not exist c:\cache mkdir c:\cache -# on the image vcredist is in C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\14.16.27012 +# on the image vcredist is in C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\14.16.27012 - if not exist c:\cache\vcredist_x64.exe curl -LfSs -o c:\cache\vcredist_x64.exe https://aka.ms/vs/15/release/vc_redist.x64.exe - - if not exist "C:\Program Files\googletest-distribution" pushd %TEMP% && curl -LfSs -o gtest.zip https://github.com/google/googletest/archive/release-1.8.1.zip && 7z x gtest.zip && cd googletest-release-1.8.1 && mkdir build && cd build && cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES=Debug;Release -Dgtest_build_samples=OFF -Dgtest_build_tests=OFF -Dgmock_build_tests=OFF -Dgtest_force_shared_crt=ON .. && cmake --build . --config Debug -- /m && cmake -DBUILD_TYPE=Debug -P cmake_install.cmake && popd + - if not exist "C:\Program Files\googletest-distribution" pushd %TEMP% && curl -LfSs -o gtest.zip https://github.com/google/googletest/archive/release-1.8.1.zip && 7z x gtest.zip && cd googletest-release-1.8.1 && mkdir build && cd build && cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES=Debug;Release -Dgtest_build_samples=OFF -Dgtest_build_tests=OFF -Dgmock_build_tests=OFF -Dgtest_force_shared_crt=ON .. && cmake --build . --config Debug -- /m && cmake -DBUILD_TYPE=Debug -P cmake_install.cmake && popd before_build: - cd "%M8R_HOME%" @@ -59,13 +59,13 @@ before_build: build_script: - pushd "%M8R_HOME%\deps\cmark-gfm" && mkdir build && cd build && cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES=Debug;Release -DCMARK_TESTS=OFF -DCMARK_SHARED=OFF .. && cmake --build . --config Release -- /m && cmake --build . --config Debug -- /m && popd - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" - - cd "%M8R_HOME%" && qmake -r mindforger.pro && nmake + - cd "%M8R_HOME%" && qmake -r mindforger.pro "CONFIG+=mfnoccache" && nmake - windeployqt app\release\mindforger.exe --dir app\release\bin --no-compiler-runtime && "C:\Program Files (x86)\Inno Setup 5\iscc.exe" /Q /DVcRedistPath=c:\cache\vcredist_x64.exe build\windows\installer\mindforger-setup.iss # - if "%APPVEYOR_REPO_BRANCH%" equ "master" appveyor PushArtifact app\release\installer\mindforger-setup.exe - appveyor PushArtifact app\release\installer\mindforger-setup.exe before_test: - - pushd "%M8R_HOME%\lib\test" && qmake -r mindforger-lib-unit-tests.pro "CONFIG+=debug" "CONFIG+=mfdebug" "CONFIG+=mfunit" && nmake && popd + - pushd "%M8R_HOME%\lib\test" && qmake -r mindforger-lib-unit-tests.pro "CONFIG+=debug" "CONFIG+=mfdebug" "CONFIG+=mfunit" "CONFIG+=mfnoccache" && nmake && popd - if not exist c:\tmp mkdir c:\tmp test_script: @@ -80,7 +80,7 @@ test_script: Write-Output "Test exit code: $TestExitCode" if ($TestExitCode -ne 0) { Push-AppveyorArtifact mindforger-unit-tests.log -Type zip - throw "Exec: tests failed" + throw "Exec: tests failed" } on_finish: diff --git a/build/Makefile b/build/Makefile index ea7d355c..4fc3c1e4 100644 --- a/build/Makefile +++ b/build/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # MindForger thinking notebook # @@ -18,7 +18,11 @@ .DEFAULT_GOAL := help -MINDFORGER_VERSION := 1.54.0 +# +# variables +# + +MINDFORGER_VERSION := 2.0.0 MINDFORGER_RELEASE_BASE_DIR := /home/dvorka/p/mindforger/release MINDFORGER_RELEASE_DIR := $(MINDFORGER_RELEASE_BASE_DIR)/$(MINDFORGER_VERSION)-maker @@ -28,48 +32,91 @@ MF_MAKER_WORKING_DIR := $(MINDFORGER_RELEASE_BASE_DIR)/maker-at-work CLASS_NAME := "New_Class" # l10n language: en, cs MF_LANG := "en" +# Ubuntu distro: trusty xenial bionic focal jammy kinetic +DISTRO := "bionic" +# CPU cores thant can be used to build the project +CPU_CORES := 7 +# Qt version to be used by MindForger +# MF_QT_VERSION := 5.9.9 +MF_QT_VERSION := 5.15.2 + +# +# OS detection +# + +# uname returns the operating system name: Darwin, Linux, etc. +UNAME := $(shell uname) +ifeq ($(UNAME), Darwin) + # this sets QTDIR and PATH shell (!) and make environment variables on macOS + QTDIR := /Users/dvorka/Qt/$(MF_QT_VERSION)/clang_64 + PATH := /Users/dvorka/Qt/$(MF_QT_VERSION)/clang_64/bin:/Library/Developer/CommandLineTools/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:$(PATH) +endif + + +# +# targets +# + + +.PHONY: diagnostics +diagnostics: + @echo "MindForger diagnostics:" + @echo " MINDFORGER_VERSION: $(MINDFORGER_VERSION)" + @echo " MINDFORGER_RELEASE_DIR: $(MINDFORGER_RELEASE_DIR)" + @echo " MF_MAKER_WORKING_DIR: $(MF_MAKER_WORKING_DIR)" + @echo " CLASS_NAME: $(CLASS_NAME)" + @echo " MF_LANG: $(MF_LANG)" + @echo " DISTRO: $(DISTRO)" + @echo " CPU_CORES: $(CPU_CORES)" + @echo " PATH: ${PATH}" + @echo " QTDIR: ${QTDIR}" + + +.PHONY: help +help: ## make targets help + @echo "MindForger Swiss knife help:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ + | sort \ + | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -help: - @echo "MindForger maker help:" - @echo "git-subs-update update git submodules" - @echo "gen-lib-class generate lib C++ class skeleton: CLASS_NAME=My_Class" - @echo "gen-ui-class generate UI C++ class skeleton: CLASS_NAME=My_Class" - @echo "devenv-debian install development environment on Debian" - @echo "clean clean build artifacts" - @echo "build build MindForger binary" - @echo "l10n update and release localization strings: MF_LANG=en" - @echo "test-lib compile and run lib/ unit tests" - @echo "test-app compile and run app/ integration tests" - @echo "dist-all build all distributions" - @echo "dist-tarball build tarball distribution" - @echo "dist-deb build Debian distribution" - @echo "dist-rpm build .rpm package on Fedora" - @echo "dist-dmg build macOS Disk iMaGe .dmg package" - @echo "dist-debian-ppa create PPA for all Debian releases" - @echo "statistic show source code statistic" - @echo "doc-to-wiki mindforger-documentation to mindforger.wiki" - @echo "api-reference generate Doxygen documentation" - @echo "dev-install-local compile and install binary to ~/bin as MIND" .PHONY: clean -clean: - rm -vf ../app/mindforger +clean: ## clean build artifacts + rm -vf ../app/mindforger ../app/*.o rm -vf ../lib/libmindforger.a rm -vf ../lib/test/src/mindforger-lib-unit-tests cd .. && make clean cd ../lib/test && make clean + +.PHONY: clean-app +clean-app: + rm -vf ../app/mindforger + + .PHONY: git-subs-update -git-subs-update: +git-subs-update: ## update Git submodules + @echo "Initializing sub-modules with cmark-gfm and other dependencies..." cd .. && git submodule update --init --recursive + +../deps/cmark-gfm/build: git-subs-update + @echo "Building cmark-gfm and other dependencies..." + cd ../deps/cmark-gfm \ + && mkdir -p build && cd build \ + && cmake -DCMARK_TESTS=OFF -DCMARK_SHARED=OFF .. \ + && cmake --build . \ + ; cd ../../../build + + .PHONY: gen-lib-class -gen-lib-class: +gen-lib-class: ## generate lib C++ class skeleton: CLASS_NAME=My_Class @echo "Generating lib C++ class for name: $(CLASS_NAME)" ./make/gen-cpp-class.py $(CLASS_NAME) + .PHONY: gen-ui-class -gen-ui-class: +gen-ui-class: ## generate UI C++ class skeleton: CLASS_NAME=My_Class @echo "Generating UI C++ class for name: $(CLASS_NAME)" ./make/gen-cpp-ui-class.py $(CLASS_NAME) @@ -77,59 +124,167 @@ gen-ui-class: devenv-debian: sudo apt-get install build-essential zlib1g-dev libhunspell-dev libqt5webkit5-dev qttools5-dev-tools ccache cmake debhelper -build: clean - cd .. && qmake -r mindforger.pro && make -j 7 +# +# build +# + + +../Makefile: + @echo "Generating Makefile..." + cd .. && qmake -r mindforger.pro ; cd build + + +../app/mindforger: ../Makefile + @echo "Building PRODUCTION MindForger executable..." + cd .. && make -j $(CPU_CORES) ; cd build @echo "If build succeeded, then MindForger executable can be found in:\n app/mindforger" ls -al ../app/mindforger -build-ci: clean + +build: clean-app ../app/mindforger ## build production MindForger application binary + ls -al ../app/mindforger + + +.PHONY: build-dev +build-dev: clean-app ## build development MindForger application binary + @echo "Building DEV MindForger executable..." + cd .. && qmake -r mindforger.pro DEFINES+=DO_MF_DEBUG && make -j $(CPU_CORES) ; cd .. +ifeq ($(UNAME), Darwin) + @echo "\nIf build succeeded, then MindForger executable can be found in:\n app/mindforger.app/Contents/MacOS/mindforger" + ls -al ../app/mindforger.app/Contents/MacOS/mindforger +else + @echo "\nIf build succeeded, then MindForger executable can be found in:\n app/mindforger" + ls -al ../app/mindforger +endif + + +.PHONY: build-rc +build-rc: clean-app ## build RC MindForger application binary + @echo "MindForger RC build..." + cd .. && qmake CONFIG+=mfrc -r mindforger.pro && make -j $(CPU_CORES) + @echo "If RC build succeeded, then MindForger executable can be found in:\n app/mindforger" + ls -al ../app/mindforger + + +.PHONY: build-ci +build-ci: clean-app ## build CI MindForger application binary @echo "MindForger CI build..." - cd .. && qmake CONFIG+=mfci -r mindforger.pro && make -j 7 + cd .. && qmake CONFIG+=mfci -r mindforger.pro && make -j $(CPU_CORES) @echo "If CI build succeeded, then MindForger executable can be found in:\n app/mindforger" ls -al ../app/mindforger -.PHONY: l10n -l10n: + +# +# run +# + + +run: ../app/mindforger ## run production MindForger + # cd ../app && pwd && ./mindforger + cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/library-trainer + # cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/computer-hw.md + # cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/bug-copy-image + + +run-rc: build-rc ## run MindForger RC build + cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/library-trainer + + +run-ci: build-ci ## run MindForger CI build + cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/library-trainer + + +run-dev: build-dev ## run MindForger development build +ifeq ($(UNAME), Darwin) + cd ../app/mindforger.app/Contents/MacOS && ./mindforger /Users/dvorka/mf-devel/mf-copy +else + cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/library-trainer + # cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/computer-hw.md + # cd ../app && pwd && ./mindforger /home/dvorka/mf-devel/bug-copy-image +endif + +# +# install +# + + +.PHONY: devenv-debian +devenv-debian: + sudo apt-get install build-essential zlib1g-dev libcurl4-gnutls-dev libhunspell-dev libqt5webkit5-dev qttools5-dev-tools ccache cmake debhelper + + +install-dev-local: ../deps/cmark-gfm/build ../Makefile ../lib/tests/Makefile clean build-rc ## install MindForger RC build to ~/bin as 'mind' executable + cp -vf ../app/mindforger ~/bin + mv -vf ~/bin/mindforger ~/bin/mind + ~/bin/mind --version + + +# +# tools +# + + +.PHONY: localization +localization: ## update and release localization strings: MF_LANG=en cd make && ./l10n-update-strings.sh && ./l10n-edit-and-release.sh $(MF_LANG) -test-lib: clean + +.PHONY: ver-find +ver-find: ## pre-version update finder + cd .. && git grep -n "1\.55" + + +../lib/tests/Makefile: + @echo "Generating lib test Makefile..." + cd ../lib/test && qmake -r mindforger-lib-unit-tests.pro ; cd ../../build + + +test-lib: clean ## compile and run lib/ unit tests cd make && ./test-lib-units.sh + .PHONY: dist-work-clean dist-work-clean: rm -rvf $(MF_MAKER_WORKING_DIR) + $(MF_MAKER_WORKING_DIR): mkdir -vp $(MF_MAKER_WORKING_DIR) + $(MINDFORGER_RELEASE_DIR): mkdir -v $(MINDFORGER_RELEASE_DIR) || echo "$(MINDFORGER_RELEASE_DIR) already exists" -dist-tarball: dist-work-clean $(MF_MAKER_WORKING_DIR) $(MINDFORGER_RELEASE_DIR) + +dist-tarball: dist-work-clean $(MF_MAKER_WORKING_DIR) $(MINDFORGER_RELEASE_DIR) ## build tarball distribution @echo "Building TARBALL distribution..." mkdir -vp $(MF_MAKER_WORKING_DIR) cp -vf ./tarball/tarball-build.sh $(MF_MAKER_WORKING_DIR) && cd $(MF_MAKER_WORKING_DIR) && ./tarball-build.sh cp -vf $(MF_MAKER_WORKING_DIR)/`cd $(MF_MAKER_WORKING_DIR) && ls -d mindforger*`/mindforger_$(MINDFORGER_VERSION)_tarball.tgz $(MINDFORGER_RELEASE_DIR) -dist-deb: dist-work-clean $(MF_MAKER_WORKING_DIR) $(MINDFORGER_RELEASE_DIR) + +dist-deb: dist-work-clean $(MF_MAKER_WORKING_DIR) $(MINDFORGER_RELEASE_DIR) ## build Debian distribution @echo "Building DEB distribution..." mkdir -vp $(MF_MAKER_WORKING_DIR) cp -vf ./debian/debian-make-deb.sh $(MF_MAKER_WORKING_DIR) && cd $(MF_MAKER_WORKING_DIR) && ./debian-make-deb.sh cp -vf $(MF_MAKER_WORKING_DIR)/`cd $(MF_MAKER_WORKING_DIR) && ls -d mindforger*`/mindforger_$(MINDFORGER_VERSION)-1_amd64.deb $(MINDFORGER_RELEASE_DIR) + .PHONY: dist-rpm -dist-rpm: +dist-rpm: ## build .rpm package on Fedora @echo "IMPORTANT: this target MUST be run on Fedora!" cd fedora && ./fedora-distro-setup.sh @echo "Building .rpm package..." cp -vf ./fedora-rpm-from-deb.sh ~/alien && cd ~/alien && sudo ./fedora-rpm-from-deb.sh $(MINDFORGER_VERSION) @echo "Find .rpm in ~/alien directory" + .PHONY: dist-dmg -dist-dmg: +dist-dmg: ## build macOS Disk iMaGe .dmg package @echo "Building .dmg package..." cd macos && ./mindforger-build.sh && ./dmg-package-build.sh + # # Debian # @@ -140,7 +295,7 @@ dist-dmg: # # - aptly CANNOT be used to build one PPA for all Debian releases # therefore every release has it's own PPA -# +# # - the structure looks like this (from deprecated debian/ to new debian-ppa/): # # https://www.mindforger.com/debian-ppa/ @@ -155,7 +310,7 @@ dist-dmg: # index.html ... created by me w/ how to set it up # # - source Debian packages for every version (which are used by aptly) -# are stored in +# are stored in # # ~/p/mindforger/debian/aptly/ # hstr/ @@ -177,38 +332,57 @@ dist-dmg: # obsolete repos: jessie-main .PHONY: dist-debian-ppa -dist-debian-aptly-create-ppa: +dist-debian-aptly-create-ppa: ## create Debian PPA for current Debian release: DISTRO=bullseye cd ./build/debian && ./debian-ppa-aptly-build.sh # # ^ Debian # + +.PHONY: dist-ubuntu-deb +dist-ubuntu-deb: ## locally build .deb for any Ubuntu version: DISTRO=bionic + @echo "Building Ubuntu $(DISTRO) .deb ..." + @echo "Copying latest version of .sh script to launchpad/ ..." + @echo "Running .sh script ..." + @echo "Copying .deb from build area to the current directory ..." + false + + +.PHONY: dist-snap +dist-snap: ## build snap distro for snapcraft.io + @echo "Building Snap ..." + cd .. && make clean && cd build + cp -vf snap/snapcraft.yaml .. && cd .. && snapcraft clean && snapcraft --debug + + +.PHONY: dist-wip +dist-snap-wip: # debug Snap build w/o clean up, but w/ incremental build + @echo "Building Snap ..." + cp -vf snap/snapcraft.yaml .. && cd .. && snapcraft --debug + + .PHONY: dist-all-clean dist-all-clean: rm -rvf $(MINDFORGER_RELEASE_DIR) -.PHONY: dist-all -dist-all: dist-all-clean $(MINDFORGER_RELEASE_DIR) dist-tarball dist-deb + +dist-all: dist-all-clean $(MINDFORGER_RELEASE_DIR) dist-tarball dist-deb ## build all distributions @echo "Building all $(MINDFORGER_VERSION) distributions" + .PHONY: statistic -statistic: +statistic: ## show source code statistic cd make && ./statistic.sh + .PHONY: doc-to-wiki -doc-to-wiki: +doc-to-wiki: ## mindforger-documentation to mindforger.wiki cd doc && ./mf-doc-to-wiki.py -.PHONY: api-reference -api-reference: - cd doxygen && doxygen ./mindforger.cfg - -# private development targets -dev-install-local: build-ci ../app/mindforger - cp -vf ../app/mindforger ~/bin - mv -vf ~/bin/mindforger ~/bin/mind - ~/bin/mind --version +.PHONY: doc-api-reference +api-reference: ## generate Doxygen source code documentation + cd doxygen && doxygen ./mindforger.cfg # eof diff --git a/build/build-win-app.bat b/build/build-win-app.bat index c12d275d..d2e093d4 100644 --- a/build/build-win-app.bat +++ b/build/build-win-app.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License @@ -41,7 +41,7 @@ nmake if "%ERRORLEVEL%" neq "0" goto :err echo =================================================== -echo MindForger application has been built successfully +echo MindForger application has been built successfully echo ================================================== goto :end :err diff --git a/build/build-win-cmake.bat b/build/build-win-cmake.bat index 8c80e041..6d95c455 100644 --- a/build/build-win-cmake.bat +++ b/build/build-win-cmake.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License @@ -47,7 +47,7 @@ echo ==================================== cmake --build . --config Debug -- /m if "%ERRORLEVEL%" neq "0" goto :err echo ==================================== -echo cmark-gfm has been built successfully +echo cmark-gfm has been built successfully echo ==================================== goto :end :err diff --git a/build/build-win-installer.bat b/build/build-win-installer.bat index f6f32009..f2207818 100644 --- a/build/build-win-installer.bat +++ b/build/build-win-installer.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License diff --git a/build/build-win-unit-tests.bat b/build/build-win-unit-tests.bat index 3810f600..f9811d70 100644 --- a/build/build-win-unit-tests.bat +++ b/build/build-win-unit-tests.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License @@ -32,17 +32,17 @@ echo ==================================== echo Generating MindForger unit test build files echo ==================================== cd "%MF_BASE%\lib\test" -qmake -r mindforger-lib-unit-tests.pro "CONFIG+=debug" "CONFIG+=mfdebug" +qmake -r mindforger-lib-unit-tests.pro "CONFIG+=debug" "CONFIG+=mfdebug" if "%ERRORLEVEL%" neq "0" goto :err echo ==================================== -echo Building MindForger unit tests +echo Building MindForger unit tests echo ==================================== nmake if "%ERRORLEVEL%" neq "0" goto :err echo ==================================== -echo MindForger unit tests has been built successfully +echo MindForger unit tests has been built successfully echo ==================================== goto :end :err diff --git a/build/debian/debian-aptly-add-deb.sh b/build/debian/debian-aptly-add-deb.sh index 0a2830ef..dea5c5af 100755 --- a/build/debian/debian-aptly-add-deb.sh +++ b/build/debian/debian-aptly-add-deb.sh @@ -2,7 +2,7 @@ # # MindForger knowledge management tool # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -32,7 +32,7 @@ # See 'MindForger Release Guide#Debian and my PPA' notebook for detailed steps description... # .deb package to be added -export NEW_VERSION_NAME="1.53.0" +export NEW_VERSION_NAME="2.0.0" export NEW_RELEASE_NAME="mindforger_${NEW_VERSION_NAME}" export NEW_DEB_NAME="${NEW_RELEASE_NAME}-1_amd64.deb" # Debian release ~ aptly publish diff --git a/build/debian/debian-make-deb.sh b/build/debian/debian-make-deb.sh index de495e01..fbdd89b2 100755 --- a/build/debian/debian-make-deb.sh +++ b/build/debian/debian-make-deb.sh @@ -2,7 +2,7 @@ # # MindForger knowledge management tool # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -41,7 +41,7 @@ fi # ############################################################################ function createChangelog() { - # Debian tooling changelog hints: + # Debian tooling changelog hints: # - signature line MUST have one whitespace prefix # - signature line MUST have double space between email and timestamp # - traling lines must have exactly one space @@ -93,7 +93,7 @@ function buildDebPackage() { # echo "This script must NOT be run if debug code is enabled - disable DO_M8R_DEBUG first" # exit 1 #fi - + # # 1) create upstream tarball # @@ -103,7 +103,7 @@ function buildDebPackage() { cd ${MFBUILD}/${MF} # copy project files to current directory cp -rvf ${MFSRC}/* ${MFSRC}/*.* . - + # 1.2) prune MindForger project source: tests, *.o/... build files, ... echo -e "\n# MF project cleanup ########################################" rm -vrf ./.git ./app/mindforger ./build ./app/test ./lib/test @@ -112,13 +112,13 @@ function buildDebPackage() { # 1.3) generate makefiles (will be used later to build binary) qmake -r mindforger.pro - + # 1.4) create tar archive createTarball # # 2) create source deb - # + # # 2.1) add Debian control files cp -rvf ${MFSRC}/build/debian/debian . createChangelog ./debian/changelog @@ -129,7 +129,7 @@ function buildDebPackage() { echo "OK: GPG agent running." else gpg-agent --daemon - fi + fi DEBEMAIL="martin.dvorak@mindforger.com" DEBFULLNAME="Martin Dvorak" @@ -142,7 +142,7 @@ function buildDebPackage() { # # 3) create source deb - # + # # 3.1) build deb # build source deb package dpkg-buildpackage -S @@ -153,7 +153,7 @@ function buildDebPackage() { # # Main # # ############################################################################ -export ARG_VERSION="1.54.0" +export ARG_VERSION="2.0.0" export ARG_BAZAAR_MSG="MindForger ${ARG_VERSION} release." # Debian releases: https://www.debian.org/releases/ diff --git a/build/debian/debian-mentors-upload.sh b/build/debian/debian-mentors-upload.sh index e5fff508..e995eacc 100755 --- a/build/debian/debian-mentors-upload.sh +++ b/build/debian/debian-mentors-upload.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/debian/debian-ppa-aptly-build.sh b/build/debian/debian-ppa-aptly-build.sh index a367e7cf..b07ec64e 100755 --- a/build/debian/debian-ppa-aptly-build.sh +++ b/build/debian/debian-ppa-aptly-build.sh @@ -46,18 +46,18 @@ export MF_IN_DEB_PACKAGES_DIR="/home/dvorka/p/mindforger/debian/aptly" # ^ must have the following structure: #. #├── hstr -#│   └── 09-stretch -#│   ├── hstr_1.27.0-1_amd64.deb -#│   ├── hstr_2.0.0-1_amd64.deb -#│   └── hstr_2.4.0-1_amd64.deb +#│ └── 09-stretch +#│ ├── hstr_1.27.0-1_amd64.deb +#│ ├── hstr_2.0.0-1_amd64.deb +#│ └── hstr_2.4.0-1_amd64.deb #└── mindforger # ├── 09-stretch -# │   ├── mindforger_1.42.0-1_amd64.deb -# │   ├── ... -# │   └── mindforger_1.53.0-1_amd64.deb +# │ ├── mindforger_1.42.0-1_amd64.deb +# │ ├── ... +# │ └── mindforger_1.53.0-1_amd64.deb # ├── ... # └── 13-trixie -#    └── mindforger_1.54.0-1_amd64.deb +# └── mindforger_1.54.0-1_amd64.deb # export MF_OUT_PPA_ALL_DEBIAN_RELEASES_DIR="/home/dvorka/p/mindforger/debian/debian-ppa.mindforger.com" # ^ PPAs for all releases side-by-side diff --git a/build/debian/debian/changelog b/build/debian/debian/changelog index 05cbaf03..afadb9da 100644 --- a/build/debian/debian/changelog +++ b/build/debian/debian/changelog @@ -1,6 +1,6 @@ -mindforger (1.54.0-1) unstable; urgency=low - +mindforger (2.0.0-1) unstable; urgency=low + * Initial New features. - - -- Martin Dvorak (Dvorka) Sat, 1 Jan 2022 14:11:33 +0100 + + -- Martin Dvorak (Dvorka) Sat, 1 Jan 2024 14:11:33 +0100 diff --git a/build/debian/debian/control b/build/debian/debian/control index a005a403..185e5f6e 100644 --- a/build/debian/debian/control +++ b/build/debian/debian/control @@ -2,7 +2,7 @@ Source: mindforger Section: utils Priority: optional Maintainer: Martin Dvorak -Build-Depends: debhelper (>= 8.0.0), build-essential, ccache, zlib1g-dev, libhunspell-dev, qt5-qmake, qtbase5-dev, libqt5webkit5-dev +Build-Depends: debhelper (>= 8.0.0), build-essential, ccache, zlib1g-dev, libcurl4-gnutls-dev, libhunspell-dev, qt5-qmake, qtbase5-dev, libqt5webkit5-dev Standards-Version: 3.9.5 Homepage: https://github.com/dvorka/mindforger Vcs-Git: https://github.com/dvorka/mindforger.git @@ -13,5 +13,5 @@ Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Thinking notebook and Markdown IDE. Search, browse, view and edit your Markdown files. Get as much - as possible from knowledge in your remarks. + as possible from the knowledge in your remarks. Tag: implemented-in::c++, interface::graphical, role::program \ No newline at end of file diff --git a/build/debian/debian/copyright b/build/debian/debian/copyright index 4a130cd6..42e95756 100644 --- a/build/debian/debian/copyright +++ b/build/debian/debian/copyright @@ -3,7 +3,7 @@ Upstream-Name: mindforger Source: https://github.com/dvorka/mindforger Files: debian/* -Copyright: 2016-2022 Martin Dvorak +Copyright: 2016-2024 Martin Dvorak License: GPL-2+ MindForger is licensed under GNU GPL version 2 or any later version. . diff --git a/build/doc/mf-doc-to-wiki.py b/build/doc/mf-doc-to-wiki.py index dc27b30f..9ce7f448 100755 --- a/build/doc/mf-doc-to-wiki.py +++ b/build/doc/mf-doc-to-wiki.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2023 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -76,6 +76,7 @@ def md_to_wiki_file(md_file_path: str, wiki_file_path: str): wiki_out.writelines(data[1:] if not is_blacklisted else data) print(" CONVERT" if not is_blacklisted else " COPY") +FILE_PATCH_FOOTER = "_Footer.md" def doc_to_wiki(doc_mf_repo_path: str, wiki_repo_path: str): if not os.path.isdir(doc_mf_repo_path): @@ -95,14 +96,34 @@ def doc_to_wiki(doc_mf_repo_path: str, wiki_repo_path: str): ) = gather_documentation_file_paths(doc_mf_repo_path) paths_to_copy: list = image_paths.copy() + paths_to_patch: list = [] print(f"Converting {len(md_paths_to_convert)} files:") for md_path in md_paths_to_convert: + wiki_file_path = md_path.replace(doc_mf_repo_memory_path, wiki_repo_path) + + # files to patch + if FILE_PATCH_FOOTER in wiki_file_path: + paths_to_patch.append(wiki_file_path) + md_to_wiki_file( md_file_path=md_path, - wiki_file_path=md_path.replace(doc_mf_repo_memory_path, wiki_repo_path), + wiki_file_path=wiki_file_path, ) + print(f"Patching {len(paths_to_patch)} files:") + for p in paths_to_patch: + print(f" {p}") + if FILE_PATCH_FOOTER in p: + with open(p, "r") as file: + filedata = file.read() + filedata = filedata.replace( + "master/CREDITS", + "master/CREDITS.md", + ) + with open(p, "w") as file: + file.write(filedata) + print(f"Copying {len(paths_to_copy)} files:") for p in paths_to_copy: print(f" {p}") @@ -116,9 +137,19 @@ def doc_to_wiki(doc_mf_repo_path: str, wiki_repo_path: str): print("Converting mindforger-documentation to mindforger.wiki:") home_path = os.path.expanduser("~") _doc_mf_repo_path = os.path.join( - home_path, "p/mindforger/git/mindforger-documentation" + home_path, + "p", + "mindforger", + "git", + "mindforger-documentation", + ) + _wiki_repo_path = os.path.join( + home_path, + "p", + "mindforger", + "git", + "mindforger.wiki", ) - _wiki_repo_path = os.path.join(home_path, "p/mindforger/git/mindforger.wiki") print(f" from: {_doc_mf_repo_path}") print(f" to : {_wiki_repo_path}") diff --git a/build/docker/dockerized-mindforger-run.sh b/build/docker/dockerized-mindforger-run.sh index a56d26a5..16ed1dc2 100755 --- a/build/docker/dockerized-mindforger-run.sh +++ b/build/docker/dockerized-mindforger-run.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/docker/dockerized-mindforger-start.sh b/build/docker/dockerized-mindforger-start.sh index 52e9f4a5..0a8df823 100755 --- a/build/docker/dockerized-mindforger-start.sh +++ b/build/docker/dockerized-mindforger-start.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/docker/mindforger/Dockerfile b/build/docker/mindforger/Dockerfile index 01a11aa2..653e3aea 100644 --- a/build/docker/mindforger/Dockerfile +++ b/build/docker/mindforger/Dockerfile @@ -1,6 +1,6 @@ # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -21,7 +21,7 @@ # Run MindForger image: # $ xhost +local:root && docker run -it --env="DISPLAY" --env="QT_X11_NO_MITSHM=1" --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" mindforger:latest mindforger -FROM ubuntu:16.04 +FROM ubuntu:18.04 MAINTAINER "Martin Dvorak" diff --git a/build/env.bat b/build/env.bat index 2313a78b..75e7bc38 100644 --- a/build/env.bat +++ b/build/env.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License @@ -27,7 +27,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary :: call Qt Development Environment Setup :: call "C:\software\Qt\5.12.0\msvc2017_64\bin\qtenv2.bat" call "C:\Qt\5.12.1\msvc2017_64\bin\qtenv2.bat" -:: set PATH to cmake and zlib +:: set PATH to cmake and zlib set "PATH=%PATH%;c:\Program Files\CMake\bin;%MF_BASE%\deps\zlib-win\lib" :: set path to Inno Setup 5 script compiler set "MF_ICSS=c:\Program Files (x86)\Inno Setup 5\ISCC.exe" diff --git a/build/fedora/fedora-distro-setup.sh b/build/fedora/fedora-distro-setup.sh index 2952f0cf..3ed7bdd6 100755 --- a/build/fedora/fedora-distro-setup.sh +++ b/build/fedora/fedora-distro-setup.sh @@ -2,7 +2,7 @@ # # MindForger knowledge management tool # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/fedora/fedora-rpm-from-deb.sh b/build/fedora/fedora-rpm-from-deb.sh index 780bc200..7092a7ff 100755 --- a/build/fedora/fedora-rpm-from-deb.sh +++ b/build/fedora/fedora-rpm-from-deb.sh @@ -2,7 +2,7 @@ # # MindForger knowledge management tool # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -31,7 +31,7 @@ echo "===============================================================" if [[ -z "${1}" ]] then - export MFVERSION="1.54.0" + export MFVERSION="2.0.0" else export MFVERSION="${1}" fi @@ -68,7 +68,7 @@ cd ${MFPRJNAME} export MFRPMROOT=`pwd` # bin build -# --target=x86_64 +# --target=x86_64 # --target=i386 rpmbuild --target=x86_64 --buildroot ${MFRPMROOT}/ -bb ${MFPRJNAME}-2.spec # noarch would be for SOURCE deb diff --git a/build/macos/cmark-gfm-build.sh b/build/macos/cmark-gfm-build.sh index 3a372f28..cf510251 100755 --- a/build/macos/cmark-gfm-build.sh +++ b/build/macos/cmark-gfm-build.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/macos/dmg-package-build.sh b/build/macos/dmg-package-build.sh index b4c21219..5ad6b1b3 100755 --- a/build/macos/dmg-package-build.sh +++ b/build/macos/dmg-package-build.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/macos/env.sh b/build/macos/env.sh index 9eeb7cee..d85401ae 100644 --- a/build/macos/env.sh +++ b/build/macos/env.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,15 +17,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -export MINDFORGER_VERSION="1.54.0" +export MINDFORGER_VERSION="2.0.0" # aligned with Ubuntu 18.4 -export QT_VERSION="5.9.9" +# export QT_VERSION="5.9.9" # MindForger 1.52.0 released for macOS Qt version # export QT_VERSION="5.11.0" -# BUG: unable to set security - images are NOT loaded with Qt 5.15.2 -# export QT_VERSION="5.15.2" - +# Qt 5.15.2 is LTS & works well on macOS BigSur 11.6 +export QT_VERSION="5.15.2" export PATH="/Users/dvorka/Qt/${QT_VERSION}/clang_64/bin":${PATH} diff --git a/build/macos/mindforger-build.sh b/build/macos/mindforger-build.sh index 9c65e30e..68f86ae0 100755 --- a/build/macos/mindforger-build.sh +++ b/build/macos/mindforger-build.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/check-n-fix-codestyle.py b/build/make/check-n-fix-codestyle.py index 572324a1..551ce4c5 100755 --- a/build/make/check-n-fix-codestyle.py +++ b/build/make/check-n-fix-codestyle.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -91,9 +91,9 @@ 'mindforger/licenses/hoedown-license.txt', } -COPYRIGHT_CPP = 'Copyright (C) 2016-2022 Martin Dvorak ' -COPYRIGHT_PYTHON = '# Copyright (C) 2016-2022 Martin Dvorak ' -COPYRIGHT_XML = '' +COPYRIGHT_CPP = 'Copyright (C) 2016-2024 Martin Dvorak ' +COPYRIGHT_PYTHON = '# Copyright (C) 2016-2024 Martin Dvorak ' +COPYRIGHT_XML = '' ESC_LIGHT_RED = '' ESC_LIGHT_GREEN = '' @@ -127,7 +127,7 @@ def loadFiles(self): def validate(self): self.validateFiles() self.showReport() - + def validateFiles(self): sys.stdout.write('Checking H/CPP source files') for f in self.cppFiles.keys(): @@ -151,9 +151,9 @@ def fixTrailingSpaces(self): #for f in self.pythonFiles.keys(): # self.pythonFiles[f].validate(self.report) #print '' - + def showReport(self): - reportEntries = 0 + reportEntries = 0 if len(self.report) == 0: print '\nMindForger Code Style Checker finished:' print '{} [INFO] successfuly checked with no issues{}'.format(ESC_LIGHT_GREEN, ESC_NO_COLOR) @@ -174,7 +174,7 @@ def showReport(self): else: print "{}{}:{}".format(OPTION_FILE_AS_URIS,entry.filename,problem[1]) print '{}{}{}'.format(ESC_LIGHT_RED, problem[0], ESC_NO_COLOR) - elif problem[0].startswith(' [WARNING]'): + elif problem[0].startswith(' [WARNING]'): if OPTION_GCC: print "{}{}:{}:1 {}{}{}".format( OPTION_FILE_AS_URIS, @@ -209,14 +209,14 @@ def __init__(self, filename): def addWarning(self, problem, filename, line): sys.stdout.write(ESC_YELLOW) sys.stdout.write('.') - sys.stdout.write(ESC_NO_COLOR); + sys.stdout.write(ESC_NO_COLOR); sys.stdout.flush() self.addProblem(problem, filename, line); def addError(self, problem, filename, line): sys.stdout.write(ESC_LIGHT_RED) sys.stdout.write('.') - sys.stdout.write(ESC_NO_COLOR); + sys.stdout.write(ESC_NO_COLOR); sys.stdout.flush() self.addProblem(problem, filename, line); @@ -308,7 +308,7 @@ def validateContent(self, reportEntry): ############################################################################################# -if len(sys.argv)>1: +if len(sys.argv)>1: for a in sys.argv: if '--color' == a or '-c' == a: ESC_LIGHT_RED="" diff --git a/build/make/doc-mf-screenshot-size-window.sh b/build/make/doc-mf-screenshot-size-window.sh index 440509a7..6b4858f3 100755 --- a/build/make/doc-mf-screenshot-size-window.sh +++ b/build/make/doc-mf-screenshot-size-window.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/gen-64k-lines-test-md.py b/build/make/gen-64k-lines-test-md.py index 507b6e1d..89b5025a 100755 --- a/build/make/gen-64k-lines-test-md.py +++ b/build/make/gen-64k-lines-test-md.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/gen-cpp-class.py b/build/make/gen-cpp-class.py index 5b901204..7ab29a52 100755 --- a/build/make/gen-cpp-class.py +++ b/build/make/gen-cpp-class.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -27,7 +27,7 @@ TEMPLATE_HEADER_FILE = """/* {}.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -65,7 +65,7 @@ class {} TEMPLATE_CPP_FILE = """/* {}.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/build/make/gen-cpp-deletes.py b/build/make/gen-cpp-deletes.py index 2e6c8def..5fa233ff 100755 --- a/build/make/gen-cpp-deletes.py +++ b/build/make/gen-cpp-deletes.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/gen-cpp-menu.py b/build/make/gen-cpp-menu.py index 50997d30..cd9cf93c 100755 --- a/build/make/gen-cpp-menu.py +++ b/build/make/gen-cpp-menu.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/gen-cpp-ui-class.py b/build/make/gen-cpp-ui-class.py index f08a6b23..712da5df 100755 --- a/build/make/gen-cpp-ui-class.py +++ b/build/make/gen-cpp-ui-class.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -27,7 +27,7 @@ TEMPLATE_HEADER_FILE = """/* {}.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -69,7 +69,7 @@ class {} : public QObject TEMPLATE_CPP_FILE = """/* {}.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/build/make/gen-l10n.sh b/build/make/gen-l10n.sh index 1c80731c..e089206e 100755 --- a/build/make/gen-l10n.sh +++ b/build/make/gen-l10n.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/gen-qt-project.prefix b/build/make/gen-qt-project.prefix index 502d2198..871c4d32 100644 --- a/build/make/gen-qt-project.prefix +++ b/build/make/gen-qt-project.prefix @@ -1,6 +1,6 @@ # mindforger.pro MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/gen-qt-project.sh b/build/make/gen-qt-project.sh index 3f5fb268..16961278 100755 --- a/build/make/gen-qt-project.sh +++ b/build/make/gen-qt-project.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/l10n-edit-and-release.sh b/build/make/l10n-edit-and-release.sh index faa46a72..08438106 100755 --- a/build/make/l10n-edit-and-release.sh +++ b/build/make/l10n-edit-and-release.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -19,8 +19,8 @@ # Hints: # - nerd English is OOTB ~ strings in the source code -# - en ... user friendly English translation -# - cs ... user friendly Czech translation +# - en ... user friendly English translation +# - cs ... user friendly Czech translation MF_LANG="en" diff --git a/build/make/l10n-update-strings.sh b/build/make/l10n-update-strings.sh index 4302c3bd..e5a75d0f 100755 --- a/build/make/l10n-update-strings.sh +++ b/build/make/l10n-update-strings.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/make-demo-repo.sh b/build/make/make-demo-repo.sh index 877ae6f5..4a175c8f 100755 --- a/build/make/make-demo-repo.sh +++ b/build/make/make-demo-repo.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/make-mf-snapshot.sh b/build/make/make-mf-snapshot.sh index fb64e95b..95dbb513 100755 --- a/build/make/make-mf-snapshot.sh +++ b/build/make/make-mf-snapshot.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/make-qt-webengine.sh b/build/make/make-qt-webengine.sh index 3c0ba8fb..c7253d62 100755 --- a/build/make/make-qt-webengine.sh +++ b/build/make/make-qt-webengine.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/profile-gprof.sh b/build/make/profile-gprof.sh index 4e0edb2c..1b0ea824 100755 --- a/build/make/profile-gprof.sh +++ b/build/make/profile-gprof.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/replace-version-all-files.py b/build/make/replace-version-all-files.py index 8e8e9d33..45683726 100755 --- a/build/make/replace-version-all-files.py +++ b/build/make/replace-version-all-files.py @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -23,16 +23,16 @@ SEMANTIC_VERSION_FILES = [ "../../build/debian/debian-aptly-add-deb.sh", - # ^ export NEW_DEB="mindforger_1.53.0-1_amd64.deb" - # ^ export NEW_VERSION="1.53.0" + # ^ export NEW_DEB="mindforger_1.54.0-1_amd64.deb" + # ^ export NEW_VERSION="1.54.0" "../../build/debian/debian-make-deb.sh", - # ^ export ARG_VERSION="1.53.0" + # ^ export ARG_VERSION="1.54.0" "../../build/debian/debian/changelog", - # ^ mindforger (1.53.0-1) unstable; urgency=low + # ^ mindforger (1.54.0-1) unstable; urgency=low "../../build/fedora/fedora-rpm-from-deb.sh", - # ^ export MFVERSION="1.53.0" + # ^ export MFVERSION="1.54.0" "../../PAD.xml", - # ^ 1.54.0 + # ^ 1.54.0 "../../build/Makefile", # ^ MINDFORGER_VERSION := 1.54.0 "../../build/macos/env.sh", @@ -45,9 +45,11 @@ MINOR_VERSION_FILES = [ "../../lib/src/app_info.h", - # ^ #define MINDFORGER_VERSION_DWORD 1,54,0,2 + # ^ #define MINDFORGER_VERSION_DWORD 1,55,0,2 + # ^ #define MINDFORGER_VERSION_MINOR "55" ] + def replace_version( file_path: str, old_version: str, @@ -59,20 +61,21 @@ def replace_version( if data and old_version and new_version: print(f"Replacing {old_version} -> {new_version} in {file_path}") - + updated_data = data.replace(old_version, new_version) with open(file_path, 'w') as file: - data = file.write(updated_data) + file.write(updated_data) return raise FileNotFoundError(f"File {file_path} not found!") + def replace_files( file_paths: list, old_version: str, - new_version: str + new_version: str ): for file_path in file_paths: replace_version( @@ -81,24 +84,31 @@ def replace_files( new_version=new_version, ) + if __name__ == "__main__": old_major_version = "1" - old_minor_version = "53" + old_minor_version = "55" + new_major_version = "1" - new_minor_version = "54" + new_minor_version = "56" # common files replacement replace_files( file_paths=SEMANTIC_VERSION_FILES, old_version=f"{old_major_version}.{old_minor_version}.0", - new_version=f"{new_major_version}.{new_minor_version}.0", + new_version=f"{new_major_version}.{new_minor_version}.0", ) # special files replacement replace_version( file_path=MINOR_VERSION_FILES[0], old_version=f"{old_major_version},{old_minor_version},0", - new_version=f"{new_major_version},{new_minor_version},0", + new_version=f"{new_major_version},{new_minor_version},0", ) -# eof + # special files replacement + replace_version( + file_path=MINOR_VERSION_FILES[0], + old_version=f"\"{old_minor_version}\"", + new_version=f"\"{new_minor_version}\"", + ) diff --git a/build/make/statistic.sh b/build/make/statistic.sh index 8ec950fe..6fa89e43 100755 --- a/build/make/statistic.sh +++ b/build/make/statistic.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/test-all.sh b/build/make/test-all.sh index dbeed638..5b0db175 100755 --- a/build/make/test-all.sh +++ b/build/make/test-all.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/test-autolinking.sh b/build/make/test-autolinking.sh index 004ea3f7..5b710a91 100755 --- a/build/make/test-autolinking.sh +++ b/build/make/test-autolinking.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/test-gui.sh b/build/make/test-gui.sh index 3024c5e4..0f9c0cef 100755 --- a/build/make/test-gui.sh +++ b/build/make/test-gui.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -24,7 +24,7 @@ #export OPTION_RECOMPILE=yes # recompile before running test(s) (comment this line to disable) #export OPTION_RUN_ALL_TESTS=yes # comment this line to disable export OPTION_TESTS="open-exit.sikuli" -export OPTION_TEST=open-exit.sikuli +export OPTION_TEST=open-exit.sikuli export M8R_TEST_APP_DIR="`pwd`/../../app/test/qt" export M8R_TEST_REPOSITORY="${HOME}/tmp/small-repository" @@ -55,7 +55,7 @@ then echo "Set M8R_SIKULIX_SCRIPTS_DIR env var to specify directory w/ MindForger's SikuliX scripts" exit 1 fi -if [ ${OPTION_RUN_VALGRIND} ] +if [ ${OPTION_RUN_VALGRIND} ] then export M8R_VALGRIND="valgrind --track-origins=yes --tool=memcheck --leak-check=full --show-leak-kinds=all" #export M8R_VALGRIND="valgrind -v --track-origins=yes --tool=memcheck --leak-check=full --show-leak-kinds=all" @@ -71,7 +71,7 @@ then exit 0 fi - + # Compile source w/ debug code enabled and various test libs linked to get test-ready binary # - use -g GCC option to get line information # Valgrind diff --git a/build/make/test-init-mf-repo-in-tmp.sh b/build/make/test-init-mf-repo-in-tmp.sh index de3702d4..b51ce2b5 100755 --- a/build/make/test-init-mf-repo-in-tmp.sh +++ b/build/make/test-init-mf-repo-in-tmp.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/test-l10n.sh b/build/make/test-l10n.sh index 4ac6c3a5..9c196578 100755 --- a/build/make/test-l10n.sh +++ b/build/make/test-l10n.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/make/test-lib-units.sh b/build/make/test-lib-units.sh index a0ff045e..525fff55 100755 --- a/build/make/test-lib-units.sh +++ b/build/make/test-lib-units.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -33,90 +33,95 @@ export OPTION_RECOMPILE=yes # recompile before running test(s) (comment this lin #export OPTION_TEST="MarkdownParserBenchmark.ParserMeta" # tests -#export OPTION_TEST="AutolinkingCmarkTestCase.Monster" + +#export OPTION_TEST="AiNlpTestCase.*" +#export OPTION_TEST="AiNlpTestCase.AaRepositoryBow" +#export OPTION_TEST="AiNlpTestCase.AaUniverseBow" +#export OPTION_TEST="AiNlpTestCase.Lexicon" +#export OPTION_TEST="AiNlpTestCase.Outline" +#export OPTION_TEST="AiNlpTestCase.Stemmer" +#export OPTION_TEST="AiNlpTestCase.Tokenizer" #export OPTION_TEST="AutolinkingCmarkTestCase.*" -#export OPTION_TEST="AutolinkingCmarkTestCase.CmarkAstRowWalker" #export OPTION_TEST="AutolinkingCmarkTestCase.CmarkAstBlockTransformer" -#export OPTION_TEST="AutolinkingCmarkTestCase.NanoRepo" +#export OPTION_TEST="AutolinkingCmarkTestCase.CmarkAstRowWalker" #export OPTION_TEST="AutolinkingCmarkTestCase.MicroRepo" +#export OPTION_TEST="AutolinkingCmarkTestCase.Monster" +#export OPTION_TEST="AutolinkingCmarkTestCase.NanoRepo" #export OPTION_TEST="AutolinkingTestCase.*" #export OPTION_TEST="AutolinkingTestCase.CrashAndBurn" -#export OPTION_TEST="FtsTestCase.*" -#export OPTION_TEST="TrieTestCase.*" -#export OPTION_TEST="TrieTestCase.AddAndRemove" -#export OPTION_TEST="FileGearTestCase.FilesystemPath" +#export OPTION_TEST="ConfigurationTestCase.*" +#export OPTION_TEST="ConfigurationTestCase.FromConstructor" +#export OPTION_TEST="ConfigurationTestCase.FromEnvironment" +#export OPTION_TEST="ConfigurationTestCase.Save*" +#export OPTION_TEST="ConfigurationTestCase.SaveAndLoad" +export OPTION_TEST="ConfigurationTestCase.SaveDefaultConfig" +#export OPTION_TEST="DateTimeGearTestCase.*" +#export OPTION_TEST="DateTimeGearTestCase.Immutability" #export OPTION_TEST="FileGearTestCase.DeepCopy" -#export OPTION_TEST="FileGearTestCase.DeepProductionCopy" #export OPTION_TEST="FileGearTestCase.DeepCopyToExisting" -#export OPTION_TEST="AiNlpTestCase.*" -#export OPTION_TEST="AiNlpTestCase.AaUniverseBow" -#export OPTION_TEST="AiNlpTestCase.AaRepositoryBow" -#export OPTION_TEST="AiNlpTestCase.Outline" -#export OPTION_TEST="AiNlpTestCase.Lexicon" -#export OPTION_TEST="AiNlpTestCase.Tokenizer" -#export OPTION_TEST="AiNlpTestCase.Stemmer" +#export OPTION_TEST="FileGearTestCase.DeepProductionCopy" +#export OPTION_TEST="FileGearTestCase.FilesystemPath" +#export OPTION_TEST="FilesystemInformationTestCase.IndexPdfs" +#export OPTION_TEST="FtsTestCase.*" #export OPTION_TEST="HtmlTestCase.*" +#export OPTION_TEST="HtmlTestCase.NoteLinks" #export OPTION_TEST="HtmlTestCase.Outline" #export OPTION_TEST="HtmlTestCase.TaskList" -#export OPTION_TEST="HtmlTestCase.NoteLinks" +#export OPTION_TEST="MarkdownParserBugsTestCase.*" +#export OPTION_TEST="MarkdownParserTestCase.*" #export OPTION_TEST="MarkdownParserTestCase.*" +#export OPTION_TEST="MarkdownParserTestCase.Bug37Notrailing" #export OPTION_TEST="MarkdownParserTestCase.Bug622Loop64kLinesOverflow" -#export OPTION_TEST="MarkdownParserTestCase.Links" -#export OPTION_TEST="MarkdownParserTestCase.TimeScope" #export OPTION_TEST="MarkdownParserTestCase.Deadline" +#export OPTION_TEST="MarkdownParserTestCase.Links" +#export OPTION_TEST="MarkdownParserTestCase.LinksWithParenthesis" +#export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerLinks" #export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerSections" -#export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerSectionsPreamble" #export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerSectionsNoMetadata" #export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerSectionsPostDeclaredHeaders" #export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerSectionsPostDeclaredHeaders2" +#export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerSectionsPreamble" #export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerTimeScope" -#export OPTION_TEST="MarkdownParserTestCase.MarkdownLexerLinks" -#export OPTION_TEST="MarkdownParserTestCase.*" #export OPTION_TEST="MarkdownParserTestCase.MarkdownParserSections" -#export OPTION_TEST="MarkdownParserTestCase.MarkdownParserSectionsPreamble" +#export OPTION_TEST="MarkdownParserTestCase.MarkdownParserSections" #export OPTION_TEST="MarkdownParserTestCase.MarkdownParserSectionsEmptyFirstLine" #export OPTION_TEST="MarkdownParserTestCase.MarkdownParserSectionsNoMetadata" -#export OPTION_TEST="MarkdownParserTestCase.MarkdownParserSections" -#export OPTION_TEST="MarkdownParserTestCase.MarkdownRepresentationPostDeclaredSection" -#export OPTION_TEST="MarkdownParserTestCase.MarkdownRepresentationTrailingHashesSection" +#export OPTION_TEST="MarkdownParserTestCase.MarkdownParserSectionsPreamble" #export OPTION_TEST="MarkdownParserTestCase.MarkdownRepresentationEmptyFirstLine" +#export OPTION_TEST="MarkdownParserTestCase.MarkdownRepresentationPostDeclaredSection" #export OPTION_TEST="MarkdownParserTestCase.MarkdownRepresentationPreamble" #export OPTION_TEST="MarkdownParserTestCase.MarkdownRepresentationSectionTrailingHashes" -#export OPTION_TEST="RepositoryIndexerTestCase.*" -export OPTION_TEST="RepositoryIndexerTestCase.RepositoryTypeDetection" -#export OPTION_TEST="RepositoryIndexerTestCase.MarkdownRepository" -#export OPTION_TEST="RepositoryIndexerTestCase.MindForgerRepository" -#export OPTION_TEST="RepositoryIndexerTestCase.MindForgerFile" -#export OPTION_TEST="RepositoryIndexerTestCase.MarkdownFile" -#export OPTION_TEST="RepositoryIndexerTestCase.MakePathRelative" +#export OPTION_TEST="MarkdownParserTestCase.MarkdownRepresentationTrailingHashesSection" +#export OPTION_TEST="MarkdownParserTestCase.TimeScope" +#export OPTION_TEST="MindTestCase.CommonWordsBlacklist" +#export OPTION_TEST="MindTestCase.LearnAmnesiaLearn" +#export OPTION_TEST="MindTestCase.LearnAndRememberMindForgerRepository" #export OPTION_TEST="NoteTestCase.*" -#export OPTION_TEST="NoteTestCase.MangleNoteName" #export OPTION_TEST="NoteTestCase.DeepUpDownFirstLastClone" +#export OPTION_TEST="NoteTestCase.DirectNoteChildren" +#export OPTION_TEST="NoteTestCase.MangleNoteName" #export OPTION_TEST="NoteTestCase.PromoteDemoteUpDownNote" #export OPTION_TEST="NoteTestCase.RefactorNote" -#export OPTION_TEST="NoteTestCase.DirectNoteChildren" -#export OPTION_TEST="MindTestCase.LearnAndRememberMindForgerRepository" -#export OPTION_TEST="MindTestCase.LearnAmnesiaLearn" -#export OPTION_TEST="MindTestCase.CommonWordsBlacklist" -#export OPTION_TEST="DateTimeGearTestCase.*" -#export OPTION_TEST="DateTimeGearTestCase.Immutability" -#export OPTION_TEST="ConfigurationTestCase.*" -#export OPTION_TEST="ConfigurationTestCase.SaveDefaultConfig" -#export OPTION_TEST="ConfigurationTestCase.FromConstructor" -#export OPTION_TEST="ConfigurationTestCase.FromEnvironment" -#export OPTION_TEST="ConfigurationTestCase.Save*" -#export OPTION_TEST="MarkdownParserTestCase.Bug37Notrailing" -#export OPTION_TEST="MarkdownParserBugsTestCase.*" -#export OPTION_TEST="OutlineTestCase.CloneOutline" -#export OPTION_TEST="OutlineTestCase.DirectOutlineNoteChildren" -#export OPTION_TEST="StringGearTestCase.Split" -#export OPTION_TEST="FilesystemInformationTestCase.IndexPdfs" #export OPTION_TEST="OrganizerTestCase.*" -#export OPTION_TEST="OrganizerTestCase.SerializeAndSplitTags" -#export OPTION_TEST="OrganizerTestCase.NoMindForgerRepositoryNoOrganizer" #export OPTION_TEST="OrganizerTestCase.DefaultOrganizerParseSaveAndLoad" +#export OPTION_TEST="OrganizerTestCase.NoMindForgerRepositoryNoOrganizer" #export OPTION_TEST="OrganizerTestCase.ParseSaveAndLoad" -#export OPTION_TEST="ConfigurationTestCase.SaveAndLoad" +#export OPTION_TEST="OrganizerTestCase.SerializeAndSplitTags" +#export OPTION_TEST="OutlineTestCase.CloneOutline" +#export OPTION_TEST="OutlineTestCase.DirectOutlineNoteChildren" +#export OPTION_TEST="RepositoryIndexerTestCase.*" +#export OPTION_TEST="RepositoryIndexerTestCase.MakePathRelative" +#export OPTION_TEST="RepositoryIndexerTestCase.MarkdownFile" +#export OPTION_TEST="RepositoryIndexerTestCase.MarkdownRepository" +#export OPTION_TEST="RepositoryIndexerTestCase.MindForgerFile" +#export OPTION_TEST="RepositoryIndexerTestCase.MindForgerRepository" +#export OPTION_TEST="RepositoryIndexerTestCase.RepositoryTypeDetection" +#export OPTION_TEST="StringGearTestCase.Split" +#export OPTION_TEST="StringGearTestCase.StringToNcName" +#export OPTION_TEST="TrieTestCase.*" +#export OPTION_TEST="TrieTestCase.AddAndRemove" +#export OPTION_TEST="JSonTestCase.SerializeOpenAiRequest" +#export OPTION_TEST="JSonTestCase.ParseOpenAiResponse" # environment - to be specified in .bashrc or elsewhere: # export M8R_CPU_CORES=7 @@ -133,9 +138,9 @@ then exit 1 fi -if [ ${OPTION_RUN_VALGRIND} ] +if [ ${OPTION_RUN_VALGRIND} ] then - if [ ${OPTION_RUN_GDB} ] + if [ ${OPTION_RUN_GDB} ] then export M8R_VALGRIND="valgrind --vgdb=yes --vgdb-error=0 --track-origins=yes --tool=memcheck --leak-check=full --show-leak-kinds=all" else @@ -143,8 +148,8 @@ then export M8R_VALGRIND="valgrind -v --track-origins=yes --tool=memcheck --leak-check=full --show-leak-kinds=all" fi else - export M8R_VALGRIND= - if [ ${OPTION_RUN_GDB} ] + export M8R_VALGRIND= + if [ ${OPTION_RUN_GDB} ] then export M8R_GDB="gdb --args" fi diff --git a/build/release/release-tgz-deb-rpm-exe.sh b/build/release/release-tgz-deb-rpm-exe.sh index 1aa615ab..fefb166d 100755 --- a/build/release/release-tgz-deb-rpm-exe.sh +++ b/build/release/release-tgz-deb-rpm-exe.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/run-win-app.bat b/build/run-win-app.bat index 0002beb7..6df26a74 100644 --- a/build/run-win-app.bat +++ b/build/run-win-app.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License diff --git a/build/run-win-unit-tests.bat b/build/run-win-unit-tests.bat index a40ac715..2102775f 100644 --- a/build/run-win-unit-tests.bat +++ b/build/run-win-unit-tests.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License diff --git a/build/snap/README.md b/build/snap/README.md deleted file mode 100644 index c12fbb39..00000000 --- a/build/snap/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Snap -Snap package to be implemented: - -* https://github.com/dvorka/mindforger/issues/100 - -How to package: - -* [ ] https://www.digitalocean.com/community/tutorials/how-to-package-and-publish-a-snap-application-on-ubuntu-18-04 - -Resources: - -* https://snapcraft.io/store - diff --git a/build/snap/snapcraft.yaml b/build/snap/snapcraft.yaml new file mode 100644 index 00000000..6133dc09 --- /dev/null +++ b/build/snap/snapcraft.yaml @@ -0,0 +1,84 @@ +name: mindforger +base: core18 # the base snap is the execution environment for this snap: core18 (18.04), core20 (20.04) +version: '2.0.0' # just for humans, typically '1.2+git' or '1.3.2' +summary: Thinking notebook and Markdown editor +description: | + Search, browse, view and edit your Markdown files. Get as much + as possible from the knowledge in your remarks with associations, + auto linking and powerful search options. + +grade: devel # must be 'stable' to release into candidate/stable channels: devel, stable +confinement: devmode # use 'strict' once you have the right plugs and slots: strict, devmode, classic +architectures: + - build-on: amd64 + +parts: + mindforger: + plugin: qmake + source: . # . or git@github.com:dvorka/mindforger.git + qt-version: qt5 + build-packages: + - libx11-xcb1 # fixes could not find or load the Qt platform plugin "xcb" in "" + - zlib1g-dev + - ccache + - libcurl4-gnutls-dev + - libhunspell-dev + - build-essential + - qtbase5-dev + - qt5-qmake + - libqt5webkit5-dev # WebKit is used @ Linux, WebEngine @ macOS/Win + - ttf-ubuntu-font-family # w/o fonts there are no menus/text in UI + - libvoikko-dev # reported as missing in the start-up log + stage-packages: # suggested by snapcraft build + - libbrotli1 + - libdouble-conversion1 + - libfreetype6 + - libgl1 + - libglvnd0 + - libglx0 + - libgraphite2-3 + - libgstreamer-plugins-base1.0-0 + - libgstreamer1.0-0 + - libharfbuzz0b + - libhunspell-1.6-0 + - libhyphen0 + - libicu60 + - libjpeg-turbo8 + - liborc-0.4-0 + - libpng16-16 + - libqt5core5a + - libqt5gui5 + - libqt5network5 + - libqt5positioning5 + - libqt5printsupport5 + - libqt5qml5 + - libqt5quick5 + - libqt5sensors5 + - libqt5webchannel5 + - libqt5webkit5 + - libqt5widgets5 + - libwebp6 + - libwoff1 + - libx11-6 + - libxau6 + - libxcb1 + - libxdmcp6 + - libxml2 + - libxslt1.1 + options: + - -r + - "CONFIG+=mfdebug" + +apps: + mindforger: + command: bin/mindforger + environment: + QT_DEBUG_PLUGINS: 1 + # # Qt's xcb plugin (X11 vs. Wayland) configuration + LD_LIBRARY_PATH: /usr/lib/x86_64-linux-gnu:${SNAP}/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/qt5/plugins/platforms # add path to dir w/ libqxcb.so + QT_PLUGIN_PATH: ${SNAP}/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/qt5/plugins + QT_QPA_PLATFORM_PLUGIN_PATH: ${SNAP}/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/qt5/plugins + # font configuration + FONTCONFIG_PATH: ${SNAP}/etc/fonts/conf.d + FONTCONFIG_FILE: ${SNAP}/etc/fonts/fonts.conf + plugs: [home, network] diff --git a/build/tarball/tarball-build.sh b/build/tarball/tarball-build.sh index 5f347bcd..a6688056 100755 --- a/build/tarball/tarball-build.sh +++ b/build/tarball/tarball-build.sh @@ -2,7 +2,7 @@ # # MindForger knowledge management tool # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -90,7 +90,7 @@ function buildGitHubTarball { #echo "This script must NOT be run if debug code is enabled - disable DO_MF_DEBUG first" #exit 1 #fi - + # # 1) create tarball # @@ -100,7 +100,7 @@ function buildGitHubTarball { cd ${MFBUILD}/${MF} # copy project files to current directory cp -rvf ${MFSRC}/* ${MFSRC}/*.* . - + # 1.2) prune MindForger project source: tests, *.o/... build files, ... echo -e "\n# MF project cleanup ########################################" rm -vrf ./.git ./app/mindforger ./build ./app/test ./lib/test @@ -119,7 +119,7 @@ function buildGitHubTarball { # # Main # # ############################################################################ -export ARG_VERSION="1.54.0" +export ARG_VERSION="2.0.0" export ARG_BAZAAR_MSG="MindForger ${ARG_VERSION} release." buildGitHubTarball "${ARG_VERSION}" "${ARG_BAZAAR_MSG}" ${1} diff --git a/build/travis-ci/.travis.yml b/build/travis-ci/.travis.yml index df0114ec..42333233 100644 --- a/build/travis-ci/.travis.yml +++ b/build/travis-ci/.travis.yml @@ -1,6 +1,6 @@ # .travis.yml Travis CI configuration file for MindForger # -# Copyright (C) 2014-2022 Martin Dvorak +# Copyright (C) 2014-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,12 +17,12 @@ os: - linux - + # Missing codecvt: upgrade from g++ 4.8 to 5 > MATRIX_EVAL sets CXX to g++-5 > qmake CONFIG and QMAKE_CXX sets it to build process matrix: include: - os: linux - addons: + addons: apt: sources: - ubuntu-toolchain-r-test @@ -40,7 +40,7 @@ dist: trusty # Travis CI provides Precise and Trusty only before_install: - sudo apt-get update -qq - "export DISPLAY=:99.0" - - "sh -e /etc/init.d/xvfb start" + - "sh -e /etc/init.d/xvfb start" - sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa - sudo apt-get update -qq - eval "${MATRIX_EVAL}" @@ -48,6 +48,7 @@ before_install: install: - sudo apt-get install -qq qtbase5-dev libqt5webkit5-dev - sudo apt-get install -qq qt5-default qttools5-dev-tools + - sudo apt-get install -qq libcurl4-gnutls-dev - sudo apt-get install -qq libhunspell-dev - sudo apt-get install -qq ccache - sudo apt-get install -qq libgtest-dev @@ -62,7 +63,7 @@ script: # make lib unit tests > run lib unit tests > make MF > install MF - cd "${M8RHOME}" - eval "${MATRIX_EVAL}" - cd deps/cmark-gfm && mkdir -v build && cd build && cmake -DCMARK_TESTS=OFF -DCMARK_SHARED=OFF .. && cmake --build . && cd ../../.. - - "echo \"M8RDEBUG: g++ compiler is set to: ${CXX}\"" + - "echo \"M8RDEBUG: g++ compiler is set to: ${CXX}\"" - cd lib/test # UNIT tests - qmake -r CONFIG+=mfnocxx CONFIG+=mfunits QMAKE_CXX=${CXX} mindforger-lib-unit-tests.pro - make diff --git a/build/ubuntu/WIP-ubuntu-launchpad-releases-from-mind.sh b/build/ubuntu/WIP-ubuntu-launchpad-releases-from-mind.sh deleted file mode 100755 index 1a09c1a7..00000000 --- a/build/ubuntu/WIP-ubuntu-launchpad-releases-from-mind.sh +++ /dev/null @@ -1,315 +0,0 @@ -#!/usr/bin/env bash -# -# MindForger knowledge management tool -# -# Copyright (C) 2016-2022 Martin Dvorak -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# This script builds: upstream tarball > source deb > binary deb -# -# See: -# Beginners guide: -# http://packaging.ubuntu.com/html/packaging-new-software.html -# Debian maintainers guide: -# https://www.debian.org/doc/manuals/maint-guide/index.en.html -# https://www.debian.org/doc/manuals/debmake-doc/index.en.html -# Debian formal doc: -# https://www.debian.org/doc/debian-policy/ -# - -# ############################################################################ -# # Checkout MindForger from bazaar, copy over new sources, clean result # -# ############################################################################ - -function checkoutMindforger { - # use `bzr` to manually check and work with Bazaar repository: - # - bzr ... get help - # - bzr status - # - bzr commit ... commints and PUSHES changes to server - - export MFSRC=$2 - # create new branch: bzr init && bzr push lp:~ultradvorka/+junk/mindforger - bzr checkout lp:~ultradvorka/+junk/mindforger - - # delete OLD files from Bazaar directory - cd mindforger - mv .bzr .. - rm -rvf app build deps lib man LICENSE *.md - mv ../.bzr . - - # copy NEW project files to Bazaar directory - echo -e "\n# copy over new MindForger files ############################" - cp -rvf ${MFSRC}/* ${MFSRC}/*.* . - - # prune MindForger project files: tests, *.o/... build files, ... - echo -e "\n# CLEANUP development and build artifacts ###################" - rm -vrf ./.git ./.qmake.stash ./app/mindforger ./build ./app/test ./lib/test - rm -vrf ./deps/cmark-gfm/.github - rm -vrf ./deps/mitie - rm -vrf ./lib/.qmake.stash ./lib/lib.pro.user ./lib/src/mindforger-lib-unit-tests - # IMPROVE: static libraries lib*.a are NOT deleted to keep cmark-gfm dependency libs - find . -type f \( -name "*moc_*.cpp" -or -name "*.o" -or -name "*.*~" -or -name ".gitignore" -or -name ".git" \) | while read F; do rm -vf $F; done - - cd .. -} - -# ############################################################################ -# # Create updated changelog # -# ############################################################################ - -function createChangelog { - export MYTS=`date "+%a, %d %b %Y %H:%M:%S"` - echo "Changelog timestamp: ${MYTS}" - echo "mindforger (${MFFULLVERSION}) ${UBUNTUVERSION}; urgency=low" > $1 - echo " " >> $1 - echo " * ${MFBZRMSG}" >> $1 - echo " " >> $1 - echo " -- Martin Dvorak (Dvorka) ${MYTS} +0100" >> $1 - echo "" >> $1 -} - -# ############################################################################ -# # Create upstream tarball in work/ # -# ############################################################################ - -function createTarball { - cd .. - mkdir work - cd work - cp -vrf ../${MF} . - rm -rvf ${MF}/.bzr - tar zcf ../${MF}.tgz ${MF} - # .orig.tar.gz is required Debian convention - cp -vf ../${MF}.tgz ../${MF}.orig.tar.gz - cd ../${MF} - - echo -e "\nMindForger TARBALL archives created using work/:\n mindforger_1.53.4.orig.tar.gz\n mindforger_1.53.4.tgz" -} - -# ############################################################################ -# # Patch qmake location (if needed) # -# ############################################################################ - -function patchQmakePathInMakefile { - MAKEFILE_PATH=${1} - echo "Patching qmake in Makefile: ${MAKEFILE_PATH}" - cat ${MAKEFILE_PATH} | while IFS= read L - do - if [[ "${L}" = "QMAKE = /usr/lib/qt5/bin/qmake" ]] - then - echo "QMAKE = /usr/bin/qmake" - else - echo "${L}" - fi - done > "${MAKEFILE_PATH}.new" - mv "${MAKEFILE_PATH}.new" ${MAKEFILE_PATH} -} - -# ############################################################################ -# # Release for *ONE* particular Ubuntu version # -# ############################################################################ - -function releaseForParticularUbuntuVersion { - export SCRIPTHOME=`pwd` - export UBUNTUVERSION=${1} - export MFVERSION=${2} - export MFBZRMSG=${3} - export MFFULLVERSION=${MFVERSION}-0ubuntu1 - export MF=mindforger_${MFVERSION} - export MFRELEASE=mindforger_${MFFULLVERSION} - export MFSRC=/home/dvorka/p/mindforger/git/mindforger - export NOW=`date +%Y-%m-%d--%H-%M-%S` - export MFBUILD=mindforger-${NOW} - - # 1) clean up - echo -e "\n# Cleanup ####################################################" - rm -rvf *.*~ ./debian - - # 2) checkout MindForger from Launchpad's bazaar to work directory (will be needed to build SOURCE .deb package) - echo -e "\n# Checkout MindForger from Launchpad's Bazaar ################" - mkdir ${MFBUILD} - cd ${MFBUILD} - checkoutMindforger ${MF} ${MFSRC} - - # 3) update Debian control files (changelog, descriptor, ...) in bzr clone - echo -e "\n# Building deb ###############################################" - cd mindforger && cp -rvf ${MFSRC}/build/ubuntu/debian . - createChangelog ./debian/changelog - - # 4) prepare MindForger dependencies/libraries - echo -e "\n---------------------------------------------------------------" - echo "4.1) build MF dependencies/libs: cmark-gfm, ..." - rm -rvf deps/cmark-gfm/build - cd deps/cmark-gfm && mkdir -v build && cd build && cmake -DCMARK_TESTS=OFF -DCMARK_SHARED=OFF .. && cmake --build . && cd ../../.. - - echo -e "\n---------------------------------------------------------------" - echo "4.2) Qt: generate Makefiles using qmake" - cd .. - mv mindforger ${MF} - cd ${MF} - # qt version MUST be specified as it CANNOT be configured by installing - # qt5-default package: Debian control file does NOT allow virtual packages - # like this qt5-default. Instead debian/rules file exports env var w/ Qt choice - # .pro file is also extended to have 'make install' target - qmake -r mindforger.pro - # PATCH optionally patch source files e.g. different Ubuntu distro specific paths - echo " PATCH files prior TARBALL in '`pwd`'" - #if [[ "xenial" = "${UBUNTUVERSION}" ]] - #then - patchQmakePathInMakefile "Makefile" - patchQmakePathInMakefile "app/Makefile" - patchQmakePathInMakefile "lib/Makefile" - patchQmakePathInMakefile "lib/src/Makefile" - #fi - - # xxx LATER - # xxx LATER - # xxx LATER - # 5) add new version to LOCAL Bazaar - #echo -e "\n# bazaar add & commit #######################################" - #bzr add . - # IMPORTANT: commit UPLOADs branch to server - #bzr commit -m "Update for ${MF} at ${NOW}." - - # 5) create tarball ~ .tgz archive w/ source and required Debian cfg files - echo -e "\n---------------------------------------------------------------" - echo -e "5.1) create TARBALL: prepare files to work/ directory" - createTarball - - # start GPG agent if it's NOT running - echo -e "\n---------------------------------------------------------------" - echo -e "5.2) GPG agent: start agent process if it is NOT running" - if [ -e "${HOME}/.gnupg/S.gpg-agent" ] - then - echo "OK: GPG agent running." - else - gpg-agent --daemon - fi - - # 6) build SOURCE .deb package - echo -e "\n# source & binary .deb packages ######################################" - echo -e "\n---------------------------------------------------------------" - echo -e "6.1) build SIGNED SOURCE .deb package on HOST system (not FAKEROOT build) using sources prepared by TARBALL in work/ directory" - pwd - # Build of SOURCE .deb package - # - build is made using Makefile(s) generated by qmake ABOVE - # - build is made using files prepared by TARBALL step in work/ directory - # - build is made on HOST system, NOT clean FAKEROOT system - # - build is made using `bzr builddeb` - # - toolchain: builddeb > debuild > dpkg-buildpackage (find documentation there) - # bzr builddeb -- -us -uc -j7 - # --source ... build source package - # -us ... do NOT sign source package - # -uc ... do NOT sign .changes file - # -j7 ... - # -b ... build BINARY package (SOURCE package otherwise w/ -S) - # -i ... ignore build-in deps conflicts - # doc and man: - # http://manpages.ubuntu.com/manpages/xenial/en/man1/dpkg-buildpackage.1.html - # http://manpages.ubuntu.com/manpages/xenial/en/man1/debuild.1.html - # man debuild - # build SIGNED source .deb package: - bzr builddeb --source - # verify build result - build_status=$? - echo -e "SOURCE .deb package build on HOST system (buildarea/mindforger_...orig.tar.gz):" - [ $build_status -eq 0 ] && echo " SUCCESSFULL" || exit 1 - - # 7) build BINARY .deb from source deb on CLEAN system - no deps installed - echo -e "\n# CLEAN SYSTEM MindForger build by pbuilder @ FAKEROOT #########" - echo -e "5.4) build SIGNED BINARY .deb package on FAKEROOT system using sources prepared by SOURCE .deb build" - # Build is made using Makefile(s) generated by qmake above: - # - build-area/ directory created by SOURCE `bzr buildeb` in the previous step - # is used to build MindForger using `pbuilder-dist` on fakeroot system - # - IMPORTANT: pbuilder's caches in /var and /home MUST be on same physical drive - # as build-area/ - # - WARNING: mindforger/Makefile contains path to qmake which was determined - # on HOST system, therefore it does NOT have to be the same on fakeroot system - # - DEBUG: $PBUILDERFOLDER ... build directory on HOST system (defined below) - # - DEBUG: /var/cache/pbuilder ... last build's artifacts - # - DEBUG: /var/cache/pbuilder/base.tgz ... last build's distro of Ubuntu - # - DEBUG: ~/pbuilder ... Ubuntu distro snapshots ^ - # DRY RUN - # cd /home/dvorka/p/mindforger/launchpad/mindforger-2021-12-26--09-17-35/build-area && export PBUILDFOLDER=/tmp/mindforger-pbuilder-tmp && rm -rvf ${PBUILDFOLDER} ; mkdir -p ${PBUILDFOLDER} ; cp -rvf ~/pbuilder/*.tgz ${PBUILDFOLDER} ; pbuilder-dist xenial build mindforger_1.53.4-0ubuntu1.dsc - # SHARP run: - cd ../build-area - # CLEAN build directory for pbuilder in tmp/ - export PBUILDFOLDER=/tmp/mindforger-pbuilder-tmp - rm -rvf ${PBUILDFOLDER} - mkdir -p ${PBUILDFOLDER} - # COPY Ubuntu distros from user home to pbuilder build directory in tmp/ - cp -rvf ~/pbuilder/*.tgz ${PBUILDFOLDER} - # BUILD .deb using source .deb files in tmp/ directory according to .dsc - echo " Running 'pbuilder-dist ${UBUNTUVERSION} build ${MFRELEASE}.dsc' in '`pwd`'" - echo " - mindfoger_..-0ubuntu1.dsc ... control descriptor according to which is build made" - echo " - mindfoger_...orig.tar.gz ... TARBALL w/ Debian control files used to build .deb" - pbuilder-dist ${UBUNTUVERSION} build ${MFRELEASE}.dsc - # VERIFY pbuilder-dist build result - build_status=$? - echo -e "BINARY .deb package build on FAKEROOT system (${PBUILDFOLDER}):" - [ $build_status -eq 0 ] && echo " SUCCESSFULL" || exit 1 - - # 8) upload updated sources to Launchpad: push Bazaar and put changes - echo -e "\n# bzr push .deb to Launchpad ###################################" - # from buildarea/ to ./dist - cd ../${MF} - echo "Before bzr push: " `pwd` - - # TODO commit in bzr first - - echo -e "SKIPPED FOR NOW" - echo -e "SKIPPED FOR NOW" - echo -e "SKIPPED FOR NOW" - exit 0 - exit 0 - exit 0 - - bzr push lp:~ultradvorka/+junk/mindforger - cd .. - echo "Before dput push: " `pwd` - # recently added /ppa to fix the path and package rejections - # MF PPA w/ 64b build only - dput ppa:ultradvorka/productivity ${MFRELEASE}_source.changes - # SKIP: HSTR PPA w/ 64b 32b and ARM builds - #dput ppa:ultradvorka/ppa ${MFRELEASE}_source.changes -} - -# ############################################################################ -# # Main # -# ############################################################################ - -if [ -e "../../.git" ] -then - echo "This script must NOT be run from Git repository - run it e.g. from ~/p/mindforger/launchpad instead" - exit 1 -fi - -export ARG_MAJOR_VERSION=1.53. -export ARG_MINOR_VERSION=4 # minor version is incremented for every Ubuntu version -export ARG_BAZAAR_MSG="MindForger ${ARG_MAJOR_VERSION}${ARG_MINOR_VERSION} release." - -# https://wiki.ubuntu.com/Releases -# obsolete: precise quantal saucy precise utopic vivid wily yakkety artful cosmic -# current : (trusty) xenial bionic (cosmic disco eoan) focal (groovy) hirsute impish -# xenial bionic focal hirsute impish -# WIP: trusty xenial bionic focal hirsute impish -for UBUNTU_VERSION in bionic -do - echo "Releasing MF for Ubuntu version: ${UBUNTU_VERSION}" - releaseForParticularUbuntuVersion ${UBUNTU_VERSION} ${ARG_MAJOR_VERSION}${ARG_MINOR_VERSION} "${ARG_BAZAAR_MSG}" - ARG_MINOR_VERSION=`expr $ARG_MINOR_VERSION + 1` -done - -# eof diff --git a/build/ubuntu/build-all-clean-system.sh b/build/ubuntu/build-all-clean-system.sh index 887064f9..43e2f88b 100755 --- a/build/ubuntu/build-all-clean-system.sh +++ b/build/ubuntu/build-all-clean-system.sh @@ -2,7 +2,7 @@ # # MindForger knowledge management tool # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -29,7 +29,7 @@ git submodule init git submodule update # deps install -sudo apt-get install build-essential zlib1g-dev libhunspell-dev libqt5webkit5-dev qttools5-dev-tools qt5-default ccache +sudo apt-get install build-essential zlib1g-dev libcurl4-gnutls-dev libhunspell-dev libqt5webkit5-dev qttools5-dev-tools qt5-default ccache # deps build cd ${SCRIPT_HOME}/../../deps/cmark-gfm diff --git a/build/ubuntu/debian/changelog b/build/ubuntu/debian/changelog index 9dd38553..4c4a5c2a 100644 --- a/build/ubuntu/debian/changelog +++ b/build/ubuntu/debian/changelog @@ -1,6 +1,5 @@ -mindforger (1.54.1-0ubuntu1) trusty; urgency=low +mindforger (2.0.0-0ubuntu1) bionic; urgency=low - * Experimental packaging. - - -- Martin Dvorak (Dvorka) Sat, 1 Jan 2022 14:11:33 +0100 + * New version. + -- Martin Dvorak (Dvorka) Sat, 1 Jan 2024 14:11:33 +0100 diff --git a/build/ubuntu/debian/control b/build/ubuntu/debian/control index e4d0780e..5c296633 100644 --- a/build/ubuntu/debian/control +++ b/build/ubuntu/debian/control @@ -2,7 +2,7 @@ Source: mindforger Section: utils Priority: optional Maintainer: Martin Dvorak -Build-Depends: debhelper (>= 8.0.0), build-essential, ccache, qt5-qmake, zlib1g-dev, libhunspell-dev, qtbase5-dev, libqt5webkit5-dev +Build-Depends: debhelper (>= 8.0.0), build-essential, ccache, qt5-qmake, zlib1g-dev, libcurl4-gnutls-dev, libhunspell-dev (>=1.6), qtbase5-dev, libqt5webkit5-dev Standards-Version: 3.9.5 Homepage: https://github.com/dvorka/mindforger Vcs-Git: https://github.com/dvorka/mindforger.git @@ -13,5 +13,5 @@ Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Thinking notebook and Markdown IDE. Search, browse, view and edit your Markdown files. Get as much - as possible from knowledge in your remarks. + as possible from the knowledge in your remarks. Tag: implemented-in::c++, interface::graphical, role::program \ No newline at end of file diff --git a/build/ubuntu/debian/copyright b/build/ubuntu/debian/copyright index 4a130cd6..42e95756 100644 --- a/build/ubuntu/debian/copyright +++ b/build/ubuntu/debian/copyright @@ -3,7 +3,7 @@ Upstream-Name: mindforger Source: https://github.com/dvorka/mindforger Files: debian/* -Copyright: 2016-2022 Martin Dvorak +Copyright: 2016-2024 Martin Dvorak License: GPL-2+ MindForger is licensed under GNU GPL version 2 or any later version. . diff --git a/build/ubuntu/ubuntu-launchpad-releases-from-beast.sh b/build/ubuntu/ubuntu-launchpad-releases-from-beast.sh index f7ac79f2..5dee1e41 100755 --- a/build/ubuntu/ubuntu-launchpad-releases-from-beast.sh +++ b/build/ubuntu/ubuntu-launchpad-releases-from-beast.sh @@ -2,7 +2,7 @@ # # MindForger knowledge management tool # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -103,7 +103,7 @@ function releaseForParticularUbuntuVersion() { export MFSRC=/home/dvorka/p/mindforger/git/mindforger export NOW=`date +%Y-%m-%d--%H-%M-%S` export MFBUILD=mindforger-${NOW} - + # 1) clean up echo -e "\n# Cleanup ####################################################" rm -rvf *.*~ ./debian @@ -122,7 +122,7 @@ function releaseForParticularUbuntuVersion() { echo "4.1) build MF dependencies" rm -rvf deps/cmark-gfm/build cd deps/cmark-gfm && mkdir -v build && cd build && cmake -DCMARK_TESTS=OFF -DCMARK_SHARED=OFF .. && cmake --build . && cd ../../.. - + echo "4.2) Qt: generate makefile using qmake" echo -e "\n# qmake ######################################################" cd .. @@ -133,7 +133,7 @@ function releaseForParticularUbuntuVersion() { # like this qt5-default. Instead debian/rules file exports env var w/ Qt choice # .pro file is also extended to have 'make install' target qmake -r mindforger.pro CONFIG+=mfoldhunspell - + # 5) add new version to LOCAL Bazaar echo -e "\n# bazaar add & commit #######################################" bzr add . @@ -149,8 +149,8 @@ function releaseForParticularUbuntuVersion() { echo "OK: GPG agent running." else gpg-agent --daemon - fi - + fi + # 6) build debs echo -e "\n# source & binary debs ######################################" # OPTIONAL: build .deb package (us uc tells that no GPG signing is needed) @@ -160,7 +160,7 @@ function releaseForParticularUbuntuVersion() { # 7) build binary from source deb on CLEAN system - no deps installed echo -e "\n# clean build ~ pbuilder ####################################" - cd ../build-area + cd ../build-area # IMPORTANT pbuilder's caches in /var and /home MUST be on same physical drive # BEGIN export PBUILDFOLDER=/tmp/mindforger-tmp @@ -175,10 +175,10 @@ function releaseForParticularUbuntuVersion() { echo -e "\n${UBUNTUVERSION} DRY RUN finished - exiting WITHOUT upload to Launchpad\n" exit 0 fi - + # 8) upload to Launchpad: push Bazaar and put changes echo -e "\n# bzr push .deb to Launchpad #################################" - + # from buildarea/ to ./dist cd ../${MF} echo "Before bzr push: " `pwd` @@ -203,8 +203,8 @@ then exit 1 fi -export ARG_MAJOR_VERSION=1.54. -export ARG_MINOR_VERSION=6 # minor version is incremented for every Ubuntu version +export ARG_MAJOR_VERSION=2.0. +export ARG_MINOR_VERSION=0 # minor version is incremented for every Ubuntu version export ARG_BAZAAR_MSG="MindForger ${ARG_MAJOR_VERSION}${ARG_MINOR_VERSION} release." # export DRY_RUN="true" diff --git a/build/ubuntu/ubuntu-launchpad-releases-from-mind.sh b/build/ubuntu/ubuntu-launchpad-releases-from-mind.sh new file mode 100755 index 00000000..80ba6bc6 --- /dev/null +++ b/build/ubuntu/ubuntu-launchpad-releases-from-mind.sh @@ -0,0 +1,437 @@ +#!/usr/bin/env bash +# +# MindForger knowledge management tool +# +# Copyright (C) 2016-2024 Martin Dvorak +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### +# +# Goal - CREATE UBUNTU PACKAGE at: +# +# https://launchpad.net/~ultradvorka/+archive/ubuntu/productivity/+packages +# +# This script: +# > checkouts MF from LaunchPad's bazaar +# > copies latest sources to bazaar +# > builds upstream tarball +# ~ checks that local build is OK +# > builds source .deb +# ~ checks that .deb build for target Ubuntu distro is OK +# > signs its .dsc descriptor using PGP +# > builds binary .deb +# ~ checks that .deb build for target Ubuntu distro is OK +# > uploads signed .dsc to LaunchPad using dput +# IMPORTANT: for ^ upload .deb builds are NOT needed, only signed .dsc +# +# Tips: +# - run the script from Emacs shell to easily review and analyze +# the script output +# - make sure PGP and .ssh keys are trusted and registered +# on Launchpad +# - set OPT_* for PUSH and RELEASE to false to get .deb for any Ubuntu +# version locally +# +# GPG key configuration: +# - GNU Privacy Guard @ PGP pretty good privacy +# - identifies the person on LaunchPad +# 1. generate +# OR +# copy the key from another machine +# 2. LOCAL: trust the key +# ~/.gnupg +# gpg --list-keys +# ^ key is SUFFIX of pub key, last 16 characters +# gpg --edit-key +# gpg --edit-key B72E4F7F24AF591D # ... +# ^ starts a tool with shell, write command: +# > trust +# 3. Launchpad: upload and register the key at +# https://launchpad.net/~ultradvorka/+editpgpkeys +# +# SSH key configuration: +# 1. Launchpad: upload and register the key +# https://launchpad.net/~ultradvorka/+editsshkeys +# ~/.ssh/id_rsa.pub +# +# See: +# Beginners guide: +# http://packaging.ubuntu.com/html/packaging-new-software.html +# PGP +# https://unix.stackexchange.com/questions/188668/how-does-gpg-agent-work +# Debian maintainers guide: +# https://www.debian.org/doc/manuals/maint-guide/index.en.html +# https://www.debian.org/doc/manuals/debmake-doc/index.en.html +# Debian formal doc: +# https://www.debian.org/doc/debian-policy/ +# + +# ######################################################################## +# # Configuration +# ######################################################################## + +# Ubuntu version: +# - https://wiki.ubuntu.com/Releases +# - obsolete: +# precise quantal saucy precise utopic vivid wily yakkety artful cosmic +# - current : +# (trusty) xenial bionic (cosmic disco eoan) focal (groovy) (hirsute) (impish) jammy kinetic +# - command (Bash tuple of distro names): +# trusty xenial bionic focal jammy kinetic + +if [[ ${#} == 1 ]] +then + export UBUNTU_VERSIONS=(${1}) +else + export UBUNTU_VERSIONS=(focal) +fi + +# environment variables +export MAJOR_VERSION=1 +export MINOR_VERSION=55 +export PATCH_VERSION=5 # patch version is incremented for every Ubuntu build @ Launchpad +export MF_VERSION="${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}" # semantic version +export RM_CMD="rm -vrf " +export CP_CMD="cp -vrf " + +export OPT_VERBOSE="v" +if [[ ${#} == 1 ]] +then + export OPT_DO_PUSH="false" # "true" to upload src to bazaar + export OPT_DO_RELEASE="false" # "true" to dpush binary .deb to Launchpad and TRIGGER release +else + #export OPT_DO_PUSH="false" # "true" to upload src to bazaar + #export OPT_DO_RELEASE="false" # "true" to dpush binary .deb to Launchpad and TRIGGER release + export OPT_DO_PUSH="true" # "true" to upload src to bazaar + export OPT_DO_RELEASE="true" # "true" to dpush binary .deb to Launchpad and TRIGGER release +fi + +# shell variables +# ... + +# ######################################################################## +# # Helpers +# ######################################################################## + +function echoStep { + echo -e "\n# ${1} ###################################################" +} + +function echoStepDone { + echo -e "\n# DONE: ${1} #############################################" + pwd +} + +function debugExit { + echo "EXITING SCRIPT: intentional development script exit" + exit 1 +} + +# ######################################################################## +# # Checkout MindForger from bazaar, copy over new sources, clean result +# ######################################################################## + +function checkoutMindforger { + # use `bzr` to manually check and work with Bazaar repository: + # - bzr ... get help + # - bzr status + # - bzr commit ... commints and PUSHES changes to server + + export MFSRC=$2 + # create new branch: bzr init && bzr push lp:~ultradvorka/+junk/mindforger + bzr checkout lp:~ultradvorka/+junk/mindforger + + # delete OLD files from Bazaar directory + cd mindforger + mv .bzr .. + rm -rf${OPT_VERBOSE} app build deps lib man LICENSE *.md + mv ../.bzr . + + # copy NEW project files to Bazaar directory + echo -e "\n# copy over new MindForger files ############################" + cp -rf${OPT_VERBOSE} ${MFSRC}/* ${MFSRC}/*.* . + + # prune MindForger project files: tests, *.o/... build files, ... + echo -e "\n# CLEANUP development and build artifacts ###################" + rm -rf${OPT_VERBOSE} ./.git ./.qmake.stash ./app/mindforger ./build ./app/test ./lib/test + rm -rf${OPT_VERBOSE} ./lib/.qmake.stash ./lib/lib.pro.user ./lib/src/mindforger-lib-unit-tests + rm -rf${OPT_VERBOSE} ./deps/cmark-gfm/.github + rm -rf${OPT_VERBOSE} ./deps/mitie + # IMPROVE: static libraries lib*.a are NOT deleted to keep cmark-gfm dependency libs + find . -type f \( -name "*moc_*.cpp" -or -name "*.o" -or -name "*.*~" -or -name ".gitignore" -or -name ".git" \) | while read F; do rm -vf $F; done + + cd .. +} + +# ############################################################################ +# # Create updated changelog +# ############################################################################ + +function createChangelog { + export MYTS=`date "+%a, %d %b %Y %H:%M:%S"` + echo "Changelog timestamp: ${MYTS}" + echo "mindforger (${MFFULLVERSION}) ${UBUNTU_VERSION}; urgency=low" > $1 + echo " " >> $1 + echo " * ${MFBZRMSG}" >> $1 + echo " " >> $1 + echo " -- Martin Dvorak (Dvorka) ${MYTS} +0100" >> $1 + # additional new line removed as it's not in HSTR + #echo "" >> $1 +} + +# ############################################################################ +# # Create upstream tarball in work/ +# ############################################################################ + +function createTarball { + echoStep "Create TARBALL ${MF}" + # .orig.tar.gz is required Debian convention + TARBALL_FILE="${MF}.orig.tar.gz" + + cd .. + mkdir work + cd work + cp -rf${OPT_VERBOSE} ../${MF} . + # remove bazaar control files + rm -rf${OPT_VERBOSE} ${MF}/.bzr + # create archives + tar zcf ../${MF}.tgz ${MF} + cp -fv ../${MF}.tgz ../${TARBALL_FILE} + # change back to the directory which was zipped as tarball + cd ../${MF} + + echoStepDone "TARBALL archive created in $(pwd)/..:" + ls -l ../*.gz +} + +# ############################################################################ +# # Patch qmake location (if needed) +# ############################################################################ + +function patchQmakePathInMakefile { + MAKEFILE_PATH=${1} + echo "Patching qmake in Makefile: ${MAKEFILE_PATH}" + cat ${MAKEFILE_PATH} | while IFS= read L + do + if [[ "${L}" = "QMAKE = /usr/lib/qt5/bin/qmake" ]] + then + echo "QMAKE = /usr/bin/qmake" + else + echo "${L}" + fi + done > "${MAKEFILE_PATH}.new" + mv "${MAKEFILE_PATH}.new" ${MAKEFILE_PATH} +} + +# ############################################################################ +# # Release for *ONE* particular Ubuntu version +# ############################################################################ +# - this is the main() function of this script +# - step by step it releases MindForger for one particular Ubuntu version + +function releaseForParticularUbuntuVersion { + export SCRIPTHOME=`pwd` + export UBUNTUVERSION=${1} + export MFVERSION=${2} + export MFBZRMSG=${3} + export MFFULLVERSION=${MFVERSION}-0ubuntu1 + export MF=mindforger_${MFVERSION} + export MFRELEASE=mindforger_${MFFULLVERSION} + export MFSRC=/home/dvorka/p/mindforger/git/mindforger + export NOW=`date +%Y-%m-%d--%H-%M-%S` + export MFBUILD=mindforger-${NOW} + + # 1) clean up + echoStep "Cleanup" + rm -rvf *.*~ ./debian + + # 2) checkout MindForger from Launchpad's bazaar to work directory + # (will be needed to build SOURCE .deb package) + echoStep "Checkout MF from LaunchPad bazaar" + mkdir ${MFBUILD} + cd ${MFBUILD} + checkoutMindforger ${MF} ${MFSRC} + + # 3) update Debian control files (changelog, descriptor, ...) in bzr clone + echoStep "Create Debian control files" + cd mindforger && cp -rvf ${MFSRC}/build/ubuntu/debian . + createChangelog ./debian/changelog + echo "Changelog:" + cat ./debian/changelog + + # 4) build MF dependencies + echoStep "Build MindForger library dependencies: cmark-gfm" + rm -rf${OPT_VERBOSE} deps/cmark-gfm/build + cd deps/cmark-gfm && mkdir -v build && cd build && cmake -DCMARK_TESTS=OFF -DCMARK_SHARED=OFF .. && cmake --build . && cd ../../.. + echoStepDone "cmark-gfm build" + # cmark-gfm static library: + ls -l deps/cmark-gfm/build/src/libcmark-gfm.a + if [[ $? -eq 0 ]] ; then echo " SUCCESSFULL"; else echo " FAILED"; exit 1; fi + + # 5) generate MF Makefiles using qmake + echoStep "Generate Makefiles using qmake" + cd .. + mv mindforger ${MF} + cd ${MF} + # Qt version MUST be specified as it CANNOT be configured by installing + # qt5-default package: Debian control file does NOT allow virtual packages + # like this qt5-default. + # Instead debian/rules file exports env var w/ Qt choice + # .pro file is also extended to have 'make install' target + qmake -r mindforger.pro + + # 6) optionally PATCH source files e.g. different Ubuntu distro specific paths + echoStep "Patch Makefiles - fix Qt paths for Ubuntu versions" + #if [[ "xenial" = "${UBUNTUVERSION}" ]] + #then + patchQmakePathInMakefile "Makefile" + patchQmakePathInMakefile "app/Makefile" + patchQmakePathInMakefile "lib/Makefile" + patchQmakePathInMakefile "lib/src/Makefile" + #fi + + # 7) create tarball ~ .tgz archive w/ source and required Debian cfg files + echo -e "\n---------------------------------------------------------------" + echo -e "5.1) create TARBALL: prepare files to work/ directory" + createTarball + + # 8) start GPG agent if it's NOT running + # gpg-agent is a program that runs in the background (a daemon) and stores + # GPG secret keys in memory. When a GPG process needs the key, it contacts + # the running gpg-agent program through a socket and requests the key. + # + echoStep "Start GPG agent process (if it is NOT running)" + if [ -e "${HOME}/.gnupg/S.gpg-agent" ] + then + echo "OK: GPG agent running." + else + gpg-agent --daemon + fi + + # 9) add new version to LOCAL Bazaar branch (which will be used for .deb build) + echoStep "add & commit ${MF} prepared files to the current bazaar branch" + bzr add . + # IMPORTANT: commit UPLOADs branch to server + # https://code.launchpad.net/~ultradvorka/+junk/mindforger + # ^ browse changes/code and pushes @ Launchpad + bzr commit -m "Update for ${MF} at ${NOW}." + + # 10) build SOURCE .deb package (copy sources, add control files and .tgz it to get .deb package) + echoStep "Build SIGNED SOURCE .deb package from bzr branch" + echo " Building .deb package on HOST system (not FAKEROOT build) using sources prepared by TARBALL in bazaar work/ directory:" + pwd + # Build of SOURCE .deb package + # - build is made using Makefile(s) generated by qmake ABOVE + # - build is made using files prepared by TARBALL step in work/ directory + # - build is made on HOST system, NOT clean FAKEROOT system + # - build is made using `bzr builddeb` + # - toolchain: builddeb > debuild > dpkg-buildpackage (find documentation there) + # bzr builddeb -- -us -uc -j7 + # --source ... build source package + # -us ... do NOT sign source package + # -uc ... do NOT sign .changes file + # -j7 ... + # -b ... build BINARY package (SOURCE package otherwise w/ -S) + # -i ... ignore build-in deps conflicts + # doc and man: + # http://doc.bazaar.canonical.com/plugins/en/builddeb-plugin.html + # http://manpages.ubuntu.com/manpages/xenial/en/man1/dpkg-buildpackage.1.html + # http://manpages.ubuntu.com/manpages/xenial/en/man1/debuild.1.html + # man debuild + # build SIGNED source .deb package: + bzr builddeb --verbose --source + # verify build result and EXIT on failure + build_status=$? + echo -e "DONE: SOURCE .deb package build on HOST system (buildarea/mindforger_...orig.tar.gz):" + if [[ $build_status -eq 0 ]] ; then echo " SUCCESSFULL"; else echo " FAILED"; exit 1; fi + + # 11) build BINARY .deb from source .deb on CLEAN system to dry run build @ Launchpad + echoStep "Build SIGNED BINARY .deb package from source .deb (created in previous step) on CLEAN system (FAKEROOT mounted) - this is actual deps installation, compilation and link of the executable to create .deb file with the binary, HOWEVER, the binar .deb is NOT uploaded, this steps is made just to verify that the build will NOT fail on Launchpad (for the build is used just signed .dsc file)" + # Build is made using Makefile(s) generated by qmake above: + # - build is made using GPG signed .dsc file which pbuild-dist takes as a parameter + # - .dsc files was created in the previous steps for .deb files + # - build-area/ directory created by SOURCE `bzr buildeb` in the previous step + # is used to build MindForger using `pbuilder-dist` on fakeroot system + # - OUTPUT of the pbuild-dist is stored in /tmp/mindforger-pbuilder-tmp/_result + # - IMPORTANT: pbuilder's caches in /var and /home MUST be on same physical drive + # as build-area/ + # - WARNING: mindforger/Makefile contains path to qmake which was determined + # on HOST system, therefore it does NOT have to be the same on fakeroot system + # - DEBUG: $PBUILDERFOLDER ... build directory on HOST system (defined below) + # - DEBUG: /var/cache/pbuilder ... last build's artifacts + # - DEBUG: /var/cache/pbuilder/base.tgz ... last build's distro of Ubuntu + # - DEBUG: ~/pbuilder ... Ubuntu distro snapshots ^ + cd ../build-area + # CLEAN build directory for pbuilder in tmp/ + export PBUILDFOLDER=/tmp/mindforger-pbuilder-tmp + rm -rvf ${PBUILDFOLDER} + mkdir -p ${PBUILDFOLDER} + # COPY Ubuntu distros from user home to pbuilder build directory in tmp/ + cp -rvf ~/pbuilder/*.tgz ${PBUILDFOLDER} + # BUILD .deb using source .deb files in tmp/ directory according to .dsc + echo " Running 'pbuilder-dist ${UBUNTUVERSION} build ${MFRELEASE}.dsc' in '`pwd`'" + echo " - mindfoger_..-0ubuntu1.dsc ... control descriptor according to which is build made" + echo " - mindfoger_...orig.tar.gz ... TARBALL w/ Debian control files used to build .deb" + # pbuild-dist help: https://wiki.ubuntu.com/PbuilderHowto + pbuilder-dist ${UBUNTUVERSION} build ${MFRELEASE}.dsc + # VERIFY pbuilder-dist build result + build_status=$? + echo -e "DONE: BINARY .deb package build on FAKEROOT system, result stored to ${PBUILDFOLDER}/${UBUNTUVERSION}_result:" + if [[ $build_status -eq 0 ]] ; then echo " SUCCESSFULL"; else echo " FAILED"; exit 1; fi + + if [[ ${OPT_DO_PUSH} == "true" ]] + then + # 12) push updated sources to Launchpad bazaar server + echoStep "Push updated sources to Launchpad bazaar" + cd ../${MF} + echo "Invoking bzr push in: $(pwd)" + bzr push lp:~ultradvorka/+junk/mindforger + + if [[ ${OPT_DO_RELEASE} == "true" ]] + then + cd .. + echo "Invoking dput in: $(pwd)" + ls -l ${MFRELEASE}_source.changes + # recently added /ppa to fix the path and package rejections + # MF PPA w/ 64b build only + dput ppa:ultradvorka/productivity ${MFRELEASE}_source.changes + # SKIP: MF PPA w/ 64b 32b and ARM builds + #dput ppa:ultradvorka/ppa ${MFRELEASE}_source.changes + fi + fi +} + +############################################################################# +# Main +############################################################################# + +if [ -e "../../.git" ] +then + echo "This script must NOT be run from Git repository - run it e.g. from ~/p/mindforger/launchpad instead" + exit 1 +fi + +export BAZAAR_MSG="MindForger ${MF_VERSION} release." + +for UBUNTU_VERSION in ${UBUNTU_VERSIONS} +do + echo -e "\n###################################################" + echo "# Releasing MF for Ubuntu version: ${UBUNTU_VERSION}" + echo "###################################################" + releaseForParticularUbuntuVersion ${UBUNTU_VERSION} "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}" "${BAZAAR_MSG}" + MINOR_VERSION=`expr $MINOR_VERSION + 1` +done + +# eof diff --git a/build/ubuntu/ubuntu-pbuilder-add-distros.sh b/build/ubuntu/ubuntu-pbuilder-add-distros.sh index c572fcf2..9d15fbb9 100755 --- a/build/ubuntu/ubuntu-pbuilder-add-distros.sh +++ b/build/ubuntu/ubuntu-pbuilder-add-distros.sh @@ -2,7 +2,7 @@ # # MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/build/windows/build-win-installer.bat b/build/windows/build-win-installer.bat index 3cb352f0..cdfeb514 100644 --- a/build/windows/build-win-installer.bat +++ b/build/windows/build-win-installer.bat @@ -1,7 +1,7 @@ @echo off rem MindForger thinking notebook -rem Copyright (C) 2016-2022 +rem Copyright (C) 2016-2024 rem This program is free software; you can redistribute it and/or rem modify it under the terms of the GNU General Public License @@ -28,3 +28,5 @@ C:\Qt\5.12.1\msvc2017_64\bin\windeployqt app\release\mindforger.exe --dir app\r rem Build installer "C:\Program Files (x86)\Inno Setup 5\ISCC.exe" /Qp /DVcRedistPath="c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\14.16.27012\vcredist_x64.exe" build\windows\installer\mindforger-setup.iss + +echo "Find installer in mindforger/app/release/installer/*.exe" diff --git a/build/windows/installer/mindforger-setup.iss b/build/windows/installer/mindforger-setup.iss index c8278e2b..511617f6 100644 --- a/build/windows/installer/mindforger-setup.iss +++ b/build/windows/installer/mindforger-setup.iss @@ -47,5 +47,5 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MINDFORGER_APP_N [Run] Filename: "{tmp}\vcredist_x64.exe"; \ Parameters: "/install /quiet /norestart"; \ - StatusMsg: "Installing VC++ 2017 Redistributables..." + StatusMsg: "Installing VC++ 2019 Redistributables..." Filename: "{app}\bin\{#MINDFORGER_APP_EXE}"; WorkingDir: "{app}\bin\"; Flags: shellexec nowait postinstall skipifsilent runascurrentuser; Description: "{cm:LaunchProgram,{#StringChange(MINDFORGER_APP_NAME, '&', '&&')}}" diff --git a/deps/mitie b/deps/mitie deleted file mode 160000 index 6f43a5b9..00000000 --- a/deps/mitie +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6f43a5b9cb8ddd852a047fb3d2e73b816ea54465 diff --git a/deps/zlib-win/include/zconf.h b/deps/zlib-win/include/zconf.h index d8c78e99..6baede84 100644 --- a/deps/zlib-win/include/zconf.h +++ b/deps/zlib-win/include/zconf.h @@ -5,7 +5,7 @@ /* * MindForger thinking notebook - * Copyright (C) 2016-2022 Martin Dvorak + * Copyright (C) 2016-2024 Martin Dvorak * * This header file has been modified for MindForger as follows: diff --git a/lib/lib.pro b/lib/lib.pro index 9b047581..4f03d153 100644 --- a/lib/lib.pro +++ b/lib/lib.pro @@ -1,6 +1,6 @@ # mindforger-lib.pro MindForger thinking notebook # -# Copyright (C) 2016-2022 Martin Dvorak +# Copyright (C) 2016-2024 Martin Dvorak # # This program is free software ; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -18,7 +18,14 @@ TARGET = mindforger TEMPLATE = lib CONFIG += staticlib -CONFIG -= qt + +win32|macx { + # Qt Network as CURL replacement on Win - add Qt to libmindforger + CONFIG += qt + QT += network +} else { + CONFIG -= qt +} # Dependencies: # - INCLUDEPATH is used during compilation to find included header files. @@ -41,13 +48,6 @@ win32 { DEPENDPATH += $$PWD/../deps/zlib-win/include } -# NER library -mfner { - DEFINES += MF_NER - INCLUDEPATH += $$PWD/../deps/mitie/mitielib/include - DEPENDPATH += $$PWD/../deps/mitie/mitielib/include -} - # debug mfdebug|mfunits { DEFINES += DO_MF_DEBUG @@ -56,6 +56,11 @@ mfdebug|mfunits { # compiler options (qmake CONFIG+=mfnoccache ...) win32{ QMAKE_CXXFLAGS += /MP + + # DISABLED ccache as it causes compilation error: + # "C1090: PDB API call failed, error code '23'" when used + # when used w/ MS VS compiler: + # !mfnoccache { QMAKE_CXX = ccache $$QMAKE_CXX } } else { # linux and macos mfnoccache { @@ -68,6 +73,8 @@ win32{ # debug info QMAKE_CXXFLAGS += -g } + + # -O3 ... can be specified by this variable (overrides -O1 -O2) QMAKE_CXXFLAGS += -pedantic -std=c++11 } @@ -111,6 +118,9 @@ SOURCES += \ src/config/repository_configuration.cpp \ src/gear/async_utils.cpp \ src/gear/math_utils.cpp \ + src/mind/ai/llm/wingman.cpp \ + src/mind/ai/llm/mock_wingman.cpp \ + src/mind/ai/llm/openai_wingman.cpp \ src/mind/dikw/dikw_pyramid.cpp \ src/mind/dikw/filesystem_information.cpp \ src/mind/dikw/information.cpp \ @@ -157,12 +167,6 @@ SOURCES += \ src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.cpp } -mfner { - SOURCES += \ - src/mind/ai/nlp/named_entity_recognition.cpp \ - src/mind/ai/nlp/ner_named_entity.cpp -} - HEADERS += \ ./src/debug.h \ ./src/exceptions.h \ @@ -225,6 +229,9 @@ HEADERS += \ ./src/gear/math_utils.h \ ./src/mind/dikw/dikw_pyramid.h \ ./src/mind/dikw/filesystem_information.h \ + src/mind/ai/llm/wingman.h \ + src/mind/ai/llm/mock_wingman.h \ + src/mind/ai/llm/openai_wingman.h \ src/mind/dikw/information.h \ src/model/eisenhower_matrix.h \ src/model/kanban.h \ @@ -294,12 +301,6 @@ HEADERS += \ src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.h } -mfner { - HEADERS += \ - src/mind/ai/nlp/named_entity_recognition.h \ - src/mind/ai/nlp/ner_named_entity.h -} - win32 { HEADERS += \ ../deps/dirent/dirent.h \ diff --git a/lib/src/app_info.h b/lib/src/app_info.h index 2153a905..2381bf07 100644 --- a/lib/src/app_info.h +++ b/lib/src/app_info.h @@ -1,12 +1,12 @@ -#define MINDFORGER_VERSION_MAJOR "1" -#define MINDFORGER_VERSION_MINOR "54" +#define MINDFORGER_VERSION_MAJOR "2" +#define MINDFORGER_VERSION_MINOR "0" #define MINDFORGER_VERSION_REVISION "0" -#define MINDFORGER_VERSION_STRING "1.54.0" -#define MINDFORGER_VERSION_DWORD 1,54,0,2 +#define MINDFORGER_VERSION_STRING "2.0.0" +#define MINDFORGER_VERSION_DWORD 2,0,0,2 #define MINDFORGER_APP_NAME "MindForger" #define MINDFORGER_APP_DESCRIPTION "MindForger Thinking Notebook" #define MINDFORGER_APP_AUTHOR "Martin Dvorak" #define MINDFORGER_APP_URL "https://www.mindforger.com" #define MINDFORGER_APP_COMPANY MINDFORGER_APP_NAME -#define MINDFORGER_APP_LEGAL "\xA9 2016-2022 Martin Dvorak. All Rights Reserved" -#define MINDFORGER_APP_EXE "mindforger.exe" +#define MINDFORGER_APP_LEGAL "\xA9 2016-2024 Martin Dvorak. All Rights Reserved" +#define MINDFORGER_APP_EXE "mindforger.exe" diff --git a/lib/src/compilation.h b/lib/src/compilation.h index b275aaaa..78e5c16e 100644 --- a/lib/src/compilation.h +++ b/lib/src/compilation.h @@ -1,7 +1,7 @@ /* compilation.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/color.h b/lib/src/config/color.h index 380b1c2a..4febc4f3 100644 --- a/lib/src/config/color.h +++ b/lib/src/config/color.h @@ -1,7 +1,7 @@ /* color.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/configuration.cpp b/lib/src/config/configuration.cpp index 291cdb52..b7b167e6 100644 --- a/lib/src/config/configuration.cpp +++ b/lib/src/config/configuration.cpp @@ -1,7 +1,7 @@ /* configuration.cpp M8r configuration management - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -29,6 +29,8 @@ using namespace m8r::filesystem; namespace m8r { +const string KnowledgeTool::TOOL_PHRASE = string{"<>"}; + // non-primitive constants initializations const string Configuration::DEFAULT_ACTIVE_REPOSITORY_PATH = string{FILE_PATH_M8R_REPOSITORY}; const string Configuration::DEFAULT_STARTUP_VIEW_NAME = string{DEFAULT_STARTUP_VIEW}; @@ -36,6 +38,7 @@ const string Configuration::DEFAULT_UI_THEME_NAME = string{UI_DEFAULT_THEME}; const string Configuration::DEFAULT_UI_HTML_CSS_THEME = string{UI_DEFAULT_HTML_CSS_THEME}; const string Configuration::DEFAULT_EDITOR_FONT= string{UI_DEFAULT_EDITOR_FONT}; const string Configuration::DEFAULT_TIME_SCOPE = string{"0y0m0d0h0m"}; +const string Configuration::DEFAULT_WINGMAN_LLM_MODEL_OPENAI = string{"gpt-3.5-turbo"}; Configuration::Configuration() : asyncMindThreshold{}, @@ -47,9 +50,14 @@ Configuration::Configuration() autolinking{DEFAULT_AUTOLINKING}, autolinkingColonSplit{}, autolinkingCaseInsensitive{}, + wingmanProvider{DEFAULT_WINGMAN_LLM_PROVIDER}, + wingmanApiKey{}, + wingmanOpenAiApiKey{}, + wingmanLlmModel{DEFAULT_WINGMAN_LLM_MODEL_OPENAI}, md2HtmlOptions{}, distributorSleepInterval{DEFAULT_DISTRIBUTOR_SLEEP_INTERVAL}, markdownQuoteSections{}, + recentIncludeOs{DEFAULT_RECENT_INCLUDE_OS}, uiNerdTargetAudience{DEFAULT_UI_NERD_MENU}, uiHtmlZoom{}, externalEditorCmd{}, @@ -71,6 +79,7 @@ Configuration::Configuration() uiFullOPreview{DEFAULT_FULL_O_PREVIEW}, uiShowToolbar{DEFAULT_UI_SHOW_TOOLBAR}, uiExpertMode{DEFAULT_UI_EXPERT_MODE}, + uiAppFontSize{DEFAULT_UI_APP_FONT_SIZE}, uiDistractionFreeMode{}, uiHoistedMode{}, uiLiveNotePreview{DEFAULT_UI_LIVE_NOTE_PREVIEW}, @@ -140,9 +149,14 @@ void Configuration::clear() autolinking = DEFAULT_AUTOLINKING; autolinkingColonSplit = DEFAULT_AUTOLINKING_COLON_SPLIT; autolinkingCaseInsensitive = DEFAULT_AUTOLINKING_CASE_INSENSITIVE; + wingmanProvider = DEFAULT_WINGMAN_LLM_PROVIDER; + wingmanApiKey.clear(); + wingmanOpenAiApiKey.clear(); + wingmanLlmModel.clear(); timeScopeAsString.assign(DEFAULT_TIME_SCOPE); tagsScope.clear(); markdownQuoteSections = DEFAULT_MD_QUOTE_SECTIONS; + recentIncludeOs = DEFAULT_RECENT_INCLUDE_OS; // Markdown 2 HTML options md2HtmlOptions = 0 @@ -192,6 +206,7 @@ void Configuration::clear() navigatorMaxNodes = DEFAULT_NAVIGATOR_MAX_GRAPH_NODES; uiShowToolbar = DEFAULT_UI_SHOW_TOOLBAR; uiExpertMode = DEFAULT_UI_EXPERT_MODE; + uiAppFontSize = DEFAULT_UI_APP_FONT_SIZE; uiDistractionFreeMode = false; uiHoistedMode = false; uiLiveNotePreview = DEFAULT_UI_LIVE_NOTE_PREVIEW; @@ -268,7 +283,11 @@ void Configuration::setActiveRepository( memoryPath.clear(); memoryPath += activeRepository->getDir(); - // TODO limbo class + mindPath.clear(); + mindPath += activeRepository->getDir(); + + outlinesMapPath.clear(); + limboPath.clear(); limboPath += activeRepository->getDir(); @@ -279,12 +298,18 @@ void Configuration::setActiveRepository( memoryPath+=FILE_PATH_SEPARATOR; memoryPath+=DIRNAME_MEMORY; - // TODO limbo class + mindPath+=FILE_PATH_SEPARATOR; + mindPath+=DIRNAME_MIND; + + outlinesMapPath+=mindPath; + outlinesMapPath+=FILE_PATH_SEPARATOR; + outlinesMapPath+=FILENAME_OUTLINES_MAP; + limboPath+=FILE_PATH_SEPARATOR; limboPath+=DIRNAME_LIMBO; // setting ACTIVE repository means that repository SPECIFIC configuration must be loaded - this->initRepositoryConfiguration(EisenhowerMatrix::createEisenhowMatrixOrganizer()); + this->initRepositoryConfiguration(EisenhowerMatrix::createEisenhowerMatrixOrganizer()); persistence.load(*this); } else { this->clearRepositoryConfiguration(); @@ -366,4 +391,129 @@ const char* Configuration::getEditorFromEnv() return editor; } +bool Configuration::canWingmanOpenAi() +{ + if ( + this->wingmanOpenAiApiKey.size() > 0 + || std::getenv(ENV_VAR_OPENAI_API_KEY) != nullptr + ) { + return true; + } + + return false; +} + +void Configuration::setWingmanLlmProvider(WingmanLlmProviders provider) +{ + MF_DEBUG( + "Configuration::setWingmanLlmProvider(): " + << std::to_string(provider) << endl); + + wingmanProvider = provider; + + // try to initialize Wingman @ given LLM provider, + // if it fails, then set it to false ~ disabled Wingman + initWingman(); +} + +bool Configuration::initWingmanMock() +{ + if(canWingmanMock()) { + wingmanApiKey.clear(); + wingmanLlmModel.clear(); + return true; + } + + return false; +} + +/** + * @brief Check whether OpenAI Wingman requirements are satisfied. + * + * In case that the requirements are satisfied (OpenAI API key provided), + * then Wingman @ OpenAI can be choosen @ Mindforger configuration. +*/ +bool Configuration::initWingmanOpenAi() { + MF_DEBUG(" Configuration::initWingmanOpenAi()" << endl); + if(canWingmanOpenAi()) { + MF_DEBUG( + " Wingman OpenAI API key found in the shell environment variable " + "MINDFORGER_OPENAI_API_KEY or set in MF config" << endl); + if(wingmanOpenAiApiKey.size() > 0) { + wingmanApiKey = wingmanOpenAiApiKey; + } else { + const char* apiKeyEnv = std::getenv(ENV_VAR_OPENAI_API_KEY); + MF_DEBUG(" Wingman API key loaded from the env: " << apiKeyEnv << endl); + wingmanApiKey = apiKeyEnv; + } + wingmanLlmModel = DEFAULT_WINGMAN_LLM_MODEL_OPENAI; + wingmanProvider = WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI; + return true; + } + + MF_DEBUG( + " Wingman OpenAI API key NEITHER found in the environment variable " + "MINDFORGER_OPENAI_API_KEY, NOR set in MF configuration" << endl); + wingmanApiKey.clear(); + wingmanLlmModel.clear(); + wingmanProvider = WingmanLlmProviders::WINGMAN_PROVIDER_NONE; + return false; +} + +bool Configuration::initWingman() +{ + MF_DEBUG( + " BEFORE Configuration::initWingman():" << endl << + " LLM provider: " << wingmanProvider << endl << + " OpenAI API key env var name: " << ENV_VAR_OPENAI_API_KEY << endl << + " Wingman provider API key : " << wingmanApiKey << endl + ); + + bool initialized = false; + + switch (wingmanProvider) { + case WingmanLlmProviders::WINGMAN_PROVIDER_NONE: + MF_DEBUG(" NONE Wingman CONFIGURED" << endl); + return true; +#ifdef MF_WIP + case WingmanLlmProviders::WINGMAN_PROVIDER_MOCK: + MF_DEBUG(" MOCK Wingman provider CONFIGURED" << endl); + initialized = initWingmanMock(); + break; +#endif + case WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI: + MF_DEBUG(" OpenAI Wingman provider CONFIGURED" << endl); + initialized = initWingmanOpenAi(); + break; + default: + MF_DEBUG( + " ERROR: unable to CONFIGURE UNKNOWN Wingman provider: " + << wingmanProvider << endl); + initialized = false; + } + + if(!initialized) { + wingmanProvider = WingmanLlmProviders::WINGMAN_PROVIDER_NONE; + wingmanApiKey.clear(); + wingmanLlmModel.clear(); + } + + MF_DEBUG( + " BEFORE Configuration::initWingman():" << endl << + " LLM provider: " << wingmanProvider << endl << + " OpenAI API key env var name: " << ENV_VAR_OPENAI_API_KEY << endl << + " Wingman provider API key : " << wingmanApiKey << endl + ); + + return initialized; +} + +/** + * @brief Re-initialize Wingman using configured LLM provider and return + * whether it is ready to be used. + */ +bool Configuration::isWingman() { + return WingmanLlmProviders::WINGMAN_PROVIDER_NONE==wingmanProvider?false:true; +} + } // m8r namespace diff --git a/lib/src/config/configuration.h b/lib/src/config/configuration.h index 9e72e99c..08790b19 100644 --- a/lib/src/config/configuration.h +++ b/lib/src/config/configuration.h @@ -1,7 +1,7 @@ /* configuration.h M8r configuration management - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -16,6 +16,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + +// TODO this class to be rewritten using templates and dynamic configuration +// so that adding of new configuration is easier and more robust, +// ideally there should be a configuration runtime configured by +// a data structure ~ list of configuration items + #ifndef M8R_CONFIGURATION_H_ #define M8R_CONFIGURATION_H_ @@ -23,7 +29,6 @@ #include #include #include -#include #include "repository.h" #include "time_scope.h" @@ -40,6 +45,13 @@ namespace m8r { +enum WingmanLlmProviders { + WINGMAN_PROVIDER_NONE, + WINGMAN_PROVIDER_MOCK, + WINGMAN_PROVIDER_OPENAI + // TODO WINGMAN_PROVIDER_GOOGLE, +}; + // const in constexpr makes value const constexpr const auto ENV_VAR_HOME = "HOME"; constexpr const auto ENV_VAR_DISPLAY = "DISPLAY"; @@ -51,6 +63,7 @@ constexpr const auto DIRNAME_M8R_REPOSITORY = "mindforger-repository"; constexpr const auto FILE_PATH_M8R_REPOSITORY = "~/mindforger-repository"; constexpr const auto FILENAME_M8R_CONFIGURATION = ".mindforger.md"; +constexpr const auto FILENAME_OUTLINES_MAP = "outlines-map.md"; constexpr const auto DIRNAME_MEMORY = "memory"; constexpr const auto DIRNAME_MIND = "mind"; constexpr const auto DIRNAME_LIMBO = "limbo"; @@ -66,11 +79,11 @@ constexpr const auto UI_THEME_BLACK_WITH_FIXED_FONT = "black with fixed font"; constexpr const auto UI_THEME_NATIVE = "native"; constexpr const auto UI_THEME_NATIVE_WITH_FIXED_FONT = "native with fixed font"; -constexpr const auto START_TO_DASHBOARD = "dashboard"; +constexpr const auto START_TO_OUTLINES_TREE = "outlines tree"; constexpr const auto START_TO_OUTLINES = "outlines"; constexpr const auto START_TO_TAGS = "tags"; constexpr const auto START_TO_RECENT = "recent"; -constexpr const auto START_TO_EISENHOWER_MATRIX = "Eisehower"; +constexpr const auto START_TO_EISENHOWER_MATRIX = "Eisenhower"; constexpr const auto START_TO_HOME_OUTLINE = "home"; constexpr const auto DEFAULT_STARTUP_VIEW = START_TO_OUTLINES; @@ -100,6 +113,71 @@ constexpr const auto UI_DEFAULT_HTML_CSS_THEME = UI_HTML_THEME_CSS_LIGHT; constexpr const auto UI_DEFAULT_EDITOR_FONT = "Monospace,10"; constexpr const auto UI_DEFAULT_FONT_POINT_SIZE = 10; +struct KnowledgeTool +{ + static const std::string TOOL_PHRASE; + + // knowledge tools IDs + static constexpr const auto ARXIV = "arxiv"; + static constexpr const auto WIKIPEDIA = "wikipedia"; + static constexpr const auto GH_REPOS = "github-repositories"; + static constexpr const auto GH_CODE = "github-code"; + static constexpr const auto STACK_OVERFLOW = "stackoverflow"; + static constexpr const auto DUCKDUCKGO = "duckduckgo"; + static constexpr const auto GOOGLE = "google"; + static constexpr const auto CPP = "cpp"; + static constexpr const auto PYTHON = "python"; + + std::string id; + std::string name; + std::string urlTemplate; + + KnowledgeTool( + const std::string& id, const std::string& name, const std::string& urlTemplate) + : id(id), name(name), urlTemplate(urlTemplate) {} + + static std::vector getToolIds() { + return { + ARXIV, + WIKIPEDIA, + GH_REPOS, + GH_CODE, + STACK_OVERFLOW, + DUCKDUCKGO, + GOOGLE, + CPP, + PYTHON + }; + } + + static std::string getUrlTemplateForToolId(const std::string& toolId) { + if (toolId == ARXIV) { + return "https://arxiv.org/search/?query=" + TOOL_PHRASE; + } else if (toolId == WIKIPEDIA) { + return "https://en.wikipedia.org/w/index.php?search=" + TOOL_PHRASE; + } else if (toolId == GH_REPOS) { + return "https://www.github.com/search?type=repositories&q=" + TOOL_PHRASE; + } else if (toolId == GH_CODE) { + return "https://www.github.com/search?type=code&q=" + TOOL_PHRASE; + } else if (toolId == DUCKDUCKGO) { + return "https://www.duckduckgo.com/?q=" + TOOL_PHRASE; + } else if (toolId == GOOGLE) { + return "https://www.google.com/search?q=" + TOOL_PHRASE; + } else if (toolId == STACK_OVERFLOW) { + return "https://stackoverflow.com/search?q=" + TOOL_PHRASE; + } else if (toolId == CPP) { + return "https://duckduckgo.com/?sites=cppreference.com&ia=web&q=" + TOOL_PHRASE; + } else if (toolId == PYTHON) { + return "https://docs.python.org/3.11/search.html?q=" + TOOL_PHRASE; + } + + return ""; + } +}; + +// Wingman LLM models API keys +constexpr const auto ENV_VAR_OPENAI_API_KEY = "MINDFORGER_OPENAI_API_KEY"; + // improve platform/language specific constexpr const auto DEFAULT_NEW_OUTLINE = "# New Markdown File\n\nThis is a new Markdown file created by MindForger.\n\n#Section 1\nThe first section.\n\n"; @@ -110,8 +188,8 @@ class RepositoryConfigurationPersistence; * @brief MindForger configuration. * * Configuration file (Markdown-based DSL) maintained by this class contains - * location of repositories, active repository and user preferences (for GUI - * and library). + * location of repositories, active repository and user preferences + * (for GUIand library). * * MindForger configuration file is stored in ~/.mindforger.md by default. * @@ -180,10 +258,12 @@ class Configuration { static const std::string DEFAULT_ACTIVE_REPOSITORY_PATH; static const std::string DEFAULT_TIME_SCOPE; + static const std::string DEFAULT_WINGMAN_LLM_MODEL_OPENAI; static constexpr const bool DEFAULT_AUTOLINKING = false; static constexpr const bool DEFAULT_AUTOLINKING_COLON_SPLIT = true; static constexpr const bool DEFAULT_AUTOLINKING_CASE_INSENSITIVE = true; + static constexpr const WingmanLlmProviders DEFAULT_WINGMAN_LLM_PROVIDER = WingmanLlmProviders::WINGMAN_PROVIDER_NONE; static constexpr const bool DEFAULT_SAVE_READS_METADATA = true; static constexpr const bool UI_DEFAULT_NERD_TARGET_AUDIENCE = true; @@ -191,6 +271,7 @@ class Configuration { static const std::string DEFAULT_UI_THEME_NAME; static constexpr const bool DEFAULT_UI_SHOW_TOOLBAR = true; static constexpr const bool DEFAULT_UI_EXPERT_MODE = false; + static constexpr const int DEFAULT_UI_APP_FONT_SIZE = 0; static constexpr const bool DEFAULT_UI_LIVE_NOTE_PREVIEW = true; static constexpr const bool DEFAULT_UI_NERD_MENU = false; static const std::string DEFAULT_UI_HTML_CSS_THEME; @@ -206,6 +287,7 @@ class Configuration { static constexpr const bool DEFAULT_EDITOR_AUTOSAVE = false; static constexpr const bool DEFAULT_FULL_O_PREVIEW = false; static constexpr const bool DEFAULT_MD_QUOTE_SECTIONS = true; + static constexpr const bool DEFAULT_RECENT_INCLUDE_OS= false; static constexpr const bool DEFAULT_SPELLCHECK_LIVE = true; static constexpr const bool DEFAULT_MD_HIGHLIGHT = true; static constexpr const bool DEFAULT_MD_MATH = false; @@ -224,7 +306,7 @@ class Configuration { // configured Mind state where user wants Mind to be MindState desiredMindState; // current Mind state on the way to desired state - MindState mindState; + MindState mindState; // if count(N) > asyncMindTreshold then long-running mind computations should be run in async unsigned int asyncMindThreshold; @@ -238,6 +320,8 @@ class Configuration { // active repository memory, limbo, ... paths (efficiency) std::string memoryPath; + std::string mindPath; + std::string outlinesMapPath; std::string limboPath; // repository configuration (when in repository mode) @@ -249,13 +333,65 @@ class Configuration { bool autolinking; // enable MD autolinking bool autolinkingColonSplit; bool autolinkingCaseInsensitive; + + /* + Wingman configuration, initialization and use: + + - CONFIGURATION: + - configuration initialization: + - configuration constructor(): + - configuration.llmProvider set to NONE + - configuration load(): + - configuration.llmProvider is load first - is one of: + - NONE + - MOCK + - OPEN_AI + - configuration detection whether particular Wingman provider is available: + - bool can() + - Wingman initialization from the configuration perspective + (all fields, like API key, are set ...) + - bool init() + - Wingman CONFIGURATION AVAILABILITY to the runtime: + - bool isWingman() + - Wingman is available from the configuration perspective + - MIND: + - constructor: + if Wingman configuration is available, + then instantiate a Wingman @ configured provider + - if configuration.isWingman() + then mind.wingman = Wingman() + - Wingman AVAILABILITY to the runtime: + - Wingman* mind.getWingman() + - nullptr || Wingman instance + - configuration CHANGE detection: + - mind.llmProvider used to detect configuration change + - on change: switch Wingman instance + - APP WINDOW / WINGMAN DIALOG: + - configuration CHANGE detection: + - appWindow.llmProvider used to detect configuration change + - on change: re-init Wingman DIALOG (refresh pre-defined prompts) + */ + WingmanLlmProviders wingmanProvider; // "none", "Mock", "OpenAI", ... + std::string wingmanApiKey; // API key of the currently configured Wingman LLM provider + std::string wingmanOpenAiApiKey; // OpenAI API specified by user in the config, env or UI + std::string wingmanLlmModel; // preferred LLM model the currently configured provider, like "gpt-3.5-turbo" + TimeScope timeScope; std::string timeScopeAsString; std::vector tagsScope; unsigned int md2HtmlOptions; AssociationAssessmentAlgorithm aaAlgorithm; int distributorSleepInterval; + bool markdownQuoteSections; + /** + * @brief Do include Outlines in the recent view or not. + * + * Subjectively it's better to show visited/editor Ns only as user + * can always easily get to O description + automatically added + * Os are increasing entropy of the recent view too much. + */ + bool recentIncludeOs; // GUI configuration bool uiNerdTargetAudience; @@ -286,6 +422,7 @@ class Configuration { bool uiFullOPreview; bool uiShowToolbar; bool uiExpertMode; + int uiAppFontSize; bool uiDistractionFreeMode; // fullscreen, no split, hidden toolbar + menu bool uiHoistedMode; // no split bool uiLiveNotePreview; @@ -321,6 +458,8 @@ class Configuration { } const std::string& getMemoryPath() const { return memoryPath; } + const std::string& getMindPath() const { return mindPath; } + const std::string& getOutlinesMapPath() const { return outlinesMapPath; } const std::string& getLimboPath() const { return limboPath; } const char* getRepositoryPathFromEnv(); /** @@ -399,6 +538,52 @@ class Configuration { void setDistributorSleepInterval(int sleepInterval) { distributorSleepInterval = sleepInterval; } bool isMarkdownQuoteSections() const { return markdownQuoteSections; } void setMarkdownQuoteSections(bool markdownQuoteSections) { this->markdownQuoteSections = markdownQuoteSections; } + bool isRecentIncludeOs() const { return recentIncludeOs; } + void setRecentIncludeOs(bool recentIncludeOs) { this->recentIncludeOs = recentIncludeOs; } + + /* + * Wingman + */ + void setWingmanLlmProvider(WingmanLlmProviders provider); + WingmanLlmProviders getWingmanLlmProvider() const { return wingmanProvider; } + static std::string getWingmanLlmProviderAsString(WingmanLlmProviders provider) { + if(provider == WingmanLlmProviders::WINGMAN_PROVIDER_MOCK) { + return "mock"; + } else if(provider == WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI) { + return "openai"; + } + + return "none"; + } +#ifdef MF_WIP + bool canWingmanMock() { return true; } +#else + bool canWingmanMock() { return false; } +#endif + bool canWingmanOpenAi(); +private: + bool initWingmanMock(); + bool initWingmanOpenAi(); + /** + * @brief Initialize Wingman's LLM provider. + */ + bool initWingman(); +public: + std::string getWingmanOpenAiApiKey() const { return wingmanOpenAiApiKey; } + void setWingmanOpenAiApiKey(std::string apiKey) { wingmanOpenAiApiKey = apiKey; } + /** + * @brief Get API key of the currently configured Wingman LLM provider. + */ + std::string getWingmanApiKey() const { return wingmanApiKey; } + /** + * @brief Get preferred Wingman LLM provider model name. + */ + std::string getWingmanLlmModel() const { return wingmanLlmModel; } + /** + * @brief Check whether a Wingman LLM provider is ready from + * the configuration perspective. + */ + bool isWingman(); /* * GUI @@ -444,7 +629,7 @@ class Configuration { void setUiEditorLiveSpellCheck(bool enable) { uiEditorLiveSpellCheck= enable; } std::string getUiEditorSpellCheckDefaultLanguage() const { return uiEditorSpellCheckLanguage; - } + } void setUiEditorSpellCheckDefaultLanguage(std::string lang) { uiEditorSpellCheckLanguage = lang; } @@ -541,7 +726,12 @@ class Configuration { bool isUiShowToolbar() const { return uiShowToolbar; } void setUiShowToolbar(bool showToolbar){ this->uiShowToolbar = showToolbar; } bool isUiExpertMode() const { return uiExpertMode; } - void setUiExpertMode(bool uiExpertMode){ this->uiExpertMode= uiExpertMode; } + void setUiExpertMode(bool uiExpertMode){ this->uiExpertMode = uiExpertMode; } + int getUiAppFontSize() const { return uiAppFontSize; } + void setUiAppFontSize(int appFontSize){ + MF_DEBUG("Configuration::setUiAppFontSize: " << appFontSize << std::endl); + this->uiAppFontSize = appFontSize; + } bool isUiDistractionFreeMode() const { return uiDistractionFreeMode; } void setUiDistractionFreeMode(bool distractionFreeMode){ this->uiDistractionFreeMode = distractionFreeMode; } bool isUiHoistedMode() const { return uiHoistedMode; } @@ -554,7 +744,6 @@ class Configuration { void setUiOsTableSortOrder(const bool ascending) { this->uiOsTableSortOrder = ascending; } bool isUiDoubleClickNoteViewToEdit() const { return this->uiDoubleClickNoteViewToEdit; } void setUiDoubleClickNoteViewToEdit(bool enable) { this->uiDoubleClickNoteViewToEdit = enable; } - }; } // namespace diff --git a/lib/src/config/palette.cpp b/lib/src/config/palette.cpp index a1b0a4d6..afc9940d 100644 --- a/lib/src/config/palette.cpp +++ b/lib/src/config/palette.cpp @@ -1,7 +1,7 @@ /* palette.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/palette.h b/lib/src/config/palette.h index 7a566293..d7aa8ee3 100644 --- a/lib/src/config/palette.h +++ b/lib/src/config/palette.h @@ -1,7 +1,7 @@ /* palette.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/repository.cpp b/lib/src/config/repository.cpp index 3451b582..520e5dba 100644 --- a/lib/src/config/repository.cpp +++ b/lib/src/config/repository.cpp @@ -1,7 +1,7 @@ /* repository.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/repository.h b/lib/src/config/repository.h index 1b82ef0d..79652f3c 100644 --- a/lib/src/config/repository.h +++ b/lib/src/config/repository.h @@ -1,7 +1,7 @@ /* repository.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -35,9 +35,9 @@ class Repository /** * @brief Repository type. * - * MindForger repository is a directory with sub-directories enabling advanced - * knowledge organization and memory/ directory with Outlines written in Markdown-based - * DSL (metadata enriched) format. + * MindForger repository is a directory with sub-directories enabling + * knowledge organization and memory/ directory with Outlines written + * in Markdown-based DSL (metadata enriched) format. * * Markdown repository is any directory structure containing Markdown files. */ diff --git a/lib/src/config/repository_configuration.cpp b/lib/src/config/repository_configuration.cpp index f607ca24..4645b078 100644 --- a/lib/src/config/repository_configuration.cpp +++ b/lib/src/config/repository_configuration.cpp @@ -1,7 +1,7 @@ /* repository_configuration.cpp M8r configuration management - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/repository_configuration.h b/lib/src/config/repository_configuration.h index 3da7591a..d59e6472 100644 --- a/lib/src/config/repository_configuration.h +++ b/lib/src/config/repository_configuration.h @@ -1,7 +1,7 @@ /* repository_configuration.h M8r configuration management - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/time_scope.cpp b/lib/src/config/time_scope.cpp index adbda343..914e2906 100644 --- a/lib/src/config/time_scope.cpp +++ b/lib/src/config/time_scope.cpp @@ -1,7 +1,7 @@ /* time_scope.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/config/time_scope.h b/lib/src/config/time_scope.h index 645940e7..22654725 100644 --- a/lib/src/config/time_scope.h +++ b/lib/src/config/time_scope.h @@ -1,7 +1,7 @@ /* time_scope.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/debug.h b/lib/src/debug.h index 0c87d801..59a12987 100644 --- a/lib/src/debug.h +++ b/lib/src/debug.h @@ -1,7 +1,7 @@ /* debug.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -34,12 +34,13 @@ // enable/disable verbose debug of particular components //#define MF_DEBUG_HTML //#define MF_DEBUG_ASYNC_TASKS - //#define MF_DEBUG_QRC //#define MF_DEBUG_L10N //#define MF_DEBUG_AUTOLINKING + //#define MF_DEBUG_LIBRARY // show WIP features #define MF_WIP + #define MF_WIP_WINGMAN // future timestamps check #define MF_ASSERT_WHERE " (" << __FILE__ << ":" << __LINE__ << ")" diff --git a/lib/src/definitions.h b/lib/src/definitions.h index 1e5a210f..e5b428c1 100644 --- a/lib/src/definitions.h +++ b/lib/src/definitions.h @@ -1,7 +1,7 @@ /* definitions.h MindForger type, include, ... definitions - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/exceptions.h b/lib/src/exceptions.h index d5f646cc..a1ee2f65 100644 --- a/lib/src/exceptions.h +++ b/lib/src/exceptions.h @@ -1,7 +1,7 @@ /* exceptions.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/async_utils.cpp b/lib/src/gear/async_utils.cpp index 6e581e86..391752e8 100644 --- a/lib/src/gear/async_utils.cpp +++ b/lib/src/gear/async_utils.cpp @@ -1,7 +1,7 @@ /* async_utils.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/async_utils.h b/lib/src/gear/async_utils.h index 0382f08d..66e4a5ce 100644 --- a/lib/src/gear/async_utils.h +++ b/lib/src/gear/async_utils.h @@ -1,7 +1,7 @@ /* async_utils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/datetime_utils.cpp b/lib/src/gear/datetime_utils.cpp index 97ea7c05..c2026d96 100644 --- a/lib/src/gear/datetime_utils.cpp +++ b/lib/src/gear/datetime_utils.cpp @@ -1,7 +1,7 @@ /* datetime_utils.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/datetime_utils.h b/lib/src/gear/datetime_utils.h index c3cb92df..1b26f3b3 100644 --- a/lib/src/gear/datetime_utils.h +++ b/lib/src/gear/datetime_utils.h @@ -1,7 +1,7 @@ /* datetime_utils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/file_utils.cpp b/lib/src/gear/file_utils.cpp index bf0f7f1a..18f538e2 100644 --- a/lib/src/gear/file_utils.cpp +++ b/lib/src/gear/file_utils.cpp @@ -1,7 +1,7 @@ /* file_utils.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -451,7 +451,8 @@ bool isPathRelative(const string& path) } } -bool createDirectory(const string& path) { +bool createDirectory(const string& path) +{ #ifdef _WIN32 int e = _mkdir(path.c_str()); #else @@ -466,6 +467,46 @@ bool createDirectory(const string& path) { } } +bool createDirectories(const string& path) +{ +#if defined(_WIN32) + int ret = _mkdir(path.c_str()); +#else + mode_t mode = 0755; + int ret = mkdir(path.c_str(), mode); +#endif + if (ret == 0) + return true; + + switch (errno) { + case ENOENT: + // parent didn't exist, try to create it + { + size_t pos = path.find_last_of('/'); + if (pos == std::string::npos) +#if defined(_WIN32) + pos = path.find_last_of('\\'); + if (pos == std::string::npos) +#endif + return false; + if (!createDirectories( path.substr(0, pos) )) + return false; + } + // now, try to create again +#if defined(_WIN32) + return 0 == _mkdir(path.c_str()); +#else + return 0 == mkdir(path.c_str(), mode); +#endif + + case EEXIST: + return isDirectory(path.c_str()); + + default: + return false; + } +} + char* makeTempDirectory(char* dirNamePrefix) { #ifdef _WIN32 diff --git a/lib/src/gear/file_utils.h b/lib/src/gear/file_utils.h index c0a3b429..35572f6a 100644 --- a/lib/src/gear/file_utils.h +++ b/lib/src/gear/file_utils.h @@ -1,7 +1,7 @@ /* file_utils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -246,12 +246,18 @@ int removeDirectoryRecursively(const char* path); int copyDirectoryRecursively(const char* srcPath, const char* dstPath, bool extractGz=false); bool createDirectory(const std::string& path); +/** + * @brief Create directory including (non-existent) parent directories. + */ +bool createDirectories(const std::string& path); + /** * @brief Get path to the the executable on macOS or windows. Othewise returns nullptr. * * Method is not reentrant - it returns pointer to the static buffer. */ char* getExecutablePath(); + } // m8r namespace #endif /* M8R_FILE_UTILS_H_ */ diff --git a/lib/src/gear/hash_map.h b/lib/src/gear/hash_map.h index 2b66c168..9738f92e 100644 --- a/lib/src/gear/hash_map.h +++ b/lib/src/gear/hash_map.h @@ -1,7 +1,7 @@ /* hash_map.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/lang_utils.h b/lib/src/gear/lang_utils.h index f4038732..7a9f2a6b 100644 --- a/lib/src/gear/lang_utils.h +++ b/lib/src/gear/lang_utils.h @@ -1,7 +1,7 @@ /* lang-utils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/math_utils.cpp b/lib/src/gear/math_utils.cpp index 12d12a19..14abbf59 100644 --- a/lib/src/gear/math_utils.cpp +++ b/lib/src/gear/math_utils.cpp @@ -1,7 +1,7 @@ /* math_utils.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/math_utils.h b/lib/src/gear/math_utils.h index a579ff24..f0580a87 100644 --- a/lib/src/gear/math_utils.h +++ b/lib/src/gear/math_utils.h @@ -1,7 +1,7 @@ /* math_utils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/string_utils.cpp b/lib/src/gear/string_utils.cpp index 7c98082d..31fbdee3 100644 --- a/lib/src/gear/string_utils.cpp +++ b/lib/src/gear/string_utils.cpp @@ -1,7 +1,7 @@ /* string-utils.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/gear/string_utils.h b/lib/src/gear/string_utils.h index 257220b9..4475c491 100644 --- a/lib/src/gear/string_utils.h +++ b/lib/src/gear/string_utils.h @@ -1,7 +1,7 @@ /* string-utils.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -59,7 +59,7 @@ std::vector stringSplit(const std::string s, const std::string rege std::string normalizeToNcName(std::string name, char quoteChar); /** - * @brief Check wheter strings are identical while ignoring case. + * @brief Check whether the strings are identical while ignoring case. */ static inline bool stringistring(const std::string& a, const std::string& b) { @@ -88,7 +88,7 @@ static inline void stringToLower(const std::string& s, std::string& lowerS) * * New trimmed string is created and returned - caller is responsible for freeing it. */ -static inline char *stringTrim(const char *s) { +static inline char* stringTrim(const char* s) { if(s) { while(isspace(static_cast(*s))) { s++; diff --git a/lib/src/gear/trie.cpp b/lib/src/gear/trie.cpp index 467a82fc..7c3e6fcd 100644 --- a/lib/src/gear/trie.cpp +++ b/lib/src/gear/trie.cpp @@ -1,7 +1,7 @@ /* trie.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -34,7 +34,7 @@ Trie::~Trie() } void Trie::destroy(Node* n) -{ +{ for(Node* c:n->mChildren) { destroy(c); } diff --git a/lib/src/gear/trie.h b/lib/src/gear/trie.h index 63d51043..a834930d 100644 --- a/lib/src/gear/trie.h +++ b/lib/src/gear/trie.h @@ -1,7 +1,7 @@ /* trie.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/install/installer.cpp b/lib/src/install/installer.cpp index 21caedf1..fabda199 100644 --- a/lib/src/install/installer.cpp +++ b/lib/src/install/installer.cpp @@ -1,7 +1,7 @@ /* installer.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/install/installer.h b/lib/src/install/installer.h index 5fc3f5dd..4c3e8182 100644 --- a/lib/src/install/installer.h +++ b/lib/src/install/installer.h @@ -1,7 +1,7 @@ /* installer.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/aa_model.cpp b/lib/src/mind/ai/aa_model.cpp index b9825e42..cee616f2 100644 --- a/lib/src/mind/ai/aa_model.cpp +++ b/lib/src/mind/ai/aa_model.cpp @@ -1,7 +1,7 @@ /* aa_model.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/aa_model.h b/lib/src/mind/ai/aa_model.h index bf077fd8..3ea7e2f4 100644 --- a/lib/src/mind/ai/aa_model.h +++ b/lib/src/mind/ai/aa_model.h @@ -1,7 +1,7 @@ /* aa_model.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/aa_notes_feature.cpp b/lib/src/mind/ai/aa_notes_feature.cpp index 32f30369..68e71396 100644 --- a/lib/src/mind/ai/aa_notes_feature.cpp +++ b/lib/src/mind/ai/aa_notes_feature.cpp @@ -1,7 +1,7 @@ /* aa_notes_feature.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/aa_notes_feature.h b/lib/src/mind/ai/aa_notes_feature.h index b759ddbe..a0409c85 100644 --- a/lib/src/mind/ai/aa_notes_feature.h +++ b/lib/src/mind/ai/aa_notes_feature.h @@ -1,7 +1,7 @@ /* aa_notes_feature.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/ai.cpp b/lib/src/mind/ai/ai.cpp index 45ec930a..3179c8c6 100644 --- a/lib/src/mind/ai/ai.cpp +++ b/lib/src/mind/ai/ai.cpp @@ -1,7 +1,7 @@ /* ai.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,9 +23,6 @@ namespace m8r { using namespace std; Ai::Ai(Memory& memory, Mind& mind) -#ifdef MF_NER - : ner{} -#endif { switch(Configuration::getInstance().getAaAlgorithm()) { case Configuration::AssociationAssessmentAlgorithm::BOW: @@ -37,12 +34,6 @@ Ai::Ai(Memory& memory, Mind& mind) default: aa = nullptr; } - -#ifdef MF_NER - // TODO get MODEL location from configuration - static std::string nerModelPath{"/home/dvorka/p/mindforger/lab/ner/MITIE/MITIE-models/english/ner_model.dat"}; - ner.setNerModel(nerModelPath); -#endif } Ai::~Ai() diff --git a/lib/src/mind/ai/ai.h b/lib/src/mind/ai/ai.h index 3116b0e4..d57c9f7e 100644 --- a/lib/src/mind/ai/ai.h +++ b/lib/src/mind/ai/ai.h @@ -1,7 +1,7 @@ /* ai.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -29,9 +29,6 @@ #include "./aa_model.h" #include "./ai_aa_weighted_fts.h" #include "./ai_aa_bow.h" -#ifdef MF_NER - #include "./nlp/named_entity_recognition.h" -#endif namespace m8r { @@ -73,17 +70,9 @@ class Ai * Associations */ - // Associations assessment implemenations: AA @ weighted FTS, AA @ BoW + // Associations assessment implementations: AA @ weighted FTS, AA @ BoW AiAssociationsAssessment* aa; -#ifdef MF_NER - /* - * Named-entity recognition (NER) - */ - - NamedEntityRecognition ner; -#endif - /* * Neural network models */ @@ -127,17 +116,6 @@ class Ai return aa->getAssociatedNotes(words, associations, self); } -#ifdef MF_NER - bool isNerInitialized() const { return ner.isInitialized(); } - - /** - * @brief Recognize person names in O. - */ - void recognizePersons(const Outline* outline, int entityFilter, std::vector& result) { - ner.recognizePersons(outline, entityFilter, result); - } -#endif - /** * @brief Clear, but don't deallocate. * @@ -163,8 +141,8 @@ class Ai */ void trainAaNn(); -public: #ifdef DO_MF_DEBUG +public: static void print(const Note* n, std::vector>& leaderboard) { std::cout << "Note '" << n->getName() << "' AA leaderboard("<< leaderboard.size() <<"):" << std::endl; int i=1; @@ -173,6 +151,7 @@ class Ai } } #endif + }; } diff --git a/lib/src/mind/ai/ai_aa.h b/lib/src/mind/ai/ai_aa.h index d021e05b..0e70166f 100644 --- a/lib/src/mind/ai/ai_aa.h +++ b/lib/src/mind/ai/ai_aa.h @@ -1,7 +1,7 @@ /* ai_aa.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/ai_aa_bow.cpp b/lib/src/mind/ai/ai_aa_bow.cpp index 96153a49..22bbf253 100644 --- a/lib/src/mind/ai/ai_aa_bow.cpp +++ b/lib/src/mind/ai/ai_aa_bow.cpp @@ -1,7 +1,7 @@ /* ai_aa_bow.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -147,7 +147,7 @@ shared_future AiAaBoW::getAssociatedNotes(const Note* note, vector p{}; p.set_value(true); return shared_future(p.get_future()); - } else { + } else { MF_DEBUG("AA.BoW: ASYNC leaderboard calculation for '" << note->getName() << "'" << endl); if(leaderboardWip.find(note) != leaderboardWip.end()) { // calculation WIP & future OWNER will update what needs to be updated -> intentionally NOT sharing futures diff --git a/lib/src/mind/ai/ai_aa_bow.h b/lib/src/mind/ai/ai_aa_bow.h index 3393069b..477c8a40 100644 --- a/lib/src/mind/ai/ai_aa_bow.h +++ b/lib/src/mind/ai/ai_aa_bow.h @@ -1,7 +1,7 @@ /* ai_aa_bow.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/ai_aa_weighted_fts.cpp b/lib/src/mind/ai/ai_aa_weighted_fts.cpp index 22020888..18e8bb2c 100644 --- a/lib/src/mind/ai/ai_aa_weighted_fts.cpp +++ b/lib/src/mind/ai/ai_aa_weighted_fts.cpp @@ -1,7 +1,7 @@ /* ai_aa_weighted_fts.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -112,7 +112,7 @@ void AiAaWeightedFts::tokenizeAndStripString(string s, const bool ignoreCase, ve } vector>* AiAaWeightedFts::assessNotesWithFallback(const string& regexp, Outline* scope, const Note* self) -{ +{ vector>* result = new vector>(); if(regexp.empty()) return result; diff --git a/lib/src/mind/ai/ai_aa_weighted_fts.h b/lib/src/mind/ai/ai_aa_weighted_fts.h index 0a77a5ea..34906c3e 100644 --- a/lib/src/mind/ai/ai_aa_weighted_fts.h +++ b/lib/src/mind/ai/ai_aa_weighted_fts.h @@ -1,7 +1,7 @@ /* ai_aa_weighted_fts.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/autolinking/autolinking_mind.cpp b/lib/src/mind/ai/autolinking/autolinking_mind.cpp index fc67a52f..5dbd992f 100644 --- a/lib/src/mind/ai/autolinking/autolinking_mind.cpp +++ b/lib/src/mind/ai/autolinking/autolinking_mind.cpp @@ -1,7 +1,7 @@ /* autolinking_mind.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -26,6 +26,8 @@ namespace m8r { using namespace std; +const vector AutolinkingMind::excludedWords({"http", "https"}); + AutolinkingMind::AutolinkingMind(Mind& mind) : mind{mind}, trie{nullptr} @@ -76,11 +78,19 @@ void AutolinkingMind::updateTrieIndex() addThingToTrie(n); } + // remove excluded words whose autolinking breaks + // Markdown structure (like e.g. http:// in links) + for(const string& s:this->excludedWords) { + trie->removeWord(s); + } + // IMPROVE: add also tags #ifdef DO_MF_DEBUG auto end = chrono::high_resolution_clock::now(); - MF_DEBUG("[Autolinking] trie w/ " << size << " things updated in: " << chrono::duration_cast(end-begin).count()/1000000.0 << "ms" << endl); + MF_DEBUG( + "[Autolinking] trie w/ " << size << " things updated in: " + << chrono::duration_cast(end-begin).count()/1000000.0 << "ms" << endl); #endif } diff --git a/lib/src/mind/ai/autolinking/autolinking_mind.h b/lib/src/mind/ai/autolinking/autolinking_mind.h index b31e92ed..2a3f89cb 100644 --- a/lib/src/mind/ai/autolinking/autolinking_mind.h +++ b/lib/src/mind/ai/autolinking/autolinking_mind.h @@ -1,7 +1,7 @@ /* autolinking_mind.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -42,6 +42,7 @@ class AutolinkingMind Trie* trie; + static const std::vector excludedWords; public: explicit AutolinkingMind(Mind& mind); AutolinkingMind(const AutolinkingMind&) = delete; diff --git a/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.cpp b/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.cpp index 9702d6ff..16012c37 100644 --- a/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.cpp +++ b/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.cpp @@ -1,7 +1,7 @@ /* cmark_aho_corasick_block_autolinking_preprocessor.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -269,7 +269,8 @@ void injectThingsLinks(cmark_node* srcNode, Mind& mind) * Preprocessor. */ -const string CmarkAhoCorasickBlockAutolinkingPreprocessor::TRAILING_CHARS = string{" \t,:;.!?<>{}&()-+/*\\_=%~#$^[]'\""}; +const string CmarkAhoCorasickBlockAutolinkingPreprocessor::TRAILING_CHARS + = string{" \t,:;.!?<>{}&()-+/*\\_=%~#$^[]'\""}; CmarkAhoCorasickBlockAutolinkingPreprocessor::CmarkAhoCorasickBlockAutolinkingPreprocessor(Mind& mind) : AutolinkingPreprocessor{mind} diff --git a/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.h b/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.h index 6c93d461..f51dcee6 100644 --- a/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.h +++ b/lib/src/mind/ai/autolinking/cmark_aho_corasick_block_autolinking_preprocessor.h @@ -1,7 +1,7 @@ /* cmark_aho_corasick_block_autolinking_preprocessor.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.cpp b/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.cpp index 733fbf8c..adb42f55 100644 --- a/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.cpp +++ b/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.cpp @@ -1,7 +1,7 @@ /* cmark_trie_line_autolinking_preprocessor.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.h b/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.h index 970b6e16..7e976755 100644 --- a/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.h +++ b/lib/src/mind/ai/autolinking/cmark_trie_line_autolinking_preprocessor.h @@ -1,7 +1,7 @@ /* cmark_trie_line_autolinking_preprocessor.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.cpp b/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.cpp index 53eac510..403fb193 100644 --- a/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.cpp +++ b/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.cpp @@ -1,7 +1,7 @@ /* naive_autolinking_preprocessor.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -118,7 +118,7 @@ void NaiveAutolinkingPreprocessor::process(const vector& md, string &am // skip code/math/... blocks if(stringStartsWith(*l, CODE_BLOCK)) { - inCodeBlock = !inCodeBlock; + inCodeBlock = !inCodeBlock; nl->append(*l); amdl.push_back(nl); diff --git a/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.h b/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.h index e2dbdf66..74f5cd0c 100644 --- a/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.h +++ b/lib/src/mind/ai/autolinking/naive_autolinking_preprocessor.h @@ -1,7 +1,7 @@ /* naive_autolinking_preprocessor.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/autolinking_preprocessor.cpp b/lib/src/mind/ai/autolinking_preprocessor.cpp index 5c99e639..12839fe8 100644 --- a/lib/src/mind/ai/autolinking_preprocessor.cpp +++ b/lib/src/mind/ai/autolinking_preprocessor.cpp @@ -1,7 +1,7 @@ /* autolinking_preprocessor.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/autolinking_preprocessor.h b/lib/src/mind/ai/autolinking_preprocessor.h index 4e92ebcf..2cb0fba7 100644 --- a/lib/src/mind/ai/autolinking_preprocessor.h +++ b/lib/src/mind/ai/autolinking_preprocessor.h @@ -1,7 +1,7 @@ /* autolinking_preprocessor.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/ner_named_entity.cpp b/lib/src/mind/ai/llm/bard_wingman.cpp similarity index 76% rename from lib/src/mind/ai/nlp/ner_named_entity.cpp rename to lib/src/mind/ai/llm/bard_wingman.cpp index c2d5be45..73c08647 100644 --- a/lib/src/mind/ai/nlp/ner_named_entity.cpp +++ b/lib/src/mind/ai/llm/bard_wingman.cpp @@ -1,7 +1,7 @@ /* - ner_named_entity.cpp MindForger thinking notebook + bard_wingman.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -16,7 +16,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "ner_named_entity.h" +#include "bard_wingman.h" namespace m8r { + +BardWingman::BardWingman() +{ +} + +BardWingman::~BardWingman() +{ +} + } // m8r namespace diff --git a/lib/src/mind/ai/llm/bard_wingman.h b/lib/src/mind/ai/llm/bard_wingman.h new file mode 100644 index 00000000..f950725b --- /dev/null +++ b/lib/src/mind/ai/llm/bard_wingman.h @@ -0,0 +1,100 @@ +/* + bard_wingman.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8R_BARD_WINGMAN_H +#define M8R_BARD_WINGMAN_H + +namespace m8r { + +/* + +PaLM2 prompt: Give C++ call to bard API to get inference + +ANSWER: + +To call the Bard API in C++ to get an inference, you can use the following code: + +#include +#include + +int main() { + // Initialize CURL + CURL *curl = curl_easy_init(); + if (!curl) { + std::cerr << "Failed to initialize CURL" << std::endl; + return 1; + } + + // Set the URL of the Bard API endpoint + curl_easy_setopt(curl, CURLOPT_URL, "https://bard.google.com/v2/query"); + + // Set the request body + std::string requestBody = "query=Hello, world!"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestBody.c_str()); + + // Set the content type + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, + std::vector({ + {"Content-Type: application/json"}, + })); + + // Perform the request + CURLcode res = curl_easy_perform(curl); + if (res != CURLE_OK) { + std::cerr << "Failed to perform the request: " << curl_easy_strerror(res) + << std::endl; + return 1; + } + + // Get the response + std::string responseBody; + curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &responseBody.size()); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res); + if (res != CURLE_OK || responseBody.empty()) { + std::cerr << "Failed to get a valid response" << std::endl; + return 1; + } + + // Read the response body + std::vector responseBuffer(responseBody.size()); + curl_easy_read_buffer(curl, responseBuffer.data(), responseBuffer.size()); + responseBody.assign(responseBuffer.data(), responseBuffer.size()); + + // Close the connection + curl_easy_cleanup(curl); + + // Print the response + std::cout << responseBody << std::endl; + + return 0; +} + +*/ +class BardWingman +{ +public: + explicit BardWingman(); + BardWingman(const BardWingman&) = delete; + BardWingman(const BardWingman&&) = delete; + BardWingman& operator =(const BardWingman&) = delete; + BardWingman& operator =(const BardWingman&&) = delete; + ~BardWingman(); +}; + +} +#endif // M8R_BARD_WINGMAN_H diff --git a/app/src/qt/note_edit_model.cpp b/lib/src/mind/ai/llm/llamacpp_wingman.cpp similarity index 66% rename from app/src/qt/note_edit_model.cpp rename to lib/src/mind/ai/llm/llamacpp_wingman.cpp index 5a11e626..1afe0bb5 100644 --- a/app/src/qt/note_edit_model.cpp +++ b/lib/src/mind/ai/llm/llamacpp_wingman.cpp @@ -1,7 +1,7 @@ /* - note_edit_model.cpp MindForger thinking notebook + llamacpp_wingman.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -10,18 +10,22 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "note_edit_model.h" +#include "llamacpp_wingman.h" namespace m8r { -NoteEditModel::NoteEditModel() +LlamaCppWingman::LlamaCppWingman() { } +LlamaCppWingman::~LlamaCppWingman() +{ } + +} // m8r namespace diff --git a/lib/src/mind/ai/llm/llamacpp_wingman.h b/lib/src/mind/ai/llm/llamacpp_wingman.h new file mode 100644 index 00000000..492f7f00 --- /dev/null +++ b/lib/src/mind/ai/llm/llamacpp_wingman.h @@ -0,0 +1,49 @@ +/* + llamacpp_wingman.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8R_LLAMACPP_WINGMAN_H +#define M8R_LLAMACPP_WINGMAN_H + +namespace m8r { + +/** + * llama.cpp Wingman implementation. + * + * LLM models to use: + * + * - llama 7B + * - llama-2-7b.Q4_0.gguf + * - Zephir 7B + * - ?.gguf + * - Mistral 7B + * - ?.gguf + * + */ +class LlamaCppWingman +{ +public: + explicit LlamaCppWingman(); + LlamaCppWingman(const LlamaCppWingman&) = delete; + LlamaCppWingman(const LlamaCppWingman&&) = delete; + LlamaCppWingman& operator =(const LlamaCppWingman&) = delete; + LlamaCppWingman& operator =(const LlamaCppWingman&&) = delete; + ~LlamaCppWingman(); +}; + +} +#endif // M8R_LLAMACPP_WINGMAN_H diff --git a/lib/src/mind/ai/llm/mock_wingman.cpp b/lib/src/mind/ai/llm/mock_wingman.cpp new file mode 100644 index 00000000..481f9379 --- /dev/null +++ b/lib/src/mind/ai/llm/mock_wingman.cpp @@ -0,0 +1,49 @@ +/* + mock_wingman.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "mock_wingman.h" + +namespace m8r { + +using namespace std; + +MockWingman::MockWingman(const string& llmModel) + : Wingman(WingmanLlmProviders::WINGMAN_PROVIDER_MOCK), + llmModel{llmModel} +{ +} + +MockWingman::~MockWingman() +{ +} + +void MockWingman::chat(CommandWingmanChat& command) { + MF_DEBUG("MockWingman::chat() prompt:" << command.prompt << endl); + + command.httpResponse.clear(); + command.status=WingmanStatusCode::WINGMAN_STATUS_CODE_OK; + command.errorMessage.clear(); + command.answerLlmModel.assign(this->llmModel); + command.promptTokens=42; + command.answerTokens=42198; + command.answerMarkdown.assign("chat(MOCK, '"+command.prompt+"')"); + + MF_DEBUG("MockWingman::chat() answer:" << command.answerMarkdown << endl); +} + +} // m8r namespace diff --git a/lib/src/mind/ai/llm/mock_wingman.h b/lib/src/mind/ai/llm/mock_wingman.h new file mode 100644 index 00000000..8ca9a8da --- /dev/null +++ b/lib/src/mind/ai/llm/mock_wingman.h @@ -0,0 +1,47 @@ +/* + mock_wingman.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8R_MOCK_WINGMAN_H +#define M8R_MOCK_WINGMAN_H + +#include "wingman.h" + +namespace m8r { + +/** + * Mock Wingman implementation. + */ +class MockWingman: Wingman +{ + std::string llmModel; + +public: + explicit MockWingman(const std::string& llmModel); + MockWingman(const MockWingman&) = delete; + MockWingman(const MockWingman&&) = delete; + MockWingman& operator =(const MockWingman&) = delete; + MockWingman& operator =(const MockWingman&&) = delete; + ~MockWingman() override; + + std::string getWingmanLlmModel() const { return llmModel; } + + virtual void chat(CommandWingmanChat& command) override; +}; + +} +#endif // M8R_MOCK_WINGMAN_H diff --git a/lib/src/mind/ai/llm/openai_wingman.cpp b/lib/src/mind/ai/llm/openai_wingman.cpp new file mode 100644 index 00000000..b6b7ce77 --- /dev/null +++ b/lib/src/mind/ai/llm/openai_wingman.cpp @@ -0,0 +1,366 @@ +/* + openai_wingman.cpp MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "openai_wingman.h" + +#include "../../../representations/json/nlohmann/json.hpp" + +#include "../../../gear/string_utils.h" + +namespace m8r { + +using namespace std; + +/* + * cURL callback for writing data to string. + */ + +size_t openaiCurlWriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) { + size_t totalSize = size * nmemb; + output->append((char*)contents, totalSize); + return totalSize; +} + +/* + * OpenAi Wingman class implementation. + */ + +OpenAiWingman::OpenAiWingman( + const string& apiKey, + const std::string& llmModel +) + : Wingman(WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI), + apiKey{apiKey}, + llmModel{llmModel} +{ + MF_DEBUG("OpenAiWingman::OpenAiWingman() apiKey: " << apiKey << endl); +} + +OpenAiWingman::~OpenAiWingman() +{ +} + +/** + * OpenAI cURL GET request. + * + * @see https://platform.openai.com/docs/guides/text-generation/chat-completions-api?lang=curl + * @see https://github.com/nlohmann/json?tab=readme-ov-file + * @see https://json.nlohmann.me/ + */ +void OpenAiWingman::curlGet(CommandWingmanChat& command) { +#if !defined(__APPLE__) && !defined(_WIN32) + CURL* curl = curl_easy_init(); + if (curl) { +#endif + string escapedPrompt{command.prompt}; + replaceAll("\n", " ", escapedPrompt); + replaceAll("\"", "\\\"", escapedPrompt); + + /* + OpenAI API JSon request example (see unit test): + + { + "messages": [ + { + "content": "You are a helpful assistant.", + "role": "system" + }, + { + "content": "Hey hello! I'm MindForger user - how can you help me?", + "role": "user" + } + ], + "model": "gpt-3.5-turbo" + } + + */ + nlohmann::json messageSystemJSon{}; + messageSystemJSon["role"] = "system"; // system (instruct GPT who it is), user (user prompts), assistant (GPT answers) + messageSystemJSon["content"] = + // "You are a helpful assistant that returns HTML-formatted answers to the user's prompts." + "You are a helpful assistant." + ; + // ... more messages like above (with chat history) can be created to provide context + nlohmann::json messageUserJSon{}; + messageUserJSon["role"] = "user"; + messageUserJSon["content"] = escapedPrompt; + + nlohmann::json requestJSon; + requestJSon["model"] = llmModel; + requestJSon["messages"] = nlohmann::json::array( + { + messageSystemJSon, + messageUserJSon, + } + ); + string requestJSonStr = requestJSon.dump(4); + + MF_DEBUG( + "OpenAiWingman::curlGet() promptJSon:" << endl + << ">>>" + << requestJSonStr + << "<<<" + << endl); + +#if defined(_WIN32) || defined(__APPLE__) + /* Qt Networking examples: + * + * - https://forum.qt.io/topic/116601/qnetworkaccessmanager-reply-is-always-empty/7 + * - https://community.openai.com/t/qt-interface-w-chatgpt-api/354900 + * - https://gist.github.com/FONQRI/d8fb13150c1e6760f1b1617730559418 + */ + + QNetworkAccessManager networkManager; + + QNetworkRequest request(QUrl("https://api.openai.com/v1/chat/completions")); + request.setHeader( + QNetworkRequest::ContentTypeHeader, + "application/json"); + request.setRawHeader( + "Authorization", + "Bearer " + QString::fromStdString(apiKey).toUtf8()); + + QNetworkReply* reply = networkManager.post( + request, + requestJSonStr.c_str() + ); + QEventLoop loop; + QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + reply->deleteLater(); + + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_OK; + + // response: error handling + auto error = reply->error(); + if(error != QNetworkReply::NoError) { + command.errorMessage = + "Error: request to OpenAI Wingman provider failed due a network error - " + + reply->errorString().toStdString(); + MF_DEBUG(command.errorMessage << endl); + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + } + QByteArray read; + if(command.status == m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_OK) { + read = reply->readAll(); + + if(read.isEmpty()) { + command.errorMessage = + "Error: Request to OpenAI Wingman provider failed - response is empty'"; + MF_DEBUG(command.errorMessage << endl); + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + } + } + + // response: successful response processing + if(command.status == m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_OK) { + QString qCommandResponse = QString{read}; + command.httpResponse = qCommandResponse.toStdString(); + command.errorMessage.clear(); + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_OK; + MF_DEBUG( + "Successful OpenAI Wingman provider response:" << endl << + " '" << command.httpResponse << "'" << endl); + } +#else + // set up cURL options + command.httpResponse.clear(); + curl_easy_setopt( + curl, CURLOPT_URL, + "https://api.openai.com/v1/chat/completions"); + curl_easy_setopt( + curl, CURLOPT_POSTFIELDS, + requestJSonStr.c_str()); + curl_easy_setopt( + curl, CURLOPT_WRITEFUNCTION, + openaiCurlWriteCallback); + curl_easy_setopt( + curl, CURLOPT_WRITEDATA, + &command.httpResponse); + + struct curl_slist* headers = NULL; + headers = curl_slist_append(headers, ("Authorization: Bearer " + apiKey).c_str()); + headers = curl_slist_append(headers, "Content-Type: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + // perform the request + CURLcode res = curl_easy_perform(curl); + + // clean up + curl_easy_cleanup(curl); + curl_slist_free_all(headers); + + if (res != CURLE_OK) { + command.status = WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + command.errorMessage = curl_easy_strerror(res); + } else { + command.status = WingmanStatusCode::WINGMAN_STATUS_CODE_OK; + } +#endif + + // finish error handling (shared by QNetwork/CURL) + if(command.status == WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR) { + std::cerr << + "Error: Wingman OpenAI cURL/QtNetwork request failed (error message/HTTP response):" << endl << + " '" << command.errorMessage << "'" << endl << + " '" << command.httpResponse << "'" << endl; + + command.httpResponse.clear(); + command.answerMarkdown.clear(); + command.answerTokens = 0; + command.answerLlmModel = llmModel; + + return; + } + + // parse JSon + /* + OpenAI API JSon response example: + { + "id": "chatcmpl-8gspbsufrxF42A6JfaiwuxoitQ1fT", + "object": "chat.completion", + "created": 1705231239, + "model": "gpt-3.5-turbo-0613", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "...LLM answer...", + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 26, + "completion_tokens": 491, + "total_tokens": 517 + }, + "system_fingerprint": null + } + */ + + // parse response string to JSon object + nlohmann::json httpResponseJSon; + try { + httpResponseJSon = nlohmann::json::parse(command.httpResponse); + } catch (...) { + // catch ALL exceptions + MF_DEBUG( + "Error: unable to parse OpenAI JSon response:" << endl << + "'" << command.httpResponse << "'" << endl + ); + + command.status = WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + command.errorMessage = "Error: unable to parse OpenAI JSon response: '" + command.httpResponse + "'"; + command.answerMarkdown.clear(); + command.answerTokens = 0; + command.answerLlmModel = llmModel; + + return; + } + + MF_DEBUG( + "OpenAiWingman::curlGet() parsed response:" << endl + << ">>>" + << httpResponseJSon.dump(4) + << "<<<" + << endl); + + MF_DEBUG("OpenAiWingman::curlGet() fields:" << endl); + if(httpResponseJSon.contains("model")) { + httpResponseJSon["model"].get_to(command.answerLlmModel); + MF_DEBUG(" model: " << command.answerLlmModel << endl); + } + if(httpResponseJSon.contains("usage")) { + if(httpResponseJSon["usage"].contains("prompt_tokens")) { + httpResponseJSon["usage"]["prompt_tokens"].get_to(command.promptTokens); + MF_DEBUG(" prompt_tokens: " << command.promptTokens << endl); + } + if(httpResponseJSon["usage"].contains("completion_tokens")) { + httpResponseJSon["usage"]["completion_tokens"].get_to(command.answerTokens); + MF_DEBUG(" answer_tokens: " << command.answerTokens << endl); + } + } + if(httpResponseJSon.contains("choices") + && httpResponseJSon["choices"].size() > 0 + ) { + // TODO get the last choice rather than the first one + auto choice = httpResponseJSon["choices"][0]; + if(choice.contains("message") + && choice["message"].contains("content") + ) { + choice["message"]["content"].get_to(command.answerMarkdown); + // TODO ask GPT for HTML formatted response + m8r::replaceAll( + "\n", + "
", + command.answerMarkdown); + MF_DEBUG(" answer (HTML): " << command.answerMarkdown << endl); + } + if(choice.contains("finish_reason")) { + string statusStr{}; + choice["finish_reason"].get_to(statusStr); + if(statusStr == "stop") { + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_OK; + } else { + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + command.errorMessage.assign( + "OpenAI API HTTP required failed with finish_reason: " + + statusStr); + command.answerMarkdown.clear(); + command.answerTokens = 0; + command.answerLlmModel = llmModel; + } + MF_DEBUG(" status: " << command.status << endl); + } + } else { + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + command.answerMarkdown.clear(); + command.answerTokens = 0; + command.answerLlmModel = llmModel; + if( + httpResponseJSon.contains("error") + && httpResponseJSon["error"].contains("message") + ) { + httpResponseJSon["error"]["message"].get_to(command.errorMessage); + } else { + command.errorMessage.assign( + "No choices in the OpenAI API HTTP response"); + } + } +#if !defined(__APPLE__) && !defined(_WIN32) + } + else { + command.status = m8r::WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + command.errorMessage.assign( + "OpenAI API HTTP request failed: unable to initialize cURL"); + } +#endif +} + +void OpenAiWingman::chat(CommandWingmanChat& command) { + MF_DEBUG("OpenAiWingman::chat() prompt:" << endl << command.prompt << endl); + + curlGet(command); + + MF_DEBUG("OpenAiWingman::chat() answer:" << endl << command.answerMarkdown << endl); +} + +} // m8r namespace diff --git a/lib/src/mind/ai/llm/openai_wingman.h b/lib/src/mind/ai/llm/openai_wingman.h new file mode 100644 index 00000000..64fd80c9 --- /dev/null +++ b/lib/src/mind/ai/llm/openai_wingman.h @@ -0,0 +1,58 @@ +/* + openai_wingman.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8R_OPENAI_WINGMAN_H +#define M8R_OPENAI_WINGMAN_H + +#include + +// HTTP client: CURL on Linux, Qt Network on macOS and Win +#if defined(_WIN32) || defined(__APPLE__) + #include +#else + #include "curl/curl.h" +#endif + +#include "wingman.h" + +namespace m8r { + +/** + * OpenAI Wingman implementation. + */ +class OpenAiWingman: Wingman +{ +private: + std::string apiKey; + std::string llmModel; + + void curlGet(CommandWingmanChat& command); + +public: + explicit OpenAiWingman(const std::string& apiKey, const std::string& llmModel); + OpenAiWingman(const OpenAiWingman&) = delete; + OpenAiWingman(const OpenAiWingman&&) = delete; + OpenAiWingman& operator =(const OpenAiWingman&) = delete; + OpenAiWingman& operator =(const OpenAiWingman&&) = delete; + ~OpenAiWingman() override; + + virtual void chat(CommandWingmanChat& command) override; +}; + +} +#endif // M8R_OPENAI_WINGMAN_H diff --git a/app/src/qt/note_edit_model.h b/lib/src/mind/ai/llm/wingman.cpp similarity index 59% rename from app/src/qt/note_edit_model.h rename to lib/src/mind/ai/llm/wingman.cpp index f4ddc18e..5bdc8154 100644 --- a/app/src/qt/note_edit_model.h +++ b/lib/src/mind/ai/llm/wingman.cpp @@ -1,7 +1,7 @@ /* - note_edit_model.h MindForger thinking notebook + wingman.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -10,28 +10,29 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef M8RUI_NOTE_EDIT_MODEL_H -#define M8RUI_NOTE_EDIT_MODEL_H +#include "wingman.h" -#include +namespace m8r { -#include "model_meta_definitions.h" +using namespace std; -namespace m8r { +/* + * Wingman class implementation. + */ -class NoteEditModel : public QObject +Wingman::Wingman(WingmanLlmProviders llmProvider) { - Q_OBJECT - -public: - NoteEditModel(); -}; + this->llmProvider = llmProvider; +} +Wingman::~Wingman() +{ } -#endif // M8RUI_NOTE_EDIT_MODEL_H + +} // m8r namespace diff --git a/lib/src/mind/ai/llm/wingman.h b/lib/src/mind/ai/llm/wingman.h new file mode 100644 index 00000000..45ace621 --- /dev/null +++ b/lib/src/mind/ai/llm/wingman.h @@ -0,0 +1,159 @@ +/* + wingman.h MindForger thinking notebook + + Copyright (C) 2016-2024 Martin Dvorak + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef M8R_WINGMAN_H +#define M8R_WINGMAN_H + +#include +#include + +#include "../../../debug.h" +#include "../../../config/configuration.h" + +namespace m8r { + +/* + * Predefined LLM prompts. + */ + +constexpr const auto CTX_INCLUDE_NAME = "#NAME"; +constexpr const auto CTX_INCLUDE_TEXT = "#TEXT"; + +constexpr const auto PROMPT_SUMMARIZE = "Summarize: #NAME. #TEXT"; +constexpr const auto PROMPT_GENERATE_TAGS = "Generate tags for: #NAME. #TEXT"; +constexpr const auto PROMPT_FIND_TASKS = "Find tasks in: #NAME. #TEXT"; +constexpr const auto PROMPT_FIND_PERSONS = "Find persons names in: #NAME. #TEXT"; +constexpr const auto PROMPT_FIND_LOCATIONS = "Find locations in: #NAME. #TEXT"; +constexpr const auto PROMPT_FIND_ORGS = "Find organizations in: #NAME. #TEXT"; +constexpr const auto PROMPT_CHAT = "Chat with the context."; + +constexpr const auto PROMPT_SHORTEN = "Shorten: #TEXT"; +constexpr const auto PROMPT_EXPLAIN_LIKE_5 = "Explain like I'm 5: #NAME"; +constexpr const auto PROMPT_EXPLAIN_LIKE_5_TXT = "Explain like I'm 5: #TEXT"; +constexpr const auto PROMPT_FIX_GRAMMAR = "Fix grammar in: #TEXT"; +constexpr const auto PROMPT_FIND_GRAMMAR = "Find grammar errors in: #TEXT"; +constexpr const auto PROMPT_TRANSLATE_EN = "Translate to English: #TEXT"; +constexpr const auto PROMPT_REWRITE_FORMALLY = "Rewrite formally: #TEXT"; +constexpr const auto PROMPT_REWRITE_ACADEMIA = "Rewrite in academic style: #TEXT"; +constexpr const auto PROMPT_REWRITE_SLANG = "Rewrite in a slang style: #TEXT"; +constexpr const auto PROMPT_SYNONYM = "Give synonym to: #TEXT"; +constexpr const auto PROMPT_ANTONYM = "Give antonym to: #TEXT"; +constexpr const auto PROMPT_COMPLETE_TEXT = "Complete work-in-progress text: #TEXT"; + +// other UCs: +// - NER UCs +// - simplify +// - beautify +// - translate +// - fix spelling +// - fix style +// - create plan ... + +// Wingman provider service status codes +enum WingmanStatusCode { + WINGMAN_STATUS_CODE_OK, + WINGMAN_STATUS_CODE_ERROR +}; + +/** + * Wingman chat request command pattern must be used as asynchronous requests. + * As it annot handle that many parameters this structure is used. + */ +struct CommandWingmanChat { + std::string prompt; + std::string httpResponse; + WingmanStatusCode status; + std::string errorMessage; + std::string answerLlmModel; + int promptTokens; + int answerTokens; + std::string answerMarkdown; +}; + + +/** + * Wingman is a class that provides a set of LLM-based use cases. + */ +class Wingman +{ +private: + WingmanLlmProviders llmProvider; + + std::vector outlinePrompts = { + PROMPT_SUMMARIZE, + PROMPT_TRANSLATE_EN, + PROMPT_FIND_GRAMMAR, + PROMPT_GENERATE_TAGS, + PROMPT_FIND_TASKS, + PROMPT_FIND_PERSONS, + PROMPT_FIND_LOCATIONS, + PROMPT_FIND_ORGS, + // PROMPT_CHAT, + }; + + std::vector notePrompts = { + PROMPT_SUMMARIZE, + PROMPT_SHORTEN, + PROMPT_FIND_GRAMMAR, + PROMPT_EXPLAIN_LIKE_5, + PROMPT_TRANSLATE_EN, + PROMPT_FIND_TASKS, + PROMPT_GENERATE_TAGS, + PROMPT_FIX_GRAMMAR, + PROMPT_REWRITE_FORMALLY, + PROMPT_REWRITE_SLANG, + // PROMPT_CHAT, + }; + + std::vector textPrompts = { + PROMPT_COMPLETE_TEXT, + PROMPT_EXPLAIN_LIKE_5_TXT, + PROMPT_FIX_GRAMMAR, + PROMPT_FIND_GRAMMAR, + PROMPT_TRANSLATE_EN, + PROMPT_GENERATE_TAGS, + PROMPT_REWRITE_FORMALLY, + PROMPT_REWRITE_ACADEMIA, + PROMPT_REWRITE_SLANG, + PROMPT_SYNONYM, + PROMPT_ANTONYM, + }; + +public: + explicit Wingman(WingmanLlmProviders llmProvider); + Wingman(const Wingman&) = delete; + Wingman(const Wingman&&) = delete; + Wingman& operator =(const Wingman&) = delete; + Wingman& operator =(const Wingman&&) = delete; + virtual ~Wingman(); + + virtual const std::vector& getPredefinedOPrompts() { + return outlinePrompts; + } + virtual const std::vector& getPredefinedNPrompts() { + return notePrompts; + } + virtual const std::vector& getPredefinedTPrompts() { + return textPrompts; + } + + virtual void chat(CommandWingmanChat& command) = 0; +}; + +} +#endif // M8R_WINGMAN_H diff --git a/lib/src/mind/ai/nlp/bag_of_words.cpp b/lib/src/mind/ai/nlp/bag_of_words.cpp index 414ff1e1..37ccafee 100644 --- a/lib/src/mind/ai/nlp/bag_of_words.cpp +++ b/lib/src/mind/ai/nlp/bag_of_words.cpp @@ -1,7 +1,7 @@ /* bag_of_words.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/bag_of_words.h b/lib/src/mind/ai/nlp/bag_of_words.h index 1dac64ae..ce9ba884 100644 --- a/lib/src/mind/ai/nlp/bag_of_words.h +++ b/lib/src/mind/ai/nlp/bag_of_words.h @@ -1,7 +1,7 @@ /* bag_of_words.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/char_provider.h b/lib/src/mind/ai/nlp/char_provider.h index b3e07232..f5596c1d 100644 --- a/lib/src/mind/ai/nlp/char_provider.h +++ b/lib/src/mind/ai/nlp/char_provider.h @@ -1,7 +1,7 @@ /* char_provider.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/common_words_blacklist.cpp b/lib/src/mind/ai/nlp/common_words_blacklist.cpp index d7c3dc16..fb21bfde 100644 --- a/lib/src/mind/ai/nlp/common_words_blacklist.cpp +++ b/lib/src/mind/ai/nlp/common_words_blacklist.cpp @@ -1,7 +1,7 @@ /* common_words_blacklist.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/common_words_blacklist.h b/lib/src/mind/ai/nlp/common_words_blacklist.h index 801bd8cd..6e8eb2b9 100644 --- a/lib/src/mind/ai/nlp/common_words_blacklist.h +++ b/lib/src/mind/ai/nlp/common_words_blacklist.h @@ -1,7 +1,7 @@ /* common_words_blacklist.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/lexicon.cpp b/lib/src/mind/ai/nlp/lexicon.cpp index a57f0d4c..b7b4b83f 100644 --- a/lib/src/mind/ai/nlp/lexicon.cpp +++ b/lib/src/mind/ai/nlp/lexicon.cpp @@ -1,7 +1,7 @@ /* lexicon.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/lexicon.h b/lib/src/mind/ai/nlp/lexicon.h index 1d2094eb..cc30d39d 100644 --- a/lib/src/mind/ai/nlp/lexicon.h +++ b/lib/src/mind/ai/nlp/lexicon.h @@ -1,7 +1,7 @@ /* lexicon.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/markdown_tokenizer.cpp b/lib/src/mind/ai/nlp/markdown_tokenizer.cpp index 2942de79..54f24eb9 100644 --- a/lib/src/mind/ai/nlp/markdown_tokenizer.cpp +++ b/lib/src/mind/ai/nlp/markdown_tokenizer.cpp @@ -1,7 +1,7 @@ /* markdown_tokenizer.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/markdown_tokenizer.h b/lib/src/mind/ai/nlp/markdown_tokenizer.h index 055cbe23..2274c67f 100644 --- a/lib/src/mind/ai/nlp/markdown_tokenizer.h +++ b/lib/src/mind/ai/nlp/markdown_tokenizer.h @@ -1,7 +1,7 @@ /* markdown_tokenizer.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/named_entity_recognition.cpp b/lib/src/mind/ai/nlp/named_entity_recognition.cpp deleted file mode 100644 index 1b08066e..00000000 --- a/lib/src/mind/ai/nlp/named_entity_recognition.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - named_entity_recognition.cpp MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "named_entity_recognition.h" - -namespace m8r { - -using namespace std; - -NamedEntityRecognition::NamedEntityRecognition() - : initilized{false}, nerModel{} -{ -} - -NamedEntityRecognition::~NamedEntityRecognition() -{ -} - -void NamedEntityRecognition::setNerModel(const std::string& nerModel) { - std::lock_guard criticalSection{initMutex}; - - initilized = false; - nerModelPath = nerModel; -} - -// this method is NOT synchronized - callers are synchronized so that race condition is avoided -bool NamedEntityRecognition::loadAndInitNerModel() -{ - if(!initilized) { - // Load MITIE's named entity extractor from disk. Each file in the MITIE-models - // folder begins with a string containing the name of the serialized class. In - // this case classname contains "mitie::named_entity_extractor". It can be used to - // identify what is in any particular file. However, in this example we don't need - // it so it is just ignored. -#ifdef DO_MF_DEBUG - MF_DEBUG("NER loading model: " << nerModelPath << endl); - auto begin = chrono::high_resolution_clock::now(); -#endif - string classname; - dlib::deserialize(nerModelPath) >> classname >> nerModel; - initilized = true; -#ifdef DO_MF_DEBUG - auto end = chrono::high_resolution_clock::now(); - MF_DEBUG("NER model loaded in " << chrono::duration_cast(end-begin).count()/1000.0 << "ms" << endl); -#endif - -#ifdef DO_MF_DEBUG - // print out what kind of tags this tagger can predict. - const std::vector tagstr = nerModel.get_tag_name_strings(); - MF_DEBUG("NER tagger supports "<< tagstr.size() <<" tags:" << endl); - for(unsigned int i = 0; i < tagstr.size(); ++i) { - MF_DEBUG(" " << tagstr[i] << endl); - } -#endif - } - - return true; -} - -vector NamedEntityRecognition::tokenizeFile(const string& filename) -{ - ifstream fin(filename.c_str()); - if(!fin) { - cout << "Unable to load input text file" << endl; - exit(EXIT_FAILURE); - } - - // The conll_tokenizer splits the contents of an istream into a bunch of words and is - // MITIE's default tokenization method. - mitie::conll_tokenizer tok(fin); - std::vector tokens; - string token; - - // Read the tokens out of the file one at a time and store into tokens. - while(tok(token)) { - tokens.push_back(token); - } - - return tokens; -} - -bool NamedEntityRecognition::recognizePersons(vector& result) -{ - UNUSED_ARG(result); - - - - std::lock_guard criticalSection{initMutex}; - - if(loadAndInitNerModel()) { - // ... - } - - return false; -} - -bool NamedEntityRecognition::recognizePersons(const Outline* outline, int entityTypeFilter, vector& result) -{ - std::lock_guard criticalSection{initMutex}; - - if(loadAndInitNerModel()) { - try { - // tokenize data to prepare it for the tagger - MF_DEBUG("NER: tokenizing O " << outline->getKey() << endl); - std::vector tokens = tokenizeFile(outline->getKey()); - - std::vector > chunks; - std::vector chunk_tags; - std::vector chunk_scores; - - // Now detect all the entities in the text file we loaded and print them to the screen. - // The output of this function is a set of "chunks" of tokens, each a named entity. - // Additionally, if it is useful for your application a confidence score for each "chunk" - // is available by using the predict() method. The larger the score the more - // confident MITIE is in the tag. -#ifdef DO_MF_DEBUG - MF_DEBUG("NER predicting..." << endl); - auto begin = chrono::high_resolution_clock::now(); -#endif - nerModel.predict(tokens, chunks, chunk_tags, chunk_scores); -#ifdef DO_MF_DEBUG - auto end = chrono::high_resolution_clock::now(); - MF_DEBUG("NER prediction done in " << chrono::duration_cast(end-begin).count()/1000.0 << "ms" << endl); -#endif - - // If a confidence score is not necessary for your application you can detect entities - // using the operator() method as shown in the following line. - //ner(tokens, chunks, chunk_tags); - - MF_DEBUG("\nNumber of named entities detected: " << chunks.size() << endl); - const std::vector tagstr = nerModel.get_tag_name_strings(); - string entityName{}; - for (unsigned int i = 0; i < chunks.size(); ++i) { - if((1<(1<(chunk_scores[i])}; - result.push_back(entity); - } - } - - return true; - } - catch(std::exception& e) { - cerr << "NRE error: " << e.what() << endl; - } - } - - return false; -} - -} // m8r namespace diff --git a/lib/src/mind/ai/nlp/named_entity_recognition.h b/lib/src/mind/ai/nlp/named_entity_recognition.h deleted file mode 100644 index f1eea089..00000000 --- a/lib/src/mind/ai/nlp/named_entity_recognition.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - named_entity_recognition.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8R_NAMED_ENTITY_RECOGNITION_H -#define M8R_NAMED_ENTITY_RECOGNITION_H - -#include -#include - -#include -#include -#include -#include -#include - -#include "../../deps/mitie/mitielib/include/mitie/named_entity_extractor.h" -#include "../../deps/mitie/mitielib/include/mitie/conll_tokenizer.h" -#include "../../deps/mitie/mitielib/include/mitie.h" - -#include "ner_named_entity.h" - -#include "../../../model/outline.h" - -namespace m8r { - -class NamedEntityRecognition -{ -private: - std::mutex initMutex; - bool initilized; - - std::string nerModelPath; - mitie::named_entity_extractor nerModel; - -public: - explicit NamedEntityRecognition(); - NamedEntityRecognition(const NamedEntityRecognition&) = delete; - NamedEntityRecognition(const NamedEntityRecognition&&) = delete; - NamedEntityRecognition &operator=(const NamedEntityRecognition&) = delete; - NamedEntityRecognition &operator=(const NamedEntityRecognition&&) = delete; - ~NamedEntityRecognition(); - - bool isInitialized() const { return initilized; } - - /** - * @brief Set NER model location. - * - * This set path to the method, but it does NOT load and initialize it. - */ - void setNerModel(const std::string& nerModel); - - /** - * @brief NRE persons in memory. - */ - bool recognizePersons(std::vector& result); - - /** - * @brief NRE persons in O. - */ - bool recognizePersons(const Outline* outline, int entityTypeFilter, std::vector& result); - -private: - std::vector tokenizeFile(const std::string& filename); - - /** - * @brief Load and initialize NER model file. - * - * NER file is typically huge (MBs) therefore it is loaded and initialized on demand. - */ - bool loadAndInitNerModel(); -}; - -} -#endif // M8R_NAMED_ENTITY_RECOGNITION_H diff --git a/lib/src/mind/ai/nlp/ner_named_entity.h b/lib/src/mind/ai/nlp/ner_named_entity.h deleted file mode 100644 index c0b9b8ac..00000000 --- a/lib/src/mind/ai/nlp/ner_named_entity.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - ner_named_entity.h MindForger thinking notebook - - Copyright (C) 2016-2022 Martin Dvorak - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef M8R_NER_NAMED_ENTITY_H -#define M8R_NER_NAMED_ENTITY_H - -#include - -namespace m8r { - -enum NerNamedEntityType { - PERSON = 1<<0, - LOCATION = 1<<1, - ORGANIZATION = 1<<2, - MISC = 1<<3 -}; - -struct NerNamedEntity -{ - std::string name; - NerNamedEntityType type; - float score; - - explicit NerNamedEntity(const std::string& n, NerNamedEntityType t, float s) { - this->name = n; - this->type = t; - this->score = s; - } -}; - -} -#endif // M8R_NER_NAMED_ENTITY_H diff --git a/lib/src/mind/ai/nlp/note_char_provider.cpp b/lib/src/mind/ai/nlp/note_char_provider.cpp index 2983828a..8fca90df 100644 --- a/lib/src/mind/ai/nlp/note_char_provider.cpp +++ b/lib/src/mind/ai/nlp/note_char_provider.cpp @@ -1,7 +1,7 @@ /* note_char_provider.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/note_char_provider.h b/lib/src/mind/ai/nlp/note_char_provider.h index 0549f9f0..0f8e98c0 100644 --- a/lib/src/mind/ai/nlp/note_char_provider.h +++ b/lib/src/mind/ai/nlp/note_char_provider.h @@ -1,7 +1,7 @@ /* note_char_provider.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/outline_char_provider.cpp b/lib/src/mind/ai/nlp/outline_char_provider.cpp index 73a94188..38a4c3bd 100644 --- a/lib/src/mind/ai/nlp/outline_char_provider.cpp +++ b/lib/src/mind/ai/nlp/outline_char_provider.cpp @@ -1,7 +1,7 @@ /* outline_char_provider.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/outline_char_provider.h b/lib/src/mind/ai/nlp/outline_char_provider.h index b048e39f..3e41895f 100644 --- a/lib/src/mind/ai/nlp/outline_char_provider.h +++ b/lib/src/mind/ai/nlp/outline_char_provider.h @@ -1,7 +1,7 @@ /* outline_char_provider.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/stemmer/stemmer.cpp b/lib/src/mind/ai/nlp/stemmer/stemmer.cpp index f1c095ef..2af14f93 100644 --- a/lib/src/mind/ai/nlp/stemmer/stemmer.cpp +++ b/lib/src/mind/ai/nlp/stemmer/stemmer.cpp @@ -1,7 +1,7 @@ /* stemmer.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/stemmer/stemmer.h b/lib/src/mind/ai/nlp/stemmer/stemmer.h index 657a07d0..fbe9f911 100644 --- a/lib/src/mind/ai/nlp/stemmer/stemmer.h +++ b/lib/src/mind/ai/nlp/stemmer/stemmer.h @@ -1,7 +1,7 @@ /* stemmer.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/string_char_provider.cpp b/lib/src/mind/ai/nlp/string_char_provider.cpp index 2adacc40..fb7e3f8d 100644 --- a/lib/src/mind/ai/nlp/string_char_provider.cpp +++ b/lib/src/mind/ai/nlp/string_char_provider.cpp @@ -1,7 +1,7 @@ /* string_char_provider.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/string_char_provider.h b/lib/src/mind/ai/nlp/string_char_provider.h index 4accdfe4..4bc673f3 100644 --- a/lib/src/mind/ai/nlp/string_char_provider.h +++ b/lib/src/mind/ai/nlp/string_char_provider.h @@ -1,7 +1,7 @@ /* string_char_provider.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/word_frequency_list.cpp b/lib/src/mind/ai/nlp/word_frequency_list.cpp index 8aacf752..0968b612 100644 --- a/lib/src/mind/ai/nlp/word_frequency_list.cpp +++ b/lib/src/mind/ai/nlp/word_frequency_list.cpp @@ -1,7 +1,7 @@ /* word_frequency_list.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ai/nlp/word_frequency_list.h b/lib/src/mind/ai/nlp/word_frequency_list.h index 9c8fcbd6..08a616c8 100644 --- a/lib/src/mind/ai/nlp/word_frequency_list.h +++ b/lib/src/mind/ai/nlp/word_frequency_list.h @@ -1,7 +1,7 @@ /* word_frequency_list.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/aspect/aspect.h b/lib/src/mind/aspect/aspect.h index d8d04333..60a6b54e 100644 --- a/lib/src/mind/aspect/aspect.h +++ b/lib/src/mind/aspect/aspect.h @@ -1,7 +1,7 @@ /* aspect.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/aspect/mind_scope_aspect.cpp b/lib/src/mind/aspect/mind_scope_aspect.cpp index 970ea97c..99f42f22 100644 --- a/lib/src/mind/aspect/mind_scope_aspect.cpp +++ b/lib/src/mind/aspect/mind_scope_aspect.cpp @@ -1,7 +1,7 @@ /* mind_scope_aspect.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/aspect/mind_scope_aspect.h b/lib/src/mind/aspect/mind_scope_aspect.h index 17a129b4..a05c1a98 100644 --- a/lib/src/mind/aspect/mind_scope_aspect.h +++ b/lib/src/mind/aspect/mind_scope_aspect.h @@ -1,7 +1,7 @@ /* mind_scope_aspect.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/aspect/tag_scope_aspect.cpp b/lib/src/mind/aspect/tag_scope_aspect.cpp index 40b34ad6..ea885ecc 100644 --- a/lib/src/mind/aspect/tag_scope_aspect.cpp +++ b/lib/src/mind/aspect/tag_scope_aspect.cpp @@ -1,7 +1,7 @@ /* tag_scope_aspect.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/aspect/tag_scope_aspect.h b/lib/src/mind/aspect/tag_scope_aspect.h index 812a7771..93fbd407 100644 --- a/lib/src/mind/aspect/tag_scope_aspect.h +++ b/lib/src/mind/aspect/tag_scope_aspect.h @@ -1,7 +1,7 @@ /* tag_scope_aspect.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/aspect/time_scope_aspect.cpp b/lib/src/mind/aspect/time_scope_aspect.cpp index 9795a439..4b884cbc 100644 --- a/lib/src/mind/aspect/time_scope_aspect.cpp +++ b/lib/src/mind/aspect/time_scope_aspect.cpp @@ -1,7 +1,7 @@ /* forget_aspect.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -32,14 +32,15 @@ TimeScopeAspect::~TimeScopeAspect() { } -string TimeScopeAspect::getTimeScopeAsString() +string TimeScopeAspect::getTimeScopeAsString() const { string result{}; + timeScope.toString(result); #ifdef __APPLE__ return result; #else - return std::move(result); + return result; #endif } diff --git a/lib/src/mind/aspect/time_scope_aspect.h b/lib/src/mind/aspect/time_scope_aspect.h index b7b16835..a65fef82 100644 --- a/lib/src/mind/aspect/time_scope_aspect.h +++ b/lib/src/mind/aspect/time_scope_aspect.h @@ -1,7 +1,7 @@ /* time_scope_aspect.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -69,7 +69,7 @@ class TimeScopeAspect : public Aspect timePoint = now-timeScope.relativeSecs; } TimeScope& getTimeScope() { return timeScope; } - std::string getTimeScopeAsString(); + std::string getTimeScopeAsString() const; void resetTimeScope() { timeScope.reset(); } void setTimePoint(time_t timePoint); diff --git a/lib/src/mind/associated_notes.cpp b/lib/src/mind/associated_notes.cpp index ba49725a..e87587bb 100644 --- a/lib/src/mind/associated_notes.cpp +++ b/lib/src/mind/associated_notes.cpp @@ -1,7 +1,7 @@ /* associated_notes.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/associated_notes.h b/lib/src/mind/associated_notes.h index fe1100dc..4b7e806e 100644 --- a/lib/src/mind/associated_notes.h +++ b/lib/src/mind/associated_notes.h @@ -1,7 +1,7 @@ /* associated_notes.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/dikw/dikw_pyramid.cpp b/lib/src/mind/dikw/dikw_pyramid.cpp index a56648c9..9f36b151 100644 --- a/lib/src/mind/dikw/dikw_pyramid.cpp +++ b/lib/src/mind/dikw/dikw_pyramid.cpp @@ -1,7 +1,7 @@ /* dikw_pyramid.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/dikw/dikw_pyramid.h b/lib/src/mind/dikw/dikw_pyramid.h index 124a6800..1165fda3 100644 --- a/lib/src/mind/dikw/dikw_pyramid.h +++ b/lib/src/mind/dikw/dikw_pyramid.h @@ -1,7 +1,7 @@ /* dikw_pyramid.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/dikw/filesystem_information.cpp b/lib/src/mind/dikw/filesystem_information.cpp index 8cafa062..05611c8d 100644 --- a/lib/src/mind/dikw/filesystem_information.cpp +++ b/lib/src/mind/dikw/filesystem_information.cpp @@ -1,7 +1,7 @@ /* filesystem_information.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,6 +23,93 @@ using namespace m8r::filesystem; namespace m8r { +constexpr const auto META_SRC_PATH_PREFIX = "Source directory: "; + +std::vector FilesystemInformationSource::findInformationSources( + Configuration &config, + Mind& mind, + MarkdownDocumentRepresentation& mdDocumentRepresentation +) { + vector infoSrc; + + if(config.getActiveRepository()->getType() != Repository::RepositoryType::MINDFORGER + || config.getActiveRepository()->getMode() != Repository::RepositoryMode::REPOSITORY + ) { + MF_DEBUG( + "Error: filesystem information resource cannot be indexed as " + "active directory is not of MINDFORGER/REPOSITORY type"); + return infoSrc; + } + + string libraryPath{ + config.getMemoryPath()+FILE_PATH_SEPARATOR+DIR_MEMORY_M1ndF0rg3rL1br8ry + }; + if(!isDirectory(libraryPath.c_str())) { + MF_DEBUG( + "Error: memory's library path '" << libraryPath << "' does not exist"); + return infoSrc; + } + + MF_DEBUG( + endl << + "SEARCHING existing information sources in memory's library path: '" << + libraryPath << "'"); + DIR* dir; + if((dir = opendir(libraryPath.c_str()))) { + const struct dirent *entry; + if((entry = readdir(dir))) { + string path; + do { + if(entry->d_type == DT_DIR) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + MF_DEBUG( + endl << "LIBRARY SOURCE> " << libraryPath.c_str() << "/" << entry->d_name); + path.assign(libraryPath); + path += FILE_PATH_SEPARATOR; + path += entry->d_name; + + string metaPath{ + path+FILE_PATH_SEPARATOR+FILE_META_M1ndF0rg3rL1br8ryM3t8 + }; + MF_DEBUG(endl << " Metadata file path: '" << metaPath << "'"); + if(!isFile(metaPath.c_str())) { + continue; + } + + vector metaLines{}; + size_t fileSize{}; + fileToLines(&metaPath, metaLines, fileSize); + + if(metaLines.size() >= 2 && metaLines[2]) { + string* line=metaLines[2]; + string libSrcPath = line->substr(strlen(META_SRC_PATH_PREFIX)); + MF_DEBUG( + endl << " Library source dir: '" << libSrcPath << "'"); + + if(!isDirectory(libSrcPath.c_str())) { + continue; + } + + MF_DEBUG(endl << " VALID"); + FilesystemInformationSource* src = new FilesystemInformationSource{ + libSrcPath, + mind, + mdDocumentRepresentation, + }; + src->setMfPath(path); + infoSrc.push_back(src); + } + } + } while ((entry = readdir(dir)) != 0); + closedir(dir); + } + } + + return infoSrc; +} + FilesystemInformationSource::FilesystemInformationSource( string& sourcePath, Mind& mind, @@ -30,7 +117,8 @@ FilesystemInformationSource::FilesystemInformationSource( ) : InformationSource{SourceType::FILESYSTEM, sourcePath}, mind{mind}, - mdDocumentRepresentation{mdDocumentRepresentation} + mdDocumentRepresentation{mdDocumentRepresentation}, + mfPath{} { } @@ -67,25 +155,32 @@ FilesystemInformationSource::~FilesystemInformationSource() } } -FilesystemInformationSource::ErrorCode FilesystemInformationSource::indexToMemory(Repository& repository) -{ +FilesystemInformationSource::ErrorCode FilesystemInformationSource::indexToMemory( + Repository& repository, bool synchronize +) { MF_DEBUG("Indexing LIBRARY documents to memory:" << endl); if(!isDirectory(locator.c_str())) { - MF_DEBUG("Error: filesystem information resource cannot be indexed to memory as its locator path '" << locator << "' does not exist"); + MF_DEBUG( + "Error: filesystem information resource cannot be indexed to memory " + "as its locator path '" << locator << "' does not exist"); return FilesystemInformationSource::ErrorCode::INVALID_LOCATOR; } if(repository.getType() != Repository::RepositoryType::MINDFORGER || repository.getMode() != Repository::RepositoryMode::REPOSITORY ) { - MF_DEBUG("Error: filesystem information resource cannot be indexed as active directory is not of MINDFORGER/REPOSITORY type"); + MF_DEBUG( + "Error: filesystem information resource cannot be indexed as " + "active directory is not of MINDFORGER/REPOSITORY type"); return FilesystemInformationSource::ErrorCode::NOT_MINDFORGER_REPOSITORY; } string memoryPath{repository.getDir()+FILE_PATH_SEPARATOR+DIRNAME_MEMORY}; if(!isDirectory(memoryPath.c_str())) { - MF_DEBUG("Error: filesystem information resource cannot be indexed to memory path '" << memoryPath << "' as this directory does not exist"); + MF_DEBUG( + "Error: filesystem information resource cannot be indexed to " + "memory path '" << memoryPath << "' as this directory does not exist"); return FilesystemInformationSource::ErrorCode::INVALID_MEMORY_PATH; } @@ -100,7 +195,7 @@ FilesystemInformationSource::ErrorCode FilesystemInformationSource::indexToMemor memoryInformationSourceIndexPath += FILE_PATH_SEPARATOR; memoryInformationSourceIndexPath += normalizeToNcName(this->locator, '_'); MF_DEBUG(" Library path in memory: " << memoryInformationSourceIndexPath << endl); - if(isDirectory(memoryInformationSourceIndexPath.c_str())) { + if(!synchronize && isDirectory(memoryInformationSourceIndexPath.c_str())) { return ErrorCode::LIBRARY_ALREADY_EXISTS; } else { createDirectory(memoryInformationSourceIndexPath); @@ -125,16 +220,25 @@ FilesystemInformationSource::ErrorCode FilesystemInformationSource::indexToMemor pathToDirectoryAndFile(outlinePathInMemory, outlineDir, outlineFilename); if(outlineDir.size() && !isDirectory(outlineDir.c_str())) { - // TODO create directory including parent directories - MF_DEBUG(" TO BE IMPLEMENTED - create directory including parent directories: " << outlinePathInMemory << endl); - createDirectory(outlineDir); + MF_DEBUG(" creating dir including parent dirs: " << outlinePathInMemory << endl); + createDirectories(outlineDir); } - Outline* o=mdDocumentRepresentation.to(*pdf_path, outlinePathInMemory); - - mind.outlineNew(o); + if(!isFile(outlinePathInMemory.c_str())) { + Outline* o=mdDocumentRepresentation.to(*pdf_path, outlinePathInMemory); + mind.outlineNew(o); + } else { + MF_DEBUG(" SKIPPING creation of O as it already EXISTS"); + } } + string metaPath{ + memoryInformationSourceIndexPath + + FILE_PATH_SEPARATOR + + FILE_META_M1ndF0rg3rL1br8ryM3t8 + }; + saveMetadata(metaPath, locator); + return ErrorCode::SUCCESS; } @@ -142,7 +246,10 @@ void FilesystemInformationSource::indexDirectoryToMemory( const string& directory, const string& memoryPath ) { - MF_DEBUG(endl << "INDEXING information source DIR: '" << directory << "' to memory DIR: '" << memoryPath << "'"); + MF_DEBUG( + endl << + "INDEXING information source DIR: '" << + directory << "' to memory DIR: '" << memoryPath << "'"); DIR* dir; if((dir = opendir(directory.c_str()))) { const struct dirent *entry; @@ -154,14 +261,16 @@ void FilesystemInformationSource::indexDirectoryToMemory( if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } - MF_DEBUG(endl << "DIVE> " << directory.c_str() << "//" << entry->d_name); + MF_DEBUG( + endl << "DIVE> " << directory.c_str() << "//" << entry->d_name); path.assign(directory); path += FILE_PATH_SEPARATOR; path += entry->d_name; indexDirectoryToMemory(path, memoryPath); } else { - MF_DEBUG(endl << " FILE: " << directory.c_str() << "//" << entry->d_name); + MF_DEBUG( + endl << " FILE: " << directory.c_str() << "//" << entry->d_name); ppath = new string{directory}; ppath->append(FILE_PATH_SEPARATOR); ppath->append(entry->d_name); @@ -179,4 +288,16 @@ void FilesystemInformationSource::indexDirectoryToMemory( } } +void FilesystemInformationSource::saveMetadata( + string& metaPath, + string& librarySrcPath +) { + std::ofstream out(metaPath); + out << "# MindForger Library Metadata" << endl + << "Library name: My library" << endl + << META_SRC_PATH_PREFIX << librarySrcPath << endl; + out.close(); + +} + } // m8r namespace diff --git a/lib/src/mind/dikw/filesystem_information.h b/lib/src/mind/dikw/filesystem_information.h index 4211a9ec..e9291478 100644 --- a/lib/src/mind/dikw/filesystem_information.h +++ b/lib/src/mind/dikw/filesystem_information.h @@ -1,7 +1,7 @@ /* filesystem_information.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -64,7 +64,23 @@ class FilesystemInformationSource : InformationSource Mind& mind; MarkdownDocumentRepresentation& mdDocumentRepresentation; + std::string mfPath; + public: + /** + * @brief Find information sources in given directory. + * + * List sub-directories of given directory and check whether the sub-directory + * has metadata file describing ainformation source (library). For every such + * directory create FilesystemInformationSource instance and return vector + * of such instances. + */ + static std::vector findInformationSources( + Configuration &config, + Mind& mind, + MarkdownDocumentRepresentation& mdDocumentRepresentation + ); + explicit FilesystemInformationSource( std::string& sourcePath, Mind& mind, @@ -79,15 +95,16 @@ class FilesystemInformationSource : InformationSource /** * @brief Index this information source to memory. * - * Scan given filesystem directory, find know files - * and convert them to Os/Ns/Ts/... in memory so that - * the information might be used. + * Scan given filesystem directory, find documents with known extensions + * and convert them to Os/Ns/Ts/... in memory so that the information + * might be used. * * For instance index given filesystem information by creating Markdown - * descriptor in $MINDFORGER_REPOSITORY/memory for each file - * found in given information source. + * descriptor in $MINDFORGER_REPOSITORY/memory for each document found in given + * information source. * * Orphan detection and management: + * * - list of library's Os in memory is scanned before documents indexation * - if a document does NOT have valid path to document, then it is TAGGED * with `orphan` tag @@ -96,12 +113,18 @@ class FilesystemInformationSource : InformationSource * * @return true if source was successfully indexed, false otherwise. */ - ErrorCode indexToMemory(Repository& repository); + ErrorCode indexToMemory(Repository& repository, bool synchronize = false); std::set getPdfs() const { return this->pdfs_paths; } + std::string getPath() const {return this->locator; } + void setMfPath(std::string mfPath) { this->mfPath = mfPath; } + std::string getMfPath() {return mfPath; } + + void saveMetadata(std::string& metaPath, std::string& librarySrcPath); private: - void indexDirectoryToMemory(const std::string& directory, const std::string& memoryPath); + void indexDirectoryToMemory( + const std::string& directory, const std::string& memoryPath); }; } diff --git a/lib/src/mind/dikw/information.cpp b/lib/src/mind/dikw/information.cpp index 5bd5f4fa..eb953657 100644 --- a/lib/src/mind/dikw/information.cpp +++ b/lib/src/mind/dikw/information.cpp @@ -1,7 +1,7 @@ /* information.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,7 +22,10 @@ using namespace std; namespace m8r { -const std::string InformationSource::DIR_MEMORY_M1ndF0rg3rL1br8ry = string{"M1ndF0rg3r-L1br8ry"}; +const std::string InformationSource::DIR_MEMORY_M1ndF0rg3rL1br8ry + = string{"M1ndF0rg3r-L1br8ry"}; +const std::string InformationSource::FILE_META_M1ndF0rg3rL1br8ryM3t8 + = string{"M1ndF0rg3r-L1br8ry-M3t8"}; InformationSource::InformationSource(SourceType type, std::string locator) : type{type}, diff --git a/lib/src/mind/dikw/information.h b/lib/src/mind/dikw/information.h index 7b1f8bfe..9f1a3311 100644 --- a/lib/src/mind/dikw/information.h +++ b/lib/src/mind/dikw/information.h @@ -1,7 +1,7 @@ /* information.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,6 +27,7 @@ class InformationSource { public: static const std::string DIR_MEMORY_M1ndF0rg3rL1br8ry; + static const std::string FILE_META_M1ndF0rg3rL1br8ryM3t8; enum SourceType { FILESYSTEM, diff --git a/lib/src/mind/galaxy.cpp b/lib/src/mind/galaxy.cpp index 808dde88..cb7276f6 100644 --- a/lib/src/mind/galaxy.cpp +++ b/lib/src/mind/galaxy.cpp @@ -1,7 +1,7 @@ /* galaxy.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/galaxy.h b/lib/src/mind/galaxy.h index 22534b0a..f7572509 100644 --- a/lib/src/mind/galaxy.h +++ b/lib/src/mind/galaxy.h @@ -1,7 +1,7 @@ /* galaxy.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/knowledge_graph.cpp b/lib/src/mind/knowledge_graph.cpp index 7edd04d5..a75992fc 100644 --- a/lib/src/mind/knowledge_graph.cpp +++ b/lib/src/mind/knowledge_graph.cpp @@ -1,7 +1,7 @@ /* knowledge_graph.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/knowledge_graph.h b/lib/src/mind/knowledge_graph.h index 4bd22d0d..52a53309 100644 --- a/lib/src/mind/knowledge_graph.h +++ b/lib/src/mind/knowledge_graph.h @@ -1,7 +1,7 @@ /* knowledge_graph.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -123,11 +123,11 @@ class KnowledgeGraph public: explicit KnowledgeGraph( - Mind* mind, - long unsigned mindColor=0x008C00, - long unsigned coreColor=0x000000, - long unsigned outlinesColor=0x220000, - long unsigned notesColor=0x000022); + Mind* mind, + long unsigned mindColor=0x008C00, + long unsigned coreColor=0x000000, + long unsigned outlinesColor=0x220000, + long unsigned notesColor=0x000022); KnowledgeGraph(const KnowledgeGraph&) = delete; KnowledgeGraph(const KnowledgeGraph&&) = delete; KnowledgeGraph &operator=(const KnowledgeGraph&) = delete; diff --git a/lib/src/mind/limbo.cpp b/lib/src/mind/limbo.cpp index fe597bea..1c78379c 100644 --- a/lib/src/mind/limbo.cpp +++ b/lib/src/mind/limbo.cpp @@ -1,7 +1,7 @@ /* limbo.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/limbo.h b/lib/src/mind/limbo.h index 52aec810..f028676c 100644 --- a/lib/src/mind/limbo.h +++ b/lib/src/mind/limbo.h @@ -1,7 +1,7 @@ /* limbo.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/memory.cpp b/lib/src/mind/memory.cpp index fd468d8a..d58c26ae 100644 --- a/lib/src/mind/memory.cpp +++ b/lib/src/mind/memory.cpp @@ -1,7 +1,7 @@ /* memory.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -210,6 +210,11 @@ bool Memory::learnOutlineTWiki(const string& twikiFileName, const string& outlin return twikiRepresentation.outline(File{twikiFileName}, File{outlineFileName}); } +Outline* Memory::learnOutlinesMap(const string& filePath) +{ + return mdRepresentation.outline(File{filePath}); +} + Note* Memory::createNote(Stencil* stencil) { if(stencil && ResourceType::NOTE==stencil->getType()) { diff --git a/lib/src/mind/memory.h b/lib/src/mind/memory.h index b06679d1..42f190a5 100644 --- a/lib/src/mind/memory.h +++ b/lib/src/mind/memory.h @@ -1,7 +1,7 @@ /* memory.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -53,7 +53,7 @@ class Memory */ bool aware; - /** + /** * @brief Cache outlines in memory. * * If FALSE, then outlines are always loaded from @@ -117,6 +117,11 @@ class Memory */ Outline* createOutline(Stencil* stencil); + /** + * @brief Learn Outlines map (tree). + */ + Outline* learnOutlinesMap(const std::string& fileNamePath); + /** * @brief Convert TWiki file to MD file (O not instantiated). */ diff --git a/lib/src/mind/memory_dwell.cpp b/lib/src/mind/memory_dwell.cpp index 10c3299b..2af986f9 100644 --- a/lib/src/mind/memory_dwell.cpp +++ b/lib/src/mind/memory_dwell.cpp @@ -1,7 +1,7 @@ /* memory_dwell.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/memory_dwell.h b/lib/src/mind/memory_dwell.h index d3a227e6..17e70294 100644 --- a/lib/src/mind/memory_dwell.h +++ b/lib/src/mind/memory_dwell.h @@ -1,7 +1,7 @@ /* memory_dwell.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/mind.cpp b/lib/src/mind/mind.cpp index 5b03de67..aebf753a 100644 --- a/lib/src/mind/mind.cpp +++ b/lib/src/mind/mind.cpp @@ -1,7 +1,7 @@ /* mind.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -45,12 +45,19 @@ Mind::Mind(Configuration &configuration) #else autolinking{nullptr}, #endif + outlinesMap{}, exclusiveMind{}, timeScopeAspect{}, tagsScopeAspect{ontology}, scopeAspect{timeScopeAspect, tagsScopeAspect} { - ai = new Ai{memory,*this}; + ai = new Ai{memory, *this}; + + // TODO BEGIN: code before Wingman config persisted + config.setWingmanLlmProvider(WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI); + // TODO END: code before Wingman config persisted + initWingman(); + deleteWatermark = 0; activeProcesses = 0; associationsSemaphore = 0; @@ -72,12 +79,17 @@ Mind::Mind(Configuration &configuration) Mind::~Mind() { delete ai; + if(wingman) delete wingman; delete knowledgeGraph; delete mdConfigRepresentation; delete autoInterceptor; delete autolinking; delete stats; + if(this->outlinesMap) { + delete this->outlinesMap; + } + // - Memory destruct outlines // - allNotesCache Notes is just container referencing Memory's Outlines } @@ -357,6 +369,15 @@ void Mind::getOutlineNames(vector& names) const } } +void Mind::getOutlineKeys(vector& keys) const +{ + // IMPROVE PERF cache vector (stack member) until and evict on memory modification + vector outlines = memory.getOutlines(); + for(Outline* outline:outlines) { + keys.push_back(outline->getKey()); + } +} + // One match in either title or body is enought to be added to the result void Mind::findNoteFts( vector* result, @@ -950,16 +971,258 @@ bool Mind::outlineForget(string outlineKey) return false; } +string Mind::outlineMapKey2Relative(const string& outlineKey) const +{ + string relativeKey{ + outlineKey.substr(config.getMemoryPath().size() +1) + }; + MF_DEBUG(" " << relativeKey << endl); + + return relativeKey; +} + +string Mind::outlineMapKey2Absolute(const string& outlineKey) const +{ + string resolvedKey{ + config.getMemoryPath() + + FILE_PATH_SEPARATOR + + outlineKey + }; + MF_DEBUG(" " << resolvedKey << endl); + + return resolvedKey; +} + +Outline* Mind::outlinesMapNew(string outlineKey) +{ + MF_DEBUG("Creating Os map:" << endl); + Outline* newOutlinesMap = new Outline{ + memory.getOntology().getDefaultOutlineType()}; + + for(Outline* o:getOutlines()) { + Note* n = o->getOutlineDescriptorAsNote(); + newOutlinesMap->addNote(n); + + n->addLink( + new Link{ + LINK_NAME_OUTLINE_KEY, + o->getKey() + } + ); + n->addLink( + new Link{ + LINK_NAME_OUTLINE_PATH, + Mind::outlineMapKey2Relative(o->getKey()) + } + ); + } + + newOutlinesMap->setName("Notebooks Map"); + newOutlinesMap->setKey(outlineKey); + newOutlinesMap->sortNotesByRead(); + + newOutlinesMap->completeProperties(datetimeNow()); + + return newOutlinesMap; +} + +void Mind::outlinesMapSynchronize(Outline* outlinesMap) +{ + vector osToRemove{}; + + // ensure that map contains only valid Os + // - remove from map: map O NOT in runtime O + // - add at the top of map: runtime Os NOT in mapOs + MF_DEBUG("Map O links validity check:"); + vector mapOsKeys{}; + for(Note* n:outlinesMap->getNotes()) { + Link* oLink = n->getLinkByName(LINK_NAME_OUTLINE_KEY); + if(oLink) { + string oKey{oLink->getUrl()}; + Outline* o = findOutlineByKey(oKey); + if(o) { + // valid O in MF & map + #ifdef MF_DEBUG_LIBRARY + MF_DEBUG( + " VALID : " << n->getName() << endl << + " " << oKey << endl + ); + #endif + // refresh N representing O (name, timestamps, ... may be changed by other views) + n->setName(o->getName()); + n->setModified(o->getModified()); + n->setModifiedPretty(); + n->setRead(o->getRead()); + n->setReadPretty(); + mapOsKeys.push_back(oKey); + } else { + MF_DEBUG(" INVALID (no O for link): " << n->getName() << endl); + osToRemove.push_back(n); + } + } else { + MF_DEBUG(" INVALID (missing link): " << n->getName() << endl); + osToRemove.push_back(n); + } + } + MF_DEBUG("DONE O links validity check" << endl); + + if(osToRemove.size()) { + MF_DEBUG("Removing Ns with INVALID O key:" << endl); + for(auto oToRemove:osToRemove) { + MF_DEBUG(" " << oToRemove->getName() << endl); + delete oToRemove; + outlinesMap->removeNote(oToRemove); + } + osToRemove.clear(); + } + + // find mind keys which are NOT in map > prepend them to map + vector osToAdd{}; + MF_DEBUG("Finding mind keys to be ADDED to map:" << endl); + for(auto mindO: getOutlines()) { + if(find(mapOsKeys.begin(), mapOsKeys.end(), mindO->getKey()) == mapOsKeys.end()) { + MF_DEBUG(" " << mindO->getKey() << endl); + + // TODO skip keys w/ "," ~ https://github.com/dvorka/mindforger/issues/1518 workaround + // TODO remove this code once #1518 is fixed + if(find(mindO->getKey().begin(), mindO->getKey().end(), ',') == mindO->getKey().end()) { + osToAdd.push_back(mindO); + } else { + MF_DEBUG(" SKIPPING key w/ ','" << endl); + continue; + } + + } + } + MF_DEBUG("ADDING mind keys to map:" << endl); + for(auto o:osToAdd) { + MF_DEBUG(" " << o->getKey() << endl); + // clone O's descriptor to get N which might be deleted later + Note* n = new Note(*o->getOutlineDescriptorAsNote()); + + n->clearLinks(); + n->addLink( + new Link{ + LINK_NAME_OUTLINE_KEY, + o->getKey() + } + ); + n->addLink( + new Link{ + LINK_NAME_OUTLINE_PATH, + Mind::outlineMapKey2Relative(o->getKey()) + } + ); + + outlinesMap->addNote(n , 0); + } +} + +Outline* Mind::outlinesMapLearn(string outlineKey) +{ + #ifdef MF_DEBUG_LIBRARY + MF_DEBUG("Learning Os map from " << outlineKey << endl); + #endif + Outline* outlinesMap = memory.learnOutlinesMap(outlineKey); + + vector osToRemove{}; + + // normalization: set Ns types to O + resolve O links to absolute + #ifdef MF_DEBUG_LIBRARY + MF_DEBUG("Setting map's Ns type O" << endl); + #endif + for(auto n:outlinesMap->getNotes()) { + #ifdef MF_DEBUG_LIBRARY + MF_DEBUG( + " Setting '" << n->getName() + << "' with " << n->getLinks().size() << " link(s)" + << " to O" << endl + ); + #endif + n->setType(&Outline::NOTE_4_OUTLINE_TYPE); + + Link* oMemPathLink = n->getLinkByName(LINK_NAME_OUTLINE_PATH); + if(oMemPathLink && oMemPathLink->getUrl().size() > 0) { + string oMemPath{oMemPathLink->getUrl()}; + + n->clearLinks(); + n->addLink( + new Link{ + LINK_NAME_OUTLINE_KEY, + Mind::outlineMapKey2Absolute(oMemPath) + } + ); + n->addLink( + new Link{ + LINK_NAME_OUTLINE_PATH, + oMemPath + } + ); + } else { + MF_DEBUG(" SKIPPING N w/o link: " << n->getName() << endl); + osToRemove.push_back(n); + } + } + + if(osToRemove.size()) { + MF_DEBUG("Removing Ns with MISSING relative O key:" << endl); + for(auto oToRemove:osToRemove) { + MF_DEBUG(" " << oToRemove->getName() << endl); + delete oToRemove; + outlinesMap->removeNote(oToRemove); + } + osToRemove.clear(); + } + + // synchronize map's Os with mind's Os + outlinesMapSynchronize(outlinesMap); + + return outlinesMap; +} + +Outline* Mind::outlinesMapGet() +{ + if(this->outlinesMap) { + // ensure consistency between mind's and map's Os + outlinesMapSynchronize(this->outlinesMap); + + return this->outlinesMap; + } + + string outlinesMapPath{config.getOutlinesMapPath()}; + + if(isFile(outlinesMapPath.c_str())) { + // load existing Os map + this->outlinesMap = outlinesMapLearn(outlinesMapPath); + } else { + // create new Os map + this->outlinesMap = outlinesMapNew(outlinesMapPath); + + outlinesMapRemember(); + } + + return this->outlinesMap; +} + +Outline* Mind::outlinesMapRemember() +{ + if(this->outlinesMap) { + remind().getPersistence().save(this->outlinesMap); + } + + return this->outlinesMap; +} + Note* Mind::noteNew( - const std::string& outlineKey, - const uint16_t offset, - // IMPROVE pass name by reference - const std::string* name, - const NoteType* noteType, - u_int16_t depth, - const std::vector* tags, - const int8_t progress, - Stencil* noteStencil) + const std::string& outlineKey, + const uint16_t offset, + // IMPROVE pass name by reference + const std::string* name, + const NoteType* noteType, + u_int16_t depth, + const std::vector* tags, + const int8_t progress, + Stencil* noteStencil) { Outline* o = memory.getOutline(outlineKey); if(o) { @@ -1158,23 +1421,6 @@ MindStatistics* Mind::getStatistics() return stats; } -/* - * NER - */ - -#ifdef MF_NER - -bool Mind::isNerInitilized() const -{ - return ai->isNerInitialized(); -} - -void Mind::recognizePersons(const Outline* outline, int entityFilter, std::vector& result) { - ai->recognizePersons(outline, entityFilter, result); -} - -#endif - // unique_ptr template BREAKS Qt Developer indentation > stored at EOF unique_ptr> Mind::findOutlineByNameFts(const string& pattern) const { @@ -1192,4 +1438,80 @@ unique_ptr> Mind::findOutlineByNameFts(const string& pattern) c return result; } +Outline* Mind::findOutlineByKey(const string& key) const +{ + if(key.size()) { + vector outlines = memory.getOutlines(); + for(Outline* outline:outlines) { + if(key.compare(outline->getKey()) == 0) { + return outline; + } + } + } + + return nullptr; +} + +void Mind::initWingman() +{ + MF_DEBUG( + "MIND Wingman init: " << boolalpha << config.isWingman() << endl + ); + if(config.isWingman()) { + MF_DEBUG("MIND Wingman INIT: instantiation..." << endl); + switch(config.getWingmanLlmProvider()) { + case WingmanLlmProviders::WINGMAN_PROVIDER_OPENAI: + MF_DEBUG(" MIND Wingman init: OpenAI" << endl); + wingman = (Wingman*)new OpenAiWingman{ + config.getWingmanApiKey(), + config.getWingmanLlmModel() + }; + wingmanLlmProvider = config.getWingmanLlmProvider(); + return; + // case BARD: + // wingman = (Wingman*)new BardWingman{}; + // return; + case WingmanLlmProviders::WINGMAN_PROVIDER_MOCK: + MF_DEBUG(" MIND Wingman init: MOCK" << endl); + wingman = (Wingman*)new MockWingman{ + "mock-llm-model" + }; + wingmanLlmProvider = config.getWingmanLlmProvider(); + return; + default: + MF_DEBUG(" MIND Wingman init: UNKNOWN" << endl); + break; + } + } + + MF_DEBUG("MIND Wingman init: DISABLED" << endl); + wingman = nullptr; + wingmanLlmProvider = WingmanLlmProviders::WINGMAN_PROVIDER_NONE; +} + +Wingman* Mind::getWingman() +{ + if(this->wingmanLlmProvider != config.getWingmanLlmProvider()) { + initWingman(); + } + + return this->wingman; +} + +CommandWingmanChat Mind::wingmanChat(CommandWingmanChat& command) +{ + MF_DEBUG("MIND: Wingman chat..." << endl); + + if(getWingman()) { + getWingman()->chat(command); + MF_DEBUG("MIND: DONE Wingman chat" << endl); + } else { + MF_DEBUG("ERROR: MIND Wingman chat - Wingman NOT configured and/or initialized" << endl); + command.errorMessage = "ERROR: Wingman NOT configured and/or initialized"; + command.status = WingmanStatusCode::WINGMAN_STATUS_CODE_ERROR; + } + + return command; +} + } /* namespace */ diff --git a/lib/src/mind/mind.h b/lib/src/mind/mind.h index 571a201d..6d8e55d8 100644 --- a/lib/src/mind/mind.h +++ b/lib/src/mind/mind.h @@ -1,7 +1,7 @@ /* mind.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,19 +23,20 @@ #include #include #include +#include #include "memory.h" #include "knowledge_graph.h" #include "ai/ai.h" +#include "ai/llm/wingman.h" +#include "ai/llm/openai_wingman.h" +#include "ai/llm/mock_wingman.h" #include "associated_notes.h" #include "ontology/thing_class_rel_triple.h" #include "aspect/mind_scope_aspect.h" #include "../config/configuration.h" #include "../representations/representation_interceptor.h" #include "../representations/markdown/markdown_configuration_representation.h" -#ifdef MF_NER - #include "ai/nlp/named_entity_recognition.h" -#endif namespace m8r { @@ -153,6 +154,19 @@ class Mind : public OntologyProvider AutolinkingMind* autolinking; MindStatistics* stats; + /** + * Outline map is an Outline used to organize Outlines into the tree. + * Notes in the Outline map: + * + * - has exactly one link which points to the Outline they represent + * - Outline link is *relative* on the filesystem and absolute (resolved) in runtime + */ + Outline* outlinesMap; + + std::string outlineMapKey2Relative(const std::string& outlineKey) const; + std::string outlineMapKey2Absolute(const std::string& outlineKey) const; + void outlinesMapSynchronize(Outline* outlinesMap); + /** * Atomic mind state changes and asynchronous computations synchronization * through Mind components and processes. @@ -181,6 +195,20 @@ class Mind : public OntologyProvider */ Ai* ai; + /** + * Configuration driven Wingman initialization. + */ + void initWingman(); + /** + * Wingman LLM provider currently used by Mind. + * (user to detect configuration changes) + */ + WingmanLlmProviders wingmanLlmProvider; + /** + * Wingman + */ + Wingman* wingman; + /** * @brief Knowledge graph mind representation. */ @@ -309,17 +337,6 @@ class Mind : public OntologyProvider size_t getTriplesCount() const { return triples.size(); } -#ifdef MF_NER - - /* - * NRE - */ - - bool isNerInitilized() const; - void recognizePersons(const Outline* outline, int entityFilter, std::vector& result); - -#endif - /* * REMEMBERING */ @@ -367,6 +384,7 @@ class Mind : public OntologyProvider */ std::unique_ptr> findOutlineByNameFts(const std::string& pattern) const; //std::vector* findNoteByNameFts(const std::string& pattern) const; + Outline* findOutlineByKey(const std::string& key) const; std::vector* findNoteFts( const std::string& pattern, const FtsSearch mode = FtsSearch::EXACT, @@ -374,6 +392,7 @@ class Mind : public OntologyProvider // TODO findFts() - search also outline name and description // >> temporary note of Outline type (never saved), cannot be created by user void getOutlineNames(std::vector& names) const; + void getOutlineKeys(std::vector& keys) const; /* * SCOPING @@ -541,6 +560,27 @@ class Mind : public OntologyProvider */ bool outlineForget(std::string outlineKey); + /* + * OUTLINE MAP (TREE) + */ + + /** + * @brief Create new O map (tree). + */ + Outline* outlinesMapNew(std::string outlineKey); + /** + * @brief Load Os map (tree). + */ + Outline* outlinesMapLearn(std::string outlineKey); + /** + * @brief Load or create Os map (tree). + */ + Outline* outlinesMapGet(); + /** + * @brief Save Os map (tree). + */ + Outline* outlinesMapRemember(); + /* * NOTE MGMT */ @@ -642,6 +682,12 @@ class Mind : public OntologyProvider */ void noteOnRename(const std::string& oldName, const std::string& newName); + /* + * WINGMAN + */ + Wingman* getWingman(); + CommandWingmanChat wingmanChat(CommandWingmanChat& command); + /* * DIAGNOSTICS */ diff --git a/lib/src/mind/mind_listener.h b/lib/src/mind/mind_listener.h index 5b4ca9c2..390ddf19 100644 --- a/lib/src/mind/mind_listener.h +++ b/lib/src/mind/mind_listener.h @@ -1,7 +1,7 @@ /* mind_listener.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ontology/ontology.cpp b/lib/src/mind/ontology/ontology.cpp index 3221042f..009f50fc 100644 --- a/lib/src/mind/ontology/ontology.cpp +++ b/lib/src/mind/ontology/ontology.cpp @@ -1,7 +1,7 @@ /* ontology.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ontology/ontology.h b/lib/src/mind/ontology/ontology.h index 7fd37fcf..5c3e6e75 100644 --- a/lib/src/mind/ontology/ontology.h +++ b/lib/src/mind/ontology/ontology.h @@ -1,7 +1,7 @@ /* ontology.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ontology/ontology_vocabulary.h b/lib/src/mind/ontology/ontology_vocabulary.h index ab3b339e..c66b120c 100644 --- a/lib/src/mind/ontology/ontology_vocabulary.h +++ b/lib/src/mind/ontology/ontology_vocabulary.h @@ -1,7 +1,7 @@ /* ontology_map.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ontology/taxonomy.h b/lib/src/mind/ontology/taxonomy.h index 85ee15f6..4a1527b7 100644 --- a/lib/src/mind/ontology/taxonomy.h +++ b/lib/src/mind/ontology/taxonomy.h @@ -1,7 +1,7 @@ /* taxonomy.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ontology/thing_class_rel_triple.cpp b/lib/src/mind/ontology/thing_class_rel_triple.cpp index 359a1b74..3fa704b4 100644 --- a/lib/src/mind/ontology/thing_class_rel_triple.cpp +++ b/lib/src/mind/ontology/thing_class_rel_triple.cpp @@ -1,7 +1,7 @@ /* thing.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/ontology/thing_class_rel_triple.h b/lib/src/mind/ontology/thing_class_rel_triple.h index f99db098..71250ea8 100644 --- a/lib/src/mind/ontology/thing_class_rel_triple.h +++ b/lib/src/mind/ontology/thing_class_rel_triple.h @@ -1,7 +1,7 @@ /* thing_class_rel_triple.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/working_memory.cpp b/lib/src/mind/working_memory.cpp index fd07eca7..92b2de1e 100644 --- a/lib/src/mind/working_memory.cpp +++ b/lib/src/mind/working_memory.cpp @@ -1,7 +1,7 @@ /* working_memory.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/mind/working_memory.h b/lib/src/mind/working_memory.h index 5c379e37..6eabed7f 100644 --- a/lib/src/mind/working_memory.h +++ b/lib/src/mind/working_memory.h @@ -1,7 +1,7 @@ /* working_memory.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/eisenhower_matrix.cpp b/lib/src/model/eisenhower_matrix.cpp index 155c6141..a7887fa6 100644 --- a/lib/src/model/eisenhower_matrix.cpp +++ b/lib/src/model/eisenhower_matrix.cpp @@ -1,7 +1,7 @@ /* eisenhower_matrix.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -63,8 +63,10 @@ const string EisenhowerMatrix::getSortByAsStr() { } } -EisenhowerMatrix* EisenhowerMatrix::createEisenhowMatrixOrganizer() { - EisenhowerMatrix* eisenhowerMatrixOrganizer = new EisenhowerMatrix("Eisenhower Matrix"); +EisenhowerMatrix* EisenhowerMatrix::createEisenhowerMatrixOrganizer() { + EisenhowerMatrix* eisenhowerMatrixOrganizer = new EisenhowerMatrix( + "Eisenhower Matrix" + ); eisenhowerMatrixOrganizer->setKey(EisenhowerMatrix::KEY_EISENHOWER_MATRIX); eisenhowerMatrixOrganizer->setUpperRightTag("important & urgent"); diff --git a/lib/src/model/eisenhower_matrix.h b/lib/src/model/eisenhower_matrix.h index 8ddb7793..2f3be4b4 100644 --- a/lib/src/model/eisenhower_matrix.h +++ b/lib/src/model/eisenhower_matrix.h @@ -1,7 +1,7 @@ /* eisenhower_matrix.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -37,11 +37,12 @@ class EisenhowerMatrix : public Organizer static constexpr const auto CONFIG_VALUE_SORT_BY_I = "importance"; static constexpr const auto CONFIG_VALUE_SORT_BY_U = "urgency"; - static constexpr const auto KEY_EISENHOWER_MATRIX = "/m1ndf0rg3r/organizers/eisenhower-matrix"; + static constexpr const auto KEY_EISENHOWER_MATRIX = + "/m1ndf0rg3r/organizers/eisenhower-matrix"; static std::string createEisenhowerMatrixKey(); - static EisenhowerMatrix* createEisenhowMatrixOrganizer(); + static EisenhowerMatrix* createEisenhowerMatrixOrganizer(); static bool isEisenhowMatrixOrganizer(Organizer* o); public: diff --git a/lib/src/model/kanban.cpp b/lib/src/model/kanban.cpp index f9e06dc0..83c6b737 100644 --- a/lib/src/model/kanban.cpp +++ b/lib/src/model/kanban.cpp @@ -1,7 +1,7 @@ /* kanban.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/kanban.h b/lib/src/model/kanban.h index 91a00640..fb507c58 100644 --- a/lib/src/model/kanban.h +++ b/lib/src/model/kanban.h @@ -1,7 +1,7 @@ /* kanban.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/link.cpp b/lib/src/model/link.cpp index 31dcbd6c..ad43af20 100644 --- a/lib/src/model/link.cpp +++ b/lib/src/model/link.cpp @@ -1,7 +1,7 @@ /* link.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/link.h b/lib/src/model/link.h index 2da33691..1422ffc9 100644 --- a/lib/src/model/link.h +++ b/lib/src/model/link.h @@ -1,7 +1,7 @@ /* link.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/note.cpp b/lib/src/model/note.cpp index 86fe458c..321f98b2 100644 --- a/lib/src/model/note.cpp +++ b/lib/src/model/note.cpp @@ -1,7 +1,7 @@ /* note.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -67,6 +67,12 @@ Note::Note(const Note& n) tags.insert(tags.end(), n.tags.begin(), n.tags.end()); } + if(n.links.size()) { + for(Link* l:n.links) { + links.push_back(new Link(l->getName(), l->getUrl())); + } + } + flags = n.flags; } @@ -290,7 +296,7 @@ const vector& Note::getDescription() const } string Note::getDescriptionAsString(const std::string& separator) const -{ +{ // IMPROVE cache narrowed description for performance & return it by reference string result{}; if(description.size()) { @@ -456,6 +462,17 @@ void Note::addLink(Link* link) } } +Link* Note::getLinkByName(const string& name) const +{ + for(Link* l:this->links) { + if(l->getName() == name) { + return l; + } + } + + return nullptr; +} + void Note::demote() { depth++; diff --git a/lib/src/model/note.h b/lib/src/model/note.h index f3ad3157..4364faec 100644 --- a/lib/src/model/note.h +++ b/lib/src/model/note.h @@ -1,7 +1,7 @@ /* note.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -34,6 +34,12 @@ namespace m8r { class Outline; +// Outline key - resolved O path which may change if the repository is moved +constexpr const auto LINK_NAME_OUTLINE_KEY = "Outline key"; +// Outline path - relative O path which can be used to create valid absolute O path on map load +constexpr const auto LINK_NAME_OUTLINE_PATH = "Outline path"; +// ^ const in constexpr ensures const value + /** * @brief Note - a thought. * @@ -160,7 +166,12 @@ class Note : public ThingInTime void addLink(Link* link); const std::vector& getLinks() const { return links; } + Link* getLinkByName(const std::string& name) const; size_t getLinksCount() const { return links.size(); } + void clearLinks() { + for(auto l:links) { delete l; } + links.clear(); + } void promote(); void demote(); diff --git a/lib/src/model/note_type.cpp b/lib/src/model/note_type.cpp index a5234371..155492e3 100644 --- a/lib/src/model/note_type.cpp +++ b/lib/src/model/note_type.cpp @@ -1,7 +1,7 @@ /* note_type.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/note_type.h b/lib/src/model/note_type.h index 186312e4..8d8f47f8 100644 --- a/lib/src/model/note_type.h +++ b/lib/src/model/note_type.h @@ -1,7 +1,7 @@ /* note_type.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/organizer.cpp b/lib/src/model/organizer.cpp index 733f4fdb..5d752b24 100644 --- a/lib/src/model/organizer.cpp +++ b/lib/src/model/organizer.cpp @@ -1,7 +1,7 @@ /* organizer.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,7 +23,7 @@ using namespace std; namespace m8r { const string Organizer::TYPE_STR_KANBAN = string{"Kanban"}; -const string Organizer::TYPE_STR_EISENHOWER_MATRIX= string{"Eisenhower Matrix"}; +const string Organizer::TYPE_STR_EISENHOWER_MATRIX = string{"Eisenhower Matrix"}; std::string Organizer::createOrganizerKey( const set& keys, @@ -58,7 +58,7 @@ Organizer::Organizer(const Organizer& o) organizerType{o.organizerType}, filterBy{o.getFilterBy()}, modified{o.modified} -{ +{ this->tagsUrQuadrant = o.tagsUrQuadrant; this->tagsUlQuadrant = o.tagsUlQuadrant; this->tagsLrQuadrant = o.tagsLlQuadrant; diff --git a/lib/src/model/organizer.h b/lib/src/model/organizer.h index 2f25a61f..9cb76265 100644 --- a/lib/src/model/organizer.h +++ b/lib/src/model/organizer.h @@ -1,7 +1,7 @@ /* organizer.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/outline.cpp b/lib/src/model/outline.cpp index ff866e50..9767edfc 100644 --- a/lib/src/model/outline.cpp +++ b/lib/src/model/outline.cpp @@ -1,7 +1,7 @@ /* outline.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -393,6 +393,11 @@ void Outline::setNotes(const vector& notes) this->notes = notes; } +void Outline::sortNotesByRead() +{ + Outline::sortByRead(this->notes); +} + int8_t Outline::getProgress() const { return progress; @@ -504,7 +509,7 @@ Note* Outline::cloneNote(const Note* clonedNote, const bool deep) { int offset = getNoteOffset(clonedNote); if(offset != -1) { - Note* newNote; + Note* newNote{}; vector children{}; getAllNoteChildren(clonedNote, &children); diff --git a/lib/src/model/outline.h b/lib/src/model/outline.h index c4b7610f..81955499 100644 --- a/lib/src/model/outline.h +++ b/lib/src/model/outline.h @@ -1,7 +1,7 @@ /* outline.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -259,7 +259,8 @@ class Outline : public ThingInTime const std::vector& getNotes() const; size_t getNotesCount() const; void setNotes(const std::vector& notes); - void addNote(Note*); + void sortNotesByRead(); + void addNote(Note*); /** * @brief Clone Note including its children. * diff --git a/lib/src/model/outline_type.cpp b/lib/src/model/outline_type.cpp index 7f33efa0..6a63d1b4 100644 --- a/lib/src/model/outline_type.cpp +++ b/lib/src/model/outline_type.cpp @@ -1,7 +1,7 @@ /* outline_type.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/outline_type.h b/lib/src/model/outline_type.h index b8c86817..5306ecef 100644 --- a/lib/src/model/outline_type.h +++ b/lib/src/model/outline_type.h @@ -1,7 +1,7 @@ /* outline_type.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/resource_types.h b/lib/src/model/resource_types.h index 82e8e1fb..ef52a802 100644 --- a/lib/src/model/resource_types.h +++ b/lib/src/model/resource_types.h @@ -1,7 +1,7 @@ /* resource_types.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/stencil.cpp b/lib/src/model/stencil.cpp index aceb4314..e43c82ba 100644 --- a/lib/src/model/stencil.cpp +++ b/lib/src/model/stencil.cpp @@ -1,7 +1,7 @@ /* concept_stencil.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/stencil.h b/lib/src/model/stencil.h index 565f38b4..93e99df8 100644 --- a/lib/src/model/stencil.h +++ b/lib/src/model/stencil.h @@ -1,7 +1,7 @@ /* concept_stencil.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/tag.cpp b/lib/src/model/tag.cpp index 339563c9..b64d5623 100644 --- a/lib/src/model/tag.cpp +++ b/lib/src/model/tag.cpp @@ -1,7 +1,7 @@ /* tag.cpp MindForger application entry point - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/model/tag.h b/lib/src/model/tag.h index 41150c07..b069db85 100644 --- a/lib/src/model/tag.h +++ b/lib/src/model/tag.h @@ -1,7 +1,7 @@ /* tag.h MindForger application entry point - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/persistence/configuration_persistence.cpp b/lib/src/persistence/configuration_persistence.cpp index cff4a41b..c71bb13e 100644 --- a/lib/src/persistence/configuration_persistence.cpp +++ b/lib/src/persistence/configuration_persistence.cpp @@ -1,7 +1,7 @@ /* configuration_persistence.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/persistence/configuration_persistence.h b/lib/src/persistence/configuration_persistence.h index 1620140f..0f497dc5 100644 --- a/lib/src/persistence/configuration_persistence.h +++ b/lib/src/persistence/configuration_persistence.h @@ -1,7 +1,7 @@ /* configuration_persistence.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/persistence/filesystem_persistence.cpp b/lib/src/persistence/filesystem_persistence.cpp index 6da47064..bbf46850 100644 --- a/lib/src/persistence/filesystem_persistence.cpp +++ b/lib/src/persistence/filesystem_persistence.cpp @@ -1,7 +1,7 @@ /* filesystem_persistence.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/persistence/filesystem_persistence.h b/lib/src/persistence/filesystem_persistence.h index 53f29e3c..d0173acf 100644 --- a/lib/src/persistence/filesystem_persistence.h +++ b/lib/src/persistence/filesystem_persistence.h @@ -1,7 +1,7 @@ /* filesystem_persistence.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/persistence/persistence.cpp b/lib/src/persistence/persistence.cpp index f265acee..7f3a8457 100644 --- a/lib/src/persistence/persistence.cpp +++ b/lib/src/persistence/persistence.cpp @@ -1,7 +1,7 @@ /* persistence.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/persistence/persistence.h b/lib/src/persistence/persistence.h index 1cf9e628..86c2f750 100644 --- a/lib/src/persistence/persistence.h +++ b/lib/src/persistence/persistence.h @@ -1,7 +1,7 @@ /* persistence.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -37,7 +37,7 @@ class Persistence { const std::string& extension) = 0; virtual void load(Stencil* stencil) = 0; virtual bool isWriteable(const std::string& outlineKey) = 0; - virtual void save(Outline* outline) = 0; + virtual void save(Outline* outline) = 0; virtual void saveAsHtml(Outline* outline, const std::string& fileName) = 0; }; diff --git a/lib/src/repository_indexer.cpp b/lib/src/repository_indexer.cpp index d2379fb8..2a477bda 100644 --- a/lib/src/repository_indexer.cpp +++ b/lib/src/repository_indexer.cpp @@ -1,7 +1,7 @@ /* repository_indexer.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/repository_indexer.h b/lib/src/repository_indexer.h index 88cc4810..807360bb 100644 --- a/lib/src/repository_indexer.h +++ b/lib/src/repository_indexer.h @@ -1,7 +1,7 @@ /* repository_indexer.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/representations/csv/csv_outline_representation.cpp b/lib/src/representations/csv/csv_outline_representation.cpp index ed9c660e..ffbfe1a6 100644 --- a/lib/src/representations/csv/csv_outline_representation.cpp +++ b/lib/src/representations/csv/csv_outline_representation.cpp @@ -1,7 +1,7 @@ /* csv_outline_representation.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/representations/csv/csv_outline_representation.h b/lib/src/representations/csv/csv_outline_representation.h index d58315aa..0adef823 100644 --- a/lib/src/representations/csv/csv_outline_representation.h +++ b/lib/src/representations/csv/csv_outline_representation.h @@ -1,7 +1,7 @@ /* csv_outline_representation.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/representations/html/html_document.cpp b/lib/src/representations/html/html_document.cpp index b5c55e52..d3e30522 100644 --- a/lib/src/representations/html/html_document.cpp +++ b/lib/src/representations/html/html_document.cpp @@ -1,7 +1,7 @@ /* html_document.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/representations/html/html_document.h b/lib/src/representations/html/html_document.h index 20c98104..234f36ef 100644 --- a/lib/src/representations/html/html_document.h +++ b/lib/src/representations/html/html_document.h @@ -1,7 +1,7 @@ /* html_document.h MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/src/representations/html/html_outline_representation.cpp b/lib/src/representations/html/html_outline_representation.cpp index 2c2a5556..ba9062c3 100644 --- a/lib/src/representations/html/html_outline_representation.cpp +++ b/lib/src/representations/html/html_outline_representation.cpp @@ -1,7 +1,7 @@ /* html_outline_representation.cpp MindForger thinking notebook - Copyright (C) 2016-2022 Martin Dvorak + Copyright (C) 2016-2024 Martin Dvorak This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -144,6 +144,7 @@ void HtmlOutlineRepresentation::header(string& html, string* basePath, bool stan html.assign( "\n" "" + "" "
";
@@ -152,7 +153,9 @@ void HtmlOutlineRepresentation::header(string& html, string* basePath, bool stan
         html.assign(
             "\n"
             ""
-            "");
+            ""
+            ""
+        );
 #ifdef DO_MF_DEBUG
         html += "\n";
 #endif
diff --git a/lib/src/representations/html/html_outline_representation.h b/lib/src/representations/html/html_outline_representation.h
index 50e828d5..0e5efa1e 100644
--- a/lib/src/representations/html/html_outline_representation.h
+++ b/lib/src/representations/html/html_outline_representation.h
@@ -1,7 +1,7 @@
 /*
  html_outline_representation.h     MindForger thinking notebook
 
- Copyright (C) 2016-2022 Martin Dvorak 
+ Copyright (C) 2016-2024 Martin Dvorak 
 
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
@@ -79,7 +79,7 @@ class HtmlOutlineRepresentation
 
     Configuration& config;
     HtmlExportColorsRepresentation exportColors;
-    HtmlColorsRepresentation& lf;    
+    HtmlColorsRepresentation& lf;
     MarkdownOutlineRepresentation markdownRepresentation;
     MarkdownTranscoder* markdownTranscoder;
 
diff --git a/lib/src/representations/json/nlohmann/json.hpp b/lib/src/representations/json/nlohmann/json.hpp
new file mode 100644
index 00000000..b191bb91
--- /dev/null
+++ b/lib/src/representations/json/nlohmann/json.hpp
@@ -0,0 +1,24766 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+/****************************************************************************\
+ * Note on documentation: The source files contain links to the online      *
+ * documentation of the public API at https://json.nlohmann.me. This URL    *
+ * contains the most recent documentation and should also be applicable to  *
+ * previous versions; documentation for deprecated functions is not         *
+ * removed, but marked deprecated. See "Generate documentation" section in  *
+ * file docs/README.md.                                                     *
+\****************************************************************************/
+
+#ifndef INCLUDE_NLOHMANN_JSON_HPP_
+#define INCLUDE_NLOHMANN_JSON_HPP_
+
+#include  // all_of, find, for_each
+#include  // nullptr_t, ptrdiff_t, size_t
+#include  // hash, less
+#include  // initializer_list
+#ifndef JSON_NO_IO
+    #include  // istream, ostream
+#endif  // JSON_NO_IO
+#include  // random_access_iterator_tag
+#include  // unique_ptr
+#include  // string, stoi, to_string
+#include  // declval, forward, move, pair, swap
+#include  // vector
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include 
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+// This file contains all macro definitions affecting or depending on the ABI
+
+#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
+    #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
+        #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
+            #warning "Already included a different version of the library!"
+        #endif
+    #endif
+#endif
+
+#define NLOHMANN_JSON_VERSION_MAJOR 3   // NOLINT(modernize-macro-to-enum)
+#define NLOHMANN_JSON_VERSION_MINOR 11  // NOLINT(modernize-macro-to-enum)
+#define NLOHMANN_JSON_VERSION_PATCH 3   // NOLINT(modernize-macro-to-enum)
+
+#ifndef JSON_DIAGNOSTICS
+    #define JSON_DIAGNOSTICS 0
+#endif
+
+#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
+#endif
+
+#if JSON_DIAGNOSTICS
+    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
+#else
+    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
+#endif
+
+#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
+#else
+    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
+#endif
+
+#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
+    #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
+#endif
+
+// Construct the namespace ABI tags component
+#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
+#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
+    NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
+
+#define NLOHMANN_JSON_ABI_TAGS                                       \
+    NLOHMANN_JSON_ABI_TAGS_CONCAT(                                   \
+            NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS,                       \
+            NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
+
+// Construct the namespace version component
+#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
+    _v ## major ## _ ## minor ## _ ## patch
+#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
+    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
+
+#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
+#define NLOHMANN_JSON_NAMESPACE_VERSION
+#else
+#define NLOHMANN_JSON_NAMESPACE_VERSION                                 \
+    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
+                                           NLOHMANN_JSON_VERSION_MINOR, \
+                                           NLOHMANN_JSON_VERSION_PATCH)
+#endif
+
+// Combine namespace components
+#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
+#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
+    NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
+
+#ifndef NLOHMANN_JSON_NAMESPACE
+#define NLOHMANN_JSON_NAMESPACE               \
+    nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
+            NLOHMANN_JSON_ABI_TAGS,           \
+            NLOHMANN_JSON_NAMESPACE_VERSION)
+#endif
+
+#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
+#define NLOHMANN_JSON_NAMESPACE_BEGIN                \
+    namespace nlohmann                               \
+    {                                                \
+    inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
+                NLOHMANN_JSON_ABI_TAGS,              \
+                NLOHMANN_JSON_NAMESPACE_VERSION)     \
+    {
+#endif
+
+#ifndef NLOHMANN_JSON_NAMESPACE_END
+#define NLOHMANN_JSON_NAMESPACE_END                                     \
+    }  /* namespace (inline namespace) NOLINT(readability/namespace) */ \
+    }  // namespace nlohmann
+#endif
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // transform
+#include  // array
+#include  // forward_list
+#include  // inserter, front_inserter, end
+#include  // map
+#include  // string
+#include  // tuple, make_tuple
+#include  // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
+#include  // unordered_map
+#include  // pair, declval
+#include  // valarray
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // nullptr_t
+#include  // exception
+#if JSON_DIAGNOSTICS
+    #include  // accumulate
+#endif
+#include  // runtime_error
+#include  // to_string
+#include  // vector
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // array
+#include  // size_t
+#include  // uint8_t
+#include  // string
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // declval, pair
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include 
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+// #include 
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template struct make_void
+{
+    using type = void;
+};
+template using void_t = typename make_void::type;
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// https://en.cppreference.com/w/cpp/experimental/is_detected
+struct nonesuch
+{
+    nonesuch() = delete;
+    ~nonesuch() = delete;
+    nonesuch(nonesuch const&) = delete;
+    nonesuch(nonesuch const&&) = delete;
+    void operator=(nonesuch const&) = delete;
+    void operator=(nonesuch&&) = delete;
+};
+
+template class Op,
+         class... Args>
+struct detector
+{
+    using value_t = std::false_type;
+    using type = Default;
+};
+
+template class Op, class... Args>
+struct detector>, Op, Args...>
+{
+    using value_t = std::true_type;
+    using type = Op;
+};
+
+template class Op, class... Args>
+using is_detected = typename detector::value_t;
+
+template class Op, class... Args>
+struct is_detected_lazy : is_detected { };
+
+template class Op, class... Args>
+using detected_t = typename detector::type;
+
+template class Op, class... Args>
+using detected_or = detector;
+
+template class Op, class... Args>
+using detected_or_t = typename detected_or::type;
+
+template class Op, class... Args>
+using is_detected_exact = std::is_same>;
+
+template class Op, class... Args>
+using is_detected_convertible =
+    std::is_convertible, To>;
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+
+
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson 
+// SPDX-License-Identifier: MIT
+
+/* Hedley - https://nemequ.github.io/hedley
+ * Created by Evan Nemerson 
+ */
+
+#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15)
+#if defined(JSON_HEDLEY_VERSION)
+    #undef JSON_HEDLEY_VERSION
+#endif
+#define JSON_HEDLEY_VERSION 15
+
+#if defined(JSON_HEDLEY_STRINGIFY_EX)
+    #undef JSON_HEDLEY_STRINGIFY_EX
+#endif
+#define JSON_HEDLEY_STRINGIFY_EX(x) #x
+
+#if defined(JSON_HEDLEY_STRINGIFY)
+    #undef JSON_HEDLEY_STRINGIFY
+#endif
+#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)
+
+#if defined(JSON_HEDLEY_CONCAT_EX)
+    #undef JSON_HEDLEY_CONCAT_EX
+#endif
+#define JSON_HEDLEY_CONCAT_EX(a,b) a##b
+
+#if defined(JSON_HEDLEY_CONCAT)
+    #undef JSON_HEDLEY_CONCAT
+#endif
+#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)
+
+#if defined(JSON_HEDLEY_CONCAT3_EX)
+    #undef JSON_HEDLEY_CONCAT3_EX
+#endif
+#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c
+
+#if defined(JSON_HEDLEY_CONCAT3)
+    #undef JSON_HEDLEY_CONCAT3
+#endif
+#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)
+
+#if defined(JSON_HEDLEY_VERSION_ENCODE)
+    #undef JSON_HEDLEY_VERSION_ENCODE
+#endif
+#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)
+    #undef JSON_HEDLEY_VERSION_DECODE_MAJOR
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)
+    #undef JSON_HEDLEY_VERSION_DECODE_MINOR
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)
+    #undef JSON_HEDLEY_VERSION_DECODE_REVISION
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)
+
+#if defined(JSON_HEDLEY_GNUC_VERSION)
+    #undef JSON_HEDLEY_GNUC_VERSION
+#endif
+#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
+    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+#elif defined(__GNUC__)
+    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)
+    #undef JSON_HEDLEY_GNUC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_GNUC_VERSION)
+    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_MSVC_VERSION)
+    #undef JSON_HEDLEY_MSVC_VERSION
+#endif
+#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
+#elif defined(_MSC_FULL_VER) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
+#elif defined(_MSC_VER) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)
+    #undef JSON_HEDLEY_MSVC_VERSION_CHECK
+#endif
+#if !defined(JSON_HEDLEY_MSVC_VERSION)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
+#else
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_VERSION)
+    #undef JSON_HEDLEY_INTEL_VERSION
+#endif
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)
+    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
+#elif defined(__INTEL_COMPILER) && !defined(__ICL)
+    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)
+    #undef JSON_HEDLEY_INTEL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_INTEL_VERSION)
+    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION
+#endif
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)
+    #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_PGI_VERSION)
+    #undef JSON_HEDLEY_PGI_VERSION
+#endif
+#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
+    #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
+#endif
+
+#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)
+    #undef JSON_HEDLEY_PGI_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_PGI_VERSION)
+    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_SUNPRO_VERSION)
+    #undef JSON_HEDLEY_SUNPRO_VERSION
+#endif
+#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)
+#elif defined(__SUNPRO_C)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)
+#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)
+#elif defined(__SUNPRO_CC)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)
+#endif
+
+#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)
+    #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_SUNPRO_VERSION)
+    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
+    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION
+#endif
+#if defined(__EMSCRIPTEN__)
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)
+#endif
+
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)
+    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_ARM_VERSION)
+    #undef JSON_HEDLEY_ARM_VERSION
+#endif
+#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)
+#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)
+#endif
+
+#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)
+    #undef JSON_HEDLEY_ARM_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_ARM_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_IBM_VERSION)
+    #undef JSON_HEDLEY_IBM_VERSION
+#endif
+#if defined(__ibmxl__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)
+#elif defined(__xlC__) && defined(__xlC_ver__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
+#elif defined(__xlC__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)
+#endif
+
+#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)
+    #undef JSON_HEDLEY_IBM_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_IBM_VERSION)
+    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_VERSION)
+    #undef JSON_HEDLEY_TI_VERSION
+#endif
+#if \
+    defined(__TI_COMPILER_VERSION__) && \
+    ( \
+      defined(__TMS470__) || defined(__TI_ARM__) || \
+      defined(__MSP430__) || \
+      defined(__TMS320C2000__) \
+    )
+#if (__TI_COMPILER_VERSION__ >= 16000000)
+    #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+#endif
+
+#if defined(JSON_HEDLEY_TI_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_VERSION)
+    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
+    #undef JSON_HEDLEY_TI_CL2000_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)
+    #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
+    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL430_VERSION)
+    #undef JSON_HEDLEY_TI_CL430_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)
+    #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL430_VERSION)
+    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
+    #undef JSON_HEDLEY_TI_ARMCL_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))
+    #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
+    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
+    #undef JSON_HEDLEY_TI_CL6X_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)
+    #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
+    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
+    #undef JSON_HEDLEY_TI_CL7X_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)
+    #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
+    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
+    #undef JSON_HEDLEY_TI_CLPRU_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)
+    #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
+    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_CRAY_VERSION)
+    #undef JSON_HEDLEY_CRAY_VERSION
+#endif
+#if defined(_CRAYC)
+    #if defined(_RELEASE_PATCHLEVEL)
+        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)
+    #else
+        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)
+    #endif
+#endif
+
+#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)
+    #undef JSON_HEDLEY_CRAY_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_CRAY_VERSION)
+    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_IAR_VERSION)
+    #undef JSON_HEDLEY_IAR_VERSION
+#endif
+#if defined(__IAR_SYSTEMS_ICC__)
+    #if __VER__ > 1000
+        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))
+    #else
+        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0)
+    #endif
+#endif
+
+#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)
+    #undef JSON_HEDLEY_IAR_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_IAR_VERSION)
+    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TINYC_VERSION)
+    #undef JSON_HEDLEY_TINYC_VERSION
+#endif
+#if defined(__TINYC__)
+    #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
+#endif
+
+#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)
+    #undef JSON_HEDLEY_TINYC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TINYC_VERSION)
+    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_DMC_VERSION)
+    #undef JSON_HEDLEY_DMC_VERSION
+#endif
+#if defined(__DMC__)
+    #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)
+#endif
+
+#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)
+    #undef JSON_HEDLEY_DMC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_DMC_VERSION)
+    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_COMPCERT_VERSION)
+    #undef JSON_HEDLEY_COMPCERT_VERSION
+#endif
+#if defined(__COMPCERT_VERSION__)
+    #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)
+#endif
+
+#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)
+    #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_COMPCERT_VERSION)
+    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_PELLES_VERSION)
+    #undef JSON_HEDLEY_PELLES_VERSION
+#endif
+#if defined(__POCC__)
+    #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)
+    #undef JSON_HEDLEY_PELLES_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_PELLES_VERSION)
+    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #undef JSON_HEDLEY_MCST_LCC_VERSION
+#endif
+#if defined(__LCC__) && defined(__LCC_MINOR__)
+    #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__)
+#endif
+
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK)
+    #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_VERSION)
+    #undef JSON_HEDLEY_GCC_VERSION
+#endif
+#if \
+    defined(JSON_HEDLEY_GNUC_VERSION) && \
+    !defined(__clang__) && \
+    !defined(JSON_HEDLEY_INTEL_VERSION) && \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_ARM_VERSION) && \
+    !defined(JSON_HEDLEY_CRAY_VERSION) && \
+    !defined(JSON_HEDLEY_TI_VERSION) && \
+    !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL430_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \
+    !defined(__COMPCERT__) && \
+    !defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION
+#endif
+
+#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)
+    #undef JSON_HEDLEY_GCC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_GCC_VERSION)
+    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_ATTRIBUTE
+#endif
+#if \
+  defined(__has_attribute) && \
+  ( \
+    (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \
+  )
+#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)
+#else
+#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
+#endif
+#if defined(__has_attribute)
+    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
+#endif
+#if defined(__has_attribute)
+    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
+#endif
+#if \
+    defined(__has_cpp_attribute) && \
+    defined(__cplusplus) && \
+    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)
+    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
+#endif
+#if !defined(__cplusplus) || !defined(__has_cpp_attribute)
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
+#elif \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_IAR_VERSION) && \
+    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \
+    (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)
+#else
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
+#endif
+#if defined(__has_cpp_attribute) && defined(__cplusplus)
+    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
+#endif
+#if defined(__has_cpp_attribute) && defined(__cplusplus)
+    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_BUILTIN)
+    #undef JSON_HEDLEY_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)
+    #undef JSON_HEDLEY_GNUC_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)
+    #undef JSON_HEDLEY_GCC_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_FEATURE)
+    #undef JSON_HEDLEY_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_HAS_FEATURE(feature) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)
+    #undef JSON_HEDLEY_GNUC_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)
+    #undef JSON_HEDLEY_GCC_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_EXTENSION)
+    #undef JSON_HEDLEY_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)
+    #undef JSON_HEDLEY_GNUC_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)
+    #undef JSON_HEDLEY_GCC_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_WARNING)
+    #undef JSON_HEDLEY_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_HAS_WARNING(warning) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)
+    #undef JSON_HEDLEY_GNUC_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_WARNING)
+    #undef JSON_HEDLEY_GCC_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+    defined(__clang__) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
+    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
+    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
+    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
+#else
+    #define JSON_HEDLEY_PRAGMA(value)
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
+    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
+#endif
+#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
+    #undef JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+#if defined(__clang__)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
+    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
+#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH
+    #define JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+
+/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for
+   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
+#endif
+#if defined(__cplusplus)
+#  if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat")
+#    if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions")
+#      if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions")
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#      else
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#      endif
+#    else
+#      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#    endif
+#  endif
+#endif
+#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x
+#endif
+
+#if defined(JSON_HEDLEY_CONST_CAST)
+    #undef JSON_HEDLEY_CONST_CAST
+#endif
+#if defined(__cplusplus)
+#  define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr))
+#elif \
+  JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \
+        JSON_HEDLEY_DIAGNOSTIC_PUSH \
+        JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \
+        ((T) (expr)); \
+        JSON_HEDLEY_DIAGNOSTIC_POP \
+    }))
+#else
+#  define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_REINTERPRET_CAST)
+    #undef JSON_HEDLEY_REINTERPRET_CAST
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr))
+#else
+    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_STATIC_CAST)
+    #undef JSON_HEDLEY_STATIC_CAST
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr))
+#else
+    #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_CPP_CAST)
+    #undef JSON_HEDLEY_CPP_CAST
+#endif
+#if defined(__cplusplus)
+#  if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast")
+#    define JSON_HEDLEY_CPP_CAST(T, expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
+    ((T) (expr)) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)
+#    define JSON_HEDLEY_CPP_CAST(T, expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("diag_suppress=Pe137") \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  else
+#    define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))
+#  endif
+#else
+#  define JSON_HEDLEY_CPP_CAST(T, expr) (expr)
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445")
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215")
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161")
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098")
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097")
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunused-function")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505))
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#endif
+
+#if defined(JSON_HEDLEY_DEPRECATED)
+    #undef JSON_HEDLEY_DEPRECATED
+#endif
+#if defined(JSON_HEDLEY_DEPRECATED_FOR)
+    #undef JSON_HEDLEY_DEPRECATED_FOR
+#endif
+#if \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
+#elif \
+    (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
+#elif defined(__cplusplus) && (__cplusplus >= 201402L)
+    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated")
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated")
+#else
+    #define JSON_HEDLEY_DEPRECATED(since)
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)
+#endif
+
+#if defined(JSON_HEDLEY_UNAVAILABLE)
+    #undef JSON_HEDLEY_UNAVAILABLE
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since)))
+#else
+    #define JSON_HEDLEY_UNAVAILABLE(available_since)
+#endif
+
+#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)
+    #undef JSON_HEDLEY_WARN_UNUSED_RESULT
+#endif
+#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)
+    #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))
+#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+#elif defined(_Check_return_) /* SAL */
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_
+#else
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)
+#endif
+
+#if defined(JSON_HEDLEY_SENTINEL)
+    #undef JSON_HEDLEY_SENTINEL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))
+#else
+    #define JSON_HEDLEY_SENTINEL(position)
+#endif
+
+#if defined(JSON_HEDLEY_NO_RETURN)
+    #undef JSON_HEDLEY_NO_RETURN
+#endif
+#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_NO_RETURN __noreturn
+#elif \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+    #define JSON_HEDLEY_NO_RETURN _Noreturn
+#elif defined(__cplusplus) && (__cplusplus >= 201103L)
+    #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
+#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
+    #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
+    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
+#else
+    #define JSON_HEDLEY_NO_RETURN
+#endif
+
+#if defined(JSON_HEDLEY_NO_ESCAPE)
+    #undef JSON_HEDLEY_NO_ESCAPE
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)
+    #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))
+#else
+    #define JSON_HEDLEY_NO_ESCAPE
+#endif
+
+#if defined(JSON_HEDLEY_UNREACHABLE)
+    #undef JSON_HEDLEY_UNREACHABLE
+#endif
+#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)
+    #undef JSON_HEDLEY_UNREACHABLE_RETURN
+#endif
+#if defined(JSON_HEDLEY_ASSUME)
+    #undef JSON_HEDLEY_ASSUME
+#endif
+#if \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_ASSUME(expr) __assume(expr)
+#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)
+    #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)
+#elif \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
+    #if defined(__cplusplus)
+        #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)
+    #else
+        #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)
+    #endif
+#endif
+#if \
+    (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()
+#elif defined(JSON_HEDLEY_ASSUME)
+    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
+#endif
+#if !defined(JSON_HEDLEY_ASSUME)
+    #if defined(JSON_HEDLEY_UNREACHABLE)
+        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))
+    #else
+        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)
+    #endif
+#endif
+#if defined(JSON_HEDLEY_UNREACHABLE)
+    #if  \
+        JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
+        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))
+    #else
+        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()
+    #endif
+#else
+    #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)
+#endif
+#if !defined(JSON_HEDLEY_UNREACHABLE)
+    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
+#endif
+
+JSON_HEDLEY_DIAGNOSTIC_PUSH
+#if JSON_HEDLEY_HAS_WARNING("-Wpedantic")
+    #pragma clang diagnostic ignored "-Wpedantic"
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus)
+    #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0)
+    #if defined(__clang__)
+        #pragma clang diagnostic ignored "-Wvariadic-macros"
+    #elif defined(JSON_HEDLEY_GCC_VERSION)
+        #pragma GCC diagnostic ignored "-Wvariadic-macros"
+    #endif
+#endif
+#if defined(JSON_HEDLEY_NON_NULL)
+    #undef JSON_HEDLEY_NON_NULL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
+    #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+    #define JSON_HEDLEY_NON_NULL(...)
+#endif
+JSON_HEDLEY_DIAGNOSTIC_POP
+
+#if defined(JSON_HEDLEY_PRINTF_FORMAT)
+    #undef JSON_HEDLEY_PRINTF_FORMAT
+#endif
+#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))
+#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(format) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))
+#else
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)
+#endif
+
+#if defined(JSON_HEDLEY_CONSTEXPR)
+    #undef JSON_HEDLEY_CONSTEXPR
+#endif
+#if defined(__cplusplus)
+    #if __cplusplus >= 201103L
+        #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)
+    #endif
+#endif
+#if !defined(JSON_HEDLEY_CONSTEXPR)
+    #define JSON_HEDLEY_CONSTEXPR
+#endif
+
+#if defined(JSON_HEDLEY_PREDICT)
+    #undef JSON_HEDLEY_PREDICT
+#endif
+#if defined(JSON_HEDLEY_LIKELY)
+    #undef JSON_HEDLEY_LIKELY
+#endif
+#if defined(JSON_HEDLEY_UNLIKELY)
+    #undef JSON_HEDLEY_UNLIKELY
+#endif
+#if defined(JSON_HEDLEY_UNPREDICTABLE)
+    #undef JSON_HEDLEY_UNPREDICTABLE
+#endif
+#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)
+    #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))
+#endif
+#if \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(  (expr), (value), (probability))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability)   __builtin_expect_with_probability(!!(expr),    1   , (probability))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability)  __builtin_expect_with_probability(!!(expr),    0   , (probability))
+#  define JSON_HEDLEY_LIKELY(expr)                      __builtin_expect                 (!!(expr),    1                  )
+#  define JSON_HEDLEY_UNLIKELY(expr)                    __builtin_expect                 (!!(expr),    0                  )
+#elif \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \
+  JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PREDICT(expr, expected, probability) \
+    (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \
+    (__extension__ ({ \
+        double hedley_probability_ = (probability); \
+        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \
+    }))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \
+    (__extension__ ({ \
+        double hedley_probability_ = (probability); \
+        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \
+    }))
+#  define JSON_HEDLEY_LIKELY(expr)   __builtin_expect(!!(expr), 1)
+#  define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
+#else
+#  define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))
+#  define JSON_HEDLEY_LIKELY(expr) (!!(expr))
+#  define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))
+#endif
+#if !defined(JSON_HEDLEY_UNPREDICTABLE)
+    #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)
+#endif
+
+#if defined(JSON_HEDLEY_MALLOC)
+    #undef JSON_HEDLEY_MALLOC
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_MALLOC __declspec(restrict)
+#else
+    #define JSON_HEDLEY_MALLOC
+#endif
+
+#if defined(JSON_HEDLEY_PURE)
+    #undef JSON_HEDLEY_PURE
+#endif
+#if \
+  JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PURE __attribute__((__pure__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+#  define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data")
+#elif defined(__cplusplus) && \
+    ( \
+      JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
+      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \
+      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \
+    )
+#  define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;")
+#else
+#  define JSON_HEDLEY_PURE
+#endif
+
+#if defined(JSON_HEDLEY_CONST)
+    #undef JSON_HEDLEY_CONST
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(const) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_CONST __attribute__((__const__))
+#elif \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_CONST _Pragma("no_side_effect")
+#else
+    #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE
+#endif
+
+#if defined(JSON_HEDLEY_RESTRICT)
+    #undef JSON_HEDLEY_RESTRICT
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
+    #define JSON_HEDLEY_RESTRICT restrict
+#elif \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
+    defined(__clang__) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_RESTRICT __restrict
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)
+    #define JSON_HEDLEY_RESTRICT _Restrict
+#else
+    #define JSON_HEDLEY_RESTRICT
+#endif
+
+#if defined(JSON_HEDLEY_INLINE)
+    #undef JSON_HEDLEY_INLINE
+#endif
+#if \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+    (defined(__cplusplus) && (__cplusplus >= 199711L))
+    #define JSON_HEDLEY_INLINE inline
+#elif \
+    defined(JSON_HEDLEY_GCC_VERSION) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)
+    #define JSON_HEDLEY_INLINE __inline__
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_INLINE __inline
+#else
+    #define JSON_HEDLEY_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_ALWAYS_INLINE)
+    #undef JSON_HEDLEY_ALWAYS_INLINE
+#endif
+#if \
+  JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+  JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE __forceinline
+#elif defined(__cplusplus) && \
+    ( \
+      JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+      JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+      JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+      JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \
+    )
+#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced")
+#else
+#  define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_NEVER_INLINE)
+    #undef JSON_HEDLEY_NEVER_INLINE
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline")
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never")
+#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
+    #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
+    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
+#else
+    #define JSON_HEDLEY_NEVER_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_PRIVATE)
+    #undef JSON_HEDLEY_PRIVATE
+#endif
+#if defined(JSON_HEDLEY_PUBLIC)
+    #undef JSON_HEDLEY_PUBLIC
+#endif
+#if defined(JSON_HEDLEY_IMPORT)
+    #undef JSON_HEDLEY_IMPORT
+#endif
+#if defined(_WIN32) || defined(__CYGWIN__)
+#  define JSON_HEDLEY_PRIVATE
+#  define JSON_HEDLEY_PUBLIC   __declspec(dllexport)
+#  define JSON_HEDLEY_IMPORT   __declspec(dllimport)
+#else
+#  if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+    ( \
+      defined(__TI_EABI__) && \
+      ( \
+        (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \
+      ) \
+    ) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#    define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden")))
+#    define JSON_HEDLEY_PUBLIC  __attribute__((__visibility__("default")))
+#  else
+#    define JSON_HEDLEY_PRIVATE
+#    define JSON_HEDLEY_PUBLIC
+#  endif
+#  define JSON_HEDLEY_IMPORT    extern
+#endif
+
+#if defined(JSON_HEDLEY_NO_THROW)
+    #undef JSON_HEDLEY_NO_THROW
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
+    #define JSON_HEDLEY_NO_THROW __declspec(nothrow)
+#else
+    #define JSON_HEDLEY_NO_THROW
+#endif
+
+#if defined(JSON_HEDLEY_FALL_THROUGH)
+    #undef JSON_HEDLEY_FALL_THROUGH
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)
+    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)
+    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])
+#elif defined(__fallthrough) /* SAL */
+    #define JSON_HEDLEY_FALL_THROUGH __fallthrough
+#else
+    #define JSON_HEDLEY_FALL_THROUGH
+#endif
+
+#if defined(JSON_HEDLEY_RETURNS_NON_NULL)
+    #undef JSON_HEDLEY_RETURNS_NON_NULL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))
+#elif defined(_Ret_notnull_) /* SAL */
+    #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_
+#else
+    #define JSON_HEDLEY_RETURNS_NON_NULL
+#endif
+
+#if defined(JSON_HEDLEY_ARRAY_PARAM)
+    #undef JSON_HEDLEY_ARRAY_PARAM
+#endif
+#if \
+    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+    !defined(__STDC_NO_VLA__) && \
+    !defined(__cplusplus) && \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_TINYC_VERSION)
+    #define JSON_HEDLEY_ARRAY_PARAM(name) (name)
+#else
+    #define JSON_HEDLEY_ARRAY_PARAM(name)
+#endif
+
+#if defined(JSON_HEDLEY_IS_CONSTANT)
+    #undef JSON_HEDLEY_IS_CONSTANT
+#endif
+#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)
+    #undef JSON_HEDLEY_REQUIRE_CONSTEXPR
+#endif
+/* JSON_HEDLEY_IS_CONSTEXPR_ is for
+   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */
+#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
+    #undef JSON_HEDLEY_IS_CONSTEXPR_
+#endif
+#if \
+    JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)
+#endif
+#if !defined(__cplusplus)
+#  if \
+       JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \
+       JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+       JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+       JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+       JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+       JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
+       JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)
+#if defined(__INTPTR_TYPE__)
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)
+#else
+    #include 
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)
+#endif
+#  elif \
+       ( \
+          defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
+          !defined(JSON_HEDLEY_SUNPRO_VERSION) && \
+          !defined(JSON_HEDLEY_PGI_VERSION) && \
+          !defined(JSON_HEDLEY_IAR_VERSION)) || \
+       (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
+       JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
+       JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \
+       JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
+       JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)
+#if defined(__INTPTR_TYPE__)
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)
+#else
+    #include 
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)
+#endif
+#  elif \
+       defined(JSON_HEDLEY_GCC_VERSION) || \
+       defined(JSON_HEDLEY_INTEL_VERSION) || \
+       defined(JSON_HEDLEY_TINYC_VERSION) || \
+       defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \
+       JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \
+       defined(JSON_HEDLEY_TI_CL2000_VERSION) || \
+       defined(JSON_HEDLEY_TI_CL6X_VERSION) || \
+       defined(JSON_HEDLEY_TI_CL7X_VERSION) || \
+       defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \
+       defined(__clang__)
+#    define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \
+        sizeof(void) != \
+        sizeof(*( \
+                  1 ? \
+                  ((void*) ((expr) * 0L) ) : \
+((struct { char v[sizeof(void) * 2]; } *) 1) \
+                ) \
+              ) \
+                                            )
+#  endif
+#endif
+#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
+    #if !defined(JSON_HEDLEY_IS_CONSTANT)
+        #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)
+    #endif
+    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))
+#else
+    #if !defined(JSON_HEDLEY_IS_CONSTANT)
+        #define JSON_HEDLEY_IS_CONSTANT(expr) (0)
+    #endif
+    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)
+#endif
+
+#if defined(JSON_HEDLEY_BEGIN_C_DECLS)
+    #undef JSON_HEDLEY_BEGIN_C_DECLS
+#endif
+#if defined(JSON_HEDLEY_END_C_DECLS)
+    #undef JSON_HEDLEY_END_C_DECLS
+#endif
+#if defined(JSON_HEDLEY_C_DECL)
+    #undef JSON_HEDLEY_C_DECL
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" {
+    #define JSON_HEDLEY_END_C_DECLS }
+    #define JSON_HEDLEY_C_DECL extern "C"
+#else
+    #define JSON_HEDLEY_BEGIN_C_DECLS
+    #define JSON_HEDLEY_END_C_DECLS
+    #define JSON_HEDLEY_C_DECL
+#endif
+
+#if defined(JSON_HEDLEY_STATIC_ASSERT)
+    #undef JSON_HEDLEY_STATIC_ASSERT
+#endif
+#if \
+  !defined(__cplusplus) && ( \
+      (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \
+      (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
+      JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \
+      JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+      defined(_Static_assert) \
+    )
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
+#elif \
+  (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))
+#else
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message)
+#endif
+
+#if defined(JSON_HEDLEY_NULL)
+    #undef JSON_HEDLEY_NULL
+#endif
+#if defined(__cplusplus)
+    #if __cplusplus >= 201103L
+        #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)
+    #elif defined(NULL)
+        #define JSON_HEDLEY_NULL NULL
+    #else
+        #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)
+    #endif
+#elif defined(NULL)
+    #define JSON_HEDLEY_NULL NULL
+#else
+    #define JSON_HEDLEY_NULL ((void*) 0)
+#endif
+
+#if defined(JSON_HEDLEY_MESSAGE)
+    #undef JSON_HEDLEY_MESSAGE
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+#  define JSON_HEDLEY_MESSAGE(msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
+    JSON_HEDLEY_PRAGMA(message msg) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#elif \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)
+#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#else
+#  define JSON_HEDLEY_MESSAGE(msg)
+#endif
+
+#if defined(JSON_HEDLEY_WARNING)
+    #undef JSON_HEDLEY_WARNING
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+#  define JSON_HEDLEY_WARNING(msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
+    JSON_HEDLEY_PRAGMA(clang warning msg) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#elif \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \
+  JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#else
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)
+#endif
+
+#if defined(JSON_HEDLEY_REQUIRE)
+    #undef JSON_HEDLEY_REQUIRE
+#endif
+#if defined(JSON_HEDLEY_REQUIRE_MSG)
+    #undef JSON_HEDLEY_REQUIRE_MSG
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)
+#  if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat")
+#    define JSON_HEDLEY_REQUIRE(expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
+    __attribute__((diagnose_if(!(expr), #expr, "error"))) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
+    __attribute__((diagnose_if(!(expr), msg, "error"))) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  else
+#    define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error")))
+#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error")))
+#  endif
+#else
+#  define JSON_HEDLEY_REQUIRE(expr)
+#  define JSON_HEDLEY_REQUIRE_MSG(expr,msg)
+#endif
+
+#if defined(JSON_HEDLEY_FLAGS)
+    #undef JSON_HEDLEY_FLAGS
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion"))
+    #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))
+#else
+    #define JSON_HEDLEY_FLAGS
+#endif
+
+#if defined(JSON_HEDLEY_FLAGS_CAST)
+    #undef JSON_HEDLEY_FLAGS_CAST
+#endif
+#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)
+#  define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \
+        JSON_HEDLEY_DIAGNOSTIC_PUSH \
+        _Pragma("warning(disable:188)") \
+        ((T) (expr)); \
+        JSON_HEDLEY_DIAGNOSTIC_POP \
+    }))
+#else
+#  define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)
+#endif
+
+#if defined(JSON_HEDLEY_EMPTY_BASES)
+    #undef JSON_HEDLEY_EMPTY_BASES
+#endif
+#if \
+    (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)
+#else
+    #define JSON_HEDLEY_EMPTY_BASES
+#endif
+
+/* Remaining macros are deprecated. */
+
+#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)
+    #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
+#endif
+#if defined(__clang__)
+    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)
+#else
+    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)
+    #undef JSON_HEDLEY_CLANG_HAS_BUILTIN
+#endif
+#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)
+    #undef JSON_HEDLEY_CLANG_HAS_FEATURE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)
+    #undef JSON_HEDLEY_CLANG_HAS_EXTENSION
+#endif
+#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)
+    #undef JSON_HEDLEY_CLANG_HAS_WARNING
+#endif
+#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)
+
+#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */
+
+
+// This file contains all internal macro definitions (except those affecting ABI)
+// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
+
+// #include 
+
+
+// exclude unsupported compilers
+#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
+    #if defined(__clang__)
+        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
+            #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
+        #endif
+    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
+        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
+            #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
+        #endif
+    #endif
+#endif
+
+// C++ language standard detection
+// if the user manually specified the used c++ version this is skipped
+#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
+    #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
+        #define JSON_HAS_CPP_20
+        #define JSON_HAS_CPP_17
+        #define JSON_HAS_CPP_14
+    #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
+        #define JSON_HAS_CPP_17
+        #define JSON_HAS_CPP_14
+    #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
+        #define JSON_HAS_CPP_14
+    #endif
+    // the cpp 11 flag is always specified because it is the minimal required version
+    #define JSON_HAS_CPP_11
+#endif
+
+#ifdef __has_include
+    #if __has_include()
+        #include 
+    #endif
+#endif
+
+#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
+    #ifdef JSON_HAS_CPP_17
+        #if defined(__cpp_lib_filesystem)
+            #define JSON_HAS_FILESYSTEM 1
+        #elif defined(__cpp_lib_experimental_filesystem)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #elif !defined(__has_include)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #elif __has_include()
+            #define JSON_HAS_FILESYSTEM 1
+        #elif __has_include()
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #endif
+
+        // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/
+        #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(__clang_major__) && __clang_major__ < 7
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(_MSC_VER) && _MSC_VER < 1914
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before iOS 13
+        #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before macOS Catalina
+        #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+    #endif
+#endif
+
+#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+    #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
+#endif
+
+#ifndef JSON_HAS_FILESYSTEM
+    #define JSON_HAS_FILESYSTEM 0
+#endif
+
+#ifndef JSON_HAS_THREE_WAY_COMPARISON
+    #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
+        && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
+        #define JSON_HAS_THREE_WAY_COMPARISON 1
+    #else
+        #define JSON_HAS_THREE_WAY_COMPARISON 0
+    #endif
+#endif
+
+#ifndef JSON_HAS_RANGES
+    // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error
+    #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427
+        #define JSON_HAS_RANGES 0
+    #elif defined(__cpp_lib_ranges)
+        #define JSON_HAS_RANGES 1
+    #else
+        #define JSON_HAS_RANGES 0
+    #endif
+#endif
+
+#ifndef JSON_HAS_STATIC_RTTI
+    #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0
+        #define JSON_HAS_STATIC_RTTI 1
+    #else
+        #define JSON_HAS_STATIC_RTTI 0
+    #endif
+#endif
+
+#ifdef JSON_HAS_CPP_17
+    #define JSON_INLINE_VARIABLE inline
+#else
+    #define JSON_INLINE_VARIABLE
+#endif
+
+#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
+    #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
+#else
+    #define JSON_NO_UNIQUE_ADDRESS
+#endif
+
+// disable documentation warnings on clang
+#if defined(__clang__)
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wdocumentation"
+    #pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
+#endif
+
+// allow disabling exceptions
+#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
+    #define JSON_THROW(exception) throw exception
+    #define JSON_TRY try
+    #define JSON_CATCH(exception) catch(exception)
+    #define JSON_INTERNAL_CATCH(exception) catch(exception)
+#else
+    #include 
+    #define JSON_THROW(exception) std::abort()
+    #define JSON_TRY if(true)
+    #define JSON_CATCH(exception) if(false)
+    #define JSON_INTERNAL_CATCH(exception) if(false)
+#endif
+
+// override exception macros
+#if defined(JSON_THROW_USER)
+    #undef JSON_THROW
+    #define JSON_THROW JSON_THROW_USER
+#endif
+#if defined(JSON_TRY_USER)
+    #undef JSON_TRY
+    #define JSON_TRY JSON_TRY_USER
+#endif
+#if defined(JSON_CATCH_USER)
+    #undef JSON_CATCH
+    #define JSON_CATCH JSON_CATCH_USER
+    #undef JSON_INTERNAL_CATCH
+    #define JSON_INTERNAL_CATCH JSON_CATCH_USER
+#endif
+#if defined(JSON_INTERNAL_CATCH_USER)
+    #undef JSON_INTERNAL_CATCH
+    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
+#endif
+
+// allow overriding assert
+#if !defined(JSON_ASSERT)
+    #include  // assert
+    #define JSON_ASSERT(x) assert(x)
+#endif
+
+// allow to access some private functions (needed by the test suite)
+#if defined(JSON_TESTS_PRIVATE)
+    #define JSON_PRIVATE_UNLESS_TESTED public
+#else
+    #define JSON_PRIVATE_UNLESS_TESTED private
+#endif
+
+/*!
+@brief macro to briefly define a mapping between an enum and JSON
+@def NLOHMANN_JSON_SERIALIZE_ENUM
+@since version 3.4.0
+*/
+#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                            \
+    template                                                            \
+    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                   \
+    {                                                                                           \
+        static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!");          \
+        static const std::pair m[] = __VA_ARGS__;                     \
+        auto it = std::find_if(std::begin(m), std::end(m),                                      \
+                               [e](const std::pair& ej_pair) -> bool  \
+        {                                                                                       \
+            return ej_pair.first == e;                                                          \
+        });                                                                                     \
+        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                 \
+    }                                                                                           \
+    template                                                            \
+    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                 \
+    {                                                                                           \
+        static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!");          \
+        static const std::pair m[] = __VA_ARGS__;                     \
+        auto it = std::find_if(std::begin(m), std::end(m),                                      \
+                               [&j](const std::pair& ej_pair) -> bool \
+        {                                                                                       \
+            return ej_pair.second == j;                                                         \
+        });                                                                                     \
+        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                  \
+    }
+
+// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
+// may be removed in the future once the class is split.
+
+#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \
+    template class ObjectType,   \
+             template class ArrayType,              \
+             class StringType, class BooleanType, class NumberIntegerType, \
+             class NumberUnsignedType, class NumberFloatType,              \
+             template class AllocatorType,                       \
+             template class JSONSerializer,     \
+             class BinaryType,                                             \
+             class CustomBaseClass>
+
+#define NLOHMANN_BASIC_JSON_TPL                                            \
+    basic_json
+
+// Macros to simplify conversion from/to types
+
+#define NLOHMANN_JSON_EXPAND( x ) x
+#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
+#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
+        NLOHMANN_JSON_PASTE64, \
+        NLOHMANN_JSON_PASTE63, \
+        NLOHMANN_JSON_PASTE62, \
+        NLOHMANN_JSON_PASTE61, \
+        NLOHMANN_JSON_PASTE60, \
+        NLOHMANN_JSON_PASTE59, \
+        NLOHMANN_JSON_PASTE58, \
+        NLOHMANN_JSON_PASTE57, \
+        NLOHMANN_JSON_PASTE56, \
+        NLOHMANN_JSON_PASTE55, \
+        NLOHMANN_JSON_PASTE54, \
+        NLOHMANN_JSON_PASTE53, \
+        NLOHMANN_JSON_PASTE52, \
+        NLOHMANN_JSON_PASTE51, \
+        NLOHMANN_JSON_PASTE50, \
+        NLOHMANN_JSON_PASTE49, \
+        NLOHMANN_JSON_PASTE48, \
+        NLOHMANN_JSON_PASTE47, \
+        NLOHMANN_JSON_PASTE46, \
+        NLOHMANN_JSON_PASTE45, \
+        NLOHMANN_JSON_PASTE44, \
+        NLOHMANN_JSON_PASTE43, \
+        NLOHMANN_JSON_PASTE42, \
+        NLOHMANN_JSON_PASTE41, \
+        NLOHMANN_JSON_PASTE40, \
+        NLOHMANN_JSON_PASTE39, \
+        NLOHMANN_JSON_PASTE38, \
+        NLOHMANN_JSON_PASTE37, \
+        NLOHMANN_JSON_PASTE36, \
+        NLOHMANN_JSON_PASTE35, \
+        NLOHMANN_JSON_PASTE34, \
+        NLOHMANN_JSON_PASTE33, \
+        NLOHMANN_JSON_PASTE32, \
+        NLOHMANN_JSON_PASTE31, \
+        NLOHMANN_JSON_PASTE30, \
+        NLOHMANN_JSON_PASTE29, \
+        NLOHMANN_JSON_PASTE28, \
+        NLOHMANN_JSON_PASTE27, \
+        NLOHMANN_JSON_PASTE26, \
+        NLOHMANN_JSON_PASTE25, \
+        NLOHMANN_JSON_PASTE24, \
+        NLOHMANN_JSON_PASTE23, \
+        NLOHMANN_JSON_PASTE22, \
+        NLOHMANN_JSON_PASTE21, \
+        NLOHMANN_JSON_PASTE20, \
+        NLOHMANN_JSON_PASTE19, \
+        NLOHMANN_JSON_PASTE18, \
+        NLOHMANN_JSON_PASTE17, \
+        NLOHMANN_JSON_PASTE16, \
+        NLOHMANN_JSON_PASTE15, \
+        NLOHMANN_JSON_PASTE14, \
+        NLOHMANN_JSON_PASTE13, \
+        NLOHMANN_JSON_PASTE12, \
+        NLOHMANN_JSON_PASTE11, \
+        NLOHMANN_JSON_PASTE10, \
+        NLOHMANN_JSON_PASTE9, \
+        NLOHMANN_JSON_PASTE8, \
+        NLOHMANN_JSON_PASTE7, \
+        NLOHMANN_JSON_PASTE6, \
+        NLOHMANN_JSON_PASTE5, \
+        NLOHMANN_JSON_PASTE4, \
+        NLOHMANN_JSON_PASTE3, \
+        NLOHMANN_JSON_PASTE2, \
+        NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
+#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
+#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
+#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
+#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
+#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
+#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
+#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
+#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
+#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
+#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
+#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
+#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
+#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
+#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
+#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
+#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
+#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
+#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
+#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
+#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
+#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
+#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
+#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
+#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
+#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
+#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
+#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
+#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
+#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
+#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
+#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
+#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
+#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
+#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
+#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
+#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
+#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
+#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
+#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
+#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
+#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
+#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
+#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
+#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
+#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
+#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
+#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
+#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
+#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
+#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
+#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
+#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
+#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
+#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
+#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
+#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
+#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
+#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
+#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
+#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
+#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
+#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
+#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
+
+#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;
+#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
+#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1);
+
+/*!
+@brief macro
+@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
+@since version 3.9.0
+*/
+#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \
+    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
+
+#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
+    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+
+#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...)  \
+    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
+
+/*!
+@brief macro
+@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
+@since version 3.9.0
+*/
+#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \
+    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
+
+#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...)  \
+    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
+
+#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
+    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+
+// inspired from https://stackoverflow.com/a/26745591
+// allows to call any std function as if (e.g. with begin):
+// using std::begin; begin(x);
+//
+// it allows using the detected idiom to retrieve the return type
+// of such an expression
+#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name)                                 \
+    namespace detail {                                                            \
+    using std::std_name;                                                          \
+    \
+    template                                                       \
+    using result_of_##std_name = decltype(std_name(std::declval()...));        \
+    }                                                                             \
+    \
+    namespace detail2 {                                                           \
+    struct std_name##_tag                                                         \
+    {                                                                             \
+    };                                                                            \
+    \
+    template                                                       \
+    std_name##_tag std_name(T&&...);                                              \
+    \
+    template                                                       \
+    using result_of_##std_name = decltype(std_name(std::declval()...));        \
+    \
+    template                                                       \
+    struct would_call_std_##std_name                                              \
+    {                                                                             \
+        static constexpr auto const value = ::nlohmann::detail::                  \
+                                            is_detected_exact::value; \
+    };                                                                            \
+    } /* namespace detail2 */ \
+    \
+    template                                                       \
+    struct would_call_std_##std_name : detail2::would_call_std_##std_name   \
+    {                                                                             \
+    }
+
+#ifndef JSON_USE_IMPLICIT_CONVERSIONS
+    #define JSON_USE_IMPLICIT_CONVERSIONS 1
+#endif
+
+#if JSON_USE_IMPLICIT_CONVERSIONS
+    #define JSON_EXPLICIT
+#else
+    #define JSON_EXPLICIT explicit
+#endif
+
+#ifndef JSON_DISABLE_ENUM_SERIALIZATION
+    #define JSON_DISABLE_ENUM_SERIALIZATION 0
+#endif
+
+#ifndef JSON_USE_GLOBAL_UDLS
+    #define JSON_USE_GLOBAL_UDLS 1
+#endif
+
+#if JSON_HAS_THREE_WAY_COMPARISON
+    #include  // partial_ordering
+#endif
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////////////////////
+// JSON type enumeration //
+///////////////////////////
+
+/*!
+@brief the JSON type enumeration
+
+This enumeration collects the different JSON types. It is internally used to
+distinguish the stored values, and the functions @ref basic_json::is_null(),
+@ref basic_json::is_object(), @ref basic_json::is_array(),
+@ref basic_json::is_string(), @ref basic_json::is_boolean(),
+@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
+@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
+@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
+@ref basic_json::is_structured() rely on it.
+
+@note There are three enumeration entries (number_integer, number_unsigned, and
+number_float), because the library distinguishes these three types for numbers:
+@ref basic_json::number_unsigned_t is used for unsigned integers,
+@ref basic_json::number_integer_t is used for signed integers, and
+@ref basic_json::number_float_t is used for floating-point numbers or to
+approximate integers which do not fit in the limits of their respective type.
+
+@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON
+value with the default value for a given type
+
+@since version 1.0.0
+*/
+enum class value_t : std::uint8_t
+{
+    null,             ///< null value
+    object,           ///< object (unordered set of name/value pairs)
+    array,            ///< array (ordered collection of values)
+    string,           ///< string value
+    boolean,          ///< boolean value
+    number_integer,   ///< number value (signed integer)
+    number_unsigned,  ///< number value (unsigned integer)
+    number_float,     ///< number value (floating-point)
+    binary,           ///< binary array (ordered collection of bytes)
+    discarded         ///< discarded by the parser callback function
+};
+
+/*!
+@brief comparison operator for JSON types
+
+Returns an ordering that is similar to Python:
+- order: null < boolean < number < object < array < string < binary
+- furthermore, each type is not smaller than itself
+- discarded values are not comparable
+- binary is represented as a b"" string in python and directly comparable to a
+  string; however, making a binary array directly comparable with a string would
+  be surprising behavior in a JSON file.
+
+@since version 1.0.0
+*/
+#if JSON_HAS_THREE_WAY_COMPARISON
+    inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*
+#else
+    inline bool operator<(const value_t lhs, const value_t rhs) noexcept
+#endif
+{
+    static constexpr std::array order = {{
+            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
+            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,
+            6 /* binary */
+        }
+    };
+
+    const auto l_index = static_cast(lhs);
+    const auto r_index = static_cast(rhs);
+#if JSON_HAS_THREE_WAY_COMPARISON
+    if (l_index < order.size() && r_index < order.size())
+    {
+        return order[l_index] <=> order[r_index]; // *NOPAD*
+    }
+    return std::partial_ordering::unordered;
+#else
+    return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
+#endif
+}
+
+// GCC selects the built-in operator< over an operator rewritten from
+// a user-defined spaceship operator
+// Clang, MSVC, and ICC select the rewritten candidate
+// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
+#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
+inline bool operator<(const value_t lhs, const value_t rhs) noexcept
+{
+    return std::is_lt(lhs <=> rhs); // *NOPAD*
+}
+#endif
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+// #include 
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief replace all occurrences of a substring by another string
+
+@param[in,out] s  the string to manipulate; changed so that all
+               occurrences of @a f are replaced with @a t
+@param[in]     f  the substring to replace with @a t
+@param[in]     t  the string to replace @a f
+
+@pre The search string @a f must not be empty. **This precondition is
+enforced with an assertion.**
+
+@since version 2.0.0
+*/
+template
+inline void replace_substring(StringType& s, const StringType& f,
+                              const StringType& t)
+{
+    JSON_ASSERT(!f.empty());
+    for (auto pos = s.find(f);                // find first occurrence of f
+            pos != StringType::npos;          // make sure f was found
+            s.replace(pos, f.size(), t),      // replace with t, and
+            pos = s.find(f, pos + t.size()))  // find next occurrence of f
+    {}
+}
+
+/*!
+ * @brief string escaping as described in RFC 6901 (Sect. 4)
+ * @param[in] s string to escape
+ * @return    escaped string
+ *
+ * Note the order of escaping "~" to "~0" and "/" to "~1" is important.
+ */
+template
+inline StringType escape(StringType s)
+{
+    replace_substring(s, StringType{"~"}, StringType{"~0"});
+    replace_substring(s, StringType{"/"}, StringType{"~1"});
+    return s;
+}
+
+/*!
+ * @brief string unescaping as described in RFC 6901 (Sect. 4)
+ * @param[in] s string to unescape
+ * @return    unescaped string
+ *
+ * Note the order of escaping "~1" to "/" and "~0" to "~" is important.
+ */
+template
+static void unescape(StringType& s)
+{
+    replace_substring(s, StringType{"~1"}, StringType{"/"});
+    replace_substring(s, StringType{"~0"}, StringType{"~"});
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // size_t
+
+// #include 
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// struct to capture the start position of the current token
+struct position_t
+{
+    /// the total number of characters read
+    std::size_t chars_read_total = 0;
+    /// the number of characters read in the current line
+    std::size_t chars_read_current_line = 0;
+    /// the number of lines read
+    std::size_t lines_read = 0;
+
+    /// conversion to size_t to preserve SAX interface
+    constexpr operator size_t() const
+    {
+        return chars_read_total;
+    }
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-FileCopyrightText: 2018 The Abseil Authors
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // array
+#include  // size_t
+#include  // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
+#include  // index_sequence, make_index_sequence, index_sequence_for
+
+// #include 
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template
+using uncvref_t = typename std::remove_cv::type>::type;
+
+#ifdef JSON_HAS_CPP_14
+
+// the following utilities are natively available in C++14
+using std::enable_if_t;
+using std::index_sequence;
+using std::make_index_sequence;
+using std::index_sequence_for;
+
+#else
+
+// alias templates to reduce boilerplate
+template
+using enable_if_t = typename std::enable_if::type;
+
+// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h
+// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.
+
+//// START OF CODE FROM GOOGLE ABSEIL
+
+// integer_sequence
+//
+// Class template representing a compile-time integer sequence. An instantiation
+// of `integer_sequence` has a sequence of integers encoded in its
+// type through its template arguments (which is a common need when
+// working with C++11 variadic templates). `absl::integer_sequence` is designed
+// to be a drop-in replacement for C++14's `std::integer_sequence`.
+//
+// Example:
+//
+//   template< class T, T... Ints >
+//   void user_function(integer_sequence);
+//
+//   int main()
+//   {
+//     // user_function's `T` will be deduced to `int` and `Ints...`
+//     // will be deduced to `0, 1, 2, 3, 4`.
+//     user_function(make_integer_sequence());
+//   }
+template 
+struct integer_sequence
+{
+    using value_type = T;
+    static constexpr std::size_t size() noexcept
+    {
+        return sizeof...(Ints);
+    }
+};
+
+// index_sequence
+//
+// A helper template for an `integer_sequence` of `size_t`,
+// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
+// `std::index_sequence`.
+template 
+using index_sequence = integer_sequence;
+
+namespace utility_internal
+{
+
+template 
+struct Extend;
+
+// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
+template 
+struct Extend, SeqSize, 0>
+{
+    using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;
+};
+
+template 
+struct Extend, SeqSize, 1>
+{
+    using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;
+};
+
+// Recursion helper for 'make_integer_sequence'.
+// 'Gen::type' is an alias for 'integer_sequence'.
+template 
+struct Gen
+{
+    using type =
+        typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;
+};
+
+template 
+struct Gen
+{
+    using type = integer_sequence;
+};
+
+}  // namespace utility_internal
+
+// Compile-time sequences of integers
+
+// make_integer_sequence
+//
+// This template alias is equivalent to
+// `integer_sequence`, and is designed to be a drop-in
+// replacement for C++14's `std::make_integer_sequence`.
+template 
+using make_integer_sequence = typename utility_internal::Gen::type;
+
+// make_index_sequence
+//
+// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
+// and is designed to be a drop-in replacement for C++14's
+// `std::make_index_sequence`.
+template 
+using make_index_sequence = make_integer_sequence;
+
+// index_sequence_for
+//
+// Converts a typename pack into an index sequence of the same length, and
+// is designed to be a drop-in replacement for C++14's
+// `std::index_sequence_for()`
+template 
+using index_sequence_for = make_index_sequence;
+
+//// END OF CODE FROM GOOGLE ABSEIL
+
+#endif
+
+// dispatch utility (taken from ranges-v3)
+template struct priority_tag : priority_tag < N - 1 > {};
+template<> struct priority_tag<0> {};
+
+// taken from ranges-v3
+template
+struct static_const
+{
+    static JSON_INLINE_VARIABLE constexpr T value{};
+};
+
+#ifndef JSON_HAS_CPP_17
+    template
+    constexpr T static_const::value;
+#endif
+
+template
+inline constexpr std::array make_array(Args&& ... args)
+{
+    return std::array {{static_cast(std::forward(args))...}};
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // numeric_limits
+#include  // false_type, is_constructible, is_integral, is_same, true_type
+#include  // declval
+#include  // tuple
+#include  // char_traits
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+#include  // random_access_iterator_tag
+
+// #include 
+
+// #include 
+
+// #include 
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template
+struct iterator_types {};
+
+template
+struct iterator_types <
+    It,
+    void_t>
+{
+    using difference_type = typename It::difference_type;
+    using value_type = typename It::value_type;
+    using pointer = typename It::pointer;
+    using reference = typename It::reference;
+    using iterator_category = typename It::iterator_category;
+};
+
+// This is required as some compilers implement std::iterator_traits in a way that
+// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
+template
+struct iterator_traits
+{
+};
+
+template
+struct iterator_traits < T, enable_if_t < !std::is_pointer::value >>
+            : iterator_types
+{
+};
+
+template
+struct iterator_traits::value>>
+{
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = T;
+    using difference_type = ptrdiff_t;
+    using pointer = T*;
+    using reference = T&;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+// #include 
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+
+
+// #include 
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include 
+
+// #include 
+
+// #include 
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann 
+// SPDX-License-Identifier: MIT
+
+#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
+    #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
+
+    #include  // int64_t, uint64_t
+    #include  // map
+    #include  // allocator
+    #include  // string
+    #include  // vector
+
+    // #include 
+
+
+    /*!
+    @brief namespace for Niels Lohmann
+    @see https://github.com/nlohmann
+    @since version 1.0.0
+    */
+    NLOHMANN_JSON_NAMESPACE_BEGIN
+
+    /*!
+    @brief default JSONSerializer template argument
+
+    This serializer ignores the template arguments and uses ADL
+    ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
+    for serialization.
+    */
+    template
+    struct adl_serializer;
+
+    /// a class to store JSON values
+    /// @sa https://json.nlohmann.me/api/basic_json/
+    template class ObjectType =
+    std::map,
+    template class ArrayType = std::vector,
+    class StringType = std::string, class BooleanType = bool,
+    class NumberIntegerType = std::int64_t,
+    class NumberUnsignedType = std::uint64_t,
+    class NumberFloatType = double,
+    template class AllocatorType = std::allocator,
+    template class JSONSerializer =
+    adl_serializer,
+    class BinaryType = std::vector, // cppcheck-suppress syntaxError
+    class CustomBaseClass = void>
+    class basic_json;
+
+    /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
+    /// @sa https://json.nlohmann.me/api/json_pointer/
+    template
+    class json_pointer;
+
+    /*!
+    @brief default specialization
+    @sa https://json.nlohmann.me/api/json/
+    */
+    using json = basic_json<>;
+
+    /// @brief a minimal map-like container that preserves insertion order
+    /// @sa https://json.nlohmann.me/api/ordered_map/
+    template
+    struct ordered_map;
+
+    /// @brief specialization that maintains the insertion order of object keys
+    /// @sa https://json.nlohmann.me/api/ordered_json/
+    using ordered_json = basic_json;
+
+    NLOHMANN_JSON_NAMESPACE_END
+
+#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+/*!
+@brief detail namespace with internal helper functions
+
+This namespace collects functions that should not be exposed,
+implementations of some @ref basic_json methods, and meta-programming helpers.
+
+@since version 2.1.0
+*/
+namespace detail
+{
+
+/////////////
+// helpers //
+/////////////
+
+// Note to maintainers:
+//
+// Every trait in this file expects a non CV-qualified type.
+// The only exceptions are in the 'aliases for detected' section
+// (i.e. those of the form: decltype(T::member_function(std::declval())))
+//
+// In this case, T has to be properly CV-qualified to constraint the function arguments
+// (e.g. to_json(BasicJsonType&, const T&))
+
+template struct is_basic_json : std::false_type {};
+
+NLOHMANN_BASIC_JSON_TPL_DECLARATION
+struct is_basic_json : std::true_type {};
+
+// used by exceptions create() member functions
+// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
+// false_type otherwise
+template
+struct is_basic_json_context :
+    std::integral_constant < bool,
+    is_basic_json::type>::type>::value
+    || std::is_same::value >
+{};
+
+//////////////////////
+// json_ref helpers //
+//////////////////////
+
+template
+class json_ref;
+
+template
+struct is_json_ref : std::false_type {};
+
+template
+struct is_json_ref> : std::true_type {};
+
+//////////////////////////
+// aliases for detected //
+//////////////////////////
+
+template
+using mapped_type_t = typename T::mapped_type;
+
+template
+using key_type_t = typename T::key_type;
+
+template
+using value_type_t = typename T::value_type;
+
+template
+using difference_type_t = typename T::difference_type;
+
+template
+using pointer_t = typename T::pointer;
+
+template
+using reference_t = typename T::reference;
+
+template
+using iterator_category_t = typename T::iterator_category;
+
+template
+using to_json_function = decltype(T::to_json(std::declval()...));
+
+template
+using from_json_function = decltype(T::from_json(std::declval()...));
+
+template
+using get_template_function = decltype(std::declval().template get());
+
+// trait checking if JSONSerializer::from_json(json const&, udt&) exists
+template
+struct has_from_json : std::false_type {};
+
+// trait checking if j.get is valid
+// use this trait instead of std::is_constructible or std::is_convertible,
+// both rely on, or make use of implicit conversions, and thus fail when T
+// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
+template 
+struct is_getable
+{
+    static constexpr bool value = is_detected::value;
+};
+
+template
+struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer;
+
+    static constexpr bool value =
+        is_detected_exact::value;
+};
+
+// This trait checks if JSONSerializer::from_json(json const&) exists
+// this overload is used for non-default-constructible user-defined-types
+template
+struct has_non_default_from_json : std::false_type {};
+
+template
+struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer;
+
+    static constexpr bool value =
+        is_detected_exact::value;
+};
+
+// This trait checks if BasicJsonType::json_serializer::to_json exists
+// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
+template
+struct has_to_json : std::false_type {};
+
+template
+struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer;
+
+    static constexpr bool value =
+        is_detected_exact::value;
+};
+
+template
+using detect_key_compare = typename T::key_compare;
+
+template
+struct has_key_compare : std::integral_constant::value> {};
+
+// obtains the actual object key comparator
+template
+struct actual_object_comparator
+{
+    using object_t = typename BasicJsonType::object_t;
+    using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
+    using type = typename std::conditional < has_key_compare::value,
+          typename object_t::key_compare, object_comparator_t>::type;
+};
+
+template
+using actual_object_comparator_t = typename actual_object_comparator::type;
+
+/////////////////
+// char_traits //
+/////////////////
+
+// Primary template of char_traits calls std char_traits
+template
+struct char_traits : std::char_traits
+{};
+
+// Explicitly define char traits for unsigned char since it is not standard
+template<>
+struct char_traits : std::char_traits
+{
+    using char_type = unsigned char;
+    using int_type = uint64_t;
+
+    // Redefine to_int_type function
+    static int_type to_int_type(char_type c) noexcept
+    {
+        return static_cast(c);
+    }
+
+    static char_type to_char_type(int_type i) noexcept
+    {
+        return static_cast(i);
+    }
+
+    static constexpr int_type eof() noexcept
+    {
+        return static_cast(EOF);
+    }
+};
+
+// Explicitly define char traits for signed char since it is not standard
+template<>
+struct char_traits : std::char_traits
+{
+    using char_type = signed char;
+    using int_type = uint64_t;
+
+    // Redefine to_int_type function
+    static int_type to_int_type(char_type c) noexcept
+    {
+        return static_cast(c);
+    }
+
+    static char_type to_char_type(int_type i) noexcept
+    {
+        return static_cast(i);
+    }
+
+    static constexpr int_type eof() noexcept
+    {
+        return static_cast(EOF);
+    }
+};
+
+///////////////////
+// is_ functions //
+///////////////////
+
+// https://en.cppreference.com/w/cpp/types/conjunction
+template struct conjunction : std::true_type { };
+template struct conjunction : B { };
+template
+struct conjunction
+: std::conditional(B::value), conjunction, B>::type {};
+
+// https://en.cppreference.com/w/cpp/types/negation
+template struct negation : std::integral_constant < bool, !B::value > { };
+
+// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
+// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
+// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
+template 
+struct is_default_constructible : std::is_default_constructible {};
+
+template 
+struct is_default_constructible>
+            : conjunction, is_default_constructible> {};
+
+template 
+struct is_default_constructible>
+            : conjunction, is_default_constructible> {};
+
+template 
+struct is_default_constructible>
+            : conjunction...> {};
+
+template 
+struct is_default_constructible>
+            : conjunction...> {};
+
+template 
+struct is_constructible : std::is_constructible {};
+
+template 
+struct is_constructible> : is_default_constructible> {};
+
+template 
+struct is_constructible> : is_default_constructible> {};
+
+template 
+struct is_constructible> : is_default_constructible> {};
+
+template 
+struct is_constructible> : is_default_constructible> {};
+
+template
+struct is_iterator_traits : std::false_type {};
+
+template
+struct is_iterator_traits>
+{
+  private:
+    using traits = iterator_traits;
+
+  public:
+    static constexpr auto value =
+        is_detected::value &&
+        is_detected::value &&
+        is_detected::value &&
+        is_detected::value &&
+        is_detected::value;
+};
+
+template
+struct is_range
+{
+  private:
+    using t_ref = typename std::add_lvalue_reference::type;
+
+    using iterator = detected_t;
+    using sentinel = detected_t;
+
+    // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
+    // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
+    // but reimplementing these would be too much work, as a lot of other concepts are used underneath
+    static constexpr auto is_iterator_begin =
+        is_iterator_traits>::value;
+
+  public:
+    static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin;
+};
+
+template
+using iterator_t = enable_if_t::value, result_of_begin())>>;
+
+template
+using range_value_t = value_type_t>>;
+
+// The following implementation of is_complete_type is taken from
+// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
+// and is written by Xiang Fan who agreed to using it in this library.
+
+template
+struct is_complete_type : std::false_type {};
+
+template
+struct is_complete_type : std::true_type {};
+
+template
+struct is_compatible_object_type_impl : std::false_type {};
+
+template
+struct is_compatible_object_type_impl <
+    BasicJsonType, CompatibleObjectType,
+    enable_if_t < is_detected::value&&
+    is_detected::value >>
+{
+    using object_t = typename BasicJsonType::object_t;
+
+    // macOS's is_constructible does not play well with nonesuch...
+    static constexpr bool value =
+        is_constructible::value &&
+        is_constructible::value;
+};
+
+template
+struct is_compatible_object_type
+    : is_compatible_object_type_impl {};
+
+template
+struct is_constructible_object_type_impl : std::false_type {};
+
+template
+struct is_constructible_object_type_impl <
+    BasicJsonType, ConstructibleObjectType,
+    enable_if_t < is_detected::value&&
+    is_detected::value >>
+{
+    using object_t = typename BasicJsonType::object_t;
+
+    static constexpr bool value =
+        (is_default_constructible::value &&
+         (std::is_move_assignable::value ||
+          std::is_copy_assignable::value) &&
+         (is_constructible::value &&
+          std::is_same <
+          typename object_t::mapped_type,
+          typename ConstructibleObjectType::mapped_type >::value)) ||
+        (has_from_json::value ||
+         has_non_default_from_json <
+         BasicJsonType,
+         typename ConstructibleObjectType::mapped_type >::value);
+};
+
+template
+struct is_constructible_object_type
+    : is_constructible_object_type_impl {};
+
+template
+struct is_compatible_string_type
+{
+    static constexpr auto value =
+        is_constructible::value;
+};
+
+template
+struct is_constructible_string_type
+{
+    // launder type through decltype() to fix compilation failure on ICPC
+#ifdef __INTEL_COMPILER
+    using laundered_type = decltype(std::declval());
+#else
+    using laundered_type = ConstructibleStringType;
+#endif
+
+    static constexpr auto value =
+        conjunction <
+        is_constructible,
+        is_detected_exact>::value;
+};
+
+template
+struct is_compatible_array_type_impl : std::false_type {};
+
+template
+struct is_compatible_array_type_impl <
+    BasicJsonType, CompatibleArrayType,
+    enable_if_t <
+    is_detected::value&&
+    is_iterator_traits>>::value&&
+// special case for types like std::filesystem::path whose iterator's value_type are themselves
+// c.f. https://github.com/nlohmann/json/pull/3073
+    !std::is_same>::value >>
+{
+    static constexpr bool value =
+        is_constructible>::value;
+};
+
+template
+struct is_compatible_array_type
+    : is_compatible_array_type_impl {};
+
+template
+struct is_constructible_array_type_impl : std::false_type {};
+
+template
+struct is_constructible_array_type_impl <
+    BasicJsonType, ConstructibleArrayType,
+    enable_if_t::value >>
+            : std::true_type {};
+
+template
+struct is_constructible_array_type_impl <
+    BasicJsonType, ConstructibleArrayType,
+    enable_if_t < !std::is_same::value&&
+    !is_compatible_string_type::value&&
+    is_default_constructible::value&&
+(std::is_move_assignable::value ||
+ std::is_copy_assignable::value)&&
+is_detected::value&&
+is_iterator_traits>>::value&&
+is_detected::value&&
+// special case for types like std::filesystem::path whose iterator's value_type are themselves
+// c.f. https://github.com/nlohmann/json/pull/3073
+!std::is_same>::value&&
+        is_complete_type <
+        detected_t>::value >>
+{
+    using value_type = range_value_t;
+
+    static constexpr bool value =
+        std::is_same::value ||
+        has_from_json::value ||
+        has_non_default_from_json <
+        BasicJsonType,
+        value_type >::value;
+};
+
+template
+struct is_constructible_array_type
+    : is_constructible_array_type_impl {};
+
+template
+struct is_compatible_integer_type_impl : std::false_type {};
+
+template
+struct is_compatible_integer_type_impl <
+    RealIntegerType, CompatibleNumberIntegerType,
+    enable_if_t < std::is_integral::value&&
+    std::is_integral::value&&
+    !std::is_same::value >>
+{
+    // is there an assert somewhere on overflows?
+    using RealLimits = std::numeric_limits;
+    using CompatibleLimits = std::numeric_limits;
+
+    static constexpr auto value =
+        is_constructible::value &&
+        CompatibleLimits::is_integer &&
+        RealLimits::is_signed == CompatibleLimits::is_signed;
+};
+
+template
+struct is_compatible_integer_type
+    : is_compatible_integer_type_impl {};
+
+template
+struct is_compatible_type_impl: std::false_type {};
+
+template
+struct is_compatible_type_impl <
+    BasicJsonType, CompatibleType,
+    enable_if_t::value >>
+{
+    static constexpr bool value =
+        has_to_json::value;
+};
+
+template
+struct is_compatible_type
+    : is_compatible_type_impl {};
+
+template
+struct is_constructible_tuple : std::false_type {};
+
+template
+struct is_constructible_tuple> : conjunction...> {};
+
+template
+struct is_json_iterator_of : std::false_type {};
+
+template
+struct is_json_iterator_of : std::true_type {};
+
+template
+struct is_json_iterator_of : std::true_type
+{};
+
+// checks if a given type T is a template specialization of Primary
+template