Commit 92e352f4 authored by Eike Ziller's avatar Eike Ziller

EditorManager: Auto-suspend editors

Adds an option (enabled by default) to close older documents when
opening new documents. These documents are put into "suspended" state,
similar to when restoring sessions: They editors and document are
removed, freeing the memory from their content and attached resources
(e.g. code model resources), but keeping the entry in the open editor
list (and history list, of course).
This is limited to editor/document types that can restore their UI state
when the document is reopened.

Task-number: QTCREATORBUG-10016
Change-Id: Icb5595aec950e3f666d42177fe2fd233954f2772
Reviewed-by: default avatarDavid Schulz <david.schulz@theqtcompany.com>
Reviewed-by: Riitta-Leena Miettinen's avatarLeena Miettinen <riitta-leena.miettinen@qt.io>
parent 98192159
......@@ -42,6 +42,7 @@ AndroidManifestDocument::AndroidManifestDocument(AndroidManifestEditorWidget *ed
{
setId(Constants::ANDROID_MANIFEST_EDITOR_ID);
setMimeType(QLatin1String(Constants::ANDROID_MANIFEST_MIME_TYPE));
setSuspendAllowed(false);
connect(editorWidget, SIGNAL(guiChanged()),
this, SIGNAL(changed()));
}
......
......@@ -355,20 +355,28 @@ DocumentModel::Entry *DocumentModelPrivate::firstSuspendedEntry()
return Utils::findOrDefault(d->m_entries, [](DocumentModel::Entry *entry) { return entry->isSuspended; });
}
void DocumentModelPrivate::removeEditor(IEditor *editor, bool *lastOneForDocument)
{
if (lastOneForDocument)
*lastOneForDocument = false;
QTC_ASSERT(editor, return);
/*!
Removes an editor from the list of open editors for its entry. If the editor is the last
one, the entry is put into suspended state.
Returns the affected entry.
*/
DocumentModel::Entry *DocumentModelPrivate::removeEditor(IEditor *editor)
{
QTC_ASSERT(editor, return nullptr);
IDocument *document = editor->document();
QTC_ASSERT(d->m_editors.contains(document), return);
QTC_ASSERT(d->m_editors.contains(document), return nullptr);
d->m_editors[document].removeAll(editor);
DocumentModel::Entry *entry = DocumentModel::entryForDocument(document);
if (d->m_editors.value(document).isEmpty()) {
if (lastOneForDocument)
*lastOneForDocument = true;
d->m_editors.remove(document);
d->removeDocument(DocumentModel::indexOfDocument(document));
entry->document = new IDocument;
entry->document->setFilePath(document->filePath());
entry->document->setPreferredDisplayName(document->preferredDisplayName());
entry->document->setUniqueDisplayName(document->uniqueDisplayName());
entry->document->setId(document->id());
entry->isSuspended = true;
}
return entry;
}
void DocumentModelPrivate::removeEntry(DocumentModel::Entry *entry)
......
......@@ -67,7 +67,7 @@ public:
static void addEditor(IEditor *editor, bool *isNewDocument);
static void addSuspendedDocument(const QString &fileName, const QString &displayName, Id id);
static DocumentModel::Entry *firstSuspendedEntry();
static void removeEditor(IEditor *editor, bool *lastOneForDocument);
static DocumentModel::Entry *removeEditor(IEditor *editor);
static void removeEntry(DocumentModel::Entry *entry);
static void removeAllSuspendedEntries();
......
......@@ -111,6 +111,8 @@ static const char documentStatesKey[] = "EditorManager/DocumentStates";
static const char reloadBehaviorKey[] = "EditorManager/ReloadBehavior";
static const char autoSaveEnabledKey[] = "EditorManager/AutoSaveEnabled";
static const char autoSaveIntervalKey[] = "EditorManager/AutoSaveInterval";
static const char autoSuspendEnabledKey[] = "EditorManager/AutoSuspendEnabled";
static const char autoSuspendMinDocumentCountKey[] = "EditorManager/AutoSuspendMinDocuments";
static const char warnBeforeOpeningBigTextFilesKey[] = "EditorManager/WarnBeforeOpeningBigTextFiles";
static const char bigTextFileSizeLimitKey[] = "EditorManager/BigTextFileSizeLimitInMB";
static const char fileSystemCaseSensitivityKey[] = "Core/FileSystemCaseSensitivity";
......@@ -961,6 +963,8 @@ void EditorManagerPrivate::saveSettings()
qsettings->setValue(reloadBehaviorKey, d->m_reloadSetting);
qsettings->setValue(autoSaveEnabledKey, d->m_autoSaveEnabled);
qsettings->setValue(autoSaveIntervalKey, d->m_autoSaveInterval);
qsettings->setValue(autoSuspendEnabledKey, d->m_autoSuspendEnabled);
qsettings->setValue(autoSuspendMinDocumentCountKey, d->m_autoSuspendMinDocumentCount);
qsettings->setValue(warnBeforeOpeningBigTextFilesKey,
d->m_warnBeforeOpeningBigFilesEnabled);
qsettings->setValue(bigTextFileSizeLimitKey, d->m_bigFileSizeLimitInMB);
......@@ -1054,6 +1058,26 @@ int EditorManagerPrivate::autoSaveInterval()
return d->m_autoSaveInterval;
}
void EditorManagerPrivate::setAutoSuspendEnabled(bool enabled)
{
d->m_autoSuspendEnabled = enabled;
}
bool EditorManagerPrivate::autoSuspendEnabled()
{
return d->m_autoSuspendEnabled;
}
void EditorManagerPrivate::setAutoSuspendMinDocumentCount(int count)
{
d->m_autoSuspendMinDocumentCount = count;
}
int EditorManagerPrivate::autoSuspendMinDocumentCount()
{
return d->m_autoSuspendMinDocumentCount;
}
bool EditorManagerPrivate::warnBeforeOpeningBigFilesEnabled()
{
return d->m_warnBeforeOpeningBigFilesEnabled;
......@@ -1141,14 +1165,18 @@ void EditorManagerPrivate::addEditor(IEditor *editor)
editor->document()->id());
}
emit m_instance->editorOpened(editor);
QTimer::singleShot(0, d, &EditorManagerPrivate::autoSuspendDocuments);
}
void EditorManagerPrivate::removeEditor(IEditor *editor)
void EditorManagerPrivate::removeEditor(IEditor *editor, bool removeSuspendedEntry)
{
bool lastOneForDocument = false;
DocumentModelPrivate::removeEditor(editor, &lastOneForDocument);
if (lastOneForDocument)
DocumentModel::Entry *entry = DocumentModelPrivate::removeEditor(editor);
QTC_ASSERT(entry, return);
if (entry->isSuspended) {
DocumentManager::removeDocument(editor->document());
if (removeSuspendedEntry)
DocumentModelPrivate::removeEntry(entry);
}
ICore::removeContextObject(editor);
}
......@@ -1273,7 +1301,7 @@ void EditorManagerPrivate::closeEditorOrDocument(IEditor *editor)
}
}
bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, bool askAboutModifiedEditors)
bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, CloseFlag flag)
{
if (editors.isEmpty())
return true;
......@@ -1311,7 +1339,7 @@ bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, bool ask
return false;
//ask whether to save modified documents that we are about to close
if (askAboutModifiedEditors) {
if (flag == CloseFlag::CloseWithAsking) {
// Check for which documents we will close all editors, and therefore might have to ask the user
QList<IDocument *> documentsToClose;
for (auto i = documentMap.constBegin(); i != documentMap.constEnd(); ++i) {
......@@ -1347,7 +1375,7 @@ bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, bool ask
d->m_editorStates.insert(editor->document()->filePath().toString(), QVariant(state));
}
removeEditor(editor);
removeEditor(editor, flag != CloseFlag::Suspend);
if (EditorView *view = viewForEditor(editor)) {
if (qApp->focusWidget() && qApp->focusWidget() == editor->widget()->focusWidget())
focusView = view;
......@@ -1542,7 +1570,7 @@ void EditorManagerPrivate::emptyView(EditorView *view)
continue; // don't close the editor
}
emit m_instance->editorAboutToClose(editor);
removeEditor(editor);
removeEditor(editor, true /*=removeSuspendedEntry, but doesn't matter since it's not the last editor anyhow*/);
view->removeEditor(editor);
}
if (!editors.isEmpty()) {
......@@ -2146,6 +2174,29 @@ void EditorManagerPrivate::revertToSaved(IDocument *document)
QMessageBox::critical(ICore::mainWindow(), tr("File Error"), errorString);
}
void EditorManagerPrivate::autoSuspendDocuments()
{
if (!d->m_autoSuspendEnabled)
return;
auto visibleDocuments = Utils::transform<QSet>(EditorManager::visibleEditors(),
[](IEditor *editor) { return editor->document(); });
int keptEditorCount = 0;
QList<IDocument *> documentsToSuspend;
foreach (const EditLocation &editLocation, d->m_globalHistory) {
IDocument *document = editLocation.document;
if (!document || !document->isSuspendAllowed() || document->isModified()
|| document->isTemporary() || document->filePath().isEmpty()
|| visibleDocuments.contains(document))
continue;
if (keptEditorCount >= d->m_autoSuspendMinDocumentCount)
documentsToSuspend.append(document);
else
++keptEditorCount;
}
closeEditors(DocumentModel::editorsForDocuments(documentsToSuspend), CloseFlag::Suspend);
}
void EditorManagerPrivate::showInGraphicalShell()
{
if (!d->m_contextMenuEntry || d->m_contextMenuEntry->fileName().isEmpty())
......@@ -2456,7 +2507,9 @@ void EditorManager::closeDocument(DocumentModel::Entry *entry)
bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool askAboutModifiedEditors)
{
return EditorManagerPrivate::closeEditors(editorsToClose, askAboutModifiedEditors);
return EditorManagerPrivate::closeEditors(editorsToClose,
askAboutModifiedEditors ? EditorManagerPrivate::CloseFlag::CloseWithAsking
: EditorManagerPrivate::CloseFlag::CloseWithoutAsking);
}
void EditorManager::activateEditorForEntry(DocumentModel::Entry *entry, OpenEditorFlags flags)
......
......@@ -61,6 +61,12 @@ class EditorManagerPrivate : public QObject
friend class Core::EditorManager;
public:
enum class CloseFlag {
CloseWithAsking,
CloseWithoutAsking,
Suspend
};
static EditorManagerPrivate *instance();
static void extensionsInitialized(); // only use from MainWindow
......@@ -90,7 +96,7 @@ public:
EditorManager::OpenEditorFlags flags = EditorManager::NoFlags);
/* closes the document if there is no other editor on the document visible */
static void closeEditorOrDocument(IEditor *editor);
static bool closeEditors(const QList<IEditor *> &editors, bool askAboutModifiedEditors);
static bool closeEditors(const QList<IEditor *> &editors, CloseFlag flag);
static EditorView *viewForEditor(IEditor *editor);
static void setCurrentView(EditorView *view);
......@@ -107,6 +113,10 @@ public:
static bool autoSaveEnabled();
static void setAutoSaveInterval(int interval);
static int autoSaveInterval();
static void setAutoSuspendEnabled(bool enabled);
static bool autoSuspendEnabled();
static void setAutoSuspendMinDocumentCount(int count);
static int autoSuspendMinDocumentCount();
static void setWarnBeforeOpeningBigFilesEnabled(bool enabled);
static bool warnBeforeOpeningBigFilesEnabled();
static void setBigFileSizeLimit(int limitInMB);
......@@ -159,6 +169,7 @@ private:
static void closeAllEditorsExceptVisible();
static void revertToSaved(IDocument *document);
static void autoSuspendDocuments();
static void showInGraphicalShell();
static void openTerminal();
......@@ -174,7 +185,7 @@ private:
static EditorManager::EditorFactoryList findFactories(Id editorId, const QString &fileName);
static IEditor *createEditor(IEditorFactory *factory, const QString &fileName);
static void addEditor(IEditor *editor);
static void removeEditor(IEditor *editor);
static void removeEditor(IEditor *editor, bool removeSusependedEntry);
static IEditor *placeEditor(EditorView *view, IEditor *editor);
static void restoreEditorState(IEditor *editor);
static int visibleDocumentsCount();
......@@ -250,6 +261,9 @@ private:
bool m_autoSaveEnabled = true;
int m_autoSaveInterval = 5;
bool m_autoSuspendEnabled = true;
int m_autoSuspendMinDocumentCount = 30;
bool m_warnBeforeOpeningBigFilesEnabled = true;
int m_bigFileSizeLimitInMB = 5;
......
......@@ -78,6 +78,7 @@ public:
bool temporary = false;
bool hasWriteWarning = false;
bool restored = false;
bool isSuspendAllowed = false;
};
} // namespace Internal
......@@ -207,6 +208,16 @@ bool IDocument::isSaveAsAllowed() const
return false;
}
bool IDocument::isSuspendAllowed() const
{
return d->isSuspendAllowed;
}
void IDocument::setSuspendAllowed(bool value)
{
d->isSuspendAllowed = value;
}
bool IDocument::isFileReadOnly() const
{
if (filePath().isEmpty())
......@@ -351,6 +362,11 @@ void IDocument::setPreferredDisplayName(const QString &name)
emit changed();
}
QString IDocument::preferredDisplayName() const
{
return d->preferredDisplayName;
}
/*!
\internal
Returns displayName without disambiguation.
......@@ -369,4 +385,9 @@ void IDocument::setUniqueDisplayName(const QString &name)
d->uniqueDisplayName = name;
}
QString IDocument::uniqueDisplayName() const
{
return d->uniqueDisplayName;
}
} // namespace Core
......@@ -97,8 +97,10 @@ public:
virtual void setFilePath(const Utils::FileName &filePath);
QString displayName() const;
void setPreferredDisplayName(const QString &name);
QString preferredDisplayName() const;
QString plainDisplayName() const;
void setUniqueDisplayName(const QString &name);
QString uniqueDisplayName() const;
virtual bool isFileReadOnly() const;
bool isTemporary() const;
......@@ -113,6 +115,8 @@ public:
virtual bool shouldAutoSave() const;
virtual bool isModified() const;
virtual bool isSaveAsAllowed() const;
bool isSuspendAllowed() const;
void setSuspendAllowed(bool value);
virtual ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
virtual bool reload(QString *errorString, ReloadFlag flag, ChangeType type);
......
......@@ -95,6 +95,8 @@ QWidget *SystemSettings::widget()
m_page->patchChooser->setPath(PatchTool::patchCommand());
m_page->autoSaveCheckBox->setChecked(EditorManagerPrivate::autoSaveEnabled());
m_page->autoSaveInterval->setValue(EditorManagerPrivate::autoSaveInterval());
m_page->autoSuspendCheckBox->setChecked(EditorManagerPrivate::autoSuspendEnabled());
m_page->autoSuspendMinDocumentCount->setValue(EditorManagerPrivate::autoSuspendMinDocumentCount());
m_page->warnBeforeOpeningBigFiles->setChecked(
EditorManagerPrivate::warnBeforeOpeningBigFilesEnabled());
m_page->bigFilesLimitSpinBox->setValue(EditorManagerPrivate::bigFileSizeLimit());
......@@ -159,6 +161,8 @@ void SystemSettings::apply()
PatchTool::setPatchCommand(m_page->patchChooser->path());
EditorManagerPrivate::setAutoSaveEnabled(m_page->autoSaveCheckBox->isChecked());
EditorManagerPrivate::setAutoSaveInterval(m_page->autoSaveInterval->value());
EditorManagerPrivate::setAutoSuspendEnabled(m_page->autoSuspendCheckBox->isChecked());
EditorManagerPrivate::setAutoSuspendMinDocumentCount(m_page->autoSuspendMinDocumentCount->value());
EditorManagerPrivate::setWarnBeforeOpeningBigFilesEnabled(
m_page->warnBeforeOpeningBigFiles->isChecked());
EditorManagerPrivate::setBigFileSizeLimit(m_page->bigFilesLimitSpinBox->value());
......
This diff is collapsed.
......@@ -260,6 +260,8 @@ TextDocument::TextDocument(Id id)
if (id.isValid())
setId(id);
setSuspendAllowed(true);
}
TextDocument::~TextDocument()
......
......@@ -67,6 +67,7 @@ VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters *parameters,
auto document = new TextDocument(parameters->id);
// if (QLatin1String(parameters->mimeType) != QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE))
document->setMimeType(QLatin1String(parameters->mimeType));
document->setSuspendAllowed(false);
return document;
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment