Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-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 "workspace.h"
23 :
24 : #include "multiwindows/resourcelockguard.h"
25 :
26 : #include "workspacefile.h"
27 : #include "workspaceerrors.h"
28 :
29 : #include "log.h"
30 :
31 : using namespace muse;
32 : using namespace muse::workspace;
33 :
34 4 : Workspace::Workspace(const io::path_t& filePath, const modularity::ContextPtr& iocCtx)
35 4 : : Contextable(iocCtx)
36 : {
37 4 : m_file = std::make_shared<WorkspaceFile>(filePath);
38 :
39 4 : multiwindowsProvider()->resourceChanged().onReceive(this, [this](const std::string& resourceName){
40 0 : if (resourceName == fileResourceName()) {
41 0 : reload();
42 : }
43 0 : });
44 4 : }
45 :
46 0 : Workspace::Workspace(const io::path_t& filePath, const Workspace* other, const modularity::ContextPtr& iocCtx)
47 0 : : Workspace(filePath, iocCtx)
48 : {
49 0 : m_file = std::make_shared<WorkspaceFile>(filePath, other->m_file.get());
50 0 : }
51 :
52 16 : std::string Workspace::name() const
53 : {
54 16 : return io::completeBasename(m_file->filePath()).toStdString();
55 : }
56 :
57 0 : bool Workspace::isBuiltin() const
58 : {
59 0 : io::path_t builtinWorkspacePath = this->builtinWorkspacePath();
60 0 : return !builtinWorkspacePath.empty();
61 0 : }
62 :
63 0 : bool Workspace::isEdited() const
64 : {
65 0 : if (!isBuiltin()) {
66 0 : return false;
67 : }
68 :
69 0 : if (m_file->isNeedSave()) {
70 0 : return true;
71 : }
72 :
73 0 : return io::absoluteDirpath(filePath()) == configuration()->userWorkspacesPath();
74 : }
75 :
76 0 : bool Workspace::isNeedSave() const
77 : {
78 0 : return m_file ? m_file->isNeedSave() : false;
79 : }
80 :
81 1 : RetVal<QByteArray> Workspace::rawData(const DataKey& key) const
82 : {
83 2 : TRACEFUNC;
84 :
85 1 : IF_ASSERT_FAILED(m_file->isLoaded()) {
86 0 : return RetVal<QByteArray>(make_ret(Err::NotLoaded));
87 : }
88 :
89 1 : RetVal<QByteArray> rv;
90 1 : rv.ret = make_ret(Ret::Code::Ok);
91 2 : rv.val = m_file->data(key);
92 1 : return rv;
93 1 : }
94 :
95 0 : Ret Workspace::setRawData(const DataKey& key, const QByteArray& data)
96 : {
97 0 : m_file->setData(key, data);
98 0 : return make_ret(Ret::Code::Ok);
99 : }
100 :
101 0 : void Workspace::reset()
102 : {
103 0 : if (!isEdited()) {
104 0 : return;
105 : }
106 :
107 0 : io::path_t builtinWorkspacePath = this->builtinWorkspacePath();
108 :
109 0 : if (builtinWorkspacePath == filePath()) {
110 : //! if the user made changes and they were not saved, then just reload file
111 0 : reload();
112 0 : return;
113 : }
114 :
115 : //! remove current file
116 0 : fileSystem()->remove(filePath());
117 :
118 : //! redirect to builtin workspace file
119 0 : m_file = std::make_shared<WorkspaceFile>(builtinWorkspacePath);
120 :
121 0 : reload();
122 0 : }
123 :
124 0 : void Workspace::assignNewName(const std::string& newName)
125 : {
126 0 : io::path_t filePath = m_file->filePath();
127 0 : io::path_t newPath = io::absoluteDirpath(filePath) + "/" + newName + "." + io::suffix(filePath);
128 :
129 0 : if (filePath == newPath) {
130 0 : return;
131 : }
132 :
133 0 : Ret ret = doSave();
134 0 : if (!ret) {
135 0 : LOGE() << "Failed to save workspace, error: " << ret.toString();
136 : }
137 :
138 0 : fileSystem()->move(filePath, newPath);
139 :
140 0 : m_file = std::make_shared<WorkspaceFile>(newPath);
141 0 : load();
142 0 : }
143 :
144 4 : async::Notification Workspace::reloadNotification()
145 : {
146 4 : return m_reloadNotification;
147 : }
148 :
149 5 : bool Workspace::isLoaded() const
150 : {
151 5 : return m_file->isLoaded();
152 : }
153 :
154 3 : io::path_t Workspace::filePath() const
155 : {
156 3 : return m_file->filePath();
157 : }
158 :
159 3 : Ret Workspace::load()
160 : {
161 3 : mi::ReadResourceLockGuard resource_guard(multiwindowsProvider.get(), fileResourceName());
162 6 : return m_file->load();
163 3 : }
164 :
165 3 : Ret Workspace::save()
166 : {
167 3 : if (!m_file->isNeedSave()) {
168 3 : return true;
169 : }
170 :
171 0 : if (isBuiltin()) {
172 0 : copyBuiltinWorkspaceToUserDir();
173 : }
174 :
175 0 : return doSave();
176 : }
177 :
178 0 : Ret Workspace::doSave()
179 : {
180 0 : mi::WriteResourceLockGuard resource_guard(multiwindowsProvider.get(), fileResourceName());
181 0 : m_file->setMeta("app_version", Val(application()->version().toStdString()));
182 0 : return m_file->save();
183 0 : }
184 :
185 0 : void Workspace::reload()
186 : {
187 0 : load();
188 0 : m_reloadNotification.notify();
189 0 : }
190 :
191 3 : std::string Workspace::fileResourceName() const
192 : {
193 3 : return filePath().toStdString();
194 : }
195 :
196 0 : io::path_t Workspace::builtinWorkspacePath() const
197 : {
198 0 : std::string currentWorkspaceName = name();
199 :
200 0 : io::paths_t builtinWorkspacesPaths = configuration()->builtinWorkspacesFilePaths();
201 0 : for (const io::path_t& builtinWorkspacePath : builtinWorkspacesPaths) {
202 0 : std::string builtinWorkspaceName = io::completeBasename(builtinWorkspacePath).toStdString();
203 0 : if (builtinWorkspaceName == currentWorkspaceName) {
204 0 : return builtinWorkspacePath;
205 : }
206 0 : }
207 :
208 0 : return {};
209 0 : }
210 :
211 0 : void Workspace::copyBuiltinWorkspaceToUserDir()
212 : {
213 0 : io::path_t userFilePath = configuration()->userWorkspacesPath() + "/" + io::filename(filePath());
214 :
215 0 : fileSystem()->copy(m_file->filePath(), userFilePath);
216 0 : m_file->redirect(userFilePath);
217 :
218 0 : Ret ret = doSave();
219 0 : if (!ret) {
220 0 : LOGE() << "Failed to save workspace: " << ret.toString();
221 : }
222 :
223 0 : load();
224 0 : }
|