LCOV - code coverage report
Current view: top level - src/project/internal - saveprojectscenario.h Coverage Total Hit
Test: filtered_coverage.info Lines: 100.0 % 5 5
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) 2026 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              : 
      23              : #pragma once
      24              : 
      25              : #include "isaveprojectscenario.h"
      26              : 
      27              : #include <QIODevice>
      28              : #include <QString>
      29              : #include <QUrl>
      30              : 
      31              : #include "modularity/ioc.h"
      32              : #include "async/asyncable.h"
      33              : #include "async/promise.h"
      34              : #include "interactive/iinteractive.h"
      35              : #include "interactive/iplatforminteractive.h"
      36              : #include "project/iprojectsession.h"
      37              : #include "cloud/musescorecom/imusescorecomservice.h"
      38              : #include "cloud/audiocom/iaudiocomservice.h"
      39              : #include "io/ifilesystem.h"
      40              : #include "notation/inotationconfiguration.h"
      41              : #include "progress.h"
      42              : 
      43              : #include "iexportprojectscenario.h"
      44              : #include "iprojectconfiguration.h"
      45              : #include "irecentfilescontroller.h"
      46              : #include "iopenprojectscenario.h"
      47              : 
      48              : namespace mu::project {
      49              : class SaveProjectScenario : public ISaveProjectScenario, public muse::Contextable, public muse::async::Asyncable
      50              : {
      51              :     friend class SaveProjectScenarioTests;
      52              : 
      53              : public:
      54              :     muse::GlobalInject<IProjectConfiguration> configuration;
      55              :     muse::GlobalInject<notation::INotationConfiguration> notationConfiguration;
      56              :     muse::GlobalInject<muse::io::IFileSystem> fileSystem;
      57              :     muse::GlobalInject<muse::cloud::IMuseScoreComService> museScoreComService;
      58              :     muse::GlobalInject<muse::cloud::IAudioComService> audioComService;
      59              :     muse::GlobalInject<muse::IPlatformInteractive> platformInteractive;
      60              :     muse::ContextInject<IRecentFilesController> recentFilesController = { this };
      61              :     muse::ContextInject<IExportProjectScenario> exportProjectScenario = { this };
      62              :     muse::ContextInject<muse::IInteractive> interactive = { this };
      63              :     muse::ContextInject<project::IProjectSession> projectSession = { this };
      64              :     muse::ContextInject<IOpenProjectScenario> openProjectScenario = { this };
      65              : 
      66           61 :     SaveProjectScenario(const muse::modularity::ContextPtr& iocCtx)
      67           61 :         : muse::Contextable(iocCtx) {}
      68              : 
      69              :     muse::async::Promise<muse::Ret> saveProject(SaveMode saveMode, SaveLocationType saveLocationType = SaveLocationType::Undefined,
      70              :                                                 bool force = false) override;
      71              :     muse::async::Promise<muse::Ret> saveProject(const muse::io::path_t& path = muse::io::path_t()) override;
      72              :     muse::async::Promise<muse::Ret> saveProjectAt(const muse::rcommand::Params& params) override;
      73              : 
      74              :     muse::async::Promise<muse::Ret> publish() override;
      75              :     muse::async::Promise<muse::Ret> shareAudio() override;
      76              : 
      77              :     bool isBusy(BusyStatus status) const override;
      78              :     muse::async::Notification busyChanged() const override;
      79              : 
      80              : private:
      81              :     static constexpr int RET_CODE_CHANGE_SAVE_LOCATION_TYPE = 1234;
      82              :     static constexpr int RET_CODE_CONFLICT_RESPONSE_SAVE_AS = 1235;
      83              :     static constexpr int RET_CODE_CONFLICT_RESPONSE_PUBLISH_AS_NEW_SCORE = 1236;
      84              :     static constexpr int RET_CODE_CONFLICT_RESPONSE_REPLACE = 1237;
      85              : 
      86              :     struct AudioFile {
      87              :         QString format;
      88              :         std::shared_ptr<QIODevice> device = nullptr;
      89              : 
      90           25 :         AudioFile() {}
      91              : 
      92           10 :         bool isValid() const
      93              :         {
      94           10 :             return !format.isEmpty() && device != nullptr;
      95              :         }
      96              :     };
      97              : 
      98              :     INotationProjectPtr currentNotationProject() const;
      99              :     notation::INotationInteractionPtr currentInteraction() const;
     100              : 
     101              :     void setBusy(BusyStatus status, bool isBusy);
     102              :     muse::async::Promise<muse::Ret> runIfNotBusy(BusyStatus status, const std::function<muse::async::Promise<muse::Ret>()>& flow);
     103              : 
     104              :     muse::async::Promise<muse::RetVal<muse::Val> > openDialog(const muse::UriQuery& query) const;
     105              : 
     106              :     muse::async::Promise<bool> refuseSaveAfter(muse::async::Promise<muse::Ret> shown);
     107              : 
     108              :     muse::async::Promise<muse::RetVal<SaveLocation> > askSaveLocation(INotationProjectPtr project, SaveMode mode,
     109              :                                                                       SaveLocationType preselectedType = SaveLocationType::Undefined) const;
     110              :     muse::async::Promise<muse::RetVal<SaveLocation> > askSaveLocationOfType(INotationProjectPtr project, SaveMode mode,
     111              :                                                                             SaveLocationType type) const;
     112              :     muse::async::Promise<muse::RetVal<muse::io::path_t> > askLocalPath(INotationProjectPtr project, SaveMode mode) const;
     113              :     muse::async::Promise<muse::Ret> saveProjectLocallyInstead(const INotationProjectPtr& project, SaveMode saveMode);
     114              :     muse::async::Promise<muse::RetVal<SaveLocationType> > saveLocationType() const;
     115              :     muse::async::Promise<muse::RetVal<SaveLocationType> > askSaveLocationType() const;
     116              :     muse::async::Promise<muse::RetVal<CloudProjectInfo> > askCloudLocation(INotationProjectPtr project, SaveMode mode) const;
     117              :     muse::async::Promise<muse::RetVal<CloudProjectInfo> > askPublishLocation(INotationProjectPtr project) const;
     118              :     muse::async::Promise<muse::RetVal<CloudAudioInfo> > askShareAudioLocation(INotationProjectPtr project) const;
     119              :     muse::async::Promise<muse::RetVal<CloudAudioInfo> > doAskShareAudioLocation(INotationProjectPtr project) const;
     120              :     muse::async::Promise<muse::RetVal<CloudProjectInfo> > doAskCloudLocation(INotationProjectPtr project, SaveMode mode,
     121              :                                                                              bool isPublishShare) const;
     122              :     muse::async::Promise<muse::RetVal<CloudProjectInfo> > doAskCloudLocationAuthorized(INotationProjectPtr project, SaveMode mode,
     123              :                                                                                        bool isPublishShare) const;
     124              :     muse::async::Promise<muse::RetVal<CloudProjectInfo> > askCloudProjectInfo(INotationProjectPtr project, SaveMode mode,
     125              :                                                                               bool isPublishShare) const;
     126              :     muse::async::Promise<muse::RetVal<CloudProjectInfo> > askCloudProjectInfo(INotationProjectPtr project, SaveMode mode,
     127              :                                                                               bool isPublishShare, const QString& defaultName,
     128              :                                                                               muse::cloud::Visibility defaultVisibility,
     129              :                                                                               const QUrl& existingScoreUrl) const;
     130              :     muse::async::Promise<bool> warnBeforePublishing(bool isPublishShare, muse::cloud::Visibility visibility) const;
     131              :     muse::async::Promise<bool> warnBeforeSavingToExistingPubliclyVisibleCloudProject() const;
     132              :     muse::async::Promise<muse::Ret> warnCloudNotAvailableForUploading(bool isPublishShare) const;
     133              :     muse::async::Promise<muse::Ret> warnCloudNotAvailableForSharingAudio() const;
     134              :     muse::async::Promise<muse::RetVal<muse::Val> > ensureAuthorization(const QString& cloudCode, bool publishingScore,
     135              :                                                                        const std::string& text) const;
     136              :     muse::async::Promise<muse::Ret> showCloudSaveError(const muse::Ret& ret, const CloudProjectInfo& info, bool isPublishShare,
     137              :                                                        bool alreadyAttempted) const;
     138              :     muse::async::Promise<muse::Ret> showAudioCloudShareError(const muse::Ret& ret) const;
     139              : 
     140              :     muse::Ret canSaveProject() const;
     141              :     muse::async::Promise<muse::Ret> saveProjectAt(const SaveLocation& saveLocation, SaveMode saveMode = SaveMode::Save, bool force = false);
     142              :     muse::async::Promise<muse::Ret> doSaveProjectAt(const SaveLocation& saveLocation, SaveMode saveMode);
     143              :     muse::async::Promise<muse::Ret> saveProjectToCloud(CloudProjectInfo info, SaveMode saveMode = SaveMode::Save);
     144              :     muse::async::Promise<muse::Ret> doSaveProjectToCloud(const CloudProjectInfo& info, SaveMode saveMode);
     145              :     muse::async::Promise<muse::Ret> saveAndUploadProject(const INotationProjectPtr& project, CloudProjectInfo info, SaveMode saveMode);
     146              :     muse::async::Promise<muse::Ret> doSaveAndUploadProject(const INotationProjectPtr& project, const CloudProjectInfo& info,
     147              :                                                            SaveMode saveMode, bool isPublic);
     148              :     muse::async::Promise<muse::Ret> saveProjectLocally(const muse::io::path_t& path, SaveMode saveMode = SaveMode::Save,
     149              :                                                        bool createBackup = true);
     150              :     muse::async::Promise<muse::Ret> saveCloudProjectLocally(const INotationProjectPtr& project, const CloudProjectInfo& info,
     151              :                                                             SaveMode saveMode);
     152              : 
     153              :     muse::async::Promise<muse::Ret> shareAudio(const AudioFile& existingAudio);
     154              :     muse::async::Promise<muse::Ret> uploadAudioToAudioCom(const AudioFile& audio, const INotationProjectPtr& project,
     155              :                                                           const CloudAudioInfo& info);
     156              :     muse::async::Promise<muse::Ret> alsoShareAudioCom(const AudioFile& audio);
     157              : 
     158              :     muse::async::Promise<muse::Ret> askAudioGenerationSettings() const;
     159              :     muse::async::Promise<muse::RetVal<bool> > needGenerateAudio(bool isPublic) const;
     160              :     bool needGenerateAudioAccordingToSettings() const;
     161              :     AudioFile exportMp3(const notation::INotationPtr notation) const;
     162              : 
     163              :     void showUploadProgressDialog();
     164              :     void closeUploadProgressDialog();
     165              : 
     166              :     muse::async::Promise<muse::Ret> uploadProject(const CloudProjectInfo& info, const AudioFile& audio, bool openEditUrl, bool publishMode);
     167              :     muse::async::Promise<muse::Ret> uploadAudioToMuseScoreCom(const AudioFile& audio, const QUrl& sourceUrl, const QUrl& urlToOpen,
     168              :                                                               bool isFirstSave, bool publishMode);
     169              : 
     170              :     muse::async::Promise<muse::Ret> onUploadFinished(const QUrl& urlToOpen, bool isFirstSave, const AudioFile& audio, bool publishMode);
     171              :     muse::async::Promise<muse::Ret> onProjectSuccessfullyUploaded(const QUrl& urlToOpen = QUrl(), bool isFirstSave = true);
     172              :     muse::async::Promise<muse::Ret> onProjectUploadFailed(const muse::Ret& ret, const CloudProjectInfo& info, const AudioFile& audio,
     173              :                                                           bool openEditUrl, bool publishMode);
     174              : 
     175              :     void onAudioSuccessfullyUploaded(const QUrl& urlToOpen);
     176              :     muse::async::Promise<muse::Ret> onAudioUploadFailed(const muse::Ret& ret);
     177              : 
     178              :     muse::async::Promise<muse::Ret> warnCloudIsNotAvailable();
     179              : 
     180              :     muse::async::Promise<bool> askIfUserAgreesToSaveProjectWithErrors(const muse::Ret& ret, const SaveLocation& location);
     181              :     muse::async::Promise<bool> askIfUserAgreesToSaveCorruptedScore(const SaveLocation& location, const std::string& errorText,
     182              :                                                                    bool newlyCreated);
     183              :     muse::async::Promise<muse::Ret> warnCorruptedScoreCannotBeSavedOnCloud(const std::string& errorText, bool canRevert);
     184              :     muse::async::Promise<bool> askIfUserAgreesToSaveCorruptedScoreLocally(const std::string& errorText, bool canRevert);
     185              :     muse::async::Promise<bool> askIfUserAgreesToSaveCorruptedScoreUponOpenning(const SaveLocation& location, const std::string& errorText);
     186              :     muse::async::Promise<muse::Ret> showErrCorruptedScoreCannotBeSaved(const SaveLocation& location, const std::string& errorText);
     187              : 
     188              :     muse::async::Promise<muse::Ret> warnScoreCouldnotBeSaved(const muse::Ret& ret);
     189              :     muse::async::Promise<muse::Ret> warnScoreCouldnotBeSaved(const std::string& errorText);
     190              :     muse::async::Promise<int> warnScoreHasBecomeCorruptedAfterSave(const muse::Ret& ret);
     191              : 
     192              :     muse::async::Promise<muse::Ret> askToRevertCorruptedScoreToLastSaved();
     193              : 
     194              :     RecentFile makeRecentFile(INotationProjectPtr project);
     195              :     void moveProject(INotationProjectPtr project, const muse::io::path_t& newPath, bool replace);
     196              : 
     197              :     QUrl scoreManagerUrl() const;
     198              : 
     199              :     std::set<BusyStatus> m_busyStatuses;
     200              :     muse::async::Notification m_busyChanged;
     201              : 
     202              :     muse::ProgressPtr m_uploadingProjectProgress = nullptr;
     203              :     muse::ProgressPtr m_uploadingAudioProgress = nullptr;
     204              : 
     205              :     int m_numberOfSavesToCloud = 0;
     206              : };
     207              : }
        

Generated by: LCOV version 2.0-1