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 | // components/formeditor |
30 | #include "formwindowmanager.h" |
31 | #include "formwindow_dnditem.h" |
32 | #include "formwindow.h" |
33 | #include "formeditor.h" |
34 | #include "widgetselection.h" |
35 | #include "previewactiongroup.h" |
36 | #include "formwindowsettings.h" |
37 | |
38 | // shared |
39 | #include <widgetdatabase_p.h> |
40 | #include <iconloader_p.h> |
41 | #include <connectionedit_p.h> |
42 | #include <qtresourcemodel_p.h> |
43 | #include <qdesigner_dnditem_p.h> |
44 | #include <qdesigner_command_p.h> |
45 | #include <qdesigner_command2_p.h> |
46 | #include <layoutinfo_p.h> |
47 | #include <qlayout_widget_p.h> |
48 | #include <qdesigner_objectinspector_p.h> |
49 | #include <actioneditor_p.h> |
50 | #include <shared_settings_p.h> |
51 | #include <previewmanager_p.h> |
52 | #include <abstractdialoggui_p.h> |
53 | #include <widgetfactory_p.h> |
54 | #include <spacer_widget_p.h> |
55 | |
56 | // SDK |
57 | #include <QtDesigner/qextensionmanager.h> |
58 | #include <QtDesigner/abstractlanguage.h> |
59 | #include <QtDesigner/container.h> |
60 | #include <QtDesigner/abstractwidgetbox.h> |
61 | #include <QtDesigner/abstractintegration.h> |
62 | |
63 | #include <QtWidgets/qundogroup.h> |
64 | #include <QtWidgets/qaction.h> |
65 | #include <QtWidgets/qsplitter.h> |
66 | #include <QtGui/qevent.h> |
67 | #include <QtWidgets/qapplication.h> |
68 | #include <QtWidgets/qsizegrip.h> |
69 | #if QT_CONFIG(clipboard) |
70 | #include <QtGui/qclipboard.h> |
71 | #endif |
72 | #include <QtWidgets/qmdiarea.h> |
73 | #include <QtWidgets/qmdisubwindow.h> |
74 | #include <QtWidgets/qmessagebox.h> |
75 | |
76 | #include <QtCore/qdebug.h> |
77 | |
78 | QT_BEGIN_NAMESPACE |
79 | |
80 | namespace { |
81 | enum { debugFWM = 0 }; |
82 | } |
83 | |
84 | static inline QString whatsThisFrom(const QString &str) { /// ### implement me! |
85 | return str; |
86 | } |
87 | |
88 | // find the first child of w in a sequence |
89 | template <class Iterator> |
90 | static inline Iterator findFirstChildOf(Iterator it,Iterator end, const QWidget *w) |
91 | { |
92 | for (;it != end; ++it) { |
93 | if (w->isAncestorOf(child: *it)) |
94 | return it; |
95 | } |
96 | return it; |
97 | } |
98 | |
99 | namespace qdesigner_internal { |
100 | |
101 | FormWindowManager::FormWindowManager(QDesignerFormEditorInterface *core, QObject *parent) : |
102 | QDesignerFormWindowManager(parent), |
103 | m_core(core), |
104 | m_activeFormWindow(nullptr), |
105 | m_previewManager(new PreviewManager(PreviewManager::SingleFormNonModalPreview, this)), |
106 | m_createLayoutContext(LayoutContainer), |
107 | m_morphLayoutContainer(nullptr), |
108 | m_actionGroupPreviewInStyle(nullptr), |
109 | m_actionShowFormWindowSettingsDialog(nullptr) |
110 | { |
111 | setupActions(); |
112 | qApp->installEventFilter(filterObj: this); |
113 | } |
114 | |
115 | FormWindowManager::~FormWindowManager() |
116 | { |
117 | qDeleteAll(c: m_formWindows); |
118 | } |
119 | |
120 | QDesignerFormEditorInterface *FormWindowManager::core() const |
121 | { |
122 | return m_core; |
123 | } |
124 | |
125 | QDesignerFormWindowInterface *FormWindowManager::activeFormWindow() const |
126 | { |
127 | return m_activeFormWindow; |
128 | } |
129 | |
130 | int FormWindowManager::formWindowCount() const |
131 | { |
132 | return m_formWindows.size(); |
133 | } |
134 | |
135 | QDesignerFormWindowInterface *FormWindowManager::formWindow(int index) const |
136 | { |
137 | return m_formWindows.at(i: index); |
138 | } |
139 | |
140 | bool FormWindowManager::eventFilter(QObject *o, QEvent *e) |
141 | { |
142 | if (!o->isWidgetType()) |
143 | return false; |
144 | |
145 | // If we don't have an active form, we only listen for WindowActivate to speed up integrations |
146 | const QEvent::Type eventType = e->type(); |
147 | if (m_activeFormWindow == nullptr && eventType != QEvent::WindowActivate) |
148 | return false; |
149 | |
150 | switch (eventType) { // Uninteresting events |
151 | case QEvent::Create: |
152 | case QEvent::Destroy: |
153 | case QEvent::ActionAdded: |
154 | case QEvent::ActionChanged: |
155 | case QEvent::ActionRemoved: |
156 | case QEvent::ChildAdded: |
157 | case QEvent::ChildPolished: |
158 | case QEvent::ChildRemoved: |
159 | #if QT_CONFIG(clipboard) |
160 | case QEvent::Clipboard: |
161 | #endif |
162 | case QEvent::ContentsRectChange: |
163 | case QEvent::DeferredDelete: |
164 | case QEvent::FileOpen: |
165 | case QEvent::LanguageChange: |
166 | case QEvent::MetaCall: |
167 | case QEvent::ModifiedChange: |
168 | case QEvent::Paint: |
169 | case QEvent::PaletteChange: |
170 | case QEvent::ParentAboutToChange: |
171 | case QEvent::ParentChange: |
172 | case QEvent::Polish: |
173 | case QEvent::PolishRequest: |
174 | case QEvent::QueryWhatsThis: |
175 | case QEvent::StatusTip: |
176 | case QEvent::StyleChange: |
177 | case QEvent::Timer: |
178 | case QEvent::ToolBarChange: |
179 | case QEvent::ToolTip: |
180 | case QEvent::WhatsThis: |
181 | case QEvent::WhatsThisClicked: |
182 | case QEvent::WinIdChange: |
183 | case QEvent::DynamicPropertyChange: |
184 | case QEvent::HoverEnter: |
185 | case QEvent::HoverLeave: |
186 | case QEvent::HoverMove: |
187 | case QEvent::AcceptDropsChange: |
188 | return false; |
189 | default: |
190 | break; |
191 | } |
192 | |
193 | QWidget *widget = static_cast<QWidget*>(o); |
194 | |
195 | if (qobject_cast<WidgetHandle*>(object: widget)) { // ### remove me |
196 | return false; |
197 | } |
198 | |
199 | FormWindow *fw = FormWindow::findFormWindow(w: widget); |
200 | if (fw == nullptr) { |
201 | return false; |
202 | } |
203 | |
204 | if (QWidget *managedWidget = findManagedWidget(fw, w: widget)) { |
205 | // Prevent MDI subwindows from being closed by clicking at the title bar |
206 | if (managedWidget != widget && eventType == QEvent::Close) { |
207 | e->ignore(); |
208 | return true; |
209 | } |
210 | switch (eventType) { |
211 | case QEvent::LayoutRequest: |
212 | // QTBUG-61439: Suppress layout request while changing the QGridLayout |
213 | // span of a QTabWidget, which sends LayoutRequest in resizeEvent(). |
214 | if (fw->handleOperation() == FormWindow::ChangeLayoutSpanHandleOperation) { |
215 | e->ignore(); |
216 | return true; |
217 | } |
218 | break; |
219 | |
220 | case QEvent::WindowActivate: { |
221 | if (fw->parentWidget()->isWindow() && fw->isMainContainer(w: managedWidget) && activeFormWindow() != fw) { |
222 | setActiveFormWindow(fw); |
223 | } |
224 | } break; |
225 | |
226 | case QEvent::WindowDeactivate: { |
227 | if (o == fw && o == activeFormWindow()) |
228 | fw->repaintSelection(); |
229 | } break; |
230 | |
231 | case QEvent::KeyPress: { |
232 | QKeyEvent *ke = static_cast<QKeyEvent*>(e); |
233 | if (ke->key() == Qt::Key_Escape) { |
234 | ke->accept(); |
235 | return true; |
236 | } |
237 | } |
238 | Q_FALLTHROUGH(); // don't break... |
239 | |
240 | // Embedded Design: Drop on different form: Make sure the right form |
241 | // window/device is active before having the widget created by the factory |
242 | case QEvent::Drop: |
243 | if (activeFormWindow() != fw) |
244 | setActiveFormWindow(fw); |
245 | Q_FALLTHROUGH(); // don't break... |
246 | default: { |
247 | if (fw->handleEvent(widget, managedWidget, event: e)) { |
248 | return true; |
249 | } |
250 | } break; |
251 | |
252 | } // end switch |
253 | } |
254 | |
255 | return false; |
256 | } |
257 | |
258 | void FormWindowManager::addFormWindow(QDesignerFormWindowInterface *w) |
259 | { |
260 | FormWindow *formWindow = qobject_cast<FormWindow*>(object: w); |
261 | if (!formWindow || m_formWindows.contains(t: formWindow)) |
262 | return; |
263 | |
264 | connect(sender: formWindow, signal: &QDesignerFormWindowInterface::selectionChanged, |
265 | receiver: this, slot: &FormWindowManager::slotUpdateActions); |
266 | connect(sender: formWindow->commandHistory(), signal: &QUndoStack::indexChanged, |
267 | receiver: this, slot: &FormWindowManager::slotUpdateActions); |
268 | connect(sender: formWindow, signal: &QDesignerFormWindowInterface::toolChanged, |
269 | receiver: this, slot: &FormWindowManager::slotUpdateActions); |
270 | |
271 | if (ActionEditor *ae = qobject_cast<ActionEditor *>(object: m_core->actionEditor())) { |
272 | connect(sender: w, signal: &QDesignerFormWindowInterface::mainContainerChanged, |
273 | receiver: ae, slot: &ActionEditor::mainContainerChanged); |
274 | } |
275 | if (QDesignerObjectInspector *oi = qobject_cast<QDesignerObjectInspector *>(object: m_core->objectInspector())) |
276 | connect(sender: w, signal: &QDesignerFormWindowInterface::mainContainerChanged, |
277 | receiver: oi, slot: &QDesignerObjectInspector::mainContainerChanged); |
278 | |
279 | m_formWindows.append(t: formWindow); |
280 | emit formWindowAdded(formWindow); |
281 | } |
282 | |
283 | void FormWindowManager::removeFormWindow(QDesignerFormWindowInterface *w) |
284 | { |
285 | FormWindow *formWindow = qobject_cast<FormWindow*>(object: w); |
286 | |
287 | int idx = m_formWindows.indexOf(t: formWindow); |
288 | if (!formWindow || idx == -1) |
289 | return; |
290 | |
291 | formWindow->disconnect(receiver: this); |
292 | m_formWindows.removeAt(i: idx); |
293 | emit formWindowRemoved(formWindow); |
294 | |
295 | if (formWindow == m_activeFormWindow) |
296 | setActiveFormWindow(nullptr); |
297 | |
298 | // Make sure that widget box is enabled by default |
299 | if (m_formWindows.isEmpty() && m_core->widgetBox()) |
300 | m_core->widgetBox()->setEnabled(true); |
301 | |
302 | } |
303 | |
304 | void FormWindowManager::setActiveFormWindow(QDesignerFormWindowInterface *w) |
305 | { |
306 | FormWindow *formWindow = qobject_cast<FormWindow*>(object: w); |
307 | |
308 | if (formWindow == m_activeFormWindow) |
309 | return; |
310 | |
311 | FormWindow *old = m_activeFormWindow; |
312 | |
313 | m_activeFormWindow = formWindow; |
314 | |
315 | QtResourceSet *resourceSet = nullptr; |
316 | if (formWindow) |
317 | resourceSet = formWindow->resourceSet(); |
318 | m_core->resourceModel()->setCurrentResourceSet(resourceSet); |
319 | |
320 | slotUpdateActions(); |
321 | |
322 | if (m_activeFormWindow) { |
323 | m_activeFormWindow->repaintSelection(); |
324 | if (old) |
325 | old->repaintSelection(); |
326 | } |
327 | |
328 | emit activeFormWindowChanged(formWindow: m_activeFormWindow); |
329 | |
330 | if (m_activeFormWindow) { |
331 | m_activeFormWindow->emitSelectionChanged(); |
332 | m_activeFormWindow->commandHistory()->setActive(); |
333 | // Trigger setActiveSubWindow on mdi area unless we are in toplevel mode |
334 | QMdiSubWindow *mdiSubWindow = nullptr; |
335 | if (QWidget *formwindow = m_activeFormWindow->parentWidget()) { |
336 | mdiSubWindow = qobject_cast<QMdiSubWindow *>(object: formwindow->parentWidget()); |
337 | } |
338 | if (mdiSubWindow) { |
339 | for (QWidget *parent = mdiSubWindow->parentWidget(); parent; parent = parent->parentWidget()) { |
340 | if (QMdiArea *mdiArea = qobject_cast<QMdiArea*>(object: parent)) { |
341 | mdiArea->setActiveSubWindow(mdiSubWindow); |
342 | break; |
343 | } |
344 | } |
345 | } |
346 | } |
347 | } |
348 | |
349 | void FormWindowManager::closeAllPreviews() |
350 | { |
351 | m_previewManager->closeAllPreviews(); |
352 | } |
353 | |
354 | QWidget *FormWindowManager::findManagedWidget(FormWindow *fw, QWidget *w) |
355 | { |
356 | while (w && w != fw) { |
357 | if (fw->isManaged(w)) |
358 | break; |
359 | w = w->parentWidget(); |
360 | } |
361 | return w; |
362 | } |
363 | |
364 | void FormWindowManager::setupActions() |
365 | { |
366 | #if QT_CONFIG(clipboard) |
367 | const QIcon cutIcon = QIcon::fromTheme(QStringLiteral("edit-cut" ), fallback: createIconSet(QStringLiteral("editcut.png" ))); |
368 | m_actionCut = new QAction(cutIcon, tr(s: "Cu&t" ), this); |
369 | m_actionCut->setObjectName(QStringLiteral("__qt_cut_action" )); |
370 | m_actionCut->setShortcut(QKeySequence::Cut); |
371 | m_actionCut->setStatusTip(tr(s: "Cuts the selected widgets and puts them on the clipboard" )); |
372 | m_actionCut->setWhatsThis(whatsThisFrom(QStringLiteral("Edit|Cut" ))); |
373 | connect(sender: m_actionCut, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionCutActivated); |
374 | m_actionCut->setEnabled(false); |
375 | |
376 | const QIcon copyIcon = QIcon::fromTheme(QStringLiteral("edit-copy" ), fallback: createIconSet(QStringLiteral("editcopy.png" ))); |
377 | m_actionCopy = new QAction(copyIcon, tr(s: "&Copy" ), this); |
378 | m_actionCopy->setObjectName(QStringLiteral("__qt_copy_action" )); |
379 | m_actionCopy->setShortcut(QKeySequence::Copy); |
380 | m_actionCopy->setStatusTip(tr(s: "Copies the selected widgets to the clipboard" )); |
381 | m_actionCopy->setWhatsThis(whatsThisFrom(QStringLiteral("Edit|Copy" ))); |
382 | connect(sender: m_actionCopy, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionCopyActivated); |
383 | m_actionCopy->setEnabled(false); |
384 | |
385 | const QIcon pasteIcon = QIcon::fromTheme(QStringLiteral("edit-paste" ), fallback: createIconSet(QStringLiteral("editpaste.png" ))); |
386 | m_actionPaste = new QAction(pasteIcon, tr(s: "&Paste" ), this); |
387 | m_actionPaste->setObjectName(QStringLiteral("__qt_paste_action" )); |
388 | m_actionPaste->setShortcut(QKeySequence::Paste); |
389 | m_actionPaste->setStatusTip(tr(s: "Pastes the clipboard's contents" )); |
390 | m_actionPaste->setWhatsThis(whatsThisFrom(QStringLiteral("Edit|Paste" ))); |
391 | connect(sender: m_actionPaste, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionPasteActivated); |
392 | m_actionPaste->setEnabled(false); |
393 | #endif |
394 | |
395 | m_actionDelete = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete" )), tr(s: "&Delete" ), this); |
396 | m_actionDelete->setObjectName(QStringLiteral("__qt_delete_action" )); |
397 | m_actionDelete->setStatusTip(tr(s: "Deletes the selected widgets" )); |
398 | m_actionDelete->setWhatsThis(whatsThisFrom(QStringLiteral("Edit|Delete" ))); |
399 | connect(sender: m_actionDelete, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionDeleteActivated); |
400 | m_actionDelete->setEnabled(false); |
401 | |
402 | m_actionSelectAll = new QAction(tr(s: "Select &All" ), this); |
403 | m_actionSelectAll->setObjectName(QStringLiteral("__qt_select_all_action" )); |
404 | m_actionSelectAll->setShortcut(QKeySequence::SelectAll); |
405 | m_actionSelectAll->setStatusTip(tr(s: "Selects all widgets" )); |
406 | m_actionSelectAll->setWhatsThis(whatsThisFrom(QStringLiteral("Edit|Select All" ))); |
407 | connect(sender: m_actionSelectAll, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionSelectAllActivated); |
408 | m_actionSelectAll->setEnabled(false); |
409 | |
410 | m_actionRaise = new QAction(createIconSet(QStringLiteral("editraise.png" )), tr(s: "Bring to &Front" ), this); |
411 | m_actionRaise->setObjectName(QStringLiteral("__qt_raise_action" )); |
412 | m_actionRaise->setShortcut(Qt::CTRL | Qt::Key_L); |
413 | m_actionRaise->setStatusTip(tr(s: "Raises the selected widgets" )); |
414 | m_actionRaise->setWhatsThis(tr(s: "Raises the selected widgets" )); |
415 | connect(sender: m_actionRaise, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionRaiseActivated); |
416 | m_actionRaise->setEnabled(false); |
417 | |
418 | m_actionLower = new QAction(createIconSet(QStringLiteral("editlower.png" )), tr(s: "Send to &Back" ), this); |
419 | m_actionLower->setObjectName(QStringLiteral("__qt_lower_action" )); |
420 | m_actionLower->setShortcut(Qt::CTRL | Qt::Key_K); |
421 | m_actionLower->setStatusTip(tr(s: "Lowers the selected widgets" )); |
422 | m_actionLower->setWhatsThis(tr(s: "Lowers the selected widgets" )); |
423 | connect(sender: m_actionLower, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionLowerActivated); |
424 | m_actionLower->setEnabled(false); |
425 | |
426 | m_actionAdjustSize = new QAction(createIconSet(QStringLiteral("adjustsize.png" )), tr(s: "Adjust &Size" ), this); |
427 | m_actionAdjustSize->setObjectName(QStringLiteral("__qt_adjust_size_action" )); |
428 | m_actionAdjustSize->setShortcut(Qt::CTRL | Qt::Key_J); |
429 | m_actionAdjustSize->setStatusTip(tr(s: "Adjusts the size of the selected widget" )); |
430 | m_actionAdjustSize->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Adjust Size" ))); |
431 | connect(sender: m_actionAdjustSize, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionAdjustSizeActivated); |
432 | m_actionAdjustSize->setEnabled(false); |
433 | |
434 | |
435 | m_actionHorizontalLayout = new QAction(createIconSet(QStringLiteral("edithlayout.png" )), tr(s: "Lay Out &Horizontally" ), this); |
436 | m_actionHorizontalLayout->setObjectName(QStringLiteral("__qt_horizontal_layout_action" )); |
437 | m_actionHorizontalLayout->setShortcut(Qt::CTRL | Qt::Key_1); |
438 | m_actionHorizontalLayout->setStatusTip(tr(s: "Lays out the selected widgets horizontally" )); |
439 | m_actionHorizontalLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Horizontally" ))); |
440 | m_actionHorizontalLayout->setData(LayoutInfo::HBox); |
441 | m_actionHorizontalLayout->setEnabled(false); |
442 | connect(sender: m_actionHorizontalLayout, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::createLayout); |
443 | |
444 | m_actionVerticalLayout = new QAction(createIconSet(QStringLiteral("editvlayout.png" )), tr(s: "Lay Out &Vertically" ), this); |
445 | m_actionVerticalLayout->setObjectName(QStringLiteral("__qt_vertical_layout_action" )); |
446 | m_actionVerticalLayout->setShortcut(Qt::CTRL | Qt::Key_2); |
447 | m_actionVerticalLayout->setStatusTip(tr(s: "Lays out the selected widgets vertically" )); |
448 | m_actionVerticalLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Vertically" ))); |
449 | m_actionVerticalLayout->setData(LayoutInfo::VBox); |
450 | m_actionVerticalLayout->setEnabled(false); |
451 | connect(sender: m_actionVerticalLayout, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::createLayout); |
452 | |
453 | QIcon formIcon = QIcon::fromTheme(QStringLiteral("designer-form-layout" ), fallback: createIconSet(QStringLiteral("editform.png" ))); |
454 | m_actionFormLayout = new QAction(formIcon, tr(s: "Lay Out in a &Form Layout" ), this); |
455 | m_actionFormLayout->setObjectName(QStringLiteral("__qt_form_layout_action" )); |
456 | m_actionFormLayout->setShortcut(Qt::CTRL | Qt::Key_6); |
457 | m_actionFormLayout->setStatusTip(tr(s: "Lays out the selected widgets in a form layout" )); |
458 | m_actionFormLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out in a Form" ))); |
459 | m_actionFormLayout->setData(LayoutInfo::Form); |
460 | m_actionFormLayout->setEnabled(false); |
461 | connect(sender: m_actionFormLayout, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::createLayout); |
462 | |
463 | m_actionGridLayout = new QAction(createIconSet(QStringLiteral("editgrid.png" )), tr(s: "Lay Out in a &Grid" ), this); |
464 | m_actionGridLayout->setObjectName(QStringLiteral("__qt_grid_layout_action" )); |
465 | m_actionGridLayout->setShortcut(Qt::CTRL | Qt::Key_5); |
466 | m_actionGridLayout->setStatusTip(tr(s: "Lays out the selected widgets in a grid" )); |
467 | m_actionGridLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out in a Grid" ))); |
468 | m_actionGridLayout->setData(LayoutInfo::Grid); |
469 | m_actionGridLayout->setEnabled(false); |
470 | connect(sender: m_actionGridLayout, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::createLayout); |
471 | |
472 | m_actionSplitHorizontal = new QAction(createIconSet(QStringLiteral("edithlayoutsplit.png" )), |
473 | tr(s: "Lay Out Horizontally in S&plitter" ), this); |
474 | m_actionSplitHorizontal->setObjectName(QStringLiteral("__qt_split_horizontal_action" )); |
475 | m_actionSplitHorizontal->setShortcut(Qt::CTRL | Qt::Key_3); |
476 | m_actionSplitHorizontal->setStatusTip(tr(s: "Lays out the selected widgets horizontally in a splitter" )); |
477 | m_actionSplitHorizontal->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Horizontally in Splitter" ))); |
478 | m_actionSplitHorizontal->setData(LayoutInfo::HSplitter); |
479 | m_actionSplitHorizontal->setEnabled(false); |
480 | connect(sender: m_actionSplitHorizontal, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::createLayout); |
481 | |
482 | m_actionSplitVertical = new QAction(createIconSet(QStringLiteral("editvlayoutsplit.png" )), |
483 | tr(s: "Lay Out Vertically in Sp&litter" ), this); |
484 | m_actionSplitVertical->setObjectName(QStringLiteral("__qt_split_vertical_action" )); |
485 | m_actionSplitVertical->setShortcut(Qt::CTRL | Qt::Key_4); |
486 | m_actionSplitVertical->setStatusTip(tr(s: "Lays out the selected widgets vertically in a splitter" )); |
487 | m_actionSplitVertical->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Vertically in Splitter" ))); |
488 | connect(sender: m_actionSplitVertical, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::createLayout); |
489 | m_actionSplitVertical->setData(LayoutInfo::VSplitter); |
490 | |
491 | m_actionSplitVertical->setEnabled(false); |
492 | |
493 | m_actionBreakLayout = new QAction(createIconSet(QStringLiteral("editbreaklayout.png" )), tr(s: "&Break Layout" ), this); |
494 | m_actionBreakLayout->setObjectName(QStringLiteral("__qt_break_layout_action" )); |
495 | m_actionBreakLayout->setShortcut(Qt::CTRL | Qt::Key_0); |
496 | m_actionBreakLayout->setStatusTip(tr(s: "Breaks the selected layout" )); |
497 | m_actionBreakLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Break Layout" ))); |
498 | connect(sender: m_actionBreakLayout, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionBreakLayoutActivated); |
499 | m_actionBreakLayout->setEnabled(false); |
500 | |
501 | m_actionSimplifyLayout = new QAction(tr(s: "Si&mplify Grid Layout" ), this); |
502 | m_actionSimplifyLayout->setObjectName(QStringLiteral("__qt_simplify_layout_action" )); |
503 | m_actionSimplifyLayout->setStatusTip(tr(s: "Removes empty columns and rows" )); |
504 | m_actionSimplifyLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Simplify Layout" ))); |
505 | connect(sender: m_actionSimplifyLayout, signal: &QAction::triggered, receiver: this, slot: &FormWindowManager::slotActionSimplifyLayoutActivated); |
506 | m_actionSimplifyLayout->setEnabled(false); |
507 | |
508 | m_actionDefaultPreview = new QAction(tr(s: "&Preview..." ), this); |
509 | m_actionDefaultPreview->setObjectName(QStringLiteral("__qt_default_preview_action" )); |
510 | m_actionDefaultPreview->setStatusTip(tr(s: "Preview current form" )); |
511 | m_actionDefaultPreview->setWhatsThis(whatsThisFrom(QStringLiteral("Form|Preview" ))); |
512 | connect(sender: m_actionDefaultPreview, signal: &QAction::triggered, |
513 | receiver: this, slot: &FormWindowManager::showPreview); |
514 | |
515 | m_undoGroup = new QUndoGroup(this); |
516 | |
517 | m_actionUndo = m_undoGroup->createUndoAction(parent: this); |
518 | m_actionUndo->setEnabled(false); |
519 | |
520 | m_actionUndo->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo" ), fallback: createIconSet(QStringLiteral("undo.png" )))); |
521 | m_actionRedo = m_undoGroup->createRedoAction(parent: this); |
522 | m_actionRedo->setEnabled(false); |
523 | m_actionRedo->setIcon(QIcon::fromTheme(QStringLiteral("edit-redo" ), fallback: createIconSet(QStringLiteral("redo.png" )))); |
524 | |
525 | m_actionShowFormWindowSettingsDialog = new QAction(tr(s: "Form &Settings..." ), this); |
526 | m_actionShowFormWindowSettingsDialog->setObjectName(QStringLiteral("__qt_form_settings_action" )); |
527 | connect(sender: m_actionShowFormWindowSettingsDialog, signal: &QAction::triggered, |
528 | receiver: this, slot: &FormWindowManager::slotActionShowFormWindowSettingsDialog); |
529 | m_actionShowFormWindowSettingsDialog->setEnabled(false); |
530 | } |
531 | |
532 | #if QT_CONFIG(clipboard) |
533 | void FormWindowManager::slotActionCutActivated() |
534 | { |
535 | m_activeFormWindow->cut(); |
536 | } |
537 | |
538 | void FormWindowManager::slotActionCopyActivated() |
539 | { |
540 | m_activeFormWindow->copy(); |
541 | slotUpdateActions(); |
542 | } |
543 | |
544 | void FormWindowManager::slotActionPasteActivated() |
545 | { |
546 | m_activeFormWindow->paste(); |
547 | } |
548 | #endif |
549 | |
550 | void FormWindowManager::slotActionDeleteActivated() |
551 | { |
552 | m_activeFormWindow->deleteWidgets(); |
553 | } |
554 | |
555 | void FormWindowManager::slotActionLowerActivated() |
556 | { |
557 | m_activeFormWindow->lowerWidgets(); |
558 | } |
559 | |
560 | void FormWindowManager::slotActionRaiseActivated() |
561 | { |
562 | m_activeFormWindow->raiseWidgets(); |
563 | } |
564 | |
565 | static inline QWidget *findLayoutContainer(const FormWindow *fw) |
566 | { |
567 | QWidgetList l(fw->selectedWidgets()); |
568 | fw->simplifySelection(sel: &l); |
569 | return l.isEmpty() ? fw->mainContainer() : l.constFirst(); |
570 | } |
571 | |
572 | void FormWindowManager::createLayout() |
573 | { |
574 | QAction *a = qobject_cast<QAction *>(object: sender()); |
575 | if (!a) |
576 | return; |
577 | const int type = a->data().toInt(); |
578 | switch (m_createLayoutContext) { |
579 | case LayoutContainer: |
580 | // Cannot create a splitter on a container |
581 | if (type != LayoutInfo::HSplitter && type != LayoutInfo::VSplitter) |
582 | m_activeFormWindow->createLayout(type, container: findLayoutContainer(fw: m_activeFormWindow)); |
583 | break; |
584 | case LayoutSelection: |
585 | m_activeFormWindow->createLayout(type); |
586 | break; |
587 | case MorphLayout: |
588 | m_activeFormWindow->morphLayout(container: m_morphLayoutContainer, newType: type); |
589 | break; |
590 | } |
591 | } |
592 | |
593 | void FormWindowManager::slotActionBreakLayoutActivated() |
594 | { |
595 | const QWidgetList layouts = layoutsToBeBroken(); |
596 | if (layouts.isEmpty()) |
597 | return; |
598 | |
599 | if (debugFWM) { |
600 | qDebug() << "slotActionBreakLayoutActivated: " << layouts.size(); |
601 | for (const QWidget *w : layouts) |
602 | qDebug() << w; |
603 | } |
604 | |
605 | m_activeFormWindow->beginCommand(description: tr(s: "Break Layout" )); |
606 | for (QWidget *layout : layouts) |
607 | m_activeFormWindow->breakLayout(w: layout); |
608 | m_activeFormWindow->endCommand(); |
609 | } |
610 | |
611 | void FormWindowManager::slotActionSimplifyLayoutActivated() |
612 | { |
613 | Q_ASSERT(m_activeFormWindow != nullptr); |
614 | QWidgetList selectedWidgets = m_activeFormWindow->selectedWidgets(); |
615 | m_activeFormWindow->simplifySelection(sel: &selectedWidgets); |
616 | if (selectedWidgets.size() != 1) |
617 | return; |
618 | SimplifyLayoutCommand *cmd = new SimplifyLayoutCommand(m_activeFormWindow); |
619 | if (cmd->init(layoutBase: selectedWidgets.constFirst())) { |
620 | m_activeFormWindow->commandHistory()->push(cmd); |
621 | } else { |
622 | delete cmd; |
623 | } |
624 | } |
625 | |
626 | void FormWindowManager::slotActionAdjustSizeActivated() |
627 | { |
628 | Q_ASSERT(m_activeFormWindow != nullptr); |
629 | |
630 | m_activeFormWindow->beginCommand(description: tr(s: "Adjust Size" )); |
631 | |
632 | QWidgetList selectedWidgets = m_activeFormWindow->selectedWidgets(); |
633 | m_activeFormWindow->simplifySelection(sel: &selectedWidgets); |
634 | |
635 | if (selectedWidgets.isEmpty()) { |
636 | Q_ASSERT(m_activeFormWindow->mainContainer() != nullptr); |
637 | selectedWidgets.append(t: m_activeFormWindow->mainContainer()); |
638 | } |
639 | |
640 | // Always count the main container as unlaid-out |
641 | for (QWidget *widget : qAsConst(t&: selectedWidgets)) { |
642 | bool unlaidout = LayoutInfo::layoutType(core: core(), w: widget->parentWidget()) == LayoutInfo::NoLayout; |
643 | bool isMainContainer = m_activeFormWindow->isMainContainer(w: widget); |
644 | |
645 | if (unlaidout || isMainContainer) { |
646 | AdjustWidgetSizeCommand *cmd = new AdjustWidgetSizeCommand(m_activeFormWindow); |
647 | cmd->init(widget); |
648 | m_activeFormWindow->commandHistory()->push(cmd); |
649 | } |
650 | } |
651 | |
652 | m_activeFormWindow->endCommand(); |
653 | } |
654 | |
655 | void FormWindowManager::slotActionSelectAllActivated() |
656 | { |
657 | m_activeFormWindow->selectAll(); |
658 | } |
659 | |
660 | void FormWindowManager::showPreview() |
661 | { |
662 | slotActionGroupPreviewInStyle(style: QString(), deviceProfileIndex: -1); |
663 | } |
664 | |
665 | void FormWindowManager::slotActionGroupPreviewInStyle(const QString &style, int deviceProfileIndex) |
666 | { |
667 | QDesignerFormWindowInterface *fw = activeFormWindow(); |
668 | if (!fw) |
669 | return; |
670 | |
671 | QString errorMessage; |
672 | if (!m_previewManager->showPreview(fw, style, deviceProfileIndex, errorMessage: &errorMessage)) { |
673 | const QString title = tr(s: "Could not create form preview" , c: "Title of warning message box" ); |
674 | core()->dialogGui()->message(parent: fw, context: QDesignerDialogGuiInterface::FormEditorMessage, icon: QMessageBox::Warning, |
675 | title, text: errorMessage); |
676 | } |
677 | } |
678 | |
679 | // The user might click on a layout child or the actual layout container. |
680 | QWidgetList FormWindowManager::layoutsToBeBroken(QWidget *w) const |
681 | { |
682 | if (!w) |
683 | return QWidgetList(); |
684 | |
685 | if (debugFWM) |
686 | qDebug() << "layoutsToBeBroken: " << w; |
687 | |
688 | QWidget *parent = w->parentWidget(); |
689 | if (m_activeFormWindow->isMainContainer(w)) |
690 | parent = nullptr; |
691 | |
692 | QWidget *widget = core()->widgetFactory()->containerOfWidget(w); |
693 | |
694 | // maybe we want to remove following block |
695 | const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); |
696 | const QDesignerWidgetDataBaseItemInterface *item = db->item(index: db->indexOfObject(object: widget)); |
697 | if (!item) { |
698 | if (debugFWM) |
699 | qDebug() << "layoutsToBeBroken: Don't have an item, recursing for parent" ; |
700 | return layoutsToBeBroken(w: parent); |
701 | } |
702 | |
703 | const bool layoutContainer = (item->isContainer() || m_activeFormWindow->isMainContainer(w: widget)); |
704 | |
705 | if (!layoutContainer) { |
706 | if (debugFWM) |
707 | qDebug() << "layoutsToBeBroken: Not a container, recursing for parent" ; |
708 | return layoutsToBeBroken(w: parent); |
709 | } |
710 | |
711 | QLayout *widgetLayout = widget->layout(); |
712 | QLayout *managedLayout = LayoutInfo::managedLayout(core: m_core, layout: widgetLayout); |
713 | if (!managedLayout) { |
714 | if (qobject_cast<const QSplitter *>(object: widget)) { |
715 | if (debugFWM) |
716 | qDebug() << "layoutsToBeBroken: Splitter special" ; |
717 | QWidgetList list = layoutsToBeBroken(w: parent); |
718 | list.append(t: widget); |
719 | return list; |
720 | } |
721 | if (debugFWM) |
722 | qDebug() << "layoutsToBeBroken: Is a container but doesn't have a managed layout (has an internal layout), returning 0" ; |
723 | return QWidgetList(); |
724 | } |
725 | |
726 | if (managedLayout) { |
727 | QWidgetList list; |
728 | if (debugFWM) |
729 | qDebug() << "layoutsToBeBroken: Is a container and has a layout" ; |
730 | if (qobject_cast<const QLayoutWidget *>(object: widget)) { |
731 | if (debugFWM) |
732 | qDebug() << "layoutsToBeBroken: red layout special case" ; |
733 | list = layoutsToBeBroken(w: parent); |
734 | } |
735 | list.append(t: widget); |
736 | return list; |
737 | } |
738 | if (debugFWM) |
739 | qDebug() << "layoutsToBeBroken: Is a container but doesn't have a layout at all, returning 0" ; |
740 | return QWidgetList(); |
741 | |
742 | } |
743 | |
744 | QSet<QWidget *> FormWindowManager::getUnsortedLayoutsToBeBroken(bool firstOnly) const |
745 | { |
746 | // Return a set of layouts to be broken. |
747 | QSet<QWidget *> layouts; |
748 | |
749 | QWidgetList selection = m_activeFormWindow->selectedWidgets(); |
750 | if (selection.isEmpty() && m_activeFormWindow->mainContainer()) |
751 | selection.append(t: m_activeFormWindow->mainContainer()); |
752 | |
753 | for (QWidget *selectedWidget : qAsConst(t&: selection)) { |
754 | // find all layouts |
755 | const QWidgetList &list = layoutsToBeBroken(w: selectedWidget); |
756 | if (!list.isEmpty()) { |
757 | for (QWidget *widget : list) |
758 | layouts.insert(value: widget); |
759 | if (firstOnly) |
760 | return layouts; |
761 | } |
762 | } |
763 | return layouts; |
764 | } |
765 | |
766 | bool FormWindowManager::hasLayoutsToBeBroken() const |
767 | { |
768 | // Quick check for layouts to be broken |
769 | return !getUnsortedLayoutsToBeBroken(firstOnly: true).isEmpty(); |
770 | } |
771 | |
772 | QWidgetList FormWindowManager::layoutsToBeBroken() const |
773 | { |
774 | // Get all layouts. This is a list of all 'red' layouts (QLayoutWidgets) |
775 | // up to the first 'real' widget with a layout in hierarchy order. |
776 | const QSet<QWidget *> unsortedLayouts = getUnsortedLayoutsToBeBroken(firstOnly: false); |
777 | // Sort in order of hierarchy |
778 | QWidgetList orderedLayoutList; |
779 | for (QWidget *wToBeInserted : unsortedLayouts) { |
780 | if (!orderedLayoutList.contains(t: wToBeInserted)) { |
781 | // try to find first child, use as insertion position, else append |
782 | const QWidgetList::iterator firstChildPos = findFirstChildOf(it: orderedLayoutList.begin(), end: orderedLayoutList.end(), w: wToBeInserted); |
783 | if (firstChildPos == orderedLayoutList.end()) { |
784 | orderedLayoutList.push_back(t: wToBeInserted); |
785 | } else { |
786 | orderedLayoutList.insert(before: firstChildPos, t: wToBeInserted); |
787 | } |
788 | } |
789 | } |
790 | return orderedLayoutList; |
791 | } |
792 | |
793 | static inline bool hasManagedLayoutItems(const QDesignerFormEditorInterface *core, QWidget *w) |
794 | { |
795 | if (const QLayout *ml = LayoutInfo::managedLayout(core, widget: w)) { |
796 | // Try to find managed items, ignore dummy grid spacers |
797 | const int count = ml->count(); |
798 | for (int i = 0; i < count; i++) |
799 | if (!LayoutInfo::isEmptyItem(item: ml->itemAt(index: i))) |
800 | return true; |
801 | } |
802 | return false; |
803 | } |
804 | |
805 | void FormWindowManager::slotUpdateActions() |
806 | { |
807 | m_createLayoutContext = LayoutSelection; |
808 | m_morphLayoutContainer = nullptr; |
809 | bool canMorphIntoVBoxLayout = false; |
810 | bool canMorphIntoHBoxLayout = false; |
811 | bool canMorphIntoGridLayout = false; |
812 | bool canMorphIntoFormLayout = false; |
813 | int selectedWidgetCount = 0; |
814 | int laidoutWidgetCount = 0; |
815 | int unlaidoutWidgetCount = 0; |
816 | #if QT_CONFIG(clipboard) |
817 | bool pasteAvailable = false; |
818 | #endif |
819 | bool layoutAvailable = false; |
820 | bool breakAvailable = false; |
821 | bool simplifyAvailable = false; |
822 | bool layoutContainer = false; |
823 | bool canChangeZOrder = true; |
824 | |
825 | do { |
826 | if (m_activeFormWindow == nullptr || m_activeFormWindow->currentTool() != 0) |
827 | break; |
828 | |
829 | breakAvailable = hasLayoutsToBeBroken(); |
830 | |
831 | QWidgetList simplifiedSelection = m_activeFormWindow->selectedWidgets(); |
832 | |
833 | selectedWidgetCount = simplifiedSelection.count(); |
834 | #if QT_CONFIG(clipboard) |
835 | pasteAvailable = qApp->clipboard()->mimeData() && qApp->clipboard()->mimeData()->hasText(); |
836 | #endif |
837 | |
838 | m_activeFormWindow->simplifySelection(sel: &simplifiedSelection); |
839 | QWidget *mainContainer = m_activeFormWindow->mainContainer(); |
840 | if (simplifiedSelection.isEmpty() && mainContainer) |
841 | simplifiedSelection.append(t: mainContainer); |
842 | |
843 | // Always count the main container as unlaid-out |
844 | const QWidgetList::const_iterator cend = simplifiedSelection.constEnd(); |
845 | for (QWidgetList::const_iterator it = simplifiedSelection.constBegin(); it != cend; ++it) { |
846 | if (*it != mainContainer && LayoutInfo::isWidgetLaidout(core: m_core, widget: *it)) { |
847 | ++laidoutWidgetCount; |
848 | } else { |
849 | ++unlaidoutWidgetCount; |
850 | } |
851 | if (qobject_cast<const QLayoutWidget *>(object: *it) || qobject_cast<const Spacer *>(object: *it)) |
852 | canChangeZOrder = false; |
853 | } |
854 | |
855 | // Figure out layouts: Looking at a group of dangling widgets |
856 | if (simplifiedSelection.count() != 1) { |
857 | layoutAvailable = unlaidoutWidgetCount > 1; |
858 | //breakAvailable = false; |
859 | break; |
860 | } |
861 | // Manipulate layout of a single widget |
862 | m_createLayoutContext = LayoutSelection; |
863 | QWidget *widget = core()->widgetFactory()->containerOfWidget(w: simplifiedSelection.first()); |
864 | if (widget == nullptr) // We are looking at a page-based container with 0 pages |
865 | break; |
866 | |
867 | const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); |
868 | const QDesignerWidgetDataBaseItemInterface *item = db->item(index: db->indexOfObject(object: widget)); |
869 | if (!item) |
870 | break; |
871 | |
872 | QLayout *widgetLayout = LayoutInfo::internalLayout(widget); |
873 | QLayout *managedLayout = LayoutInfo::managedLayout(core: m_core, layout: widgetLayout); |
874 | // We don't touch a layout created by a custom widget |
875 | if (widgetLayout && !managedLayout) |
876 | break; |
877 | |
878 | layoutContainer = (item->isContainer() || m_activeFormWindow->isMainContainer(w: widget)); |
879 | |
880 | layoutAvailable = layoutContainer && m_activeFormWindow->hasInsertedChildren(w: widget) && managedLayout == nullptr; |
881 | simplifyAvailable = SimplifyLayoutCommand::canSimplify(core: m_core, w: widget); |
882 | if (layoutAvailable) { |
883 | m_createLayoutContext = LayoutContainer; |
884 | } else { |
885 | /* Cannot create a layout, have some layouts to be broken and |
886 | * exactly one, non-empty layout with selected: check the morph layout options |
887 | * (Note that there might be > 1 layouts to broken if the selection |
888 | * is a red layout, however, we want the inner-most layout here). */ |
889 | if (breakAvailable && simplifiedSelection.size() == 1 |
890 | && hasManagedLayoutItems(core: m_core, w: widget)) { |
891 | int type; |
892 | m_morphLayoutContainer = widget; // Was: page of first selected |
893 | m_createLayoutContext = MorphLayout; |
894 | if (MorphLayoutCommand::canMorph(formWindow: m_activeFormWindow, w: m_morphLayoutContainer, ptrToCurrentType: &type)) { |
895 | canMorphIntoVBoxLayout = type != LayoutInfo::VBox; |
896 | canMorphIntoHBoxLayout = type != LayoutInfo::HBox; |
897 | canMorphIntoGridLayout = type != LayoutInfo::Grid; |
898 | canMorphIntoFormLayout = type != LayoutInfo::Form; |
899 | } |
900 | } |
901 | } |
902 | } while(false); |
903 | |
904 | #if QT_CONFIG(clipboard) |
905 | m_actionCut->setEnabled(selectedWidgetCount > 0); |
906 | m_actionCopy->setEnabled(selectedWidgetCount > 0); |
907 | m_actionPaste->setEnabled(pasteAvailable); |
908 | #endif |
909 | m_actionDelete->setEnabled(selectedWidgetCount > 0); |
910 | m_actionLower->setEnabled(canChangeZOrder && selectedWidgetCount > 0); |
911 | m_actionRaise->setEnabled(canChangeZOrder && selectedWidgetCount > 0); |
912 | |
913 | |
914 | m_actionSelectAll->setEnabled(m_activeFormWindow != nullptr); |
915 | |
916 | m_actionAdjustSize->setEnabled(unlaidoutWidgetCount > 0); |
917 | |
918 | m_actionHorizontalLayout->setEnabled(layoutAvailable || canMorphIntoHBoxLayout); |
919 | m_actionVerticalLayout->setEnabled(layoutAvailable || canMorphIntoVBoxLayout); |
920 | m_actionSplitHorizontal->setEnabled(layoutAvailable && !layoutContainer); |
921 | m_actionSplitVertical->setEnabled(layoutAvailable && !layoutContainer); |
922 | m_actionFormLayout->setEnabled(layoutAvailable || canMorphIntoFormLayout); |
923 | m_actionGridLayout->setEnabled(layoutAvailable || canMorphIntoGridLayout); |
924 | |
925 | m_actionBreakLayout->setEnabled(breakAvailable); |
926 | m_actionSimplifyLayout->setEnabled(simplifyAvailable); |
927 | m_actionShowFormWindowSettingsDialog->setEnabled(m_activeFormWindow != nullptr); |
928 | } |
929 | |
930 | QDesignerFormWindowInterface *FormWindowManager::createFormWindow(QWidget *parentWidget, Qt::WindowFlags flags) |
931 | { |
932 | FormWindow *formWindow = new FormWindow(qobject_cast<FormEditor*>(object: core()), parentWidget, flags); |
933 | formWindow->setProperty(name: WidgetFactory::disableStyleCustomPaintingPropertyC, value: QVariant(true)); |
934 | addFormWindow(w: formWindow); |
935 | return formWindow; |
936 | } |
937 | |
938 | QPixmap FormWindowManager::createPreviewPixmap() const |
939 | { |
940 | const QDesignerFormWindowInterface *fw = activeFormWindow(); |
941 | if (!fw) |
942 | return QPixmap(); |
943 | QString errorMessage; |
944 | const QPixmap pix = m_previewManager->createPreviewPixmap(fw, style: QString(), errorMessage: &errorMessage); |
945 | if (pix.isNull() && !errorMessage.isEmpty()) |
946 | qWarning(msg: "Preview pixmap creation failed: %s" , qPrintable(errorMessage)); |
947 | return pix; |
948 | } |
949 | |
950 | void FormWindowManager::deviceProfilesChanged() |
951 | { |
952 | if (m_actionGroupPreviewInStyle) |
953 | m_actionGroupPreviewInStyle->updateDeviceProfiles(); |
954 | } |
955 | |
956 | // DnD stuff |
957 | |
958 | void FormWindowManager::dragItems(const QList<QDesignerDnDItemInterface*> &item_list) |
959 | { |
960 | QDesignerMimeData::execDrag(items: item_list, dragSource: m_core->topLevel()); |
961 | } |
962 | |
963 | QUndoGroup *FormWindowManager::undoGroup() const |
964 | { |
965 | return m_undoGroup; |
966 | } |
967 | |
968 | void FormWindowManager::slotActionShowFormWindowSettingsDialog() |
969 | { |
970 | QDesignerFormWindowInterface *fw = activeFormWindow(); |
971 | if (!fw) |
972 | return; |
973 | |
974 | QDialog *settingsDialog = nullptr; |
975 | const bool wasDirty = fw->isDirty(); |
976 | |
977 | // Ask the language extension for a dialog. If not, create our own |
978 | if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*>(manager: m_core->extensionManager(), object: m_core)) |
979 | settingsDialog = lang->createFormWindowSettingsDialog(formWindow: fw, /*parent=*/ parentWidget: nullptr); |
980 | |
981 | if (!settingsDialog) |
982 | settingsDialog = new FormWindowSettings(fw); |
983 | |
984 | QString title = QFileInfo(fw->fileName()).fileName(); |
985 | if (title.isEmpty()) // Grab the title from the outer window if no filename |
986 | if (const QWidget *window = m_core->integration()->containerWindow(widget: fw)) |
987 | title = window->windowTitle(); |
988 | |
989 | settingsDialog->setWindowTitle(tr(s: "Form Settings - %1" ).arg(a: title)); |
990 | if (settingsDialog->exec()) |
991 | if (fw->isDirty() != wasDirty) |
992 | emit formWindowSettingsChanged(fw); |
993 | |
994 | delete settingsDialog; |
995 | } |
996 | |
997 | QAction *FormWindowManager::action(Action action) const |
998 | { |
999 | switch (action) { |
1000 | #if QT_CONFIG(clipboard) |
1001 | case QDesignerFormWindowManagerInterface::CutAction: |
1002 | return m_actionCut; |
1003 | case QDesignerFormWindowManagerInterface::CopyAction: |
1004 | return m_actionCopy; |
1005 | case QDesignerFormWindowManagerInterface::PasteAction: |
1006 | return m_actionPaste; |
1007 | #endif |
1008 | case QDesignerFormWindowManagerInterface::DeleteAction: |
1009 | return m_actionDelete; |
1010 | case QDesignerFormWindowManagerInterface::SelectAllAction: |
1011 | return m_actionSelectAll; |
1012 | case QDesignerFormWindowManagerInterface::LowerAction: |
1013 | return m_actionLower; |
1014 | case QDesignerFormWindowManagerInterface::RaiseAction: |
1015 | return m_actionRaise; |
1016 | case QDesignerFormWindowManagerInterface::UndoAction: |
1017 | return m_actionUndo; |
1018 | case QDesignerFormWindowManagerInterface::RedoAction: |
1019 | return m_actionRedo; |
1020 | case QDesignerFormWindowManagerInterface::HorizontalLayoutAction: |
1021 | return m_actionHorizontalLayout; |
1022 | case QDesignerFormWindowManagerInterface::VerticalLayoutAction: |
1023 | return m_actionVerticalLayout; |
1024 | case QDesignerFormWindowManagerInterface::SplitHorizontalAction: |
1025 | return m_actionSplitHorizontal; |
1026 | case QDesignerFormWindowManagerInterface::SplitVerticalAction: |
1027 | return m_actionSplitVertical; |
1028 | case QDesignerFormWindowManagerInterface::GridLayoutAction: |
1029 | return m_actionGridLayout; |
1030 | case QDesignerFormWindowManagerInterface::FormLayoutAction: |
1031 | return m_actionFormLayout; |
1032 | case QDesignerFormWindowManagerInterface::BreakLayoutAction: |
1033 | return m_actionBreakLayout; |
1034 | case QDesignerFormWindowManagerInterface::AdjustSizeAction: |
1035 | return m_actionAdjustSize; |
1036 | case QDesignerFormWindowManagerInterface::SimplifyLayoutAction: |
1037 | return m_actionSimplifyLayout; |
1038 | case QDesignerFormWindowManagerInterface::DefaultPreviewAction: |
1039 | return m_actionDefaultPreview; |
1040 | case QDesignerFormWindowManagerInterface::FormWindowSettingsDialogAction: |
1041 | return m_actionShowFormWindowSettingsDialog; |
1042 | } |
1043 | qWarning(msg: "FormWindowManager::action: Unhanded enumeration value %d" , action); |
1044 | return nullptr; |
1045 | } |
1046 | |
1047 | QActionGroup *FormWindowManager::actionGroup(ActionGroup actionGroup) const |
1048 | { |
1049 | switch (actionGroup) { |
1050 | case QDesignerFormWindowManagerInterface::StyledPreviewActionGroup: |
1051 | if (m_actionGroupPreviewInStyle == nullptr) { |
1052 | // Wish we could make the 'this' pointer mutable ;-) |
1053 | QObject *parent = const_cast<FormWindowManager*>(this); |
1054 | m_actionGroupPreviewInStyle = new PreviewActionGroup(m_core, parent); |
1055 | connect(sender: m_actionGroupPreviewInStyle, signal: &PreviewActionGroup::preview, |
1056 | receiver: this, slot: &FormWindowManager::slotActionGroupPreviewInStyle); |
1057 | } |
1058 | return m_actionGroupPreviewInStyle; |
1059 | } |
1060 | qWarning(msg: "FormWindowManager::actionGroup: Unhanded enumeration value %d" , actionGroup); |
1061 | return nullptr; |
1062 | } |
1063 | |
1064 | } |
1065 | |
1066 | QT_END_NAMESPACE |
1067 | |