From ad4d25589fcd5efd4faa3074c19928d195f615bb Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 21 Jul 2015 08:43:39 +0200 Subject: Add recent file handling to SDI/MDI and remove the recentfiles example. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing recentfiles example was basically a clone of the SDI example with a "Recent" menu added. Assuming it is better to have it all in one place, the functionality is merged into the existing SDI/MDI examples. - Implement recently opened files handling using a submenu and a QSettings array in the SDI/MDI examples. - Remove recentfiles example. Change-Id: Id5a1ab9fa1c2e6b9ec81309cfe74cf86f450392a Reviewed-by: Topi Reiniƶ --- doc/src/images/recentfiles-example.png | Bin 5400 -> 0 bytes examples/widgets/doc/src/application.qdoc | 9 +- examples/widgets/doc/src/recentfiles.qdoc | 37 --- examples/widgets/mainwindows/mainwindows.pro | 1 - examples/widgets/mainwindows/mdi/main.cpp | 2 + examples/widgets/mainwindows/mdi/mainwindow.cpp | 121 +++++++++- examples/widgets/mainwindows/mdi/mainwindow.h | 11 + examples/widgets/mainwindows/recentfiles/main.cpp | 53 ----- .../widgets/mainwindows/recentfiles/mainwindow.cpp | 251 --------------------- .../widgets/mainwindows/recentfiles/mainwindow.h | 96 -------- .../mainwindows/recentfiles/recentfiles.pro | 9 - examples/widgets/mainwindows/sdi/mainwindow.cpp | 101 ++++++++- examples/widgets/mainwindows/sdi/mainwindow.h | 13 ++ 13 files changed, 240 insertions(+), 464 deletions(-) delete mode 100644 doc/src/images/recentfiles-example.png delete mode 100644 examples/widgets/doc/src/recentfiles.qdoc delete mode 100644 examples/widgets/mainwindows/recentfiles/main.cpp delete mode 100644 examples/widgets/mainwindows/recentfiles/mainwindow.cpp delete mode 100644 examples/widgets/mainwindows/recentfiles/mainwindow.h delete mode 100644 examples/widgets/mainwindows/recentfiles/recentfiles.pro diff --git a/doc/src/images/recentfiles-example.png b/doc/src/images/recentfiles-example.png deleted file mode 100644 index 8a1f2e5509..0000000000 Binary files a/doc/src/images/recentfiles-example.png and /dev/null differ diff --git a/examples/widgets/doc/src/application.qdoc b/examples/widgets/doc/src/application.qdoc index 048b4bfd21..cd284ecba0 100644 --- a/examples/widgets/doc/src/application.qdoc +++ b/examples/widgets/doc/src/application.qdoc @@ -50,11 +50,10 @@ To keep the example simple, recently opened files aren't shown in the \uicontrol{File} menu, even though this feature is desired in 90% - of applications. The \l{mainwindows/recentfiles}{Recent Files} - example shows how to implement this. Furthermore, this example - can only load one file at a time. The \l{mainwindows/sdi}{SDI} - and \l{mainwindows/mdi}{MDI} examples shows how to lift these - restrictions. + of applications. Furthermore, this example can only load one file at a + time. The \l{mainwindows/sdi}{SDI} and \l{mainwindows/mdi}{MDI} examples + show how to lift these restrictions and how to implement recently opened files + handling. \section1 MainWindow Class Definition diff --git a/examples/widgets/doc/src/recentfiles.qdoc b/examples/widgets/doc/src/recentfiles.qdoc deleted file mode 100644 index b58c9a1f76..0000000000 --- a/examples/widgets/doc/src/recentfiles.qdoc +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** 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 Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: http://www.gnu.org/copyleft/fdl.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \example mainwindows/recentfiles - \title Recent Files Example - \ingroup examples-mainwindow - - \brief The Recent Files example shows how a standard File menu can be extended to show - the most recent files loaded by a main window application. - - \image recentfiles-example.png -*/ diff --git a/examples/widgets/mainwindows/mainwindows.pro b/examples/widgets/mainwindows/mainwindows.pro index 52179ec9bd..dcda89abaf 100644 --- a/examples/widgets/mainwindows/mainwindows.pro +++ b/examples/widgets/mainwindows/mainwindows.pro @@ -4,5 +4,4 @@ SUBDIRS = application \ mainwindow \ mdi \ menus \ - recentfiles \ sdi diff --git a/examples/widgets/mainwindows/mdi/main.cpp b/examples/widgets/mainwindows/mdi/main.cpp index 5976c85c1c..f02285d1cf 100644 --- a/examples/widgets/mainwindows/mdi/main.cpp +++ b/examples/widgets/mainwindows/mdi/main.cpp @@ -49,6 +49,8 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(mdi); QApplication app(argc, argv); + QCoreApplication::setApplicationName("MDI Example"); + QCoreApplication::setOrganizationName("QtProject"); QCoreApplication::setApplicationVersion(QT_VERSION_STR); QCommandLineParser parser; parser.setApplicationDescription("Qt MDI Example"); diff --git a/examples/widgets/mainwindows/mdi/mainwindow.cpp b/examples/widgets/mainwindows/mdi/mainwindow.cpp index 4dada5ce70..35136c81c4 100644 --- a/examples/widgets/mainwindows/mdi/mainwindow.cpp +++ b/examples/widgets/mainwindows/mdi/mainwindow.cpp @@ -82,19 +82,24 @@ void MainWindow::newFile() void MainWindow::open() { - QString fileName = QFileDialog::getOpenFileName(this); - if (!fileName.isEmpty()) { - if (QMdiSubWindow *existing = findMdiChild(fileName)) { - mdiArea->setActiveSubWindow(existing); - return; - } + const QString fileName = QFileDialog::getOpenFileName(this); + if (!fileName.isEmpty()) + openFile(fileName); +} - if (openFile(fileName)) - statusBar()->showMessage(tr("File loaded"), 2000); +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::openFile(const QString &fileName) +bool MainWindow::loadFile(const QString &fileName) { MdiChild *child = createMdiChild(); const bool succeeded = child->loadFile(fileName); @@ -102,9 +107,87 @@ bool MainWindow::openFile(const QString &fileName) child->show(); else child->close(); + MainWindow::prependToRecentFiles(fileName); return succeeded; } +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(sender())) + openFile(action->data().toString()); +} + void MainWindow::save() { if (activeMdiChild() && activeMdiChild()->save()) @@ -113,8 +196,11 @@ void MainWindow::save() void MainWindow::saveAs() { - if (activeMdiChild() && activeMdiChild()->saveAs()) + MdiChild *child = activeMdiChild(); + if (child && child->saveAs()) { statusBar()->showMessage(tr("File saved"), 2000); + MainWindow::prependToRecentFiles(child->currentFile()); + } } #ifndef QT_NO_CLIPBOARD @@ -262,8 +348,23 @@ void MainWindow::createActions() 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::closeAllWindows); diff --git a/examples/widgets/mainwindows/mdi/mainwindow.h b/examples/widgets/mainwindows/mdi/mainwindow.h index bdc2a6a09d..3ac60282fd 100644 --- a/examples/widgets/mainwindows/mdi/mainwindow.h +++ b/examples/widgets/mainwindows/mdi/mainwindow.h @@ -68,6 +68,8 @@ private slots: void open(); void save(); void saveAs(); + void updateRecentFileActions(); + void openRecentFile(); #ifndef QT_NO_CLIPBOARD void cut(); void copy(); @@ -80,10 +82,16 @@ private slots: void switchLayoutDirection(); 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; @@ -93,6 +101,9 @@ private: QAction *newAct; QAction *saveAct; QAction *saveAsAct; + QAction *recentFileActs[MaxRecentFiles]; + QAction *recentFileSeparator; + QAction *recentFileSubMenuAct; #ifndef QT_NO_CLIPBOARD QAction *cutAct; QAction *copyAct; diff --git a/examples/widgets/mainwindows/recentfiles/main.cpp b/examples/widgets/mainwindows/recentfiles/main.cpp deleted file mode 100644 index 23ff3eda16..0000000000 --- a/examples/widgets/mainwindows/recentfiles/main.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -#include "mainwindow.h" - -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - app.setOrganizationName("QtProject"); - app.setApplicationName("Recent Files Example"); - MainWindow *mainWin = new MainWindow; - mainWin->show(); - return app.exec(); -} diff --git a/examples/widgets/mainwindows/recentfiles/mainwindow.cpp b/examples/widgets/mainwindows/recentfiles/mainwindow.cpp deleted file mode 100644 index b89797092a..0000000000 --- a/examples/widgets/mainwindows/recentfiles/mainwindow.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -#include "mainwindow.h" - -MainWindow::MainWindow() -{ - setAttribute(Qt::WA_DeleteOnClose); - - textEdit = new QTextEdit; - setCentralWidget(textEdit); - - createActions(); - createMenus(); - (void)statusBar(); - - setWindowFilePath(QString()); - resize(400, 300); -} - -void MainWindow::newFile() -{ - MainWindow *other = new MainWindow; - other->show(); -} - -void MainWindow::open() -{ - QString fileName = QFileDialog::getOpenFileName(this); - if (!fileName.isEmpty()) - loadFile(fileName); -} - -void MainWindow::save() -{ - if (curFile.isEmpty()) - saveAs(); - else - saveFile(curFile); -} - -void MainWindow::saveAs() -{ - QString fileName = QFileDialog::getSaveFileName(this); - if (fileName.isEmpty()) - return; - - saveFile(fileName); -} - -void MainWindow::openRecentFile() -{ - QAction *action = qobject_cast(sender()); - if (action) - loadFile(action->data().toString()); -} - -void MainWindow::about() -{ - QMessageBox::about(this, tr("About Recent Files"), - tr("The Recent Files example demonstrates how to provide a " - "recently used file menu in a Qt application.")); -} - -void MainWindow::createActions() -{ - newAct = new QAction(tr("&New"), this); - newAct->setShortcuts(QKeySequence::New); - newAct->setStatusTip(tr("Create a new file")); - connect(newAct, SIGNAL(triggered()), this, SLOT(newFile())); - - openAct = new QAction(tr("&Open..."), this); - openAct->setShortcuts(QKeySequence::Open); - openAct->setStatusTip(tr("Open an existing file")); - connect(openAct, SIGNAL(triggered()), this, SLOT(open())); - - saveAct = new QAction(tr("&Save"), this); - saveAct->setShortcuts(QKeySequence::Save); - saveAct->setStatusTip(tr("Save the document to disk")); - connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); - - saveAsAct = new QAction(tr("Save &As..."), this); - saveAsAct->setShortcuts(QKeySequence::SaveAs); - saveAsAct->setStatusTip(tr("Save the document under a new name")); - connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs())); - - for (int i = 0; i < MaxRecentFiles; ++i) { - recentFileActs[i] = new QAction(this); - recentFileActs[i]->setVisible(false); - connect(recentFileActs[i], SIGNAL(triggered()), - this, SLOT(openRecentFile())); - } - - exitAct = new QAction(tr("E&xit"), this); - exitAct->setShortcuts(QKeySequence::Quit); - exitAct->setStatusTip(tr("Exit the application")); - connect(exitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); - - aboutAct = new QAction(tr("&About"), this); - aboutAct->setStatusTip(tr("Show the application's About box")); - connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); - - aboutQtAct = new QAction(tr("About &Qt"), this); - aboutQtAct->setStatusTip(tr("Show the Qt library's About box")); - connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); -} - -void MainWindow::createMenus() -{ - fileMenu = menuBar()->addMenu(tr("&File")); - fileMenu->addAction(newAct); - fileMenu->addAction(openAct); - fileMenu->addAction(saveAct); - fileMenu->addAction(saveAsAct); - separatorAct = fileMenu->addSeparator(); - for (int i = 0; i < MaxRecentFiles; ++i) - fileMenu->addAction(recentFileActs[i]); - fileMenu->addSeparator(); - fileMenu->addAction(exitAct); - updateRecentFileActions(); - - menuBar()->addSeparator(); - - helpMenu = menuBar()->addMenu(tr("&Help")); - helpMenu->addAction(aboutAct); - helpMenu->addAction(aboutQtAct); -} - -void MainWindow::loadFile(const QString &fileName) -{ - QFile file(fileName); - if (!file.open(QFile::ReadOnly | QFile::Text)) { - QMessageBox::warning(this, tr("Recent Files"), - tr("Cannot read file %1:\n%2.") - .arg(fileName) - .arg(file.errorString())); - return; - } - - QTextStream in(&file); - QApplication::setOverrideCursor(Qt::WaitCursor); - textEdit->setPlainText(in.readAll()); - QApplication::restoreOverrideCursor(); - - setCurrentFile(fileName); - statusBar()->showMessage(tr("File loaded"), 2000); -} - -void MainWindow::saveFile(const QString &fileName) -{ - QFile file(fileName); - if (!file.open(QFile::WriteOnly | QFile::Text)) { - QMessageBox::warning(this, tr("Recent Files"), - tr("Cannot write file %1:\n%2.") - .arg(fileName) - .arg(file.errorString())); - return; - } - - QTextStream out(&file); - QApplication::setOverrideCursor(Qt::WaitCursor); - out << textEdit->toPlainText(); - QApplication::restoreOverrideCursor(); - - setCurrentFile(fileName); - statusBar()->showMessage(tr("File saved"), 2000); -} - -void MainWindow::setCurrentFile(const QString &fileName) -{ - curFile = fileName; - setWindowFilePath(curFile); - - QSettings settings; - QStringList files = settings.value("recentFileList").toStringList(); - files.removeAll(fileName); - files.prepend(fileName); - while (files.size() > MaxRecentFiles) - files.removeLast(); - - settings.setValue("recentFileList", files); - - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - MainWindow *mainWin = qobject_cast(widget); - if (mainWin) - mainWin->updateRecentFileActions(); - } -} - -void MainWindow::updateRecentFileActions() -{ - QSettings settings; - QStringList files = settings.value("recentFileList").toStringList(); - - int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles); - - for (int i = 0; i < numRecentFiles; ++i) { - QString text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i])); - recentFileActs[i]->setText(text); - recentFileActs[i]->setData(files[i]); - recentFileActs[i]->setVisible(true); - } - for (int j = numRecentFiles; j < MaxRecentFiles; ++j) - recentFileActs[j]->setVisible(false); - - separatorAct->setVisible(numRecentFiles > 0); -} - -QString MainWindow::strippedName(const QString &fullFileName) -{ - return QFileInfo(fullFileName).fileName(); -} diff --git a/examples/widgets/mainwindows/recentfiles/mainwindow.h b/examples/widgets/mainwindows/recentfiles/mainwindow.h deleted file mode 100644 index 95252ca525..0000000000 --- a/examples/widgets/mainwindows/recentfiles/mainwindow.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include - -QT_BEGIN_NAMESPACE -class QAction; -class QMenu; -class QTextEdit; -QT_END_NAMESPACE - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - MainWindow(); - -private slots: - void newFile(); - void open(); - void save(); - void saveAs(); - void openRecentFile(); - void about(); - -private: - void createActions(); - void createMenus(); - void loadFile(const QString &fileName); - void saveFile(const QString &fileName); - void setCurrentFile(const QString &fileName); - void updateRecentFileActions(); - QString strippedName(const QString &fullFileName); - - QString curFile; - - QTextEdit *textEdit; - QMenu *fileMenu; - QMenu *recentFilesMenu; - QMenu *helpMenu; - QAction *newAct; - QAction *openAct; - QAction *saveAct; - QAction *saveAsAct; - QAction *exitAct; - QAction *aboutAct; - QAction *aboutQtAct; - QAction *separatorAct; - - enum { MaxRecentFiles = 5 }; - QAction *recentFileActs[MaxRecentFiles]; -}; - -#endif diff --git a/examples/widgets/mainwindows/recentfiles/recentfiles.pro b/examples/widgets/mainwindows/recentfiles/recentfiles.pro deleted file mode 100644 index ccf948f560..0000000000 --- a/examples/widgets/mainwindows/recentfiles/recentfiles.pro +++ /dev/null @@ -1,9 +0,0 @@ -QT += widgets - -HEADERS = mainwindow.h -SOURCES = main.cpp \ - mainwindow.cpp - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/widgets/mainwindows/recentfiles -INSTALLS += target diff --git a/examples/widgets/mainwindows/sdi/mainwindow.cpp b/examples/widgets/mainwindows/sdi/mainwindow.cpp index 0fba7f792b..29618f9ac2 100644 --- a/examples/widgets/mainwindows/sdi/mainwindow.cpp +++ b/examples/widgets/mainwindows/sdi/mainwindow.cpp @@ -74,9 +74,12 @@ void MainWindow::newFile() void MainWindow::open() { const QString fileName = QFileDialog::getOpenFileName(this); - if (fileName.isEmpty()) - return; + if (!fileName.isEmpty()) + openFile(fileName); +} +void MainWindow::openFile(const QString &fileName) +{ MainWindow *existing = findMainWindow(fileName); if (existing) { existing->show(); @@ -196,6 +199,19 @@ void MainWindow::createActions() 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()); + QAction *closeAct = fileMenu->addAction(tr("&Close"), this, &QWidget::close); closeAct->setShortcut(tr("Ctrl+W")); closeAct->setStatusTip(tr("Close this window")); @@ -316,6 +332,83 @@ void MainWindow::loadFile(const QString &fileName) statusBar()->showMessage(tr("File loaded"), 2000); } +void MainWindow::setRecentFilesVisible(bool visible) +{ + recentFileSubMenuAct->setVisible(visible); + recentFileSeparator->setVisible(visible); +} + +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::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 = MainWindow::strippedName(recentFiles.at(i)); + 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(sender())) + openFile(action->data().toString()); +} + bool MainWindow::saveFile(const QString &fileName) { QFile file(fileName); @@ -349,6 +442,10 @@ void MainWindow::setCurrentFile(const QString &fileName) textEdit->document()->setModified(false); setWindowModified(false); + + if (!isUntitled && windowFilePath() != curFile) + MainWindow::prependToRecentFiles(curFile); + setWindowFilePath(curFile); } diff --git a/examples/widgets/mainwindows/sdi/mainwindow.h b/examples/widgets/mainwindows/sdi/mainwindow.h index 3c01f38566..66ac618c72 100644 --- a/examples/widgets/mainwindows/sdi/mainwindow.h +++ b/examples/widgets/mainwindows/sdi/mainwindow.h @@ -70,23 +70,36 @@ private slots: void open(); bool save(); bool saveAs(); + void updateRecentFileActions(); + void openRecentFile(); void about(); void documentWasModified(); private: + enum { MaxRecentFiles = 5 }; + void init(); void createActions(); void createStatusBar(); void readSettings(); void writeSettings(); bool maybeSave(); + void openFile(const QString &fileName); void loadFile(const QString &fileName); + static bool hasRecentFiles(); + void prependToRecentFiles(const QString &fileName); + void setRecentFilesVisible(bool visible); bool saveFile(const QString &fileName); void setCurrentFile(const QString &fileName); static QString strippedName(const QString &fullFileName); MainWindow *findMainWindow(const QString &fileName) const; QTextEdit *textEdit; + + QAction *recentFileActs[MaxRecentFiles]; + QAction *recentFileSeparator; + QAction *recentFileSubMenuAct; + QString curFile; bool isUntitled; }; -- cgit v1.2.3