2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2011-04-15 11:49:11 +02:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
#include "idocument.h"
|
2011-04-15 11:49:11 +02:00
|
|
|
|
2022-07-28 16:09:45 +02:00
|
|
|
#include <utils/filepath.h>
|
2020-06-17 12:23:44 +02:00
|
|
|
#include <utils/infobar.h>
|
2022-05-04 18:12:55 +02:00
|
|
|
#include <utils/minimizableinfobars.h>
|
2014-03-05 15:58:12 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QFile>
|
|
|
|
|
#include <QFileInfo>
|
2011-05-10 20:43:03 +02:00
|
|
|
|
2022-06-27 14:39:20 +02:00
|
|
|
#include <memory>
|
2022-08-26 10:30:00 +02:00
|
|
|
#include <optional>
|
2022-06-27 14:39:20 +02:00
|
|
|
|
2014-01-21 14:22:33 +01:00
|
|
|
/*!
|
|
|
|
|
\class Core::IDocument
|
2020-06-12 16:04:30 +02:00
|
|
|
\inheaderfile coreplugin/idocument.h
|
2020-03-18 13:32:02 +01:00
|
|
|
\inmodule QtCreator
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
\brief The IDocument class describes a document that can be saved and
|
|
|
|
|
reloaded.
|
2014-01-21 14:22:33 +01:00
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
The class has two use cases.
|
2014-01-21 14:22:33 +01:00
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
\section1 Handling External Modifications
|
|
|
|
|
|
|
|
|
|
You can implement IDocument and register instances in DocumentManager to
|
|
|
|
|
let it handle external modifications of a file. When the file specified with
|
|
|
|
|
filePath() has changed externally, the DocumentManager asks the
|
|
|
|
|
corresponding IDocument instance what to do via reloadBehavior(). If that
|
|
|
|
|
returns \c IDocument::BehaviorAsk, the user is asked if the file should be
|
|
|
|
|
reloaded from disk. If the user requests the reload or reloadBehavior()
|
|
|
|
|
returns \c IDocument::BehaviorSilent, the DocumentManager calls reload()
|
|
|
|
|
to initiate a reload of the file from disk.
|
|
|
|
|
|
|
|
|
|
Core functions: setFilePath(), reload(), reloadBehavior().
|
|
|
|
|
|
|
|
|
|
If the content of the document can change in \QC, diverging from the
|
|
|
|
|
content on disk: isModified(), save(), isSaveAsAllowed(),
|
|
|
|
|
fallbackSaveAsPath(), fallbackSaveAsFileName().
|
|
|
|
|
|
|
|
|
|
\section1 Editor Document
|
|
|
|
|
|
|
|
|
|
The most common use case for implementing an IDocument subclass is as a
|
|
|
|
|
document for an IEditor implementation. Multiple editor instances can work
|
|
|
|
|
on the same document instance, for example if the document is visible in
|
|
|
|
|
multiple splits simultaneously. So the IDocument subclass should hold all
|
|
|
|
|
data that is independent from the specific IEditor instance, for example
|
|
|
|
|
the content and highlighting information.
|
|
|
|
|
|
|
|
|
|
Each IDocument subclass is only required to work with the corresponding
|
|
|
|
|
IEditor subclasses that it was designed to work with.
|
|
|
|
|
|
|
|
|
|
An IDocument can either be backed by a file, or solely represent some data
|
|
|
|
|
in memory. Documents backed by a file are automatically added to the
|
|
|
|
|
DocumentManager by the EditorManager.
|
|
|
|
|
|
|
|
|
|
Core functions: setId(), isModified(), contents(), setContents().
|
|
|
|
|
|
|
|
|
|
If the content of the document is backed by a file: open(), save(),
|
|
|
|
|
setFilePath(), mimeType(), shouldAutoSave(), setSuspendAllowed(), and
|
|
|
|
|
everything from \l{Handling External Modifications}.
|
|
|
|
|
|
|
|
|
|
If the content of the document is not backed by a file:
|
|
|
|
|
setPreferredDisplayName(), setTemporary().
|
2014-01-21 14:22:33 +01:00
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
\ingroup mainclasses
|
2014-01-21 14:22:33 +01:00
|
|
|
*/
|
|
|
|
|
|
2013-07-04 11:35:56 +02:00
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
\enum IDocument::OpenResult
|
|
|
|
|
|
|
|
|
|
The OpenResult enum describes whether a file was successfully opened.
|
|
|
|
|
|
|
|
|
|
\value Success
|
|
|
|
|
The file was read successfully and can be handled by this document
|
|
|
|
|
type.
|
|
|
|
|
\value ReadError
|
|
|
|
|
The file could not be opened for reading, either because it does not
|
|
|
|
|
exist or because of missing permissions.
|
|
|
|
|
\value CannotHandle
|
|
|
|
|
This document type could not handle the file content.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\enum IDocument::ReloadSetting
|
|
|
|
|
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\enum IDocument::ChangeTrigger
|
|
|
|
|
|
|
|
|
|
The ChangeTrigger enum describes whether a file was changed from \QC
|
|
|
|
|
internally or from the outside.
|
|
|
|
|
|
|
|
|
|
\value TriggerInternal
|
|
|
|
|
The file was changed by \QC.
|
|
|
|
|
\value TriggerExternal
|
|
|
|
|
The file was changed from the outside.
|
|
|
|
|
|
|
|
|
|
\sa IDocument::reloadBehavior()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\enum IDocument::ChangeType
|
|
|
|
|
|
|
|
|
|
The ChangeType enum describes the way in which the file changed.
|
|
|
|
|
|
|
|
|
|
\value TypeContents
|
|
|
|
|
The contents of the file changed.
|
|
|
|
|
\value TypeRemoved
|
|
|
|
|
The file was removed.
|
|
|
|
|
|
|
|
|
|
\sa IDocument::reloadBehavior()
|
|
|
|
|
\sa IDocument::reload()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\enum IDocument::ReloadFlag
|
|
|
|
|
|
|
|
|
|
The ReloadFlag enum describes if a file should be reloaded from disk.
|
|
|
|
|
|
|
|
|
|
\value FlagReload
|
|
|
|
|
The file should be reloaded.
|
|
|
|
|
\value FlagIgnore
|
|
|
|
|
The file should not be reloaded, but the document state should
|
|
|
|
|
reflect the change.
|
|
|
|
|
|
|
|
|
|
\sa IDocument::reload()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn Core::IDocument::changed()
|
|
|
|
|
|
|
|
|
|
This signal is emitted when the document's meta data, like file name or
|
|
|
|
|
modified state, changes.
|
|
|
|
|
|
|
|
|
|
\sa isModified()
|
|
|
|
|
\sa filePath()
|
|
|
|
|
\sa displayName()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn Core::IDocument::contentsChanged()
|
|
|
|
|
|
|
|
|
|
This signal is emitted when the document's content changes.
|
|
|
|
|
|
|
|
|
|
\sa contents()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn Core::IDocument::mimeTypeChanged()
|
|
|
|
|
|
|
|
|
|
This signal is emitted when the document content's MIME type changes.
|
|
|
|
|
|
|
|
|
|
\sa mimeType()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn Core::IDocument::aboutToReload()
|
|
|
|
|
|
|
|
|
|
This signal is emitted before the document is reloaded from the backing
|
|
|
|
|
file.
|
|
|
|
|
|
|
|
|
|
\sa reload()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn Core::IDocument::reloadFinished(bool success)
|
|
|
|
|
|
|
|
|
|
This signal is emitted after the document is reloaded from the backing
|
|
|
|
|
file, or if reloading failed.
|
|
|
|
|
|
|
|
|
|
The success state is passed in \a success.
|
|
|
|
|
|
|
|
|
|
\sa reload()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn Core::IDocument::filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName)
|
|
|
|
|
|
|
|
|
|
This signal is emitted after the file path changed from \a oldName to \a
|
|
|
|
|
newName.
|
|
|
|
|
|
|
|
|
|
\sa filePath()
|
2013-07-04 11:35:56 +02:00
|
|
|
*/
|
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
using namespace Utils;
|
2011-04-15 11:49:11 +02:00
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
namespace Core {
|
2015-01-11 23:32:51 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
class IDocumentPrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
~IDocumentPrivate()
|
|
|
|
|
{
|
|
|
|
|
delete infoBar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString mimeType;
|
2019-05-28 13:49:26 +02:00
|
|
|
Utils::FilePath filePath;
|
2015-02-25 14:36:03 +02:00
|
|
|
QString preferredDisplayName;
|
|
|
|
|
QString uniqueDisplayName;
|
2021-05-18 13:55:23 +02:00
|
|
|
Utils::FilePath autoSavePath;
|
2020-06-17 12:23:44 +02:00
|
|
|
Utils::InfoBar *infoBar = nullptr;
|
2022-06-27 14:39:20 +02:00
|
|
|
std::unique_ptr<MinimizableInfoBars> minimizableInfoBars;
|
2015-01-13 14:43:13 +01:00
|
|
|
Id id;
|
2022-08-26 10:30:00 +02:00
|
|
|
std::optional<bool> fileIsReadOnly;
|
2016-05-30 14:51:09 +02:00
|
|
|
bool temporary = false;
|
|
|
|
|
bool hasWriteWarning = false;
|
|
|
|
|
bool restored = false;
|
2016-06-13 12:59:35 +02:00
|
|
|
bool isSuspendAllowed = false;
|
2015-01-11 23:32:51 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Creates an IDocument with \a parent.
|
|
|
|
|
|
|
|
|
|
\note Using the \a parent for ownership of the document is generally a
|
|
|
|
|
bad idea if the IDocument is intended for use with IEditor. It is better to
|
|
|
|
|
use shared ownership in that case.
|
|
|
|
|
*/
|
2013-07-12 15:36:29 +02:00
|
|
|
IDocument::IDocument(QObject *parent) : QObject(parent),
|
2015-01-11 23:32:51 +02:00
|
|
|
d(new Internal::IDocumentPrivate)
|
2011-04-15 11:49:11 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Destroys the IDocument.
|
|
|
|
|
If there was an auto save file for this document, it is removed.
|
|
|
|
|
|
|
|
|
|
\sa shouldAutoSave()
|
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
IDocument::~IDocument()
|
2011-04-15 11:49:11 +02:00
|
|
|
{
|
2011-05-10 20:43:03 +02:00
|
|
|
removeAutoSaveFile();
|
2015-01-11 23:32:51 +02:00
|
|
|
delete d;
|
2011-04-15 11:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
\fn void IDocument::setId(Utils::Id id)
|
|
|
|
|
|
|
|
|
|
Sets the ID for this document type to \a id. This is coupled with the
|
|
|
|
|
corresponding IEditor implementation and the \l{IEditorFactory::id()}{id()}
|
|
|
|
|
of the IEditorFactory. If the IDocument implementation only works with a
|
|
|
|
|
single IEditor type, this is preferably set in the IDocuments's
|
|
|
|
|
constructor.
|
|
|
|
|
|
|
|
|
|
\sa id()
|
|
|
|
|
*/
|
2014-03-05 15:58:12 +01:00
|
|
|
void IDocument::setId(Id id)
|
|
|
|
|
{
|
2015-01-11 23:32:51 +02:00
|
|
|
d->id = id;
|
2014-03-05 15:58:12 +01:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the ID for this document type.
|
|
|
|
|
|
|
|
|
|
\sa setId()
|
|
|
|
|
*/
|
2014-03-05 15:58:12 +01:00
|
|
|
Id IDocument::id() const
|
|
|
|
|
{
|
2015-01-11 23:32:51 +02:00
|
|
|
QTC_CHECK(d->id.isValid());
|
|
|
|
|
return d->id;
|
2014-03-05 15:58:12 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-04 15:21:02 +02:00
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
The open() method is used to load the contents of a file when a document is
|
|
|
|
|
opened in an editor.
|
2015-06-04 15:21:02 +02:00
|
|
|
|
2021-05-18 13:55:23 +02:00
|
|
|
If the document is opened from an auto save file, \a realFilePath is the
|
|
|
|
|
name of the auto save file that should be loaded, and \a filePath is the
|
2020-08-21 15:43:24 +02:00
|
|
|
file name of the resulting file. In that case, the contents of the auto
|
|
|
|
|
save file should be loaded, the file name of the IDocument should be set to
|
2021-05-18 13:55:23 +02:00
|
|
|
\a filePath, and the document state be set to modified.
|
2015-06-04 15:21:02 +02:00
|
|
|
|
2021-05-18 13:55:23 +02:00
|
|
|
If the editor is opened from a regular file, \a filePath and \a
|
|
|
|
|
filePath are the same.
|
2020-08-21 15:43:24 +02:00
|
|
|
|
|
|
|
|
Use \a errorString to return an error message if this document cannot
|
|
|
|
|
handle the file contents.
|
|
|
|
|
|
|
|
|
|
Returns whether the file was opened and read successfully.
|
|
|
|
|
|
|
|
|
|
The default implementation does nothing and returns
|
|
|
|
|
CannotHandle.
|
|
|
|
|
|
2020-09-29 15:20:22 +02:00
|
|
|
\sa EditorManager::openEditor()
|
2020-08-21 15:43:24 +02:00
|
|
|
\sa shouldAutoSave()
|
|
|
|
|
\sa setFilePath()
|
|
|
|
|
*/
|
2021-05-18 13:55:23 +02:00
|
|
|
IDocument::OpenResult IDocument::open(QString *errorString, const Utils::FilePath &filePath, const Utils::FilePath &realFilePath)
|
2015-06-02 17:14:48 +02:00
|
|
|
{
|
|
|
|
|
Q_UNUSED(errorString)
|
2021-05-18 13:55:23 +02:00
|
|
|
Q_UNUSED(filePath)
|
|
|
|
|
Q_UNUSED(realFilePath)
|
2015-06-04 15:21:02 +02:00
|
|
|
return OpenResult::CannotHandle;
|
2015-06-02 17:14:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
2021-05-18 13:55:23 +02:00
|
|
|
Saves the contents of the document to the \a filePath on disk.
|
2020-08-21 15:43:24 +02:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
\sa shouldAutoSave()
|
|
|
|
|
*/
|
2021-05-18 13:55:23 +02:00
|
|
|
bool IDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
|
2016-03-16 20:52:48 +02:00
|
|
|
{
|
|
|
|
|
Q_UNUSED(errorString)
|
2021-05-18 13:55:23 +02:00
|
|
|
Q_UNUSED(filePath)
|
2016-03-16 20:52:48 +02:00
|
|
|
Q_UNUSED(autoSave)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-15 15:24:49 +01:00
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
Returns the current contents of the document. The default implementation
|
|
|
|
|
returns an empty QByteArray.
|
|
|
|
|
|
|
|
|
|
\sa setContents()
|
|
|
|
|
\sa contentsChanged()
|
|
|
|
|
*/
|
2016-01-15 15:24:49 +01:00
|
|
|
QByteArray IDocument::contents() const
|
|
|
|
|
{
|
|
|
|
|
return QByteArray();
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-15 15:14:10 +02:00
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
The setContents() method is for example used by
|
|
|
|
|
EditorManager::openEditorWithContents() to set the \a contents of this
|
|
|
|
|
document.
|
2020-03-18 13:32:02 +01:00
|
|
|
|
|
|
|
|
Returns whether setting the contents was successful.
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
The default implementation does nothing and returns false.
|
|
|
|
|
|
|
|
|
|
\sa contents()
|
|
|
|
|
\sa EditorManager::openEditorWithContents()
|
2013-07-15 15:14:10 +02:00
|
|
|
*/
|
|
|
|
|
bool IDocument::setContents(const QByteArray &contents)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(contents)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the absolute path of the file that this document refers to. May be
|
|
|
|
|
empty for documents that are not backed by a file.
|
|
|
|
|
|
|
|
|
|
\sa setFilePath()
|
|
|
|
|
*/
|
2019-05-28 13:49:26 +02:00
|
|
|
const Utils::FilePath &IDocument::filePath() const
|
2015-01-11 23:32:51 +02:00
|
|
|
{
|
|
|
|
|
return d->filePath;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
The reloadBehavior() method is used by the DocumentManager to ask what to
|
|
|
|
|
do if the file backing this document has changed on disk.
|
|
|
|
|
|
|
|
|
|
The \a trigger specifies if the change was triggered by some operation in
|
|
|
|
|
\QC. The \a type specifies if the file changed permissions or contents, or
|
|
|
|
|
was removed completely.
|
|
|
|
|
|
|
|
|
|
Returns whether the user should be asked or the document should be
|
|
|
|
|
reloaded silently.
|
|
|
|
|
|
|
|
|
|
The default implementation requests a silent reload if only the permissions
|
|
|
|
|
changed or if the contents have changed but the \a trigger is internal and
|
|
|
|
|
the document is not modified.
|
|
|
|
|
|
|
|
|
|
\sa isModified()
|
|
|
|
|
*/
|
|
|
|
|
IDocument::ReloadBehavior IDocument::reloadBehavior(ChangeTrigger trigger, ChangeType type) const
|
2011-04-15 11:53:46 +02:00
|
|
|
{
|
2020-08-21 15:43:24 +02:00
|
|
|
if (type == TypeContents && trigger == TriggerInternal && !isModified())
|
2011-04-15 11:53:46 +02:00
|
|
|
return BehaviorSilent;
|
|
|
|
|
return BehaviorAsk;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Reloads the document from the backing file when that changed on disk.
|
|
|
|
|
|
|
|
|
|
If \a flag is FlagIgnore the file should not actually be loaded, but the
|
|
|
|
|
document should reflect the change in its \l{isModified()}{modified state}.
|
|
|
|
|
|
|
|
|
|
The \a type specifies whether only the file permissions changed or if the
|
|
|
|
|
contents of the file changed.
|
|
|
|
|
|
|
|
|
|
Use \a errorString to return an error message, if this document cannot
|
|
|
|
|
handle the file contents.
|
|
|
|
|
|
|
|
|
|
Returns if the file was reloaded successfully.
|
|
|
|
|
|
|
|
|
|
The default implementation does nothing and returns \c true.
|
|
|
|
|
|
|
|
|
|
Subclasses should emit aboutToReload() before, and reloadFinished() after
|
|
|
|
|
reloading the file.
|
|
|
|
|
|
|
|
|
|
\sa isModified()
|
|
|
|
|
\sa aboutToReload()
|
|
|
|
|
\sa reloadFinished()
|
|
|
|
|
\sa changed()
|
|
|
|
|
*/
|
2016-03-16 20:52:48 +02:00
|
|
|
bool IDocument::reload(QString *errorString, ReloadFlag flag, ChangeType type)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(errorString)
|
|
|
|
|
Q_UNUSED(flag)
|
|
|
|
|
Q_UNUSED(type)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
2021-01-13 16:27:02 +01:00
|
|
|
Updates the cached information about the read-only status of the backing file.
|
2020-08-21 15:43:24 +02:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void IDocument::checkPermissions()
|
2011-04-15 11:49:11 +02:00
|
|
|
{
|
2021-01-13 16:27:02 +01:00
|
|
|
bool previousReadOnly = d->fileIsReadOnly.value_or(false);
|
|
|
|
|
if (!filePath().isEmpty()) {
|
2021-07-23 17:58:23 +02:00
|
|
|
d->fileIsReadOnly = !filePath().isWritableFile();
|
2021-01-13 16:27:02 +01:00
|
|
|
} else {
|
|
|
|
|
d->fileIsReadOnly = false;
|
|
|
|
|
}
|
|
|
|
|
if (previousReadOnly != *(d->fileIsReadOnly))
|
|
|
|
|
emit changed();
|
2011-04-15 11:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns whether the document should automatically be saved at a user-defined
|
|
|
|
|
interval.
|
|
|
|
|
|
|
|
|
|
The default implementation returns \c false.
|
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
bool IDocument::shouldAutoSave() const
|
2011-05-10 20:43:03 +02:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns whether the document has been modified after it was loaded from a
|
|
|
|
|
file.
|
|
|
|
|
|
|
|
|
|
The default implementation returns \c false. Re-implementations should emit
|
|
|
|
|
changed() when this property changes.
|
|
|
|
|
|
|
|
|
|
\sa changed()
|
|
|
|
|
*/
|
2016-03-16 20:52:48 +02:00
|
|
|
bool IDocument::isModified() const
|
|
|
|
|
{
|
2016-10-20 08:34:55 +00:00
|
|
|
return false;
|
2016-03-16 20:52:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns whether the document may be saved under a different file name.
|
|
|
|
|
|
|
|
|
|
The default implementation returns \c false.
|
|
|
|
|
|
|
|
|
|
\sa save()
|
|
|
|
|
*/
|
2016-03-16 20:52:48 +02:00
|
|
|
bool IDocument::isSaveAsAllowed() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns whether the document may be suspended.
|
|
|
|
|
|
|
|
|
|
The EditorManager can automatically suspend editors and its corresponding
|
|
|
|
|
documents if the document is backed by a file, is not modified, and is not
|
|
|
|
|
temporary. Suspended IEditor and IDocument instances are deleted and
|
|
|
|
|
removed from memory, but are still visually accessible as if the document
|
|
|
|
|
was still opened in \QC.
|
|
|
|
|
|
|
|
|
|
The default is \c false.
|
|
|
|
|
|
|
|
|
|
\sa setSuspendAllowed()
|
|
|
|
|
\sa isModified()
|
|
|
|
|
\sa isTemporary()
|
|
|
|
|
*/
|
2016-06-13 12:59:35 +02:00
|
|
|
bool IDocument::isSuspendAllowed() const
|
|
|
|
|
{
|
|
|
|
|
return d->isSuspendAllowed;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Sets whether the document may be suspended to \a value.
|
|
|
|
|
|
|
|
|
|
\sa isSuspendAllowed()
|
|
|
|
|
*/
|
2016-06-13 12:59:35 +02:00
|
|
|
void IDocument::setSuspendAllowed(bool value)
|
|
|
|
|
{
|
|
|
|
|
d->isSuspendAllowed = value;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns whether the file backing this document is read-only, or \c false if
|
|
|
|
|
the document is not backed by a file.
|
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
bool IDocument::isFileReadOnly() const
|
2012-02-14 12:10:29 +01:00
|
|
|
{
|
2013-07-04 13:30:26 +02:00
|
|
|
if (filePath().isEmpty())
|
2012-02-14 12:10:29 +01:00
|
|
|
return false;
|
2021-01-13 16:27:02 +01:00
|
|
|
if (!d->fileIsReadOnly)
|
|
|
|
|
const_cast<IDocument *>(this)->checkPermissions();
|
|
|
|
|
return d->fileIsReadOnly.value_or(false);
|
2012-02-14 12:10:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-07-12 15:36:29 +02:00
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
Returns if the document is temporary, and should for example not be
|
|
|
|
|
considered when saving or restoring the session state, or added to the recent
|
|
|
|
|
files list.
|
|
|
|
|
|
|
|
|
|
The default is \c false.
|
|
|
|
|
|
2013-07-12 15:36:29 +02:00
|
|
|
\sa setTemporary()
|
|
|
|
|
*/
|
|
|
|
|
bool IDocument::isTemporary() const
|
|
|
|
|
{
|
2015-01-11 23:32:51 +02:00
|
|
|
return d->temporary;
|
2013-07-12 15:36:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
Sets whether the document is \a temporary.
|
|
|
|
|
|
2013-07-12 15:36:29 +02:00
|
|
|
\sa isTemporary()
|
|
|
|
|
*/
|
|
|
|
|
void IDocument::setTemporary(bool temporary)
|
|
|
|
|
{
|
2015-01-11 23:32:51 +02:00
|
|
|
d->temporary = temporary;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns a path to use for the \uicontrol{Save As} file dialog in case the
|
|
|
|
|
document is not backed by a file.
|
|
|
|
|
|
|
|
|
|
\sa fallbackSaveAsFileName()
|
|
|
|
|
*/
|
2021-09-21 06:36:32 +02:00
|
|
|
FilePath IDocument::fallbackSaveAsPath() const
|
2016-01-14 15:01:05 +01:00
|
|
|
{
|
2021-09-21 06:36:32 +02:00
|
|
|
return {};
|
2016-01-14 15:01:05 +01:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns a file name to use for the \uicontrol{Save As} file dialog in case
|
|
|
|
|
the document is not backed by a file.
|
|
|
|
|
|
|
|
|
|
\sa fallbackSaveAsPath()
|
|
|
|
|
*/
|
2016-01-14 15:01:05 +01:00
|
|
|
QString IDocument::fallbackSaveAsFileName() const
|
|
|
|
|
{
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the MIME type of the document content, if applicable.
|
|
|
|
|
|
|
|
|
|
Subclasses should set this with setMimeType() after setting or loading
|
|
|
|
|
content.
|
|
|
|
|
|
|
|
|
|
The default MIME type is empty.
|
|
|
|
|
|
|
|
|
|
\sa setMimeType()
|
|
|
|
|
\sa mimeTypeChanged()
|
|
|
|
|
*/
|
2015-01-11 23:32:51 +02:00
|
|
|
QString IDocument::mimeType() const
|
|
|
|
|
{
|
|
|
|
|
return d->mimeType;
|
2013-07-12 15:36:29 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Sets the MIME type of the document content to \a mimeType.
|
|
|
|
|
|
|
|
|
|
\sa mimeType()
|
|
|
|
|
*/
|
2014-06-26 02:15:34 +02:00
|
|
|
void IDocument::setMimeType(const QString &mimeType)
|
|
|
|
|
{
|
2015-01-11 23:32:51 +02:00
|
|
|
if (d->mimeType != mimeType) {
|
|
|
|
|
d->mimeType = mimeType;
|
2014-06-26 02:15:34 +02:00
|
|
|
emit mimeTypeChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-05-18 13:55:23 +02:00
|
|
|
bool IDocument::autoSave(QString *errorString, const FilePath &filePath)
|
2011-05-10 20:43:03 +02:00
|
|
|
{
|
2021-05-18 13:55:23 +02:00
|
|
|
if (!save(errorString, filePath, true))
|
2011-05-10 20:43:03 +02:00
|
|
|
return false;
|
2021-05-18 13:55:23 +02:00
|
|
|
d->autoSavePath = filePath;
|
2011-05-10 20:43:03 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char kRestoredAutoSave[] = "RestoredAutoSave";
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-05-18 13:55:23 +02:00
|
|
|
void IDocument::setRestoredFrom(const Utils::FilePath &path)
|
2011-05-10 20:43:03 +02:00
|
|
|
{
|
2021-05-18 13:55:23 +02:00
|
|
|
d->autoSavePath = path;
|
2015-01-11 23:32:51 +02:00
|
|
|
d->restored = true;
|
2020-06-17 12:23:44 +02:00
|
|
|
Utils::InfoBarEntry info(Id(kRestoredAutoSave),
|
|
|
|
|
tr("File was restored from auto-saved copy. "
|
|
|
|
|
"Select Save to confirm or Revert to Saved to discard changes."));
|
2011-05-10 20:43:03 +02:00
|
|
|
infoBar()->addInfo(info);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void IDocument::removeAutoSaveFile()
|
2011-05-10 20:43:03 +02:00
|
|
|
{
|
2021-05-18 13:55:23 +02:00
|
|
|
if (!d->autoSavePath.isEmpty()) {
|
|
|
|
|
QFile::remove(d->autoSavePath.toString());
|
|
|
|
|
d->autoSavePath.clear();
|
2015-01-11 23:32:51 +02:00
|
|
|
if (d->restored) {
|
|
|
|
|
d->restored = false;
|
2012-11-08 21:12:56 +02:00
|
|
|
infoBar()->removeInfo(Id(kRestoredAutoSave));
|
2011-05-10 20:43:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2015-01-11 23:32:51 +02:00
|
|
|
bool IDocument::hasWriteWarning() const
|
|
|
|
|
{
|
|
|
|
|
return d->hasWriteWarning;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2015-01-11 23:32:51 +02:00
|
|
|
void IDocument::setWriteWarning(bool has)
|
|
|
|
|
{
|
|
|
|
|
d->hasWriteWarning = has;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the document's Utils::InfoBar, which is shown at the top of an
|
|
|
|
|
editor.
|
|
|
|
|
*/
|
2020-06-17 12:23:44 +02:00
|
|
|
Utils::InfoBar *IDocument::infoBar()
|
2011-05-06 12:48:44 +02:00
|
|
|
{
|
2015-01-11 23:32:51 +02:00
|
|
|
if (!d->infoBar)
|
2020-06-17 12:23:44 +02:00
|
|
|
d->infoBar = new Utils::InfoBar;
|
2015-01-11 23:32:51 +02:00
|
|
|
return d->infoBar;
|
2011-05-06 12:48:44 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-04 18:12:55 +02:00
|
|
|
MinimizableInfoBars *IDocument::minimizableInfoBars()
|
|
|
|
|
{
|
|
|
|
|
if (!d->minimizableInfoBars)
|
2022-06-27 14:39:20 +02:00
|
|
|
d->minimizableInfoBars.reset(new Utils::MinimizableInfoBars(*infoBar()));
|
|
|
|
|
return d->minimizableInfoBars.get();
|
2022-05-04 18:12:55 +02:00
|
|
|
}
|
|
|
|
|
|
2013-07-04 11:35:56 +02:00
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
Sets the absolute \a filePath of the file that backs this document. The
|
|
|
|
|
default implementation sets the file name and sends the filePathChanged() and
|
|
|
|
|
changed() signals.
|
|
|
|
|
|
2013-07-04 13:30:26 +02:00
|
|
|
\sa filePath()
|
2020-08-21 15:43:24 +02:00
|
|
|
\sa filePathChanged()
|
|
|
|
|
\sa changed()
|
2013-07-04 11:35:56 +02:00
|
|
|
*/
|
2019-05-28 13:49:26 +02:00
|
|
|
void IDocument::setFilePath(const Utils::FilePath &filePath)
|
2013-07-04 11:35:56 +02:00
|
|
|
{
|
2015-01-11 23:32:51 +02:00
|
|
|
if (d->filePath == filePath)
|
2013-07-04 11:35:56 +02:00
|
|
|
return;
|
2019-05-28 13:49:26 +02:00
|
|
|
Utils::FilePath oldName = d->filePath;
|
2015-01-11 23:32:51 +02:00
|
|
|
d->filePath = filePath;
|
|
|
|
|
emit filePathChanged(oldName, d->filePath);
|
2013-07-04 11:35:56 +02:00
|
|
|
emit changed();
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-04 22:25:15 +02:00
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
Returns the string to display for this document, for example in the
|
|
|
|
|
\uicontrol{Open Documents} view and the documents drop down.
|
2020-03-18 13:32:02 +01:00
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
The display name is one of the following, in order:
|
2015-02-25 14:36:03 +02:00
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
\list 1
|
|
|
|
|
\li Unique display name set by the document model
|
|
|
|
|
\li Preferred display name set by the owner
|
|
|
|
|
\li Base name of the document's file name
|
|
|
|
|
\endlist
|
|
|
|
|
|
|
|
|
|
\sa setPreferredDisplayName()
|
2020-08-21 15:43:24 +02:00
|
|
|
\sa filePath()
|
|
|
|
|
\sa changed()
|
2013-07-04 22:25:15 +02:00
|
|
|
*/
|
|
|
|
|
QString IDocument::displayName() const
|
|
|
|
|
{
|
2015-02-25 14:36:03 +02:00
|
|
|
return d->uniqueDisplayName.isEmpty() ? plainDisplayName() : d->uniqueDisplayName;
|
2013-07-04 22:25:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2020-08-21 15:43:24 +02:00
|
|
|
Sets the preferred display \a name for this document.
|
|
|
|
|
|
|
|
|
|
\sa preferredDisplayName()
|
2013-07-04 22:25:15 +02:00
|
|
|
\sa displayName()
|
|
|
|
|
*/
|
2015-02-25 14:36:03 +02:00
|
|
|
void IDocument::setPreferredDisplayName(const QString &name)
|
2013-07-04 22:25:15 +02:00
|
|
|
{
|
2015-02-25 14:36:03 +02:00
|
|
|
if (name == d->preferredDisplayName)
|
2013-07-04 22:25:15 +02:00
|
|
|
return;
|
2015-02-25 14:36:03 +02:00
|
|
|
d->preferredDisplayName = name;
|
2013-07-04 22:25:15 +02:00
|
|
|
emit changed();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the preferred display name for this document.
|
|
|
|
|
|
|
|
|
|
The default preferred display name is empty, which means that the display
|
|
|
|
|
name is preferably the file name of the file backing this document.
|
|
|
|
|
|
|
|
|
|
\sa setPreferredDisplayName()
|
|
|
|
|
\sa displayName()
|
|
|
|
|
*/
|
2016-06-13 12:59:35 +02:00
|
|
|
QString IDocument::preferredDisplayName() const
|
|
|
|
|
{
|
|
|
|
|
return d->preferredDisplayName;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-25 14:36:03 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
Returns displayName without disambiguation.
|
|
|
|
|
*/
|
|
|
|
|
QString IDocument::plainDisplayName() const
|
|
|
|
|
{
|
|
|
|
|
return d->preferredDisplayName.isEmpty() ? d->filePath.fileName() : d->preferredDisplayName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
Sets unique display name for the document. Used by the document model.
|
|
|
|
|
*/
|
|
|
|
|
void IDocument::setUniqueDisplayName(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
d->uniqueDisplayName = name;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 15:43:24 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2016-06-13 12:59:35 +02:00
|
|
|
QString IDocument::uniqueDisplayName() const
|
|
|
|
|
{
|
|
|
|
|
return d->uniqueDisplayName;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-15 11:49:11 +02:00
|
|
|
} // namespace Core
|