From d23ee1c627b35cc7d872a70599ea5b1baeb44b30 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 14:33:14 +0200 Subject: [PATCH 01/37] Rename consent form --- .../html/{ErrorLoggingConsent.html => AppFeaturesConsent.html} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ManiVault/res/html/{ErrorLoggingConsent.html => AppFeaturesConsent.html} (100%) diff --git a/ManiVault/res/html/ErrorLoggingConsent.html b/ManiVault/res/html/AppFeaturesConsent.html similarity index 100% rename from ManiVault/res/html/ErrorLoggingConsent.html rename to ManiVault/res/html/AppFeaturesConsent.html From 3ac2523aa97a3ce872e3493fef8d97398d5923f5 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 14:37:00 +0200 Subject: [PATCH 02/37] Rename error logging consent dialog --- ...ErrorLoggingConsentDialog.cpp => AppFeaturesConsentDialog.cpp} | 0 .../{ErrorLoggingConsentDialog.h => AppFeaturesConsentDialog.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename ManiVault/src/private/{ErrorLoggingConsentDialog.cpp => AppFeaturesConsentDialog.cpp} (100%) rename ManiVault/src/private/{ErrorLoggingConsentDialog.h => AppFeaturesConsentDialog.h} (100%) diff --git a/ManiVault/src/private/ErrorLoggingConsentDialog.cpp b/ManiVault/src/private/AppFeaturesConsentDialog.cpp similarity index 100% rename from ManiVault/src/private/ErrorLoggingConsentDialog.cpp rename to ManiVault/src/private/AppFeaturesConsentDialog.cpp diff --git a/ManiVault/src/private/ErrorLoggingConsentDialog.h b/ManiVault/src/private/AppFeaturesConsentDialog.h similarity index 100% rename from ManiVault/src/private/ErrorLoggingConsentDialog.h rename to ManiVault/src/private/AppFeaturesConsentDialog.h From 8c748af14d90240a0c2fa070b8de7fd2a8a240b7 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 14:43:38 +0200 Subject: [PATCH 03/37] Rename app features consent dialog and modify cmake --- ManiVault/cmake/CMakeMvSourcesApplication.cmake | 15 +++++++++++++-- ...resConsentDialog.cpp => AppFeaturesDialog.cpp} | 0 ...eaturesConsentDialog.h => AppFeaturesDialog.h} | 0 3 files changed, 13 insertions(+), 2 deletions(-) rename ManiVault/src/private/{AppFeaturesConsentDialog.cpp => AppFeaturesDialog.cpp} (100%) rename ManiVault/src/private/{AppFeaturesConsentDialog.h => AppFeaturesDialog.h} (100%) diff --git a/ManiVault/cmake/CMakeMvSourcesApplication.cmake b/ManiVault/cmake/CMakeMvSourcesApplication.cmake index e79db012f..d19095b9d 100644 --- a/ManiVault/cmake/CMakeMvSourcesApplication.cmake +++ b/ManiVault/cmake/CMakeMvSourcesApplication.cmake @@ -288,7 +288,6 @@ if(MV_USE_ERROR_LOGGING) list(APPEND PRIVATE_APPLICATION_HEADERS src/private/SentryErrorLogger.h src/private/CrashReportDialog.h - src/private/ErrorLoggingConsentDialog.h ) endif() @@ -307,7 +306,6 @@ if(MV_USE_ERROR_LOGGING) list(APPEND PRIVATE_APPLICATION_SOURCES src/private/SentryErrorLogger.cpp src/private/CrashReportDialog.cpp - src/private/ErrorLoggingConsentDialog.cpp ) endif() @@ -316,6 +314,19 @@ set(PRIVATE_APPLICATION_FILES ${PRIVATE_APPLICATION_SOURCES} ) +set(PRIVATE_APP_FEATURES_HEADERS + src/private/AppFeaturesDialog.h +) + +set(PRIVATE_APP_FEATURES_SOURCES + src/private/AppFeaturesDialog.cpp +) + +set(PRIVATE_APP_FEATURES_FILES + ${PRIVATE_APP_FEATURES_HEADERS} + ${PRIVATE_APP_FEATURES_SOURCES} +) + set(PRIVATE_STARTUP_PROJECT_HEADERS src/private/StartupProjectsModel.h src/private/StartupProjectsFilterModel.h diff --git a/ManiVault/src/private/AppFeaturesConsentDialog.cpp b/ManiVault/src/private/AppFeaturesDialog.cpp similarity index 100% rename from ManiVault/src/private/AppFeaturesConsentDialog.cpp rename to ManiVault/src/private/AppFeaturesDialog.cpp diff --git a/ManiVault/src/private/AppFeaturesConsentDialog.h b/ManiVault/src/private/AppFeaturesDialog.h similarity index 100% rename from ManiVault/src/private/AppFeaturesConsentDialog.h rename to ManiVault/src/private/AppFeaturesDialog.h From f73ec0df5af0c777606bff0afc797eca0a0d07d6 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 14:47:07 +0200 Subject: [PATCH 04/37] Rename app features consent dialog --- ManiVault/res/html/AppFeatures.html | 37 ++++++++++++++++++++++ ManiVault/res/html/AppFeaturesConsent.html | 25 --------------- 2 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 ManiVault/res/html/AppFeatures.html delete mode 100644 ManiVault/res/html/AppFeaturesConsent.html diff --git a/ManiVault/res/html/AppFeatures.html b/ManiVault/res/html/AppFeatures.html new file mode 100644 index 000000000..d8d3c3814 --- /dev/null +++ b/ManiVault/res/html/AppFeatures.html @@ -0,0 +1,37 @@ + + + +

Automated error reporting and start page content

+ +

ManiVault Studio can automatically report bugs and crashes using Sentry. This might help us fix issues faster and improve the application for everyone.

+ +

What we collect:

+
    +
  • Details about errors (e.g., crash logs, stack traces).
  • +
  • Basic system information (e.g., operating system, app version).
  • +
  • Contact details (if you opt to supply them).
  • +
+ +

What we don’t collect:

+
    +
  • Personal files like projects or research data.
  • +
  • Sensitive data like passwords.
  • +
+ +

You can opt out of automated error reporting at any time in the application settings.

+ +

Start page content

+ +

ManiVault Studio can optionally download dynamic content for the application's start page. This content includes:

+ +
    +
  • A curated list of tutorials, which can be downloaded and opened directly.
  • +
  • A curated list of projects, which can be downloaded and opened directly.
  • +
+ +

When you enable this feature, the application connects to ManiVault Studio servers to fetch available tutorials and project listings. We do not track which tutorials or projects you view or download.

+ +

If you prefer not to allow automatic downloads of start page content, you can disable this feature in the application settings.

+ + + diff --git a/ManiVault/res/html/AppFeaturesConsent.html b/ManiVault/res/html/AppFeaturesConsent.html deleted file mode 100644 index 2556e2aa4..000000000 --- a/ManiVault/res/html/AppFeaturesConsent.html +++ /dev/null @@ -1,25 +0,0 @@ - - - -

Automated error reporting

-

ManiVault Studio can automatically report bugs and crashes using Sentry. This might helps us fix issues faster and improve the application for everyone.

-

What we collect: -

    -
  • Details about errors (e.g., crash logs, stack traces).
  • -
  • Basic system information (e.g., operating system, app version).
  • -
  • Contact details (if you opt to supply them)
  • -
-

What we don’t collect:

-
    -
  • Personal files like projects or research data.
  • -
  • Sensitive data like passwords.
  • -
- -

Sentry has a privacy policy that outlines how they collect, use, and protect personal information. You can view the full policy here.

- -

You can opt out at any time in the application settings.

- -

We also support self-hosted Sentry servers. Simply modify the error logging DSN in the application settings to point to your own self-hosted Sentry server to mitigate possible privacy concerns.

- - - \ No newline at end of file From 0c5a16781357f5cc30e1f87789aca7a32e07e5d8 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 14:57:42 +0200 Subject: [PATCH 05/37] Add app features dialog to dedicated source gorup and remove unnecessary include --- ManiVault/cmake/CMakeMvSourcesApplication.cmake | 3 +++ ManiVault/src/private/AppFeaturesDialog.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ManiVault/cmake/CMakeMvSourcesApplication.cmake b/ManiVault/cmake/CMakeMvSourcesApplication.cmake index d19095b9d..dfe00e21e 100644 --- a/ManiVault/cmake/CMakeMvSourcesApplication.cmake +++ b/ManiVault/cmake/CMakeMvSourcesApplication.cmake @@ -446,6 +446,7 @@ set(PRIVATE_HEADERS ${PRIVATE_MISCELLANEOUS_HEADERS} ${PRIVATE_ACTIONS_HEADERS} ${PRIVATE_STARTUP_PROJECT_HEADERS} + ${PRIVATE_APP_FEATURES_HEADERS} ) set(PRIVATE_SOURCES @@ -458,6 +459,7 @@ set(PRIVATE_SOURCES ${PRIVATE_MISCELLANEOUS_SOURCES} ${PRIVATE_ACTIONS_SOURCES} ${PRIVATE_STARTUP_PROJECT_SOURCES} + ${PRIVATE_APP_FEATURES_SOURCES} ${PRIVATE_HEADERS} ) @@ -467,6 +469,7 @@ list(REMOVE_DUPLICATES PRIVATE_SOURCES) source_group(Core FILES ${PRIVATE_CORE_FILES}) source_group(Actions FILES ${PRIVATE_ACTION_FILES}) source_group(Application FILES ${PRIVATE_APPLICATION_FILES} ${MAIN_SOURCES}) +source_group(AppFeatures FILES ${PRIVATE_APP_FEATURES_FILES}) source_group(StartupProject FILES ${PRIVATE_STARTUP_PROJECT_FILES}) source_group(Managers\\Layout FILES ${PRIVATE_LAYOUT_MANAGER_FILES}) source_group(Managers\\Plugin FILES ${PRIVATE_PLUGIN_MANAGER_FILES}) diff --git a/ManiVault/src/private/AppFeaturesDialog.h b/ManiVault/src/private/AppFeaturesDialog.h index cad26c6a0..1293defb9 100644 --- a/ManiVault/src/private/AppFeaturesDialog.h +++ b/ManiVault/src/private/AppFeaturesDialog.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include #include From 0f2715ffcb1309b85b555626f77de6265a43085a Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 15:01:42 +0200 Subject: [PATCH 06/37] Rename error logging consent dialog --- ManiVault/src/private/AppFeaturesDialog.cpp | 8 +++----- ManiVault/src/private/AppFeaturesDialog.h | 11 +++++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ManiVault/src/private/AppFeaturesDialog.cpp b/ManiVault/src/private/AppFeaturesDialog.cpp index 5ef8b2d27..1a580efa7 100644 --- a/ManiVault/src/private/AppFeaturesDialog.cpp +++ b/ManiVault/src/private/AppFeaturesDialog.cpp @@ -2,22 +2,20 @@ // A corresponding LICENSE file is located in the root directory of this source tree // Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) -#include "ErrorLoggingConsentDialog.h" +#include "AppFeaturesDialog.h" #include "AbstractErrorLogger.h" -#include - #include #ifdef _DEBUG - #define ERROR_LOGGING_CONSENT_DIALOG_VERBOSE + #define APP_FEATURES_DIALOG_VERBOSE #endif using namespace mv; using namespace mv::gui; using namespace mv::util; -ErrorLoggingConsentDialog::ErrorLoggingConsentDialog(QWidget* parent): +AppFeaturesDialog::AppFeaturesDialog(QWidget* parent): QDialog(parent), _acceptPushButton("Accept"), _optOutPushButton( "Opt Out"), diff --git a/ManiVault/src/private/AppFeaturesDialog.h b/ManiVault/src/private/AppFeaturesDialog.h index 1293defb9..f0f14c296 100644 --- a/ManiVault/src/private/AppFeaturesDialog.h +++ b/ManiVault/src/private/AppFeaturesDialog.h @@ -11,13 +11,16 @@ #include /** - * Error logging consent dialog class + * App features dialog class * - * Establish whether the user wants to opt in or out of (anonymous) error logging. + * Establish which app features the user wants. + * - Automated error reporting + * - A curated list of tutorials (downloaded from the ManiVault Studio website) + * - A curated list of downloadable projects (downloaded from the ManiVault Studio website) * * @author Thomas Kroes */ -class ErrorLoggingConsentDialog : public QDialog +class AppFeaturesDialog : public QDialog { Q_OBJECT @@ -27,7 +30,7 @@ class ErrorLoggingConsentDialog : public QDialog * Construct with pointer to \p parent widget * @param parent Pointer to parent widget (maybe nullptr) */ - explicit ErrorLoggingConsentDialog(QWidget* parent = nullptr); + explicit AppFeaturesDialog(QWidget* parent = nullptr); private: QVBoxLayout _layout; /** Main layout */ From 36ef746b503ea6a89fb03d283ba13df7cbb1cf34 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 15:51:40 +0200 Subject: [PATCH 07/37] Load correct app features HTML file --- ManiVault/src/private/AppFeaturesDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ManiVault/src/private/AppFeaturesDialog.cpp b/ManiVault/src/private/AppFeaturesDialog.cpp index 1a580efa7..3c94bdc9b 100644 --- a/ManiVault/src/private/AppFeaturesDialog.cpp +++ b/ManiVault/src/private/AppFeaturesDialog.cpp @@ -32,7 +32,7 @@ AppFeaturesDialog::AppFeaturesDialog(QWidget* parent): _notificationLabel.setWordWrap(true); _notificationLabel.setOpenExternalLinks(true); - QFile errorLoggingConsentHtmlFile(":/HTML/ErrorLoggingConsent"); + QFile errorLoggingConsentHtmlFile(":/HTML/AppFeatures.html"); if (errorLoggingConsentHtmlFile.open(QIODevice::ReadOnly)) { _notificationLabel.setText(errorLoggingConsentHtmlFile.readAll()); From 337a46fc348c134e2ab93187e0f3f03395765a28 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 15:55:34 +0200 Subject: [PATCH 08/37] Change app features HTML resource and removed unused include --- ManiVault/res/ResourcesCore.qrc | 2 +- ManiVault/src/Main.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ManiVault/res/ResourcesCore.qrc b/ManiVault/res/ResourcesCore.qrc index e7ae63975..b97615d4b 100644 --- a/ManiVault/res/ResourcesCore.qrc +++ b/ManiVault/res/ResourcesCore.qrc @@ -82,6 +82,6 @@ html/markdown.html - html/ErrorLoggingConsent.html + html/AppFeatures.html diff --git a/ManiVault/src/Main.cpp b/ManiVault/src/Main.cpp index a2f7b8626..ab49c47c7 100644 --- a/ManiVault/src/Main.cpp +++ b/ManiVault/src/Main.cpp @@ -22,8 +22,6 @@ #include #include -#include "private/ErrorLoggingConsentDialog.h" - using namespace mv; using namespace mv::util; using namespace mv::gui; From d2e6b488c8712264837951d63c5a9e1d29919839 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 16:06:14 +0200 Subject: [PATCH 09/37] Rename error logging settings action --- ...rLoggingSettingsAction.cpp => AppFeaturesSettingsAction.cpp} | 0 ...ErrorLoggingSettingsAction.h => AppFeaturesSettingsAction.h} | 0 ManiVault/src/private/ErrorManager.cpp | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename ManiVault/src/{ErrorLoggingSettingsAction.cpp => AppFeaturesSettingsAction.cpp} (100%) rename ManiVault/src/{ErrorLoggingSettingsAction.h => AppFeaturesSettingsAction.h} (100%) diff --git a/ManiVault/src/ErrorLoggingSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp similarity index 100% rename from ManiVault/src/ErrorLoggingSettingsAction.cpp rename to ManiVault/src/AppFeaturesSettingsAction.cpp diff --git a/ManiVault/src/ErrorLoggingSettingsAction.h b/ManiVault/src/AppFeaturesSettingsAction.h similarity index 100% rename from ManiVault/src/ErrorLoggingSettingsAction.h rename to ManiVault/src/AppFeaturesSettingsAction.h diff --git a/ManiVault/src/private/ErrorManager.cpp b/ManiVault/src/private/ErrorManager.cpp index e6ce94590..47f725376 100644 --- a/ManiVault/src/private/ErrorManager.cpp +++ b/ManiVault/src/private/ErrorManager.cpp @@ -3,7 +3,7 @@ // Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) #include "ErrorManager.h" -#include "ErrorLoggingConsentDialog.h" +#include "AppFeaturesDialog.h" using namespace mv::gui; using namespace mv::util; From 0dd651f881ee474d5254f3fc8a6d60333aca1fb9 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 28 Apr 2025 16:09:12 +0200 Subject: [PATCH 10/37] Modify cmake accordingly --- ManiVault/cmake/CMakeMvSourcesPublic.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ManiVault/cmake/CMakeMvSourcesPublic.cmake b/ManiVault/cmake/CMakeMvSourcesPublic.cmake index 5b19041f6..2f1cba772 100644 --- a/ManiVault/cmake/CMakeMvSourcesPublic.cmake +++ b/ManiVault/cmake/CMakeMvSourcesPublic.cmake @@ -993,7 +993,7 @@ set(PUBLIC_GLOBAL_SETTINGS_HEADERS src/TasksSettingsAction.h src/AppearanceSettingsAction.h src/TemporaryDirectoriesSettingsAction.h - src/ErrorLoggingSettingsAction.h + src/AppFeaturesSettingsAction.h src/PluginGlobalSettingsGroupAction.h ) @@ -1004,7 +1004,7 @@ set(PUBLIC_GLOBAL_SETTINGS_SOURCES src/TasksSettingsAction.cpp src/AppearanceSettingsAction.cpp src/TemporaryDirectoriesSettingsAction.cpp - src/ErrorLoggingSettingsAction.cpp + src/AppFeaturesSettingsAction.cpp src/PluginGlobalSettingsGroupAction.cpp ) From 95f339f775fae6f7fe424a6f5530320d179658e8 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 11:26:25 +0200 Subject: [PATCH 11/37] Further refactor of error logging classes and added app feature action base class --- ManiVault/cmake/CMakeMvSourcesPublic.cmake | 2 + ManiVault/src/AbstractSettingsManager.h | 5 ++- ManiVault/src/AppFeaturesSettingsAction.cpp | 19 +++++---- ManiVault/src/AppFeaturesSettingsAction.h | 18 ++++----- ManiVault/src/actions/AppFeatureAction.cpp | 14 +++++++ ManiVault/src/actions/AppFeatureAction.h | 39 +++++++++++++++++++ ManiVault/src/private/SettingsManager.cpp | 2 +- ManiVault/src/private/SettingsManager.h | 4 +- .../src/private/SettingsManagerDialog.cpp | 5 +-- 9 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 ManiVault/src/actions/AppFeatureAction.cpp create mode 100644 ManiVault/src/actions/AppFeatureAction.h diff --git a/ManiVault/cmake/CMakeMvSourcesPublic.cmake b/ManiVault/cmake/CMakeMvSourcesPublic.cmake index 2f1cba772..c6e97b9e3 100644 --- a/ManiVault/cmake/CMakeMvSourcesPublic.cmake +++ b/ManiVault/cmake/CMakeMvSourcesPublic.cmake @@ -351,6 +351,7 @@ set(PUBLIC_ACTIONS_INTERNAL_HEADERS src/actions/ColorSchemeAction.h src/actions/EditColorSchemeAction.h src/actions/NavigationAction.h + src/actions/AppFeatureAction.h ) set(PUBLIC_ACTIONS_INTERNAL_SOURCES @@ -390,6 +391,7 @@ set(PUBLIC_ACTIONS_INTERNAL_SOURCES src/actions/ColorSchemeAction.cpp src/actions/EditColorSchemeAction.cpp src/actions/NavigationAction.cpp + src/actions/AppFeatureAction.cpp ) set(PUBLIC_ACTIONS_INTERNAL_FILES diff --git a/ManiVault/src/AbstractSettingsManager.h b/ManiVault/src/AbstractSettingsManager.h index 406fecdf9..c0cb7e430 100644 --- a/ManiVault/src/AbstractSettingsManager.h +++ b/ManiVault/src/AbstractSettingsManager.h @@ -8,12 +8,12 @@ #include "actions/TriggerAction.h" +#include "AppFeaturesSettingsAction.h" #include "ParametersSettingsAction.h" #include "MiscellaneousSettingsAction.h" #include "TasksSettingsAction.h" #include "AppearanceSettingsAction.h" #include "TemporaryDirectoriesSettingsAction.h" -#include "ErrorLoggingSettingsAction.h" #include "PluginGlobalSettingsGroupAction.h" namespace mv { @@ -56,12 +56,13 @@ class CORE_EXPORT AbstractSettingsManager : public AbstractManager public: // Global settings actions + virtual gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() = 0; virtual gui::ParametersSettingsAction& getParametersSettings() = 0; virtual gui::MiscellaneousSettingsAction& getMiscellaneousSettings() = 0; virtual gui::TasksSettingsAction& getTasksSettingsAction() = 0; virtual gui::AppearanceSettingsAction& getAppearanceSettingsAction() = 0; virtual gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() = 0; - virtual gui::ErrorLoggingSettingsAction& getErrorLoggingSettingsAction() = 0; + /** * Get plugin global settings for plugin \p kind diff --git a/ManiVault/src/AppFeaturesSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp index 4ee1c9980..4768eb2db 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.cpp +++ b/ManiVault/src/AppFeaturesSettingsAction.cpp @@ -2,37 +2,40 @@ // A corresponding LICENSE file is located in the root directory of this source tree // Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) -#include "ErrorLoggingSettingsAction.h" +#include "AppFeaturesSettingsAction.h" namespace mv::gui { -ErrorLoggingSettingsAction::ErrorLoggingSettingsAction(QObject* parent) : - GlobalSettingsGroupAction(parent, "Error logging", false) +AppFeaturesSettingsAction::AppFeaturesSettingsAction(QObject* parent) : + GlobalSettingsGroupAction(parent, "App Features", false) { +//#ifdef ERROR_LOGGING +// _groupsAction.addGroupAction(&mv::settings().getErrorLoggingSettingsAction()); +//#endif } -const gui::TriggerAction& ErrorLoggingSettingsAction::getLoggingAskConsentDialogAction() const +const gui::TriggerAction& AppFeaturesSettingsAction::getLoggingAskConsentDialogAction() const { return mv::errors().getLoggingAskConsentDialogAction(); } -const gui::ToggleAction& ErrorLoggingSettingsAction::getUserHasOptedAction() const +const gui::ToggleAction& AppFeaturesSettingsAction::getUserHasOptedAction() const { return mv::errors().getLoggingUserHasOptedAction(); } -const gui::ToggleAction& ErrorLoggingSettingsAction::getEnabledAction() const +const gui::ToggleAction& AppFeaturesSettingsAction::getEnabledAction() const { return mv::errors().getLoggingEnabledAction(); } -const gui::StringAction& ErrorLoggingSettingsAction::getDsnAction() const +const gui::StringAction& AppFeaturesSettingsAction::getDsnAction() const { return mv::errors().getLoggingDsnAction(); } -const gui::ToggleAction& ErrorLoggingSettingsAction::getShowCrashReportDialogAction() const +const gui::ToggleAction& AppFeaturesSettingsAction::getShowCrashReportDialogAction() const { return mv::errors().getLoggingShowCrashReportDialogAction(); } diff --git a/ManiVault/src/AppFeaturesSettingsAction.h b/ManiVault/src/AppFeaturesSettingsAction.h index 222786153..ca37faf98 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.h +++ b/ManiVault/src/AppFeaturesSettingsAction.h @@ -14,13 +14,13 @@ namespace mv::gui { /** - * Error logging settings action class + * App features settings action class * - * Groups all error logging settings for the application + * Groups all app features settings for the application * * @author Thomas Kroes */ -class CORE_EXPORT ErrorLoggingSettingsAction final : public GlobalSettingsGroupAction +class CORE_EXPORT AppFeaturesSettingsAction final : public GlobalSettingsGroupAction { public: @@ -28,15 +28,15 @@ class CORE_EXPORT ErrorLoggingSettingsAction final : public GlobalSettingsGroupA * Construct the error logging settings action with a parent object * @param parent Pointer to parent object */ - ErrorLoggingSettingsAction(QObject* parent); + AppFeaturesSettingsAction(QObject* parent); public: // Action getters - const gui::TriggerAction& getLoggingAskConsentDialogAction() const; /** Get action for asking the user for consent to log errors */ - const gui::ToggleAction& getUserHasOptedAction() const; /** Get action for user has opted */ - const gui::ToggleAction& getEnabledAction() const; /** Get action for logging enabled */ - const gui::StringAction& getDsnAction() const; /** Get action for logging data source name (DSN) */ - const gui::ToggleAction& getShowCrashReportDialogAction() const; /** Get action for showing a crash report dialog when the application fails */ + //const gui::TriggerAction& getLoggingAskConsentDialogAction() const; /** Get action for asking the user for consent to log errors */ + //const gui::ToggleAction& getUserHasOptedAction() const; /** Get action for user has opted */ + //const gui::ToggleAction& getEnabledAction() const; /** Get action for logging enabled */ + //const gui::StringAction& getDsnAction() const; /** Get action for logging data source name (DSN) */ + //const gui::ToggleAction& getShowCrashReportDialogAction() const; /** Get action for showing a crash report dialog when the application fails */ }; } diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp new file mode 100644 index 000000000..36991a6c4 --- /dev/null +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#include "AppFeatureAction.h" + +namespace mv::gui { + +AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : + WidgetAction(parent, title) +{ +} + +} diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h new file mode 100644 index 000000000..fdff7336e --- /dev/null +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#pragma once + +#include "VerticalGroupAction.h" + +namespace mv::gui { + +/** + * App feature action class + * + * Base vertical group action class for grouping app feature settings + * + * Note: This action is developed for internal use only + * + * @author Thomas Kroes + */ +class CORE_EXPORT AppFeatureAction : public WidgetAction +{ + Q_OBJECT + +public: + + /** + * Construct with pointer to \p parent object and \p title + * @param parent Pointer to parent object + * @param title Title of the action + */ + Q_INVOKABLE AppFeatureAction(QObject* parent, const QString& title); + +}; + +} + +Q_DECLARE_METATYPE(mv::gui::AppFeatureAction) + +inline const auto appFeatureActionMetaTypeId = qRegisterMetaType("mv::gui::AppFeatureAction"); diff --git a/ManiVault/src/private/SettingsManager.cpp b/ManiVault/src/private/SettingsManager.cpp index 2b92b2e7d..c8b72edfd 100644 --- a/ManiVault/src/private/SettingsManager.cpp +++ b/ManiVault/src/private/SettingsManager.cpp @@ -27,11 +27,11 @@ namespace mv SettingsManager::SettingsManager(QObject* parent) : AbstractSettingsManager(parent), _editSettingsAction(this, "Settings..."), + _appFeaturesSettingsAction(this), _parametersSettingsAction(this), _miscellaneousSettingsAction(this), _tasksSettingsAction(this), _temporaryDirectoriesSettingsAction(this), - _errorLoggingSettingsAction(this), _appearanceSettingsAction(this) { _editSettingsAction.setShortcutContext(Qt::WidgetWithChildrenShortcut); diff --git a/ManiVault/src/private/SettingsManager.h b/ManiVault/src/private/SettingsManager.h index 1b29af5d4..2267cb6d0 100644 --- a/ManiVault/src/private/SettingsManager.h +++ b/ManiVault/src/private/SettingsManager.h @@ -39,12 +39,12 @@ class SettingsManager final : public AbstractSettingsManager public: // Global settings actions + gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() override { return _appFeaturesSettingsAction; }; gui::ParametersSettingsAction& getParametersSettings() override { return _parametersSettingsAction; }; gui::MiscellaneousSettingsAction& getMiscellaneousSettings() override { return _miscellaneousSettingsAction; }; gui::TasksSettingsAction& getTasksSettingsAction() override { return _tasksSettingsAction; }; gui::AppearanceSettingsAction& getAppearanceSettingsAction() override { return _appearanceSettingsAction; }; gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() override { return _temporaryDirectoriesSettingsAction; }; - gui::ErrorLoggingSettingsAction& getErrorLoggingSettingsAction() override { return _errorLoggingSettingsAction; }; /** * Get plugin global settings for plugin \p kind @@ -61,13 +61,13 @@ class SettingsManager final : public AbstractSettingsManager gui::PluginGlobalSettingsGroupAction* getPluginGlobalSettingsGroupAction(const plugin::Plugin* plugin) override; private: + gui::AppFeaturesSettingsAction _appFeaturesSettingsAction; /** App features global settings */ gui::TriggerAction _editSettingsAction; /** Action for triggering the settings dialog */ gui::ParametersSettingsAction _parametersSettingsAction; /** Parameters global settings */ gui::MiscellaneousSettingsAction _miscellaneousSettingsAction; /** Miscellaneous global settings */ gui::TasksSettingsAction _tasksSettingsAction; /** Tasks global settings */ gui::AppearanceSettingsAction _appearanceSettingsAction; /** Appearance global settings */ gui::TemporaryDirectoriesSettingsAction _temporaryDirectoriesSettingsAction; /** Temporary files global settings */ - gui::ErrorLoggingSettingsAction _errorLoggingSettingsAction; /** Error logging settings */ }; } diff --git a/ManiVault/src/private/SettingsManagerDialog.cpp b/ManiVault/src/private/SettingsManagerDialog.cpp index dd29b694d..05e9400a8 100644 --- a/ManiVault/src/private/SettingsManagerDialog.cpp +++ b/ManiVault/src/private/SettingsManagerDialog.cpp @@ -33,10 +33,7 @@ SettingsManagerDialog::SettingsManagerDialog(QWidget* parent /*= nullptr*/) : layout->addWidget(_groupsAction.createWidget(this)); -#ifdef ERROR_LOGGING - _groupsAction.addGroupAction(&mv::settings().getErrorLoggingSettingsAction()); -#endif - + _groupsAction.addGroupAction(&mv::settings().getAppFeaturesSettingsAction()); _groupsAction.addGroupAction(&mv::settings().getAppearanceSettingsAction()); _groupsAction.addGroupAction(&mv::settings().getParametersSettings()); _groupsAction.addGroupAction(&mv::settings().getMiscellaneousSettings()); From 0838d27b912d84ec2c7e2b0cbabe69a4345ce12d Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 11:30:11 +0200 Subject: [PATCH 12/37] Remove redundant friend declaration and comment unused member functions --- ManiVault/src/AbstractErrorManager.h | 1 - ManiVault/src/AppFeaturesSettingsAction.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ManiVault/src/AbstractErrorManager.h b/ManiVault/src/AbstractErrorManager.h index 37a3a5ef1..e3c1e3998 100644 --- a/ManiVault/src/AbstractErrorManager.h +++ b/ManiVault/src/AbstractErrorManager.h @@ -82,7 +82,6 @@ class CORE_EXPORT AbstractErrorManager : public AbstractManager AbstractErrorLogger* _errorLogger; /** Pointer to the error logger */ friend class AbstractErrorLogger; - friend class gui::ErrorLoggingSettingsAction; }; } diff --git a/ManiVault/src/AppFeaturesSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp index 4768eb2db..3f6525a9d 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.cpp +++ b/ManiVault/src/AppFeaturesSettingsAction.cpp @@ -15,6 +15,7 @@ AppFeaturesSettingsAction::AppFeaturesSettingsAction(QObject* parent) : //#endif } +/* const gui::TriggerAction& AppFeaturesSettingsAction::getLoggingAskConsentDialogAction() const { return mv::errors().getLoggingAskConsentDialogAction(); @@ -39,5 +40,6 @@ const gui::ToggleAction& AppFeaturesSettingsAction::getShowCrashReportDialogActi { return mv::errors().getLoggingShowCrashReportDialogAction(); } +*/ } From 285be813b2fdc91b5d36f6f639f05a9568ed6943 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 11:54:56 +0200 Subject: [PATCH 13/37] Add dynamic content app feature action --- ManiVault/cmake/CMakeMvSourcesPublic.cmake | 22 ++++++++++- ManiVault/src/AppFeaturesSettingsAction.cpp | 4 +- ManiVault/src/AppFeaturesSettingsAction.h | 16 ++++---- .../DynamicContentAppFeatureAction.cpp | 14 +++++++ .../actions/DynamicContentAppFeatureAction.h | 38 +++++++++++++++++++ .../actions/ErrorLoggingAppFeatureAction.cpp | 14 +++++++ .../actions/ErrorLoggingAppFeatureAction.h | 38 +++++++++++++++++++ 7 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 ManiVault/src/actions/DynamicContentAppFeatureAction.cpp create mode 100644 ManiVault/src/actions/DynamicContentAppFeatureAction.h create mode 100644 ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp create mode 100644 ManiVault/src/actions/ErrorLoggingAppFeatureAction.h diff --git a/ManiVault/cmake/CMakeMvSourcesPublic.cmake b/ManiVault/cmake/CMakeMvSourcesPublic.cmake index c6e97b9e3..ea4629e36 100644 --- a/ManiVault/cmake/CMakeMvSourcesPublic.cmake +++ b/ManiVault/cmake/CMakeMvSourcesPublic.cmake @@ -314,6 +314,23 @@ set(PUBLIC_TASK_ACTIONS_FILES ${PUBLIC_TASK_ACTIONS_SOURCES} ) +set(PUBLIC_APP_FEATURE_ACTIONS_HEADERS + src/actions/AppFeatureAction.h + src/actions/ErrorLoggingAppFeatureAction.h + src/actions/DynamicContentAppFeatureAction.h +) + +set(PUBLIC_APP_FEATURE_ACTIONS_SOURCES + src/actions/AppFeatureAction.cpp + src/actions/ErrorLoggingAppFeatureAction.cpp + src/actions/DynamicContentAppFeatureAction.cpp +) + +set(PUBLIC_APP_FEATURE_ACTIONS_FILES + ${PUBLIC_APP_FEATURE_ACTIONS_HEADERS} + ${PUBLIC_APP_FEATURE_ACTIONS_SOURCES} +) + set(PUBLIC_ACTIONS_INTERNAL_HEADERS src/actions/WidgetAction.h src/actions/WidgetActionWidget.h @@ -351,7 +368,6 @@ set(PUBLIC_ACTIONS_INTERNAL_HEADERS src/actions/ColorSchemeAction.h src/actions/EditColorSchemeAction.h src/actions/NavigationAction.h - src/actions/AppFeatureAction.h ) set(PUBLIC_ACTIONS_INTERNAL_SOURCES @@ -391,7 +407,6 @@ set(PUBLIC_ACTIONS_INTERNAL_SOURCES src/actions/ColorSchemeAction.cpp src/actions/EditColorSchemeAction.cpp src/actions/NavigationAction.cpp - src/actions/AppFeatureAction.cpp ) set(PUBLIC_ACTIONS_INTERNAL_FILES @@ -1080,6 +1095,7 @@ set(PUBLIC_HEADERS ${PUBLIC_TOOLBAR_ACTIONS_HEADERS} ${PUBLIC_MISCELLANEOUS_ACTIONS_HEADERS} ${PUBLIC_TASK_ACTIONS_HEADERS} + ${PUBLIC_APP_FEATURE_ACTIONS_HEADERS} ${PUBLIC_ACTIONS_INTERNAL_HEADERS} ${PUBLIC_WIDGETS_HEADERS} ${PUBLIC_WIDGETS_INTERNAL_HEADERS} @@ -1128,6 +1144,7 @@ set(PUBLIC_SOURCES ${PUBLIC_TOOLBAR_ACTIONS_SOURCES} ${PUBLIC_MISCELLANEOUS_ACTIONS_SOURCES} ${PUBLIC_TASK_ACTIONS_SOURCES} + ${PUBLIC_APP_FEATURE_ACTIONS_SOURCES} ${PUBLIC_ACTIONS_INTERNAL_SOURCES} ${PUBLIC_WIDGETS_SOURCES} ${PUBLIC_WIDGETS_INTERNAL_SOURCES} @@ -1190,6 +1207,7 @@ source_group(Actions\\Toolbar FILES ${PUBLIC_TOOLBAR_ACTIONS_FILES}) source_group(Actions\\Miscellaneous FILES ${PUBLIC_MISCELLANEOUS_ACTIONS_FILES}) source_group(Actions\\Task FILES ${PUBLIC_TASK_ACTIONS_FILES}) source_group(Actions\\Internal FILES ${PUBLIC_ACTIONS_INTERNAL_FILES}) +source_group(Actions\\AppFeature FILES ${PUBLIC_APP_FEATURE_ACTIONS_FILES}) source_group(Widgets FILES ${PUBLIC_WIDGETS_FILES}) source_group(Widgets\\Internal FILES ${PUBLIC_WIDGETS_INTERNAL_FILES}) source_group(Renderers FILES ${PUBLIC_RENDERERS_FILES}) diff --git a/ManiVault/src/AppFeaturesSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp index 3f6525a9d..1d2790bb4 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.cpp +++ b/ManiVault/src/AppFeaturesSettingsAction.cpp @@ -8,7 +8,9 @@ namespace mv::gui { AppFeaturesSettingsAction::AppFeaturesSettingsAction(QObject* parent) : - GlobalSettingsGroupAction(parent, "App Features", false) + GlobalSettingsGroupAction(parent, "App Features", false), + _errorLoggingAppFeatureAction(this), + _dynamicContentAppFeatureAction(this) { //#ifdef ERROR_LOGGING // _groupsAction.addGroupAction(&mv::settings().getErrorLoggingSettingsAction()); diff --git a/ManiVault/src/AppFeaturesSettingsAction.h b/ManiVault/src/AppFeaturesSettingsAction.h index ca37faf98..51b66f007 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.h +++ b/ManiVault/src/AppFeaturesSettingsAction.h @@ -6,9 +6,8 @@ #include "GlobalSettingsGroupAction.h" -#include "actions/ToggleAction.h" -#include "actions/StringAction.h" -#include "actions/TriggerAction.h" +#include "actions/ErrorLoggingAppFeatureAction.h" +#include "actions/DynamicContentAppFeatureAction.h" namespace mv::gui { @@ -32,11 +31,12 @@ class CORE_EXPORT AppFeaturesSettingsAction final : public GlobalSettingsGroupAc public: // Action getters - //const gui::TriggerAction& getLoggingAskConsentDialogAction() const; /** Get action for asking the user for consent to log errors */ - //const gui::ToggleAction& getUserHasOptedAction() const; /** Get action for user has opted */ - //const gui::ToggleAction& getEnabledAction() const; /** Get action for logging enabled */ - //const gui::StringAction& getDsnAction() const; /** Get action for logging data source name (DSN) */ - //const gui::ToggleAction& getShowCrashReportDialogAction() const; /** Get action for showing a crash report dialog when the application fails */ + const gui::ErrorLoggingAppFeatureAction& getErrorLoggingAppFeatureAction() const { return _errorLoggingAppFeatureAction; } + const gui::DynamicContentAppFeatureAction& getDynamicContentAppFeatureAction() const { return _dynamicContentAppFeatureAction; } + +private: + ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ + DynamicContentAppFeatureAction _dynamicContentAppFeatureAction; /** App feature action for configuring dynamic content */ }; } diff --git a/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp b/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp new file mode 100644 index 000000000..187c4467e --- /dev/null +++ b/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#include "DynamicContentAppFeatureAction.h" + +namespace mv::gui { + + DynamicContentAppFeatureAction::DynamicContentAppFeatureAction(QObject* parent, const QString& title /*= "Dynamic Content"*/) : + AppFeatureAction(parent, title) +{ +} + +} diff --git a/ManiVault/src/actions/DynamicContentAppFeatureAction.h b/ManiVault/src/actions/DynamicContentAppFeatureAction.h new file mode 100644 index 000000000..746886047 --- /dev/null +++ b/ManiVault/src/actions/DynamicContentAppFeatureAction.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#pragma once + +#include "AppFeatureAction.h" + +namespace mv::gui { + +/** + * Dynamic content app feature action class + * + * App feature action class for grouping dynamic content settings + * + * Note: This action is developed for internal use only + * + * @author Thomas Kroes + */ +class CORE_EXPORT DynamicContentAppFeatureAction : public AppFeatureAction +{ + Q_OBJECT + +public: + + /** + * Construct with pointer to \p parent object and \p title + * @param parent Pointer to parent object + * @param title Title of the action + */ + Q_INVOKABLE DynamicContentAppFeatureAction(QObject* parent, const QString& title = "Dynamic Content"); +}; + +} + +Q_DECLARE_METATYPE(mv::gui::DynamicContentAppFeatureAction) + +inline const auto dynamicContentAppFeatureActionMetaTypeId = qRegisterMetaType("mv::gui::DynamicContentAppFeatureAction"); diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp new file mode 100644 index 000000000..55b979d43 --- /dev/null +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#include "ErrorLoggingAppFeatureAction.h" + +namespace mv::gui { + +ErrorLoggingAppFeatureAction::ErrorLoggingAppFeatureAction(QObject* parent, const QString& title /*= "Error Logging"*/) : + AppFeatureAction(parent, title) +{ +} + +} diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.h b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.h new file mode 100644 index 000000000..9c28e1395 --- /dev/null +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#pragma once + +#include "AppFeatureAction.h" + +namespace mv::gui { + +/** + * Error logging app feature action class + * + * App feature action class for grouping error logging settings + * + * Note: This action is developed for internal use only + * + * @author Thomas Kroes + */ +class CORE_EXPORT ErrorLoggingAppFeatureAction : public AppFeatureAction +{ + Q_OBJECT + +public: + + /** + * Construct with pointer to \p parent object and \p title + * @param parent Pointer to parent object + * @param title Title of the action + */ + Q_INVOKABLE ErrorLoggingAppFeatureAction(QObject* parent, const QString& title = "Error Logging"); +}; + +} + +Q_DECLARE_METATYPE(mv::gui::ErrorLoggingAppFeatureAction) + +inline const auto errorLoggingAppFeatureActionMetaTypeId = qRegisterMetaType("mv::gui::ErrorLoggingAppFeatureAction"); From 69dafa10e1effe67f6921edce012e332927d4fae Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 12:09:30 +0200 Subject: [PATCH 14/37] Work on app feature implementation --- ManiVault/src/AppFeaturesSettingsAction.cpp | 9 ++++++--- ManiVault/src/actions/AppFeatureAction.cpp | 11 ++++++++++- ManiVault/src/actions/AppFeatureAction.h | 20 +++++++++++++++++++- ManiVault/src/actions/GroupAction.cpp | 3 +-- ManiVault/src/actions/GroupAction.h | 2 +- ManiVault/src/private/CrashReportDialog.cpp | 3 ++- ManiVault/src/private/ErrorManager.cpp | 21 ++++++++++++--------- 7 files changed, 51 insertions(+), 18 deletions(-) diff --git a/ManiVault/src/AppFeaturesSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp index 1d2790bb4..f30fbafbf 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.cpp +++ b/ManiVault/src/AppFeaturesSettingsAction.cpp @@ -12,9 +12,12 @@ AppFeaturesSettingsAction::AppFeaturesSettingsAction(QObject* parent) : _errorLoggingAppFeatureAction(this), _dynamicContentAppFeatureAction(this) { -//#ifdef ERROR_LOGGING -// _groupsAction.addGroupAction(&mv::settings().getErrorLoggingSettingsAction()); -//#endif + +#ifdef ERROR_LOGGING + addAction(&_errorLoggingAppFeatureAction); +#endif + + addAction(&_dynamicContentAppFeatureAction); } /* diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 36991a6c4..7b9e1a8e6 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -7,8 +7,17 @@ namespace mv::gui { AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : - WidgetAction(parent, title) + HorizontalGroupAction(parent, title), + _settingsAction(this, "Settings") { + _settingsAction.setIconByName("gear"); + _settingsAction.setToolTip(QString("%1 settings").arg(title)); + + HorizontalGroupAction::addAction(&_settingsAction); } +void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags, WidgetConfigurationFunction widgetConfigurationFunction, bool load) +{ + _settingsAction.addAction(action, widgetFlags, widgetConfigurationFunction, load); +} } diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h index fdff7336e..4b20dd6f2 100644 --- a/ManiVault/src/actions/AppFeatureAction.h +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -4,6 +4,8 @@ #pragma once +#include "HorizontalGroupAction.h" +#include "ToggleAction.h" #include "VerticalGroupAction.h" namespace mv::gui { @@ -17,7 +19,7 @@ namespace mv::gui { * * @author Thomas Kroes */ -class CORE_EXPORT AppFeatureAction : public WidgetAction +class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction { Q_OBJECT @@ -30,6 +32,22 @@ class CORE_EXPORT AppFeatureAction : public WidgetAction */ Q_INVOKABLE AppFeatureAction(QObject* parent, const QString& title); + /** + * Add \p action to the group + * @param action Pointer to action to add + * @param widgetFlags Action widget flags (default flags if -1) + * @param widgetConfigurationFunction When set, overrides the standard widget configuration function in the widget action + * @param load Currently not used + */ + void addAction(WidgetAction* action, std::int32_t widgetFlags, WidgetConfigurationFunction widgetConfigurationFunction, bool load) override; + +public: // Action getters + + const ToggleAction& getEnabledAction() const { return _enabledAction; } + +private: + ToggleAction _enabledAction; /** Settings action for the app feature */ + VerticalGroupAction _settingsAction; /** Vertical group action for settings */ }; } diff --git a/ManiVault/src/actions/GroupAction.cpp b/ManiVault/src/actions/GroupAction.cpp index 85d7c3526..2de9bc15b 100644 --- a/ManiVault/src/actions/GroupAction.cpp +++ b/ManiVault/src/actions/GroupAction.cpp @@ -115,8 +115,7 @@ void GroupAction::setShowLabels(bool showLabels) emit showLabelsChanged(_showLabels); } -void GroupAction::addAction(WidgetAction* action, std::int32_t widgetFlags /*= -1*/, WidgetConfigurationFunction widgetConfigurationFunction /*= WidgetConfigurationFunction()*/ - , bool load) +void GroupAction::addAction(WidgetAction* action, std::int32_t widgetFlags /*= -1*/, WidgetConfigurationFunction widgetConfigurationFunction /*= WidgetConfigurationFunction()*/, bool load) { Q_ASSERT(action != nullptr); diff --git a/ManiVault/src/actions/GroupAction.h b/ManiVault/src/actions/GroupAction.h index 3af439f01..783f03c54 100644 --- a/ManiVault/src/actions/GroupAction.h +++ b/ManiVault/src/actions/GroupAction.h @@ -172,7 +172,7 @@ class CORE_EXPORT GroupAction : public WidgetAction * @param action Pointer to action to add * @param widgetFlags Action widget flags (default flags if -1) * @param widgetConfigurationFunction When set, overrides the standard widget configuration function in the widget action - * @param load + * @param load Currently not used */ virtual void addAction(WidgetAction* action, std::int32_t widgetFlags = -1, WidgetConfigurationFunction widgetConfigurationFunction = WidgetConfigurationFunction(), bool load = true); diff --git a/ManiVault/src/private/CrashReportDialog.cpp b/ManiVault/src/private/CrashReportDialog.cpp index e4bd7dec2..3de14bc84 100644 --- a/ManiVault/src/private/CrashReportDialog.cpp +++ b/ManiVault/src/private/CrashReportDialog.cpp @@ -69,7 +69,8 @@ CrashReportDialog::CrashReportDialog(QWidget* parent): _layout.addWidget(&_contactLineEdit); - _buttonsLayout.addWidget(const_cast(mv::settings().getErrorLoggingSettingsAction().getShowCrashReportDialogAction()).createWidget(this)); + // TODO + // _buttonsLayout.addWidget(const_cast(mv::settings().getErrorLoggingSettingsAction().getShowCrashReportDialogAction()).createWidget(this)); _buttonsLayout.addStretch(1); _buttonsLayout.addWidget(&_sendButton); _buttonsLayout.addWidget(&_cancelButton); diff --git a/ManiVault/src/private/ErrorManager.cpp b/ManiVault/src/private/ErrorManager.cpp index 47f725376..cea93f7e7 100644 --- a/ManiVault/src/private/ErrorManager.cpp +++ b/ManiVault/src/private/ErrorManager.cpp @@ -75,12 +75,14 @@ void ErrorManager::initialize() beginInitialization(); { - auto& errorLoggingSettingsAction = mv::settings().getErrorLoggingSettingsAction(); + // TODO + //auto& errorLoggingSettingsAction = mv::settings().getErrorLoggingSettingsAction(); - errorLoggingSettingsAction.addAction(&getLoggingAskConsentDialogAction()); - errorLoggingSettingsAction.addAction(&getLoggingEnabledAction()); - errorLoggingSettingsAction.addAction(&getLoggingDsnAction()); - errorLoggingSettingsAction.addAction(&getLoggingShowCrashReportDialogAction()); + // TODO + //errorLoggingSettingsAction.addAction(&getLoggingAskConsentDialogAction()); + //errorLoggingSettingsAction.addAction(&getLoggingEnabledAction()); + //errorLoggingSettingsAction.addAction(&getLoggingDsnAction()); + //errorLoggingSettingsAction.addAction(&getLoggingShowCrashReportDialogAction()); #ifdef ERROR_LOGGING setErrorLogger(new SentryErrorLogger(this)); @@ -112,10 +114,11 @@ void ErrorManager::reset() void ErrorManager::showErrorLoggingConsentDialog() { -#ifdef ERROR_LOGGING - ErrorLoggingConsentDialog errorLoggingConsentDialog; - errorLoggingConsentDialog.exec(); -#endif +// TODO +//#ifdef ERROR_LOGGING +// ErrorLoggingConsentDialog errorLoggingConsentDialog; +// errorLoggingConsentDialog.exec(); +//#endif } } From fc024c58ede31fef66b7e7ee1e6d0b8a260f980c Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 12:14:54 +0200 Subject: [PATCH 15/37] Work on app feature action class --- ManiVault/src/actions/AppFeatureAction.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 7b9e1a8e6..2a722de83 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -8,12 +8,25 @@ namespace mv::gui { AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : HorizontalGroupAction(parent, title), + _enabledAction(this, "Enabled", false), _settingsAction(this, "Settings") { + setShowLabels(false); + _settingsAction.setIconByName("gear"); _settingsAction.setToolTip(QString("%1 settings").arg(title)); + _settingsAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); + HorizontalGroupAction::addAction(&_enabledAction); HorizontalGroupAction::addAction(&_settingsAction); + + const auto updateSettingsActionReadOnly = [this]() -> void { + _settingsAction.setEnabled(_enabledAction.isChecked()); + }; + + updateSettingsActionReadOnly(); + + connect(&_enabledAction, &ToggleAction::toggled, this, updateSettingsActionReadOnly); } void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags, WidgetConfigurationFunction widgetConfigurationFunction, bool load) From 0db33c5c603a86872d9588334ab74102a3808347 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 12:23:02 +0200 Subject: [PATCH 16/37] Fix app featurre action overload and work on dynamic content app feature action --- ManiVault/src/actions/AppFeatureAction.cpp | 2 +- ManiVault/src/actions/AppFeatureAction.h | 2 +- .../src/actions/DynamicContentAppFeatureAction.cpp | 8 ++++++-- .../src/actions/DynamicContentAppFeatureAction.h | 11 +++++++++++ ManiVault/src/actions/GroupAction.h | 12 ++++++------ 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 2a722de83..320a24d33 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -29,7 +29,7 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : connect(&_enabledAction, &ToggleAction::toggled, this, updateSettingsActionReadOnly); } -void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags, WidgetConfigurationFunction widgetConfigurationFunction, bool load) +void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags /*= -1*/, WidgetConfigurationFunction widgetConfigurationFunction /*= WidgetConfigurationFunction()*/, bool load) { _settingsAction.addAction(action, widgetFlags, widgetConfigurationFunction, load); } diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h index 4b20dd6f2..592869053 100644 --- a/ManiVault/src/actions/AppFeatureAction.h +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -39,7 +39,7 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction * @param widgetConfigurationFunction When set, overrides the standard widget configuration function in the widget action * @param load Currently not used */ - void addAction(WidgetAction* action, std::int32_t widgetFlags, WidgetConfigurationFunction widgetConfigurationFunction, bool load) override; + void addAction(WidgetAction* action, std::int32_t widgetFlags = -1, WidgetConfigurationFunction widgetConfigurationFunction = WidgetConfigurationFunction(), bool load = true) override; public: // Action getters diff --git a/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp b/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp index 187c4467e..275953de2 100644 --- a/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp +++ b/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp @@ -6,9 +6,13 @@ namespace mv::gui { - DynamicContentAppFeatureAction::DynamicContentAppFeatureAction(QObject* parent, const QString& title /*= "Dynamic Content"*/) : - AppFeatureAction(parent, title) +DynamicContentAppFeatureAction::DynamicContentAppFeatureAction(QObject* parent, const QString& title /*= "Dynamic Content"*/) : + AppFeatureAction(parent, title), + _tutorialsAction(this, "Tutorials"), + _projectsAction(this, "Projects") { + addAction(&_tutorialsAction); + addAction(&_projectsAction); } } diff --git a/ManiVault/src/actions/DynamicContentAppFeatureAction.h b/ManiVault/src/actions/DynamicContentAppFeatureAction.h index 746886047..2b58869f5 100644 --- a/ManiVault/src/actions/DynamicContentAppFeatureAction.h +++ b/ManiVault/src/actions/DynamicContentAppFeatureAction.h @@ -6,6 +6,8 @@ #include "AppFeatureAction.h" +#include "actions/ToggleAction.h" + namespace mv::gui { /** @@ -29,6 +31,15 @@ class CORE_EXPORT DynamicContentAppFeatureAction : public AppFeatureAction * @param title Title of the action */ Q_INVOKABLE DynamicContentAppFeatureAction(QObject* parent, const QString& title = "Dynamic Content"); + +public: // Action getters + + const ToggleAction& getTutorialsAction() const { return _tutorialsAction; } + const ToggleAction& getProjectsAction() const { return _projectsAction; } + +private: + ToggleAction _tutorialsAction; /** Toggle tutorials dynamic content */ + ToggleAction _projectsAction; /** Toggle projects dynamic content */ }; } diff --git a/ManiVault/src/actions/GroupAction.h b/ManiVault/src/actions/GroupAction.h index 783f03c54..6f5f23318 100644 --- a/ManiVault/src/actions/GroupAction.h +++ b/ManiVault/src/actions/GroupAction.h @@ -180,25 +180,25 @@ class CORE_EXPORT GroupAction : public WidgetAction * Remove \p action from the group * @param action Pointer to action to add */ - virtual void removeAction(WidgetAction* action) final; + void removeAction(WidgetAction* action); /** Remove all actions */ - virtual void removeAllActions() final; + void removeAllActions(); /** Remove all actions (alias for GroupAction::removeAllActions()) */ - virtual void clear() final; + void clear(); /** * Get actions * @return Vector of pointers to actions */ - virtual WidgetActions getActions() final; + WidgetActions getActions(); /** * Get const actions * @return Vector of const pointers to actions */ - virtual ConstWidgetActions getConstActions() final; + ConstWidgetActions getConstActions(); /** * Get widget flags map (maps widget action pointer to widget creation flags) @@ -247,7 +247,7 @@ class CORE_EXPORT GroupAction : public WidgetAction private: /** Sort added actions based on their sort index */ - virtual void sortActions() final; + void sortActions(); public: // Serialization From 77b5a9e339dd9f096fc259aea6653fab2e3e9016 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 12:26:39 +0200 Subject: [PATCH 17/37] Refactor --- .../{DynamicContentAppFeatureAction.h => TutorialsAppFeature.h} | 0 ...cContentAppFeatureAction.cpp => TutorialsAppFeatureAction.cpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename ManiVault/src/actions/{DynamicContentAppFeatureAction.h => TutorialsAppFeature.h} (100%) rename ManiVault/src/actions/{DynamicContentAppFeatureAction.cpp => TutorialsAppFeatureAction.cpp} (100%) diff --git a/ManiVault/src/actions/DynamicContentAppFeatureAction.h b/ManiVault/src/actions/TutorialsAppFeature.h similarity index 100% rename from ManiVault/src/actions/DynamicContentAppFeatureAction.h rename to ManiVault/src/actions/TutorialsAppFeature.h diff --git a/ManiVault/src/actions/DynamicContentAppFeatureAction.cpp b/ManiVault/src/actions/TutorialsAppFeatureAction.cpp similarity index 100% rename from ManiVault/src/actions/DynamicContentAppFeatureAction.cpp rename to ManiVault/src/actions/TutorialsAppFeatureAction.cpp From c6a41ec56b1347a9929e4ca3e7b3c6bf82bccc54 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 12:46:39 +0200 Subject: [PATCH 18/37] Add other dynamic content app feature actions and add app feature toggle notifications --- ManiVault/cmake/CMakeMvSourcesPublic.cmake | 8 ++- ManiVault/src/AppFeaturesSettingsAction.cpp | 8 ++- ManiVault/src/AppFeaturesSettingsAction.h | 16 ++++-- ManiVault/src/actions/AppFeatureAction.cpp | 6 +++ .../src/actions/ProjectsAppFeatureAction.cpp | 14 ++++++ .../src/actions/ProjectsAppFeatureAction.h | 50 +++++++++++++++++++ ManiVault/src/actions/TutorialsAppFeature.h | 49 ------------------ .../src/actions/TutorialsAppFeatureAction.cpp | 10 ++-- .../src/actions/TutorialsAppFeatureAction.h | 50 +++++++++++++++++++ .../src/actions/VideosAppFeatureAction.cpp | 14 ++++++ .../src/actions/VideosAppFeatureAction.h | 50 +++++++++++++++++++ 11 files changed, 210 insertions(+), 65 deletions(-) create mode 100644 ManiVault/src/actions/ProjectsAppFeatureAction.cpp create mode 100644 ManiVault/src/actions/ProjectsAppFeatureAction.h delete mode 100644 ManiVault/src/actions/TutorialsAppFeature.h create mode 100644 ManiVault/src/actions/TutorialsAppFeatureAction.h create mode 100644 ManiVault/src/actions/VideosAppFeatureAction.cpp create mode 100644 ManiVault/src/actions/VideosAppFeatureAction.h diff --git a/ManiVault/cmake/CMakeMvSourcesPublic.cmake b/ManiVault/cmake/CMakeMvSourcesPublic.cmake index ea4629e36..19c7d2819 100644 --- a/ManiVault/cmake/CMakeMvSourcesPublic.cmake +++ b/ManiVault/cmake/CMakeMvSourcesPublic.cmake @@ -317,13 +317,17 @@ set(PUBLIC_TASK_ACTIONS_FILES set(PUBLIC_APP_FEATURE_ACTIONS_HEADERS src/actions/AppFeatureAction.h src/actions/ErrorLoggingAppFeatureAction.h - src/actions/DynamicContentAppFeatureAction.h + src/actions/TutorialsAppFeatureAction.h + src/actions/ProjectsAppFeatureAction.h + src/actions/VideosAppFeatureAction.h ) set(PUBLIC_APP_FEATURE_ACTIONS_SOURCES src/actions/AppFeatureAction.cpp src/actions/ErrorLoggingAppFeatureAction.cpp - src/actions/DynamicContentAppFeatureAction.cpp + src/actions/TutorialsAppFeatureAction.cpp + src/actions/ProjectsAppFeatureAction.cpp + src/actions/VideosAppFeatureAction.cpp ) set(PUBLIC_APP_FEATURE_ACTIONS_FILES diff --git a/ManiVault/src/AppFeaturesSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp index f30fbafbf..e19305f57 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.cpp +++ b/ManiVault/src/AppFeaturesSettingsAction.cpp @@ -10,14 +10,18 @@ namespace mv::gui AppFeaturesSettingsAction::AppFeaturesSettingsAction(QObject* parent) : GlobalSettingsGroupAction(parent, "App Features", false), _errorLoggingAppFeatureAction(this), - _dynamicContentAppFeatureAction(this) + _projectsAppFeatureAction(this), + _tutorialsAppFeatureAction(this), + _videosAppFeatureAction(this) { #ifdef ERROR_LOGGING addAction(&_errorLoggingAppFeatureAction); #endif - addAction(&_dynamicContentAppFeatureAction); + addAction(&_projectsAppFeatureAction); + addAction(&_tutorialsAppFeatureAction); + addAction(&_videosAppFeatureAction); } /* diff --git a/ManiVault/src/AppFeaturesSettingsAction.h b/ManiVault/src/AppFeaturesSettingsAction.h index 51b66f007..b3e2d4456 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.h +++ b/ManiVault/src/AppFeaturesSettingsAction.h @@ -7,7 +7,9 @@ #include "GlobalSettingsGroupAction.h" #include "actions/ErrorLoggingAppFeatureAction.h" -#include "actions/DynamicContentAppFeatureAction.h" +#include "actions/ProjectsAppFeatureAction.h" +#include "actions/TutorialsAppFeatureAction.h" +#include "actions/VideosAppFeatureAction.h" namespace mv::gui { @@ -31,12 +33,16 @@ class CORE_EXPORT AppFeaturesSettingsAction final : public GlobalSettingsGroupAc public: // Action getters - const gui::ErrorLoggingAppFeatureAction& getErrorLoggingAppFeatureAction() const { return _errorLoggingAppFeatureAction; } - const gui::DynamicContentAppFeatureAction& getDynamicContentAppFeatureAction() const { return _dynamicContentAppFeatureAction; } + const ErrorLoggingAppFeatureAction& getErrorLoggingAppFeatureAction() const { return _errorLoggingAppFeatureAction; } + const ProjectsAppFeatureAction& getProjectsAppFeatureAction() const { return _projectsAppFeatureAction; } + const TutorialsAppFeatureAction& getTutorialsAppFeatureAction() const { return _tutorialsAppFeatureAction; } + const VideosAppFeatureAction& getVideosAppFeatureAction() const { return _videosAppFeatureAction; } private: - ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ - DynamicContentAppFeatureAction _dynamicContentAppFeatureAction; /** App feature action for configuring dynamic content */ + ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ + ProjectsAppFeatureAction _projectsAppFeatureAction; /** App feature action for configuring projects dynamic content */ + TutorialsAppFeatureAction _tutorialsAppFeatureAction; /** App feature action for configuring tutorials dynamic content */ + VideosAppFeatureAction _videosAppFeatureAction; /** App feature action for configuring videos dynamic content */ }; } diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 320a24d33..f6114586e 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -4,6 +4,8 @@ #include "AppFeatureAction.h" +using namespace mv::util; + namespace mv::gui { AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : @@ -27,6 +29,10 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : updateSettingsActionReadOnly(); connect(&_enabledAction, &ToggleAction::toggled, this, updateSettingsActionReadOnly); + + connect(&_enabledAction, &ToggleAction::toggled, this, [this](bool toggled) -> void { + mv::help().addNotification("App Feature", QString("%1 app feature has been %2").arg(text(), toggled ? "enabled" : "disabled"), StyledIcon(toggled ? "toggle-on" : "toggle-off")); + }); } void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags /*= -1*/, WidgetConfigurationFunction widgetConfigurationFunction /*= WidgetConfigurationFunction()*/, bool load) diff --git a/ManiVault/src/actions/ProjectsAppFeatureAction.cpp b/ManiVault/src/actions/ProjectsAppFeatureAction.cpp new file mode 100644 index 000000000..5f0ad4d90 --- /dev/null +++ b/ManiVault/src/actions/ProjectsAppFeatureAction.cpp @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#include "ProjectsAppFeatureAction.h" + +namespace mv::gui { + +ProjectsAppFeatureAction::ProjectsAppFeatureAction(QObject* parent, const QString& title /*= "Projects"*/) : + AppFeatureAction(parent, title) +{ +} + +} diff --git a/ManiVault/src/actions/ProjectsAppFeatureAction.h b/ManiVault/src/actions/ProjectsAppFeatureAction.h new file mode 100644 index 000000000..bbdcd9e9b --- /dev/null +++ b/ManiVault/src/actions/ProjectsAppFeatureAction.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#pragma once + +#include "AppFeatureAction.h" + +#include "actions/ToggleAction.h" + +namespace mv::gui { + +/** + * Projects app feature action class + * + * App feature action class for grouping projects dynamic content settings + * + * Note: This action is developed for internal use only + * + * @author Thomas Kroes + */ +class CORE_EXPORT ProjectsAppFeatureAction : public AppFeatureAction +{ + Q_OBJECT + +public: + + /** + * Construct with pointer to \p parent object and \p title + * @param parent Pointer to parent object + * @param title Title of the action + */ + Q_INVOKABLE ProjectsAppFeatureAction(QObject* parent, const QString& title = "Projects"); + +//TODO +//public: // Action getters +// +// const ToggleAction& getTutorialsAction() const { return _tutorialsAction; } +// const ToggleAction& getProjectsAction() const { return _projectsAction; } +// +//private: +// ToggleAction _tutorialsAction; /** Toggle tutorials dynamic content */ +// ToggleAction _projectsAction; /** Toggle projects dynamic content */ +}; + +} + +Q_DECLARE_METATYPE(mv::gui::ProjectsAppFeatureAction) + +inline const auto projectsAppFeatureActionMetaTypeId = qRegisterMetaType("mv::gui::ProjectsAppFeatureAction"); diff --git a/ManiVault/src/actions/TutorialsAppFeature.h b/ManiVault/src/actions/TutorialsAppFeature.h deleted file mode 100644 index 2b58869f5..000000000 --- a/ManiVault/src/actions/TutorialsAppFeature.h +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// A corresponding LICENSE file is located in the root directory of this source tree -// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) - -#pragma once - -#include "AppFeatureAction.h" - -#include "actions/ToggleAction.h" - -namespace mv::gui { - -/** - * Dynamic content app feature action class - * - * App feature action class for grouping dynamic content settings - * - * Note: This action is developed for internal use only - * - * @author Thomas Kroes - */ -class CORE_EXPORT DynamicContentAppFeatureAction : public AppFeatureAction -{ - Q_OBJECT - -public: - - /** - * Construct with pointer to \p parent object and \p title - * @param parent Pointer to parent object - * @param title Title of the action - */ - Q_INVOKABLE DynamicContentAppFeatureAction(QObject* parent, const QString& title = "Dynamic Content"); - -public: // Action getters - - const ToggleAction& getTutorialsAction() const { return _tutorialsAction; } - const ToggleAction& getProjectsAction() const { return _projectsAction; } - -private: - ToggleAction _tutorialsAction; /** Toggle tutorials dynamic content */ - ToggleAction _projectsAction; /** Toggle projects dynamic content */ -}; - -} - -Q_DECLARE_METATYPE(mv::gui::DynamicContentAppFeatureAction) - -inline const auto dynamicContentAppFeatureActionMetaTypeId = qRegisterMetaType("mv::gui::DynamicContentAppFeatureAction"); diff --git a/ManiVault/src/actions/TutorialsAppFeatureAction.cpp b/ManiVault/src/actions/TutorialsAppFeatureAction.cpp index 275953de2..bb874d329 100644 --- a/ManiVault/src/actions/TutorialsAppFeatureAction.cpp +++ b/ManiVault/src/actions/TutorialsAppFeatureAction.cpp @@ -2,17 +2,13 @@ // A corresponding LICENSE file is located in the root directory of this source tree // Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) -#include "DynamicContentAppFeatureAction.h" +#include "TutorialsAppFeatureAction.h" namespace mv::gui { -DynamicContentAppFeatureAction::DynamicContentAppFeatureAction(QObject* parent, const QString& title /*= "Dynamic Content"*/) : - AppFeatureAction(parent, title), - _tutorialsAction(this, "Tutorials"), - _projectsAction(this, "Projects") +TutorialsAppFeatureAction::TutorialsAppFeatureAction(QObject* parent, const QString& title /*= "Tutorials"*/) : + AppFeatureAction(parent, title) { - addAction(&_tutorialsAction); - addAction(&_projectsAction); } } diff --git a/ManiVault/src/actions/TutorialsAppFeatureAction.h b/ManiVault/src/actions/TutorialsAppFeatureAction.h new file mode 100644 index 000000000..5fc79c87b --- /dev/null +++ b/ManiVault/src/actions/TutorialsAppFeatureAction.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#pragma once + +#include "AppFeatureAction.h" + +#include "actions/ToggleAction.h" + +namespace mv::gui { + +/** + * Tutorials app feature action class + * + * App feature action class for grouping tutorials dynamic content settings + * + * Note: This action is developed for internal use only + * + * @author Thomas Kroes + */ +class CORE_EXPORT TutorialsAppFeatureAction : public AppFeatureAction +{ + Q_OBJECT + +public: + + /** + * Construct with pointer to \p parent object and \p title + * @param parent Pointer to parent object + * @param title Title of the action + */ + Q_INVOKABLE TutorialsAppFeatureAction(QObject* parent, const QString& title = "Tutorials"); + +// TODO +//public: // Action getters +// +// const ToggleAction& getTutorialsAction() const { return _tutorialsAction; } +// const ToggleAction& getProjectsAction() const { return _projectsAction; } +// +//private: +// ToggleAction _tutorialsAction; /** Toggle tutorials dynamic content */ +// ToggleAction _projectsAction; /** Toggle projects dynamic content */ +}; + +} + +Q_DECLARE_METATYPE(mv::gui::TutorialsAppFeatureAction) + +inline const auto tutorialsAppFeatureActionMetaTypeId = qRegisterMetaType("mv::gui::TutorialsAppFeatureAction"); diff --git a/ManiVault/src/actions/VideosAppFeatureAction.cpp b/ManiVault/src/actions/VideosAppFeatureAction.cpp new file mode 100644 index 000000000..d176e1625 --- /dev/null +++ b/ManiVault/src/actions/VideosAppFeatureAction.cpp @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#include "VideosAppFeatureAction.h" + +namespace mv::gui { + +VideosAppFeatureAction::VideosAppFeatureAction(QObject* parent, const QString& title /*= "Videos"*/) : + AppFeatureAction(parent, title) +{ +} + +} diff --git a/ManiVault/src/actions/VideosAppFeatureAction.h b/ManiVault/src/actions/VideosAppFeatureAction.h new file mode 100644 index 000000000..0684eb314 --- /dev/null +++ b/ManiVault/src/actions/VideosAppFeatureAction.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#pragma once + +#include "AppFeatureAction.h" + +#include "actions/ToggleAction.h" + +namespace mv::gui { + +/** + * Videos app feature action class + * + * App feature action class for grouping videos dynamic content settings + * + * Note: This action is developed for internal use only + * + * @author Thomas Kroes + */ +class CORE_EXPORT VideosAppFeatureAction : public AppFeatureAction +{ + Q_OBJECT + +public: + + /** + * Construct with pointer to \p parent object and \p title + * @param parent Pointer to parent object + * @param title Title of the action + */ + Q_INVOKABLE VideosAppFeatureAction(QObject* parent, const QString& title = "Videos"); + +// TODO +//public: // Action getters +// +// const ToggleAction& getTutorialsAction() const { return _tutorialsAction; } +// const ToggleAction& getProjectsAction() const { return _projectsAction; } +// +//private: +// ToggleAction _tutorialsAction; /** Toggle tutorials dynamic content */ +// ToggleAction _projectsAction; /** Toggle projects dynamic content */ +}; + +} + +Q_DECLARE_METATYPE(mv::gui::VideosAppFeatureAction) + +inline const auto videosAppFeatureActionMetaTypeId = qRegisterMetaType("mv::gui::VideosAppFeatureAction"); From 3afaef27409bce5a1f1365eebb08cf8ff1ea9111 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 17:08:23 +0200 Subject: [PATCH 19/37] Group several app features into downloadable content app features --- ManiVault/cmake/CMakeMvSourcesPublic.cmake | 2 + ManiVault/src/AppFeaturesSettingsAction.cpp | 8 +--- ManiVault/src/AppFeaturesSettingsAction.h | 14 ++---- ManiVault/src/actions/AppFeatureAction.cpp | 4 +- .../DownloadableContentAppFeaturesAction.cpp | 26 +++++++++++ .../DownloadableContentAppFeaturesAction.h | 45 +++++++++++++++++++ ManiVault/src/actions/ToggleAction.cpp | 1 + 7 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp create mode 100644 ManiVault/src/actions/DownloadableContentAppFeaturesAction.h diff --git a/ManiVault/cmake/CMakeMvSourcesPublic.cmake b/ManiVault/cmake/CMakeMvSourcesPublic.cmake index 19c7d2819..fb153f8ae 100644 --- a/ManiVault/cmake/CMakeMvSourcesPublic.cmake +++ b/ManiVault/cmake/CMakeMvSourcesPublic.cmake @@ -320,6 +320,7 @@ set(PUBLIC_APP_FEATURE_ACTIONS_HEADERS src/actions/TutorialsAppFeatureAction.h src/actions/ProjectsAppFeatureAction.h src/actions/VideosAppFeatureAction.h + src/actions/DownloadableContentAppFeaturesAction.h ) set(PUBLIC_APP_FEATURE_ACTIONS_SOURCES @@ -328,6 +329,7 @@ set(PUBLIC_APP_FEATURE_ACTIONS_SOURCES src/actions/TutorialsAppFeatureAction.cpp src/actions/ProjectsAppFeatureAction.cpp src/actions/VideosAppFeatureAction.cpp + src/actions/DownloadableContentAppFeaturesAction.cpp ) set(PUBLIC_APP_FEATURE_ACTIONS_FILES diff --git a/ManiVault/src/AppFeaturesSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp index e19305f57..cbf31f457 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.cpp +++ b/ManiVault/src/AppFeaturesSettingsAction.cpp @@ -10,18 +10,14 @@ namespace mv::gui AppFeaturesSettingsAction::AppFeaturesSettingsAction(QObject* parent) : GlobalSettingsGroupAction(parent, "App Features", false), _errorLoggingAppFeatureAction(this), - _projectsAppFeatureAction(this), - _tutorialsAppFeatureAction(this), - _videosAppFeatureAction(this) + _downloadableContentAppFeaturesAction(this) { #ifdef ERROR_LOGGING addAction(&_errorLoggingAppFeatureAction); #endif - addAction(&_projectsAppFeatureAction); - addAction(&_tutorialsAppFeatureAction); - addAction(&_videosAppFeatureAction); + addAction(&_downloadableContentAppFeaturesAction); } /* diff --git a/ManiVault/src/AppFeaturesSettingsAction.h b/ManiVault/src/AppFeaturesSettingsAction.h index b3e2d4456..f242675f3 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.h +++ b/ManiVault/src/AppFeaturesSettingsAction.h @@ -7,9 +7,7 @@ #include "GlobalSettingsGroupAction.h" #include "actions/ErrorLoggingAppFeatureAction.h" -#include "actions/ProjectsAppFeatureAction.h" -#include "actions/TutorialsAppFeatureAction.h" -#include "actions/VideosAppFeatureAction.h" +#include "actions/DownloadableContentAppFeaturesAction.h" namespace mv::gui { @@ -34,15 +32,11 @@ class CORE_EXPORT AppFeaturesSettingsAction final : public GlobalSettingsGroupAc public: // Action getters const ErrorLoggingAppFeatureAction& getErrorLoggingAppFeatureAction() const { return _errorLoggingAppFeatureAction; } - const ProjectsAppFeatureAction& getProjectsAppFeatureAction() const { return _projectsAppFeatureAction; } - const TutorialsAppFeatureAction& getTutorialsAppFeatureAction() const { return _tutorialsAppFeatureAction; } - const VideosAppFeatureAction& getVideosAppFeatureAction() const { return _videosAppFeatureAction; } + const DownloadableContentAppFeaturesAction& getDownloadableContentAppFeaturesAction() const { return _downloadableContentAppFeaturesAction; } private: - ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ - ProjectsAppFeatureAction _projectsAppFeatureAction; /** App feature action for configuring projects dynamic content */ - TutorialsAppFeatureAction _tutorialsAppFeatureAction; /** App feature action for configuring tutorials dynamic content */ - VideosAppFeatureAction _videosAppFeatureAction; /** App feature action for configuring videos dynamic content */ + ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ + DownloadableContentAppFeaturesAction _downloadableContentAppFeaturesAction; /** App feature action for configuring downloadable dynamic content */ }; } diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index f6114586e..b1dbd9a0d 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -11,10 +11,12 @@ namespace mv::gui { AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : HorizontalGroupAction(parent, title), _enabledAction(this, "Enabled", false), - _settingsAction(this, "Settings") + _settingsAction(this, QString("App Feature: %1").arg(title)) { setShowLabels(false); + _enabledAction.setDefaultWidgetFlags(ToggleAction::WidgetFlag::ToggleImage); + _settingsAction.setIconByName("gear"); _settingsAction.setToolTip(QString("%1 settings").arg(title)); _settingsAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); diff --git a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp new file mode 100644 index 000000000..34dd252ad --- /dev/null +++ b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#include "DownloadableContentAppFeaturesAction.h" + +namespace mv::gui +{ + +DownloadableContentAppFeaturesAction::DownloadableContentAppFeaturesAction(QObject* parent) : + VerticalGroupAction(parent, "Downloadable content", false), + _projectsAppFeatureAction(this), + _tutorialsAppFeatureAction(this), + _videosAppFeatureAction(this) +{ + + setShowLabels(false); + + setDefaultWidgetFlag(GroupAction::WidgetFlag::NoMargins); + + addAction(&_projectsAppFeatureAction); + addAction(&_tutorialsAppFeatureAction); + addAction(&_videosAppFeatureAction); +} + +} diff --git a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.h b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.h new file mode 100644 index 000000000..91e783b76 --- /dev/null +++ b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// A corresponding LICENSE file is located in the root directory of this source tree +// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) + +#pragma once + +#include "actions/VerticalGroupAction.h" + +#include "actions/ProjectsAppFeatureAction.h" +#include "actions/TutorialsAppFeatureAction.h" +#include "actions/VideosAppFeatureAction.h" + +namespace mv::gui +{ + +/** + * Downloadable content app features action class + * + * Groups all app features for downloadable content + * + * @author Thomas Kroes + */ +class CORE_EXPORT DownloadableContentAppFeaturesAction final : public VerticalGroupAction +{ +public: + + /** + * Construct with pointer to \p parent object + * @param parent Pointer to parent object + */ + DownloadableContentAppFeaturesAction(QObject* parent); + +public: // Action getters + + ProjectsAppFeatureAction& getProjectsAppFeatureAction() { return _projectsAppFeatureAction; } + TutorialsAppFeatureAction& getTutorialsAppFeatureAction() { return _tutorialsAppFeatureAction; } + VideosAppFeatureAction& getVideosAppFeatureAction() { return _videosAppFeatureAction; } + +private: + ProjectsAppFeatureAction _projectsAppFeatureAction; /** App feature action for configuring projects dynamic content */ + TutorialsAppFeatureAction _tutorialsAppFeatureAction; /** App feature action for configuring tutorials dynamic content */ + VideosAppFeatureAction _videosAppFeatureAction; /** App feature action for configuring videos dynamic content */ +}; + +} diff --git a/ManiVault/src/actions/ToggleAction.cpp b/ManiVault/src/actions/ToggleAction.cpp index d243d6ea6..2f7f5c4bd 100644 --- a/ManiVault/src/actions/ToggleAction.cpp +++ b/ManiVault/src/actions/ToggleAction.cpp @@ -239,6 +239,7 @@ ToggleAction::ToggleImageLabelWidget::ToggleImageLabelWidget(QWidget* parent, To { setAcceptDrops(true); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + setAlignment(Qt::AlignVCenter); const auto updatePixmap = [this]() -> void { setPixmap(QIcon(StyledIcon(_toggleAction->isChecked() ? "toggle-on" : "toggle-off")).pixmap(QSize(20, 20))); From 03025bb0bafcf6952f6d6f29e39a8f6d36f1ae14 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 17:58:36 +0200 Subject: [PATCH 20/37] Work on downloadable content app feature --- ManiVault/src/actions/AppFeatureAction.h | 2 +- .../src/actions/DownloadableContentAppFeaturesAction.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h index 592869053..b44792d15 100644 --- a/ManiVault/src/actions/AppFeatureAction.h +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -43,7 +43,7 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction public: // Action getters - const ToggleAction& getEnabledAction() const { return _enabledAction; } + ToggleAction& getEnabledAction() { return _enabledAction; } private: ToggleAction _enabledAction; /** Settings action for the app feature */ diff --git a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp index 34dd252ad..7d7194a77 100644 --- a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp +++ b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp @@ -18,6 +18,10 @@ DownloadableContentAppFeaturesAction::DownloadableContentAppFeaturesAction(QObje setDefaultWidgetFlag(GroupAction::WidgetFlag::NoMargins); + _projectsAppFeatureAction.getEnabledAction().setDefaultWidgetFlag(ToggleAction::Text); + _tutorialsAppFeatureAction.getEnabledAction().setDefaultWidgetFlag(ToggleAction::Text); + _videosAppFeatureAction.getEnabledAction().setDefaultWidgetFlag(ToggleAction::Text); + addAction(&_projectsAppFeatureAction); addAction(&_tutorialsAppFeatureAction); addAction(&_videosAppFeatureAction); From fa70ba77fff4a18d4611f3cb4002f9792275639f Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Fri, 2 May 2025 18:23:04 +0200 Subject: [PATCH 21/37] Fix downloadable content --- ManiVault/src/actions/AppFeatureAction.cpp | 2 +- .../src/actions/DownloadableContentAppFeaturesAction.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index b1dbd9a0d..0fd50f088 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -10,7 +10,7 @@ namespace mv::gui { AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : HorizontalGroupAction(parent, title), - _enabledAction(this, "Enabled", false), + _enabledAction(this, title, false), _settingsAction(this, QString("App Feature: %1").arg(title)) { setShowLabels(false); diff --git a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp index 7d7194a77..672a71617 100644 --- a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp +++ b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp @@ -18,9 +18,9 @@ DownloadableContentAppFeaturesAction::DownloadableContentAppFeaturesAction(QObje setDefaultWidgetFlag(GroupAction::WidgetFlag::NoMargins); - _projectsAppFeatureAction.getEnabledAction().setDefaultWidgetFlag(ToggleAction::Text); - _tutorialsAppFeatureAction.getEnabledAction().setDefaultWidgetFlag(ToggleAction::Text); - _videosAppFeatureAction.getEnabledAction().setDefaultWidgetFlag(ToggleAction::Text); + _projectsAppFeatureAction.getEnabledAction().setDefaultWidgetFlags(ToggleAction::ToggleImageText); + _tutorialsAppFeatureAction.getEnabledAction().setDefaultWidgetFlags(ToggleAction::ToggleImageText); + _videosAppFeatureAction.getEnabledAction().setDefaultWidgetFlags(ToggleAction::ToggleImageText); addAction(&_projectsAppFeatureAction); addAction(&_tutorialsAppFeatureAction); From b519a4810d09c736cb90fbd8f8e76f7b9e0d33a1 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 6 May 2025 09:38:42 +0200 Subject: [PATCH 22/37] Work on app feature action and some re-structuring --- ManiVault/cmake/CMakeMvSourcesPublic.cmake | 2 - ManiVault/src/AppFeaturesSettingsAction.cpp | 15 ++++- ManiVault/src/AppFeaturesSettingsAction.h | 14 ++-- ManiVault/src/actions/AppFeatureAction.cpp | 65 ++++++++++++++++++- ManiVault/src/actions/AppFeatureAction.h | 56 +++++++++++++++- .../DownloadableContentAppFeaturesAction.cpp | 30 --------- .../DownloadableContentAppFeaturesAction.h | 45 ------------- .../actions/ErrorLoggingAppFeatureAction.cpp | 1 + .../src/actions/ProjectsAppFeatureAction.cpp | 1 + .../src/actions/TutorialsAppFeatureAction.cpp | 1 + .../src/actions/VideosAppFeatureAction.cpp | 1 + 11 files changed, 143 insertions(+), 88 deletions(-) delete mode 100644 ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp delete mode 100644 ManiVault/src/actions/DownloadableContentAppFeaturesAction.h diff --git a/ManiVault/cmake/CMakeMvSourcesPublic.cmake b/ManiVault/cmake/CMakeMvSourcesPublic.cmake index fb153f8ae..19c7d2819 100644 --- a/ManiVault/cmake/CMakeMvSourcesPublic.cmake +++ b/ManiVault/cmake/CMakeMvSourcesPublic.cmake @@ -320,7 +320,6 @@ set(PUBLIC_APP_FEATURE_ACTIONS_HEADERS src/actions/TutorialsAppFeatureAction.h src/actions/ProjectsAppFeatureAction.h src/actions/VideosAppFeatureAction.h - src/actions/DownloadableContentAppFeaturesAction.h ) set(PUBLIC_APP_FEATURE_ACTIONS_SOURCES @@ -329,7 +328,6 @@ set(PUBLIC_APP_FEATURE_ACTIONS_SOURCES src/actions/TutorialsAppFeatureAction.cpp src/actions/ProjectsAppFeatureAction.cpp src/actions/VideosAppFeatureAction.cpp - src/actions/DownloadableContentAppFeaturesAction.cpp ) set(PUBLIC_APP_FEATURE_ACTIONS_FILES diff --git a/ManiVault/src/AppFeaturesSettingsAction.cpp b/ManiVault/src/AppFeaturesSettingsAction.cpp index cbf31f457..fe2f08491 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.cpp +++ b/ManiVault/src/AppFeaturesSettingsAction.cpp @@ -4,20 +4,31 @@ #include "AppFeaturesSettingsAction.h" +#include "actions/VerticalGroupAction.h" + namespace mv::gui { AppFeaturesSettingsAction::AppFeaturesSettingsAction(QObject* parent) : GlobalSettingsGroupAction(parent, "App Features", false), _errorLoggingAppFeatureAction(this), - _downloadableContentAppFeaturesAction(this) + _projectsAppFeatureAction(this), + _tutorialsAppFeatureAction(this), + _videosAppFeatureAction(this) { #ifdef ERROR_LOGGING addAction(&_errorLoggingAppFeatureAction); #endif - addAction(&_downloadableContentAppFeaturesAction); + auto downloadableContentAppFeaturesAction = new VerticalGroupAction(this, "Downloadable Content"); + + downloadableContentAppFeaturesAction->setShowLabels(false); + downloadableContentAppFeaturesAction->setDefaultWidgetFlag(GroupAction::WidgetFlag::NoMargins); + + addAction(&_projectsAppFeatureAction); + addAction(&_tutorialsAppFeatureAction); + addAction(&_videosAppFeatureAction); } /* diff --git a/ManiVault/src/AppFeaturesSettingsAction.h b/ManiVault/src/AppFeaturesSettingsAction.h index f242675f3..948f0e254 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.h +++ b/ManiVault/src/AppFeaturesSettingsAction.h @@ -7,7 +7,9 @@ #include "GlobalSettingsGroupAction.h" #include "actions/ErrorLoggingAppFeatureAction.h" -#include "actions/DownloadableContentAppFeaturesAction.h" +#include "actions/ProjectsAppFeatureAction.h" +#include "actions/TutorialsAppFeatureAction.h" +#include "actions/VideosAppFeatureAction.h" namespace mv::gui { @@ -32,11 +34,15 @@ class CORE_EXPORT AppFeaturesSettingsAction final : public GlobalSettingsGroupAc public: // Action getters const ErrorLoggingAppFeatureAction& getErrorLoggingAppFeatureAction() const { return _errorLoggingAppFeatureAction; } - const DownloadableContentAppFeaturesAction& getDownloadableContentAppFeaturesAction() const { return _downloadableContentAppFeaturesAction; } + ProjectsAppFeatureAction& getProjectsAppFeatureAction() { return _projectsAppFeatureAction; } + TutorialsAppFeatureAction& getTutorialsAppFeatureAction() { return _tutorialsAppFeatureAction; } + VideosAppFeatureAction& getVideosAppFeatureAction() { return _videosAppFeatureAction; } private: - ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ - DownloadableContentAppFeaturesAction _downloadableContentAppFeaturesAction; /** App feature action for configuring downloadable dynamic content */ + ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ + ProjectsAppFeatureAction _projectsAppFeatureAction; /** App feature action for configuring projects dynamic content */ + TutorialsAppFeatureAction _tutorialsAppFeatureAction; /** App feature action for configuring tutorials dynamic content */ + VideosAppFeatureAction _videosAppFeatureAction; /** App feature action for configuring videos dynamic content */ }; } diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 0fd50f088..4fe23be5f 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -11,34 +11,93 @@ namespace mv::gui { AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : HorizontalGroupAction(parent, title), _enabledAction(this, title, false), + _summaryAction(this, "Summary"), + _userHasOptedAction(this, "User has opted", false), + _descriptionAction(this, "Description"), _settingsAction(this, QString("App Feature: %1").arg(title)) { setShowLabels(false); + //_enabledAction.setSettingsPrefix(QString("AppFeatures/%1/Enabled").arg(title)); + //_userHasOptedAction.setSettingsPrefix(QString("AppFeatures/%1/Enabled").arg(title)); + _enabledAction.setDefaultWidgetFlags(ToggleAction::WidgetFlag::ToggleImage); + _summaryAction.setEnabled(false); + _summaryAction.setDefaultWidgetFlags(StringAction::WidgetFlag::LineEdit); + _summaryAction.setToolTip(QString("%1 summary").arg(title)); + _summaryAction.setStretch(1); + + _descriptionAction.setIconByName("circle-info"); + _descriptionAction.setToolTip(QString("%1 settings").arg(title)); + _descriptionAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); + _settingsAction.setIconByName("gear"); _settingsAction.setToolTip(QString("%1 settings").arg(title)); _settingsAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); HorizontalGroupAction::addAction(&_enabledAction); + HorizontalGroupAction::addAction(&_summaryAction); + HorizontalGroupAction::addAction(&_descriptionAction); HorizontalGroupAction::addAction(&_settingsAction); - const auto updateSettingsActionReadOnly = [this]() -> void { + const auto updateActionsReadOnly = [this]() -> void { _settingsAction.setEnabled(_enabledAction.isChecked()); + _descriptionAction.setEnabled(_enabledAction.isChecked()); }; - updateSettingsActionReadOnly(); + updateActionsReadOnly(); - connect(&_enabledAction, &ToggleAction::toggled, this, updateSettingsActionReadOnly); + connect(&_enabledAction, &ToggleAction::toggled, this, updateActionsReadOnly); connect(&_enabledAction, &ToggleAction::toggled, this, [this](bool toggled) -> void { mv::help().addNotification("App Feature", QString("%1 app feature has been %2").arg(text(), toggled ? "enabled" : "disabled"), StyledIcon(toggled ? "toggle-on" : "toggle-off")); }); + + if (hasSetting(PrefixType::UserHasOpted)) { + if (getUserHasOptedFromSettings()) { + _enabledAction.setChecked(getEnabledFromSettings()); + } + } } void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags /*= -1*/, WidgetConfigurationFunction widgetConfigurationFunction /*= WidgetConfigurationFunction()*/, bool load) { _settingsAction.addAction(action, widgetFlags, widgetConfigurationFunction, load); } + +QString AppFeatureAction::getSettingsPrefix(const PrefixType& prefixType) const +{ + switch (prefixType) { + case PrefixType::Enabled: + return QString("AppFeatures/%1/Enabled").arg(text()); + + case PrefixType::UserHasOpted: + return QString("AppFeatures/%1/UserHasOpted").arg(text()); + } + + return {}; +} + +bool AppFeatureAction::hasSetting(const PrefixType& prefixType) const +{ + return Application::current()->hasSetting(getSettingsPrefix(prefixType)); +} + +bool AppFeatureAction::getEnabledFromSettings() const +{ + if (hasSetting(PrefixType::Enabled)) + return Application::current()->getSetting(getSettingsPrefix(PrefixType::Enabled)).toBool(); + + return false; +} + +bool AppFeatureAction::getUserHasOptedFromSettings() const +{ + if (hasSetting(PrefixType::UserHasOpted)) + return Application::current()->getSetting(getSettingsPrefix(PrefixType::UserHasOpted)).toBool(); + + return false; +} + } diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h index b44792d15..d8ef83d1b 100644 --- a/ManiVault/src/actions/AppFeatureAction.h +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -23,6 +23,15 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction { Q_OBJECT +public: + + /** Enum for the prefix type */ + enum class PrefixType + { + Enabled, /** Prefix for the enabled type */ + UserHasOpted, /** Prefix for the user has opted type */ + }; + public: /** @@ -41,13 +50,56 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction */ void addAction(WidgetAction* action, std::int32_t widgetFlags = -1, WidgetConfigurationFunction widgetConfigurationFunction = WidgetConfigurationFunction(), bool load = true) override; +protected: // Settings + + /** + * Get the settings prefix for the given \p prefixType + * @param prefixType Prefix type to get the settings prefix for + * @return Settings prefix + */ + QString getSettingsPrefix(const PrefixType& prefixType) const; + + /** + * Get whether a setting is available + * @param prefixType Prefix type to check + * @return Pointer to the settings action + */ + bool hasSetting(const PrefixType& prefixType) const; + +private: // Settings + + /** + * Get whether the feature is on or off from settings + * @return Boolean determining whether the feature is on or off (off if the setting is not found) + */ + bool getEnabledFromSettings() const; + + /** + * Get whether the user has opted for the feature or not from settings + * @return Boolean determining whether the user has opted for the feature or not (off if the setting is not found) + */ + bool getUserHasOptedFromSettings() const; + public: // Action getters + const ToggleAction& getEnabledAction() const { return _enabledAction; } + const StringAction& getSummaryAction() const { return _summaryAction; } + const ToggleAction& getUserHasOptedAction() const { return _userHasOptedAction; } + +protected: // Action getters + ToggleAction& getEnabledAction() { return _enabledAction; } + StringAction& getSummaryAction() { return _summaryAction; } + ToggleAction& getUserHasOptedAction() { return _userHasOptedAction; } private: - ToggleAction _enabledAction; /** Settings action for the app feature */ - VerticalGroupAction _settingsAction; /** Vertical group action for settings */ + ToggleAction _enabledAction; /** Determines whether the app feature is enabled or not */ + StringAction _summaryAction; /** Short one-liner that describes the app feature */ + ToggleAction _userHasOptedAction; /** Determines if the user has given permission to use the app feature */ + VerticalGroupAction _descriptionAction; /** Vertical group action for app feature description */ + VerticalGroupAction _settingsAction; /** Vertical group action for app feature settings */ + + friend class AppFeaturesSettingsAction; // Allow access to private members }; } diff --git a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp deleted file mode 100644 index 672a71617..000000000 --- a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// A corresponding LICENSE file is located in the root directory of this source tree -// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) - -#include "DownloadableContentAppFeaturesAction.h" - -namespace mv::gui -{ - -DownloadableContentAppFeaturesAction::DownloadableContentAppFeaturesAction(QObject* parent) : - VerticalGroupAction(parent, "Downloadable content", false), - _projectsAppFeatureAction(this), - _tutorialsAppFeatureAction(this), - _videosAppFeatureAction(this) -{ - - setShowLabels(false); - - setDefaultWidgetFlag(GroupAction::WidgetFlag::NoMargins); - - _projectsAppFeatureAction.getEnabledAction().setDefaultWidgetFlags(ToggleAction::ToggleImageText); - _tutorialsAppFeatureAction.getEnabledAction().setDefaultWidgetFlags(ToggleAction::ToggleImageText); - _videosAppFeatureAction.getEnabledAction().setDefaultWidgetFlags(ToggleAction::ToggleImageText); - - addAction(&_projectsAppFeatureAction); - addAction(&_tutorialsAppFeatureAction); - addAction(&_videosAppFeatureAction); -} - -} diff --git a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.h b/ManiVault/src/actions/DownloadableContentAppFeaturesAction.h deleted file mode 100644 index 91e783b76..000000000 --- a/ManiVault/src/actions/DownloadableContentAppFeaturesAction.h +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// A corresponding LICENSE file is located in the root directory of this source tree -// Copyright (C) 2023 BioVault (Biomedical Visual Analytics Unit LUMC - TU Delft) - -#pragma once - -#include "actions/VerticalGroupAction.h" - -#include "actions/ProjectsAppFeatureAction.h" -#include "actions/TutorialsAppFeatureAction.h" -#include "actions/VideosAppFeatureAction.h" - -namespace mv::gui -{ - -/** - * Downloadable content app features action class - * - * Groups all app features for downloadable content - * - * @author Thomas Kroes - */ -class CORE_EXPORT DownloadableContentAppFeaturesAction final : public VerticalGroupAction -{ -public: - - /** - * Construct with pointer to \p parent object - * @param parent Pointer to parent object - */ - DownloadableContentAppFeaturesAction(QObject* parent); - -public: // Action getters - - ProjectsAppFeatureAction& getProjectsAppFeatureAction() { return _projectsAppFeatureAction; } - TutorialsAppFeatureAction& getTutorialsAppFeatureAction() { return _tutorialsAppFeatureAction; } - VideosAppFeatureAction& getVideosAppFeatureAction() { return _videosAppFeatureAction; } - -private: - ProjectsAppFeatureAction _projectsAppFeatureAction; /** App feature action for configuring projects dynamic content */ - TutorialsAppFeatureAction _tutorialsAppFeatureAction; /** App feature action for configuring tutorials dynamic content */ - VideosAppFeatureAction _videosAppFeatureAction; /** App feature action for configuring videos dynamic content */ -}; - -} diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp index 55b979d43..af0226f67 100644 --- a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp @@ -9,6 +9,7 @@ namespace mv::gui { ErrorLoggingAppFeatureAction::ErrorLoggingAppFeatureAction(QObject* parent, const QString& title /*= "Error Logging"*/) : AppFeatureAction(parent, title) { + getSummaryAction().setString("Send anonymous crash reports to improve the application"); } } diff --git a/ManiVault/src/actions/ProjectsAppFeatureAction.cpp b/ManiVault/src/actions/ProjectsAppFeatureAction.cpp index 5f0ad4d90..a45c7ba78 100644 --- a/ManiVault/src/actions/ProjectsAppFeatureAction.cpp +++ b/ManiVault/src/actions/ProjectsAppFeatureAction.cpp @@ -9,6 +9,7 @@ namespace mv::gui { ProjectsAppFeatureAction::ProjectsAppFeatureAction(QObject* parent, const QString& title /*= "Projects"*/) : AppFeatureAction(parent, title) { + getSummaryAction().setString("Allow ManiVault Studio to download projects"); } } diff --git a/ManiVault/src/actions/TutorialsAppFeatureAction.cpp b/ManiVault/src/actions/TutorialsAppFeatureAction.cpp index bb874d329..07fafc0ef 100644 --- a/ManiVault/src/actions/TutorialsAppFeatureAction.cpp +++ b/ManiVault/src/actions/TutorialsAppFeatureAction.cpp @@ -9,6 +9,7 @@ namespace mv::gui { TutorialsAppFeatureAction::TutorialsAppFeatureAction(QObject* parent, const QString& title /*= "Tutorials"*/) : AppFeatureAction(parent, title) { + getSummaryAction().setString("Allow ManiVault Studio to download learning center tutorial content"); } } diff --git a/ManiVault/src/actions/VideosAppFeatureAction.cpp b/ManiVault/src/actions/VideosAppFeatureAction.cpp index d176e1625..f6dfbe003 100644 --- a/ManiVault/src/actions/VideosAppFeatureAction.cpp +++ b/ManiVault/src/actions/VideosAppFeatureAction.cpp @@ -9,6 +9,7 @@ namespace mv::gui { VideosAppFeatureAction::VideosAppFeatureAction(QObject* parent, const QString& title /*= "Videos"*/) : AppFeatureAction(parent, title) { + getSummaryAction().setString("Allow ManiVault Studio to download data for learning center videos."); } } From 3d4e8da8d211538bc4fee3aa4d487225368d23fc Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 6 May 2025 11:20:19 +0200 Subject: [PATCH 23/37] App featur action is working properly now - Added summary item - Added HTML description --- ManiVault/res/ResourcesCore.qrc | 5 +- .../res/html/AppFeatureErrorLogging.html | 20 ++++++++ ManiVault/res/html/AppFeatureProjects.html | 20 ++++++++ ManiVault/res/html/AppFeatureTutorials.html | 20 ++++++++ ManiVault/res/html/AppFeatureVideos.html | 14 ++++++ ManiVault/res/html/AppFeatures.html | 37 --------------- ManiVault/src/actions/AppFeatureAction.cpp | 25 ++++++++++ ManiVault/src/actions/AppFeatureAction.h | 14 ++++-- .../actions/ErrorLoggingAppFeatureAction.cpp | 9 ++++ .../src/actions/ProjectsAppFeatureAction.cpp | 2 + ManiVault/src/actions/StringAction.cpp | 47 +++++++++++++++++++ ManiVault/src/actions/StringAction.h | 16 +++++++ .../src/actions/TutorialsAppFeatureAction.cpp | 2 + .../src/actions/VideosAppFeatureAction.cpp | 2 + 14 files changed, 192 insertions(+), 41 deletions(-) create mode 100644 ManiVault/res/html/AppFeatureErrorLogging.html create mode 100644 ManiVault/res/html/AppFeatureProjects.html create mode 100644 ManiVault/res/html/AppFeatureTutorials.html create mode 100644 ManiVault/res/html/AppFeatureVideos.html delete mode 100644 ManiVault/res/html/AppFeatures.html diff --git a/ManiVault/res/ResourcesCore.qrc b/ManiVault/res/ResourcesCore.qrc index b97615d4b..95eb90262 100644 --- a/ManiVault/res/ResourcesCore.qrc +++ b/ManiVault/res/ResourcesCore.qrc @@ -82,6 +82,9 @@ html/markdown.html - html/AppFeatures.html + html/AppFeatureErrorLogging.html + html/AppFeatureProjects.html + html/AppFeatureTutorials.html + html/AppFeatureVideos.html diff --git a/ManiVault/res/html/AppFeatureErrorLogging.html b/ManiVault/res/html/AppFeatureErrorLogging.html new file mode 100644 index 000000000..6025f211c --- /dev/null +++ b/ManiVault/res/html/AppFeatureErrorLogging.html @@ -0,0 +1,20 @@ + + + +

Automated error reporting

+ +

ManiVault Studio can automatically report bugs and crashes using Sentry. This might help us fix issues faster and improve the application for everyone.

+

What we collect:

+
    +
  • Details about errors (e.g., crash logs, stack traces).
  • +
  • Basic system information (e.g., operating system, app version).
  • +
  • Contact details (if you opt to supply them).
  • +
+

What we don’t collect:

+
    +
  • Personal files like projects or research data.
  • +
  • Sensitive data like passwords.
  • +
+

You can opt out of automated error reporting at any time in the application settings.

+ + diff --git a/ManiVault/res/html/AppFeatureProjects.html b/ManiVault/res/html/AppFeatureProjects.html new file mode 100644 index 000000000..e1340302a --- /dev/null +++ b/ManiVault/res/html/AppFeatureProjects.html @@ -0,0 +1,20 @@ + + + +

Projects

+

ManiVault Studio can optionally download dynamic projects content. When you enable this feature, the application connects to servers to:

+
    +
  • Fetch available projects listings.
  • +
  • Download projects.
  • +
+

You will find this feature at the start page of ManiVault Studio.

+

Projects listings and projects might originate from:

+
    +
  • Servers hosted by the ManiVault Studio team.
  • +
  • Servers hosted by third-party plugin developers (i.e. example projects accompanied by plugins).
  • +
+

Please note that we do not track which projects you download.

+

If you prefer not to allow automatic downloads of proejcts, you can disable this feature at any time in the application settings.

+ + + diff --git a/ManiVault/res/html/AppFeatureTutorials.html b/ManiVault/res/html/AppFeatureTutorials.html new file mode 100644 index 000000000..d29c8c288 --- /dev/null +++ b/ManiVault/res/html/AppFeatureTutorials.html @@ -0,0 +1,20 @@ + + + +

Learning center tutorials

+

As part of the learning center, ManiVault Studio can optionally download dynamic tutorial content. When you enable this feature, the application connects to servers to:

+
    +
  • Fetch available tutorials listings.
  • +
  • Download tutorial projects.
  • +
+

You will find this feature at the start page of ManiVault Studio and in the help menu.

+

Tutorials listings and projects might originate from:

+
    +
  • Servers hosted by the ManiVault Studio team.
  • +
  • Servers hosted by third-party plugin developers if the plugins provide tutorials.
  • +
+

+

Please note that we do not track which tutorials you download.

+

If you prefer not to allow automatic downloads of start page content, you can disable this feature at any time in the application settings.

+ + diff --git a/ManiVault/res/html/AppFeatureVideos.html b/ManiVault/res/html/AppFeatureVideos.html new file mode 100644 index 000000000..61282b71b --- /dev/null +++ b/ManiVault/res/html/AppFeatureVideos.html @@ -0,0 +1,14 @@ + + + +

Learning center videos

+

As part of the learning center, ManiVault Studio can optionally download dynamic video content. When you enable this feature, the application connects to servers to fetch available videos listings (the videos are watched by opening a browser window). Videos listings might originate from: +

    +
  • Servers hosted by the ManiVault Studio team.
  • +
  • Servers hosted by third-party plugin developers.
  • +
+

+

Please note that we do not track which videos you view.

+

If you prefer not to allow automatic downloads of videos content, you can disable this feature at any time in the application settings.

+ + diff --git a/ManiVault/res/html/AppFeatures.html b/ManiVault/res/html/AppFeatures.html deleted file mode 100644 index d8d3c3814..000000000 --- a/ManiVault/res/html/AppFeatures.html +++ /dev/null @@ -1,37 +0,0 @@ - - - -

Automated error reporting and start page content

- -

ManiVault Studio can automatically report bugs and crashes using Sentry. This might help us fix issues faster and improve the application for everyone.

- -

What we collect:

-
    -
  • Details about errors (e.g., crash logs, stack traces).
  • -
  • Basic system information (e.g., operating system, app version).
  • -
  • Contact details (if you opt to supply them).
  • -
- -

What we don’t collect:

-
    -
  • Personal files like projects or research data.
  • -
  • Sensitive data like passwords.
  • -
- -

You can opt out of automated error reporting at any time in the application settings.

- -

Start page content

- -

ManiVault Studio can optionally download dynamic content for the application's start page. This content includes:

- -
    -
  • A curated list of tutorials, which can be downloaded and opened directly.
  • -
  • A curated list of projects, which can be downloaded and opened directly.
  • -
- -

When you enable this feature, the application connects to ManiVault Studio servers to fetch available tutorials and project listings. We do not track which tutorials or projects you view or download.

- -

If you prefer not to allow automatic downloads of start page content, you can disable this feature in the application settings.

- - - diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 4fe23be5f..2517698dd 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -4,6 +4,8 @@ #include "AppFeatureAction.h" +#include + using namespace mv::util; namespace mv::gui { @@ -31,6 +33,16 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : _descriptionAction.setIconByName("circle-info"); _descriptionAction.setToolTip(QString("%1 settings").arg(title)); _descriptionAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); + _descriptionAction.setDefaultWidgetFlags(StringAction::WidgetFlag::TextBrowser); + _descriptionAction.setPopupSizeHint(QSize(550, 400)); + + //_descriptionAction.setWidgetConfigurationFunction([this](WidgetAction* action, QWidget* widget) -> void { + // auto textEdit = widget->findChild("TextEdit"); + + // textEdit->setAcceptRichText(true); + // textEdit->setHtml(_descriptionAction.getString()); + // textEdit->setHtml("

Hello

This is bold text

"); + //}); _settingsAction.setIconByName("gear"); _settingsAction.setToolTip(QString("%1 settings").arg(title)); @@ -84,6 +96,19 @@ bool AppFeatureAction::hasSetting(const PrefixType& prefixType) const return Application::current()->hasSetting(getSettingsPrefix(prefixType)); } +void AppFeatureAction::loadDescriptionFromResource(const QString& resourceLocation) +{ + QFile appFeatureHtmlFile(resourceLocation); + + if (appFeatureHtmlFile.open(QIODevice::ReadOnly)) { + _descriptionAction.setString(appFeatureHtmlFile.readAll()); + appFeatureHtmlFile.close(); + } + else { + qWarning() << QString("No description available for %1: %2").arg(text(), appFeatureHtmlFile.errorString()); + } +} + bool AppFeatureAction::getEnabledFromSettings() const { if (hasSetting(PrefixType::Enabled)) diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h index d8ef83d1b..2acace155 100644 --- a/ManiVault/src/actions/AppFeatureAction.h +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -50,7 +50,7 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction */ void addAction(WidgetAction* action, std::int32_t widgetFlags = -1, WidgetConfigurationFunction widgetConfigurationFunction = WidgetConfigurationFunction(), bool load = true) override; -protected: // Settings +protected: /** * Get the settings prefix for the given \p prefixType @@ -66,6 +66,12 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction */ bool hasSetting(const PrefixType& prefixType) const; + /** + * Load the description from \p resourceName + * @param resourceLocation Location of the resource to load + */ + void loadDescriptionFromResource(const QString& resourceLocation); + private: // Settings /** @@ -85,19 +91,21 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction const ToggleAction& getEnabledAction() const { return _enabledAction; } const StringAction& getSummaryAction() const { return _summaryAction; } const ToggleAction& getUserHasOptedAction() const { return _userHasOptedAction; } + const StringAction& getDescriptionAction() const { return _descriptionAction; } protected: // Action getters ToggleAction& getEnabledAction() { return _enabledAction; } StringAction& getSummaryAction() { return _summaryAction; } ToggleAction& getUserHasOptedAction() { return _userHasOptedAction; } + StringAction& getDescriptionAction() { return _descriptionAction; } private: ToggleAction _enabledAction; /** Determines whether the app feature is enabled or not */ StringAction _summaryAction; /** Short one-liner that describes the app feature */ ToggleAction _userHasOptedAction; /** Determines if the user has given permission to use the app feature */ - VerticalGroupAction _descriptionAction; /** Vertical group action for app feature description */ - VerticalGroupAction _settingsAction; /** Vertical group action for app feature settings */ + StringAction _descriptionAction; /** App feature description */ + VerticalGroupAction _settingsAction; /** App feature settings */ friend class AppFeaturesSettingsAction; // Allow access to private members }; diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp index af0226f67..94187c154 100644 --- a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp @@ -9,6 +9,15 @@ namespace mv::gui { ErrorLoggingAppFeatureAction::ErrorLoggingAppFeatureAction(QObject* parent, const QString& title /*= "Error Logging"*/) : AppFeatureAction(parent, title) { + loadDescriptionFromResource(":/HTML/AppFeatureErrorLogging"); + + /*QFile file(":/HTML/AppFeatureErrorLogging"); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Failed to load resource:" << file.errorString(); + } + else { + qDebug() << "Resource loaded successfully."; + }*/ getSummaryAction().setString("Send anonymous crash reports to improve the application"); } diff --git a/ManiVault/src/actions/ProjectsAppFeatureAction.cpp b/ManiVault/src/actions/ProjectsAppFeatureAction.cpp index a45c7ba78..7b34b32f1 100644 --- a/ManiVault/src/actions/ProjectsAppFeatureAction.cpp +++ b/ManiVault/src/actions/ProjectsAppFeatureAction.cpp @@ -9,6 +9,8 @@ namespace mv::gui { ProjectsAppFeatureAction::ProjectsAppFeatureAction(QObject* parent, const QString& title /*= "Projects"*/) : AppFeatureAction(parent, title) { + loadDescriptionFromResource(":/HTML/AppFeatureProjects"); + getSummaryAction().setString("Allow ManiVault Studio to download projects"); } diff --git a/ManiVault/src/actions/StringAction.cpp b/ManiVault/src/actions/StringAction.cpp index 2cfae1e1b..a057f15c6 100644 --- a/ManiVault/src/actions/StringAction.cpp +++ b/ManiVault/src/actions/StringAction.cpp @@ -210,6 +210,9 @@ QWidget* StringAction::getWidget(QWidget* parent, const std::int32_t& widgetFlag if (widgetFlags & WidgetFlag::TextEdit) layout->addWidget(new StringAction::TextEditWidget(parent, this)); + if (widgetFlags & WidgetFlag::TextBrowser) + layout->addWidget(new StringAction::TextBrowserWidget(parent, this)); + widget->setLayout(layout); return widget; @@ -505,4 +508,48 @@ StringAction::TextEditWidget::TextEditWidget(QWidget* parent, StringAction* stri updatePlaceHolderText(); } +StringAction::TextBrowserWidget::TextBrowserWidget(QWidget* parent, StringAction* stringAction) : + QTextEdit(parent) +{ + setObjectName("TextBrowser"); + setAcceptDrops(true); + + const auto updateToolTip = [this, stringAction]() -> void { + setToolTip(stringAction->getString()); + }; + + updateToolTip(); + + connect(stringAction, &QAction::changed, this, updateToolTip); + + const auto updateTextBrowser = [this, stringAction]() { + QSignalBlocker blocker(this); + + const auto cacheCursorPosition = textCursor().position(); + + setHtml(stringAction->getString()); + + auto updateCursor = textCursor(); + + updateCursor.setPosition(cacheCursorPosition); + + setTextCursor(updateCursor); + }; + + const auto updatePlaceHolderText = [this, stringAction]() -> void { + setPlaceholderText(stringAction->getPlaceholderString()); + }; + + connect(stringAction, &StringAction::stringChanged, this, updateTextBrowser); + + connect(stringAction, &StringAction::placeholderStringChanged, this, updatePlaceHolderText); + + connect(this, &QTextEdit::textChanged, this, [this, stringAction]() { + stringAction->setString(toPlainText()); + }); + + updateTextBrowser(); + updatePlaceHolderText(); +} + } diff --git a/ManiVault/src/actions/StringAction.h b/ManiVault/src/actions/StringAction.h index 8a2db779a..a93afc71b 100644 --- a/ManiVault/src/actions/StringAction.h +++ b/ManiVault/src/actions/StringAction.h @@ -38,6 +38,7 @@ class CORE_EXPORT StringAction : public WidgetAction Label = 0x00001, /** Widget includes a label */ LineEdit = 0x00002, /** Widget includes a line edit */ TextEdit = 0x00004, /** Widget includes a text edit */ + TextBrowser = 0x00008, /** Widget includes a text browser */ Default = LineEdit, }; @@ -177,6 +178,21 @@ class CORE_EXPORT StringAction : public WidgetAction friend class StringAction; }; + /** Text browser widget class for multi-line (HTML) strings */ + class CORE_EXPORT TextBrowserWidget : public QTextEdit + { + protected: + + /** + * Constructor + * @param parent Pointer to parent widget + * @param stringAction Pointer to string action + */ + TextBrowserWidget(QWidget* parent, StringAction* stringAction); + + friend class StringAction; + }; + protected: /** diff --git a/ManiVault/src/actions/TutorialsAppFeatureAction.cpp b/ManiVault/src/actions/TutorialsAppFeatureAction.cpp index 07fafc0ef..8671cfabf 100644 --- a/ManiVault/src/actions/TutorialsAppFeatureAction.cpp +++ b/ManiVault/src/actions/TutorialsAppFeatureAction.cpp @@ -9,6 +9,8 @@ namespace mv::gui { TutorialsAppFeatureAction::TutorialsAppFeatureAction(QObject* parent, const QString& title /*= "Tutorials"*/) : AppFeatureAction(parent, title) { + loadDescriptionFromResource(":/HTML/AppFeatureTutorials"); + getSummaryAction().setString("Allow ManiVault Studio to download learning center tutorial content"); } diff --git a/ManiVault/src/actions/VideosAppFeatureAction.cpp b/ManiVault/src/actions/VideosAppFeatureAction.cpp index f6dfbe003..87f4e1869 100644 --- a/ManiVault/src/actions/VideosAppFeatureAction.cpp +++ b/ManiVault/src/actions/VideosAppFeatureAction.cpp @@ -9,6 +9,8 @@ namespace mv::gui { VideosAppFeatureAction::VideosAppFeatureAction(QObject* parent, const QString& title /*= "Videos"*/) : AppFeatureAction(parent, title) { + loadDescriptionFromResource(":/HTML/AppFeatureVideos"); + getSummaryAction().setString("Allow ManiVault Studio to download data for learning center videos."); } From bd32b9381996c34200af35967c51a77c5a51345c Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 6 May 2025 12:50:52 +0200 Subject: [PATCH 24/37] Conditionally hide the settings action --- ManiVault/res/html/AppFeatureProjects.html | 2 +- ManiVault/src/actions/AppFeatureAction.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ManiVault/res/html/AppFeatureProjects.html b/ManiVault/res/html/AppFeatureProjects.html index e1340302a..1336aa048 100644 --- a/ManiVault/res/html/AppFeatureProjects.html +++ b/ManiVault/res/html/AppFeatureProjects.html @@ -14,7 +14,7 @@

Projects

  • Servers hosted by third-party plugin developers (i.e. example projects accompanied by plugins).
  • Please note that we do not track which projects you download.

    -

    If you prefer not to allow automatic downloads of proejcts, you can disable this feature at any time in the application settings.

    +

    If you prefer not to allow automatic downloads of projects, you can disable this feature at any time in the application settings.

    diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 2517698dd..9622307cb 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -34,7 +34,7 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : _descriptionAction.setToolTip(QString("%1 settings").arg(title)); _descriptionAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); _descriptionAction.setDefaultWidgetFlags(StringAction::WidgetFlag::TextBrowser); - _descriptionAction.setPopupSizeHint(QSize(550, 400)); + _descriptionAction.setPopupSizeHint(QSize(550, 350)); //_descriptionAction.setWidgetConfigurationFunction([this](WidgetAction* action, QWidget* widget) -> void { // auto textEdit = widget->findChild("TextEdit"); @@ -44,6 +44,7 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : // textEdit->setHtml("

    Hello

    This is bold text

    "); //}); + _settingsAction.setVisible(false); _settingsAction.setIconByName("gear"); _settingsAction.setToolTip(QString("%1 settings").arg(title)); _settingsAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); @@ -76,6 +77,7 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags /*= -1*/, WidgetConfigurationFunction widgetConfigurationFunction /*= WidgetConfigurationFunction()*/, bool load) { _settingsAction.addAction(action, widgetFlags, widgetConfigurationFunction, load); + _settingsAction.setVisible(true); } QString AppFeatureAction::getSettingsPrefix(const PrefixType& prefixType) const From 7031f86e67af5e76ec1f01bac2876a468b8656c2 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 6 May 2025 12:58:28 +0200 Subject: [PATCH 25/37] Move error logging DSN and other parameters to the error logging app feature --- .../src/actions/ErrorLoggingAppFeatureAction.cpp | 7 ++++++- ManiVault/src/actions/ErrorLoggingAppFeatureAction.h | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp index 94187c154..b4077c704 100644 --- a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp @@ -7,7 +7,9 @@ namespace mv::gui { ErrorLoggingAppFeatureAction::ErrorLoggingAppFeatureAction(QObject* parent, const QString& title /*= "Error Logging"*/) : - AppFeatureAction(parent, title) + AppFeatureAction(parent, title), + _loggingDsnAction(this, "Sentry DSN", "https://211289c773dcc267b1bb536b6c3a23f7@lkebsentry.nl/2"), + _loggingShowCrashReportDialogAction(this, "Show crash report dialog", true) { loadDescriptionFromResource(":/HTML/AppFeatureErrorLogging"); @@ -19,6 +21,9 @@ ErrorLoggingAppFeatureAction::ErrorLoggingAppFeatureAction(QObject* parent, cons qDebug() << "Resource loaded successfully."; }*/ getSummaryAction().setString("Send anonymous crash reports to improve the application"); + + addAction(&_loggingDsnAction); + addAction(&_loggingShowCrashReportDialogAction); } } diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.h b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.h index 9c28e1395..872419003 100644 --- a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.h +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.h @@ -6,6 +6,9 @@ #include "AppFeatureAction.h" +#include "actions/StringAction.h" +#include "actions/ToggleAction.h" + namespace mv::gui { /** @@ -29,6 +32,15 @@ class CORE_EXPORT ErrorLoggingAppFeatureAction : public AppFeatureAction * @param title Title of the action */ Q_INVOKABLE ErrorLoggingAppFeatureAction(QObject* parent, const QString& title = "Error Logging"); + +public: // Action getters + + gui::StringAction& getLoggingDsnAction() { return _loggingDsnAction; } + gui::ToggleAction& getLoggingShowCrashReportDialogAction() { return _loggingShowCrashReportDialogAction; } + +private: + StringAction _loggingDsnAction; /** Error logging data source name action */ + ToggleAction _loggingShowCrashReportDialogAction; /** Toggle crash dialog on/off */ }; } From cdf91d165993842254d66dd09bb453b16221a8c4 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 6 May 2025 13:05:39 +0200 Subject: [PATCH 26/37] Cleanup error logging app feature class --- ManiVault/src/actions/AppFeatureAction.cpp | 13 ++--------- .../actions/ErrorLoggingAppFeatureAction.cpp | 23 +++++++++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 9622307cb..d21f06eb7 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -4,8 +4,6 @@ #include "AppFeatureAction.h" -#include - using namespace mv::util; namespace mv::gui { @@ -16,7 +14,7 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : _summaryAction(this, "Summary"), _userHasOptedAction(this, "User has opted", false), _descriptionAction(this, "Description"), - _settingsAction(this, QString("App Feature: %1").arg(title)) + _settingsAction(this, QString("%1 Settings").arg(title)) { setShowLabels(false); @@ -36,18 +34,11 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : _descriptionAction.setDefaultWidgetFlags(StringAction::WidgetFlag::TextBrowser); _descriptionAction.setPopupSizeHint(QSize(550, 350)); - //_descriptionAction.setWidgetConfigurationFunction([this](WidgetAction* action, QWidget* widget) -> void { - // auto textEdit = widget->findChild("TextEdit"); - - // textEdit->setAcceptRichText(true); - // textEdit->setHtml(_descriptionAction.getString()); - // textEdit->setHtml("

    Hello

    This is bold text

    "); - //}); - _settingsAction.setVisible(false); _settingsAction.setIconByName("gear"); _settingsAction.setToolTip(QString("%1 settings").arg(title)); _settingsAction.setConfigurationFlag(ConfigurationFlag::ForceCollapsedInGroup); + _settingsAction.setPopupSizeHint(QSize(400, 10)); HorizontalGroupAction::addAction(&_enabledAction); HorizontalGroupAction::addAction(&_summaryAction); diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp index b4077c704..2ced5da37 100644 --- a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp @@ -13,17 +13,26 @@ ErrorLoggingAppFeatureAction::ErrorLoggingAppFeatureAction(QObject* parent, cons { loadDescriptionFromResource(":/HTML/AppFeatureErrorLogging"); - /*QFile file(":/HTML/AppFeatureErrorLogging"); - if (!file.open(QIODevice::ReadOnly)) { - qWarning() << "Failed to load resource:" << file.errorString(); - } - else { - qDebug() << "Resource loaded successfully."; - }*/ getSummaryAction().setString("Send anonymous crash reports to improve the application"); + _loggingDsnAction.setSettingsPrefix("AppFeatures/Logging/DSN"); + _loggingDsnAction.setToolTip("The Sentry error logging data source name"); + _loggingDsnAction.getValidator().setRegularExpression(QRegularExpression(R"(^https?://[a-f0-9]{32}@[a-z0-9\.-]+(:\d+)?/[\d]+$)")); + + _loggingShowCrashReportDialogAction.setSettingsPrefix("AppFeatures/Logging/ShowCrashReportDialog"); + _loggingShowCrashReportDialogAction.setToolTip("Show the crash report dialog prior to sending an error report"); + addAction(&_loggingDsnAction); addAction(&_loggingShowCrashReportDialogAction); + + const auto allowErrorReportingChanged = [this]() -> void { + _loggingShowCrashReportDialogAction.setEnabled(getEnabledAction().isChecked()); + _loggingDsnAction.setEnabled(getEnabledAction().isChecked()); + }; + + allowErrorReportingChanged(); + + connect(&getEnabledAction(), &ToggleAction::toggled, this, allowErrorReportingChanged); } } From f38347c028ed5c94df7c3c10a352685787dbb92f Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 6 May 2025 13:11:18 +0200 Subject: [PATCH 27/37] Streamline settings IO --- ManiVault/src/actions/AppFeatureAction.cpp | 10 ++++++++-- ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index d21f06eb7..6cd9bffd4 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -18,8 +18,14 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : { setShowLabels(false); - //_enabledAction.setSettingsPrefix(QString("AppFeatures/%1/Enabled").arg(title)); - //_userHasOptedAction.setSettingsPrefix(QString("AppFeatures/%1/Enabled").arg(title)); + auto settingsPrefix = QString("AppFeatures/%1/").arg(title); + + settingsPrefix.replace(" ", ""); + + setSettingsPrefix(settingsPrefix); + + _enabledAction.setSettingsPrefix(QString("%1/Enabled").arg(WidgetAction::getSettingsPrefix())); + _userHasOptedAction.setSettingsPrefix(QString("%1/UserHasOpted").arg(WidgetAction::getSettingsPrefix())); _enabledAction.setDefaultWidgetFlags(ToggleAction::WidgetFlag::ToggleImage); diff --git a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp index 2ced5da37..9c2262063 100644 --- a/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp +++ b/ManiVault/src/actions/ErrorLoggingAppFeatureAction.cpp @@ -15,11 +15,11 @@ ErrorLoggingAppFeatureAction::ErrorLoggingAppFeatureAction(QObject* parent, cons getSummaryAction().setString("Send anonymous crash reports to improve the application"); - _loggingDsnAction.setSettingsPrefix("AppFeatures/Logging/DSN"); + _loggingDsnAction.setSettingsPrefix(QString("%1/DSN").arg(WidgetAction::getSettingsPrefix())); _loggingDsnAction.setToolTip("The Sentry error logging data source name"); _loggingDsnAction.getValidator().setRegularExpression(QRegularExpression(R"(^https?://[a-f0-9]{32}@[a-z0-9\.-]+(:\d+)?/[\d]+$)")); - _loggingShowCrashReportDialogAction.setSettingsPrefix("AppFeatures/Logging/ShowCrashReportDialog"); + _loggingShowCrashReportDialogAction.setSettingsPrefix(QString("%1/ShowCrashReportDialog").arg(WidgetAction::getSettingsPrefix())); _loggingShowCrashReportDialogAction.setToolTip("Show the crash report dialog prior to sending an error report"); addAction(&_loggingDsnAction); From 18015b2b1ac17a854c93ce868c16f394d6346824 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 09:39:08 +0200 Subject: [PATCH 28/37] Several improvements: - Improve app feature HTML files - Add const action getters in the abstract settings manager - The user must give explicit consent after reading app feature description --- .../res/html/AppFeatureErrorLogging.html | 1 - ManiVault/src/AbstractSettingsManager.h | 7 ++ ManiVault/src/actions/AppFeatureAction.cpp | 87 ++++++++++++++++++- ManiVault/src/actions/AppFeatureAction.h | 40 +++++++++ ManiVault/src/private/SettingsManager.h | 7 ++ 5 files changed, 138 insertions(+), 4 deletions(-) diff --git a/ManiVault/res/html/AppFeatureErrorLogging.html b/ManiVault/res/html/AppFeatureErrorLogging.html index 6025f211c..6fd1ef9ac 100644 --- a/ManiVault/res/html/AppFeatureErrorLogging.html +++ b/ManiVault/res/html/AppFeatureErrorLogging.html @@ -2,7 +2,6 @@

    Automated error reporting

    -

    ManiVault Studio can automatically report bugs and crashes using Sentry. This might help us fix issues faster and improve the application for everyone.

    What we collect:

      diff --git a/ManiVault/src/AbstractSettingsManager.h b/ManiVault/src/AbstractSettingsManager.h index c0cb7e430..95b797ca7 100644 --- a/ManiVault/src/AbstractSettingsManager.h +++ b/ManiVault/src/AbstractSettingsManager.h @@ -62,6 +62,13 @@ class CORE_EXPORT AbstractSettingsManager : public AbstractManager virtual gui::TasksSettingsAction& getTasksSettingsAction() = 0; virtual gui::AppearanceSettingsAction& getAppearanceSettingsAction() = 0; virtual gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() = 0; + + virtual const gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() const = 0; + virtual const gui::ParametersSettingsAction& getParametersSettings() const = 0; + virtual const gui::MiscellaneousSettingsAction& getMiscellaneousSettings() const = 0; + virtual const gui::TasksSettingsAction& getTasksSettingsAction() const = 0; + virtual const gui::AppearanceSettingsAction& getAppearanceSettingsAction() const = 0; + virtual const gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() const = 0; /** diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index 6cd9bffd4..e3cb4d29a 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -58,10 +58,24 @@ AppFeatureAction::AppFeatureAction(QObject* parent, const QString& title) : updateActionsReadOnly(); - connect(&_enabledAction, &ToggleAction::toggled, this, updateActionsReadOnly); + connect(&_enabledAction, &ToggleAction::toggled, this, [this, updateActionsReadOnly](bool toggled) -> void { + + if (toggled) { + ConsentDialog consentDialog(this); + + if (consentDialog.exec() == QDialog::Accepted) { + _userHasOptedAction.setChecked(true); + _enabledAction.setChecked(true); + } + else { + _enabledAction.setChecked(false); + } + _settingsAction.setEnabled(_enabledAction.isChecked()); + _descriptionAction.setEnabled(_enabledAction.isChecked()); + } - connect(&_enabledAction, &ToggleAction::toggled, this, [this](bool toggled) -> void { - mv::help().addNotification("App Feature", QString("%1 app feature has been %2").arg(text(), toggled ? "enabled" : "disabled"), StyledIcon(toggled ? "toggle-on" : "toggle-off")); + updateActionsReadOnly(); + //mv::help().addNotification("App Feature", QString("%1 app feature has been %2").arg(text(), toggled ? "enabled" : "disabled"), StyledIcon(toggled ? "toggle-on" : "toggle-off")); }); if (hasSetting(PrefixType::UserHasOpted)) { @@ -77,6 +91,11 @@ void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags _settingsAction.setVisible(true); } +QString AppFeatureAction::getResourceLocation() const +{ + return _resourceLocation; +} + QString AppFeatureAction::getSettingsPrefix(const PrefixType& prefixType) const { switch (prefixType) { @@ -97,6 +116,8 @@ bool AppFeatureAction::hasSetting(const PrefixType& prefixType) const void AppFeatureAction::loadDescriptionFromResource(const QString& resourceLocation) { + _resourceLocation = resourceLocation; + QFile appFeatureHtmlFile(resourceLocation); if (appFeatureHtmlFile.open(QIODevice::ReadOnly)) { @@ -124,4 +145,64 @@ bool AppFeatureAction::getUserHasOptedFromSettings() const return false; } +AppFeatureAction::ConsentDialog::ConsentDialog(AppFeatureAction* appFeatureAction, QWidget* parent /*= nullptr*/) : + QDialog(parent), + _acceptPushButton("Accept"), + _cancelPushButton("Cancel"), + _decideLaterPushButton("Decide Later") +{ + setWindowModality(Qt::ApplicationModal); + setWindowFlag(Qt::Dialog); + setWindowFlag(Qt::WindowTitleHint); + setWindowFlag(Qt::WindowStaysOnTopHint); + setWindowTitle(QString("Turn on %1 App Feature").arg(appFeatureAction->text())); + setWindowIcon(StyledIcon("toggle-on")); + move(QApplication::activeWindow()->geometry().center() - rect().center()); + + _notificationLabel.setWordWrap(true); + _notificationLabel.setOpenExternalLinks(true); + + QFile errorLoggingConsentHtmlFile(appFeatureAction->getResourceLocation()); + + if (errorLoggingConsentHtmlFile.open(QIODevice::ReadOnly)) { + _notificationLabel.setText(errorLoggingConsentHtmlFile.readAll()); + errorLoggingConsentHtmlFile.close(); + } + + _layout.addWidget(&_notificationLabel); + _layout.addStretch(1); + + _buttonsLayout.setContentsMargins(9, 30, 9, 9); + + _buttonsLayout.addStretch(1); + _buttonsLayout.addWidget(&_acceptPushButton); + _buttonsLayout.addWidget(&_cancelPushButton); + + const auto& constErrorManager = mv::errors(); + + if (!constErrorManager.getLoggingUserHasOptedAction().isChecked()) + _buttonsLayout.addWidget(&_decideLaterPushButton); + + _layout.addLayout(&_buttonsLayout); + + setLayout(&_layout); + + connect(&_acceptPushButton, &QPushButton::clicked, this, [this, &constErrorManager]() -> void { + accept(); + }); + + connect(&_cancelPushButton, &QPushButton::clicked, this, [this, &constErrorManager]() -> void { + reject(); + }); + + connect(&_decideLaterPushButton, &QPushButton::clicked, this, [this]() -> void { + reject(); + }); +} + +QSize AppFeatureAction::ConsentDialog::sizeHint() const +{ + return { 500, 300 }; +} + } diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h index 2acace155..4096b289e 100644 --- a/ManiVault/src/actions/AppFeatureAction.h +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -32,6 +32,39 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction UserHasOpted, /** Prefix for the user has opted type */ }; +protected: + + /** Dialog for giving consent for a specific app feature */ + class CORE_EXPORT ConsentDialog final : public QDialog + { + protected: + + /** + * Construct a dialog with \p parent + * @param appFeatureAction Pointer to owning app feature action + * @param parent Pointer to parent widget + */ + ConsentDialog(AppFeatureAction* appFeatureAction, QWidget* parent = nullptr); + + /** Get preferred size */ + QSize sizeHint() const override; + + /** Get minimum size hint*/ + QSize minimumSizeHint() const override { + return sizeHint(); + } + + private: + QVBoxLayout _layout; /** Main layout */ + QLabel _notificationLabel; /** Notification label */ + QHBoxLayout _buttonsLayout; /** Bottom buttons layout */ + QPushButton _acceptPushButton; /** Opt in of automated error reporting when clicked */ + QPushButton _cancelPushButton; /** Abort consent process */ + QPushButton _decideLaterPushButton; /** Exit the dialog and show it at next startup */ + + friend class AppFeatureAction; + }; + public: /** @@ -50,6 +83,12 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction */ void addAction(WidgetAction* action, std::int32_t widgetFlags = -1, WidgetConfigurationFunction widgetConfigurationFunction = WidgetConfigurationFunction(), bool load = true) override; + /** + * Get the HTML resource file location + * @return Location of the app feature description HTML resource file + */ + QString getResourceLocation() const; + protected: /** @@ -106,6 +145,7 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction ToggleAction _userHasOptedAction; /** Determines if the user has given permission to use the app feature */ StringAction _descriptionAction; /** App feature description */ VerticalGroupAction _settingsAction; /** App feature settings */ + QString _resourceLocation; /** Location of the resource to load */ friend class AppFeaturesSettingsAction; // Allow access to private members }; diff --git a/ManiVault/src/private/SettingsManager.h b/ManiVault/src/private/SettingsManager.h index 2267cb6d0..79316db0e 100644 --- a/ManiVault/src/private/SettingsManager.h +++ b/ManiVault/src/private/SettingsManager.h @@ -46,6 +46,13 @@ class SettingsManager final : public AbstractSettingsManager gui::AppearanceSettingsAction& getAppearanceSettingsAction() override { return _appearanceSettingsAction; }; gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() override { return _temporaryDirectoriesSettingsAction; }; + const gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() const override { return _appFeaturesSettingsAction; }; + const gui::ParametersSettingsAction& getParametersSettings() const override { return _parametersSettingsAction; }; + const gui::MiscellaneousSettingsAction& getMiscellaneousSettings() const override { return _miscellaneousSettingsAction; }; + const gui::TasksSettingsAction& getTasksSettingsAction() const override { return _tasksSettingsAction; }; + const gui::AppearanceSettingsAction& getAppearanceSettingsAction() const override { return _appearanceSettingsAction; }; + const gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() const override { return _temporaryDirectoriesSettingsAction; }; + /** * Get plugin global settings for plugin \p kind * @param kind Plugin kind From 9c4a139b0a8f7a6bf73b2d294fd4390cd81b66a3 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 10:40:33 +0200 Subject: [PATCH 29/37] Use tutorials app feature setting in the start page --- ManiVault/src/AbstractSettingsManager.h | 2 +- ManiVault/src/AppFeaturesSettingsAction.h | 6 ++--- ManiVault/src/CoreInterface.h | 8 ++++++ ManiVault/src/actions/AppFeatureAction.cpp | 5 ++++ ManiVault/src/actions/AppFeatureAction.h | 6 +++++ ManiVault/src/private/SettingsManager.h | 26 +++++++++---------- .../src/private/SettingsManagerDialog.cpp | 2 +- .../src/private/StartPageContentWidget.cpp | 10 +++++++ .../src/private/StartPageGetStartedWidget.cpp | 7 +++-- 9 files changed, 52 insertions(+), 20 deletions(-) diff --git a/ManiVault/src/AbstractSettingsManager.h b/ManiVault/src/AbstractSettingsManager.h index 95b797ca7..8383515a0 100644 --- a/ManiVault/src/AbstractSettingsManager.h +++ b/ManiVault/src/AbstractSettingsManager.h @@ -56,7 +56,7 @@ class CORE_EXPORT AbstractSettingsManager : public AbstractManager public: // Global settings actions - virtual gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() = 0; + //virtual gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() = 0; virtual gui::ParametersSettingsAction& getParametersSettings() = 0; virtual gui::MiscellaneousSettingsAction& getMiscellaneousSettings() = 0; virtual gui::TasksSettingsAction& getTasksSettingsAction() = 0; diff --git a/ManiVault/src/AppFeaturesSettingsAction.h b/ManiVault/src/AppFeaturesSettingsAction.h index 948f0e254..5c2d50240 100644 --- a/ManiVault/src/AppFeaturesSettingsAction.h +++ b/ManiVault/src/AppFeaturesSettingsAction.h @@ -34,9 +34,9 @@ class CORE_EXPORT AppFeaturesSettingsAction final : public GlobalSettingsGroupAc public: // Action getters const ErrorLoggingAppFeatureAction& getErrorLoggingAppFeatureAction() const { return _errorLoggingAppFeatureAction; } - ProjectsAppFeatureAction& getProjectsAppFeatureAction() { return _projectsAppFeatureAction; } - TutorialsAppFeatureAction& getTutorialsAppFeatureAction() { return _tutorialsAppFeatureAction; } - VideosAppFeatureAction& getVideosAppFeatureAction() { return _videosAppFeatureAction; } + const ProjectsAppFeatureAction& getProjectsAppFeatureAction() const { return _projectsAppFeatureAction; } + const TutorialsAppFeatureAction& getTutorialsAppFeatureAction() const { return _tutorialsAppFeatureAction; } + const VideosAppFeatureAction& getVideosAppFeatureAction() const { return _videosAppFeatureAction; } private: ErrorLoggingAppFeatureAction _errorLoggingAppFeatureAction; /** App feature action for configuring error logging */ diff --git a/ManiVault/src/CoreInterface.h b/ManiVault/src/CoreInterface.h index b883c3a5f..b6ab7c9f4 100644 --- a/ManiVault/src/CoreInterface.h +++ b/ManiVault/src/CoreInterface.h @@ -241,6 +241,14 @@ CORE_EXPORT inline AbstractSettingsManager& settings() { return core()->getSettingsManager(); } +/** +* Convenience function to obtain access to the settings manager in the core +* @return Reference to abstract settings manager +*/ +CORE_EXPORT inline const AbstractSettingsManager& constSettings() { + return core()->getSettingsManager(); +} + /** * Convenience function to obtain access to the help manager in the core * @return Reference to abstract help manager diff --git a/ManiVault/src/actions/AppFeatureAction.cpp b/ManiVault/src/actions/AppFeatureAction.cpp index e3cb4d29a..760fc3525 100644 --- a/ManiVault/src/actions/AppFeatureAction.cpp +++ b/ManiVault/src/actions/AppFeatureAction.cpp @@ -91,6 +91,11 @@ void AppFeatureAction::addAction(WidgetAction* action, std::int32_t widgetFlags _settingsAction.setVisible(true); } +bool AppFeatureAction::getEnabled() const +{ + return _enabledAction.isChecked(); +} + QString AppFeatureAction::getResourceLocation() const { return _resourceLocation; diff --git a/ManiVault/src/actions/AppFeatureAction.h b/ManiVault/src/actions/AppFeatureAction.h index 4096b289e..00ab7dd32 100644 --- a/ManiVault/src/actions/AppFeatureAction.h +++ b/ManiVault/src/actions/AppFeatureAction.h @@ -83,6 +83,12 @@ class CORE_EXPORT AppFeatureAction : public HorizontalGroupAction */ void addAction(WidgetAction* action, std::int32_t widgetFlags = -1, WidgetConfigurationFunction widgetConfigurationFunction = WidgetConfigurationFunction(), bool load = true) override; + /** + * Get whether the app feature is enabled or not + * @return Boolean determining whether the app feature is enabled or not + */ + bool getEnabled() const; + /** * Get the HTML resource file location * @return Location of the app feature description HTML resource file diff --git a/ManiVault/src/private/SettingsManager.h b/ManiVault/src/private/SettingsManager.h index 79316db0e..8ca2ed3e8 100644 --- a/ManiVault/src/private/SettingsManager.h +++ b/ManiVault/src/private/SettingsManager.h @@ -39,19 +39,19 @@ class SettingsManager final : public AbstractSettingsManager public: // Global settings actions - gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() override { return _appFeaturesSettingsAction; }; - gui::ParametersSettingsAction& getParametersSettings() override { return _parametersSettingsAction; }; - gui::MiscellaneousSettingsAction& getMiscellaneousSettings() override { return _miscellaneousSettingsAction; }; - gui::TasksSettingsAction& getTasksSettingsAction() override { return _tasksSettingsAction; }; - gui::AppearanceSettingsAction& getAppearanceSettingsAction() override { return _appearanceSettingsAction; }; - gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() override { return _temporaryDirectoriesSettingsAction; }; - - const gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() const override { return _appFeaturesSettingsAction; }; - const gui::ParametersSettingsAction& getParametersSettings() const override { return _parametersSettingsAction; }; - const gui::MiscellaneousSettingsAction& getMiscellaneousSettings() const override { return _miscellaneousSettingsAction; }; - const gui::TasksSettingsAction& getTasksSettingsAction() const override { return _tasksSettingsAction; }; - const gui::AppearanceSettingsAction& getAppearanceSettingsAction() const override { return _appearanceSettingsAction; }; - const gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() const override { return _temporaryDirectoriesSettingsAction; }; + //gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() override { return _appFeaturesSettingsAction; } + gui::ParametersSettingsAction& getParametersSettings() override { return _parametersSettingsAction; } + gui::MiscellaneousSettingsAction& getMiscellaneousSettings() override { return _miscellaneousSettingsAction; } + gui::TasksSettingsAction& getTasksSettingsAction() override { return _tasksSettingsAction; } + gui::AppearanceSettingsAction& getAppearanceSettingsAction() override { return _appearanceSettingsAction; } + gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() override { return _temporaryDirectoriesSettingsAction; } + + const gui::AppFeaturesSettingsAction& getAppFeaturesSettingsAction() const override { return _appFeaturesSettingsAction; } + const gui::ParametersSettingsAction& getParametersSettings() const override { return _parametersSettingsAction; } + const gui::MiscellaneousSettingsAction& getMiscellaneousSettings() const override { return _miscellaneousSettingsAction; } + const gui::TasksSettingsAction& getTasksSettingsAction() const override { return _tasksSettingsAction; } + const gui::AppearanceSettingsAction& getAppearanceSettingsAction() const override { return _appearanceSettingsAction; } + const gui::TemporaryDirectoriesSettingsAction& getTemporaryDirectoriesSettingsAction() const override { return _temporaryDirectoriesSettingsAction; } /** * Get plugin global settings for plugin \p kind diff --git a/ManiVault/src/private/SettingsManagerDialog.cpp b/ManiVault/src/private/SettingsManagerDialog.cpp index 05e9400a8..d54e6b5c4 100644 --- a/ManiVault/src/private/SettingsManagerDialog.cpp +++ b/ManiVault/src/private/SettingsManagerDialog.cpp @@ -33,7 +33,7 @@ SettingsManagerDialog::SettingsManagerDialog(QWidget* parent /*= nullptr*/) : layout->addWidget(_groupsAction.createWidget(this)); - _groupsAction.addGroupAction(&mv::settings().getAppFeaturesSettingsAction()); + _groupsAction.addGroupAction(&const_cast(mv::settings().getAppFeaturesSettingsAction())); _groupsAction.addGroupAction(&mv::settings().getAppearanceSettingsAction()); _groupsAction.addGroupAction(&mv::settings().getParametersSettings()); _groupsAction.addGroupAction(&mv::settings().getMiscellaneousSettings()); diff --git a/ManiVault/src/private/StartPageContentWidget.cpp b/ManiVault/src/private/StartPageContentWidget.cpp index dee177829..1190ab69d 100644 --- a/ManiVault/src/private/StartPageContentWidget.cpp +++ b/ManiVault/src/private/StartPageContentWidget.cpp @@ -94,6 +94,16 @@ StartPageContentWidget::StartPageContentWidget(QWidget* parent /*= nullptr*/) : }); connect(&_compactViewAction, &ToggleAction::toggled, this, &StartPageContentWidget::updateActions); + + const auto& tutorialsAppFeatureEnabledAction = mv::constSettings().getAppFeaturesSettingsAction().getTutorialsAppFeatureAction().getEnabledAction(); + + const auto updateTutorialsToggleVisibility = [this, &tutorialsAppFeatureEnabledAction]() -> void { + _toggleTutorialsAction.setVisible(tutorialsAppFeatureEnabledAction.isChecked()); + }; + + updateTutorialsToggleVisibility(); + + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, updateTutorialsToggleVisibility); } void StartPageContentWidget::updateActions() diff --git a/ManiVault/src/private/StartPageGetStartedWidget.cpp b/ManiVault/src/private/StartPageGetStartedWidget.cpp index 9a51d0168..1eaf3d0f5 100644 --- a/ManiVault/src/private/StartPageGetStartedWidget.cpp +++ b/ManiVault/src/private/StartPageGetStartedWidget.cpp @@ -67,15 +67,18 @@ StartPageGetStartedWidget::StartPageGetStartedWidget(StartPageContentWidget* sta _recentWorkspacesAction.initialize("Manager/Workspace/Recent", "Workspace", "Ctrl+Alt"); _recentProjectsAction.initialize("Manager/Project/Recent", "Project", "Ctrl"); - const auto toggleViews = [this]() -> void { + const auto& tutorialsAppFeatureEnabledAction = mv::settings().getAppFeaturesSettingsAction().getTutorialsAppFeatureAction().getEnabledAction(); + + const auto toggleViews = [this, &tutorialsAppFeatureEnabledAction]() -> void { _createProjectFromWorkspaceWidget.setVisible(_startPageContentWidget->getToggleProjectFromWorkspaceAction().isChecked()); _createProjectFromDatasetWidget.setVisible(_startPageContentWidget->getToggleProjectFromDataAction().isChecked()); - _tutorialsWidget.setVisible(_startPageContentWidget->getToggleTutorialsAction().isChecked()); + _tutorialsWidget.setVisible(tutorialsAppFeatureEnabledAction.isChecked() && _startPageContentWidget->getToggleTutorialsAction().isChecked()); }; connect(&_startPageContentWidget->getToggleProjectFromWorkspaceAction(), &ToggleAction::toggled, this, toggleViews); connect(&_startPageContentWidget->getToggleProjectFromDataAction(), &ToggleAction::toggled, this, toggleViews); connect(&_startPageContentWidget->getToggleTutorialsAction(), &ToggleAction::toggled, this, toggleViews); + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, toggleViews); toggleViews(); } From bdec6a027a8e88cdf28e0a3471ae86c577641ad2 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 12:42:50 +0200 Subject: [PATCH 30/37] Only show videos and tutorials help menus when the corresponding app features are enabled --- ManiVault/src/private/HelpManager.cpp | 22 ++++++++++++++++++++++ ManiVault/src/private/HelpMenu.cpp | 11 +++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ManiVault/src/private/HelpManager.cpp b/ManiVault/src/private/HelpManager.cpp index 3ae29f369..3572aa766 100644 --- a/ManiVault/src/private/HelpManager.cpp +++ b/ManiVault/src/private/HelpManager.cpp @@ -198,6 +198,17 @@ QMenu* HelpManager::getVideosMenu() const videosMenu->addAction(videoAction); } + const auto& videosAppFeatureEnabledAction = mv::settings().getAppFeaturesSettingsAction().getTutorialsAppFeatureAction().getEnabledAction(); + + const auto toggleVisibility = [videosMenu, &videosAppFeatureEnabledAction]() -> void { + videosMenu->setEnabled(videosAppFeatureEnabledAction.isChecked()); + + for (auto action : videosMenu->actions()) + action->setVisible(videosAppFeatureEnabledAction.isChecked()); + }; + + connect(&videosAppFeatureEnabledAction, &ToggleAction::toggled, videosMenu, toggleVisibility); + return videosMenu; } @@ -277,6 +288,17 @@ QMenu* HelpManager::getTutorialsMenu() const tutorialsMenu->setEnabled(!tutorials.empty()); + const auto& tutorialsAppFeatureEnabledAction = mv::settings().getAppFeaturesSettingsAction().getTutorialsAppFeatureAction().getEnabledAction(); + + const auto toggleVisibility = [tutorialsMenu, &tutorialsAppFeatureEnabledAction]() -> void { + tutorialsMenu->setEnabled(tutorialsAppFeatureEnabledAction.isChecked()); + + for (auto action : tutorialsMenu->actions()) + action->setVisible(tutorialsAppFeatureEnabledAction.isChecked()); + }; + + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, tutorialsMenu, toggleVisibility); + return tutorialsMenu; } diff --git a/ManiVault/src/private/HelpMenu.cpp b/ManiVault/src/private/HelpMenu.cpp index 94b1050f6..486ce1169 100644 --- a/ManiVault/src/private/HelpMenu.cpp +++ b/ManiVault/src/private/HelpMenu.cpp @@ -76,8 +76,15 @@ void HelpMenu::populate() addSeparator(); - addMenu(mv::help().getVideosMenu()); - addMenu(mv::help().getTutorialsMenu()); + const auto& appFeatureEnabledAction = mv::settings().getAppFeaturesSettingsAction(); + const auto& videosAppFeatureEnabledAction = appFeatureEnabledAction.getVideosAppFeatureAction().getEnabledAction(); + const auto& tutorialsAppFeatureEnabledAction = appFeatureEnabledAction.getTutorialsAppFeatureAction().getEnabledAction(); + + if (videosAppFeatureEnabledAction.isChecked()) + addMenu(mv::help().getVideosMenu()); + + if (tutorialsAppFeatureEnabledAction.isChecked()) + addMenu(mv::help().getTutorialsMenu()); if(!isEmpty()) addSeparator(); From 90145eea8e3f316c82ddd7be364038df03f5147e Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 12:50:24 +0200 Subject: [PATCH 31/37] Use the tutorials app feature in the tutorials model --- ManiVault/src/models/LearningCenterTutorialsModel.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ManiVault/src/models/LearningCenterTutorialsModel.cpp b/ManiVault/src/models/LearningCenterTutorialsModel.cpp index 64e7d16e6..d7c71dca7 100644 --- a/ManiVault/src/models/LearningCenterTutorialsModel.cpp +++ b/ManiVault/src/models/LearningCenterTutorialsModel.cpp @@ -76,6 +76,8 @@ LearningCenterTutorialsModel::LearningCenterTutorialsModel(QObject* parent /*= n for (auto pluginFactory : mv::plugins().getPluginFactoriesByTypes()) { connect(&pluginFactory->getTutorialsDsnsAction(), &StringsAction::stringsChanged, this, &LearningCenterTutorialsModel::synchronizeWithDsns); } + + connect(&mv::settings().getAppFeaturesSettingsAction().getTutorialsAppFeatureAction(), &TutorialsAppFeatureAction::enabledChanged, this, &LearningCenterTutorialsModel::synchronizeWithDsns); } QVariant LearningCenterTutorialsModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const @@ -153,6 +155,9 @@ void LearningCenterTutorialsModel::updateTags() void LearningCenterTutorialsModel::synchronizeWithDsns() { + if (!mv::settings().getAppFeaturesSettingsAction().getTutorialsAppFeatureAction().getEnabledAction().isChecked()) + return; + auto uniqueDsns = _dsnsAction.getStrings(); for (auto pluginFactory : mv::plugins().getPluginFactoriesByTypes()) { From c3293544b60a45b2afcaf69a634f549a59893f01 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 13:09:35 +0200 Subject: [PATCH 32/37] Use videos and tutorials app features in the learning center --- .../src/private/LearningPageContentWidget.cpp | 62 +++++++++++------- .../src/private/LearningPageContentWidget.h | 22 +++---- ManiVault/src/private/PageContentWidget.cpp | 2 +- .../src/private/StartPageContentWidget.cpp | 64 +++++++++---------- .../src/private/StartPageContentWidget.h | 24 +++---- 5 files changed, 96 insertions(+), 78 deletions(-) diff --git a/ManiVault/src/private/LearningPageContentWidget.cpp b/ManiVault/src/private/LearningPageContentWidget.cpp index a59077f79..0ab6f3e15 100644 --- a/ManiVault/src/private/LearningPageContentWidget.cpp +++ b/ManiVault/src/private/LearningPageContentWidget.cpp @@ -12,10 +12,10 @@ using namespace mv::gui; LearningPageContentWidget::LearningPageContentWidget(QWidget* parent /*= nullptr*/) : PageContentWidget(Qt::Vertical, parent), - _showVideosAction(this, "Show videos", true), - _showTutorialsAction(this, "Show tutorials (coming soon)", true), - _showExamplesAction(this, "Show examples (coming soon)", false), - _showPluginResourcesAction(this, "Show plugin resources", false), + _toggleVideosSectionAction(this, "Show videos", true), + _toggleTutorialsSectionAction(this, "Show tutorials", true), + _toggleExamplesSectionAction(this, "Show examples (coming soon)", false), + _togglePluginResourcesSectionAction(this, "Show plugin resources", false), _settingsAction(this, "Page settings"), _toStartPageAction(this, "To start page"), _toolbarAction(this, "Toolbar settings"), @@ -37,26 +37,33 @@ LearningPageContentWidget::LearningPageContentWidget(QWidget* parent /*= nullptr rowsLayout.addWidget(&_examplesWidget); rowsLayout.addWidget(&_pluginResourcesWidget); - _showVideosAction.setSettingsPrefix("LearningPage/ShowVideos"); - _showTutorialsAction.setSettingsPrefix("LearningPage/ShowTutorials"); - _showExamplesAction.setSettingsPrefix("LearningPage/ShowExamples"); - _showPluginResourcesAction.setSettingsPrefix("LearningPage/ShowPluginResources"); + _toggleVideosSectionAction.setSettingsPrefix("LearningPage/ShowVideos"); + _toggleTutorialsSectionAction.setSettingsPrefix("LearningPage/ShowTutorials"); + _toggleExamplesSectionAction.setSettingsPrefix("LearningPage/ShowExamples"); + _togglePluginResourcesSectionAction.setSettingsPrefix("LearningPage/ShowPluginResources"); - _showExamplesAction.setEnabled(false); + _toggleExamplesSectionAction.setEnabled(false); - const auto toggleSections = [this]() -> void { - _videosWidget.setVisible(_showVideosAction.isChecked()); - _tutorialsWidget.setVisible(_showTutorialsAction.isChecked()); - _examplesWidget.setVisible(_showExamplesAction.isChecked()); - _pluginResourcesWidget.setVisible(_showPluginResourcesAction.isChecked()); + const auto& appFeaturesSettingsAction = mv::constSettings().getAppFeaturesSettingsAction(); + const auto& videosAppFeatureEnabledAction = appFeaturesSettingsAction.getVideosAppFeatureAction().getEnabledAction(); + const auto& tutorialsAppFeatureEnabledAction = appFeaturesSettingsAction.getTutorialsAppFeatureAction().getEnabledAction(); + + const auto toggleSections = [this, &videosAppFeatureEnabledAction, &tutorialsAppFeatureEnabledAction]() -> void { + _videosWidget.setVisible(videosAppFeatureEnabledAction.isChecked() && _toggleVideosSectionAction.isChecked()); + _tutorialsWidget.setVisible(tutorialsAppFeatureEnabledAction.isChecked() && _toggleTutorialsSectionAction.isChecked()); + _examplesWidget.setVisible(_toggleExamplesSectionAction.isChecked()); + _pluginResourcesWidget.setVisible(_togglePluginResourcesSectionAction.isChecked()); }; toggleSections(); - connect(&_showVideosAction, &ToggleAction::toggled, this, toggleSections); - connect(&_showTutorialsAction, &ToggleAction::toggled, this, toggleSections); - connect(&_showExamplesAction, &ToggleAction::toggled, this, toggleSections); - connect(&_showPluginResourcesAction, &ToggleAction::toggled, this, toggleSections); + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, toggleSections); + connect(&videosAppFeatureEnabledAction, &ToggleAction::toggled, this, toggleSections); + + connect(&_toggleVideosSectionAction, &ToggleAction::toggled, this, toggleSections); + connect(&_toggleTutorialsSectionAction, &ToggleAction::toggled, this, toggleSections); + connect(&_toggleExamplesSectionAction, &ToggleAction::toggled, this, toggleSections); + connect(&_togglePluginResourcesSectionAction, &ToggleAction::toggled, this, toggleSections); _settingsAction.setToolTip("Adjust page settings"); _settingsAction.setIconByName("gear"); @@ -66,11 +73,12 @@ LearningPageContentWidget::LearningPageContentWidget(QWidget* parent /*= nullptr _toStartPageAction.setDefaultWidgetFlags(TriggerAction::Icon); _settingsAction.setConfigurationFlag(WidgetAction::ConfigurationFlag::ForceCollapsedInGroup); + _settingsAction.setPopupSizeHint(QSize(200, 200)); - _settingsAction.addAction(&_showVideosAction); - _settingsAction.addAction(&_showTutorialsAction); - _settingsAction.addAction(&_showExamplesAction); - _settingsAction.addAction(&_showPluginResourcesAction); + _settingsAction.addAction(&_toggleVideosSectionAction); + _settingsAction.addAction(&_toggleTutorialsSectionAction); + _settingsAction.addAction(&_toggleExamplesSectionAction); + _settingsAction.addAction(&_togglePluginResourcesSectionAction); _toolbarAction.setShowLabels(false); _toolbarAction.setWidgetConfigurationFunction([](WidgetAction* action, QWidget* widget) -> void { @@ -92,5 +100,15 @@ LearningPageContentWidget::LearningPageContentWidget(QWidget* parent /*= nullptr mv::help().getShowLearningCenterPageAction().setChecked(false); mv::projects().getShowStartPageAction().setChecked(true); }); + + const auto updateToggleSectionActionsVisibility = [this, &videosAppFeatureEnabledAction, &tutorialsAppFeatureEnabledAction]() -> void { + _toggleVideosSectionAction.setVisible(videosAppFeatureEnabledAction.isChecked()); + _toggleTutorialsSectionAction.setVisible(tutorialsAppFeatureEnabledAction.isChecked()); + }; + + updateToggleSectionActionsVisibility(); + + connect(&videosAppFeatureEnabledAction, &ToggleAction::toggled, this, updateToggleSectionActionsVisibility); + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, updateToggleSectionActionsVisibility); } diff --git a/ManiVault/src/private/LearningPageContentWidget.h b/ManiVault/src/private/LearningPageContentWidget.h index 2af75b3c9..980bc36fd 100644 --- a/ManiVault/src/private/LearningPageContentWidget.h +++ b/ManiVault/src/private/LearningPageContentWidget.h @@ -29,17 +29,17 @@ class LearningPageContentWidget final : public PageContentWidget LearningPageContentWidget(QWidget* parent = nullptr); private: - mv::gui::ToggleAction _showVideosAction; /** Action to toggle videos section */ - mv::gui::ToggleAction _showTutorialsAction; /** Action to toggle tutorials section */ - mv::gui::ToggleAction _showExamplesAction; /** Action to toggle examples section */ - mv::gui::ToggleAction _showPluginResourcesAction; /** Action to toggle plugin resources section */ - mv::gui::GroupAction _settingsAction; /** Page settings action */ - mv::gui::TriggerAction _toStartPageAction; /** Trigger action for showing the start page */ - mv::gui::HorizontalGroupAction _toolbarAction; /** Bottom toolbar action */ - LearningPageVideosWidget _videosWidget; /** Learning page video section content widget */ - PageTutorialsWidget _tutorialsWidget; /** Learning page tutorials section content widget */ - LearningPageExamplesWidget _examplesWidget; /** Learning page examples section content widget */ - LearningPagePluginResourcesWidget _pluginResourcesWidget; /** Learning page plugin section resources content widget */ + mv::gui::ToggleAction _toggleVideosSectionAction; /** Action to toggle the videos section */ + mv::gui::ToggleAction _toggleTutorialsSectionAction; /** Action to toggle the tutorials section */ + mv::gui::ToggleAction _toggleExamplesSectionAction; /** Action to toggle the examples section */ + mv::gui::ToggleAction _togglePluginResourcesSectionAction; /** Action to toggle the plugin resources section */ + mv::gui::GroupAction _settingsAction; /** Page settings action */ + mv::gui::TriggerAction _toStartPageAction; /** Trigger action for showing the start page */ + mv::gui::HorizontalGroupAction _toolbarAction; /** Bottom toolbar action */ + LearningPageVideosWidget _videosWidget; /** Learning page video section content widget */ + PageTutorialsWidget _tutorialsWidget; /** Learning page tutorials section content widget */ + LearningPageExamplesWidget _examplesWidget; /** Learning page examples section content widget */ + LearningPagePluginResourcesWidget _pluginResourcesWidget; /** Learning page plugin section resources content widget */ friend class LearningPageWidget; }; \ No newline at end of file diff --git a/ManiVault/src/private/PageContentWidget.cpp b/ManiVault/src/private/PageContentWidget.cpp index e444c781a..6cdd5474d 100644 --- a/ManiVault/src/private/PageContentWidget.cpp +++ b/ManiVault/src/private/PageContentWidget.cpp @@ -24,7 +24,7 @@ PageContentWidget::PageContentWidget(const Qt::Orientation& orientation, QWidget break; case Qt::Vertical: - _mainLayout.addLayout(&_rowsLayout); + _mainLayout.addLayout(&_rowsLayout, 1); break; } diff --git a/ManiVault/src/private/StartPageContentWidget.cpp b/ManiVault/src/private/StartPageContentWidget.cpp index 1190ab69d..66b151ab4 100644 --- a/ManiVault/src/private/StartPageContentWidget.cpp +++ b/ManiVault/src/private/StartPageContentWidget.cpp @@ -19,12 +19,12 @@ StartPageContentWidget::StartPageContentWidget(QWidget* parent /*= nullptr*/) : PageContentWidget(Qt::Horizontal, parent), Serializable("StartPageContentWidget"), _compactViewAction(this, "Compact"), - _toggleOpenCreateProjectAction(this, "Open & Create", true), - _toggleProjectDatabaseAction(this, "Project Database", true), - _toggleRecentProjectsAction(this, "Recent Projects", true), - _toggleProjectFromDataAction(this, "Project From Data", true), - _toggleProjectFromWorkspaceAction(this, "Project From Workspace"), - _toggleTutorialsAction(this, "Tutorials", true), + _toggleOpenCreateProjectSectionAction(this, "Open & Create", true), + _toggleProjectDatabaseSectionAction(this, "Project Database", true), + _toggleRecentProjectsSectionAction(this, "Recent Projects", true), + _toggleProjectFromDataSectionAction(this, "Project From Data", true), + _toggleProjectFromWorkspaceSectionAction(this, "Project From Workspace"), + _toggleTutorialsSectionAction(this, "Tutorials", true), _settingsAction(this, "Settings"), _toLearningCenterAction(this, "Learning center"), _toolbarAction(this, "Toolbar settings"), @@ -33,12 +33,12 @@ StartPageContentWidget::StartPageContentWidget(QWidget* parent /*= nullptr*/) : { if (!QFileInfo("StartPage.json").exists()) { _compactViewAction.setSettingsPrefix("StartPage/ToggleCompactView"); - _toggleOpenCreateProjectAction.setSettingsPrefix("StartPage/ToggleOpenCreateProject"); - _toggleProjectDatabaseAction.setSettingsPrefix("StartPage/ToggleProjectsRepository"); - _toggleRecentProjectsAction.setSettingsPrefix("StartPage/ToggleRecentProjects"); - _toggleProjectFromWorkspaceAction.setSettingsPrefix("StartPage/ToggleProjectFromWorkspace"); - _toggleProjectFromDataAction.setSettingsPrefix("StartPage/ToggleProjectFromData"); - _toggleTutorialsAction.setSettingsPrefix("StartPage/ToggleTutorials"); + _toggleOpenCreateProjectSectionAction.setSettingsPrefix("StartPage/ToggleOpenCreateProject"); + _toggleProjectDatabaseSectionAction.setSettingsPrefix("StartPage/ToggleProjectsRepository"); + _toggleRecentProjectsSectionAction.setSettingsPrefix("StartPage/ToggleRecentProjects"); + _toggleProjectFromWorkspaceSectionAction.setSettingsPrefix("StartPage/ToggleProjectFromWorkspace"); + _toggleProjectFromDataSectionAction.setSettingsPrefix("StartPage/ToggleProjectFromData"); + _toggleTutorialsSectionAction.setSettingsPrefix("StartPage/ToggleTutorials"); _getStartedWidget.getTutorialsWidget().getTutorialsFilterModel().getTagsFilterAction().setSelectedOptions({ "GettingStarted" }); } else { @@ -46,7 +46,7 @@ StartPageContentWidget::StartPageContentWidget(QWidget* parent /*= nullptr*/) : _toLearningCenterAction.setVisible(false); } - _toggleProjectFromWorkspaceAction.setEnabled(false); + _toggleProjectFromWorkspaceSectionAction.setEnabled(false); _settingsAction.setText("Toggle Views"); _settingsAction.setToolTip("Adjust page settings"); @@ -58,19 +58,19 @@ StartPageContentWidget::StartPageContentWidget(QWidget* parent /*= nullptr*/) : _settingsAction.setConfigurationFlag(WidgetAction::ConfigurationFlag::ForceCollapsedInGroup); - _settingsAction.addAction(&_toggleOpenCreateProjectAction); + _settingsAction.addAction(&_toggleOpenCreateProjectSectionAction); if (QFileInfo("StartPage.json").exists()) { - _settingsAction.addAction(&_toggleProjectDatabaseAction); + _settingsAction.addAction(&_toggleProjectDatabaseSectionAction); } - _settingsAction.addAction(&_toggleRecentProjectsAction); - _settingsAction.addAction(&_toggleProjectFromDataAction); + _settingsAction.addAction(&_toggleRecentProjectsSectionAction); + _settingsAction.addAction(&_toggleProjectFromDataSectionAction); // Disable until the project from workspace action is implemented properly - //_settingsAction.addAction(&_toggleProjectFromWorkspaceAction); + //_settingsAction.addAction(&_toggleProjectFromWorkspaceSectionAction); - _settingsAction.addAction(&_toggleTutorialsAction); + _settingsAction.addAction(&_toggleTutorialsSectionAction); _settingsAction.addAction(&_compactViewAction); getColumnsLayout().addWidget(&_openProjectWidget); @@ -98,7 +98,7 @@ StartPageContentWidget::StartPageContentWidget(QWidget* parent /*= nullptr*/) : const auto& tutorialsAppFeatureEnabledAction = mv::constSettings().getAppFeaturesSettingsAction().getTutorialsAppFeatureAction().getEnabledAction(); const auto updateTutorialsToggleVisibility = [this, &tutorialsAppFeatureEnabledAction]() -> void { - _toggleTutorialsAction.setVisible(tutorialsAppFeatureEnabledAction.isChecked()); + _toggleTutorialsSectionAction.setVisible(tutorialsAppFeatureEnabledAction.isChecked()); }; updateTutorialsToggleVisibility(); @@ -119,12 +119,12 @@ void StartPageContentWidget::fromVariantMap(const QVariantMap& variantMap) Serializable::fromVariantMap(variantMap); _compactViewAction.fromParentVariantMap(variantMap); - _toggleOpenCreateProjectAction.fromParentVariantMap(variantMap); - _toggleProjectDatabaseAction.fromParentVariantMap(variantMap); - _toggleRecentProjectsAction.fromParentVariantMap(variantMap); - _toggleProjectFromDataAction.fromParentVariantMap(variantMap); - _toggleProjectFromWorkspaceAction.fromParentVariantMap(variantMap); - _toggleTutorialsAction.fromParentVariantMap(variantMap); + _toggleOpenCreateProjectSectionAction.fromParentVariantMap(variantMap); + _toggleProjectDatabaseSectionAction.fromParentVariantMap(variantMap); + _toggleRecentProjectsSectionAction.fromParentVariantMap(variantMap); + _toggleProjectFromDataSectionAction.fromParentVariantMap(variantMap); + _toggleProjectFromWorkspaceSectionAction.fromParentVariantMap(variantMap); + _toggleTutorialsSectionAction.fromParentVariantMap(variantMap); _openProjectWidget.fromParentVariantMap(variantMap); _getStartedWidget.fromParentVariantMap(variantMap); } @@ -134,12 +134,12 @@ QVariantMap StartPageContentWidget::toVariantMap() const auto variantMap = Serializable::toVariantMap(); _compactViewAction.insertIntoVariantMap(variantMap); - _toggleOpenCreateProjectAction.insertIntoVariantMap(variantMap); - _toggleProjectDatabaseAction.insertIntoVariantMap(variantMap); - _toggleRecentProjectsAction.insertIntoVariantMap(variantMap); - _toggleProjectFromDataAction.insertIntoVariantMap(variantMap); - _toggleProjectFromWorkspaceAction.insertIntoVariantMap(variantMap); - _toggleTutorialsAction.insertIntoVariantMap(variantMap); + _toggleOpenCreateProjectSectionAction.insertIntoVariantMap(variantMap); + _toggleProjectDatabaseSectionAction.insertIntoVariantMap(variantMap); + _toggleRecentProjectsSectionAction.insertIntoVariantMap(variantMap); + _toggleProjectFromDataSectionAction.insertIntoVariantMap(variantMap); + _toggleProjectFromWorkspaceSectionAction.insertIntoVariantMap(variantMap); + _toggleTutorialsSectionAction.insertIntoVariantMap(variantMap); _openProjectWidget.insertIntoVariantMap(variantMap); _getStartedWidget.insertIntoVariantMap(variantMap); diff --git a/ManiVault/src/private/StartPageContentWidget.h b/ManiVault/src/private/StartPageContentWidget.h index 3bb6989fb..b57566493 100644 --- a/ManiVault/src/private/StartPageContentWidget.h +++ b/ManiVault/src/private/StartPageContentWidget.h @@ -51,12 +51,12 @@ class StartPageContentWidget final : public PageContentWidget, public mv::util:: public: // Action getters const mv::gui::ToggleAction& getCompactViewAction() const { return _compactViewAction; } - const mv::gui::ToggleAction& getToggleOpenCreateProjectAction() const { return _toggleOpenCreateProjectAction; } - const mv::gui::ToggleAction& getToggleProjectDatabaseAction() const { return _toggleProjectDatabaseAction; } - const mv::gui::ToggleAction& getToggleRecentProjectsAction() const { return _toggleRecentProjectsAction; } - const mv::gui::ToggleAction& getToggleProjectFromDataAction() const { return _toggleProjectFromDataAction; } - const mv::gui::ToggleAction& getToggleProjectFromWorkspaceAction() const { return _toggleProjectFromWorkspaceAction; } - const mv::gui::ToggleAction& getToggleTutorialsAction() const { return _toggleTutorialsAction; } + const mv::gui::ToggleAction& getToggleOpenCreateProjectAction() const { return _toggleOpenCreateProjectSectionAction; } + const mv::gui::ToggleAction& getToggleProjectDatabaseAction() const { return _toggleProjectDatabaseSectionAction; } + const mv::gui::ToggleAction& getToggleRecentProjectsAction() const { return _toggleRecentProjectsSectionAction; } + const mv::gui::ToggleAction& getToggleProjectFromDataAction() const { return _toggleProjectFromDataSectionAction; } + const mv::gui::ToggleAction& getToggleProjectFromWorkspaceAction() const { return _toggleProjectFromWorkspaceSectionAction; } + const mv::gui::ToggleAction& getToggleTutorialsAction() const { return _toggleTutorialsSectionAction; } const mv::gui::GroupAction& getSettingsAction() const { return _settingsAction; } const mv::gui::TriggerAction& getToLearningCenterAction() const { return _toLearningCenterAction; } @@ -65,12 +65,12 @@ class StartPageContentWidget final : public PageContentWidget, public mv::util:: private: mv::gui::ToggleAction _compactViewAction; /** Toggle compact view on/off */ - mv::gui::ToggleAction _toggleOpenCreateProjectAction; /** Toggle open and create project section */ - mv::gui::ToggleAction _toggleProjectDatabaseAction; /** Toggle project database section */ - mv::gui::ToggleAction _toggleRecentProjectsAction; /** Toggle recent projects section */ - mv::gui::ToggleAction _toggleProjectFromDataAction; /** Toggle project from data section */ - mv::gui::ToggleAction _toggleProjectFromWorkspaceAction; /** Toggle project from workspace section */ - mv::gui::ToggleAction _toggleTutorialsAction; /** Toggle tutorials section */ + mv::gui::ToggleAction _toggleOpenCreateProjectSectionAction; /** Toggle open and create project section */ + mv::gui::ToggleAction _toggleProjectDatabaseSectionAction; /** Toggle project database section */ + mv::gui::ToggleAction _toggleRecentProjectsSectionAction; /** Toggle recent projects section */ + mv::gui::ToggleAction _toggleProjectFromDataSectionAction; /** Toggle project from data section */ + mv::gui::ToggleAction _toggleProjectFromWorkspaceSectionAction; /** Toggle project from workspace section */ + mv::gui::ToggleAction _toggleTutorialsSectionAction; /** Toggle tutorials section */ mv::gui::GroupAction _settingsAction; /** Settings action */ mv::gui::TriggerAction _toLearningCenterAction; /** Trigger action for showing the learning center */ mv::gui::HorizontalGroupAction _toolbarAction; /** Bottom toolbar action */ From 6e8572c660d7636b354370bb42c7654216db70f9 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 13:12:40 +0200 Subject: [PATCH 33/37] Add videos dsns action to plugin factory --- ManiVault/src/PluginFactory.cpp | 6 +++++- ManiVault/src/PluginFactory.h | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ManiVault/src/PluginFactory.cpp b/ManiVault/src/PluginFactory.cpp index 439eeae4d..3889316dd 100644 --- a/ManiVault/src/PluginFactory.cpp +++ b/ManiVault/src/PluginFactory.cpp @@ -28,13 +28,17 @@ PluginFactory::PluginFactory(Type type, const QString& title) : _allowPluginCreationFromStandardGui(true), _pluginMetadata(*this), _tutorialsDsnsAction(this, "Tutorials DSNs"), - _projectsDsnsAction(this, "Projects DSNs") + _projectsDsnsAction(this, "Projects DSNs"), + _videosDsnsAction(this, "Videos DSNs") { _tutorialsDsnsAction.setIconByName("globe"); _tutorialsDsnsAction.setToolTip(QString("Data Source Names for %1 tutorials").arg(title)); _projectsDsnsAction.setIconByName("globe"); _projectsDsnsAction.setToolTip(QString("Data Source Names for %1 projects").arg(title)); + + _videosDsnsAction.setIconByName("globe"); + _videosDsnsAction.setToolTip(QString("Data Source Names for %1 videos").arg(title)); } QString PluginFactory::getKind() const diff --git a/ManiVault/src/PluginFactory.h b/ManiVault/src/PluginFactory.h index 7a5c78f5d..46e3f1d25 100644 --- a/ManiVault/src/PluginFactory.h +++ b/ManiVault/src/PluginFactory.h @@ -319,6 +319,7 @@ class CORE_EXPORT PluginFactory : public gui::WidgetAction gui::StringsAction& getTutorialsDsnsAction() { return _tutorialsDsnsAction; } gui::StringsAction& getProjectsDsnsAction() { return _projectsDsnsAction; } + gui::StringsAction& getVideosDsnsAction() { return _videosDsnsAction; } signals: @@ -401,7 +402,8 @@ class CORE_EXPORT PluginFactory : public gui::WidgetAction PluginMetadata _pluginMetadata; /** Plugin metadata */ QIcon _categoryIcon; /** Category icon */ gui::StringsAction _tutorialsDsnsAction; /** Action for editing the tutorials Data Source Names */ - gui::StringsAction _projectsDsnsAction; /** Action for editing the project Data Source Names */ + gui::StringsAction _projectsDsnsAction; /** Action for editing the projects Data Source Names */ + gui::StringsAction _videosDsnsAction; /** Action for editing the videos Data Source Names */ }; } From ea54ae56308daf8de1a46d50eb7d0c3926b81d19 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 13:14:43 +0200 Subject: [PATCH 34/37] Removed redundant file downloader from the help manager (relocate to videos model) --- ManiVault/src/private/HelpManager.cpp | 10 ++++++---- ManiVault/src/private/HelpManager.h | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ManiVault/src/private/HelpManager.cpp b/ManiVault/src/private/HelpManager.cpp index 3572aa766..c0dcf6d53 100644 --- a/ManiVault/src/private/HelpManager.cpp +++ b/ManiVault/src/private/HelpManager.cpp @@ -36,8 +36,7 @@ HelpManager::HelpManager(QObject* parent) : _toWebsiteAction(this, "Website"), _toWikiAction(this, "Wiki"), _toRepositoryAction(this, "Repository"), - _toLearningCenterAction(this, "Go to learning center"), - _fileDownloader(FileDownloader::StorageMode::File, Task::GuiScope::Background) + _toLearningCenterAction(this, "Go to learning center") { _showLearningCenterPageAction.setIconByName("chalkboard-user"); _showLearningCenterPageAction.setToolTip("Go to the learning center"); @@ -84,6 +83,7 @@ HelpManager::HelpManager(QObject* parent) : _showLearningCenterPageAction.setChecked(true); }); + /* connect(&_fileDownloader, &FileDownloader::downloaded, this, [this]() -> void { try { @@ -108,6 +108,7 @@ HelpManager::HelpManager(QObject* parent) : exceptionMessageBox("Unable to process learning center JSON"); } }); + */ } HelpManager::~HelpManager() @@ -128,10 +129,11 @@ void HelpManager::initialize() beginInitialization(); { - _fileDownloader.download(QUrl("https://www.manivault.studio/api/learning-center.json")); - _tutorialsModel.getDsnsAction().addString("https://www.manivault.studio/api/learning-center.json"); _tutorialsModel.synchronizeWithDsns(); + + //_videosModel.getDsnsAction().addString("https://www.manivault.studio/api/learning-center.json"); + //_videosModel.synchronizeWithDsns(); } endInitialization(); } diff --git a/ManiVault/src/private/HelpManager.h b/ManiVault/src/private/HelpManager.h index 521116266..b7b724071 100644 --- a/ManiVault/src/private/HelpManager.h +++ b/ManiVault/src/private/HelpManager.h @@ -120,7 +120,6 @@ class HelpManager : public mv::AbstractHelpManager LearningCenterVideosModel _videosModel; /** Videos model */ LearningCenterTutorialsModel _tutorialsModel; /** Tutorials model */ util::Notifications _notifications; /** Notifications manager */ - util::FileDownloader _fileDownloader; /** For downloading the learning center JSON file */ }; } From 135ae80f75b32502c601914d234cdb763f7eb375 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 13:26:24 +0200 Subject: [PATCH 35/37] Videos learning center model now uses the videos app feature --- ManiVault/src/AbstractHelpManager.h | 5 - .../src/models/LearningCenterVideosModel.cpp | 100 +++++++++++++++++- .../src/models/LearningCenterVideosModel.h | 28 ++++- ManiVault/src/private/HelpManager.cpp | 31 +----- 4 files changed, 127 insertions(+), 37 deletions(-) diff --git a/ManiVault/src/AbstractHelpManager.h b/ManiVault/src/AbstractHelpManager.h index 452fd4edc..9edba471c 100644 --- a/ManiVault/src/AbstractHelpManager.h +++ b/ManiVault/src/AbstractHelpManager.h @@ -108,11 +108,6 @@ class CORE_EXPORT AbstractHelpManager : public AbstractManager */ virtual void initializeNotifications(QWidget* parentWidget) = 0; -signals: - - /** Invoked when the videos model has been successfully populated from the website */ - void videosModelPopulatedFromWebsite(); - public: // Action getters virtual gui::ToggleAction& getShowLearningCenterPageAction() = 0; diff --git a/ManiVault/src/models/LearningCenterVideosModel.cpp b/ManiVault/src/models/LearningCenterVideosModel.cpp index 9e7500e50..9efdacdf7 100644 --- a/ManiVault/src/models/LearningCenterVideosModel.cpp +++ b/ManiVault/src/models/LearningCenterVideosModel.cpp @@ -4,11 +4,14 @@ #include "LearningCenterVideosModel.h" +#include + #ifdef _DEBUG //#define LEARNING_CENTER_VIDEOS_MODEL_VERBOSE #endif using namespace mv::util; +using namespace mv::gui; namespace mv { @@ -24,9 +27,57 @@ QMap(Column::Count)); + + _dsnsAction.setIconByName("globe"); + _dsnsAction.setToolTip("Videos Data Source Names (DSN)"); + _dsnsAction.setConfigurationFlag(WidgetAction::ConfigurationFlag::ForceCollapsedInGroup); + _dsnsAction.setDefaultWidgetFlags(StringsAction::WidgetFlag::ListView); + _dsnsAction.setPopupSizeHint(QSize(550, 100)); + + connect(&_dsnsAction, &StringsAction::stringsChanged, this, [this]() -> void { + setRowCount(0); + + _future = QtConcurrent::mapped( + _dsnsAction.getStrings(), + [this](const QString& dsn) { + return downloadVideosFromDsn(dsn); + }); + + connect(&_watcher, &QFutureWatcher::finished, [&]() { + for (int dsnIndex = 0; dsnIndex < _dsnsAction.getStrings().size(); ++dsnIndex) { + QJsonParseError jsonParseError; + + const auto jsonDocument = QJsonDocument::fromJson(_future.resultAt(dsnIndex), &jsonParseError); + + if (jsonParseError.error != QJsonParseError::NoError || !jsonDocument.isObject()) { + qWarning() << "Invalid JSON from DSN at index" << dsnIndex << ":" << jsonParseError.errorString(); + continue; + } + + const auto videos = jsonDocument.object()["videos"].toArray(); + + for (const auto video : videos) { + auto videoMap = video.toVariant().toMap(); + + addVideo(new LearningCenterVideo(LearningCenterVideo::Type::YouTube, videoMap["title"].toString(), videoMap["tags"].toStringList(), videoMap["date"].toString().chopped(15), videoMap["summary"].toString(), videoMap["youtube-id"].toString())); + } + } + + emit populatedFromDsns(); + }); + + _watcher.setFuture(_future); + }); + + for (auto pluginFactory : mv::plugins().getPluginFactoriesByTypes()) { + connect(&pluginFactory->getVideosDsnsAction(), &StringsAction::stringsChanged, this, &LearningCenterVideosModel::synchronizeWithDsns); + } + + connect(&mv::settings().getAppFeaturesSettingsAction().getVideosAppFeatureAction(), &VideosAppFeatureAction::enabledChanged, this, &LearningCenterVideosModel::synchronizeWithDsns); } QVariant LearningCenterVideosModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const @@ -70,6 +121,53 @@ QSet LearningCenterVideosModel::getTagsSet() const return _tags; } +void LearningCenterVideosModel::synchronizeWithDsns() +{ + if (!mv::settings().getAppFeaturesSettingsAction().getVideosAppFeatureAction().getEnabledAction().isChecked()) + return; + + auto uniqueDsns = _dsnsAction.getStrings(); + + for (auto pluginFactory : mv::plugins().getPluginFactoriesByTypes()) { + uniqueDsns << pluginFactory->getVideosDsnsAction().getStrings(); + } + + uniqueDsns.removeDuplicates(); + + _dsnsAction.setStrings(uniqueDsns); +} + +QByteArray LearningCenterVideosModel::downloadVideosFromDsn(const QString& dsn) +{ + QEventLoop loop; + + QByteArray downloadedData; + + FileDownloader fileDownloader; + + connect(&fileDownloader, &FileDownloader::downloaded, [&]() -> void { + try + { + downloadedData = fileDownloader.downloadedData(); + loop.quit(); + } + catch (std::exception& e) + { + exceptionMessageBox("Unable to download videos JSON from DSN", e); + } + catch (...) + { + exceptionMessageBox("Unable to download videos JSON from DSN"); + } + }); + + fileDownloader.download(dsn); + + loop.exec(); + + return downloadedData; +} + void LearningCenterVideosModel::addVideo(const LearningCenterVideo* video) { Q_ASSERT(video); diff --git a/ManiVault/src/models/LearningCenterVideosModel.h b/ManiVault/src/models/LearningCenterVideosModel.h index e02b0cc81..7580cdbfa 100644 --- a/ManiVault/src/models/LearningCenterVideosModel.h +++ b/ManiVault/src/models/LearningCenterVideosModel.h @@ -409,6 +409,24 @@ class CORE_EXPORT LearningCenterVideosModel final : public QStandardItemModel /** Builds a set of all video tags and emits LearningCenterVideosModel::tagsChanged(...) */ void updateTags(); + /** Synchronize the model with the data source names */ + void synchronizeWithDsns(); + +private: + + /** + * Download videos from \p dsn + * @param dsn Videos Data Source Name (DSN) + * @return Downloaded data + */ + static QByteArray downloadVideosFromDsn(const QString& dsn); + +public: // Action getters + + gui::StringsAction& getDsnsAction() { return _dsnsAction; } + + const gui::StringsAction& getDsnsAction() const { return _dsnsAction; } + signals: /** @@ -417,9 +435,15 @@ class CORE_EXPORT LearningCenterVideosModel final : public QStandardItemModel */ void tagsChanged(const QSet& tags); + /** Signals that the model was populated from one or more source DSNs */ + void populatedFromDsns(); + private: - util::LearningCenterVideos _videos; /** Model videos */ - QSet _tags; /** All tags */ + util::LearningCenterVideos _videos; /** Model videos */ + QSet _tags; /** All tags */ + gui::StringsAction _dsnsAction; /** Data source names action */ + QFuture _future; /** Future for downloading projects */ + QFutureWatcher _watcher; /** Future watcher for downloading projects */ }; } diff --git a/ManiVault/src/private/HelpManager.cpp b/ManiVault/src/private/HelpManager.cpp index c0dcf6d53..463e4f061 100644 --- a/ManiVault/src/private/HelpManager.cpp +++ b/ManiVault/src/private/HelpManager.cpp @@ -82,33 +82,6 @@ HelpManager::HelpManager(QObject* parent) : connect(&_toLearningCenterAction, &TriggerAction::triggered, this, [this]() -> void { _showLearningCenterPageAction.setChecked(true); }); - - /* - connect(&_fileDownloader, &FileDownloader::downloaded, this, [this]() -> void { - try - { - const auto jsonDocument = QJsonDocument::fromJson(_fileDownloader.downloadedData()); - const auto videos = jsonDocument.object()["videos"].toArray(); - const auto tutorials = jsonDocument.object()["tutorials"].toArray(); - - for (const auto video : videos) { - auto videoMap = video.toVariant().toMap(); - - addVideo(new LearningCenterVideo(LearningCenterVideo::Type::YouTube, videoMap["title"].toString(), videoMap["tags"].toStringList(), videoMap["date"].toString().chopped(15), videoMap["summary"].toString(), videoMap["youtube-id"].toString())); - } - - emit videosModelPopulatedFromWebsite(); - } - catch (std::exception& e) - { - exceptionMessageBox("Unable to process learning center JSON", e); - } - catch (...) - { - exceptionMessageBox("Unable to process learning center JSON"); - } - }); - */ } HelpManager::~HelpManager() @@ -132,8 +105,8 @@ void HelpManager::initialize() _tutorialsModel.getDsnsAction().addString("https://www.manivault.studio/api/learning-center.json"); _tutorialsModel.synchronizeWithDsns(); - //_videosModel.getDsnsAction().addString("https://www.manivault.studio/api/learning-center.json"); - //_videosModel.synchronizeWithDsns(); + _videosModel.getDsnsAction().addString("https://www.manivault.studio/api/learning-center.json"); + _videosModel.synchronizeWithDsns(); } endInitialization(); } From 14710c773db00b36805f58d858e783ddb2184a28 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Thu, 8 May 2025 13:34:18 +0200 Subject: [PATCH 36/37] Automatically toggle videos and tutorials sections of the start and learning center pages when the corresponding app features are enabled --- ManiVault/src/private/LearningPageContentWidget.cpp | 10 ++++++++++ ManiVault/src/private/StartPageContentWidget.cpp | 5 +++++ ManiVault/src/private/StartPageGetStartedWidget.cpp | 5 +++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ManiVault/src/private/LearningPageContentWidget.cpp b/ManiVault/src/private/LearningPageContentWidget.cpp index 0ab6f3e15..cb2150273 100644 --- a/ManiVault/src/private/LearningPageContentWidget.cpp +++ b/ManiVault/src/private/LearningPageContentWidget.cpp @@ -110,5 +110,15 @@ LearningPageContentWidget::LearningPageContentWidget(QWidget* parent /*= nullptr connect(&videosAppFeatureEnabledAction, &ToggleAction::toggled, this, updateToggleSectionActionsVisibility); connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, updateToggleSectionActionsVisibility); + + connect(&videosAppFeatureEnabledAction, &ToggleAction::toggled, this, [this](bool toggled) -> void { + if (toggled) + _toggleVideosSectionAction.setChecked(true); + }); + + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, [this](bool toggled) -> void { + if (toggled) + _toggleTutorialsSectionAction.setChecked(true); + }); } diff --git a/ManiVault/src/private/StartPageContentWidget.cpp b/ManiVault/src/private/StartPageContentWidget.cpp index 66b151ab4..2ff0e4c5f 100644 --- a/ManiVault/src/private/StartPageContentWidget.cpp +++ b/ManiVault/src/private/StartPageContentWidget.cpp @@ -104,6 +104,11 @@ StartPageContentWidget::StartPageContentWidget(QWidget* parent /*= nullptr*/) : updateTutorialsToggleVisibility(); connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, updateTutorialsToggleVisibility); + + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, [this](bool toggled) -> void { + if (toggled) + _toggleTutorialsSectionAction.setChecked(true); + }); } void StartPageContentWidget::updateActions() diff --git a/ManiVault/src/private/StartPageGetStartedWidget.cpp b/ManiVault/src/private/StartPageGetStartedWidget.cpp index 1eaf3d0f5..df0b827d8 100644 --- a/ManiVault/src/private/StartPageGetStartedWidget.cpp +++ b/ManiVault/src/private/StartPageGetStartedWidget.cpp @@ -75,12 +75,13 @@ StartPageGetStartedWidget::StartPageGetStartedWidget(StartPageContentWidget* sta _tutorialsWidget.setVisible(tutorialsAppFeatureEnabledAction.isChecked() && _startPageContentWidget->getToggleTutorialsAction().isChecked()); }; + toggleViews(); + connect(&_startPageContentWidget->getToggleProjectFromWorkspaceAction(), &ToggleAction::toggled, this, toggleViews); connect(&_startPageContentWidget->getToggleProjectFromDataAction(), &ToggleAction::toggled, this, toggleViews); connect(&_startPageContentWidget->getToggleTutorialsAction(), &ToggleAction::toggled, this, toggleViews); - connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, toggleViews); - toggleViews(); + connect(&tutorialsAppFeatureEnabledAction, &ToggleAction::toggled, this, toggleViews); } void StartPageGetStartedWidget::updateActions() From 987fc02ad130e9d11cb0f90024a372063729308e Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Wed, 9 Jul 2025 08:04:43 +0200 Subject: [PATCH 37/37] Change projects disclaimer --- ManiVault/res/html/AppFeatureProjects.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ManiVault/res/html/AppFeatureProjects.html b/ManiVault/res/html/AppFeatureProjects.html index 1336aa048..52e0ec1fb 100644 --- a/ManiVault/res/html/AppFeatureProjects.html +++ b/ManiVault/res/html/AppFeatureProjects.html @@ -7,7 +7,7 @@

      Projects

    • Fetch available projects listings.
    • Download projects.
    -

    You will find this feature at the start page of ManiVault Studio.

    +

    You will find this feature at the start page, and posibly during startup of ManiVault Studio.

    Projects listings and projects might originate from:

    • Servers hosted by the ManiVault Studio team.