Core: add aboutToSave and saved signal to IDocument

We need reliable signals that gets emitted when documents are saved to
inform the language server about the document state change.

Change-Id: I0a1e8a5317ae6984ff17d878952c74f69765e3f9
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
David Schulz
2023-06-13 15:00:15 +02:00
parent 16bfc82ef0
commit 95609551a1
26 changed files with 134 additions and 65 deletions

View File

@@ -25,10 +25,12 @@ AndroidManifestDocument::AndroidManifestDocument(AndroidManifestEditorWidget *ed
this, &Core::IDocument::changed);
}
bool AndroidManifestDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
bool AndroidManifestDocument::saveImpl(QString *errorString,
const Utils::FilePath &filePath,
bool autoSave)
{
m_editorWidget->preSave();
bool result = TextDocument::save(errorString, filePath, autoSave);
bool result = TextDocument::saveImpl(errorString, filePath, autoSave);
m_editorWidget->postSave();
return result;
}

View File

@@ -14,12 +14,15 @@ class AndroidManifestDocument : public TextEditor::TextDocument
{
public:
explicit AndroidManifestDocument(AndroidManifestEditorWidget *editorWidget);
bool save(QString *errorString, const Utils::FilePath &filePath,
bool autoSave = false) override;
bool isModified() const override;
bool isSaveAsAllowed() const override;
protected:
bool saveImpl(QString *errorString,
const Utils::FilePath &filePath,
bool autoSave = false) override;
private:
AndroidManifestEditorWidget *m_editorWidget;
};

View File

@@ -213,17 +213,6 @@ public:
return type == TypeRemoved ? BehaviorSilent : IDocument::reloadBehavior(state, type);
}
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override
{
QTC_ASSERT(!autoSave, return true); // bineditor does not support autosave - it would be a bit expensive
const FilePath &fileNameToUse = filePath.isEmpty() ? this->filePath() : filePath;
if (m_widget->save(errorString, this->filePath(), fileNameToUse)) {
setFilePath(fileNameToUse);
return true;
}
return false;
}
OpenResult open(QString *errorString, const FilePath &filePath,
const FilePath &realFilePath) override
{
@@ -316,6 +305,18 @@ public:
return success;
}
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override
{
QTC_ASSERT(!autoSave, return true); // bineditor does not support autosave - it would be a bit expensive
const FilePath &fileNameToUse = filePath.isEmpty() ? this->filePath() : filePath;
if (m_widget->save(errorString, this->filePath(), fileNameToUse)) {
setFilePath(fileNameToUse);
return true;
}
return false;
}
private:
BinEditorWidget *m_widget;
};

View File

@@ -181,6 +181,26 @@
\sa reload()
*/
/*!
\fn Core::IDocument::aboutToSave(const Utils::FilePath &filePath, bool autoSave)
This signal is emitted before the document is saved to \a filePath.
\a autoSave indicates whether this save was triggered by the auto save timer.
\sa save()
*/
/*!
\fn Core::IDocument::saved(const Utils::FilePath &filePath, bool autoSave)
This signal is emitted after the document was saved to \a filePath.
\a autoSave indicates whether this save was triggered by the auto save timer.
\sa save()
*/
/*!
\fn Core::IDocument::filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName)
@@ -315,11 +335,35 @@ IDocument::OpenResult IDocument::open(QString *errorString, const Utils::FilePat
Returns whether saving was successful.
The default implementation does nothing and returns \c false.
If saving was successful saved is emitted.
\sa shouldAutoSave()
\sa aboutToSave()
\sa saved()
*/
bool IDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
emit aboutToSave(filePath, autoSave);
const bool success = saveImpl(errorString, filePath, autoSave);
if (success)
emit saved(filePath, autoSave);
return success;
}
/*!
Implementation of saving the contents of the document to the \a filePath on disk.
If \a autoSave is \c true, the saving is done for an auto-save, so the
document should avoid cleanups or other operations that it does for
user-requested saves.
Use \a errorString to return an error message if saving failed.
Returns whether saving was successful.
The default implementation does nothing and returns \c false.
*/
bool IDocument::saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
Q_UNUSED(errorString)
Q_UNUSED(filePath)

