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 "qdesigner_toolbox_p.h" |
30 | #include "qdesigner_command_p.h" |
31 | #include "orderdialog_p.h" |
32 | #include "promotiontaskmenu_p.h" |
33 | #include "formwindowbase_p.h" |
34 | |
35 | #include <QtDesigner/abstractformwindow.h> |
36 | |
37 | #include <QtWidgets/qaction.h> |
38 | #include <QtWidgets/qtoolbox.h> |
39 | #include <QtWidgets/qmenu.h> |
40 | #include <QtWidgets/qlayout.h> |
41 | #include <QtWidgets/qapplication.h> |
42 | #include <QtGui/qevent.h> |
43 | #include <QtCore/qhash.h> |
44 | |
45 | QT_BEGIN_NAMESPACE |
46 | |
47 | QToolBoxHelper::QToolBoxHelper(QToolBox *toolbox) : |
48 | QObject(toolbox), |
49 | m_toolbox(toolbox), |
50 | m_actionDeletePage(new QAction(tr(s: "Delete Page" ), this)), |
51 | m_actionInsertPage(new QAction(tr(s: "Before Current Page" ), this)), |
52 | m_actionInsertPageAfter(new QAction(tr(s: "After Current Page" ), this)), |
53 | m_actionChangePageOrder(new QAction(tr(s: "Change Page Order..." ), this)), |
54 | m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(nullptr, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this)) |
55 | { |
56 | connect(sender: m_actionDeletePage, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::removeCurrentPage); |
57 | connect(sender: m_actionInsertPage, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::addPage); |
58 | connect(sender: m_actionInsertPageAfter, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::addPageAfter); |
59 | connect(sender: m_actionChangePageOrder, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::changeOrder); |
60 | |
61 | m_toolbox->installEventFilter(filterObj: this); |
62 | } |
63 | |
64 | void QToolBoxHelper::install(QToolBox *toolbox) |
65 | { |
66 | new QToolBoxHelper(toolbox); |
67 | } |
68 | |
69 | bool QToolBoxHelper::eventFilter(QObject *watched, QEvent *event) |
70 | { |
71 | switch (event->type()) { |
72 | case QEvent::ChildPolished: |
73 | // Install on the buttons |
74 | if (watched == m_toolbox) { |
75 | QChildEvent *ce = static_cast<QChildEvent *>(event); |
76 | if (!qstrcmp(str1: ce->child()->metaObject()->className(), str2: "QToolBoxButton" )) |
77 | ce->child()->installEventFilter(filterObj: this); |
78 | } |
79 | break; |
80 | case QEvent::ContextMenu: |
81 | if (watched != m_toolbox) { |
82 | // An action invoked from the passive interactor (ToolBox button) might |
83 | // cause its deletion within its event handler, triggering a warning. Re-post |
84 | // the event to the toolbox. |
85 | QContextMenuEvent *current = static_cast<QContextMenuEvent *>(event); |
86 | QContextMenuEvent *copy = new QContextMenuEvent(current->reason(), current->pos(), current-> globalPos(), current->modifiers()); |
87 | QApplication::postEvent(receiver: m_toolbox, event: copy); |
88 | current->accept(); |
89 | return true; |
90 | } |
91 | break; |
92 | case QEvent::MouseButtonRelease: |
93 | if (watched != m_toolbox) |
94 | if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) { |
95 | fw->clearSelection(); |
96 | fw->selectWidget(w: m_toolbox, select: true); |
97 | } |
98 | break; |
99 | default: |
100 | break; |
101 | } |
102 | return QObject::eventFilter(watched, event); |
103 | } |
104 | |
105 | QToolBoxHelper *QToolBoxHelper::helperOf(const QToolBox *toolbox) |
106 | { |
107 | // Look for 1st order children only..otherwise, we might get filters of nested widgets |
108 | for (QObject *o : toolbox->children()) { |
109 | if (!o->isWidgetType()) |
110 | if (QToolBoxHelper *h = qobject_cast<QToolBoxHelper *>(object: o)) |
111 | return h; |
112 | } |
113 | return nullptr; |
114 | } |
115 | |
116 | QMenu *QToolBoxHelper::(const QToolBox *toolbox, QMenu *) |
117 | { |
118 | QToolBoxHelper *helper = helperOf(toolbox); |
119 | if (!helper) |
120 | return nullptr; |
121 | return helper->addContextMenuActions(popup); |
122 | } |
123 | |
124 | void QToolBoxHelper::removeCurrentPage() |
125 | { |
126 | if (m_toolbox->currentIndex() == -1 || !m_toolbox->widget(index: m_toolbox->currentIndex())) |
127 | return; |
128 | |
129 | if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) { |
130 | qdesigner_internal::DeleteToolBoxPageCommand *cmd = new qdesigner_internal::DeleteToolBoxPageCommand(fw); |
131 | cmd->init(toolBox: m_toolbox); |
132 | fw->commandHistory()->push(cmd); |
133 | } |
134 | } |
135 | |
136 | void QToolBoxHelper::addPage() |
137 | { |
138 | if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) { |
139 | qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw); |
140 | cmd->init(toolBox: m_toolbox, mode: qdesigner_internal::AddToolBoxPageCommand::InsertBefore); |
141 | fw->commandHistory()->push(cmd); |
142 | } |
143 | } |
144 | |
145 | void QToolBoxHelper::changeOrder() |
146 | { |
147 | QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox); |
148 | |
149 | if (!fw) |
150 | return; |
151 | |
152 | const QWidgetList oldPages = qdesigner_internal::OrderDialog::pagesOfContainer(core: fw->core(), container: m_toolbox); |
153 | const int pageCount = oldPages.size(); |
154 | if (pageCount < 2) |
155 | return; |
156 | |
157 | qdesigner_internal::OrderDialog dlg(fw); |
158 | dlg.setPageList(oldPages); |
159 | if (dlg.exec() == QDialog::Rejected) |
160 | return; |
161 | |
162 | const QWidgetList newPages = dlg.pageList(); |
163 | if (newPages == oldPages) |
164 | return; |
165 | |
166 | fw->beginCommand(description: tr(s: "Change Page Order" )); |
167 | for(int i=0; i < pageCount; ++i) { |
168 | if (newPages.at(i) == m_toolbox->widget(index: i)) |
169 | continue; |
170 | qdesigner_internal::MoveToolBoxPageCommand *cmd = new qdesigner_internal::MoveToolBoxPageCommand(fw); |
171 | cmd->init(toolBox: m_toolbox, page: newPages.at(i), newIndex: i); |
172 | fw->commandHistory()->push(cmd); |
173 | } |
174 | fw->endCommand(); |
175 | } |
176 | |
177 | void QToolBoxHelper::addPageAfter() |
178 | { |
179 | if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) { |
180 | qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw); |
181 | cmd->init(toolBox: m_toolbox, mode: qdesigner_internal::AddToolBoxPageCommand::InsertAfter); |
182 | fw->commandHistory()->push(cmd); |
183 | } |
184 | } |
185 | |
186 | QPalette::ColorRole QToolBoxHelper::currentItemBackgroundRole() const |
187 | { |
188 | const QWidget *w = m_toolbox->widget(index: 0); |
189 | if (!w) |
190 | return QPalette::Window; |
191 | return w->backgroundRole(); |
192 | } |
193 | |
194 | void QToolBoxHelper::setCurrentItemBackgroundRole(QPalette::ColorRole role) |
195 | { |
196 | const int count = m_toolbox->count(); |
197 | for (int i = 0; i < count; ++i) { |
198 | QWidget *w = m_toolbox->widget(index: i); |
199 | w->setBackgroundRole(role); |
200 | w->update(); |
201 | } |
202 | } |
203 | |
204 | QMenu *QToolBoxHelper::(QMenu *) const |
205 | { |
206 | QMenu * = nullptr; |
207 | const int count = m_toolbox->count(); |
208 | m_actionDeletePage->setEnabled(count > 1); |
209 | if (count) { |
210 | const QString = tr(s: "Page %1 of %2" ).arg(a: m_toolbox->currentIndex() + 1).arg(a: count); |
211 | pageMenu = popup->addMenu(title: pageSubMenuLabel); |
212 | |
213 | pageMenu->addAction(action: m_actionDeletePage); |
214 | // Set up promotion menu for current widget. |
215 | if (QWidget *page = m_toolbox->currentWidget ()) { |
216 | m_pagePromotionTaskMenu->setWidget(page); |
217 | m_pagePromotionTaskMenu->addActions(fw: QDesignerFormWindowInterface::findFormWindow(w: m_toolbox), |
218 | flags: qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit, |
219 | menu: pageMenu); |
220 | } |
221 | } |
222 | QMenu * = popup->addMenu(title: tr(s: "Insert Page" )); |
223 | insertPageMenu->addAction(action: m_actionInsertPageAfter); |
224 | insertPageMenu->addAction(action: m_actionInsertPage); |
225 | if (count > 1) { |
226 | popup->addAction(action: m_actionChangePageOrder); |
227 | } |
228 | popup->addSeparator(); |
229 | return pageMenu; |
230 | } |
231 | |
232 | // -------- QToolBoxWidgetPropertySheet |
233 | |
234 | static const char *currentItemTextKey = "currentItemText" ; |
235 | static const char *currentItemNameKey = "currentItemName" ; |
236 | static const char *currentItemIconKey = "currentItemIcon" ; |
237 | static const char *currentItemToolTipKey = "currentItemToolTip" ; |
238 | static const char *tabSpacingKey = "tabSpacing" ; |
239 | |
240 | enum { tabSpacingDefault = -1 }; |
241 | |
242 | QToolBoxWidgetPropertySheet::QToolBoxWidgetPropertySheet(QToolBox *object, QObject *parent) : |
243 | QDesignerPropertySheet(object, parent), |
244 | m_toolBox(object) |
245 | { |
246 | createFakeProperty(propertyName: QLatin1String(currentItemTextKey), value: QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue())); |
247 | createFakeProperty(propertyName: QLatin1String(currentItemNameKey), value: QString()); |
248 | createFakeProperty(propertyName: QLatin1String(currentItemIconKey), value: QVariant::fromValue(value: qdesigner_internal::PropertySheetIconValue())); |
249 | if (formWindowBase()) |
250 | formWindowBase()->addReloadableProperty(sheet: this, index: indexOf(name: QLatin1String(currentItemIconKey))); |
251 | createFakeProperty(propertyName: QLatin1String(currentItemToolTipKey), value: QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue())); |
252 | createFakeProperty(propertyName: QLatin1String(tabSpacingKey), value: QVariant(tabSpacingDefault)); |
253 | } |
254 | |
255 | QToolBoxWidgetPropertySheet::ToolBoxProperty QToolBoxWidgetPropertySheet::toolBoxPropertyFromName(const QString &name) |
256 | { |
257 | using ToolBoxPropertyHash = QHash<QString, ToolBoxProperty>; |
258 | static ToolBoxPropertyHash toolBoxPropertyHash; |
259 | if (toolBoxPropertyHash.isEmpty()) { |
260 | toolBoxPropertyHash.insert(akey: QLatin1String(currentItemTextKey), avalue: PropertyCurrentItemText); |
261 | toolBoxPropertyHash.insert(akey: QLatin1String(currentItemNameKey), avalue: PropertyCurrentItemName); |
262 | toolBoxPropertyHash.insert(akey: QLatin1String(currentItemIconKey), avalue: PropertyCurrentItemIcon); |
263 | toolBoxPropertyHash.insert(akey: QLatin1String(currentItemToolTipKey), avalue: PropertyCurrentItemToolTip); |
264 | toolBoxPropertyHash.insert(akey: QLatin1String(tabSpacingKey), avalue: PropertyTabSpacing); |
265 | } |
266 | return toolBoxPropertyHash.value(akey: name, adefaultValue: PropertyToolBoxNone); |
267 | } |
268 | |
269 | void QToolBoxWidgetPropertySheet::setProperty(int index, const QVariant &value) |
270 | { |
271 | const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(name: propertyName(index)); |
272 | // independent of index |
273 | switch (toolBoxProperty) { |
274 | case PropertyTabSpacing: |
275 | m_toolBox->layout()->setSpacing(value.toInt()); |
276 | return; |
277 | case PropertyToolBoxNone: |
278 | QDesignerPropertySheet::setProperty(index, value); |
279 | return; |
280 | default: |
281 | break; |
282 | } |
283 | // index-dependent |
284 | const int currentIndex = m_toolBox->currentIndex(); |
285 | QWidget *currentWidget = m_toolBox->currentWidget(); |
286 | if (!currentWidget) |
287 | return; |
288 | |
289 | switch (toolBoxProperty) { |
290 | case PropertyCurrentItemText: |
291 | m_toolBox->setItemText(index: currentIndex, text: qvariant_cast<QString>(v: resolvePropertyValue(index, value))); |
292 | m_pageToData[currentWidget].text = qvariant_cast<qdesigner_internal::PropertySheetStringValue>(v: value); |
293 | break; |
294 | case PropertyCurrentItemName: |
295 | currentWidget->setObjectName(value.toString()); |
296 | break; |
297 | case PropertyCurrentItemIcon: |
298 | m_toolBox->setItemIcon(index: currentIndex, icon: qvariant_cast<QIcon>(v: resolvePropertyValue(index, value))); |
299 | m_pageToData[currentWidget].icon = qvariant_cast<qdesigner_internal::PropertySheetIconValue>(v: value); |
300 | break; |
301 | case PropertyCurrentItemToolTip: |
302 | m_toolBox->setItemToolTip(index: currentIndex, toolTip: qvariant_cast<QString>(v: resolvePropertyValue(index, value))); |
303 | m_pageToData[currentWidget].tooltip = qvariant_cast<qdesigner_internal::PropertySheetStringValue>(v: value); |
304 | break; |
305 | case PropertyTabSpacing: |
306 | case PropertyToolBoxNone: |
307 | break; |
308 | } |
309 | } |
310 | |
311 | bool QToolBoxWidgetPropertySheet::isEnabled(int index) const |
312 | { |
313 | switch (toolBoxPropertyFromName(name: propertyName(index))) { |
314 | case PropertyToolBoxNone: // independent of index |
315 | case PropertyTabSpacing: |
316 | return QDesignerPropertySheet::isEnabled(index); |
317 | default: |
318 | break; |
319 | } |
320 | return m_toolBox->currentIndex() != -1; |
321 | } |
322 | |
323 | QVariant QToolBoxWidgetPropertySheet::property(int index) const |
324 | { |
325 | const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(name: propertyName(index)); |
326 | // independent of index |
327 | switch (toolBoxProperty) { |
328 | case PropertyTabSpacing: |
329 | return m_toolBox->layout()->spacing(); |
330 | case PropertyToolBoxNone: |
331 | return QDesignerPropertySheet::property(index); |
332 | default: |
333 | break; |
334 | } |
335 | // index-dependent |
336 | QWidget *currentWidget = m_toolBox->currentWidget(); |
337 | if (!currentWidget) { |
338 | if (toolBoxProperty == PropertyCurrentItemIcon) |
339 | return QVariant::fromValue(value: qdesigner_internal::PropertySheetIconValue()); |
340 | if (toolBoxProperty == PropertyCurrentItemText) |
341 | return QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue()); |
342 | if (toolBoxProperty == PropertyCurrentItemToolTip) |
343 | return QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue()); |
344 | return QVariant(QString()); |
345 | } |
346 | |
347 | // index-dependent |
348 | switch (toolBoxProperty) { |
349 | case PropertyCurrentItemText: |
350 | return QVariant::fromValue(value: m_pageToData.value(akey: currentWidget).text); |
351 | case PropertyCurrentItemName: |
352 | return currentWidget->objectName(); |
353 | case PropertyCurrentItemIcon: |
354 | return QVariant::fromValue(value: m_pageToData.value(akey: currentWidget).icon); |
355 | case PropertyCurrentItemToolTip: |
356 | return QVariant::fromValue(value: m_pageToData.value(akey: currentWidget).tooltip); |
357 | case PropertyTabSpacing: |
358 | case PropertyToolBoxNone: |
359 | break; |
360 | } |
361 | return QVariant(); |
362 | } |
363 | |
364 | bool QToolBoxWidgetPropertySheet::reset(int index) |
365 | { |
366 | const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(name: propertyName(index)); |
367 | // independent of index |
368 | switch (toolBoxProperty) { |
369 | case PropertyTabSpacing: |
370 | setProperty(index, value: QVariant(tabSpacingDefault)); |
371 | return true; |
372 | case PropertyToolBoxNone: |
373 | return QDesignerPropertySheet::reset(index); |
374 | default: |
375 | break; |
376 | } |
377 | // index-dependent |
378 | QWidget *currentWidget = m_toolBox->currentWidget(); |
379 | if (!currentWidget) |
380 | return false; |
381 | |
382 | // index-dependent |
383 | switch (toolBoxProperty) { |
384 | case PropertyCurrentItemName: |
385 | setProperty(index, value: QString()); |
386 | break; |
387 | case PropertyCurrentItemToolTip: |
388 | m_pageToData[currentWidget].tooltip = qdesigner_internal::PropertySheetStringValue(); |
389 | setProperty(index, value: QString()); |
390 | break; |
391 | case PropertyCurrentItemText: |
392 | m_pageToData[currentWidget].text = qdesigner_internal::PropertySheetStringValue(); |
393 | setProperty(index, value: QString()); |
394 | break; |
395 | case PropertyCurrentItemIcon: |
396 | m_pageToData[currentWidget].icon = qdesigner_internal::PropertySheetIconValue(); |
397 | setProperty(index, value: QIcon()); |
398 | break; |
399 | case PropertyTabSpacing: |
400 | case PropertyToolBoxNone: |
401 | break; |
402 | } |
403 | return true; |
404 | } |
405 | |
406 | bool QToolBoxWidgetPropertySheet::checkProperty(const QString &propertyName) |
407 | { |
408 | switch (toolBoxPropertyFromName(name: propertyName)) { |
409 | case PropertyCurrentItemText: |
410 | case PropertyCurrentItemName: |
411 | case PropertyCurrentItemToolTip: |
412 | case PropertyCurrentItemIcon: |
413 | return false; |
414 | default: |
415 | break; |
416 | } |
417 | return true; |
418 | } |
419 | |
420 | QT_END_NAMESPACE |
421 | |