Qt Reference Documentation

mainwindow.cpp Example File

demos/mainwindow/mainwindow.cpp
 /****************************************************************************
 **
 ** 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:LGPL$
 ** 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.
 **
 ** GNU General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU
 ** General Public License version 3.0 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.  Please review the following information to
 ** ensure the GNU General Public License version 3.0 requirements will be
 ** met: http://www.gnu.org/copyleft/gpl.html.
 **
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

 #include "mainwindow.h"
 #include "colorswatch.h"
 #include "toolbar.h"

 #include <QAction>
 #include <QLayout>
 #include <QMenu>
 #include <QMenuBar>
 #include <QStatusBar>
 #include <QTextEdit>
 #include <QFile>
 #include <QDataStream>
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QSignalMapper>
 #include <QApplication>
 #include <QPainter>
 #include <QMouseEvent>
 #include <QLineEdit>
 #include <QComboBox>
 #include <QLabel>
 #include <QPushButton>
 #include <qdebug.h>

 static const char * const message =
     "<p><b>Qt Main Window Demo</b></p>"

     "<p>This is a demonstration of the QMainWindow, QToolBar and "
     "QDockWidget classes.</p>"

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

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

 #ifdef Q_WS_MAC
     "<p>On Mac OS X, the \"Black\" dock widget has been created as a "
     "<em>Drawer</em>, which is a special kind of QDockWidget.</p>"
 #endif
     ;

 Q_DECLARE_METATYPE(QDockWidget::DockWidgetFeatures)

 MainWindow::MainWindow(const QMap<QString, QSize> &customSizeHints,
                         QWidget *parent, Qt::WindowFlags flags)
     : QMainWindow(parent, flags)
 {
     setObjectName("MainWindow");
     setWindowTitle("Qt Main Window Demo");

     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()
 {
     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"));

     QAction *action = menu->addAction(tr("Save layout..."));
     connect(action, SIGNAL(triggered()), this, SLOT(saveLayout()));

     action = menu->addAction(tr("Load layout..."));
     connect(action, SIGNAL(triggered()), this, SLOT(loadLayout()));

     action = menu->addAction(tr("Switch layout direction"));
     connect(action, SIGNAL(triggered()), this, SLOT(switchLayoutDirection()));

     menu->addSeparator();

     menu->addAction(tr("&Quit"), this, SLOT(close()));

     mainWindowMenu = menuBar()->addMenu(tr("Main window"));

     action = mainWindowMenu->addAction(tr("Animated docks"));
     action->setCheckable(true);
     action->setChecked(dockOptions() & AnimatedDocks);
     connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));

     action = mainWindowMenu->addAction(tr("Allow nested docks"));
     action->setCheckable(true);
     action->setChecked(dockOptions() & AllowNestedDocks);
     connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));

     action = mainWindowMenu->addAction(tr("Allow tabbed docks"));
     action->setCheckable(true);
     action->setChecked(dockOptions() & AllowTabbedDocks);
     connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));

     action = mainWindowMenu->addAction(tr("Force tabbed docks"));
     action->setCheckable(true);
     action->setChecked(dockOptions() & ForceTabbedDocks);
     connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));

     action = mainWindowMenu->addAction(tr("Vertical tabs"));
     action->setCheckable(true);
     action->setChecked(dockOptions() & VerticalTabs);
     connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions()));

     QMenu *toolBarMenu = menuBar()->addMenu(tr("Tool bars"));
     for (int i = 0; i < toolBars.count(); ++i)
         toolBarMenu->addMenu(toolBars.at(i)->menu);

     dockWidgetMenu = menuBar()->addMenu(tr("&Dock Widgets"));
 }

 void MainWindow::setDockOptions()
 {
     DockOptions opts;
     QList<QAction*> 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;

     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(fileName)
                         .arg(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(fileName)
                         .arg(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(fileName)
                         .arg(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(fileName);
         QMessageBox::warning(this, tr("Error"), msg);
         return;
     }
 }

 QAction *addAction(QMenu *menu, const QString &text, QActionGroup *group, QSignalMapper *mapper,
                     int id)
 {
     bool first = group->actions().isEmpty();
     QAction *result = menu->addAction(text);
     result->setCheckable(true);
     result->setChecked(first);
     group->addAction(result);
     QObject::connect(result, SIGNAL(triggered()), mapper, SLOT(map()));
     mapper->setMapping(result, id);
     return result;
 }

 void MainWindow::setupDockWidgets(const QMap<QString, QSize> &customSizeHints)
 {
     qRegisterMetaType<QDockWidget::DockWidgetFeatures>();

     mapper = new QSignalMapper(this);
     connect(mapper, SIGNAL(mapped(int)), this, SLOT(setCorner(int)));

     QMenu *corner_menu = dockWidgetMenu->addMenu(tr("Top left corner"));
     QActionGroup *group = new QActionGroup(this);
     group->setExclusive(true);
     ::addAction(corner_menu, tr("Top dock area"), group, mapper, 0);
     ::addAction(corner_menu, tr("Left dock area"), group, mapper, 1);

     corner_menu = dockWidgetMenu->addMenu(tr("Top right corner"));
     group = new QActionGroup(this);
     group->setExclusive(true);
     ::addAction(corner_menu, tr("Top dock area"), group, mapper, 2);
     ::addAction(corner_menu, tr("Right dock area"), group, mapper, 3);

     corner_menu = dockWidgetMenu->addMenu(tr("Bottom left corner"));
     group = new QActionGroup(this);
     group->setExclusive(true);
     ::addAction(corner_menu, tr("Bottom dock area"), group, mapper, 4);
     ::addAction(corner_menu, tr("Left dock area"), group, mapper, 5);

     corner_menu = dockWidgetMenu->addMenu(tr("Bottom right corner"));
     group = new QActionGroup(this);
     group->setExclusive(true);
     ::addAction(corner_menu, tr("Bottom dock area"), group, mapper, 6);
     ::addAction(corner_menu, tr("Right dock area"), group, mapper, 7);

     dockWidgetMenu->addSeparator();

     static const struct Set {
         const char * name;
         uint flags;
         Qt::DockWidgetArea area;
     } sets [] = {
 #ifndef Q_WS_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);

     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(QIcon(QPixmap(":/res/qt.png")));
         if (qstrcmp(sets[i].name, "Blue") == 0) {
             BlueTitleBar *titlebar = new BlueTitleBar(swatch);
             swatch->setTitleBarWidget(titlebar);
             connect(swatch, SIGNAL(topLevelChanged(bool)), titlebar, SLOT(updateMask()));
             connect(swatch, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), titlebar, SLOT(updateMask()), Qt::QueuedConnection);

 #ifdef Q_WS_QWS
             QPalette pal = palette();
             pal.setBrush(backgroundRole(), QColor(0,0,0,0));
             swatch->setPalette(pal);
 #endif
         }

         QString name = QString::fromLatin1(sets[i].name);
         if (customSizeHints.contains(name))
             swatch->setCustomSizeHint(customSizeHints.value(name));

         addDockWidget(sets[i].area, swatch);
         dockWidgetMenu->addMenu(swatch->menu);
     }

     createDockWidgetAction = new QAction(tr("Add dock widget..."), this);
     connect(createDockWidgetAction, SIGNAL(triggered()), this, SLOT(createDockWidget()));
     destroyDockWidgetMenu = new QMenu(tr("Destroy dock widget"), this);
     destroyDockWidgetMenu->setEnabled(false);
     connect(destroyDockWidgetMenu, SIGNAL(triggered(QAction*)), this, SLOT(destroyDockWidget(QAction*)));

     dockWidgetMenu->addSeparator();
     dockWidgetMenu->addAction(createDockWidgetAction);
     dockWidgetMenu->addMenu(destroyDockWidgetMenu);
 }

 void MainWindow::setCorner(int id)
 {
     switch (id) {
         case 0:
             QMainWindow::setCorner(Qt::TopLeftCorner, Qt::TopDockWidgetArea);
             break;
         case 1:
             QMainWindow::setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
             break;
         case 2:
             QMainWindow::setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea);
             break;
         case 3:
             QMainWindow::setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
             break;
         case 4:
             QMainWindow::setCorner(Qt::BottomLeftCorner, Qt::BottomDockWidgetArea);
             break;
         case 5:
             QMainWindow::setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
             break;
         case 6:
             QMainWindow::setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
             break;
         case 7:
             QMainWindow::setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
             break;
     }
 }

 void MainWindow::showEvent(QShowEvent *event)
 {
     QMainWindow::showEvent(event);
 }

 void MainWindow::switchLayoutDirection()
 {
     if (layoutDirection() == Qt::LeftToRight)
         qApp->setLayoutDirection(Qt::RightToLeft);
     else
         qApp->setLayoutDirection(Qt::LeftToRight);
 }

 class CreateDockWidgetDialog : public QDialog
 {
 public:
     CreateDockWidgetDialog(QWidget *parent = 0);

     QString objectName() const;
     Qt::DockWidgetArea location() const;

 private:
     QLineEdit *m_objectName;
     QComboBox *m_location;
 };

 CreateDockWidgetDialog::CreateDockWidgetDialog(QWidget *parent)
     : QDialog(parent)
 {
     QGridLayout *layout = new QGridLayout(this);

     layout->addWidget(new QLabel(tr("Object name:")), 0, 0);
     m_objectName = new QLineEdit;
     layout->addWidget(m_objectName, 0, 1);

     layout->addWidget(new QLabel(tr("Location:")), 1, 0);
     m_location = new QComboBox;
     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);

     QHBoxLayout *buttonLayout = new QHBoxLayout;
     layout->addLayout(buttonLayout, 2, 0, 1, 2);
     buttonLayout->addStretch();

     QPushButton *cancelButton = new QPushButton(tr("Cancel"));
     connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
     buttonLayout->addWidget(cancelButton);
     QPushButton *okButton = new QPushButton(tr("Ok"));
     connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
     buttonLayout->addWidget(okButton);

     okButton->setDefault(true);
 }

 QString CreateDockWidgetDialog::objectName() const
 {
     return m_objectName->text();
 }

 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);
     int ret = dialog.exec();
     if (ret == QDialog::Rejected)
         return;

     QDockWidget *dw = new QDockWidget;
     dw->setObjectName(dialog.objectName());
     dw->setWindowTitle(dialog.objectName());
     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(dialog.objectName(), 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);
 }