View File

@@ -68,7 +68,7 @@ public:
virtual OpenResult open(QString *errorString, const Utils::FilePath &filePath, const Utils::FilePath &realFilePath);
virtual bool save(QString *errorString, const Utils::FilePath &filePath = Utils::FilePath(), bool autoSave = false);
bool save(QString *errorString, const Utils::FilePath &filePath = Utils::FilePath(), bool autoSave = false);
virtual QByteArray contents() const;
virtual bool setContents(const QByteArray &contents);
@@ -124,9 +124,16 @@ signals:
void aboutToReload();
void reloadFinished(bool success);
void aboutToSave(const Utils::FilePath &filePath, bool autoSave);
void saved(const Utils::FilePath &filePath, bool autoSave);
void filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName);
protected:
virtual bool saveImpl(QString *errorString,
const Utils::FilePath &filePath = Utils::FilePath(),
bool autoSave = false);
private:
Internal::IDocumentPrivate *d;
};

View File

@@ -435,10 +435,10 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
}
bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
bool CppEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
{
if (!indenter()->formatOnSave() || autoSave)
return TextEditor::TextDocument::save(errorString, filePath, autoSave);
return TextEditor::TextDocument::saveImpl(errorString, filePath, autoSave);
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());
const int documentRevision = layout->lastSaveRevision;
@@ -476,7 +476,7 @@ bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, boo
settings.m_cleanWhitespace = false;
setStorageSettings(settings);
return TextEditor::TextDocument::save(errorString, filePath, autoSave);
return TextEditor::TextDocument::saveImpl(errorString, filePath, autoSave);
}
bool CppEditorDocument::usesClangd() const

View File

@@ -47,10 +47,6 @@ public:
QFuture<CursorInfo> cursorInfo(const CursorInfoParams &params);
TextEditor::TabSettings tabSettings() const override;
bool save(QString *errorString,
const Utils::FilePath &filePath = Utils::FilePath(),
bool autoSave = false) override;
bool usesClangd() const;
signals:
@@ -68,8 +64,12 @@ signals:
protected:
void applyFontSettings() override;
bool saveImpl(QString *errorString,
const Utils::FilePath &filePath = Utils::FilePath(),
bool autoSave = false) override;
private:
void invalidateFormatterCache();
void onFilePathChanged(const Utils::FilePath &oldPath, const Utils::FilePath &newPath);
void onMimeTypeChanged();

View File

@@ -82,7 +82,7 @@ Core::IDocument::OpenResult FormWindowFile::open(QString *errorString,
return OpenResult::Success;
}
bool FormWindowFile::save(QString *errorString, const FilePath &filePath, bool autoSave)
bool FormWindowFile::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
{
const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;

View File

@@ -28,7 +28,6 @@ public:
// IDocument
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
const Utils::FilePath &realFilePath) override;
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
QByteArray contents() const override;
bool setContents(const QByteArray &contents) override;
bool shouldAutoSave() const override;
@@ -52,6 +51,9 @@ public:
void setShouldAutoSave(bool sad = true) { m_shouldAutoSave = sad; }
void updateIsModified();
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
private:
void slotFormWindowRemoved(QDesignerFormWindowInterface *w);

View File

