EditorManager: Avoid changing the editor in between when closing editors

Do not call setCurrentEditor(nullptr) since this sends a
currentEditorChanged signal which claims that no editor is active, which
can lead to unnecessary updates.
In the specific case, the git branch view was updating with the project
directory as a new repository, and then, after the actual new current
editor was set updated again with the repository of the editor.
This can be needlessly expensive if the previous and new editor are in
the same repository, but the project repository is something else, like
when having the Qt Creator super-repository open, or when editing files
unrelated to the project.

Change-Id: I515c3c40a86bfa2713ff13460ddfda974bc08c59
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Eike Ziller
2020-10-23 13:02:09 +02:00
parent 30017685e7
commit ee1e6ca508

View File

@@ -1650,62 +1650,91 @@ bool EditorManagerPrivate::closeEditors(const QList<IEditor*> &editors, CloseFla
if (acceptedEditors.isEmpty())
return false;
QList<EditorView*> closedViews;
EditorView *focusView = nullptr;
// remove the editors
foreach (IEditor *editor, acceptedEditors) {
emit m_instance->editorAboutToClose(editor);
if (!editor->document()->filePath().isEmpty()
&& !editor->document()->isTemporary()) {
// save editor states
for (IEditor *editor : qAsConst(acceptedEditors)) {
if (!editor->document()->filePath().isEmpty() && !editor->document()->isTemporary()) {
QByteArray state = editor->saveState();
if (!state.isEmpty())
d->m_editorStates.insert(editor->document()->filePath().toString(), QVariant(state));
}
}
EditorView *focusView = nullptr;
// Remove accepted editors from document model/manager and context list,
// and sort them per view, so we can remove them from views in an orderly
// manner.
QMultiHash<EditorView *, IEditor *> editorsPerView;
for (IEditor *editor : qAsConst(acceptedEditors)) {
emit m_instance->editorAboutToClose(editor);
removeEditor(editor, flag != CloseFlag::Suspend);
if (EditorView *view = viewForEditor(editor)) {
if (QApplication::focusWidget() && QApplication::focusWidget() == editor->widget()->focusWidget())
editorsPerView.insert(view, editor);
if (QApplication::focusWidget()
&& QApplication::focusWidget() == editor->widget()->focusWidget()) {
focusView = view;
if (editor == view->currentEditor())
closedViews += view;
if (d->m_currentEditor == editor) {
// avoid having a current editor without view
setCurrentView(view);
setCurrentEditor(nullptr);
}
view->removeEditor(editor);
}
}
QTC_CHECK(!focusView || focusView == currentView);
// TODO doesn't work as expected with multiple areas in main window and some other cases
// instead each view should have its own file history and handle solely themselves
// which editor is shown if their current editor closes
EditorView *forceViewToShowEditor = nullptr;
if (!closedViews.isEmpty() && EditorManager::visibleEditors().isEmpty()) {
if (closedViews.contains(currentView))
forceViewToShowEditor = currentView;
else
forceViewToShowEditor = closedViews.first();
}
foreach (EditorView *view, closedViews) {
IEditor *newCurrent = view->currentEditor();
if (!newCurrent && forceViewToShowEditor == view)
newCurrent = pickUnusedEditor();
if (newCurrent) {
activateEditor(view, newCurrent, EditorManager::DoNotChangeCurrentEditor);
} else if (forceViewToShowEditor == view) {
DocumentModel::Entry *entry = DocumentModelPrivate::firstSuspendedEntry();
if (entry) {
activateEditorForEntry(view, entry, EditorManager::DoNotChangeCurrentEditor);
} else { // no "suspended" ones, so any entry left should have a document
const QList<DocumentModel::Entry *> documents = DocumentModel::entries();
if (!documents.isEmpty()) {
if (IDocument *document = documents.last()->document) {
activateEditorForDocument(view, document, EditorManager::DoNotChangeCurrentEditor);
// Go through views, remove the editors from them.
// Sort such that views for which the current editor is closed come last,
// and if the global current view is one of them, that comes very last.
// When handling the last view in the list we handle the case where all
// visible editors are closed, and we need to e.g. revive an invisible or
// a suspended editor
QList<EditorView *> views = editorsPerView.keys();
Utils::sort(views, [editorsPerView, currentView](EditorView *a, EditorView *b) {
if (a == b)
return false;
const bool aHasCurrent = editorsPerView.values(a).contains(a->currentEditor());
const bool bHasCurrent = editorsPerView.values(b).contains(b->currentEditor());
const bool aHasGlobalCurrent = (a == currentView && aHasCurrent);
const bool bHasGlobalCurrent = (b == currentView && bHasCurrent);
if (bHasGlobalCurrent && !aHasGlobalCurrent)
return true;
if (bHasCurrent && !aHasCurrent)
return true;
return false;
});
for (EditorView *view : qAsConst(views)) {
QList<IEditor *> editors = editorsPerView.values(view);
// handle current editor in view last
IEditor *viewCurrentEditor = view->currentEditor();
if (editors.contains(viewCurrentEditor) && editors.last() != viewCurrentEditor) {
editors.removeAll(viewCurrentEditor);
editors.append(viewCurrentEditor);
}
for (IEditor *editor : qAsConst(editors)) {
if (editor == viewCurrentEditor && view == views.last()) {
// Avoid removing the globally current editor from its view,
// set a new current editor before.
const EditorManager::OpenEditorFlags flags = view != currentView
? EditorManager::DoNotChangeCurrentEditor
: EditorManager::NoFlags;
const QList<IEditor *> viewEditors = view->editors();
IEditor *newCurrent = viewEditors.size() > 1 ? viewEditors.at(viewEditors.size() - 2)
: nullptr;
if (!newCurrent)
newCurrent = pickUnusedEditor();
if (newCurrent) {
activateEditor(view, newCurrent, flags);
} else {
DocumentModel::Entry *entry = DocumentModelPrivate::firstSuspendedEntry();
if (entry) {
activateEditorForEntry(view, entry, flags);
} else { // no "suspended" ones, so any entry left should have a document
const QList<DocumentModel::Entry *> documents = DocumentModel::entries();
if (!documents.isEmpty()) {
if (IDocument *document = documents.last()->document) {
activateEditorForDocument(view, document, flags);
}
}
}
}
}
view->removeEditor(editor);
}
}