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 "noteinputbarcustomisemodel.h"
23 :
24 : #include "noteinputbarcustomiseitem.h"
25 :
26 : #include "translation.h"
27 :
28 : #include "noteinputbarmodel.h"
29 :
30 : #include "log.h"
31 :
32 : using namespace mu::notation;
33 : using namespace muse::ui;
34 : using namespace muse::uicomponents;
35 : using namespace muse::rcommand;
36 :
37 : static const QString NOTE_INPUT_TOOLBAR_NAME("noteInput");
38 :
39 0 : NoteInputBarCustomiseModel::NoteInputBarCustomiseModel(QObject* parent)
40 0 : : SelectableItemListModel(parent), muse::Contextable(muse::iocCtxForQmlObject(this))
41 : {
42 0 : }
43 :
44 0 : void NoteInputBarCustomiseModel::load()
45 : {
46 0 : TRACEFUNC;
47 :
48 0 : ItemList items;
49 :
50 0 : ToolConfig toolConfig = uiState()->toolConfig(NOTE_INPUT_TOOLBAR_NAME, NoteInputBarModel::defaultNoteInputConfig());
51 :
52 0 : for (const ToolConfig::Item& item : toolConfig.items) {
53 0 : if (item.isSeparator()) {
54 0 : items << makeSeparatorItem();
55 0 : } else if (item.intent == NoteInputBarModel::CROSS_STAFF_BEAMING_SUBITEMS || item.intent == NoteInputBarModel::TUPLET_SUBITEMS) {
56 0 : items << makeServiceItem(item.intent, item.show);
57 : } else {
58 0 : items << makeCommandItem(item.intent, item.show);
59 : }
60 : }
61 :
62 0 : setItems(items);
63 0 : }
64 :
65 0 : QVariant NoteInputBarCustomiseModel::data(const QModelIndex& index, int role) const
66 : {
67 0 : NoteInputBarCustomiseItem* item = modelIndexToItem(index);
68 0 : if (!item) {
69 0 : return QVariant();
70 : }
71 :
72 0 : switch (role) {
73 0 : case ItemRole: return QVariant::fromValue(item);
74 0 : default: break;
75 : }
76 :
77 0 : return SelectableItemListModel::data(index, role);
78 : }
79 :
80 0 : QHash<int, QByteArray> NoteInputBarCustomiseModel::roleNames() const
81 : {
82 0 : QHash<int, QByteArray> roles = SelectableItemListModel::roleNames();
83 0 : roles[ItemRole] = "item";
84 :
85 0 : return roles;
86 0 : }
87 :
88 0 : void NoteInputBarCustomiseModel::addSeparatorLine()
89 : {
90 0 : if (!hasSelection()) {
91 0 : return;
92 : }
93 :
94 0 : QModelIndex selectedItemIndex = selection()->selectedIndexes().first();
95 0 : if (!selectedItemIndex.isValid()) {
96 0 : return;
97 : }
98 :
99 0 : QModelIndex prevItemIndex = index(selectedItemIndex.row() - 1);
100 0 : if (!prevItemIndex.isValid()) {
101 0 : return;
102 : }
103 :
104 0 : insertItem(prevItemIndex.row() + 1, makeSeparatorItem());
105 :
106 0 : onUpdateOperationsAvailability();
107 0 : saveActions();
108 : }
109 :
110 0 : QItemSelectionModel* NoteInputBarCustomiseModel::selectionModel() const
111 : {
112 0 : return selection();
113 : }
114 :
115 0 : bool NoteInputBarCustomiseModel::isAddSeparatorAvailable() const
116 : {
117 0 : return m_isAddSeparatorAvailable;
118 : }
119 :
120 0 : void NoteInputBarCustomiseModel::setIsAddSeparatorAvailable(bool isAddSeparatorAvailable)
121 : {
122 0 : if (m_isAddSeparatorAvailable == isAddSeparatorAvailable) {
123 0 : return;
124 : }
125 :
126 0 : m_isAddSeparatorAvailable = isAddSeparatorAvailable;
127 0 : emit isAddSeparatorAvailableChanged(m_isAddSeparatorAvailable);
128 : }
129 :
130 0 : NoteInputBarCustomiseItem* NoteInputBarCustomiseModel::modelIndexToItem(const QModelIndex& index) const
131 : {
132 0 : return dynamic_cast<NoteInputBarCustomiseItem*>(item(index));
133 : }
134 :
135 0 : void NoteInputBarCustomiseModel::onUpdateOperationsAvailability()
136 : {
137 0 : TRACEFUNC;
138 :
139 0 : SelectableItemListModel::onUpdateOperationsAvailability();
140 0 : updateRemovingAvailability();
141 0 : updateAddSeparatorAvailability();
142 0 : }
143 :
144 0 : void NoteInputBarCustomiseModel::onRowsMoved()
145 : {
146 0 : saveActions();
147 0 : }
148 :
149 0 : void NoteInputBarCustomiseModel::onRowsRemoved()
150 : {
151 0 : saveActions();
152 0 : }
153 :
154 0 : void NoteInputBarCustomiseModel::updateRemovingAvailability()
155 : {
156 0 : TRACEFUNC;
157 :
158 0 : auto hasActionInSelection = [this](const QModelIndexList& selectedIndexes) {
159 0 : for (const QModelIndex& index : selectedIndexes) {
160 0 : const NoteInputBarCustomiseItem* item = modelIndexToItem(index);
161 :
162 0 : if (item && item->type() == NoteInputBarCustomiseItem::ACTION) {
163 0 : return true;
164 : }
165 : }
166 :
167 0 : return false;
168 0 : };
169 :
170 0 : QModelIndexList selectedIndexes = selection()->selectedIndexes();
171 0 : bool removingAvailable = !selectedIndexes.empty();
172 :
173 0 : if (removingAvailable) {
174 0 : removingAvailable = !hasActionInSelection(selectedIndexes);
175 : }
176 :
177 0 : setIsRemovingAvailable(removingAvailable);
178 0 : }
179 :
180 0 : void NoteInputBarCustomiseModel::updateAddSeparatorAvailability()
181 : {
182 0 : TRACEFUNC;
183 :
184 0 : bool addingAvailable = !selection()->selectedIndexes().empty();
185 0 : if (!addingAvailable) {
186 0 : setIsAddSeparatorAvailable(addingAvailable);
187 0 : return;
188 : }
189 :
190 0 : addingAvailable = selection()->selectedIndexes().count() == 1;
191 0 : if (!addingAvailable) {
192 0 : setIsAddSeparatorAvailable(addingAvailable);
193 0 : return;
194 : }
195 :
196 0 : QModelIndex selectedItemIndex = selection()->selectedIndexes().first();
197 :
198 0 : const NoteInputBarCustomiseItem* selectedItem = modelIndexToItem(selectedItemIndex);
199 0 : addingAvailable = selectedItem && selectedItem->type() == NoteInputBarCustomiseItem::ACTION;
200 :
201 0 : if (!addingAvailable) {
202 0 : setIsAddSeparatorAvailable(addingAvailable);
203 0 : return;
204 : }
205 :
206 0 : QModelIndex prevItemIndex = index(selectedItemIndex.row() - 1);
207 0 : addingAvailable = prevItemIndex.isValid();
208 0 : if (addingAvailable) {
209 0 : NoteInputBarCustomiseItem* prevItem = modelIndexToItem(prevItemIndex);
210 0 : addingAvailable = prevItem && prevItem->type() == NoteInputBarCustomiseItem::ACTION;
211 : }
212 :
213 0 : setIsAddSeparatorAvailable(addingAvailable);
214 0 : }
215 :
216 0 : NoteInputBarCustomiseItem* NoteInputBarCustomiseModel::makeServiceItem(const std::string& intent, bool checked)
217 : {
218 0 : const NoteInputBarModel::ServiceItemInfo info = NoteInputBarModel::serviceItemInfo(intent);
219 0 : NoteInputBarCustomiseItem* item = new NoteInputBarCustomiseItem(NoteInputBarCustomiseItem::ItemType::ACTION, this);
220 0 : item->setId(QString::fromStdString(intent));
221 0 : item->setTitle(info.title.qTranslatedWithoutMnemonic());
222 0 : item->setIcon(info.icon);
223 0 : item->setChecked(checked);
224 :
225 0 : connect(item, &NoteInputBarCustomiseItem::checkedChanged, this, [this](bool) {
226 0 : saveActions();
227 0 : });
228 :
229 0 : return item;
230 0 : }
231 :
232 0 : NoteInputBarCustomiseItem* NoteInputBarCustomiseModel::makeCommandItem(const std::string& intent, bool checked)
233 : {
234 0 : const CommandInfo& info = commandsRegister()->commandInfo(Command(intent));
235 0 : NoteInputBarCustomiseItem* item = new NoteInputBarCustomiseItem(NoteInputBarCustomiseItem::ItemType::ACTION, this);
236 0 : item->setId(QString::fromStdString(info.command.toString()));
237 0 : item->setTitle(info.title.qTranslatedWithoutMnemonic());
238 0 : item->setIcon(info.decoration.iconCode);
239 0 : item->setChecked(checked);
240 :
241 0 : connect(item, &NoteInputBarCustomiseItem::checkedChanged, this, [this](bool) {
242 0 : saveActions();
243 0 : });
244 :
245 0 : return item;
246 : }
247 :
248 0 : NoteInputBarCustomiseItem* NoteInputBarCustomiseModel::makeSeparatorItem()
249 : {
250 0 : NoteInputBarCustomiseItem* item = new NoteInputBarCustomiseItem(NoteInputBarCustomiseItem::ItemType::SEPARATOR, this);
251 0 : item->setTitle(QString("------- %1 -------").arg(muse::qtrc("notation", "Separator line")));
252 0 : item->setChecked(true); //! NOTE Can't be unchecked
253 0 : return item;
254 : }
255 :
256 0 : void NoteInputBarCustomiseModel::saveActions()
257 : {
258 0 : TRACEFUNC;
259 :
260 0 : ToolConfig config;
261 0 : for (const QObject* item : items()) {
262 0 : auto customiseItem = dynamic_cast<const NoteInputBarCustomiseItem*>(item);
263 0 : if (!customiseItem) {
264 0 : continue;
265 : }
266 :
267 0 : ToolConfig::Item citem;
268 0 : citem.intent = customiseItem->id().toStdString();
269 0 : citem.show = customiseItem->checked();
270 0 : config.items.append(citem);
271 0 : }
272 :
273 0 : uiState()->setToolConfig(NOTE_INPUT_TOOLBAR_NAME, config);
274 0 : }
|