@@ -235,7 +235,7 @@ bool DiffEditorDocument::isSaveAsAllowed() const
return state() == LoadOK;
}
bool DiffEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
bool DiffEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
{
Q_UNUSED(errorString)
Q_UNUSED(autoSave)

View File

@@ -60,7 +60,6 @@ public:
QString fallbackSaveAsFileName() const override;
bool isSaveAsAllowed() const override;
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
void reload();
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
@@ -75,6 +74,9 @@ signals:
void documentChanged();
void descriptionChanged();
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
private:
void beginReload();
void endReload(bool success);

View File

@@ -277,10 +277,14 @@ public:
{
QObject::disconnect(contentsChangedConnection);
QObject::disconnect(filePathChangedConnection);
QObject::disconnect(aboutToSaveConnection);
QObject::disconnect(savedConnection);
delete document;
}
QMetaObject::Connection contentsChangedConnection;
QMetaObject::Connection filePathChangedConnection;
QMetaObject::Connection aboutToSaveConnection;
QMetaObject::Connection savedConnection;
QTextDocument *document = nullptr;
};
QMap<TextEditor::TextDocument *, OpenedDocument> m_openedDocument;
@@ -648,6 +652,22 @@ void Client::openDocument(TextEditor::TextDocument *document)
if (isSupportedDocument(document))
openDocument(document);
});
d->m_openedDocument[document].savedConnection
= connect(document,
&TextDocument::saved,
this,
[this, document](const FilePath &saveFilePath) {
if (saveFilePath == document->filePath())
documentContentsSaved(document);
});
d->m_openedDocument[document].aboutToSaveConnection
= connect(document,
&TextDocument::aboutToSave,
this,
[this, document](const FilePath &saveFilePath) {
if (saveFilePath == document->filePath())
documentWillSave(document);
});
if (!d->m_documentVersions.contains(filePath))
d->m_documentVersions[filePath] = 0;
d->sendOpenNotification(filePath, document->mimeType(), document->plainText(),

View File

@@ -63,10 +63,6 @@ LanguageClientManager::LanguageClientManager(QObject *parent)
this, &LanguageClientManager::documentOpened);
connect(EditorManager::instance(), &EditorManager::documentClosed,
this, &LanguageClientManager::documentClosed);
connect(EditorManager::instance(), &EditorManager::saved,
this, &LanguageClientManager::documentContentsSaved);
connect(EditorManager::instance(), &EditorManager::aboutToSave,
this, &LanguageClientManager::documentWillSave);
connect(ProjectManager::instance(), &ProjectManager::projectAdded,
this, &LanguageClientManager::projectAdded);
connect(ProjectManager::instance(), &ProjectManager::projectRemoved,
@@ -550,24 +546,6 @@ void LanguageClientManager::documentClosed(Core::IDocument *document)
m_clientForDocument.remove(textDocument);
}
void LanguageClientManager::documentContentsSaved(Core::IDocument *document)
{
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) {
const QList<Client *> &clients = reachableClients();
for (Client *client : clients)
client->documentContentsSaved(textDocument);
}
}
void LanguageClientManager::documentWillSave(Core::IDocument *document)
{
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) {
const QList<Client *> &clients = reachableClients();
for (Client *client : clients)
client->documentWillSave(textDocument);
}
}
void LanguageClientManager::updateProject(ProjectExplorer::Project *project)
{
for (BaseSettings *setting : std::as_const(m_currentSettings)) {

View File

@@ -91,8 +91,6 @@ private:
void editorOpened(Core::IEditor *editor);
void documentOpened(Core::IDocument *document);
void documentClosed(Core::IDocument *document);
void documentContentsSaved(Core::IDocument *document);
void documentWillSave(Core::IDocument *document);
void updateProject(ProjectExplorer::Project *project);
void projectAdded(ProjectExplorer::Project *project);

View File

@@ -55,7 +55,7 @@ Core::IDocument::OpenResult ModelDocument::open(QString *errorString,
return result;
}
bool ModelDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
bool ModelDocument::saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
if (!d->documentController) {
*errorString = Tr::tr("No model loaded. Cannot save.");

View File

@@ -29,7 +29,6 @@ public:
OpenResult open(QString *errorString,
const Utils::FilePath &filePath,
const Utils::FilePath &realFilePath) override;
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
bool shouldAutoSave() const override;
bool isModified() const override;
bool isSaveAsAllowed() const override;
@@ -39,6 +38,9 @@ public:
OpenResult load(QString *errorString, const QString &fileName);
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
private:
ModelDocumentPrivate *d;
};

View File

@@ -120,10 +120,10 @@ Core::IDocument::OpenResult ResourceEditorDocument::open(QString *errorString,
return OpenResult::Success;
}
bool ResourceEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
bool ResourceEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
{
if (debugResourceEditorW)
qDebug() << ">ResourceEditorW::save: " << filePath;
qDebug() << ">ResourceEditorW::saveImpl: " << filePath;
const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;
if (actualName.isEmpty())

View File

@@ -30,7 +30,6 @@ public:
//IDocument
OpenResult open(QString *errorString, const Utils::FilePath &filePath,
const Utils::FilePath &realFilePath) override;
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
QString plainText() const;
QByteArray contents() const override;
bool setContents(const QByteArray &contents) override;
@@ -47,6 +46,9 @@ public:
signals:
void loaded(bool success);
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
private:
void dirtyChanged(bool);

View File

@@ -58,7 +58,7 @@ Core::IDocument::OpenResult ScxmlEditorDocument::open(QString *errorString,
return OpenResult::Success;
}
bool ScxmlEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
bool ScxmlEditorDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
{
const FilePath oldFileName = this->filePath();
const FilePath actualName = filePath.isEmpty() ? oldFileName : filePath;

View File

@@ -30,7 +30,6 @@ public:
OpenResult open(QString *errorString,
const Utils::FilePath &filePath,
const Utils::FilePath &realFilePath) override;
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
bool shouldAutoSave() const override;
bool isSaveAsAllowed() const override;
bool isModified() const override;
@@ -46,6 +45,9 @@ public:
signals:
void reloadRequested(QString *errorString, const QString &);
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
private:
QPointer<Common::MainWidget> m_designWidget;
};

View File

@@ -41,7 +41,9 @@ Core::IDocument::OpenResult ObjectsMapDocument::open(QString *errorString,
return result;
}
bool ObjectsMapDocument::save(QString *errorString, const Utils::FilePath &fileName, bool autoSave)
bool ObjectsMapDocument::saveImpl(QString *errorString,
const Utils::FilePath &fileName,
bool autoSave)
{
const Utils::FilePath actual = fileName.isEmpty() ? filePath() : fileName;
if (actual.isEmpty())

View File

@@ -21,7 +21,6 @@ public:
OpenResult open(QString *errorString,
const Utils::FilePath &fileName,
const Utils::FilePath &realFileName) override;
bool save(QString *errorString, const Utils::FilePath &fileName, bool autoSave) override;
Utils::FilePath fallbackSaveAsPath() const override;
QString fallbackSaveAsFileName() const override;
bool isModified() const override { return m_isModified; }
@@ -34,6 +33,9 @@ public:
QByteArray contents() const override;
ObjectsMapModel *model() const { return m_contentModel; }
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &fileName, bool autoSave) override;
private:
OpenResult openImpl(QString *error,
const Utils::FilePath &fileName,

View File

@@ -622,7 +622,7 @@ SyntaxHighlighter *TextDocument::syntaxHighlighter() const
* If \a autoSave is true, the cursor will be restored and some signals suppressed
* and we do not clean up the text file (cleanWhitespace(), ensureFinalNewLine()).
*/
bool TextDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
bool TextDocument::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
{
QTextCursor cursor(&d->m_document);

View File

@@ -101,7 +101,6 @@ public:
static bool marksAnnotationHidden(const Utils::Id &category);
// IDocument implementation.
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
QByteArray contents() const override;
bool setContents(const QByteArray &contents) override;
bool shouldAutoSave() const override;
@@ -166,6 +165,7 @@ signals:
protected:
virtual void applyFontSettings();
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
private:
OpenResult openImpl(QString *errorString,

View File

@@ -67,7 +67,7 @@ void SubmitEditorFile::setModified(bool modified)
emit changed();
}
bool SubmitEditorFile::save(QString *errorString, const FilePath &filePath, bool autoSave)
bool SubmitEditorFile::saveImpl(QString *errorString, const FilePath &filePath, bool autoSave)
{
const FilePath &fName = filePath.isEmpty() ? this->filePath() : filePath;
FileSaver saver(fName, QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);

View File

@@ -23,11 +23,13 @@ public:
bool setContents(const QByteArray &contents) override;
bool isModified() const override { return m_modified; }
bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
void setModified(bool modified = true);
protected:
bool saveImpl(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
private:
bool m_modified;
VcsBaseSubmitEditor *m_editor;