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