/******************************************************************************** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).** All rights reserved.** Contact: Nokia Corporation (qt-info@nokia.com)**** This file is part of the demonstration applications of the Qt Toolkit.**** $QT_BEGIN_LICENSE:LGPL$** No Commercial Usage** This file contains pre-release code and may not be distributed.** You may use this file in accordance with the terms and conditions** contained in the Technology Preview License Agreement accompanying** this package.**** 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 as published by the Free Software** Foundation and appearing in the file LICENSE.LGPL included in the** packaging of this file. Please review the following information to** ensure the GNU Lesser General Public License version 2.1 requirements** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.**** In addition, as a special exception, Nokia gives you certain additional** rights. These rights are described in the Nokia Qt LGPL Exception** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.**** If you have questions regarding the use of this file, please contact** Nokia at qt-info@nokia.com.****************** $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);}