diff options
Diffstat (limited to 'tests/manual/examples/widgets/mainwindows/mdi')
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 Binary files differnew file mode 100644 index 0000000000..2aeb28288f --- /dev/null +++ b/tests/manual/examples/widgets/mainwindows/mdi/images/copy.png diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/cut.png b/tests/manual/examples/widgets/mainwindows/mdi/images/cut.png Binary files differnew file mode 100644 index 0000000000..54638e9386 --- /dev/null +++ b/tests/manual/examples/widgets/mainwindows/mdi/images/cut.png diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/new.png b/tests/manual/examples/widgets/mainwindows/mdi/images/new.png Binary files differnew file mode 100644 index 0000000000..12131b0100 --- /dev/null +++ b/tests/manual/examples/widgets/mainwindows/mdi/images/new.png diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/open.png b/tests/manual/examples/widgets/mainwindows/mdi/images/open.png Binary files differnew file mode 100644 index 0000000000..45fa2883a7 --- /dev/null +++ b/tests/manual/examples/widgets/mainwindows/mdi/images/open.png diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/paste.png b/tests/manual/examples/widgets/mainwindows/mdi/images/paste.png Binary files differnew file mode 100644 index 0000000000..c14425cad1 --- /dev/null +++ b/tests/manual/examples/widgets/mainwindows/mdi/images/paste.png diff --git a/tests/manual/examples/widgets/mainwindows/mdi/images/save.png b/tests/manual/examples/widgets/mainwindows/mdi/images/save.png Binary files differnew file mode 100644 index 0000000000..e65a29d5f1 --- /dev/null +++ b/tests/manual/examples/widgets/mainwindows/mdi/images/save.png 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 |