The Qt Widgets Application example was moved to manual tests, and no longer contains the snippet identifiers. Fix \snippet and \quotefile commands to quote similar code snippets from other examples or snippet files. Fix also the following documentation warnings: * No such parameter 'parsingMode' in QUrl::fromEncoded() * Missing image: rsslisting.cpp Change-Id: Ibc989e83abc49837db08628facaf8e5f72b2f123 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> (cherry picked from commit 17ddf2a6a52bab5d406bea560591961a7527929b) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
464 lines
15 KiB
C++
464 lines
15 KiB
C++
// 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;
|
|
}
|
|
|
|
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
|
|
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(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 *child = new MdiChild;
|
|
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);
|
|
|
|
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);
|
|
}
|