summaryrefslogtreecommitdiffstats
path: root/tests/manual/examples/widgets/mainwindows/mdi
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/examples/widgets/mainwindows/mdi')
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/CMakeLists.txt55
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/images/copy.pngbin0 -> 1338 bytes
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/images/cut.pngbin0 -> 1323 bytes
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/images/new.pngbin0 -> 852 bytes
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/images/open.pngbin0 -> 2073 bytes
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/images/paste.pngbin0 -> 1645 bytes
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/images/save.pngbin0 -> 2699 bytes
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/main.cpp29
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/mainwindow.cpp476
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/mainwindow.h87
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/mdi.pro13
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/mdi.qrc10
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/mdichild.cpp158
-rw-r--r--tests/manual/examples/widgets/mainwindows/mdi/mdichild.h39
14 files changed, 867 insertions, 0 deletions
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/CMakeLists.txt b/tests/manual/examples/widgets/mainwindows/mdi/CMakeLists.txt
new file mode 100644
index 0000000000..2f544b9510
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/CMakeLists.txt
@@ -0,0 +1,55 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(mdi LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/mainwindows/mdi")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(mdi
+ main.cpp
+ mainwindow.cpp mainwindow.h
+ mdichild.cpp mdichild.h
+)
+
+set_target_properties(mdi PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(mdi PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+# Resources:
+set(mdi_resource_files
+ "images/copy.png"
+ "images/cut.png"
+ "images/new.png"
+ "images/open.png"
+ "images/paste.png"
+ "images/save.png"
+)
+
+qt_add_resources(mdi "mdi"
+ PREFIX
+ "/"
+ FILES
+ ${mdi_resource_files}
+)
+
+install(TARGETS mdi
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/copy.png b/tests/manual/examples/widgets/mainwindows/mdi/images/copy.png
new file mode 100644
index 0000000000..2aeb28288f
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/images/copy.png
Binary files differ
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/cut.png b/tests/manual/examples/widgets/mainwindows/mdi/images/cut.png
new file mode 100644
index 0000000000..54638e9386
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/images/cut.png
Binary files differ
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/new.png b/tests/manual/examples/widgets/mainwindows/mdi/images/new.png
new file mode 100644
index 0000000000..12131b0100
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/images/new.png
Binary files differ
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/open.png b/tests/manual/examples/widgets/mainwindows/mdi/images/open.png
new file mode 100644
index 0000000000..45fa2883a7
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/images/open.png
Binary files differ
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/paste.png b/tests/manual/examples/widgets/mainwindows/mdi/images/paste.png
new file mode 100644
index 0000000000..c14425cad1
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/images/paste.png
Binary files differ
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/save.png b/tests/manual/examples/widgets/mainwindows/mdi/images/save.png
new file mode 100644
index 0000000000..e65a29d5f1
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/images/save.png
Binary files differ
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/main.cpp b/tests/manual/examples/widgets/mainwindows/mdi/main.cpp
new file mode 100644
index 0000000000..ee70050544
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/main.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+#include <QCommandLineParser>
+#include <QCommandLineOption>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QCoreApplication::setApplicationName("MDI Example");
+ QCoreApplication::setOrganizationName("QtProject");
+ QCoreApplication::setApplicationVersion(QT_VERSION_STR);
+ QCommandLineParser parser;
+ parser.setApplicationDescription("Qt MDI Example");
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addPositionalArgument("file", "The file to open.");
+ parser.process(app);
+
+ MainWindow mainWin;
+ const QStringList posArgs = parser.positionalArguments();
+ for (const QString &fileName : posArgs)
+ mainWin.openFile(fileName);
+ mainWin.show();
+ return app.exec();
+}
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/mainwindow.cpp b/tests/manual/examples/widgets/mainwindows/mdi/mainwindow.cpp
new file mode 100644
index 0000000000..c0f9091002
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/mainwindow.cpp
@@ -0,0 +1,476 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtWidgets>
+
+#include "mainwindow.h"
+#include "mdichild.h"
+
+MainWindow::MainWindow()
+ : mdiArea(new QMdiArea)
+{
+ mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ setCentralWidget(mdiArea);
+ connect(mdiArea, &QMdiArea::subWindowActivated,
+ this, &MainWindow::updateMenus);
+
+ createActions();
+ createStatusBar();
+ updateMenus();
+
+ readSettings();
+
+ setWindowTitle(tr("MDI"));
+ setUnifiedTitleAndToolBarOnMac(true);
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ mdiArea->closeAllSubWindows();
+ if (mdiArea->currentSubWindow()) {
+ event->ignore();
+ } else {
+ writeSettings();
+ event->accept();
+ }
+}
+
+void MainWindow::newFile()
+{
+ MdiChild *child = createMdiChild();
+ child->newFile();
+ child->show();
+}
+
+void MainWindow::open()
+{
+ const QString fileName = QFileDialog::getOpenFileName(this);
+ if (!fileName.isEmpty())
+ openFile(fileName);
+}
+
+bool MainWindow::openFile(const QString &fileName)
+{
+ if (QMdiSubWindow *existing = findMdiChild(fileName)) {
+ mdiArea->setActiveSubWindow(existing);
+ return true;
+ }
+ const bool succeeded = loadFile(fileName);
+ if (succeeded)
+ statusBar()->showMessage(tr("File loaded"), 2000);
+ return succeeded;
+}
+
+bool MainWindow::loadFile(const QString &fileName)
+{
+ MdiChild *child = createMdiChild();
+ const bool succeeded = child->loadFile(fileName);
+ if (succeeded)
+ child->show();
+ else
+ child->close();
+ MainWindow::prependToRecentFiles(fileName);
+ return succeeded;
+}
+
+void MainWindow::newSubWindow()
+{
+ MdiChild *child = createMdiChild(static_cast<MdiChild *>(mdiArea->activeSubWindow()->widget()));
+ child->show();
+}
+
+static inline QString recentFilesKey() { return QStringLiteral("recentFileList"); }
+static inline QString fileKey() { return QStringLiteral("file"); }
+
+static QStringList readRecentFiles(QSettings &settings)
+{
+ QStringList result;
+ const int count = settings.beginReadArray(recentFilesKey());
+ for (int i = 0; i < count; ++i) {
+ settings.setArrayIndex(i);
+ result.append(settings.value(fileKey()).toString());
+ }
+ settings.endArray();
+ return result;
+}
+
+static void writeRecentFiles(const QStringList &files, QSettings &settings)
+{
+ const int count = files.size();
+ settings.beginWriteArray(recentFilesKey());
+ for (int i = 0; i < count; ++i) {
+ settings.setArrayIndex(i);
+ settings.setValue(fileKey(), files.at(i));
+ }
+ settings.endArray();
+}
+
+bool MainWindow::hasRecentFiles()
+{
+ QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
+ const int count = settings.beginReadArray(recentFilesKey());
+ settings.endArray();
+ return count > 0;
+}
+
+void MainWindow::prependToRecentFiles(const QString &fileName)
+{
+ QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
+
+ const QStringList oldRecentFiles = readRecentFiles(settings);
+ QStringList recentFiles = oldRecentFiles;
+ recentFiles.removeAll(fileName);
+ recentFiles.prepend(fileName);
+ if (oldRecentFiles != recentFiles)
+ writeRecentFiles(recentFiles, settings);
+
+ setRecentFilesVisible(!recentFiles.isEmpty());
+}
+
+void MainWindow::setRecentFilesVisible(bool visible)
+{
+ recentFileSubMenuAct->setVisible(visible);
+ recentFileSeparator->setVisible(visible);
+}
+
+void MainWindow::updateRecentFileActions()
+{
+ QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
+
+ const QStringList recentFiles = readRecentFiles(settings);
+ const int count = qMin(int(MaxRecentFiles), recentFiles.size());
+ int i = 0;
+ for ( ; i < count; ++i) {
+ const QString fileName = QFileInfo(recentFiles.at(i)).fileName();
+ recentFileActs[i]->setText(tr("&%1 %2").arg(i + 1).arg(fileName));
+ recentFileActs[i]->setData(recentFiles.at(i));
+ recentFileActs[i]->setVisible(true);
+ }
+ for ( ; i < MaxRecentFiles; ++i)
+ recentFileActs[i]->setVisible(false);
+}
+
+void MainWindow::openRecentFile()
+{
+ if (const QAction *action = qobject_cast<const QAction *>(sender()))
+ openFile(action->data().toString());
+}
+
+void MainWindow::save()
+{
+ if (activeMdiChild() && activeMdiChild()->save())
+ statusBar()->showMessage(tr("File saved"), 2000);
+}
+
+void MainWindow::saveAs()
+{
+ MdiChild *child = activeMdiChild();
+ if (child && child->saveAs()) {
+ statusBar()->showMessage(tr("File saved"), 2000);
+ MainWindow::prependToRecentFiles(child->currentFile());
+ }
+}
+
+#ifndef QT_NO_CLIPBOARD
+void MainWindow::cut()
+{
+ if (activeMdiChild())
+ activeMdiChild()->cut();
+}
+
+void MainWindow::copy()
+{
+ if (activeMdiChild())
+ activeMdiChild()->copy();
+}
+
+void MainWindow::paste()
+{
+ if (activeMdiChild())
+ activeMdiChild()->paste();
+}
+#endif
+
+void MainWindow::about()
+{
+ QMessageBox::about(this, tr("About MDI"),
+ tr("The <b>MDI</b> example demonstrates how to write multiple "
+ "document interface applications using Qt."));
+}
+
+void MainWindow::updateMenus()
+{
+ bool hasMdiChild = (activeMdiChild() != nullptr);
+ saveAct->setEnabled(hasMdiChild);
+ saveAsAct->setEnabled(hasMdiChild);
+#ifndef QT_NO_CLIPBOARD
+ pasteAct->setEnabled(hasMdiChild);
+#endif
+ newWindowAct->setEnabled(hasMdiChild);
+ closeAct->setEnabled(hasMdiChild);
+ closeAllAct->setEnabled(hasMdiChild);
+ tileAct->setEnabled(hasMdiChild);
+ cascadeAct->setEnabled(hasMdiChild);
+ nextAct->setEnabled(hasMdiChild);
+ previousAct->setEnabled(hasMdiChild);
+ windowMenuSeparatorAct->setVisible(hasMdiChild);
+
+#ifndef QT_NO_CLIPBOARD
+ bool hasSelection = (activeMdiChild() &&
+ activeMdiChild()->textCursor().hasSelection());
+ cutAct->setEnabled(hasSelection);
+ copyAct->setEnabled(hasSelection);
+#endif
+}
+
+void MainWindow::updateWindowMenu()
+{
+ windowMenu->clear();
+ windowMenu->addAction(newWindowAct);
+ windowMenu->addAction(closeAct);
+ windowMenu->addAction(closeAllAct);
+ windowMenu->addSeparator();
+ windowMenu->addAction(tileAct);
+ windowMenu->addAction(cascadeAct);
+ windowMenu->addSeparator();
+ windowMenu->addAction(nextAct);
+ windowMenu->addAction(previousAct);
+ windowMenu->addAction(windowMenuSeparatorAct);
+
+ QList<QMdiSubWindow *> windows = mdiArea->subWindowList();
+ windowMenuSeparatorAct->setVisible(!windows.isEmpty());
+
+ for (int i = 0; i < windows.size(); ++i) {
+ QMdiSubWindow *mdiSubWindow = windows.at(i);
+ MdiChild *child = qobject_cast<MdiChild *>(mdiSubWindow->widget());
+
+ QString text;
+ if (i < 9) {
+ text = tr("&%1 %2").arg(i + 1)
+ .arg(child->userFriendlyCurrentFile());
+ } else {
+ text = tr("%1 %2").arg(i + 1)
+ .arg(child->userFriendlyCurrentFile());
+ }
+ QAction *action = windowMenu->addAction(text, mdiSubWindow, [this, mdiSubWindow]() {
+ mdiArea->setActiveSubWindow(mdiSubWindow);
+ });
+ action->setCheckable(true);
+ action ->setChecked(child == activeMdiChild());
+ }
+}
+
+MdiChild *MainWindow::createMdiChild(MdiChild *other)
+{
+ MdiChild *child = new MdiChild(other);
+ mdiArea->addSubWindow(child);
+
+#ifndef QT_NO_CLIPBOARD
+ connect(child, &QTextEdit::copyAvailable, cutAct, &QAction::setEnabled);
+ connect(child, &QTextEdit::copyAvailable, copyAct, &QAction::setEnabled);
+#endif
+
+ return child;
+}
+
+void MainWindow::createActions()
+{
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+ QToolBar *fileToolBar = addToolBar(tr("File"));
+
+ const QIcon newIcon = QIcon::fromTheme("document-new", QIcon(":/images/new.png"));
+ newAct = new QAction(newIcon, tr("&New"), this);
+ newAct->setShortcuts(QKeySequence::New);
+ newAct->setStatusTip(tr("Create a new file"));
+ connect(newAct, &QAction::triggered, this, &MainWindow::newFile);
+ fileMenu->addAction(newAct);
+ fileToolBar->addAction(newAct);
+
+//! [qaction setup]
+ const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/images/open.png"));
+ QAction *openAct = new QAction(openIcon, tr("&Open..."), this);
+ openAct->setShortcuts(QKeySequence::Open);
+ openAct->setStatusTip(tr("Open an existing file"));
+ connect(openAct, &QAction::triggered, this, &MainWindow::open);
+ fileMenu->addAction(openAct);
+ fileToolBar->addAction(openAct);
+//! [qaction setup]
+
+ const QIcon saveIcon = QIcon::fromTheme("document-save", QIcon(":/images/save.png"));
+ saveAct = new QAction(saveIcon, tr("&Save"), this);
+ saveAct->setShortcuts(QKeySequence::Save);
+ saveAct->setStatusTip(tr("Save the document to disk"));
+ connect(saveAct, &QAction::triggered, this, &MainWindow::save);
+ fileToolBar->addAction(saveAct);
+
+ const QIcon saveAsIcon = QIcon::fromTheme("document-save-as");
+ saveAsAct = new QAction(saveAsIcon, tr("Save &As..."), this);
+ saveAsAct->setShortcuts(QKeySequence::SaveAs);
+ saveAsAct->setStatusTip(tr("Save the document under a new name"));
+ connect(saveAsAct, &QAction::triggered, this, &MainWindow::saveAs);
+ fileMenu->addAction(saveAsAct);
+
+ fileMenu->addSeparator();
+
+ QMenu *recentMenu = fileMenu->addMenu(tr("Recent..."));
+ connect(recentMenu, &QMenu::aboutToShow, this, &MainWindow::updateRecentFileActions);
+ recentFileSubMenuAct = recentMenu->menuAction();
+
+ for (int i = 0; i < MaxRecentFiles; ++i) {
+ recentFileActs[i] = recentMenu->addAction(QString(), this, &MainWindow::openRecentFile);
+ recentFileActs[i]->setVisible(false);
+ }
+
+ recentFileSeparator = fileMenu->addSeparator();
+
+ setRecentFilesVisible(MainWindow::hasRecentFiles());
+
+ fileMenu->addAction(tr("Switch layout direction"), this, &MainWindow::switchLayoutDirection);
+
+ fileMenu->addSeparator();
+
+//! [0]
+ const QIcon exitIcon = QIcon::fromTheme("application-exit");
+ QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), qApp, &QApplication::quit);
+ exitAct->setShortcuts(QKeySequence::Quit);
+ exitAct->setStatusTip(tr("Exit the application"));
+ fileMenu->addAction(exitAct);
+//! [0]
+
+#ifndef QT_NO_CLIPBOARD
+ QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
+ QToolBar *editToolBar = addToolBar(tr("Edit"));
+
+ const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png"));
+ cutAct = new QAction(cutIcon, tr("Cu&t"), this);
+ cutAct->setShortcuts(QKeySequence::Cut);
+ cutAct->setStatusTip(tr("Cut the current selection's contents to the "
+ "clipboard"));
+ connect(cutAct, &QAction::triggered, this, &MainWindow::cut);
+ editMenu->addAction(cutAct);
+ editToolBar->addAction(cutAct);
+
+ const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png"));
+ copyAct = new QAction(copyIcon, tr("&Copy"), this);
+ copyAct->setShortcuts(QKeySequence::Copy);
+ copyAct->setStatusTip(tr("Copy the current selection's contents to the "
+ "clipboard"));
+ connect(copyAct, &QAction::triggered, this, &MainWindow::copy);
+ editMenu->addAction(copyAct);
+ editToolBar->addAction(copyAct);
+
+ const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png"));
+ pasteAct = new QAction(pasteIcon, tr("&Paste"), this);
+ pasteAct->setShortcuts(QKeySequence::Paste);
+ pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
+ "selection"));
+ connect(pasteAct, &QAction::triggered, this, &MainWindow::paste);
+ editMenu->addAction(pasteAct);
+ editToolBar->addAction(pasteAct);
+#endif
+
+ windowMenu = menuBar()->addMenu(tr("&Window"));
+ connect(windowMenu, &QMenu::aboutToShow, this, &MainWindow::updateWindowMenu);
+
+ newWindowAct = new QAction(tr("&New view"), this);
+ newWindowAct->setStatusTip(tr("Make another window viewing the same document"));
+ connect(newWindowAct, &QAction::triggered,
+ this, &MainWindow::newSubWindow);
+
+ closeAct = new QAction(tr("Cl&ose"), this);
+ closeAct->setStatusTip(tr("Close the active window"));
+ connect(closeAct, &QAction::triggered,
+ mdiArea, &QMdiArea::closeActiveSubWindow);
+
+ closeAllAct = new QAction(tr("Close &All"), this);
+ closeAllAct->setStatusTip(tr("Close all the windows"));
+ connect(closeAllAct, &QAction::triggered, mdiArea, &QMdiArea::closeAllSubWindows);
+
+ tileAct = new QAction(tr("&Tile"), this);
+ tileAct->setStatusTip(tr("Tile the windows"));
+ connect(tileAct, &QAction::triggered, mdiArea, &QMdiArea::tileSubWindows);
+
+ cascadeAct = new QAction(tr("&Cascade"), this);
+ cascadeAct->setStatusTip(tr("Cascade the windows"));
+ connect(cascadeAct, &QAction::triggered, mdiArea, &QMdiArea::cascadeSubWindows);
+
+ nextAct = new QAction(tr("Ne&xt"), this);
+ nextAct->setShortcuts(QKeySequence::NextChild);
+ nextAct->setStatusTip(tr("Move the focus to the next window"));
+ connect(nextAct, &QAction::triggered, mdiArea, &QMdiArea::activateNextSubWindow);
+
+ previousAct = new QAction(tr("Pre&vious"), this);
+ previousAct->setShortcuts(QKeySequence::PreviousChild);
+ previousAct->setStatusTip(tr("Move the focus to the previous "
+ "window"));
+ connect(previousAct, &QAction::triggered, mdiArea, &QMdiArea::activatePreviousSubWindow);
+
+ windowMenuSeparatorAct = new QAction(this);
+ windowMenuSeparatorAct->setSeparator(true);
+
+ updateWindowMenu();
+
+ menuBar()->addSeparator();
+
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
+
+ QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::about);
+ aboutAct->setStatusTip(tr("Show the application's About box"));
+
+ QAction *aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
+ aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
+}
+
+void MainWindow::createStatusBar()
+{
+ statusBar()->showMessage(tr("Ready"));
+}
+
+void MainWindow::readSettings()
+{
+ QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
+ const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
+ if (geometry.isEmpty()) {
+ const QRect availableGeometry = screen()->availableGeometry();
+ resize(availableGeometry.width() / 3, availableGeometry.height() / 2);
+ move((availableGeometry.width() - width()) / 2,
+ (availableGeometry.height() - height()) / 2);
+ } else {
+ restoreGeometry(geometry);
+ }
+}
+
+void MainWindow::writeSettings()
+{
+ QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
+ settings.setValue("geometry", saveGeometry());
+}
+
+MdiChild *MainWindow::activeMdiChild() const
+{
+ if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow())
+ return qobject_cast<MdiChild *>(activeSubWindow->widget());
+ return nullptr;
+}
+
+QMdiSubWindow *MainWindow::findMdiChild(const QString &fileName) const
+{
+ QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
+
+ const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
+ for (QMdiSubWindow *window : subWindows) {
+ MdiChild *mdiChild = qobject_cast<MdiChild *>(window->widget());
+ if (mdiChild->currentFile() == canonicalFilePath)
+ return window;
+ }
+ return nullptr;
+}
+
+void MainWindow::switchLayoutDirection()
+{
+ if (layoutDirection() == Qt::LeftToRight)
+ QGuiApplication::setLayoutDirection(Qt::RightToLeft);
+ else
+ QGuiApplication::setLayoutDirection(Qt::LeftToRight);
+}
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/mainwindow.h b/tests/manual/examples/widgets/mainwindows/mdi/mainwindow.h
new file mode 100644
index 0000000000..c8b720e216
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/mainwindow.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+class MdiChild;
+QT_BEGIN_NAMESPACE
+class QAction;
+class QMenu;
+class QMdiArea;
+class QMdiSubWindow;
+class QTextDocument;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+ bool openFile(const QString &fileName);
+
+protected:
+ void closeEvent(QCloseEvent *event) override;
+
+private slots:
+ void newFile();
+ void open();
+ void save();
+ void saveAs();
+ void updateRecentFileActions();
+ void openRecentFile();
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste();
+#endif
+ void about();
+ void updateMenus();
+ void updateWindowMenu();
+ MdiChild *createMdiChild(MdiChild *other = nullptr);
+ void switchLayoutDirection();
+ void newSubWindow();
+
+private:
+ enum { MaxRecentFiles = 5 };
+
+ void createActions();
+ void createStatusBar();
+ void readSettings();
+ void writeSettings();
+ bool loadFile(const QString &fileName);
+ static bool hasRecentFiles();
+ void prependToRecentFiles(const QString &fileName);
+ void setRecentFilesVisible(bool visible);
+ MdiChild *activeMdiChild() const;
+ QMdiSubWindow *findMdiChild(const QString &fileName) const;
+
+ QMdiArea *mdiArea;
+
+ QMenu *windowMenu;
+ QAction *newAct;
+ QAction *saveAct;
+ QAction *saveAsAct;
+ QAction *recentFileActs[MaxRecentFiles];
+ QAction *recentFileSeparator;
+ QAction *recentFileSubMenuAct;
+#ifndef QT_NO_CLIPBOARD
+ QAction *cutAct;
+ QAction *copyAct;
+ QAction *pasteAct;
+#endif
+ QAction *newWindowAct;
+ QAction *closeAct;
+ QAction *closeAllAct;
+ QAction *tileAct;
+ QAction *cascadeAct;
+ QAction *nextAct;
+ QAction *previousAct;
+ QAction *windowMenuSeparatorAct;
+};
+
+#endif
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/mdi.pro b/tests/manual/examples/widgets/mainwindows/mdi/mdi.pro
new file mode 100644
index 0000000000..f2c236f7e2
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/mdi.pro
@@ -0,0 +1,13 @@
+QT += widgets
+requires(qtConfig(filedialog))
+
+HEADERS = mainwindow.h \
+ mdichild.h
+SOURCES = main.cpp \
+ mainwindow.cpp \
+ mdichild.cpp
+RESOURCES = mdi.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/widgets/mainwindows/mdi
+INSTALLS += target
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/mdi.qrc b/tests/manual/examples/widgets/mainwindows/mdi/mdi.qrc
new file mode 100644
index 0000000000..0a776fab4d
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/mdi.qrc
@@ -0,0 +1,10 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>images/copy.png</file>
+ <file>images/cut.png</file>
+ <file>images/new.png</file>
+ <file>images/open.png</file>
+ <file>images/paste.png</file>
+ <file>images/save.png</file>
+</qresource>
+</RCC>
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/mdichild.cpp b/tests/manual/examples/widgets/mainwindows/mdi/mdichild.cpp
new file mode 100644
index 0000000000..b922826ae3
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/mdichild.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtWidgets>
+
+#include "mdichild.h"
+
+MdiChild::MdiChild(MdiChild *other)
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+ if (other) {
+ auto *doc = other->document();
+ setDocument(doc);
+ setWindowModified(other->isWindowModified());
+ connect(doc, &QTextDocument::contentsChanged,
+ this, &MdiChild::documentWasModified);
+ curFile = other->curFile;
+ setWindowTitle(userFriendlyCurrentFile() + "[*]");
+ }
+}
+
+void MdiChild::newFile()
+{
+ static int sequenceNumber = 1;
+
+ isUntitled = true;
+ curFile = tr("document%1.txt").arg(sequenceNumber++);
+ setWindowTitle(curFile + "[*]");
+
+ connect(document(), &QTextDocument::contentsChanged,
+ this, &MdiChild::documentWasModified);
+}
+
+bool MdiChild::loadFile(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly | QFile::Text)) {
+ QMessageBox::warning(this, tr("MDI"),
+ tr("Cannot read file %1:\n%2.")
+ .arg(fileName)
+ .arg(file.errorString()));
+ return false;
+ }
+
+ QTextStream in(&file);
+ QGuiApplication::setOverrideCursor(Qt::WaitCursor);
+ setPlainText(in.readAll());
+ QGuiApplication::restoreOverrideCursor();
+
+ setCurrentFile(fileName);
+
+ connect(document(), &QTextDocument::contentsChanged,
+ this, &MdiChild::documentWasModified);
+
+ return true;
+}
+
+bool MdiChild::save()
+{
+ if (isUntitled) {
+ return saveAs();
+ } else {
+ return saveFile(curFile);
+ }
+}
+
+bool MdiChild::saveAs()
+{
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),
+ curFile);
+ if (fileName.isEmpty())
+ return false;
+
+ return saveFile(fileName);
+}
+
+bool MdiChild::saveFile(const QString &fileName)
+{
+ QString errorMessage;
+
+ QGuiApplication::setOverrideCursor(Qt::WaitCursor);
+ QSaveFile file(fileName);
+ if (file.open(QFile::WriteOnly | QFile::Text)) {
+ QTextStream out(&file);
+ out << toPlainText();
+ if (!file.commit()) {
+ errorMessage = tr("Cannot write file %1:\n%2.")
+ .arg(QDir::toNativeSeparators(fileName), file.errorString());
+ }
+ } else {
+ errorMessage = tr("Cannot open file %1 for writing:\n%2.")
+ .arg(QDir::toNativeSeparators(fileName), file.errorString());
+ }
+ QGuiApplication::restoreOverrideCursor();
+
+ if (!errorMessage.isEmpty()) {
+ QMessageBox::warning(this, tr("MDI"), errorMessage);
+ return false;
+ }
+
+ setCurrentFile(fileName);
+ return true;
+}
+
+QString MdiChild::userFriendlyCurrentFile()
+{
+ return strippedName(curFile);
+}
+
+void MdiChild::closeEvent(QCloseEvent *event)
+{
+ if (maybeSave()) {
+ event->accept();
+ } else {
+ event->ignore();
+ }
+}
+
+void MdiChild::documentWasModified()
+{
+ setWindowModified(document()->isModified());
+}
+
+bool MdiChild::maybeSave()
+{
+ if (!document()->isModified())
+ return true;
+ const QMessageBox::StandardButton ret
+ = QMessageBox::warning(this, tr("MDI"),
+ tr("'%1' has been modified.\n"
+ "Do you want to save your changes?")
+ .arg(userFriendlyCurrentFile()),
+ QMessageBox::Save | QMessageBox::Discard
+ | QMessageBox::Cancel);
+ switch (ret) {
+ case QMessageBox::Save:
+ return save();
+ case QMessageBox::Cancel:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+void MdiChild::setCurrentFile(const QString &fileName)
+{
+ curFile = QFileInfo(fileName).canonicalFilePath();
+ isUntitled = false;
+ document()->setModified(false);
+ setWindowModified(false);
+ setWindowTitle(userFriendlyCurrentFile() + "[*]");
+}
+
+QString MdiChild::strippedName(const QString &fullFileName)
+{
+ return QFileInfo(fullFileName).fileName();
+}
diff --git a/tests/manual/examples/widgets/mainwindows/mdi/mdichild.h b/tests/manual/examples/widgets/mainwindows/mdi/mdichild.h
new file mode 100644
index 0000000000..813a845594
--- /dev/null
+++ b/tests/manual/examples/widgets/mainwindows/mdi/mdichild.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MDICHILD_H
+#define MDICHILD_H
+
+#include <QTextEdit>
+
+class MdiChild : public QTextEdit
+{
+ Q_OBJECT
+
+public:
+ MdiChild(MdiChild *other = nullptr);
+
+ void newFile();
+ bool loadFile(const QString &fileName);
+ bool save();
+ bool saveAs();
+ bool saveFile(const QString &fileName);
+ QString userFriendlyCurrentFile();
+ QString currentFile() { return curFile; }
+
+protected:
+ void closeEvent(QCloseEvent *event) override;
+
+private slots:
+ void documentWasModified();
+
+private:
+ bool maybeSave();
+ void setCurrentFile(const QString &fileName);
+ QString strippedName(const QString &fullFileName);
+
+ QString curFile;
+ bool isUntitled = true;
+};
+
+#endif