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 "dockpanelview.h"
24 :
25 : #include "kddockwidgets/src/core/DockWidget.h"
26 : #include "kddockwidgets/src/core/Group.h"
27 : #include "kddockwidgets/src/qtquick/views/DockWidget.h"
28 : #include "kddockwidgets/src/qtquick/views/View.h"
29 :
30 : #include "rcommand/commandtypes.h"
31 : #include "types/translatablestring.h"
32 :
33 : #include "uicomponents/qml/Muse/UiComponents/abstractmenumodel.h"
34 :
35 : #include "dockcommands.h"
36 :
37 : #include "log.h"
38 :
39 : using namespace muse;
40 : using namespace muse::dock;
41 : using namespace muse::ui;
42 : using namespace muse::uicomponents;
43 :
44 : class DockPanelView::DockPanelMenuModel : public muse::uicomponents::AbstractMenuModel
45 : {
46 : public:
47 3 : DockPanelMenuModel(DockPanelView* panel)
48 3 : : AbstractMenuModel(panel), m_panel(panel)
49 : {
50 3 : listenFloatingChanged();
51 3 : }
52 :
53 3 : void load() override
54 : {
55 4 : TRACEFUNC;
56 :
57 3 : MenuItemList items;
58 :
59 3 : if (m_customMenuModel && m_customMenuModel->rowCount() > 0) {
60 0 : items << m_customMenuModel->items();
61 0 : items << makeSeparator();
62 : }
63 :
64 3 : MenuItem* closeDockItem = makeMenuItem(DOCK_SET_OPEN_COMMAND, TranslatableString("appshell/dock", "Close"));
65 12 : closeDockItem->setParams({ { "dock_name", Val(m_panel->objectName().toStdString()) }, { "open", Val(false) } });
66 3 : items << closeDockItem;
67 :
68 3 : MenuItem* toggleFloatingItem = makeMenuItem(DOCK_TOGGLE_FLOATING_COMMAND, toggleFloatingActionTitle());
69 9 : toggleFloatingItem->setParams({ { "dock_name", Val(m_panel->objectName().toStdString()) } });
70 3 : items << toggleFloatingItem;
71 :
72 3 : setItems(items);
73 15 : }
74 :
75 0 : void handleMenuItem(const QString& itemId) override
76 : {
77 : // my items
78 0 : rcommand::Command cmd(itemId.toStdString());
79 0 : if (cmd == DOCK_SET_OPEN_COMMAND || cmd == DOCK_TOGGLE_FLOATING_COMMAND) {
80 0 : AbstractMenuModel::handleMenuItem(itemId);
81 0 : return;
82 : }
83 :
84 : // forward to custom model
85 0 : if (m_customMenuModel) {
86 0 : m_customMenuModel->handleMenuItem(itemId);
87 : }
88 0 : }
89 :
90 0 : AbstractMenuModel* customMenuModel() const
91 : {
92 0 : return m_customMenuModel;
93 : }
94 :
95 0 : void setCustomMenuModel(AbstractMenuModel* model)
96 : {
97 0 : m_customMenuModel = model;
98 :
99 0 : if (!model) {
100 0 : return;
101 : }
102 :
103 0 : connect(model, &AbstractMenuModel::itemsChanged, this, [this]() {
104 0 : load();
105 0 : });
106 :
107 0 : connect(model, &AbstractMenuModel::itemChanged, this, [this](MenuItem* item) {
108 0 : updateItem(item);
109 0 : });
110 :
111 0 : connect(model, &AbstractMenuModel::destroyed, this, [this]() {
112 0 : m_customMenuModel = nullptr;
113 0 : });
114 : }
115 :
116 : private:
117 :
118 3 : TranslatableString toggleFloatingActionTitle() const
119 : {
120 3 : return m_panel->floating() ? TranslatableString("appshell/dock", "Dock") : TranslatableString("appshell/dock", "Undock");
121 : }
122 :
123 3 : void listenFloatingChanged()
124 : {
125 3 : connect(m_panel, &DockPanelView::floatingChanged, this, [this]() {
126 0 : MenuItem& item = findItem(DOCK_TOGGLE_FLOATING_COMMAND);
127 0 : item.setTitle(toggleFloatingActionTitle());
128 0 : });
129 3 : }
130 :
131 0 : void updateItem(MenuItem* newItem)
132 : {
133 0 : int index = itemIndex(newItem->id());
134 :
135 0 : if (index == INVALID_ITEM_INDEX) {
136 0 : return;
137 : }
138 :
139 0 : setItem(index, newItem);
140 : }
141 :
142 : AbstractMenuModel* m_customMenuModel = nullptr;
143 : DockPanelView* m_panel = nullptr;
144 : };
145 :
146 3 : DockPanelView::DockPanelView(QQuickItem* parent)
147 3 : : DockBase(DockType::Panel, parent), m_menuModel(new DockPanelMenuModel(this))
148 : {
149 3 : setLocation(Location::Left);
150 3 : }
151 :
152 6 : DockPanelView::~DockPanelView()
153 : {
154 6 : auto* dockWidgetView = qobject_cast<KDDockWidgets::QtQuick::DockWidget*>(
155 3 : KDDockWidgets::QtQuick::asQQuickItem(dockWidget()));
156 3 : if (!dockWidgetView) {
157 0 : return;
158 : }
159 :
160 3 : dockWidgetView->setProperty(DOCK_PANEL_PROPERTY, QVariant::fromValue(nullptr));
161 3 : dockWidgetView->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(nullptr));
162 3 : dockWidgetView->setProperty(TITLEBAR_PROPERTY, QVariant::fromValue(nullptr));
163 3 : dockWidgetView->setProperty(TOOLBAR_COMPONENT_PROPERTY, QVariant::fromValue(nullptr));
164 6 : }
165 :
166 0 : QString DockPanelView::groupName() const
167 : {
168 0 : return m_groupName;
169 : }
170 :
171 0 : void DockPanelView::setGroupName(const QString& name)
172 : {
173 0 : if (m_groupName == name) {
174 0 : return;
175 : }
176 :
177 0 : m_groupName = name;
178 0 : emit groupNameChanged();
179 : }
180 :
181 3 : void DockPanelView::componentComplete()
182 : {
183 3 : DockBase::componentComplete();
184 :
185 6 : auto* dockWidgetView = qobject_cast<KDDockWidgets::QtQuick::DockWidget*>(
186 3 : KDDockWidgets::QtQuick::asQQuickItem(dockWidget()));
187 3 : IF_ASSERT_FAILED(dockWidgetView) {
188 0 : return;
189 : }
190 :
191 3 : m_menuModel->load();
192 :
193 3 : dockWidgetView->setProperty(DOCK_PANEL_PROPERTY, QVariant::fromValue(this));
194 3 : dockWidgetView->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(m_menuModel));
195 3 : dockWidgetView->setProperty(TITLEBAR_PROPERTY, QVariant::fromValue(m_titleBar));
196 3 : dockWidgetView->setProperty(TOOLBAR_COMPONENT_PROPERTY, QVariant::fromValue(m_toolbarComponent));
197 :
198 3 : connect(m_menuModel, &AbstractMenuModel::itemsChanged, [dockWidgetView, this]() {
199 0 : if (dockWidgetView) {
200 0 : dockWidgetView->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(m_menuModel));
201 : }
202 0 : });
203 :
204 3 : connect(this, &DockPanelView::toolbarComponentChanged, this, [this, dockWidgetView]() {
205 0 : if (dockWidgetView) {
206 0 : dockWidgetView->setProperty(TOOLBAR_COMPONENT_PROPERTY, QVariant::fromValue(m_toolbarComponent));
207 : }
208 0 : });
209 :
210 3 : connect(this, &DockBase::frameCurrentWidgetChanged, this, [this]() {
211 0 : auto* ctrl = dockWidget();
212 0 : if (!ctrl) {
213 0 : return;
214 : }
215 0 : auto* dockWidgetView = qobject_cast<KDDockWidgets::QtQuick::DockWidget*>(
216 0 : KDDockWidgets::QtQuick::asQQuickItem(ctrl));
217 0 : auto* group = dockWidgetView ? dockWidgetView->group() : nullptr;
218 0 : if (group && group->currentDockWidget() == ctrl) {
219 0 : emit panelShown();
220 : }
221 : });
222 : }
223 :
224 0 : AbstractMenuModel* DockPanelView::contextMenuModel() const
225 : {
226 0 : return m_menuModel->customMenuModel();
227 : }
228 :
229 0 : QQmlComponent* DockPanelView::titleBar() const
230 : {
231 0 : return m_titleBar;
232 : }
233 :
234 0 : QQmlComponent* DockPanelView::toolbarComponent() const
235 : {
236 0 : return m_toolbarComponent;
237 : }
238 :
239 0 : void DockPanelView::setContextMenuModel(AbstractMenuModel* model)
240 : {
241 0 : if (m_menuModel->customMenuModel() == model) {
242 0 : return;
243 : }
244 :
245 0 : m_menuModel->setCustomMenuModel(model);
246 0 : m_menuModel->load();
247 0 : emit contextMenuModelChanged();
248 : }
249 :
250 0 : void DockPanelView::setTitleBar(QQmlComponent* titleBar)
251 : {
252 0 : if (m_titleBar == titleBar) {
253 0 : return;
254 : }
255 :
256 0 : m_titleBar = titleBar;
257 0 : emit titleBarChanged();
258 : }
259 :
260 0 : void DockPanelView::setToolbarComponent(QQmlComponent* component)
261 : {
262 0 : if (m_toolbarComponent == component) {
263 0 : return;
264 : }
265 :
266 0 : m_toolbarComponent = component;
267 0 : emit toolbarComponentChanged();
268 : }
269 :
270 3 : bool DockPanelView::isTabAllowed(const DockPanelView* tab) const
271 : {
272 3 : IF_ASSERT_FAILED(tab) {
273 0 : return false;
274 : }
275 :
276 3 : if (tab == this) {
277 3 : return false;
278 : }
279 :
280 0 : if (!isOpen()) {
281 0 : return false;
282 : }
283 :
284 0 : if (floating()) {
285 0 : return false;
286 : }
287 :
288 0 : if (m_groupName.isEmpty() || tab->m_groupName.isEmpty()) {
289 0 : return false;
290 : }
291 :
292 0 : return m_groupName == tab->m_groupName;
293 : }
294 :
295 0 : void DockPanelView::addPanelAsTab(DockPanelView* tab)
296 : {
297 0 : IF_ASSERT_FAILED(tab && dockWidget()) {
298 0 : return;
299 : }
300 :
301 0 : if (!isTabAllowed(tab)) {
302 0 : return;
303 : }
304 :
305 0 : dockWidget()->addDockWidgetAsTab(tab->dockWidget());
306 0 : tab->setVisible(true);
307 : }
308 :
309 0 : void DockPanelView::setCurrentTabIndex(int index)
310 : {
311 0 : IF_ASSERT_FAILED(dockWidget()) {
312 0 : return;
313 : }
314 :
315 0 : auto* dockWidgetView = qobject_cast<KDDockWidgets::QtQuick::DockWidget*>(
316 0 : KDDockWidgets::QtQuick::asQQuickItem(dockWidget()));
317 0 : auto* group = dockWidgetView ? dockWidgetView->group() : nullptr;
318 0 : if (group) {
319 0 : group->setCurrentTabIndex(index);
320 : }
321 : }
|