1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Designer of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "containerwidget_taskmenu.h" |
30 | |
31 | #include <QtDesigner/abstractformeditor.h> |
32 | #include <QtDesigner/abstractformwindow.h> |
33 | #include <QtDesigner/qextensionmanager.h> |
34 | #include <QtDesigner/container.h> |
35 | |
36 | #include <qdesigner_command_p.h> |
37 | #include <qdesigner_dockwidget_p.h> |
38 | #include <promotiontaskmenu_p.h> |
39 | #include <widgetdatabase_p.h> |
40 | |
41 | #include <QtWidgets/qaction.h> |
42 | #include <QtWidgets/qmainwindow.h> |
43 | #include <QtWidgets/qtoolbox.h> |
44 | #include <QtWidgets/qstackedwidget.h> |
45 | #include <QtWidgets/qtabwidget.h> |
46 | #include <QtWidgets/qscrollarea.h> |
47 | #include <QtWidgets/qmdiarea.h> |
48 | #include <QtWidgets/qwizard.h> |
49 | #include <QtWidgets/qmenu.h> |
50 | |
51 | #include <QtCore/qdebug.h> |
52 | |
53 | QT_BEGIN_NAMESPACE |
54 | |
55 | namespace qdesigner_internal { |
56 | |
57 | ContainerWidgetTaskMenu::(QWidget *widget, ContainerType type, QObject *parent) : |
58 | QDesignerTaskMenu(widget, parent), |
59 | m_type(type), |
60 | m_containerWidget(widget), |
61 | m_core(formWindow()->core()), |
62 | m_pagePromotionTaskMenu(new PromotionTaskMenu(nullptr, PromotionTaskMenu::ModeSingleWidget, this)), |
63 | m_pageMenuAction(new QAction(this)), |
64 | m_pageMenu(new QMenu), |
65 | m_actionInsertPageAfter(new QAction(this)), |
66 | m_actionInsertPage(nullptr), |
67 | m_actionDeletePage(new QAction(tr(s: "Delete" ), this)) |
68 | { |
69 | Q_ASSERT(m_core); |
70 | m_taskActions.append(t: createSeparator()); |
71 | |
72 | connect(sender: m_actionDeletePage, signal: &QAction::triggered, receiver: this, slot: &ContainerWidgetTaskMenu::removeCurrentPage); |
73 | |
74 | connect(sender: m_actionInsertPageAfter, signal: &QAction::triggered, receiver: this, slot: &ContainerWidgetTaskMenu::addPageAfter); |
75 | // Empty Per-Page submenu, deletion and promotion. Updated on demand due to promotion state |
76 | switch (m_type) { |
77 | case WizardContainer: |
78 | case PageContainer: |
79 | m_taskActions.append(t: createSeparator()); // for the browse actions |
80 | break; |
81 | case MdiContainer: |
82 | break; |
83 | } |
84 | // submenu |
85 | m_pageMenuAction->setMenu(m_pageMenu); |
86 | m_taskActions.append(t: m_pageMenuAction); |
87 | // Insertion |
88 | switch (m_type) { |
89 | case WizardContainer: |
90 | case PageContainer: { // Before and after in a submenu |
91 | QAction * = new QAction(tr(s: "Insert" ), this); |
92 | QMenu * = new QMenu; |
93 | // before |
94 | m_actionInsertPage = new QAction(tr(s: "Insert Page Before Current Page" ), this); |
95 | connect(sender: m_actionInsertPage, signal: &QAction::triggered, receiver: this, slot: &ContainerWidgetTaskMenu::addPage); |
96 | insertMenu->addAction(action: m_actionInsertPage); |
97 | // after |
98 | m_actionInsertPageAfter->setText(tr(s: "Insert Page After Current Page" )); |
99 | insertMenu->addAction(action: m_actionInsertPageAfter); |
100 | |
101 | insertMenuAction->setMenu(insertMenu); |
102 | m_taskActions.append(t: insertMenuAction); |
103 | } |
104 | break; |
105 | case MdiContainer: // No concept of order |
106 | m_actionInsertPageAfter->setText(tr(s: "Add Subwindow" )); |
107 | m_taskActions.append(t: m_actionInsertPageAfter); |
108 | break; |
109 | } |
110 | } |
111 | |
112 | ContainerWidgetTaskMenu::() = default; |
113 | |
114 | QAction *ContainerWidgetTaskMenu::() const |
115 | { |
116 | return nullptr; |
117 | } |
118 | |
119 | bool ContainerWidgetTaskMenu::canDeletePage() const |
120 | { |
121 | switch (pageCount()) { |
122 | case 0: |
123 | return false; |
124 | case 1: |
125 | return m_type != PageContainer; // Do not delete last page of page-type container |
126 | default: |
127 | break; |
128 | } |
129 | return true; |
130 | } |
131 | |
132 | int ContainerWidgetTaskMenu::() const |
133 | { |
134 | if (const QDesignerContainerExtension *ce = containerExtension()) |
135 | return ce->count(); |
136 | return 0; |
137 | } |
138 | |
139 | QString ContainerWidgetTaskMenu::(ContainerType ct, int index, int count) |
140 | { |
141 | if (ct == MdiContainer) |
142 | return tr(s: "Subwindow" ); // No concept of order, same text everywhere |
143 | if (index < 0) |
144 | return tr(s: "Page" ); |
145 | return tr(s: "Page %1 of %2" ).arg(a: index + 1).arg(a: count); |
146 | } |
147 | |
148 | QList<QAction*> ContainerWidgetTaskMenu::() const |
149 | { |
150 | const QDesignerContainerExtension *ce = containerExtension(); |
151 | const int index = ce->currentIndex(); |
152 | |
153 | auto actions = QDesignerTaskMenu::taskActions(); |
154 | actions += m_taskActions; |
155 | // Update the page submenu, deletion and promotion. Updated on demand due to promotion state. |
156 | m_pageMenu->clear(); |
157 | const bool canAddWidget = ce->canAddWidget(); |
158 | if (m_actionInsertPage) |
159 | m_actionInsertPage->setEnabled(canAddWidget); |
160 | m_actionInsertPageAfter->setEnabled(canAddWidget); |
161 | m_pageMenu->addAction(action: m_actionDeletePage); |
162 | m_actionDeletePage->setEnabled(index >= 0 && ce->canRemove(index) && canDeletePage()); |
163 | m_pageMenuAction->setText(pageMenuText(ct: m_type, index, count: ce->count())); |
164 | if (index != -1) { // Has a page |
165 | m_pageMenuAction->setEnabled(true); |
166 | m_pagePromotionTaskMenu->setWidget(ce->widget(index)); |
167 | m_pagePromotionTaskMenu->addActions(flags: PromotionTaskMenu::LeadingSeparator|PromotionTaskMenu::SuppressGlobalEdit, menu: m_pageMenu); |
168 | } else { // No page |
169 | m_pageMenuAction->setEnabled(false); |
170 | } |
171 | |
172 | return actions; |
173 | } |
174 | |
175 | QDesignerFormWindowInterface *ContainerWidgetTaskMenu::() const |
176 | { |
177 | return QDesignerFormWindowInterface::findFormWindow(w: m_containerWidget); |
178 | } |
179 | |
180 | QDesignerContainerExtension *ContainerWidgetTaskMenu::() const |
181 | { |
182 | QExtensionManager *mgr = m_core->extensionManager(); |
183 | return qt_extension<QDesignerContainerExtension*>(manager: mgr, object: m_containerWidget); |
184 | } |
185 | |
186 | void ContainerWidgetTaskMenu::() |
187 | { |
188 | if (QDesignerContainerExtension *c = containerExtension()) { |
189 | if (c->currentIndex() == -1) |
190 | return; |
191 | |
192 | QDesignerFormWindowInterface *fw = formWindow(); |
193 | DeleteContainerWidgetPageCommand *cmd = new DeleteContainerWidgetPageCommand(fw); |
194 | cmd->init(containerWidget: m_containerWidget, ct: m_type); |
195 | fw->commandHistory()->push(cmd); |
196 | } |
197 | } |
198 | |
199 | void ContainerWidgetTaskMenu::() |
200 | { |
201 | if (containerExtension()) { |
202 | QDesignerFormWindowInterface *fw = formWindow(); |
203 | AddContainerWidgetPageCommand *cmd = new AddContainerWidgetPageCommand(fw); |
204 | cmd->init(containerWidget: m_containerWidget, ct: m_type, mode: AddContainerWidgetPageCommand::InsertBefore); |
205 | fw->commandHistory()->push(cmd); |
206 | } |
207 | } |
208 | |
209 | void ContainerWidgetTaskMenu::() |
210 | { |
211 | if (containerExtension()) { |
212 | QDesignerFormWindowInterface *fw = formWindow(); |
213 | AddContainerWidgetPageCommand *cmd = new AddContainerWidgetPageCommand(fw); |
214 | cmd->init(containerWidget: m_containerWidget, ct: m_type, mode: AddContainerWidgetPageCommand::InsertAfter); |
215 | fw->commandHistory()->push(cmd); |
216 | } |
217 | } |
218 | |
219 | // -------------- WizardContainerWidgetTaskMenu |
220 | WizardContainerWidgetTaskMenu::(QWizard *w, QObject *parent) : |
221 | ContainerWidgetTaskMenu(w, WizardContainer, parent), |
222 | m_nextAction(new QAction(tr(s: "Next" ), this)), |
223 | m_previousAction(new QAction(tr(s: "Back" ), this)) |
224 | { |
225 | connect(sender: m_nextAction, signal: &QAction::triggered, receiver: w, slot: &QWizard::next); |
226 | connect(sender: m_previousAction, signal: &QAction::triggered, receiver: w, slot: &QWizard::back); |
227 | auto &l = containerActions(); |
228 | l.push_front(t: createSeparator()); |
229 | l.push_front(t: m_nextAction); |
230 | l.push_front(t: m_previousAction); |
231 | l.push_front(t: createSeparator()); |
232 | } |
233 | |
234 | QList<QAction*> WizardContainerWidgetTaskMenu::() const |
235 | { |
236 | // Enable |
237 | const QDesignerContainerExtension *ce = containerExtension(); |
238 | const int index = ce->currentIndex(); |
239 | m_previousAction->setEnabled(index > 0); |
240 | m_nextAction->setEnabled(index >= 0 && index < (ce->count() - 1)); |
241 | return ContainerWidgetTaskMenu::taskActions(); |
242 | } |
243 | |
244 | // -------------- MdiContainerWidgetTaskMenu |
245 | |
246 | MdiContainerWidgetTaskMenu::(QMdiArea *m, QObject *parent) : |
247 | ContainerWidgetTaskMenu(m, MdiContainer, parent) |
248 | { |
249 | initializeActions(); |
250 | connect(sender: m_nextAction, signal: &QAction::triggered, receiver: m, slot: &QMdiArea::activateNextSubWindow); |
251 | connect(sender: m_previousAction, signal: &QAction::triggered, receiver: m , slot: &QMdiArea::activatePreviousSubWindow); |
252 | connect(sender: m_tileAction, signal: &QAction::triggered, receiver: m, slot: &QMdiArea::tileSubWindows); |
253 | connect(sender: m_cascadeAction, signal: &QAction::triggered, receiver: m, slot: &QMdiArea::cascadeSubWindows); |
254 | } |
255 | |
256 | void MdiContainerWidgetTaskMenu::() |
257 | { |
258 | m_nextAction =new QAction(tr(s: "Next Subwindow" ), this); |
259 | m_previousAction = new QAction(tr(s: "Previous Subwindow" ), this); |
260 | m_tileAction = new QAction(tr(s: "Tile" ), this); |
261 | m_cascadeAction = new QAction(tr(s: "Cascade" ), this); |
262 | |
263 | auto &l = containerActions(); |
264 | l.push_front(t: createSeparator()); |
265 | l.push_front(t: m_tileAction); |
266 | l.push_front(t: m_cascadeAction); |
267 | l.push_front(t: m_previousAction); |
268 | l.push_front(t: m_nextAction); |
269 | l.push_front(t: createSeparator()); |
270 | } |
271 | |
272 | QList<QAction*> MdiContainerWidgetTaskMenu::() const |
273 | { |
274 | const auto rc = ContainerWidgetTaskMenu::taskActions(); |
275 | // Enable |
276 | const int count = pageCount(); |
277 | m_nextAction->setEnabled(count > 1); |
278 | m_previousAction->setEnabled(count > 1); |
279 | m_tileAction->setEnabled(count); |
280 | m_cascadeAction->setEnabled(count); |
281 | return rc; |
282 | } |
283 | |
284 | // -------------- ContainerWidgetTaskMenuFactory |
285 | |
286 | ContainerWidgetTaskMenuFactory::(QDesignerFormEditorInterface *core, QExtensionManager *extensionManager) : |
287 | QExtensionFactory(extensionManager), |
288 | m_core(core) |
289 | { |
290 | } |
291 | |
292 | QObject *ContainerWidgetTaskMenuFactory::(QObject *object, const QString &iid, QObject *parent) const |
293 | { |
294 | if (iid != QStringLiteral("QDesignerInternalTaskMenuExtension" ) || !object->isWidgetType()) |
295 | return nullptr; |
296 | |
297 | QWidget *widget = qobject_cast<QWidget*>(o: object); |
298 | |
299 | if (qobject_cast<QStackedWidget*>(object: widget) |
300 | || qobject_cast<QToolBox*>(object: widget) |
301 | || qobject_cast<QTabWidget*>(object: widget) |
302 | || qobject_cast<QMainWindow*>(object: widget)) { |
303 | // Are we using Designer's own container extensions and task menus or did |
304 | // someone provide an extra one with an addpage method, for example for a QScrollArea? |
305 | if (const WidgetDataBase *wb = qobject_cast<const WidgetDataBase *>(object: m_core->widgetDataBase())) { |
306 | const int idx = wb->indexOfObject(o: widget); |
307 | const WidgetDataBaseItem *item = static_cast<const WidgetDataBaseItem *>(wb->item(index: idx)); |
308 | if (item->addPageMethod().isEmpty()) |
309 | return nullptr; |
310 | } |
311 | } |
312 | |
313 | if (qt_extension<QDesignerContainerExtension*>(manager: extensionManager(), object) == nullptr) |
314 | return nullptr; |
315 | |
316 | if (QMdiArea* ma = qobject_cast<QMdiArea*>(object: widget)) |
317 | return new MdiContainerWidgetTaskMenu(ma, parent); |
318 | if (QWizard *wz = qobject_cast<QWizard *>(object: widget)) |
319 | return new WizardContainerWidgetTaskMenu(wz, parent); |
320 | return new ContainerWidgetTaskMenu(widget, PageContainer, parent); |
321 | } |
322 | |
323 | } |
324 | QT_END_NAMESPACE |
325 | |