From 88a4421a842c8db671c9eba56cfbef29ea0cecc8 Mon Sep 17 00:00:00 2001 From: Tobias Hunger <tobias.hunger@digia.com> Date: Tue, 21 Jan 2014 13:25:19 +0100 Subject: [PATCH] DocumentManager: Refactor saveModified methods Introduce methods to save a document/list of documents/all documents, both silently and with a dialog to the DocumentManager. All of these return a bool that signifies whether the save was successful or not. Detailed information on which files failed to load or whether the save was canceled by the user are still available as optional in/out parameters. Change-Id: Id17798302f2a8ba6b85a07c1f0b91f03b20da03f Reviewed-by: Tobias Hunger <tobias.hunger@digia.com> --- src/plugins/coreplugin/documentmanager.cpp | 183 +++++++++++++----- src/plugins/coreplugin/documentmanager.h | 25 ++- .../editormanager/editormanager.cpp | 4 +- src/plugins/coreplugin/externaltool.cpp | 4 +- src/plugins/coreplugin/mainwindow.cpp | 6 +- src/plugins/fakevim/fakevimplugin.cpp | 5 +- src/plugins/git/gitplugin.cpp | 30 +-- .../projectexplorer/projectexplorer.cpp | 24 +-- .../qmakeprojectmanager/qmakenodes.cpp | 8 +- 9 files changed, 181 insertions(+), 108 deletions(-) diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 5607341ec24..f2c70385bc1 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -104,11 +104,11 @@ namespace Core { static void readSettings(); -static QList<IDocument *> saveModifiedFilesHelper(const QList<IDocument *> &documents, - bool *cancelled, bool silently, - const QString &message, - const QString &alwaysSaveMessage = QString(), - bool *alwaysSave = 0); +static bool saveModifiedFilesHelper(const QList<IDocument *> &documents, + const QString &message, + bool *cancelled, bool silently, + const QString &alwaysSaveMessage, + bool *alwaysSave, QList<IDocument *> *failedToSave); namespace Internal { @@ -549,47 +549,10 @@ void DocumentManager::unexpectFileChange(const QString &fileName) updateExpectedState(fixedResolvedName); } - -/*! - Tries to save the files listed in \a documents. The \a cancelled argument is set to true - if the user cancelled the dialog. Returns the files that could not be saved. If the files - listed in documents have no write permissions, an additional dialog will be - displayed to - query the user for these permissions. -*/ -QList<IDocument *> DocumentManager::saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *cancelled) -{ - return saveModifiedFilesHelper(documents, cancelled, true, QString()); -} - -/*! - Asks the user whether to save the files listed in \a documents. Opens a - dialog that displays the \a message, and additional text to ask the users - if they want to enable automatic saving - of modified files (in this context). - - The \a cancelled argument is set to true if the user cancels the dialog. - \a alwaysSave is set to match the selection of the user if files should - always automatically be saved. If the files listed in documents have no write - permissions, an additional dialog will be displayed to query the user for - these permissions. - - Returns the files that have not been saved. -*/ -QList<IDocument *> DocumentManager::saveModifiedDocuments(const QList<IDocument *> &documents, - bool *cancelled, const QString &message, - const QString &alwaysSaveMessage, - bool *alwaysSave) -{ - return saveModifiedFilesHelper(documents, cancelled, false, message, alwaysSaveMessage, alwaysSave); -} - -static QList<IDocument *> saveModifiedFilesHelper(const QList<IDocument *> &documents, - bool *cancelled, - bool silently, - const QString &message, - const QString &alwaysSaveMessage, - bool *alwaysSave) +static bool saveModifiedFilesHelper(const QList<IDocument *> &documents, + const QString &message, bool *cancelled, bool silently, + const QString &alwaysSaveMessage, bool *alwaysSave, + QList<IDocument *> *failedToSave) { if (cancelled) (*cancelled) = false; @@ -626,9 +589,10 @@ static QList<IDocument *> saveModifiedFilesHelper(const QList<IDocument *> &docu if (cancelled) (*cancelled) = true; if (alwaysSave) - *alwaysSave = dia.alwaysSaveChecked(); - notSaved = modifiedDocuments; - return notSaved; + (*alwaysSave) = dia.alwaysSaveChecked(); + if (failedToSave) + (*failedToSave) = modifiedDocuments; + return false; } if (alwaysSave) *alwaysSave = dia.alwaysSaveChecked(); @@ -648,8 +612,9 @@ static QList<IDocument *> saveModifiedFilesHelper(const QList<IDocument *> &docu if (roDialog.exec() == Core::Internal::ReadOnlyFilesDialog::RO_Cancel) { if (cancelled) (*cancelled) = true; - notSaved = modifiedDocuments; - return notSaved; + if (failedToSave) + (*failedToSave) = modifiedDocuments; + return false; } } foreach (IDocument *document, documentsToSave) { @@ -660,7 +625,9 @@ static QList<IDocument *> saveModifiedFilesHelper(const QList<IDocument *> &docu } } } - return notSaved; + if (failedToSave) + (*failedToSave) = notSaved; + return notSaved.isEmpty(); } bool DocumentManager::saveDocument(IDocument *document, const QString &fileName, bool *isReadOnly) @@ -780,6 +747,118 @@ QString DocumentManager::getSaveAsFileName(const IDocument *document, const QStr return absoluteFilePath; } +/*! + Silently saves all documents and will return true if all modified documents were saved + successfully. + + This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if + a file is not writeable). + + \a Canceled will be set if the user canceled any of the dialogs that he interacted with. + \a FailedToClose will contain a list of documents that could not be saved if passed into the + method. +*/ +bool DocumentManager::saveAllModifiedDocumentsSilently(bool *canceled, + QList<IDocument *> *failedToClose) +{ + return saveModifiedDocumentsSilently(modifiedDocuments(), canceled, failedToClose); +} + +/*! + Silently saves \a documents and will return true if all of them were saved successfully. + + This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if + a file is not writeable). + + \a Canceled will be set if the user canceled any of the dialogs that he interacted with. + \a FailedToClose will contain a list of documents that could not be saved if passed into the + method. +*/ +bool DocumentManager::saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *canceled, + QList<IDocument *> *failedToClose) +{ + return saveModifiedFilesHelper(documents, QString(), canceled, true, QString(), 0, failedToClose); +} + +/*! + Silently saves a \a document and will return true if it was saved successfully. + + This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if + a file is not writeable). + + \a Canceled will be set if the user canceled any of the dialogs that he interacted with. + \a FailedToClose will contain a list of documents that could not be saved if passed into the + method. +*/ +bool DocumentManager::saveModifiedDocumentSilently(IDocument *document, bool *canceled, + QList<IDocument *> *failedToClose) +{ + return saveModifiedDocumentsSilently(QList<IDocument *>() << document, canceled, failedToClose); +} + +/*! + Presents a dialog with all modified documents to the user and will ask him which of these + should be saved. + + This method may show additional dialogs to the user, e.g. if a file is not writeable). + + The dialog text can be set using \a message. \a Canceled will be set if the user canceled any + of the dialogs that he interacted with (the method will also return false in this case). + The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of + this checkbox will be written into \a alwaysSave if set. + \a FailedToClose will contain a list of documents that could not be saved if passed into the + method. +*/ +bool DocumentManager::saveAllModifiedDocuments(const QString &message, bool *canceled, + const QString &alwaysSaveMessage, bool *alwaysSave, + QList<IDocument *> *failedToClose) +{ + return saveModifiedDocuments(modifiedDocuments(), message, canceled, + alwaysSaveMessage, alwaysSave, failedToClose); +} + +/*! + Presents a dialog with \a documents to the user and will ask him which of these should be saved. + + This method may show additional dialogs to the user, e.g. if a file is not writeable). + + The dialog text can be set using \a message. \a Canceled will be set if the user canceled any + of the dialogs that he interacted with (the method will also return false in this case). + The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of + this checkbox will be written into \a alwaysSave if set. + \a FailedToClose will contain a list of documents that could not be saved if passed into the + method. +*/ +bool DocumentManager::saveModifiedDocuments(const QList<IDocument *> &documents, + const QString &message, bool *canceled, + const QString &alwaysSaveMessage, bool *alwaysSave, + QList<IDocument *> *failedToClose) +{ + return saveModifiedFilesHelper(documents, message, canceled, false, + alwaysSaveMessage, alwaysSave, failedToClose); +} + +/*! + Presents a dialog with the one \a document to the user and will ask him whether he wants it + saved. + + This method may show additional dialogs to the user, e.g. if the file is not writeable). + + The dialog text can be set using \a message. \a Canceled will be set if the user canceled any + of the dialogs that he interacted with (the method will also return false in this case). + The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of + this checkbox will be written into \a alwaysSave if set. + \a FailedToClose will contain a list of documents that could not be saved if passed into the + method. +*/ +bool DocumentManager::saveModifiedDocument(IDocument *document, const QString &message, bool *canceled, + const QString &alwaysSaveMessage, bool *alwaysSave, + QList<IDocument *> *failedToClose) +{ + return saveModifiedDocuments(QList<IDocument *>() << document, message, canceled, + alwaysSaveMessage, alwaysSave, failedToClose); +} + /*! Asks the user for a set of file names to be opened. The \a filters and \a selectedFilter arguments are interpreted like in diff --git a/src/plugins/coreplugin/documentmanager.h b/src/plugins/coreplugin/documentmanager.h index 2bd7439da0b..1144a15d294 100644 --- a/src/plugins/coreplugin/documentmanager.h +++ b/src/plugins/coreplugin/documentmanager.h @@ -99,12 +99,27 @@ public: static QString getSaveAsFileName(const IDocument *document, const QString &filter = QString(), QString *selectedFilter = 0); - static QList<IDocument *> saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *cancelled = 0); - static QList<IDocument *> saveModifiedDocuments(const QList<IDocument *> &documents, - bool *cancelled = 0, - const QString &message = QString(), + static bool saveAllModifiedDocumentsSilently(bool *canceled = 0, + QList<IDocument *> *failedToClose = 0); + static bool saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *canceled = 0, + QList<IDocument *> *failedToClose = 0); + static bool saveModifiedDocumentSilently(IDocument *document, bool *canceled = 0, + QList<IDocument *> *failedToClose = 0); + + static bool saveAllModifiedDocuments(const QString &message = QString(), bool *canceled = 0, + const QString &alwaysSaveMessage = QString(), + bool *alwaysSave = 0, + QList<IDocument *> *failedToClose = 0); + static bool saveModifiedDocuments(const QList<IDocument *> &documents, + const QString &message = QString(), bool *canceled = 0, + const QString &alwaysSaveMessage = QString(), + bool *alwaysSave = 0, + QList<IDocument *> *failedToClose = 0); + static bool saveModifiedDocument(IDocument *document, + const QString &message = QString(), bool *canceled = 0, const QString &alwaysSaveMessage = QString(), - bool *alwaysSave = 0); + bool *alwaysSave = 0, + QList<IDocument *> *failedToClose = 0); static QString fileDialogLastVisitedDirectory(); static void setFileDialogLastVisitedDirectory(const QString &); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 4c2e9c9bbd8..4f52d0a3e47 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -1084,7 +1084,9 @@ bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool ask //ask whether to save modified files if (askAboutModifiedEditors) { bool cancelled = false; - QList<IDocument*> list = DocumentManager::saveModifiedDocuments(acceptedDocuments.toList(), &cancelled); + QList<IDocument *> list; + DocumentManager::saveModifiedDocuments(acceptedDocuments.toList(), QString(), &cancelled, + QString(), 0, &list); if (cancelled) return false; if (!list.isEmpty()) { diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp index a0d67d5d8f8..898b8e87b42 100644 --- a/src/plugins/coreplugin/externaltool.cpp +++ b/src/plugins/coreplugin/externaltool.cpp @@ -593,9 +593,7 @@ void ExternalToolRunner::run() if (m_tool->modifiesCurrentDocument()) { if (IDocument *document = EditorManager::currentDocument()) { m_expectedFileName = document->filePath(); - bool cancelled = false; - DocumentManager::saveModifiedDocuments(QList<IDocument *>() << document, &cancelled); - if (cancelled) { + if (!DocumentManager::saveModifiedDocument(document)) { deleteLater(); return; } diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 5d31975ed5e..42d657390fa 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -360,9 +360,7 @@ void MainWindow::closeEvent(QCloseEvent *event) ICore::saveSettings(); // Save opened files - bool cancelled; - QList<IDocument*> notSaved = DocumentManager::saveModifiedDocuments(DocumentManager::modifiedDocuments(), &cancelled); - if (cancelled || !notSaved.isEmpty()) { + if (!DocumentManager::saveAllModifiedDocuments()) { event->ignore(); return; } @@ -925,7 +923,7 @@ bool MainWindow::showOptionsDialog(Id category, Id page, QWidget *parent) void MainWindow::saveAll() { - DocumentManager::saveModifiedDocumentsSilently(DocumentManager::modifiedDocuments()); + DocumentManager::saveAllModifiedDocuments(); } void MainWindow::exit() diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index a7ed73ab840..1cf0e8f0197 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1945,8 +1945,9 @@ void FakeVimPluginPrivate::handleExCommand(bool *handled, const ExCommand &cmd) } else if (cmd.matches(_("wa"), _("wall"))) { // :w[all] QList<IDocument *> toSave = DocumentManager::modifiedDocuments(); - QList<IDocument *> failed = DocumentManager::saveModifiedDocumentsSilently(toSave); - if (failed.isEmpty()) + QList<IDocument *> failed; + bool success = DocumentManager::saveModifiedDocuments(toSave, QString(), 0, QString(), 0, &failed); + if (!success) handler->showMessage(MessageInfo, tr("Saving succeeded")); else handler->showMessage(MessageError, tr("%n files not saved", 0, failed.size())); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 62044430eca..b2eda533d81 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -719,14 +719,6 @@ void GitPlugin::submitEditorMerge(const QStringList &unmerged) m_gitClient->merge(m_submitRepository, unmerged); } -static bool ensureAllDocumentsSaved() -{ - bool cancelled; - Core::DocumentManager::saveModifiedDocuments(Core::DocumentManager::modifiedDocuments(), - &cancelled); - return !cancelled; -} - void GitPlugin::diffCurrentFile() { const VcsBase::VcsBasePluginState state = currentState(); @@ -788,7 +780,7 @@ void GitPlugin::reflogRepository() void GitPlugin::undoFileChanges(bool revertStaging) { - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; const VcsBase::VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasFile(), return); @@ -798,7 +790,7 @@ void GitPlugin::undoFileChanges(bool revertStaging) void GitPlugin::undoUnstagedFileChanges() { - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; undoFileChanges(false); } @@ -832,7 +824,7 @@ protected: void GitPlugin::resetRepository() { - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; const VcsBase::VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); @@ -847,7 +839,7 @@ void GitPlugin::resetRepository() void GitPlugin::startRebase() { - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; const VcsBase::VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); @@ -889,7 +881,7 @@ void GitPlugin::startChangeRelatedAction() return; } - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; switch (dialog.command()) { @@ -1150,7 +1142,7 @@ void GitPlugin::fetch() void GitPlugin::pull() { - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; const VcsBase::VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); @@ -1187,7 +1179,7 @@ void GitPlugin::startMergeTool() void GitPlugin::continueOrAbortCommand() { - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; const VcsBase::VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); @@ -1286,11 +1278,7 @@ void GitPlugin::updateSubmodules() static bool ensureFileSaved(const QString &fileName) { Core::IDocument *document = Core::EditorManager::documentModel()->documentForFilePath(fileName); - if (!document || !document->isModified()) - return true; - bool canceled; - Core::DocumentManager::saveModifiedDocuments(QList<Core::IDocument *>() << document, &canceled); - return !canceled; + return Core::DocumentManager::saveModifiedDocument(document); } void GitPlugin::applyCurrentFilePatch() @@ -1342,7 +1330,7 @@ void GitPlugin::applyPatch(const QString &workingDirectory, QString file) void GitPlugin::stash() { - if (!ensureAllDocumentsSaved()) + if (!Core::DocumentManager::saveAllModifiedDocuments()) return; // Simple stash without prompt, reset repo. const VcsBase::VcsBasePluginState state = currentState(); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 7fe089e91f6..9c48e3eca00 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1075,15 +1075,7 @@ void ProjectExplorerPlugin::unloadProject() if (!document || document->filePath().isEmpty()) //nothing to save? return; - QList<IDocument*> documentsToSave; - documentsToSave << document; - bool success = false; - if (document->isFileReadOnly()) - success = DocumentManager::saveModifiedDocuments(documentsToSave).isEmpty(); - else - success = DocumentManager::saveModifiedDocumentsSilently(documentsToSave).isEmpty(); - - if (!success) + if (!DocumentManager::saveModifiedDocumentSilently(document)) return; addToRecentProjects(document->filePath(), d->m_currentProject->displayName()); @@ -1967,13 +1959,13 @@ bool ProjectExplorerPlugin::saveModifiedFiles() } else { bool cancelled = false; bool alwaysSave = false; - DocumentManager::saveModifiedDocuments(documentsToSave, &cancelled, QString(), - tr("Always save files before build"), &alwaysSave); - - if (cancelled) - return false; - if (alwaysSave) - d->m_projectExplorerSettings.saveBeforeBuild = true; + if (!DocumentManager::saveModifiedDocuments(documentsToSave, QString(), &cancelled, + tr("Always save files before build"), &alwaysSave)) { + if (cancelled) + return false; + if (alwaysSave) + d->m_projectExplorerSettings.saveBeforeBuild = true; + } } } return true; diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 32ad3e5adb2..59a0945663c 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -1065,11 +1065,11 @@ bool QmakePriFileNode::saveModifiedEditors() if (!document || !document->isModified()) return true; - bool cancelled; - Core::DocumentManager::saveModifiedDocuments(QList<Core::IDocument *>() << document, &cancelled, - tr("There are unsaved changes for project file %1.").arg(m_projectFilePath)); - if (cancelled) + if (!Core::DocumentManager::saveDocument(document, + tr("There are unsaved changes for project file %1.") + .arg(m_projectFilePath))) { return false; + } // force instant reload of ourselves QtSupport::ProFileCacheManager::instance()->discardFile(m_projectFilePath); m_project->qmakeProjectManager()->notifyChanged(m_projectFilePath); -- GitLab