/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the demonstration applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mainwindow.h" #include "colorswatch.h" #include "toolbar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char message[] = "

Qt Main Window Example

" "

This is a demonstration of the QMainWindow, QToolBar and " "QDockWidget classes.

" "

The tool bar and dock widgets can be dragged around and rearranged " "using the mouse or via the menu.

" "

Each dock widget contains a colored frame and a context " "(right-click) menu.

" #ifdef Q_OS_MAC "

On OS X, the \"Black\" dock widget has been created as a " "Drawer, which is a special kind of QDockWidget.

" #endif ; Q_DECLARE_METATYPE(QDockWidget::DockWidgetFeatures) MainWindow::MainWindow(const CustomSizeHintMap &customSizeHints, QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) { setObjectName("MainWindow"); setWindowTitle("Qt Main Window Example"); QTextEdit *center = new QTextEdit(this); center->setReadOnly(true); center->setMinimumSize(400, 205); setCentralWidget(center); setupToolBar(); setupMenuBar(); setupDockWidgets(customSizeHints); statusBar()->showMessage(tr("Status Bar")); } void MainWindow::actionTriggered(QAction *action) { qDebug("action '%s' triggered", action->text().toLocal8Bit().data()); } void MainWindow::setupToolBar() { #ifdef Q_OS_OSX setUnifiedTitleAndToolBarOnMac(true); #endif for (int i = 0; i < 3; ++i) { ToolBar *tb = new ToolBar(QString::fromLatin1("Tool Bar %1").arg(i + 1), this); toolBars.append(tb); addToolBar(tb); } } void MainWindow::setupMenuBar() { QMenu *menu = menuBar()->addMenu(tr("&File")); menu->addAction(tr("Save layout..."), this, &MainWindow::saveLayout); menu->addAction(tr("Load layout..."), this, &MainWindow::loadLayout); menu->addAction(tr("Switch layout direction"),this, &MainWindow::switchLayoutDirection); menu->addSeparator(); menu->addAction(tr("&Quit"), this, &QWidget::close); mainWindowMenu = menuBar()->addMenu(tr("Main window")); QAction *action = mainWindowMenu->addAction(tr("Animated docks")); action->setCheckable(true); action->setChecked(dockOptions() & AnimatedDocks); connect(action, &QAction::toggled, this, &MainWindow::setDockOptions); action = mainWindowMenu->addAction(tr("Allow nested docks")); action->setCheckable(true); action->setChecked(dockOptions() & AllowNestedDocks); connect(action, &QAction::toggled, this, &MainWindow::setDockOptions); action = mainWindowMenu->addAction(tr("Allow tabbed docks")); action->setCheckable(true); action->setChecked(dockOptions() & AllowTabbedDocks); connect(action, &QAction::toggled, this, &MainWindow::setDockOptions); action = mainWindowMenu->addAction(tr("Force tabbed docks")); action->setCheckable(true); action->setChecked(dockOptions() & ForceTabbedDocks); connect(action, &QAction::toggled, this, &MainWindow::setDockOptions); action = mainWindowMenu->addAction(tr("Vertical tabs")); action->setCheckable(true); action->setChecked(dockOptions() & VerticalTabs); connect(action, &QAction::toggled, this, &MainWindow::setDockOptions); action = mainWindowMenu->addAction(tr("Grouped dragging")); action->setCheckable(true); action->setChecked(dockOptions() & GroupedDragging); connect(action, &QAction::toggled, this, &MainWindow::setDockOptions); QMenu *toolBarMenu = menuBar()->addMenu(tr("Tool bars")); for (int i = 0; i < toolBars.count(); ++i) toolBarMenu->addMenu(toolBars.at(i)->toolbarMenu()); #ifdef Q_OS_OSX toolBarMenu->addSeparator(); action = toolBarMenu->addAction(tr("Unified")); action->setCheckable(true); action->setChecked(unifiedTitleAndToolBarOnMac()); connect(action, &QAction::toggled, this, &QMainWindow::setUnifiedTitleAndToolBarOnMac); #endif dockWidgetMenu = menuBar()->addMenu(tr("&Dock Widgets")); } void MainWindow::setDockOptions() { DockOptions opts; QList actions = mainWindowMenu->actions(); if (actions.at(0)->isChecked()) opts |= AnimatedDocks; if (actions.at(1)->isChecked()) opts |= AllowNestedDocks; if (actions.at(2)->isChecked()) opts |= AllowTabbedDocks; if (actions.at(3)->isChecked()) opts |= ForceTabbedDocks; if (actions.at(4)->isChecked()) opts |= VerticalTabs; if (actions.at(5)->isChecked()) opts |= GroupedDragging; QMainWindow::setDockOptions(opts); } void MainWindow::saveLayout() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save layout")); if (fileName.isEmpty()) return; QFile file(fileName); if (!file.open(QFile::WriteOnly)) { QString msg = tr("Failed to open %1\n%2") .arg(QDir::toNativeSeparators(fileName), file.errorString()); QMessageBox::warning(this, tr("Error"), msg); return; } QByteArray geo_data = saveGeometry(); QByteArray layout_data = saveState(); bool ok = file.putChar((uchar)geo_data.size()); if (ok) ok = file.write(geo_data) == geo_data.size(); if (ok) ok = file.write(layout_data) == layout_data.size(); if (!ok) { QString msg = tr("Error writing to %1\n%2") .arg(QDir::toNativeSeparators(fileName), file.errorString()); QMessageBox::warning(this, tr("Error"), msg); return; } } void MainWindow::loadLayout() { QString fileName = QFileDialog::getOpenFileName(this, tr("Load layout")); if (fileName.isEmpty()) return; QFile file(fileName); if (!file.open(QFile::ReadOnly)) { QString msg = tr("Failed to open %1\n%2") .arg(QDir::toNativeSeparators(fileName), file.errorString()); QMessageBox::warning(this, tr("Error"), msg); return; } uchar geo_size; QByteArray geo_data; QByteArray layout_data; bool ok = file.getChar((char*)&geo_size); if (ok) { geo_data = file.read(geo_size); ok = geo_data.size() == geo_size; } if (ok) { layout_data = file.readAll(); ok = layout_data.size() > 0; } if (ok) ok = restoreGeometry(geo_data); if (ok) ok = restoreState(layout_data); if (!ok) { QString msg = tr("Error reading %1").arg(QDir::toNativeSeparators(fileName)); QMessageBox::warning(this, tr("Error"), msg); return; } } class DockWidgetAreaCornerFunctor { public: explicit DockWidgetAreaCornerFunctor(QMainWindow *mw, Qt::Corner c, Qt::DockWidgetArea a) : m_mainWindow(mw), m_area(a), m_corner(c) {} void operator()() const { m_mainWindow->setCorner(m_corner, m_area); } private: QMainWindow *m_mainWindow; Qt::DockWidgetArea m_area; Qt::Corner m_corner; }; static QAction *addCornerAction(const QString &text, QMainWindow *mw, QMenu *menu, QActionGroup *group, Qt::Corner c, Qt::DockWidgetArea a) { QAction *result = menu->addAction(text, mw, DockWidgetAreaCornerFunctor(mw, c, a)); result->setCheckable(true); group->addAction(result); return result; } void MainWindow::setupDockWidgets(const CustomSizeHintMap &customSizeHints) { qRegisterMetaType(); QMenu *cornerMenu = dockWidgetMenu->addMenu(tr("Top left corner")); QActionGroup *group = new QActionGroup(this); group->setExclusive(true); QAction *cornerAction = addCornerAction(tr("Top dock area"), this, cornerMenu, group, Qt::TopLeftCorner, Qt::TopDockWidgetArea); cornerAction->setChecked(true); addCornerAction(tr("Left dock area"), this, cornerMenu, group, Qt::TopLeftCorner, Qt::LeftDockWidgetArea); cornerMenu = dockWidgetMenu->addMenu(tr("Top right corner")); group = new QActionGroup(this); group->setExclusive(true); cornerAction = addCornerAction(tr("Top dock area"), this, cornerMenu, group, Qt::TopRightCorner, Qt::TopDockWidgetArea); cornerAction->setChecked(true); addCornerAction(tr("Right dock area"), this, cornerMenu, group, Qt::TopRightCorner, Qt::RightDockWidgetArea); cornerMenu = dockWidgetMenu->addMenu(tr("Bottom left corner")); group = new QActionGroup(this); group->setExclusive(true); cornerAction = addCornerAction(tr("Bottom dock area"), this, cornerMenu, group, Qt::BottomLeftCorner, Qt::BottomDockWidgetArea); cornerAction->setChecked(true); addCornerAction(tr("Left dock area"), this, cornerMenu, group, Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); cornerMenu = dockWidgetMenu->addMenu(tr("Bottom right corner")); group = new QActionGroup(this); group->setExclusive(true); cornerAction = addCornerAction(tr("Bottom dock area"), this, cornerMenu, group, Qt::BottomRightCorner, Qt::BottomDockWidgetArea); cornerAction->setChecked(true); addCornerAction(tr("Right dock area"), this, cornerMenu, group, Qt::BottomRightCorner, Qt::RightDockWidgetArea); dockWidgetMenu->addSeparator(); static const struct Set { const char * name; uint flags; Qt::DockWidgetArea area; } sets [] = { #ifndef Q_OS_MAC { "Black", 0, Qt::LeftDockWidgetArea }, #else { "Black", Qt::Drawer, Qt::LeftDockWidgetArea }, #endif { "White", 0, Qt::RightDockWidgetArea }, { "Red", 0, Qt::TopDockWidgetArea }, { "Green", 0, Qt::TopDockWidgetArea }, { "Blue", 0, Qt::BottomDockWidgetArea }, { "Yellow", 0, Qt::BottomDockWidgetArea } }; const int setCount = sizeof(sets) / sizeof(Set); const QIcon qtIcon(QPixmap(":/res/qt.png")); for (int i = 0; i < setCount; ++i) { ColorSwatch *swatch = new ColorSwatch(tr(sets[i].name), this, Qt::WindowFlags(sets[i].flags)); if (i % 2) swatch->setWindowIcon(qtIcon); if (qstrcmp(sets[i].name, "Blue") == 0) { BlueTitleBar *titlebar = new BlueTitleBar(swatch); swatch->setTitleBarWidget(titlebar); connect(swatch, &QDockWidget::topLevelChanged, titlebar, &BlueTitleBar::updateMask); connect(swatch, &QDockWidget::featuresChanged, titlebar, &BlueTitleBar::updateMask, Qt::QueuedConnection); } QString name = QString::fromLatin1(sets[i].name); if (customSizeHints.contains(name)) swatch->setCustomSizeHint(customSizeHints.value(name)); addDockWidget(sets[i].area, swatch); dockWidgetMenu->addMenu(swatch->colorSwatchMenu()); } destroyDockWidgetMenu = new QMenu(tr("Destroy dock widget"), this); destroyDockWidgetMenu->setEnabled(false); connect(destroyDockWidgetMenu, &QMenu::triggered, this, &MainWindow::destroyDockWidget); dockWidgetMenu->addSeparator(); dockWidgetMenu->addAction(tr("Add dock widget..."), this, &MainWindow::createDockWidget); dockWidgetMenu->addMenu(destroyDockWidgetMenu); } void MainWindow::switchLayoutDirection() { if (layoutDirection() == Qt::LeftToRight) QApplication::setLayoutDirection(Qt::RightToLeft); else QApplication::setLayoutDirection(Qt::LeftToRight); } class CreateDockWidgetDialog : public QDialog { public: explicit CreateDockWidgetDialog(QWidget *parent = Q_NULLPTR); QString enteredObjectName() const { return m_objectName->text(); } Qt::DockWidgetArea location() const; private: QLineEdit *m_objectName; QComboBox *m_location; }; CreateDockWidgetDialog::CreateDockWidgetDialog(QWidget *parent) : QDialog(parent) , m_objectName(new QLineEdit(this)) , m_location(new QComboBox(this)) { setWindowTitle(tr("Add Dock Widget")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); QGridLayout *layout = new QGridLayout(this); layout->addWidget(new QLabel(tr("Object name:")), 0, 0); layout->addWidget(m_objectName, 0, 1); layout->addWidget(new QLabel(tr("Location:")), 1, 0); m_location->setEditable(false); m_location->addItem(tr("Top")); m_location->addItem(tr("Left")); m_location->addItem(tr("Right")); m_location->addItem(tr("Bottom")); m_location->addItem(tr("Restore")); layout->addWidget(m_location, 1, 1); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::reject); layout->addWidget(buttonBox, 2, 0, 1, 2); } Qt::DockWidgetArea CreateDockWidgetDialog::location() const { switch (m_location->currentIndex()) { case 0: return Qt::TopDockWidgetArea; case 1: return Qt::LeftDockWidgetArea; case 2: return Qt::RightDockWidgetArea; case 3: return Qt::BottomDockWidgetArea; default: break; } return Qt::NoDockWidgetArea; } void MainWindow::createDockWidget() { CreateDockWidgetDialog dialog(this); if (dialog.exec() == QDialog::Rejected) return; QDockWidget *dw = new QDockWidget; const QString name = dialog.enteredObjectName(); dw->setObjectName(name); dw->setWindowTitle(name); dw->setWidget(new QTextEdit); Qt::DockWidgetArea area = dialog.location(); switch (area) { case Qt::LeftDockWidgetArea: case Qt::RightDockWidgetArea: case Qt::TopDockWidgetArea: case Qt::BottomDockWidgetArea: addDockWidget(area, dw); break; default: if (!restoreDockWidget(dw)) { QMessageBox::warning(this, QString(), tr("Failed to restore dock widget")); delete dw; return; } break; } extraDockWidgets.append(dw); destroyDockWidgetMenu->setEnabled(true); destroyDockWidgetMenu->addAction(new QAction(name, this)); } void MainWindow::destroyDockWidget(QAction *action) { int index = destroyDockWidgetMenu->actions().indexOf(action); delete extraDockWidgets.takeAt(index); destroyDockWidgetMenu->removeAction(action); action->deleteLater(); if (destroyDockWidgetMenu->isEmpty()) destroyDockWidgetMenu->setEnabled(false); }