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
mainwindow.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// Qt-Security score:significant reason:default
4
5#include "mainwindow.h"
6#include "qdesigner.h"
13
14#include <QtDesigner/abstractformwindow.h>
15
16#include <QtWidgets/qtoolbar.h>
17#include <QtWidgets/qmdisubwindow.h>
18#include <QtWidgets/qstatusbar.h>
19#include <QtWidgets/qmenu.h>
20#include <QtWidgets/qlayout.h>
21#include <QtWidgets/qdockwidget.h>
22
23#include <QtGui/qaction.h>
24#include <QtGui/qactiongroup.h>
25#include <QtGui/qevent.h>
26
27#include <QtCore/qurl.h>
28#include <QtCore/qdebug.h>
29#include <QtCore/qmimedata.h>
30
31#include <algorithm>
32
33QT_BEGIN_NAMESPACE
34
35using namespace Qt::StringLiterals;
36
37using ActionList = QList<QAction *>;
38
39// Helpers for creating toolbars and menu
40
41static void addActionsToToolBar(const ActionList &actions, QToolBar *t)
42{
43 for (QAction *action : actions) {
44 if (action->property(QDesignerActions::defaultToolbarPropertyName).toBool())
45 t->addAction(action);
46 }
47}
48
49static QToolBar *createToolBar(const QString &title, const QString &objectName,
50 const ActionList &actions)
51{
52 auto *rc = new QToolBar;
53 rc->setObjectName(objectName);
54 rc->setWindowTitle(title);
55 addActionsToToolBar(actions, rc);
56 return rc;
57}
58
59// ---------------- MainWindowBase
60
61MainWindowBase::MainWindowBase(QWidget *parent, Qt::WindowFlags flags) :
62 QMainWindow(parent, flags)
63{
64#ifndef Q_OS_MACOS
65 setWindowIcon(qDesigner->windowIcon());
66#endif
67}
68
69void MainWindowBase::closeEvent(QCloseEvent *e)
70{
71 switch (m_policy) {
73 QMainWindow::closeEvent(e);
74 break;
76 emit closeEventReceived(e);
77 break;
78 }
79}
80
81QList<QToolBar *> MainWindowBase::createToolBars(const QDesignerActions *actions, bool singleToolBar)
82{
83 // Note that whenever you want to add a new tool bar here, you also have to update the default
84 // action groups added to the toolbar manager in the mainwindow constructor
85 QList<QToolBar *> rc;
86 if (singleToolBar) {
87 //: Not currently used (main tool bar)
88 QToolBar *main = createToolBar(tr("Main"), u"mainToolBar"_s,
89 actions->fileActions()->actions());
90 addActionsToToolBar(actions->editActions()->actions(), main);
91 addActionsToToolBar(actions->toolActions()->actions(), main);
92 addActionsToToolBar(actions->formActions()->actions(), main);
93 rc.push_back(main);
94 } else {
95 rc.append(createToolBar(tr("File"), u"fileToolBar"_s,
96 actions->fileActions()->actions()));
97 rc.append(createToolBar(tr("Edit"), u"editToolBar"_s,
98 actions->editActions()->actions()));
99 rc.append(createToolBar(tr("Tools"), u"toolsToolBar"_s,
100 actions->toolActions()->actions()));
101 rc.append(createToolBar(tr("Form"), u"formToolBar"_s,
102 actions->formActions()->actions()));
103 }
104 return rc;
105}
106
107QString MainWindowBase::mainWindowTitle()
108{
109 return tr("Qt Widgets Designer");
110}
111
112// Use the minor Qt version as settings versions to avoid conflicts
114{
115 const int version = QT_VERSION;
116 return (version & 0x00FF00) >> 8;
117}
118
119// ----------------- DockedMdiArea
120
121DockedMdiArea::DockedMdiArea(const QString &extension, QWidget *parent) :
122 QMdiArea(parent),
123 m_extension(extension)
124{
125 setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
126 setLineWidth(1);
127 setAcceptDrops(true);
128 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
129 setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
130}
131
132QStringList DockedMdiArea::uiFiles(const QMimeData *d) const
133{
134 // Extract dropped UI files from Mime data.
135 QStringList rc;
136 if (!d->hasFormat("text/uri-list"_L1))
137 return rc;
138 const auto urls = d->urls();
139 if (urls.isEmpty())
140 return rc;
141 for (const auto &url : urls) {
142 const QString fileName = url.toLocalFile();
143 if (!fileName.isEmpty() && fileName.endsWith(m_extension))
144 rc.push_back(fileName);
145 }
146 return rc;
147}
148
149bool DockedMdiArea::event(QEvent *event)
150{
151 // Listen for desktop file manager drop and emit a signal once a file is
152 // dropped.
153 switch (event->type()) {
154 case QEvent::DragEnter: {
155 auto *e = static_cast<QDragEnterEvent*>(event);
156 if (!uiFiles(e->mimeData()).isEmpty()) {
157 e->acceptProposedAction();
158 return true;
159 }
160 }
161 break;
162 case QEvent::Drop: {
163 auto *e = static_cast<QDropEvent*>(event);
164 const QStringList files = uiFiles(e->mimeData());
165 for (const auto &f : files)
166 emit fileDropped(f);
167 e->acceptProposedAction();
168 return true;
169 }
170 break;
171 default:
172 break;
173 }
174 return QMdiArea::event(event);
175}
176
177// ------------- ToolBarManager:
178
179static void addActionsToToolBarManager(const ActionList &al, const QString &title, QtToolBarManager *tbm)
180{
181 for (QAction *action : al)
182 tbm->addAction(action, title);
183}
184
185ToolBarManager::ToolBarManager(QMainWindow *configureableMainWindow,
186 QWidget *parent,
187 QMenu *toolBarMenu,
188 const QDesignerActions *actions,
189 const QList<QToolBar *> &toolbars,
190 const QList<QDesignerToolWindow *> &toolWindows) :
191 QObject(parent),
192 m_configureableMainWindow(configureableMainWindow),
193 m_parent(parent),
194 m_toolBarMenu(toolBarMenu),
195 m_manager(new QtToolBarManager(this)),
196 m_configureAction(new QAction(tr("Configure Toolbars..."), this)),
197 m_toolbars(toolbars)
198{
199 m_configureAction->setMenuRole(QAction::NoRole);
200 m_configureAction->setObjectName(u"__qt_configure_tool_bars_action"_s);
201 connect(m_configureAction, &QAction::triggered, this, &ToolBarManager::configureToolBars);
202
203 m_manager->setMainWindow(configureableMainWindow);
204
205 for (QToolBar *tb : std::as_const(m_toolbars)) {
206 const QString title = tb->windowTitle();
207 m_manager->addToolBar(tb, title);
208 addActionsToToolBarManager(tb->actions(), title, m_manager);
209 }
210
211 addActionsToToolBarManager(actions->windowActions()->actions(), tr("Window"), m_manager);
212 addActionsToToolBarManager(actions->helpActions()->actions(), tr("Help"), m_manager);
213
214 // Filter out the device profile preview actions which have int data().
215 ActionList previewActions = actions->styleActions()->actions();
216 auto it = previewActions.begin();
217 for ( ; (*it)->isSeparator() || (*it)->data().metaType().id() == QMetaType::Int; ++it) ;
218 previewActions.erase(previewActions.begin(), it);
219 addActionsToToolBarManager(previewActions, tr("Style"), m_manager);
220
221 const QString dockTitle = tr("Dock views");
222 for (QDesignerToolWindow *tw : toolWindows) {
223 if (QAction *action = tw->action())
224 m_manager->addAction(action, dockTitle);
225 }
226
227 addActionsToToolBarManager(actions->fileActions()->actions(), tr("File"), m_manager);
228 addActionsToToolBarManager(actions->editActions()->actions(), tr("Edit"), m_manager);
229 addActionsToToolBarManager(actions->toolActions()->actions(), tr("Tools"), m_manager);
230 addActionsToToolBarManager(actions->formActions()->actions(), tr("Form"), m_manager);
231
232 m_manager->addAction(m_configureAction, tr("Toolbars"));
233 updateToolBarMenu();
234}
235
236// sort function for sorting tool bars alphabetically by title [non-static since called from template]
237
238bool toolBarTitleLessThan(const QToolBar *t1, const QToolBar *t2)
239{
240 return t1->windowTitle() < t2->windowTitle();
241}
242
243void ToolBarManager::updateToolBarMenu()
244{
245 // Sort tool bars alphabetically by title
246 std::stable_sort(m_toolbars.begin(), m_toolbars.end(), toolBarTitleLessThan);
247 // add to menu
248 m_toolBarMenu->clear();
249 for (QToolBar *tb : std::as_const(m_toolbars))
250 m_toolBarMenu->addAction(tb->toggleViewAction());
251 m_toolBarMenu->addAction(m_configureAction);
252}
253
254void ToolBarManager::configureToolBars()
255{
256 QtToolBarDialog dlg(m_parent);
257 dlg.setToolBarManager(m_manager);
258 dlg.exec();
259 updateToolBarMenu();
260}
261
263{
264 return m_manager->saveState(version);
265}
266
267bool ToolBarManager::restoreState(const QByteArray &state, int version)
268{
269 return m_manager->restoreState(state, version);
270}
271
272// ---------- DockedMainWindow
273
275 QMenu *toolBarMenu,
276 const QList<QDesignerToolWindow *> &toolWindows)
277{
278 setObjectName(u"MDIWindow"_s);
279 setWindowTitle(mainWindowTitle());
280
281 const QList<QToolBar *> toolbars = createToolBars(wb->actionManager(), false);
282 for (QToolBar *tb : toolbars)
283 addToolBar(tb);
284 auto *dma = new DockedMdiArea(wb->actionManager()->uiExtension());
285 connect(dma, &DockedMdiArea::fileDropped,
286 this, &DockedMainWindow::fileDropped);
287 connect(dma, &QMdiArea::subWindowActivated,
288 this, &DockedMainWindow::slotSubWindowActivated);
289 setCentralWidget(dma);
290
291 QStatusBar *sb = statusBar();
292 Q_UNUSED(sb);
293
294 m_toolBarManager = new ToolBarManager(this, this, toolBarMenu, wb->actionManager(), toolbars, toolWindows);
295}
296
297QMdiArea *DockedMainWindow::mdiArea() const
298{
299 return static_cast<QMdiArea *>(centralWidget());
300}
301
302void DockedMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow)
303{
304 if (subWindow) {
305 QWidget *widget = subWindow->widget();
306 if (auto *fw = qobject_cast<QDesignerFormWindow*>(widget)) {
307 emit formWindowActivated(fw);
308 mdiArea()->setActiveSubWindow(subWindow);
309 }
310 }
311}
312
313// Create a MDI subwindow for the form.
314QMdiSubWindow *DockedMainWindow::createMdiSubWindow(QWidget *fw, Qt::WindowFlags f, const QKeySequence &designerCloseActionShortCut)
315{
316 QMdiSubWindow *rc = mdiArea()->addSubWindow(fw, f);
317 // Make action shortcuts respond only if focused to avoid conflicts with
318 // designer menu actions
319 if (designerCloseActionShortCut == QKeySequence(QKeySequence::Close)) {
320 const ActionList systemMenuActions = rc->systemMenu()->actions();
321 for (auto *a : systemMenuActions) {
322 if (a->shortcut() == designerCloseActionShortCut) {
323 a->setShortcutContext(Qt::WidgetShortcut);
324 break;
325 }
326 }
327 }
328 return rc;
329}
330
332{
333 DockWidgetList rc;
334 for (QDesignerToolWindow *tw : tls) {
335 auto *dockWidget = new QDockWidget;
336 dockWidget->setObjectName(tw->objectName() + "_dock"_L1);
337 dockWidget->setWindowTitle(tw->windowTitle());
338 addDockWidget(tw->dockWidgetAreaHint(), dockWidget);
339 dockWidget->setWidget(tw);
340 rc.push_back(dockWidget);
341 }
342 return rc;
343}
344
345// Settings consist of MainWindow state and tool bar manager state
346void DockedMainWindow::restoreSettings(const QDesignerSettings &s, const DockWidgetList &dws, const QRect &desktopArea)
347{
348 const int version = settingsVersion();
349 m_toolBarManager->restoreState(s.toolBarsState(DockedMode), version);
350
351 // If there are no old geometry settings, show the window maximized
352 s.restoreGeometry(this, QRect(desktopArea.topLeft(), QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)));
353
354 const QByteArray mainWindowState = s.mainWindowState(DockedMode);
355 const bool restored = !mainWindowState.isEmpty() && restoreState(mainWindowState, version);
356 if (!restored) {
357 // Default: Tabify less relevant windows bottom/right.
358 tabifyDockWidget(dws.at(QDesignerToolWindow::SignalSlotEditor),
360 tabifyDockWidget(dws.at(QDesignerToolWindow::ActionEditor),
362 }
363}
364
366{
367 const int version = settingsVersion();
368 s.setToolBarsState(DockedMode, m_toolBarManager->saveState(version));
369 s.saveGeometryFor(this);
370 s.setMainWindowState(DockedMode, saveState(version));
371}
372
373QT_END_NAMESPACE
void restoreSettings(const QDesignerSettings &s, const DockWidgetList &dws, const QRect &desktopArea)
DockedMainWindow(QDesignerWorkbench *wb, QMenu *toolBarMenu, const DesignerToolWindowList &toolWindows)
DockWidgetList addToolWindows(const DesignerToolWindowList &toolWindows)
void saveSettings(QDesignerSettings &) const
QMdiSubWindow * createMdiSubWindow(QWidget *fw, Qt::WindowFlags f, const QKeySequence &designerCloseActionShortCut)
QMdiArea * mdiArea() const
bool event(QEvent *event) override
void closeEvent(QCloseEvent *e) override
This event handler is called with the given event when Qt receives a window close request for a top-l...
static int settingsVersion()
QActionGroup * helpActions() const
QActionGroup * fileActions() const
QActionGroup * styleActions() const
QActionGroup * editActions() const
QActionGroup * formActions() const
QActionGroup * toolActions() const
QActionGroup * windowActions() const
void setToolBarsState(UIMode mode, const QByteArray &mainWindowState)
void setMainWindowState(UIMode mode, const QByteArray &mainWindowState)
QByteArray toolBarsState(UIMode mode) const
void saveGeometryFor(const QWidget *w)
QDesignerActions * actionManager() const
friend class QWidget
Definition qpainter.h:432
The QtToolBarDialog class provides a dialog for customizing toolbars.
void setToolBarManager(QtToolBarManager *toolBarManager)
Connects the toolbar dialog to the given toolBarManager.
The QtToolBarManager class provides toolbar management for main windows.
QByteArray saveState(int version=0) const
Saves the state of the toolbar manager's toolbars.
void addAction(QAction *action, const QString &category)
Adds the given action to the given category in the manager's list of actions.
bool restoreState(const QByteArray &state, int version=0)
Restores the saved state of the toolbar manager's toolbars.
void setMainWindow(QMainWindow *mainWindow)
Sets the main window upon which the toolbar manager operates, to be the given mainWindow.
QByteArray saveState(int version=0) const
bool restoreState(const QByteArray &state, int version=0)
#define qDesigner
Definition qdesigner.h:20
static void addActionsToToolBar(const ActionList &actions, QToolBar *t)
static void addActionsToToolBarManager(const ActionList &al, const QString &title, QtToolBarManager *tbm)
static QToolBar * createToolBar(const QString &title, const QString &objectName, const ActionList &actions)
bool toolBarTitleLessThan(const QToolBar *t1, const QToolBar *t2)