LCOV - code coverage report
Current view: top level - src/appshell/internal - appshellconfiguration.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 157 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "appshellconfiguration.h"
      23              : 
      24              : #include <QJsonArray>
      25              : #include <QJsonDocument>
      26              : 
      27              : #include "settings.h"
      28              : 
      29              : #include "multiwindows/resourcelockguard.h"
      30              : 
      31              : #include "log.h"
      32              : 
      33              : using namespace muse;
      34              : using namespace mu;
      35              : using namespace mu::appshell;
      36              : using namespace mu::notation;
      37              : 
      38              : static const std::string module_name("appshell");
      39              : 
      40              : static const Settings::Key HAS_COMPLETED_FIRST_LAUNCH_SETUP(module_name, "application/hasCompletedFirstLaunchSetup");
      41              : 
      42              : static const Settings::Key WELCOME_DIALOG_SHOW_ON_STARTUP_KEY(module_name, "application/welcomeDialogShowOnStartup");
      43              : static const Settings::Key WELCOME_DIALOG_LAST_SHOWN_VERSION_KEY(module_name, "application/welcomeDialogLastShownVersion");
      44              : static const Settings::Key WELCOME_DIALOG_LAST_SHOWN_INDEX(module_name, "application/welcomeDialogLastShownIndex");
      45              : 
      46              : static const Settings::Key STARTUP_MODE_TYPE(module_name, "application/startup/modeStart");
      47              : static const Settings::Key STARTUP_SCORE_PATH(module_name, "application/startup/startScore");
      48              : 
      49              : static const std::string MUSESCORE_ONLINE_HANDBOOK_URL("https://handbook.musescore.org");
      50              : 
      51              : static const std::string MUSESCORE_ASK_FOR_HELP_URL_PATH("/redirect/post/question");
      52              : static const std::string MUSESCORE_ACCESSIBILITY_STATEMENT_URL_PATH("/about/musescore-studio-accessibility-statement");
      53              : static const std::string MUSESCORE_FORUM_URL_PATH("/forum");
      54              : static const std::string MUSESCORE_CONTRIBUTE_URL_PATH("/contribute");
      55              : static const std::string MUSEHUB_FREE_MUSE_SOUNDS_URL("https://www.musehub.com/free-musesounds"
      56              :                                                       "?utm_source=mss-app-dialog-ms-free"
      57              :                                                       "&utm_medium=mss-app-dialog-ms-free"
      58              :                                                       "&utm_campaign=mss-app-dialog-ms-free"
      59              :                                                       "&utm_id=mss-app-dialog");
      60              : static const std::string MUSICXML_URL("https://w3.org");
      61              : static const std::string MUSICXML_LICENSE_URL(MUSICXML_URL + "/community/about/process/final/");
      62              : static const std::string MUSICXML_LICENSE_DEED_URL(MUSICXML_URL + "/community/about/process/fsa-deed/");
      63              : 
      64              : static const std::string UTM_MEDIUM_MENU("menu");
      65              : 
      66              : static const Settings::Key SPLASH_SCREEN_VISIBLE_KEY(module_name, "ui/application/startup/showSplashScreen");
      67              : 
      68              : static const muse::io::path_t SESSION_FILE("/session.json");
      69              : static const std::string SESSION_RESOURCE_NAME("SESSION");
      70              : 
      71            0 : void AppShellConfiguration::init()
      72              : {
      73            0 :     settings()->setDefaultValue(HAS_COMPLETED_FIRST_LAUNCH_SETUP, Val(false));
      74              : 
      75            0 :     settings()->setDefaultValue(WELCOME_DIALOG_SHOW_ON_STARTUP_KEY, Val(true));
      76            0 :     settings()->valueChanged(WELCOME_DIALOG_SHOW_ON_STARTUP_KEY).onReceive(this, [this](const Val&) {
      77            0 :         m_welcomeDialogShowOnStartupChanged.notify();
      78            0 :     });
      79              : 
      80            0 :     settings()->setDefaultValue(WELCOME_DIALOG_LAST_SHOWN_VERSION_KEY, Val("0.0.0"));
      81            0 :     settings()->setDefaultValue(WELCOME_DIALOG_LAST_SHOWN_INDEX, Val(-1));
      82              : 
      83            0 :     settings()->setDefaultValue(STARTUP_MODE_TYPE, Val(StartupModeType::StartEmpty));
      84            0 :     settings()->valueChanged(STARTUP_MODE_TYPE).onReceive(this, [this](const Val&) {
      85            0 :         m_startupModeTypeChanged.notify();
      86            0 :     });
      87              : 
      88            0 :     settings()->setDefaultValue(STARTUP_SCORE_PATH, Val(projectConfiguration()->myFirstProjectPath().toStdString()));
      89            0 :     settings()->valueChanged(STARTUP_SCORE_PATH).onReceive(this, [this](const Val&) {
      90            0 :         m_startupScorePathChanged.notify();
      91            0 :     });
      92              : 
      93            0 :     fileSystem()->makePath(sessionDataPath());
      94            0 : }
      95              : 
      96            0 : bool AppShellConfiguration::hasCompletedFirstLaunchSetup() const
      97              : {
      98              : #ifdef Q_OS_WASM
      99              :     return true;
     100              : #else
     101            0 :     return settings()->value(HAS_COMPLETED_FIRST_LAUNCH_SETUP).toBool();
     102              : #endif
     103              : }
     104              : 
     105            0 : void AppShellConfiguration::setHasCompletedFirstLaunchSetup(bool has)
     106              : {
     107            0 :     settings()->setSharedValue(HAS_COMPLETED_FIRST_LAUNCH_SETUP, Val(has));
     108            0 : }
     109              : 
     110            0 : bool AppShellConfiguration::welcomeDialogShowOnStartup() const
     111              : {
     112            0 :     return settings()->value(WELCOME_DIALOG_SHOW_ON_STARTUP_KEY).toBool();
     113              : }
     114              : 
     115            0 : void AppShellConfiguration::setWelcomeDialogShowOnStartup(bool show)
     116              : {
     117            0 :     settings()->setSharedValue(WELCOME_DIALOG_SHOW_ON_STARTUP_KEY, Val(show));
     118            0 : }
     119              : 
     120            0 : async::Notification AppShellConfiguration::welcomeDialogShowOnStartupChanged() const
     121              : {
     122            0 :     return m_welcomeDialogShowOnStartupChanged;
     123              : }
     124              : 
     125            0 : std::string AppShellConfiguration::welcomeDialogLastShownVersion() const
     126              : {
     127            0 :     return settings()->value(WELCOME_DIALOG_LAST_SHOWN_VERSION_KEY).toString();
     128              : }
     129              : 
     130            0 : void AppShellConfiguration::setWelcomeDialogLastShownVersion(const std::string& version)
     131              : {
     132            0 :     settings()->setSharedValue(WELCOME_DIALOG_LAST_SHOWN_VERSION_KEY, Val(version));
     133            0 : }
     134              : 
     135            0 : int AppShellConfiguration::welcomeDialogLastShownIndex() const
     136              : {
     137            0 :     return settings()->value(WELCOME_DIALOG_LAST_SHOWN_INDEX).toInt();
     138              : }
     139              : 
     140            0 : void AppShellConfiguration::setWelcomeDialogLastShownIndex(int index)
     141              : {
     142            0 :     settings()->setSharedValue(WELCOME_DIALOG_LAST_SHOWN_INDEX, Val(index));
     143            0 : }
     144              : 
     145            0 : StartupModeType AppShellConfiguration::startupModeType() const
     146              : {
     147            0 :     return settings()->value(STARTUP_MODE_TYPE).toEnum<StartupModeType>();
     148              : }
     149              : 
     150            0 : void AppShellConfiguration::setStartupModeType(StartupModeType type)
     151              : {
     152            0 :     settings()->setSharedValue(STARTUP_MODE_TYPE, Val(type));
     153            0 : }
     154              : 
     155            0 : async::Notification AppShellConfiguration::startupModeTypeChanged() const
     156              : {
     157            0 :     return m_startupModeTypeChanged;
     158              : }
     159              : 
     160            0 : muse::io::path_t AppShellConfiguration::startupScorePath() const
     161              : {
     162            0 :     return settings()->value(STARTUP_SCORE_PATH).toString();
     163              : }
     164              : 
     165            0 : void AppShellConfiguration::setStartupScorePath(const muse::io::path_t& scorePath)
     166              : {
     167            0 :     settings()->setSharedValue(STARTUP_SCORE_PATH, Val(scorePath.toStdString()));
     168            0 : }
     169              : 
     170            0 : async::Notification AppShellConfiguration::startupScorePathChanged() const
     171              : {
     172            0 :     return m_startupScorePathChanged;
     173              : }
     174              : 
     175            0 : std::string AppShellConfiguration::handbookUrl() const
     176              : {
     177            0 :     std::string utm = utmParameters(UTM_MEDIUM_MENU);
     178            0 :     std::string languageCode = currentLanguageCode();
     179              : 
     180              :     QStringList params = {
     181              :         "tag=handbook",
     182            0 :         "locale=" + QString::fromStdString(languageCode),
     183              :         QString::fromStdString(utm)
     184            0 :     };
     185              : 
     186            0 :     return MUSESCORE_ONLINE_HANDBOOK_URL + "?" + params.join("&").toStdString();
     187            0 : }
     188              : 
     189            0 : std::string AppShellConfiguration::askForHelpUrl() const
     190              : {
     191            0 :     std::string languageCode = currentLanguageCode();
     192              : 
     193              :     QStringList params = {
     194            0 :         "locale=" + QString::fromStdString(languageCode)
     195            0 :     };
     196              : 
     197            0 :     return museScoreUrl() + MUSESCORE_ASK_FOR_HELP_URL_PATH + "?" + params.join("&").toStdString();
     198            0 : }
     199              : 
     200            0 : std::string AppShellConfiguration::accessibilityStatementUrl() const
     201              : {
     202            0 :     return museScoreUrl() + MUSESCORE_ACCESSIBILITY_STATEMENT_URL_PATH;
     203              : }
     204              : 
     205            0 : std::string AppShellConfiguration::museScoreUrl() const
     206              : {
     207            0 :     return updateConfiguration()->appWebSiteUrl();
     208              : }
     209              : 
     210            0 : std::string AppShellConfiguration::museScoreForumUrl() const
     211              : {
     212            0 :     return museScoreUrl() + MUSESCORE_FORUM_URL_PATH;
     213              : }
     214              : 
     215            0 : std::string AppShellConfiguration::museScoreContributionUrl() const
     216              : {
     217            0 :     return museScoreUrl() + MUSESCORE_CONTRIBUTE_URL_PATH;
     218              : }
     219              : 
     220            0 : std::string AppShellConfiguration::museHubFreeMuseSoundsUrl() const
     221              : {
     222            0 :     return MUSEHUB_FREE_MUSE_SOUNDS_URL;
     223              : }
     224              : 
     225            0 : std::string AppShellConfiguration::musicXMLLicenseUrl() const
     226              : {
     227            0 :     return MUSICXML_LICENSE_URL;
     228              : }
     229              : 
     230            0 : std::string AppShellConfiguration::musicXMLLicenseDeedUrl() const
     231              : {
     232            0 :     return MUSICXML_LICENSE_DEED_URL;
     233              : }
     234              : 
     235            0 : std::string AppShellConfiguration::museScoreVersion() const
     236              : {
     237            0 :     return String(application()->version().toString() + u"." + application()->build()).toStdString();
     238              : }
     239              : 
     240            0 : std::string AppShellConfiguration::museScoreRevision() const
     241              : {
     242            0 :     return application()->revision().toStdString();
     243              : }
     244              : 
     245            0 : bool AppShellConfiguration::needShowSplashScreen() const
     246              : {
     247            0 :     return settings()->value(SPLASH_SCREEN_VISIBLE_KEY).toBool();
     248              : }
     249              : 
     250            0 : void AppShellConfiguration::setNeedShowSplashScreen(bool show)
     251              : {
     252            0 :     settings()->setSharedValue(SPLASH_SCREEN_VISIBLE_KEY, Val(show));
     253            0 : }
     254              : 
     255            0 : const QString& AppShellConfiguration::preferencesDialogLastOpenedPageId() const
     256              : {
     257            0 :     return m_preferencesDialogCurrentPageId;
     258              : }
     259              : 
     260            0 : void AppShellConfiguration::setPreferencesDialogLastOpenedPageId(const QString& lastOpenedPageId)
     261              : {
     262            0 :     m_preferencesDialogCurrentPageId = lastOpenedPageId;
     263            0 : }
     264              : 
     265            0 : void AppShellConfiguration::startEditSettings()
     266              : {
     267            0 :     settings()->beginTransaction();
     268            0 : }
     269              : 
     270            0 : void AppShellConfiguration::applySettings()
     271              : {
     272            0 :     settings()->commitTransaction();
     273            0 : }
     274              : 
     275            0 : void AppShellConfiguration::rollbackSettings()
     276              : {
     277            0 :     settings()->rollbackTransaction();
     278            0 : }
     279              : 
     280            0 : void AppShellConfiguration::revertToFactorySettings(bool keepDefaultSettings, bool notifyAboutChanges, bool notifyOtherInstances) const
     281              : {
     282            0 :     settings()->reset(keepDefaultSettings, notifyAboutChanges, notifyOtherInstances);
     283            0 : }
     284              : 
     285            0 : muse::io::paths_t AppShellConfiguration::sessionProjectsPaths() const
     286              : {
     287            0 :     RetVal<ByteArray> retVal = readSessionState();
     288            0 :     if (!retVal.ret) {
     289            0 :         LOGE() << retVal.ret.toString();
     290            0 :         return {};
     291              :     }
     292              : 
     293            0 :     return parseSessionProjectsPaths(retVal.val.toQByteArrayNoCopy());
     294            0 : }
     295              : 
     296            0 : muse::Ret AppShellConfiguration::setSessionProjectsPaths(const muse::io::paths_t& paths)
     297              : {
     298            0 :     QJsonArray jsonArray;
     299            0 :     for (const muse::io::path_t& path : paths) {
     300            0 :         jsonArray << QJsonValue(path.toQString());
     301              :     }
     302              : 
     303            0 :     QByteArray data = QJsonDocument(jsonArray).toJson();
     304            0 :     return writeSessionState(data);
     305            0 : }
     306              : 
     307            0 : std::string AppShellConfiguration::utmParameters(const std::string& utmMedium) const
     308              : {
     309            0 :     return "utm_source=desktop&utm_medium=" + utmMedium
     310            0 :            + "&utm_content=" + application()->revision().toStdString()
     311            0 :            + "&utm_campaign=MuseScore" + application()->version().toStdString();
     312              : }
     313              : 
     314            0 : std::string AppShellConfiguration::currentLanguageCode() const
     315              : {
     316            0 :     QString languageCode = languagesConfiguration()->currentLanguageCode().val;
     317            0 :     QLocale locale(languageCode);
     318              : 
     319            0 :     return locale.bcp47Name().toStdString();
     320            0 : }
     321              : 
     322            0 : muse::io::path_t AppShellConfiguration::sessionDataPath() const
     323              : {
     324            0 :     return globalConfiguration()->userAppDataPath() + "/session";
     325              : }
     326              : 
     327            0 : muse::io::path_t AppShellConfiguration::sessionFilePath() const
     328              : {
     329            0 :     return sessionDataPath() + SESSION_FILE;
     330              : }
     331              : 
     332            0 : RetVal<muse::ByteArray> AppShellConfiguration::readSessionState() const
     333              : {
     334            0 :     muse::mi::ReadResourceLockGuard lock_guard(multiwindowsProvider.get(), SESSION_RESOURCE_NAME);
     335            0 :     return fileSystem()->readFile(sessionFilePath());
     336            0 : }
     337              : 
     338            0 : muse::Ret AppShellConfiguration::writeSessionState(const QByteArray& data)
     339              : {
     340            0 :     muse::mi::WriteResourceLockGuard lock_guard(multiwindowsProvider.get(), SESSION_RESOURCE_NAME);
     341            0 :     return fileSystem()->writeFile(sessionFilePath(), ByteArray::fromQByteArrayNoCopy(data));
     342            0 : }
     343              : 
     344            0 : muse::io::paths_t AppShellConfiguration::parseSessionProjectsPaths(const QByteArray& json) const
     345              : {
     346            0 :     QJsonParseError err;
     347            0 :     QJsonDocument jsodDoc = QJsonDocument::fromJson(json, &err);
     348            0 :     if (err.error != QJsonParseError::NoError || !jsodDoc.isArray()) {
     349            0 :         LOGE() << "failed parse, err: " << err.errorString();
     350            0 :         return {};
     351              :     }
     352              : 
     353            0 :     io::paths_t result;
     354            0 :     const QVariantList pathsList = jsodDoc.array().toVariantList();
     355            0 :     for (const QVariant& pathVal : pathsList) {
     356            0 :         muse::io::path_t path = pathVal.toString().toStdString();
     357            0 :         if (!path.empty()) {
     358            0 :             result.push_back(path);
     359              :         }
     360            0 :     }
     361              : 
     362            0 :     return result;
     363            0 : }
        

Generated by: LCOV version 2.0-1