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 :
23 : #include "articulationsprofileeditormodel.h"
24 :
25 : using namespace muse;
26 : using namespace muse::mpe;
27 :
28 : static const std::string PROFILE_EXTENSION = "(*.json)";
29 :
30 0 : ArticulationsProfileEditorModel::ArticulationsProfileEditorModel(QObject* parent)
31 0 : : QObject(parent), Contextable(muse::iocCtxForQmlObject(this))
32 : {
33 0 : }
34 :
35 0 : void ArticulationsProfileEditorModel::init()
36 : {
37 0 : loadItems();
38 :
39 0 : setProfile(profilesRepository()->createNew());
40 0 : }
41 :
42 0 : void ArticulationsProfileEditorModel::requestToOpenProfile()
43 : {
44 : //! Make these strings translatable when we expose this tool to users
45 0 : std::vector<std::string> filter = { /*qtrc*/ std::string("MPE articulations profile") + " " + PROFILE_EXTENSION };
46 0 : io::path_t path = interactive()->selectOpeningFileSync(/*trc*/ "Open MPE articulations profile", "", filter);
47 :
48 0 : if (path.empty()) {
49 0 : return;
50 : }
51 :
52 0 : setCurrentPath(path.toQString());
53 :
54 0 : setProfile(profilesRepository()->loadProfile(m_profilePath));
55 0 : }
56 :
57 0 : bool ArticulationsProfileEditorModel::requestToCreateProfile()
58 : {
59 0 : std::vector<std::string> filter = { /*qtrc*/ std::string("MPE articulations profile") + " " + PROFILE_EXTENSION };
60 0 : io::path_t path = interactive()->selectSavingFileSync(/*trc*/ "Save MPE articulations profile", "", filter);
61 :
62 0 : if (path.empty()) {
63 0 : return false;
64 : }
65 :
66 0 : setCurrentPath(path.toQString());
67 0 : return true;
68 0 : }
69 :
70 0 : void ArticulationsProfileEditorModel::requestToSaveProfile()
71 : {
72 0 : if (m_profilePath.empty()) {
73 0 : if (!requestToCreateProfile()) {
74 0 : return;
75 : }
76 : }
77 :
78 0 : for (const auto& item : m_singleNoteItems) {
79 0 : if (item->isActive()) {
80 0 : m_profile->setPattern(item->type(), item->patternData());
81 : } else {
82 0 : m_profile->removePattern(item->type());
83 : }
84 : }
85 :
86 0 : for (const auto& item : m_multiNoteItems) {
87 0 : if (item->isActive()) {
88 0 : m_profile->setPattern(item->type(), item->patternData());
89 : } else {
90 0 : m_profile->removePattern(item->type());
91 : }
92 : }
93 :
94 0 : profilesRepository()->saveProfile(m_profilePath, m_profile);
95 : }
96 :
97 0 : void ArticulationsProfileEditorModel::copyPatternDataFromItem(ArticulationPatternItem* item)
98 : {
99 0 : if (!item || !selectedItem()) {
100 0 : return;
101 : }
102 :
103 0 : m_selectedItem->load(item->patternData());
104 : }
105 :
106 0 : void ArticulationsProfileEditorModel::setProfile(ArticulationsProfilePtr ptr)
107 : {
108 0 : m_profile = std::move(ptr);
109 :
110 0 : auto load = [this](const QMap<ArticulationType, ArticulationPatternItem*>& items) {
111 0 : for (auto& item : items) {
112 0 : item->setIsActive(m_profile->contains(item->type()));
113 0 : item->load(m_profile->pattern(item->type()));
114 : }
115 0 : };
116 :
117 0 : load(m_singleNoteItems);
118 0 : load(m_multiNoteItems);
119 :
120 0 : setSelectedItem(m_singleNoteItems.first());
121 0 : }
122 :
123 0 : void ArticulationsProfileEditorModel::loadItems()
124 : {
125 0 : int firstIdx = static_cast<int>(ArticulationType::Standard);
126 0 : int lastIdx = static_cast<int>(ArticulationType::Last);
127 :
128 0 : for (int i = firstIdx; i < lastIdx; ++i) {
129 0 : ArticulationType type = static_cast<ArticulationType>(i);
130 :
131 0 : if (isSingleNoteArticulation(type)) {
132 0 : m_singleNoteItems.insert(type, buildItem(type, true /*isSingleNoteType*/));
133 : } else {
134 0 : m_multiNoteItems.insert(type, buildItem(type, false /*isSingleNoteType*/));
135 : }
136 : }
137 0 : }
138 :
139 0 : ArticulationPatternItem* ArticulationsProfileEditorModel::buildItem(const ArticulationType type, const bool isSingleNoteType)
140 : {
141 0 : ArticulationPatternItem* item = new ArticulationPatternItem(this, type, isSingleNoteType);
142 :
143 0 : connect(item, &ArticulationPatternItem::isSelectedChanged, this, [this, item]() {
144 0 : setSelectedItem(item);
145 0 : });
146 :
147 0 : return item;
148 : }
149 :
150 0 : QString ArticulationsProfileEditorModel::currentPath() const
151 : {
152 0 : return m_profilePath.toQString();
153 : }
154 :
155 0 : void ArticulationsProfileEditorModel::setCurrentPath(const QString& newCurrentPath)
156 : {
157 0 : io::path_t newPath(newCurrentPath);
158 :
159 0 : if (m_profilePath == newPath) {
160 0 : return;
161 : }
162 0 : m_profilePath = newPath;
163 0 : emit currentPathChanged();
164 0 : }
165 :
166 0 : ArticulationPatternItem* ArticulationsProfileEditorModel::selectedItem() const
167 : {
168 0 : return m_selectedItem;
169 : }
170 :
171 0 : void ArticulationsProfileEditorModel::setSelectedItem(ArticulationPatternItem* newSelectedItem)
172 : {
173 0 : if (m_selectedItem == newSelectedItem) {
174 0 : return;
175 : }
176 :
177 0 : if (m_selectedItem) {
178 0 : m_selectedItem->setIsSelected(false);
179 : }
180 :
181 0 : newSelectedItem->setIsSelected(true);
182 0 : m_selectedItem = newSelectedItem;
183 0 : emit selectedItemChanged();
184 : }
185 :
186 0 : QList<ArticulationPatternItem*> ArticulationsProfileEditorModel::singleNoteItems() const
187 : {
188 0 : QList<ArticulationPatternItem*> result;
189 :
190 0 : for (const auto& item : m_singleNoteItems) {
191 0 : result << item;
192 : }
193 :
194 0 : return result;
195 0 : }
196 :
197 0 : QList<ArticulationPatternItem*> ArticulationsProfileEditorModel::multiNoteItems() const
198 : {
199 0 : QList<ArticulationPatternItem*> result;
200 :
201 0 : for (const auto& item : m_multiNoteItems) {
202 0 : result << item;
203 : }
204 :
205 0 : return result;
206 0 : }
207 :
208 0 : bool ArticulationsProfileEditorModel::isArrangementVisible() const
209 : {
210 0 : return m_isArrangementVisible;
211 : }
212 :
213 0 : void ArticulationsProfileEditorModel::setIsArrangementVisible(bool newIsArrangementVisible)
214 : {
215 0 : if (m_isArrangementVisible == newIsArrangementVisible) {
216 0 : return;
217 : }
218 0 : m_isArrangementVisible = newIsArrangementVisible;
219 0 : emit isArrangementVisibleChanged();
220 : }
221 :
222 0 : bool ArticulationsProfileEditorModel::isPitchVisible() const
223 : {
224 0 : return m_isPitchVisible;
225 : }
226 :
227 0 : void ArticulationsProfileEditorModel::setIsPitchVisible(bool newIsPitchVisible)
228 : {
229 0 : if (m_isPitchVisible == newIsPitchVisible) {
230 0 : return;
231 : }
232 0 : m_isPitchVisible = newIsPitchVisible;
233 0 : emit isPitchVisibleChanged();
234 : }
235 :
236 0 : bool ArticulationsProfileEditorModel::isExpressionVisible() const
237 : {
238 0 : return m_isExpressionVisible;
239 : }
240 :
241 0 : void ArticulationsProfileEditorModel::setIsExpressionVisible(bool newIsExpressionVisible)
242 : {
243 0 : if (m_isExpressionVisible == newIsExpressionVisible) {
244 0 : return;
245 : }
246 0 : m_isExpressionVisible = newIsExpressionVisible;
247 0 : emit isExpressionVisibleChanged();
248 : }
|