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_workbench.h" |
30 | #include "qdesigner.h" |
31 | #include "qdesigner_actions.h" |
32 | #include "qdesigner_appearanceoptions.h" |
33 | #include "qdesigner_settings.h" |
34 | #include "qdesigner_toolwindow.h" |
35 | #include "qdesigner_formwindow.h" |
36 | #include "appfontdialog.h" |
37 | |
38 | #include <QtDesigner/abstractformeditor.h> |
39 | #include <QtDesigner/abstractformwindow.h> |
40 | #include <QtDesigner/abstractformwindowmanager.h> |
41 | #include <QtDesigner/abstractformeditorplugin.h> |
42 | #include <QtDesigner/abstractwidgetbox.h> |
43 | #include <QtDesigner/abstractmetadatabase.h> |
44 | |
45 | #include <QtDesigner/QDesignerComponents> |
46 | #include <QtDesigner/abstractintegration.h> |
47 | #include <QtDesigner/private/pluginmanager_p.h> |
48 | #include <QtDesigner/private/formwindowbase_p.h> |
49 | #include <QtDesigner/private/actioneditor_p.h> |
50 | |
51 | #include <QtCore/qdir.h> |
52 | #include <QtCore/qfile.h> |
53 | #include <QtCore/qurl.h> |
54 | #include <QtCore/qtimer.h> |
55 | #include <QtCore/qpluginloader.h> |
56 | #include <QtCore/qdebug.h> |
57 | |
58 | #include <QtWidgets/qactiongroup.h> |
59 | #include <QtGui/qevent.h> |
60 | #include <QtGui/qscreen.h> |
61 | #include <QtWidgets/qdockwidget.h> |
62 | #include <QtWidgets/qmenu.h> |
63 | #include <QtWidgets/qmenubar.h> |
64 | #include <QtWidgets/qmessagebox.h> |
65 | #include <QtWidgets/qpushbutton.h> |
66 | #include <QtWidgets/qtoolbar.h> |
67 | #include <QtWidgets/qmdiarea.h> |
68 | #include <QtWidgets/qmdisubwindow.h> |
69 | #include <QtWidgets/qlayout.h> |
70 | |
71 | QT_BEGIN_NAMESPACE |
72 | |
73 | static const char *appFontPrefixC = "AppFonts" ; |
74 | |
75 | using ActionList = QList<QAction *>; |
76 | |
77 | static QMdiSubWindow *mdiSubWindowOf(const QWidget *w) |
78 | { |
79 | QMdiSubWindow *rc = qobject_cast<QMdiSubWindow *>(object: w->parentWidget()); |
80 | Q_ASSERT(rc); |
81 | return rc; |
82 | } |
83 | |
84 | static QDockWidget *dockWidgetOf(const QWidget *w) |
85 | { |
86 | for (QWidget *parentWidget = w->parentWidget(); parentWidget ; parentWidget = parentWidget->parentWidget()) { |
87 | if (QDockWidget *dw = qobject_cast<QDockWidget *>(object: parentWidget)) { |
88 | return dw; |
89 | } |
90 | } |
91 | Q_ASSERT("Dock widget not found" ); |
92 | return nullptr; |
93 | } |
94 | |
95 | // ------------ QDesignerWorkbench::Position |
96 | QDesignerWorkbench::Position::Position(const QMdiSubWindow *mdiSubWindow, const QPoint &mdiAreaOffset) : |
97 | m_minimized(mdiSubWindow->isShaded()), |
98 | m_position(mdiSubWindow->pos() + mdiAreaOffset) |
99 | { |
100 | } |
101 | |
102 | QDesignerWorkbench::Position::Position(const QDockWidget *dockWidget) : |
103 | m_minimized(dockWidget->isMinimized()), |
104 | m_position(dockWidget->pos()) |
105 | { |
106 | } |
107 | |
108 | QDesignerWorkbench::Position::Position(const QWidget *topLevelWindow, const QPoint &desktopTopLeft) |
109 | { |
110 | const QWidget *window =topLevelWindow->window (); |
111 | Q_ASSERT(window); |
112 | m_minimized = window->isMinimized(); |
113 | m_position = window->pos() - desktopTopLeft; |
114 | } |
115 | |
116 | void QDesignerWorkbench::Position::applyTo(QMdiSubWindow *mdiSubWindow, |
117 | const QPoint &mdiAreaOffset) const |
118 | { |
119 | // QMdiSubWindow attempts to resize its children to sizeHint() when switching user interface modes. |
120 | // Restore old size |
121 | const QPoint mdiAreaPos = QPoint(qMax(a: 0, b: m_position.x() - mdiAreaOffset.x()), |
122 | qMax(a: 0, b: m_position.y() - mdiAreaOffset.y())); |
123 | mdiSubWindow->move(mdiAreaPos); |
124 | const QSize decorationSize = mdiSubWindow->size() - mdiSubWindow->contentsRect().size(); |
125 | mdiSubWindow->resize(mdiSubWindow->widget()->size() + decorationSize); |
126 | mdiSubWindow->show(); |
127 | if (m_minimized) { |
128 | mdiSubWindow->showShaded(); |
129 | } |
130 | } |
131 | |
132 | void QDesignerWorkbench::Position::applyTo(QWidget *topLevelWindow, const QPoint &desktopTopLeft) const |
133 | { |
134 | QWidget *window = topLevelWindow->window (); |
135 | const QPoint newPos = m_position + desktopTopLeft; |
136 | window->move(newPos); |
137 | if ( m_minimized) { |
138 | topLevelWindow->showMinimized(); |
139 | } else { |
140 | topLevelWindow->show(); |
141 | } |
142 | } |
143 | |
144 | void QDesignerWorkbench::Position::applyTo(QDockWidget *dockWidget) const |
145 | { |
146 | dockWidget->widget()->setVisible(true); |
147 | dockWidget->setVisible(!m_minimized); |
148 | } |
149 | |
150 | static inline void (QMenu *m, const ActionList &al) |
151 | { |
152 | const ActionList::const_iterator cend = al.constEnd(); |
153 | for (ActionList::const_iterator it = al.constBegin(); it != cend; ++it) |
154 | m->addAction(action: *it); |
155 | } |
156 | |
157 | static inline QMenu *(QMenuBar *mb, const QString &title, const ActionList &al) |
158 | { |
159 | QMenu *rc = mb->addMenu(title); |
160 | addActionsToMenu(m: rc, al); |
161 | return rc; |
162 | } |
163 | |
164 | // -------- QDesignerWorkbench |
165 | |
166 | QDesignerWorkbench::QDesignerWorkbench() : |
167 | m_core(QDesignerComponents::createFormEditor(parent: this)), |
168 | m_windowActions(new QActionGroup(this)), |
169 | m_globalMenuBar(new QMenuBar) |
170 | { |
171 | QDesignerSettings settings(m_core); |
172 | |
173 | (void) QDesignerComponents::createTaskMenu(core: core(), parent: this); |
174 | |
175 | initializeCorePlugins(); |
176 | QDesignerComponents::initializePlugins(core: core()); |
177 | m_actionManager = new QDesignerActions(this); // accesses plugin components |
178 | |
179 | m_windowActions->setExclusive(true); |
180 | connect(sender: m_windowActions, signal: &QActionGroup::triggered, |
181 | receiver: this, slot: &QDesignerWorkbench::formWindowActionTriggered); |
182 | |
183 | // Build main menu bar |
184 | addMenu(mb: m_globalMenuBar, title: tr(s: "&File" ), al: m_actionManager->fileActions()->actions()); |
185 | |
186 | QMenu * = addMenu(mb: m_globalMenuBar, title: tr(s: "&Edit" ), al: m_actionManager->editActions()->actions()); |
187 | editMenu->addSeparator(); |
188 | addActionsToMenu(m: editMenu, al: m_actionManager->toolActions()->actions()); |
189 | |
190 | QMenu * = addMenu(mb: m_globalMenuBar, title: tr(s: "F&orm" ), al: m_actionManager->formActions()->actions()); |
191 | QMenu * = new QMenu(tr(s: "Preview in" ), formMenu); |
192 | formMenu->insertMenu(before: m_actionManager->previewFormAction(), menu: previewSubMenu); |
193 | addActionsToMenu(m: previewSubMenu, al: m_actionManager->styleActions()->actions()); |
194 | |
195 | QMenu * = m_globalMenuBar->addMenu(title: tr(s: "&View" )); |
196 | |
197 | addMenu(mb: m_globalMenuBar, title: tr(s: "&Settings" ), al: m_actionManager->settingsActions()->actions()); |
198 | |
199 | m_windowMenu = addMenu(mb: m_globalMenuBar, title: tr(s: "&Window" ), al: m_actionManager->windowActions()->actions()); |
200 | |
201 | addMenu(mb: m_globalMenuBar, title: tr(s: "&Help" ), al: m_actionManager->helpActions()->actions()); |
202 | |
203 | // Add the tools in view menu order |
204 | QActionGroup *viewActions = new QActionGroup(this); |
205 | viewActions->setExclusive(false); |
206 | |
207 | for (int i = 0; i < QDesignerToolWindow::StandardToolWindowCount; i++) { |
208 | QDesignerToolWindow *toolWindow = QDesignerToolWindow::createStandardToolWindow(which: static_cast< QDesignerToolWindow::StandardToolWindow>(i), workbench: this); |
209 | m_toolWindows.push_back(t: toolWindow); |
210 | if (QAction *action = toolWindow->action()) { |
211 | viewMenu->addAction(action); |
212 | viewActions->addAction(a: action); |
213 | } |
214 | // The widget box becomes the main window in top level mode |
215 | if (i == QDesignerToolWindow::WidgetBox) { |
216 | connect(sender: toolWindow, signal: &QDesignerToolWindow::closeEventReceived, |
217 | receiver: this, slot: &QDesignerWorkbench::handleCloseEvent); |
218 | } |
219 | } |
220 | // Integration |
221 | m_integration = new QDesignerIntegration(m_core, this); |
222 | connect(sender: m_integration, signal: &QDesignerIntegration::helpRequested, |
223 | receiver: m_actionManager, slot: &QDesignerActions::helpRequested); |
224 | |
225 | // remaining view options (config toolbars) |
226 | viewMenu->addSeparator(); |
227 | m_toolbarMenu = viewMenu->addMenu(title: tr(s: "Toolbars" )); |
228 | |
229 | emit initialized(); |
230 | |
231 | connect(sender: m_core->formWindowManager(), signal: &QDesignerFormWindowManagerInterface::activeFormWindowChanged, |
232 | receiver: this, slot: &QDesignerWorkbench::updateWindowMenu); |
233 | |
234 | |
235 | { // Add application specific options pages |
236 | QDesignerAppearanceOptionsPage *appearanceOptions = new QDesignerAppearanceOptionsPage(m_core); |
237 | connect(sender: appearanceOptions, signal: &QDesignerAppearanceOptionsPage::settingsChanged, receiver: this, slot: &QDesignerWorkbench::notifyUISettingsChanged); |
238 | auto optionsPages = m_core->optionsPages(); |
239 | optionsPages.push_front(t: appearanceOptions); |
240 | m_core->setOptionsPages(optionsPages); |
241 | } |
242 | |
243 | restoreUISettings(); |
244 | AppFontWidget::restore(s: m_core->settingsManager(), prefix: QLatin1String(appFontPrefixC)); |
245 | m_state = StateUp; |
246 | } |
247 | |
248 | QDesignerWorkbench::~QDesignerWorkbench() |
249 | { |
250 | switch (m_mode) { |
251 | case NeutralMode: |
252 | case DockedMode: |
253 | qDeleteAll(c: m_toolWindows); |
254 | break; |
255 | case TopLevelMode: // Everything parented here |
256 | delete widgetBoxToolWindow(); |
257 | break; |
258 | } |
259 | } |
260 | |
261 | void QDesignerWorkbench::saveGeometriesForModeChange() |
262 | { |
263 | m_Positions.clear(); |
264 | switch (m_mode) { |
265 | case NeutralMode: |
266 | break; |
267 | case TopLevelMode: { |
268 | const QPoint desktopOffset = QGuiApplication::primaryScreen()->availableGeometry().topLeft(); |
269 | for (QDesignerToolWindow *tw : qAsConst(t&: m_toolWindows)) |
270 | m_Positions.insert(akey: tw, avalue: Position(tw, desktopOffset)); |
271 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) |
272 | m_Positions.insert(akey: fw, avalue: Position(fw, desktopOffset)); |
273 | } |
274 | break; |
275 | case DockedMode: { |
276 | const QPoint mdiAreaOffset = m_dockedMainWindow->mdiArea()->pos(); |
277 | for (QDesignerToolWindow *tw : qAsConst(t&: m_toolWindows)) |
278 | m_Positions.insert(akey: tw, avalue: Position(dockWidgetOf(w: tw))); |
279 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) |
280 | m_Positions.insert(akey: fw, avalue: Position(mdiSubWindowOf(w: fw), mdiAreaOffset)); |
281 | } |
282 | break; |
283 | } |
284 | } |
285 | |
286 | UIMode QDesignerWorkbench::mode() const |
287 | { |
288 | return m_mode; |
289 | } |
290 | |
291 | void QDesignerWorkbench::addFormWindow(QDesignerFormWindow *formWindow) |
292 | { |
293 | // ### Q_ASSERT(formWindow->windowTitle().isEmpty() == false); |
294 | |
295 | m_formWindows.append(t: formWindow); |
296 | |
297 | |
298 | m_actionManager->setWindowListSeparatorVisible(true); |
299 | |
300 | if (QAction *action = formWindow->action()) { |
301 | m_windowActions->addAction(a: action); |
302 | m_windowMenu->addAction(action); |
303 | action->setChecked(true); |
304 | } |
305 | |
306 | m_actionManager->minimizeAction()->setEnabled(true); |
307 | m_actionManager->minimizeAction()->setChecked(false); |
308 | connect(sender: formWindow, signal: &QDesignerFormWindow::minimizationStateChanged, |
309 | receiver: this, slot: &QDesignerWorkbench::minimizationStateChanged); |
310 | |
311 | m_actionManager->editWidgets()->trigger(); |
312 | } |
313 | |
314 | Qt::WindowFlags QDesignerWorkbench::magicalWindowFlags(const QWidget *widgetForFlags) const |
315 | { |
316 | switch (m_mode) { |
317 | case TopLevelMode: { |
318 | #ifdef Q_OS_MACOS |
319 | if (qobject_cast<const QDesignerToolWindow *>(widgetForFlags)) |
320 | return Qt::Tool; |
321 | #else |
322 | Q_UNUSED(widgetForFlags); |
323 | #endif |
324 | return Qt::Window; |
325 | } |
326 | case DockedMode: |
327 | return Qt::Window | Qt::WindowShadeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint; |
328 | case NeutralMode: |
329 | return Qt::Window; |
330 | default: |
331 | Q_ASSERT(0); |
332 | return {}; |
333 | } |
334 | } |
335 | |
336 | QWidget *QDesignerWorkbench::magicalParent(const QWidget *w) const |
337 | { |
338 | switch (m_mode) { |
339 | case TopLevelMode: { |
340 | // Use widget box as parent for all windows except self. This will |
341 | // result in having just one entry in the MS Windows task bar. |
342 | QWidget *widgetBoxWrapper = widgetBoxToolWindow(); |
343 | return w == widgetBoxWrapper ? nullptr : widgetBoxWrapper; |
344 | } |
345 | case DockedMode: |
346 | return m_dockedMainWindow->mdiArea(); |
347 | case NeutralMode: |
348 | return nullptr; |
349 | default: |
350 | Q_ASSERT(0); |
351 | return 0; |
352 | } |
353 | } |
354 | |
355 | void QDesignerWorkbench::switchToNeutralMode() |
356 | { |
357 | QDesignerSettings settings(m_core); |
358 | saveGeometries(settings); |
359 | saveGeometriesForModeChange(); |
360 | |
361 | if (m_mode == TopLevelMode) { |
362 | delete m_topLevelData.toolbarManager; |
363 | m_topLevelData.toolbarManager = nullptr; |
364 | qDeleteAll(c: m_topLevelData.toolbars); |
365 | m_topLevelData.toolbars.clear(); |
366 | } |
367 | |
368 | m_mode = NeutralMode; |
369 | |
370 | for (QDesignerToolWindow *tw : qAsConst(t&: m_toolWindows)) { |
371 | tw->setCloseEventPolicy(MainWindowBase::AcceptCloseEvents); |
372 | tw->setParent(nullptr); |
373 | } |
374 | |
375 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) { |
376 | fw->setParent(nullptr); |
377 | fw->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); |
378 | } |
379 | |
380 | #ifndef Q_OS_MACOS |
381 | m_globalMenuBar->setParent(nullptr); |
382 | #endif |
383 | |
384 | m_core->setTopLevel(nullptr); |
385 | qDesigner->setMainWindow(nullptr); |
386 | |
387 | delete m_dockedMainWindow; |
388 | m_dockedMainWindow = nullptr; |
389 | } |
390 | |
391 | void QDesignerWorkbench::switchToDockedMode() |
392 | { |
393 | if (m_mode == DockedMode) |
394 | return; |
395 | |
396 | switchToNeutralMode(); |
397 | |
398 | #if !defined(Q_OS_MACOS) |
399 | # if defined(Q_OS_UNIX) |
400 | QApplication::setAttribute(attribute: Qt::AA_DontUseNativeMenuBar, on: false); |
401 | # endif // Q_OS_UNIX |
402 | QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); |
403 | widgetBoxWrapper->action()->setVisible(true); |
404 | widgetBoxWrapper->setWindowTitle(tr(s: "Widget Box" )); |
405 | #endif // !Q_OS_MACOS |
406 | |
407 | m_mode = DockedMode; |
408 | const QDesignerSettings settings(m_core); |
409 | m_dockedMainWindow = new DockedMainWindow(this, m_toolbarMenu, m_toolWindows); |
410 | m_dockedMainWindow->setUnifiedTitleAndToolBarOnMac(true); |
411 | m_dockedMainWindow->setCloseEventPolicy(MainWindowBase::EmitCloseEventSignal); |
412 | connect(sender: m_dockedMainWindow, signal: &DockedMainWindow::closeEventReceived, |
413 | receiver: this, slot: &QDesignerWorkbench::handleCloseEvent); |
414 | connect(sender: m_dockedMainWindow, signal: &DockedMainWindow::fileDropped, |
415 | receiver: this, slot: &QDesignerWorkbench::slotFileDropped); |
416 | connect(sender: m_dockedMainWindow, signal: &DockedMainWindow::formWindowActivated, |
417 | receiver: this, slot: &QDesignerWorkbench::slotFormWindowActivated); |
418 | m_dockedMainWindow->restoreSettings(s: settings, dws: m_dockedMainWindow->addToolWindows(toolWindows: m_toolWindows), desktopArea: desktopGeometry()); |
419 | |
420 | m_core->setTopLevel(m_dockedMainWindow); |
421 | |
422 | #ifndef Q_OS_MACOS |
423 | m_dockedMainWindow->setMenuBar(m_globalMenuBar); |
424 | m_globalMenuBar->show(); |
425 | #endif |
426 | qDesigner->setMainWindow(m_dockedMainWindow); |
427 | |
428 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) { |
429 | QMdiSubWindow *subwin = m_dockedMainWindow->createMdiSubWindow(fw, f: magicalWindowFlags(widgetForFlags: fw), |
430 | designerCloseActionShortCut: m_actionManager->closeFormAction()->shortcut()); |
431 | subwin->hide(); |
432 | if (QWidget *mainContainer = fw->editor()->mainContainer()) |
433 | resizeForm(fw, mainContainer); |
434 | } |
435 | |
436 | m_actionManager->setBringAllToFrontVisible(false); |
437 | m_dockedMainWindow->show(); |
438 | // Trigger adjustMDIFormPositions() delayed as viewport size is not yet known. |
439 | |
440 | if (m_state != StateInitializing) |
441 | QMetaObject::invokeMethod(obj: this, member: "adjustMDIFormPositions" , type: Qt::QueuedConnection); |
442 | } |
443 | |
444 | void QDesignerWorkbench::adjustMDIFormPositions() |
445 | { |
446 | const QPoint mdiAreaOffset = m_dockedMainWindow->mdiArea()->pos(); |
447 | |
448 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) { |
449 | const PositionMap::const_iterator pit = m_Positions.constFind(akey: fw); |
450 | if (pit != m_Positions.constEnd()) |
451 | pit->applyTo(mdiSubWindow: mdiSubWindowOf(w: fw), mdiAreaOffset); |
452 | } |
453 | } |
454 | |
455 | void QDesignerWorkbench::switchToTopLevelMode() |
456 | { |
457 | if (m_mode == TopLevelMode) |
458 | return; |
459 | |
460 | // make sure that the widgetbox is visible if it is different from neutral. |
461 | QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); |
462 | Q_ASSERT(widgetBoxWrapper); |
463 | |
464 | switchToNeutralMode(); |
465 | const QPoint desktopOffset = desktopGeometry().topLeft(); |
466 | m_mode = TopLevelMode; |
467 | |
468 | // The widget box is special, it gets the menubar and gets to be the main widget. |
469 | |
470 | m_core->setTopLevel(widgetBoxWrapper); |
471 | #if !defined(Q_OS_MACOS) |
472 | # if defined(Q_OS_UNIX) |
473 | // For now the appmenu protocol does not make it possible to associate a |
474 | // menubar with all application windows. This means in top level mode you |
475 | // can only reach the menubar when the widgetbox window is active. Since |
476 | // this is quite inconvenient, better not use the native menubar in this |
477 | // configuration and keep the menubar in the widgetbox window. |
478 | QApplication::setAttribute(attribute: Qt::AA_DontUseNativeMenuBar, on: true); |
479 | # endif // Q_OS_UNIX |
480 | widgetBoxWrapper->setMenuBar(m_globalMenuBar); |
481 | widgetBoxWrapper->action()->setVisible(false); |
482 | widgetBoxWrapper->setCloseEventPolicy(MainWindowBase::EmitCloseEventSignal); |
483 | qDesigner->setMainWindow(widgetBoxWrapper); |
484 | widgetBoxWrapper->setWindowTitle(MainWindowBase::mainWindowTitle()); |
485 | #endif // !Q_OS_MACOS |
486 | |
487 | const QDesignerSettings settings(m_core); |
488 | m_topLevelData.toolbars = MainWindowBase::createToolBars(actions: m_actionManager, singleToolBar: false); |
489 | m_topLevelData.toolbarManager = new ToolBarManager(widgetBoxWrapper, widgetBoxWrapper, |
490 | m_toolbarMenu, m_actionManager, |
491 | m_topLevelData.toolbars, m_toolWindows); |
492 | const int toolBarCount = m_topLevelData.toolbars.size(); |
493 | for (int i = 0; i < toolBarCount; i++) { |
494 | widgetBoxWrapper->addToolBar(toolbar: m_topLevelData.toolbars.at(i)); |
495 | if (i == 3) |
496 | widgetBoxWrapper->insertToolBarBreak(before: m_topLevelData.toolbars.at(i)); |
497 | } |
498 | m_topLevelData.toolbarManager->restoreState(state: settings.toolBarsState(mode: m_mode), version: MainWindowBase::settingsVersion()); |
499 | widgetBoxWrapper->restoreState(state: settings.mainWindowState(mode: m_mode), version: MainWindowBase::settingsVersion()); |
500 | |
501 | bool found_visible_window = false; |
502 | for (QDesignerToolWindow *tw : qAsConst(t&: m_toolWindows)) { |
503 | tw->setParent(parent: magicalParent(w: tw), f: magicalWindowFlags(widgetForFlags: tw)); |
504 | settings.restoreGeometry(w: tw, fallBack: tw->geometryHint()); |
505 | tw->action()->setChecked(tw->isVisible()); |
506 | found_visible_window |= tw->isVisible(); |
507 | } |
508 | |
509 | if (!m_toolWindows.isEmpty() && !found_visible_window) |
510 | m_toolWindows.first()->show(); |
511 | |
512 | m_actionManager->setBringAllToFrontVisible(true); |
513 | |
514 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) { |
515 | fw->setParent(parent: magicalParent(w: fw), f: magicalWindowFlags(widgetForFlags: fw)); |
516 | fw->setAttribute(Qt::WA_DeleteOnClose, on: true); |
517 | const PositionMap::const_iterator pit = m_Positions.constFind(akey: fw); |
518 | if (pit != m_Positions.constEnd()) pit->applyTo(topLevelWindow: fw, desktopTopLeft: desktopOffset); |
519 | // Force an activate in order to refresh minimumSize, otherwise it will not be respected |
520 | if (QLayout *layout = fw->layout()) |
521 | layout->invalidate(); |
522 | if (QWidget *mainContainer = fw->editor()->mainContainer()) |
523 | resizeForm(fw, mainContainer); |
524 | } |
525 | } |
526 | |
527 | QDesignerFormWindowManagerInterface *QDesignerWorkbench::formWindowManager() const |
528 | { |
529 | return m_core->formWindowManager(); |
530 | } |
531 | |
532 | QDesignerFormEditorInterface *QDesignerWorkbench::core() const |
533 | { |
534 | return m_core; |
535 | } |
536 | |
537 | int QDesignerWorkbench::toolWindowCount() const |
538 | { |
539 | return m_toolWindows.count(); |
540 | } |
541 | |
542 | QDesignerToolWindow *QDesignerWorkbench::toolWindow(int index) const |
543 | { |
544 | return m_toolWindows.at(i: index); |
545 | } |
546 | |
547 | int QDesignerWorkbench::formWindowCount() const |
548 | { |
549 | return m_formWindows.count(); |
550 | } |
551 | |
552 | QDesignerFormWindow *QDesignerWorkbench::formWindow(int index) const |
553 | { |
554 | return m_formWindows.at(i: index); |
555 | } |
556 | |
557 | QRect QDesignerWorkbench::desktopGeometry() const |
558 | { |
559 | // Return geometry of the desktop designer is running in. |
560 | QWidget *widget = nullptr; |
561 | switch (m_mode) { |
562 | case DockedMode: |
563 | widget = m_dockedMainWindow; |
564 | break; |
565 | case TopLevelMode: |
566 | widget = widgetBoxToolWindow(); |
567 | break; |
568 | case NeutralMode: |
569 | break; |
570 | } |
571 | const auto screen = widget ? widget->screen() : QGuiApplication::primaryScreen(); |
572 | return screen ? screen->availableGeometry() |
573 | : QGuiApplication::primaryScreen()->availableGeometry(); |
574 | } |
575 | |
576 | QRect QDesignerWorkbench::availableGeometry() const |
577 | { |
578 | if (m_mode == DockedMode) |
579 | return m_dockedMainWindow->mdiArea()->geometry(); |
580 | |
581 | const auto screen = widgetBoxToolWindow()->screen(); |
582 | return screen ? screen->availableGeometry() : QGuiApplication::primaryScreen()->availableGeometry() ; |
583 | } |
584 | |
585 | int QDesignerWorkbench::marginHint() const |
586 | { return 20; |
587 | } |
588 | |
589 | void QDesignerWorkbench::slotFormWindowActivated(QDesignerFormWindow* fw) |
590 | { |
591 | core()->formWindowManager()->setActiveFormWindow(fw->editor()); |
592 | } |
593 | |
594 | void QDesignerWorkbench::removeFormWindow(QDesignerFormWindow *formWindow) |
595 | { |
596 | QDesignerFormWindowInterface *editor = formWindow->editor(); |
597 | const bool loadOk = editor->mainContainer(); |
598 | updateBackup(fwi: editor); |
599 | const int index = m_formWindows.indexOf(t: formWindow); |
600 | if (index != -1) { |
601 | m_formWindows.removeAt(i: index); |
602 | } |
603 | |
604 | if (QAction *action = formWindow->action()) { |
605 | m_windowActions->removeAction(a: action); |
606 | m_windowMenu->removeAction(action); |
607 | } |
608 | |
609 | if (m_formWindows.isEmpty()) { |
610 | m_actionManager->setWindowListSeparatorVisible(false); |
611 | // Show up new form dialog unless closing |
612 | if (loadOk && m_state == StateUp |
613 | && QDesignerSettings(m_core).showNewFormOnStartup()) { |
614 | QTimer::singleShot(interval: 200, receiver: m_actionManager, slot: &QDesignerActions::createForm); |
615 | } |
616 | } |
617 | } |
618 | |
619 | void QDesignerWorkbench::initializeCorePlugins() |
620 | { |
621 | QObjectList plugins = QPluginLoader::staticInstances(); |
622 | plugins += core()->pluginManager()->instances(); |
623 | |
624 | for (QObject *plugin : qAsConst(t&: plugins)) { |
625 | if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(object: plugin)) { |
626 | if (!formEditorPlugin->isInitialized()) |
627 | formEditorPlugin->initialize(core: core()); |
628 | } |
629 | } |
630 | } |
631 | |
632 | void QDesignerWorkbench::saveSettings() const |
633 | { |
634 | QDesignerSettings settings(m_core); |
635 | settings.clearBackup(); |
636 | saveGeometries(settings); |
637 | AppFontWidget::save(s: m_core->settingsManager(), prefix: QLatin1String(appFontPrefixC)); |
638 | } |
639 | |
640 | void QDesignerWorkbench::saveGeometries(QDesignerSettings &settings) const |
641 | { |
642 | switch (m_mode) { |
643 | case DockedMode: |
644 | m_dockedMainWindow->saveSettings(settings); |
645 | break; |
646 | case TopLevelMode: |
647 | settings.setToolBarsState(mode: m_mode, mainWindowState: m_topLevelData.toolbarManager->saveState(version: MainWindowBase::settingsVersion())); |
648 | settings.setMainWindowState(mode: m_mode, mainWindowState: widgetBoxToolWindow()->saveState(version: MainWindowBase::settingsVersion())); |
649 | for (const QDesignerToolWindow *tw : m_toolWindows) |
650 | settings.saveGeometryFor(w: tw); |
651 | break; |
652 | case NeutralMode: |
653 | break; |
654 | } |
655 | } |
656 | |
657 | void QDesignerWorkbench::slotFileDropped(const QString &f) |
658 | { |
659 | readInForm(fileName: f); |
660 | } |
661 | |
662 | bool QDesignerWorkbench::readInForm(const QString &fileName) const |
663 | { |
664 | return m_actionManager->readInForm(fileName); |
665 | } |
666 | |
667 | bool QDesignerWorkbench::writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName) const |
668 | { |
669 | return m_actionManager->writeOutForm(formWindow, fileName); |
670 | } |
671 | |
672 | bool QDesignerWorkbench::saveForm(QDesignerFormWindowInterface *frm) |
673 | { |
674 | return m_actionManager->saveForm(fw: frm); |
675 | } |
676 | |
677 | QDesignerFormWindow *QDesignerWorkbench::findFormWindow(QWidget *widget) const |
678 | { |
679 | for (QDesignerFormWindow *formWindow : m_formWindows) { |
680 | if (formWindow->editor() == widget) |
681 | return formWindow; |
682 | } |
683 | |
684 | return nullptr; |
685 | } |
686 | |
687 | bool QDesignerWorkbench::handleClose() |
688 | { |
689 | m_state = StateClosing; |
690 | QVector<QDesignerFormWindow *> dirtyForms; |
691 | for (QDesignerFormWindow *w : qAsConst(t&: m_formWindows)) { |
692 | if (w->editor()->isDirty()) |
693 | dirtyForms << w; |
694 | } |
695 | |
696 | const int count = dirtyForms.size(); |
697 | if (count == 1) { |
698 | if (!dirtyForms.at(i: 0)->close()) { |
699 | m_state = StateUp; |
700 | return false; |
701 | } |
702 | } else if (count > 1) { |
703 | QMessageBox box(QMessageBox::Warning, tr(s: "Save Forms?" ), |
704 | tr(s: "There are %n forms with unsaved changes." |
705 | " Do you want to review these changes before quitting?" , c: "" , n: count), |
706 | QMessageBox::Cancel | QMessageBox::Discard | QMessageBox::Save); |
707 | box.setInformativeText(tr(s: "If you do not review your documents, all your changes will be lost." )); |
708 | box.button(which: QMessageBox::Discard)->setText(tr(s: "Discard Changes" )); |
709 | QPushButton *save = static_cast<QPushButton *>(box.button(which: QMessageBox::Save)); |
710 | save->setText(tr(s: "Review Changes" )); |
711 | box.setDefaultButton(save); |
712 | switch (box.exec()) { |
713 | case QMessageBox::Cancel: |
714 | m_state = StateUp; |
715 | return false; |
716 | case QMessageBox::Save: |
717 | for (QDesignerFormWindow *fw : qAsConst(t&: dirtyForms)) { |
718 | fw->show(); |
719 | fw->raise(); |
720 | if (!fw->close()) { |
721 | m_state = StateUp; |
722 | return false; |
723 | } |
724 | } |
725 | break; |
726 | case QMessageBox::Discard: |
727 | for (QDesignerFormWindow *fw : qAsConst(t&: dirtyForms)) { |
728 | fw->editor()->setDirty(false); |
729 | fw->setWindowModified(false); |
730 | } |
731 | break; |
732 | } |
733 | } |
734 | |
735 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) |
736 | fw->close(); |
737 | |
738 | saveSettings(); |
739 | return true; |
740 | } |
741 | |
742 | QDesignerActions *QDesignerWorkbench::actionManager() const |
743 | { |
744 | return m_actionManager; |
745 | } |
746 | |
747 | void QDesignerWorkbench::(QDesignerFormWindowInterface *fwi) |
748 | { |
749 | bool minimizeChecked = false; |
750 | bool minimizeEnabled = false; |
751 | QDesignerFormWindow *activeFormWindow = nullptr; |
752 | do { |
753 | if (!fwi) |
754 | break; |
755 | activeFormWindow = qobject_cast<QDesignerFormWindow *>(object: fwi->parentWidget()); |
756 | if (!activeFormWindow) |
757 | break; |
758 | |
759 | minimizeEnabled = true; |
760 | minimizeChecked = isFormWindowMinimized(fw: activeFormWindow); |
761 | } while (false) ; |
762 | |
763 | m_actionManager->minimizeAction()->setEnabled(minimizeEnabled); |
764 | m_actionManager->minimizeAction()->setChecked(minimizeChecked); |
765 | |
766 | for (QDesignerFormWindow *fw : qAsConst(t&: m_formWindows)) |
767 | fw->action()->setChecked(fw == activeFormWindow); |
768 | } |
769 | |
770 | void QDesignerWorkbench::formWindowActionTriggered(QAction *a) |
771 | { |
772 | QDesignerFormWindow *fw = qobject_cast<QDesignerFormWindow *>(object: a->parentWidget()); |
773 | Q_ASSERT(fw); |
774 | |
775 | if (isFormWindowMinimized(fw)) |
776 | setFormWindowMinimized(fw, minimized: false); |
777 | |
778 | if (m_mode == DockedMode) { |
779 | if (QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object: fw->parent())) { |
780 | m_dockedMainWindow->mdiArea()->setActiveSubWindow(subWindow); |
781 | } |
782 | } else { |
783 | fw->activateWindow(); |
784 | fw->raise(); |
785 | } |
786 | } |
787 | |
788 | void QDesignerWorkbench::closeAllToolWindows() |
789 | { |
790 | for (QDesignerToolWindow *tw : qAsConst(t&: m_toolWindows)) |
791 | tw->hide(); |
792 | } |
793 | |
794 | bool QDesignerWorkbench::readInBackup() |
795 | { |
796 | const QMap<QString, QString> backupFileMap = QDesignerSettings(m_core).backup(); |
797 | if (backupFileMap.isEmpty()) |
798 | return false; |
799 | |
800 | const QMessageBox::StandardButton answer = |
801 | QMessageBox::question(parent: nullptr, title: tr(s: "Backup Information" ), |
802 | text: tr(s: "The last session of Designer was not terminated correctly. " |
803 | "Backup files were left behind. Do you want to load them?" ), |
804 | buttons: QMessageBox::Yes|QMessageBox::No, defaultButton: QMessageBox::Yes); |
805 | if (answer == QMessageBox::No) |
806 | return false; |
807 | |
808 | const QString modifiedPlaceHolder = QStringLiteral("[*]" ); |
809 | for (auto it = backupFileMap.cbegin(), end = backupFileMap.cend(); it != end; ++it) { |
810 | QString fileName = it.key(); |
811 | fileName.remove(s: modifiedPlaceHolder); |
812 | |
813 | if(m_actionManager->readInForm(fileName: it.value())) |
814 | formWindowManager()->activeFormWindow()->setFileName(fileName); |
815 | |
816 | } |
817 | return true; |
818 | } |
819 | |
820 | void QDesignerWorkbench::updateBackup(QDesignerFormWindowInterface* fwi) |
821 | { |
822 | QString fwn = QDir::toNativeSeparators(pathName: fwi->fileName()); |
823 | if (fwn.isEmpty()) |
824 | fwn = fwi->parentWidget()->windowTitle(); |
825 | |
826 | QDesignerSettings settings(m_core); |
827 | QMap<QString, QString> map = settings.backup(); |
828 | map.remove(akey: fwn); |
829 | settings.setBackup(map); |
830 | } |
831 | |
832 | namespace { |
833 | void raiseWindow(QWidget *w) { |
834 | if (w->isMinimized()) |
835 | w->setWindowState(w->windowState() & ~Qt::WindowMinimized); |
836 | w->raise(); |
837 | } |
838 | } |
839 | |
840 | void QDesignerWorkbench::bringAllToFront() |
841 | { |
842 | if (m_mode != TopLevelMode) |
843 | return; |
844 | for (QDesignerToolWindow *tw : qAsConst(t&: m_toolWindows)) |
845 | raiseWindow(w: tw); |
846 | for (QDesignerFormWindow *dfw : qAsConst(t&: m_formWindows)) |
847 | raiseWindow(w: dfw); |
848 | } |
849 | |
850 | // Resize a form window taking MDI decorations into account |
851 | // Apply maximum size as there is no layout connection between |
852 | // the form's main container and the integration's outer |
853 | // container due to the tool widget stack. |
854 | |
855 | void QDesignerWorkbench::resizeForm(QDesignerFormWindow *fw, const QWidget *mainContainer) const |
856 | { |
857 | const QSize containerSize = mainContainer->size(); |
858 | const QSize containerMaximumSize = mainContainer->maximumSize(); |
859 | if (m_mode != DockedMode) { |
860 | fw->resize(containerSize); |
861 | fw->setMaximumSize(containerMaximumSize); |
862 | return; |
863 | } |
864 | // get decorations and resize MDI |
865 | QMdiSubWindow *mdiSubWindow = qobject_cast<QMdiSubWindow *>(object: fw->parent()); |
866 | Q_ASSERT(mdiSubWindow); |
867 | const QSize decorationSize = mdiSubWindow->geometry().size() - mdiSubWindow->contentsRect().size(); |
868 | mdiSubWindow->resize(containerSize + decorationSize); |
869 | // In Qt::RightToLeft mode, the window can grow to be partially hidden by the right border. |
870 | const int mdiAreaWidth = m_dockedMainWindow->mdiArea()->width(); |
871 | if (qApp->layoutDirection() == Qt::RightToLeft && mdiSubWindow->geometry().right() >= mdiAreaWidth) |
872 | mdiSubWindow->move(ax: mdiAreaWidth - mdiSubWindow->width(), ay: mdiSubWindow->pos().y()); |
873 | |
874 | if (containerMaximumSize == QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) { |
875 | mdiSubWindow->setMaximumSize(containerMaximumSize); |
876 | } else { |
877 | mdiSubWindow->setMaximumSize(containerMaximumSize + decorationSize); |
878 | } |
879 | } |
880 | |
881 | |
882 | // Load a form or return 0 and do cleanup. file name and editor file |
883 | // name in case of loading a template file. |
884 | |
885 | QDesignerFormWindow * QDesignerWorkbench::loadForm(const QString &fileName, |
886 | bool detectLineTermiantorMode, |
887 | QString *errorMessage) |
888 | { |
889 | QFile file(fileName); |
890 | |
891 | qdesigner_internal::FormWindowBase::LineTerminatorMode mode = qdesigner_internal::FormWindowBase::NativeLineTerminator; |
892 | |
893 | if (detectLineTermiantorMode) { |
894 | if (file.open(flags: QFile::ReadOnly)) { |
895 | const QString text = QString::fromUtf8(str: file.readLine()); |
896 | file.close(); |
897 | |
898 | const int lf = text.indexOf(c: QLatin1Char('\n')); |
899 | if (lf > 0 && text.at(i: lf-1) == QLatin1Char('\r')) { |
900 | mode = qdesigner_internal::FormWindowBase::CRLFLineTerminator; |
901 | } else if (lf >= 0) { |
902 | mode = qdesigner_internal::FormWindowBase::LFLineTerminator; |
903 | } |
904 | } |
905 | } |
906 | |
907 | if (!file.open(flags: QFile::ReadOnly|QFile::Text)) { |
908 | *errorMessage = tr(s: "The file <b>%1</b> could not be opened: %2" ).arg(args: file.fileName(), args: file.errorString()); |
909 | return nullptr; |
910 | } |
911 | |
912 | // Create a form |
913 | QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager(); |
914 | |
915 | QDesignerFormWindow *formWindow = new QDesignerFormWindow(/*formWindow=*/ nullptr, this); |
916 | addFormWindow(formWindow); |
917 | QDesignerFormWindowInterface *editor = formWindow->editor(); |
918 | Q_ASSERT(editor); |
919 | |
920 | // Temporarily set the file name. It is needed when converting a UIC 3 file. |
921 | // In this case, the file name will we be cleared on return to force a save box. |
922 | editor->setFileName(fileName); |
923 | |
924 | if (!editor->setContents(dev: &file, errorMessage)) { |
925 | removeFormWindow(formWindow); |
926 | formWindowManager->removeFormWindow(formWindow: editor); |
927 | m_core->metaDataBase()->remove(object: editor); |
928 | return nullptr; |
929 | } |
930 | |
931 | if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(object: editor)) |
932 | fwb->setLineTerminatorMode(mode); |
933 | |
934 | switch (m_mode) { |
935 | case DockedMode: { |
936 | // below code must be after above call to setContents(), because setContents() may popup warning dialogs which would cause |
937 | // mdi sub window activation (because of dialogs internal call to processEvent or such) |
938 | // That activation could have worse consequences, e.g. NULL resource set for active form) before the form is loaded |
939 | QMdiSubWindow *subWin = m_dockedMainWindow->createMdiSubWindow(fw: formWindow, f: magicalWindowFlags(widgetForFlags: formWindow), designerCloseActionShortCut: m_actionManager->closeFormAction()->shortcut()); |
940 | m_dockedMainWindow->mdiArea()->setActiveSubWindow(subWin); |
941 | } |
942 | break; |
943 | case TopLevelMode: { |
944 | const QRect formWindowGeometryHint = formWindow->geometryHint(); |
945 | formWindow->setAttribute(Qt::WA_DeleteOnClose, on: true); |
946 | formWindow->setParent(parent: magicalParent(w: formWindow), f: magicalWindowFlags(widgetForFlags: formWindow)); |
947 | formWindow->resize(formWindowGeometryHint.size()); |
948 | formWindow->move(availableGeometry().center() - formWindowGeometryHint.center()); |
949 | } |
950 | break; |
951 | case NeutralMode: |
952 | break; |
953 | } |
954 | |
955 | // Did user specify another (missing) resource path -> set dirty. |
956 | const bool dirty = editor->property(name: "_q_resourcepathchanged" ).toBool(); |
957 | editor->setDirty(dirty); |
958 | resizeForm(fw: formWindow, mainContainer: editor->mainContainer()); |
959 | formWindowManager->setActiveFormWindow(editor); |
960 | return formWindow; |
961 | } |
962 | |
963 | |
964 | QDesignerFormWindow * QDesignerWorkbench::openForm(const QString &fileName, QString *errorMessage) |
965 | { |
966 | QDesignerFormWindow *rc = loadForm(fileName, detectLineTermiantorMode: true, errorMessage); |
967 | if (!rc) |
968 | return nullptr; |
969 | rc->editor()->setFileName(fileName); |
970 | rc->firstShow(); |
971 | return rc; |
972 | } |
973 | |
974 | QDesignerFormWindow * QDesignerWorkbench::openTemplate(const QString &templateFileName, |
975 | const QString &editorFileName, |
976 | QString *errorMessage) |
977 | { |
978 | QDesignerFormWindow *rc = loadForm(fileName: templateFileName, detectLineTermiantorMode: false, errorMessage); |
979 | if (!rc) |
980 | return nullptr; |
981 | |
982 | rc->editor()->setFileName(editorFileName); |
983 | rc->firstShow(); |
984 | return rc; |
985 | } |
986 | |
987 | void QDesignerWorkbench::minimizationStateChanged(QDesignerFormWindowInterface *formWindow, bool minimized) |
988 | { |
989 | // refresh the minimize action state |
990 | if (core()->formWindowManager()->activeFormWindow() == formWindow) { |
991 | m_actionManager->minimizeAction()->setChecked(minimized); |
992 | } |
993 | } |
994 | |
995 | void QDesignerWorkbench::toggleFormMinimizationState() |
996 | { |
997 | QDesignerFormWindowInterface *fwi = core()->formWindowManager()->activeFormWindow(); |
998 | if (!fwi || m_mode == NeutralMode) |
999 | return; |
1000 | QDesignerFormWindow *fw = qobject_cast<QDesignerFormWindow *>(object: fwi->parentWidget()); |
1001 | Q_ASSERT(fw); |
1002 | setFormWindowMinimized(fw, minimized: !isFormWindowMinimized(fw)); |
1003 | } |
1004 | |
1005 | bool QDesignerWorkbench::isFormWindowMinimized(const QDesignerFormWindow *fw) |
1006 | { |
1007 | switch (m_mode) { |
1008 | case DockedMode: |
1009 | return mdiSubWindowOf(w: fw)->isShaded(); |
1010 | case TopLevelMode: |
1011 | return fw->window()->isMinimized(); |
1012 | default: |
1013 | break; |
1014 | } |
1015 | return fw->isMinimized(); |
1016 | } |
1017 | |
1018 | void QDesignerWorkbench::setFormWindowMinimized(QDesignerFormWindow *fw, bool minimized) |
1019 | { |
1020 | switch (m_mode) { |
1021 | case DockedMode: { |
1022 | QMdiSubWindow *mdiSubWindow = mdiSubWindowOf(w: fw); |
1023 | if (minimized) { |
1024 | mdiSubWindow->showShaded(); |
1025 | } else { |
1026 | mdiSubWindow->setWindowState(mdiSubWindow->windowState() & ~Qt::WindowMinimized); |
1027 | } |
1028 | } |
1029 | break; |
1030 | case TopLevelMode: { |
1031 | QWidget *window = fw->window(); |
1032 | if (window->isMinimized()) { |
1033 | window->setWindowState(window->windowState() & ~Qt::WindowMinimized); |
1034 | } else { |
1035 | window->showMinimized(); |
1036 | } |
1037 | } |
1038 | break; |
1039 | default: |
1040 | break; |
1041 | } |
1042 | } |
1043 | |
1044 | /* Applies UI mode changes using Timer-0 delayed signal |
1045 | * signal to make sure the preferences dialog is closed and destroyed |
1046 | * before a possible switch from docked mode to top-level mode happens. |
1047 | * (The switch deletes the main window, which the preference dialog is |
1048 | * a child of -> BOOM) */ |
1049 | |
1050 | void QDesignerWorkbench::applyUiSettings() |
1051 | { |
1052 | if (m_uiSettingsChanged) { |
1053 | m_uiSettingsChanged = false; |
1054 | QTimer::singleShot(interval: 0, receiver: this, slot: &QDesignerWorkbench::restoreUISettings); |
1055 | } |
1056 | } |
1057 | |
1058 | void QDesignerWorkbench::notifyUISettingsChanged() |
1059 | { |
1060 | m_uiSettingsChanged = true; |
1061 | } |
1062 | |
1063 | void QDesignerWorkbench::restoreUISettings() |
1064 | { |
1065 | UIMode mode = QDesignerSettings(m_core).uiMode(); |
1066 | switch (mode) { |
1067 | case TopLevelMode: |
1068 | switchToTopLevelMode(); |
1069 | break; |
1070 | case DockedMode: |
1071 | switchToDockedMode(); |
1072 | break; |
1073 | |
1074 | default: Q_ASSERT(0); |
1075 | } |
1076 | |
1077 | ToolWindowFontSettings fontSettings = QDesignerSettings(m_core).toolWindowFont(); |
1078 | const QFont &font = fontSettings.m_useFont ? fontSettings.m_font : qApp->font(); |
1079 | |
1080 | if (font == m_toolWindows.constFirst()->font()) |
1081 | return; |
1082 | |
1083 | for (QDesignerToolWindow *tw : qAsConst(t&: m_toolWindows)) |
1084 | tw->setFont(font); |
1085 | } |
1086 | |
1087 | void QDesignerWorkbench::handleCloseEvent(QCloseEvent *ev) |
1088 | { |
1089 | ev->setAccepted(handleClose()); |
1090 | if (ev->isAccepted()) |
1091 | QMetaObject::invokeMethod(qDesigner, member: "quit" , type: Qt::QueuedConnection); // We're going down! |
1092 | } |
1093 | |
1094 | QDesignerToolWindow *QDesignerWorkbench::widgetBoxToolWindow() const |
1095 | { |
1096 | return m_toolWindows.at(i: QDesignerToolWindow::WidgetBox); |
1097 | } |
1098 | |
1099 | QT_END_NAMESPACE |
1100 | |