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 :
23 : #pragma once
24 :
25 : #include <QAbstractItemModel>
26 :
27 : #include "async/asyncable.h"
28 :
29 : #include "modularity/ioc.h"
30 : #include "interactive/iinteractive.h"
31 : #include "ipaletteconfiguration.h"
32 : #include "project/iprojectsession.h"
33 :
34 : #include "ipaletteprovider.h"
35 : #include "palettemodel.h"
36 :
37 : namespace mu::palette {
38 : class AbstractPaletteController;
39 : class PaletteProvider;
40 :
41 : // ========================================================
42 : // PaletteElementEditor
43 : // ========================================================
44 :
45 : class PaletteElementEditor : public QObject, public muse::async::Asyncable, public muse::Contextable
46 : {
47 : Q_OBJECT
48 :
49 : Q_PROPERTY(bool valid READ valid CONSTANT)
50 : Q_PROPERTY(QString actionName READ actionName CONSTANT) // TODO: make NOTIFY instead of CONSTANT for retranslations
51 :
52 : muse::ContextInject<muse::IInteractive> interactive = { this };
53 : muse::ContextInject<IPaletteProvider> paletteProvider = { this };
54 : public:
55 : PaletteElementEditor(const muse::modularity::ContextPtr& ctx, QObject* parent = nullptr)
56 : : QObject(parent), muse::Contextable(ctx) {}
57 0 : PaletteElementEditor(AbstractPaletteController* controller, QPersistentModelIndex paletteIndex,
58 : Palette::Type type, const muse::modularity::ContextPtr& ctx, QObject* parent = nullptr)
59 0 : : QObject(parent), muse::Contextable(ctx),
60 0 : _controller(controller), _paletteIndex(paletteIndex), _type(type) {}
61 :
62 : bool valid() const;
63 : QString actionName() const;
64 :
65 : void setPaletteIndex(QPersistentModelIndex paletteIndex);
66 :
67 : Q_INVOKABLE void open();
68 :
69 : private:
70 : void onElementAdded(const engraving::ElementPtr element);
71 :
72 : AbstractPaletteController* _controller = nullptr;
73 : QPersistentModelIndex _paletteIndex;
74 : Palette::Type _type = Palette::Type::Unknown;
75 : };
76 :
77 : // ========================================================
78 : // AbstractPaletteController
79 : // ========================================================
80 :
81 : class AbstractPaletteController : public QObject, public muse::Contextable
82 : {
83 : Q_OBJECT
84 :
85 : /// Whether dropping new elements to this palette is generally allowed
86 : Q_PROPERTY(bool canDropElements READ canDropElements CONSTANT)
87 :
88 0 : virtual bool canDropElements() const { return false; }
89 :
90 : public:
91 : enum class RemoveAction {
92 : NoAction,
93 : Hide,
94 : DeletePermanently,
95 : AutoAction
96 : };
97 :
98 0 : AbstractPaletteController(const muse::modularity::ContextPtr& ctx, QObject* parent = nullptr)
99 0 : : QObject(parent), muse::Contextable(ctx) {}
100 :
101 0 : Q_INVOKABLE virtual Qt::DropAction dropAction(const QVariantMap& mimeData, Qt::DropAction proposedAction,
102 : const QModelIndex& parent, bool internal) const
103 : {
104 : Q_UNUSED(mimeData);
105 : Q_UNUSED(proposedAction);
106 : Q_UNUSED(parent);
107 : Q_UNUSED(internal);
108 0 : return Qt::IgnoreAction;
109 : }
110 :
111 : Q_INVOKABLE virtual bool move(const QModelIndex& sourceParent, int sourceRow, const QModelIndex& destinationParent,
112 : int destinationChild) = 0;
113 : Q_INVOKABLE virtual bool insert(const QModelIndex& parent, int row, const QVariantMap& mimeData, Qt::DropAction action) = 0;
114 : Q_INVOKABLE virtual bool insertNewItem(const QModelIndex& parent, int row, const QString& name) = 0;
115 : Q_INVOKABLE virtual void remove(const QModelIndex&) = 0;
116 : Q_INVOKABLE virtual void removeSelection(const QModelIndexList&, const QModelIndex& parent = QModelIndex()) = 0;
117 :
118 0 : Q_INVOKABLE virtual bool canEdit(const QModelIndex&) const { return false; }
119 :
120 0 : Q_INVOKABLE virtual void editPaletteProperties(const QModelIndex& index) { Q_UNUSED(index); }
121 0 : Q_INVOKABLE virtual void editCellProperties(const QModelIndex& index) { Q_UNUSED(index); }
122 :
123 0 : Q_INVOKABLE virtual bool applyPaletteElement(const QModelIndex& index, Qt::KeyboardModifiers modifiers)
124 : {
125 : Q_UNUSED(index);
126 : Q_UNUSED(modifiers);
127 0 : return false;
128 : }
129 :
130 : Q_INVOKABLE mu::palette::PaletteElementEditor* elementEditor(const QModelIndex& index);
131 :
132 : private:
133 : QMap<Palette::Type, PaletteElementEditor*> m_paletteElementEditorMap;
134 : };
135 :
136 : // ========================================================
137 : // UserPaletteController
138 : // ========================================================
139 :
140 : class UserPaletteController : public AbstractPaletteController, public muse::async::Asyncable
141 : {
142 : Q_OBJECT
143 :
144 : muse::GlobalInject<IPaletteConfiguration> configuration;
145 : muse::ContextInject<project::IProjectSession> projectSession = { this };
146 : muse::ContextInject<muse::IInteractive> interactive = { this };
147 :
148 : QAbstractItemModel* _model;
149 : PaletteTreeModel* _userPalette;
150 :
151 : bool _visible = true;
152 : bool _custom = false;
153 : bool _filterCustom = false;
154 :
155 : bool _userEditable = true;
156 :
157 0 : bool canDropElements() const override { return _userEditable; }
158 :
159 : muse::async::Promise<RemoveAction> showHideOrDeleteDialog(const std::string& question) const;
160 : void queryRemove(const QModelIndexList&, int customCount);
161 :
162 : enum RemoveActionConfirmationType {
163 : NoConfirmation,
164 : CustomCellHideDeleteConfirmation,
165 : CustomPaletteHideDeleteConfirmation
166 : };
167 :
168 : void remove(const QModelIndexList&, AbstractPaletteController::RemoveAction);
169 :
170 : protected:
171 0 : QAbstractItemModel* model() { return _model; }
172 0 : const QAbstractItemModel* model() const { return _model; }
173 :
174 : public:
175 0 : UserPaletteController(QAbstractItemModel* m, PaletteTreeModel* userPalette, const muse::modularity::ContextPtr& ctx,
176 : QObject* parent = nullptr)
177 0 : : AbstractPaletteController(ctx, parent), _model(m), _userPalette(userPalette) {}
178 :
179 : bool visible() const { return _visible; }
180 0 : void setVisible(bool val) { _visible = val; }
181 : bool custom() const { return _custom; }
182 0 : void setCustom(bool val) { _custom = val; _filterCustom = true; }
183 :
184 : Qt::DropAction dropAction(const QVariantMap& mimeData, Qt::DropAction proposedAction, const QModelIndex& parent,
185 : bool internal) const override;
186 :
187 : bool move(const QModelIndex& sourceParent, int sourceRow, const QModelIndex& destinationParent, int destinationChild) override;
188 : bool insert(const QModelIndex& parent, int row, const QVariantMap& mimeData, Qt::DropAction action) override;
189 : bool insertNewItem(const QModelIndex& parent, int row, const QString& name) override;
190 : void remove(const QModelIndex& index) override;
191 : void removeSelection(const QModelIndexList&, const QModelIndex& parent = QModelIndex()) override;
192 :
193 : void editPaletteProperties(const QModelIndex& index) override;
194 : void editCellProperties(const QModelIndex& index) override;
195 :
196 0 : bool userEditable() const { return _userEditable; }
197 0 : void setUserEditable(bool val) { _userEditable = val; }
198 :
199 : bool canEdit(const QModelIndex&) const override;
200 :
201 : bool applyPaletteElement(const QModelIndex& index, Qt::KeyboardModifiers modifiers) override;
202 : };
203 :
204 : // ========================================================
205 : // PaletteProvider
206 : // ========================================================
207 :
208 : class PaletteProvider : public QObject, public IPaletteProvider, public muse::async::Asyncable, public muse::Contextable
209 : {
210 : Q_OBJECT
211 :
212 : Q_PROPERTY(QAbstractItemModel * mainPaletteModel READ mainPaletteModel NOTIFY mainPaletteChanged)
213 : Q_PROPERTY(mu::palette::AbstractPaletteController * mainPaletteController READ mainPaletteController NOTIFY mainPaletteChanged)
214 :
215 : Q_PROPERTY(mu::palette::FilterPaletteTreeModel * customElementsPaletteModel READ customElementsPaletteModel CONSTANT)
216 : Q_PROPERTY(mu::palette::AbstractPaletteController * customElementsPaletteController READ customElementsPaletteController CONSTANT)
217 :
218 : Q_PROPERTY(bool isSinglePalette READ isSinglePalette NOTIFY isSinglePaletteChanged)
219 : Q_PROPERTY(bool isSingleClickToOpenPalette READ isSingleClickToOpenPalette NOTIFY isSingleClickToOpenPaletteChanged)
220 : Q_PROPERTY(bool isPaletteDragEnabled READ isPaletteDragEnabled NOTIFY isPaletteDragEnabledChanged)
221 :
222 : muse::GlobalInject<IPaletteConfiguration> configuration;
223 : muse::ContextInject<muse::IInteractive> interactive = { this };
224 : public:
225 :
226 0 : PaletteProvider(const muse::modularity::ContextPtr& ctx, QObject* parent = nullptr)
227 0 : : QObject(parent), muse::Contextable(ctx)
228 : {
229 0 : }
230 :
231 : void init() override;
232 :
233 : PaletteTreeModel* userPaletteModel() const { return m_userPaletteModel; }
234 0 : PaletteTreePtr userPaletteTree() const override { return m_userPaletteModel->paletteTreePtr(); }
235 0 : muse::async::Notification userPaletteTreeChanged() const override { return m_userPaletteChanged; }
236 : void setUserPaletteTree(PaletteTreePtr tree) override;
237 :
238 : void setDefaultPaletteTree(PaletteTreePtr tree) override;
239 :
240 : muse::async::Channel<engraving::ElementPtr> addCustomItemRequested() const override;
241 :
242 : Q_INVOKABLE QModelIndex poolPaletteIndex(const QModelIndex& index, mu::palette::FilterPaletteTreeModel* poolPalette) const;
243 : Q_INVOKABLE QModelIndex customElementsPaletteIndex(const QModelIndex& index);
244 :
245 : Q_INVOKABLE mu::palette::FilterPaletteTreeModel* poolPaletteModel(const QModelIndex& index) const;
246 : Q_INVOKABLE mu::palette::AbstractPaletteController* poolPaletteController(mu::palette::FilterPaletteTreeModel*,
247 : const QModelIndex& rootIndex) const;
248 :
249 : Q_INVOKABLE QAbstractItemModel* availableExtraPalettesModel() const;
250 : Q_INVOKABLE bool addPalette(const QPersistentModelIndex&);
251 :
252 : Q_INVOKABLE void resetPalette(const QModelIndex&);
253 :
254 : Q_INVOKABLE bool savePalette(const QModelIndex&);
255 : Q_INVOKABLE bool loadPalette(const QModelIndex&);
256 :
257 : Q_INVOKABLE void setSearching(bool searching);
258 : Q_INVOKABLE void setFilter(const QString&);
259 :
260 : bool paletteChanged() const { return m_userPaletteModel->paletteTreeChanged(); }
261 :
262 : void write(engraving::XmlWriter&, bool pasteMode) const;
263 : bool read(engraving::XmlReader&, bool pasteMode);
264 :
265 : void updateCellsState(const engraving::Selection& sel) { m_userPaletteModel->updateCellsState(sel); }
266 : void retranslate()
267 : {
268 : m_userPaletteModel->retranslate();
269 : m_masterPaletteModel->retranslate();
270 : m_defaultPaletteModel->retranslate();
271 : }
272 :
273 : bool isSinglePalette() const;
274 : bool isSingleClickToOpenPalette() const;
275 : bool isPaletteDragEnabled() const;
276 :
277 : signals:
278 : void userPaletteChanged();
279 : void mainPaletteChanged();
280 :
281 : void isSinglePaletteChanged();
282 : void isSingleClickToOpenPaletteChanged();
283 : void isPaletteDragEnabledChanged();
284 :
285 : private slots:
286 0 : void notifyAboutUserPaletteChanged()
287 : {
288 0 : m_userPaletteChanged.notify();
289 0 : emit userPaletteChanged();
290 0 : }
291 :
292 : private:
293 : enum PalettesModelRoles {
294 : CustomRole = Qt::UserRole + 1,
295 : PaletteIndexRole
296 : };
297 :
298 : QAbstractItemModel* mainPaletteModel();
299 : AbstractPaletteController* mainPaletteController();
300 :
301 : FilterPaletteTreeModel* customElementsPaletteModel();
302 : AbstractPaletteController* customElementsPaletteController();
303 :
304 : QString getPaletteFilename(bool open, const QString& name = "") const;
305 :
306 : void doResetPalette(const QModelIndex& index);
307 :
308 : PaletteTreeModel* m_userPaletteModel = nullptr;
309 : PaletteTreeModel* m_masterPaletteModel = nullptr;
310 : PaletteTreeModel* m_defaultPaletteModel = nullptr; // palette used by "Reset palette" action
311 :
312 : muse::async::Notification m_userPaletteChanged;
313 :
314 : bool m_isSearching = false;
315 :
316 : QSortFilterProxyModel* m_visibilityFilterModel = nullptr;
317 : QSortFilterProxyModel* m_searchFilterModel = nullptr;
318 :
319 : QAbstractItemModel* m_mainPalette = nullptr; // visible userPalette entries
320 : // PaletteTreeModel* poolPalette; // masterPalette entries not yet added to mainPalette
321 : FilterPaletteTreeModel* m_customPoolPalette = nullptr; // invisible userPalette entries that do not belong to masterPalette
322 :
323 : UserPaletteController* m_mainPaletteController = nullptr;
324 : // PaletteController* m_masterPaletteController = nullptr;
325 : UserPaletteController* m_customElementsPaletteController = nullptr;
326 :
327 : muse::async::Channel<engraving::ElementPtr> m_addCustomItemRequested;
328 : };
329 : }
|