From fe21a7a77ea893ba78b1c18a79105d48177aa603 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 22 Feb 2019 15:46:19 +0100 Subject: [PATCH] Allow pinning files to ensure that they are always open This patch allows pinning files within a session. Pinning a file puts it at the top of the Open Documents list, and prevents Close All from closing it until it is unpinned. This is useful for files that should always be open for a given session. [ChangeLog] Files can now be pinned via the context menu. Pinning a file keeps it at the top of the Open Documents list, and prevents Close All and similar actions from closing it until it is unpinned. This provides a way to quickly close any open files without closing important ones. Change-Id: If47a599fb272db4c78a71eabe6fb29215a9a8a11 Fixes: QTCREATORBUG-21899 Reviewed-by: Eike Ziller --- doc/src/howto/creator-sidebar-views.qdocinc | 14 +++ doc/src/howto/creator-ui.qdoc | 1 + src/libs/utils/images/pinned.png | Bin 0 -> 168 bytes src/libs/utils/images/pinned@2x.png | Bin 0 -> 267 bytes src/libs/utils/utils.qrc | 2 + src/libs/utils/utilsicons.cpp | 2 + src/libs/utils/utilsicons.h | 1 + .../editormanager/documentmodel.cpp | 87 +++++++++++----- .../coreplugin/editormanager/documentmodel.h | 10 ++ .../editormanager/documentmodel_p.h | 16 ++- .../editormanager/editormanager.cpp | 95 +++++++++++++++--- .../coreplugin/editormanager/editormanager.h | 3 + .../editormanager/editormanager_p.h | 3 + .../editormanager/openeditorsview.cpp | 6 +- src/plugins/coreplugin/editortoolbar.cpp | 2 + src/plugins/coreplugin/idocument.cpp | 1 + src/plugins/qmldesigner/shortcutmanager.cpp | 2 +- src/tools/icons/qtcreatoricons.svg | 18 ++++ src/tools/tools.pro | 5 +- 19 files changed, 222 insertions(+), 46 deletions(-) create mode 100644 src/libs/utils/images/pinned.png create mode 100644 src/libs/utils/images/pinned@2x.png diff --git a/doc/src/howto/creator-sidebar-views.qdocinc b/doc/src/howto/creator-sidebar-views.qdocinc index bb4daaa72b0..1a6af5a3983 100644 --- a/doc/src/howto/creator-sidebar-views.qdocinc +++ b/doc/src/howto/creator-sidebar-views.qdocinc @@ -194,6 +194,20 @@ //! [projects view] +//! [open documents view] + + \section2 Viewing Open Documents + + To see a list of open documents, switch to the \uicontrol {Open Documents} + view. By right-clicking an open document, you can: + + \list + \li Pin files to ensure they stay at the top of the list and are not + closed when \uicontrol {Close All} is used. + \endlist + +//! [open documents view] + //! [file system view] \section2 Viewing the File System diff --git a/doc/src/howto/creator-ui.qdoc b/doc/src/howto/creator-ui.qdoc index be542702dad..8a6411ce5e9 100644 --- a/doc/src/howto/creator-ui.qdoc +++ b/doc/src/howto/creator-ui.qdoc @@ -148,6 +148,7 @@ \include creator-sidebar-views.qdocinc using sidebar views \include creator-sidebar-views.qdocinc projects view + \include creator-sidebar-views.qdocinc open documents view \include creator-sidebar-views.qdocinc file system view \include creator-sidebar-views.qdocinc outline view \if defined(qtcreator) diff --git a/src/libs/utils/images/pinned.png b/src/libs/utils/images/pinned.png new file mode 100644 index 0000000000000000000000000000000000000000..dc96231ca4b3628a70025bd28632cd9aa5368a67 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4h9AW2CEqh_A)RqeHGA(WQSBP4m^y&M< zwtbgaPTD&~R0o}&(D+d7P-42t`dWiz3np=fPyhe_PuRw)Cr~eZq~iOO3C|N47^ME4 Uy6NTM$_8?Rr>mdKI;Vst05rHePXGV_ literal 0 HcmV?d00001 diff --git a/src/libs/utils/images/pinned@2x.png b/src/libs/utils/images/pinned@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c59e83cefdbba5a98d9247284ef2fa6ac34f13 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2=OP(%{Ar_~TfA}*P@N_ht z7~aqz?zf%Q%Ow|Guy8Hlb)N=!(IYKUg^kc(tx4y#lV<+<@xP)nlV#Nkkb2b0=Y zGHCy}`QWKg)Yf#tu03MTN{3pmY6K-*_?i7HUPb%bhD9g0FQ^vwb>&WTShynNpx6}; zt*DLe*O+$v-r)W{-I`6!r?RCW9nzW?8LjsvUh4Uw9{1P|8M z(~b)yPezE;Y+`)L&bUC5aR!&bCk0W#8C*63pBzN*&fww`|L-jH%ba7AoE8H^+(m7c T literal 0 HcmV?d00001 diff --git a/src/libs/utils/utils.qrc b/src/libs/utils/utils.qrc index 4068ad2dc28..0f4efa870d6 100644 --- a/src/libs/utils/utils.qrc +++ b/src/libs/utils/utils.qrc @@ -34,6 +34,8 @@ images/locked@2x.png images/unlocked.png images/unlocked@2x.png + images/pinned.png + images/pinned@2x.png images/broken.png images/broken@2x.png images/notloaded.png diff --git a/src/libs/utils/utilsicons.cpp b/src/libs/utils/utilsicons.cpp index 07c4519dda6..43ceccd9267 100644 --- a/src/libs/utils/utilsicons.cpp +++ b/src/libs/utils/utilsicons.cpp @@ -43,6 +43,8 @@ const Icon LOCKED({ {QLatin1String(":/utils/images/locked.png"), Theme::PanelTextColorDark}}, Icon::Tint); const Icon UNLOCKED_TOOLBAR({ {QLatin1String(":/utils/images/unlocked.png"), Theme::IconsBaseColor}}); +const Icon PINNED({ + {QLatin1String(":/utils/images/pinned.png"), Theme::PanelTextColorDark}}, Icon::Tint); const Icon NEXT({ {QLatin1String(":/utils/images/next.png"), Theme::IconsWarningColor}}, Icon::MenuTintedStyle); const Icon NEXT_TOOLBAR({ diff --git a/src/libs/utils/utilsicons.h b/src/libs/utils/utilsicons.h index e7a08893980..7d3c7a7647b 100644 --- a/src/libs/utils/utilsicons.h +++ b/src/libs/utils/utilsicons.h @@ -38,6 +38,7 @@ QTCREATOR_UTILS_EXPORT extern const Icon EDIT_CLEAR_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon LOCKED_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon LOCKED; QTCREATOR_UTILS_EXPORT extern const Icon UNLOCKED_TOOLBAR; +QTCREATOR_UTILS_EXPORT extern const Icon PINNED; QTCREATOR_UTILS_EXPORT extern const Icon NEXT; QTCREATOR_UTILS_EXPORT extern const Icon NEXT_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon PREV; diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index 4cdb055bfcd..5406a590470 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -43,7 +43,6 @@ #include #include - static Core::Internal::DocumentModelPrivate *d; namespace Core { @@ -52,6 +51,10 @@ namespace Internal { namespace { bool compare(const DocumentModel::Entry *e1, const DocumentModel::Entry *e2) { + // Pinned files should go at the top. + if (e1->pinned != e2->pinned) + return e1->pinned; + const int cmp = e1->plainDisplayName().localeAwareCompare(e2->plainDisplayName()); return (cmp < 0) || (cmp == 0 && e1->fileName() < e2->fileName()); } @@ -111,7 +114,8 @@ void DocumentModelPrivate::addEntry(DocumentModel::Entry *entry) previousEntry->isSuspended = false; delete previousEntry->document; previousEntry->document = entry->document; - connect(previousEntry->document, &IDocument::changed, this, &DocumentModelPrivate::itemChanged); + connect(previousEntry->document, &IDocument::changed, + this, [this, document = previousEntry->document] { itemChanged(document); }); } delete entry; entry = nullptr; @@ -129,7 +133,9 @@ void DocumentModelPrivate::addEntry(DocumentModel::Entry *entry) disambiguateDisplayNames(entry); if (!fixedPath.isEmpty()) m_entryByFixedPath[fixedPath] = entry; - connect(entry->document, &IDocument::changed, this, &DocumentModelPrivate::itemChanged); + connect(entry->document, &IDocument::changed, this, [this, document = entry->document] { + itemChanged(document); + }); endInsertRows(); } @@ -196,12 +202,29 @@ bool DocumentModelPrivate::disambiguateDisplayNames(DocumentModel::Entry *entry) return true; } +void DocumentModelPrivate::setPinned(DocumentModel::Entry *entry, bool pinned) +{ + if (entry->pinned == pinned) + return; + + entry->pinned = pinned; + // Ensure that this entry is re-sorted in the list of open documents + // now that its pinned state has changed. + d->itemChanged(entry->document); +} + QIcon DocumentModelPrivate::lockedIcon() { const static QIcon icon = Utils::Icons::LOCKED.icon(); return icon; } +QIcon DocumentModelPrivate::pinnedIcon() +{ + const static QIcon icon = Utils::Icons::PINNED.icon(); + return icon; +} + Utils::optional DocumentModelPrivate::indexOfFilePath(const Utils::FileName &filePath) const { if (filePath.isEmpty()) @@ -230,7 +253,7 @@ void DocumentModelPrivate::removeDocument(int idx) DocumentManager::ResolveLinks); m_entryByFixedPath.remove(fixedPath); } - disconnect(entry->document, &IDocument::changed, this, &DocumentModelPrivate::itemChanged); + disconnect(entry->document, &IDocument::changed, this, nullptr); disambiguateDisplayNames(entry); delete entry; } @@ -307,7 +330,11 @@ QVariant DocumentModelPrivate::data(const QModelIndex &index, int role) const return name; } case Qt::DecorationRole: - return entry->document->isFileReadOnly() ? lockedIcon() : QIcon(); + if (entry->document->isFileReadOnly()) + return lockedIcon(); + if (entry->pinned) + return pinnedIcon(); + return QIcon(); case Qt::ToolTipRole: return entry->fileName().isEmpty() ? entry->displayName() : entry->fileName().toUserOutput(); default: @@ -316,10 +343,8 @@ QVariant DocumentModelPrivate::data(const QModelIndex &index, int role) const return QVariant(); } -void DocumentModelPrivate::itemChanged() +void DocumentModelPrivate::itemChanged(IDocument *document) { - auto document = qobject_cast(sender()); - const Utils::optional idx = indexOfDocument(document); if (!idx) return; @@ -353,14 +378,19 @@ void DocumentModelPrivate::itemChanged() // Make sure the entries stay sorted: auto positions = positionEntry(m_entries, entry); if (positions.first >= 0 && positions.second >= 0) { - // Entry did move: remove and add it again. - beginRemoveRows(QModelIndex(), positions.first + 1, positions.first + 1); - m_entries.removeAt(positions.first); - endRemoveRows(); + // Entry did move: update its position. - beginInsertRows(QModelIndex(), positions.second + 1, positions.second + 1); - m_entries.insert(positions.second, entry); - endInsertRows(); + // Account for the entry. + static const int noDocumentEntryOffset = 1; + const int fromIndex = positions.first + noDocumentEntryOffset; + const int toIndex = positions.second + noDocumentEntryOffset; + // Account for the weird requirements of beginMoveRows(). + const int effectiveToIndex = toIndex > fromIndex ? toIndex + 1 : toIndex; + beginMoveRows(QModelIndex(), fromIndex, fromIndex, QModelIndex(), effectiveToIndex); + + m_entries.move(fromIndex - 1, toIndex - 1); + + endMoveRows(); } else { // Nothing to remove or add: The entry did not move. QTC_CHECK(positions.first == -1 && positions.second == -1); @@ -384,7 +414,9 @@ void DocumentModelPrivate::addEditor(IEditor *editor, bool *isNewDocument) } } -void DocumentModelPrivate::addSuspendedDocument(const QString &fileName, const QString &displayName, Id id) +DocumentModel::Entry *DocumentModelPrivate::addSuspendedDocument(const QString &fileName, + const QString &displayName, + Id id) { auto entry = new DocumentModel::Entry; entry->document = new IDocument; @@ -393,6 +425,7 @@ void DocumentModelPrivate::addSuspendedDocument(const QString &fileName, const Q entry->document->setId(id); entry->isSuspended = true; d->addEntry(entry); + return entry; } DocumentModel::Entry *DocumentModelPrivate::firstSuspendedEntry() @@ -433,15 +466,20 @@ void DocumentModelPrivate::removeEntry(DocumentModel::Entry *entry) d->removeDocument(index); } -void DocumentModelPrivate::removeAllSuspendedEntries() +void DocumentModelPrivate::removeAllSuspendedEntries(PinnedFileRemovalPolicy pinnedFileRemovalPolicy) { for (int i = d->m_entries.count()-1; i >= 0; --i) { - if (d->m_entries.at(i)->isSuspended) { - int row = i + 1/**/; - d->beginRemoveRows(QModelIndex(), row, row); - delete d->m_entries.takeAt(i); - d->endRemoveRows(); - } + const DocumentModel::Entry *entry = d->m_entries.at(i); + if (!entry->isSuspended) + continue; + + if (pinnedFileRemovalPolicy == DoNotRemovePinnedFiles && entry->pinned) + continue; + + int row = i + 1/**/; + d->beginRemoveRows(QModelIndex(), row, row); + delete d->m_entries.takeAt(i); + d->endRemoveRows(); } QSet displayNames; foreach (DocumentModel::Entry *entry, d->m_entries) { @@ -480,7 +518,8 @@ void DocumentModelPrivate::DynamicEntry::setNumberedName(int number) DocumentModel::Entry::Entry() : document(nullptr), - isSuspended(false) + isSuspended(false), + pinned(false) { } diff --git a/src/plugins/coreplugin/editormanager/documentmodel.h b/src/plugins/coreplugin/editormanager/documentmodel.h index 09bb4652725..8cb5286c55c 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.h +++ b/src/plugins/coreplugin/editormanager/documentmodel.h @@ -60,7 +60,17 @@ public: Id id() const; IDocument *document; + // When an entry is suspended, it means that it is not in memory, + // and there is no IEditor for it and only a dummy IDocument. + // This is typically the case for files that have not been opened yet, + // but can also happen later after they have been opened. + // The related setting for this is found in: + // Options > Environment > System > Auto-suspend unmodified files bool isSuspended; + // The entry has been pinned, which means that it should stick to + // the top of any lists of open files, and that any actions that close + // files in bulk should not close this one. + bool pinned; }; static Entry *entryAtRow(int row); diff --git a/src/plugins/coreplugin/editormanager/documentmodel_p.h b/src/plugins/coreplugin/editormanager/documentmodel_p.h index 10f8ebfb4d8..4a92baad7f9 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel_p.h +++ b/src/plugins/coreplugin/editormanager/documentmodel_p.h @@ -63,15 +63,25 @@ public: bool disambiguateDisplayNames(DocumentModel::Entry *entry); + static void setPinned(DocumentModel::Entry *entry, bool pinned); + static QIcon lockedIcon(); + static QIcon pinnedIcon(); static void addEditor(IEditor *editor, bool *isNewDocument); - static void addSuspendedDocument(const QString &fileName, const QString &displayName, Id id); + static DocumentModel::Entry *addSuspendedDocument(const QString &fileName, + const QString &displayName, + Id id); static DocumentModel::Entry *firstSuspendedEntry(); static DocumentModel::Entry *removeEditor(IEditor *editor); static void removeEntry(DocumentModel::Entry *entry); - static void removeAllSuspendedEntries(); + enum PinnedFileRemovalPolicy { + DoNotRemovePinnedFiles, + RemovePinnedFiles + }; + static void removeAllSuspendedEntries(PinnedFileRemovalPolicy pinnedFileRemovalPolicy + = RemovePinnedFiles); - void itemChanged(); + void itemChanged(IDocument *document); class DynamicEntry { diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index b9a26caf730..4be3ce3a1ed 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -216,7 +216,8 @@ EditorManagerPrivate::EditorManagerPrivate(QObject *parent) : m_openGraphicalShellAction(new QAction(FileUtils::msgGraphicalShellAction(), this)), m_openTerminalAction(new QAction(FileUtils::msgTerminalAction(), this)), m_findInDirectoryAction(new QAction(FileUtils::msgFindInDirectory(), this)), - m_filePropertiesAction(new QAction(tr("Properties..."), this)) + m_filePropertiesAction(new QAction(tr("Properties..."), this)), + m_pinAction(new QAction(tr("Pin"), this)) { d = this; } @@ -302,8 +303,7 @@ void EditorManagerPrivate::init() cmd = ActionManager::registerAction(m_closeAllEditorsAction, Constants::CLOSEALL, editManagerContext, true); cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+W"))); mfile->addAction(cmd, Constants::G_FILE_CLOSE); - connect(m_closeAllEditorsAction, &QAction::triggered, - m_instance, []() { EditorManager::closeAllEditors(); }); + connect(m_closeAllEditorsAction, &QAction::triggered, m_instance, &EditorManager::closeAllDocuments); // Close All Others Action cmd = ActionManager::registerAction(m_closeOtherDocumentsAction, Constants::CLOSEOTHERS, editManagerContext, true); @@ -334,7 +334,7 @@ void EditorManagerPrivate::init() // Close XXX Context Actions connect(m_closeAllEditorsContextAction, &QAction::triggered, - m_instance, []() { EditorManager::closeAllEditors(); }); + m_instance, &EditorManager::closeAllDocuments); connect(m_closeCurrentEditorContextAction, &QAction::triggered, this, &EditorManagerPrivate::closeEditorFromContextMenu); connect(m_closeOtherDocumentsContextAction, &QAction::triggered, @@ -352,6 +352,7 @@ void EditorManagerPrivate::init() return; DocumentManager::showFilePropertiesDialog(d->m_contextMenuEntry->fileName()); }); + connect(m_pinAction, &QAction::triggered, this, &EditorManagerPrivate::togglePinned); // Goto Previous In History Action cmd = ActionManager::registerAction(m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editDesignContext); @@ -2217,8 +2218,13 @@ bool EditorManagerPrivate::saveDocumentAs(IDocument *document) void EditorManagerPrivate::closeAllEditorsExceptVisible() { - DocumentModelPrivate::removeAllSuspendedEntries(); + DocumentModelPrivate::removeAllSuspendedEntries(DocumentModelPrivate::DoNotRemovePinnedFiles); QList documentsToClose = DocumentModel::openedDocuments(); + // Remove all pinned files from the list of files to close. + documentsToClose = Utils::filtered(documentsToClose, [](IDocument *document) { + DocumentModel::Entry *entry = DocumentModel::entryForDocument(document); + return !entry->pinned; + }); foreach (IEditor *editor, EditorManager::visibleEditors()) documentsToClose.removeAll(editor->document()); EditorManager::closeDocuments(documentsToClose, true); @@ -2303,6 +2309,15 @@ void EditorManagerPrivate::findInDirectory() emit m_instance->findOnFileSystemRequest(d->m_contextMenuEntry->fileName().parentDir().toString()); } +void EditorManagerPrivate::togglePinned() +{ + if (!d->m_contextMenuEntry || d->m_contextMenuEntry->fileName().isEmpty()) + return; + + const bool currentlyPinned = d->m_contextMenuEntry->pinned; + DocumentModelPrivate::setPinned(d->m_contextMenuEntry, !currentlyPinned); +} + void EditorManagerPrivate::split(Qt::Orientation orientation) { EditorView *view = currentEditorView(); @@ -2401,12 +2416,25 @@ bool EditorManager::closeAllEditors(bool askAboutModifiedEditors) void EditorManager::closeOtherDocuments(IDocument *document) { - DocumentModelPrivate::removeAllSuspendedEntries(); + DocumentModelPrivate::removeAllSuspendedEntries(DocumentModelPrivate::DoNotRemovePinnedFiles); QList documentsToClose = DocumentModel::openedDocuments(); + // Remove all pinned files from the list of files to close. + documentsToClose = Utils::filtered(documentsToClose, [](IDocument *document) { + DocumentModel::Entry *entry = DocumentModel::entryForDocument(document); + return !entry->pinned; + }); documentsToClose.removeAll(document); closeDocuments(documentsToClose, true); } +void EditorManager::closeAllDocuments() +{ + // Only close the files that aren't pinned. + const QList entriesToClose + = Utils::filtered(DocumentModel::entries(), Utils::equal(&DocumentModel::Entry::pinned, false)); + EditorManager::closeDocuments(entriesToClose); +} + // SLOT connected to action void EditorManager::slotCloseCurrentEditorOrDocument() { @@ -2488,6 +2516,20 @@ void EditorManager::addSaveAndCloseEditorActions(QMenu *contextMenu, DocumentMod contextMenu->addAction(d->m_closeAllEditorsExceptVisibleContextAction); } +void EditorManager::addPinEditorActions(QMenu *contextMenu, DocumentModel::Entry *entry) +{ + const QString quotedDisplayName = entry ? Utils::quoteAmpersands(entry->displayName()) : QString(); + if (entry) { + d->m_pinAction->setText(entry->pinned + ? tr("Unpin \"%1\"").arg(quotedDisplayName) + : tr("Pin \"%1\"").arg(quotedDisplayName)); + } else { + d->m_pinAction->setText(tr("Pin Editor")); + } + d->m_pinAction->setEnabled(entry != nullptr); + contextMenu->addAction(d->m_pinAction); +} + void EditorManager::addNativeDirAndOpenWithActions(QMenu *contextMenu, DocumentModel::Entry *entry) { QTC_ASSERT(contextMenu, return); @@ -2587,6 +2629,20 @@ void EditorManager::closeDocument(DocumentModel::Entry *entry) closeDocuments({entry->document}); } +void EditorManager::closeDocuments(const QList &entries) +{ + QList documentsToClose; + for (DocumentModel::Entry *entry : entries) { + if (!entry) + continue; + if (entry->isSuspended) + DocumentModelPrivate::removeEntry(entry); + else + documentsToClose << entry->document; + } + closeDocuments(documentsToClose); +} + bool EditorManager::closeEditors(const QList &editorsToClose, bool askAboutModifiedEditors) { return EditorManagerPrivate::closeEditors(editorsToClose, @@ -2906,13 +2962,13 @@ QVector editorWindows(const QList &areas) return result; } -// Save state of all non-teporary editors. +// Save state of all non-temporary editors. QByteArray EditorManager::saveState() { QByteArray bytes; QDataStream stream(&bytes, QIODevice::WriteOnly); - stream << QByteArray("EditorManagerV4"); + stream << QByteArray("EditorManagerV5"); // TODO: In case of split views it's not possible to restore these for all correctly with this QList documents = DocumentModel::openedDocuments(); @@ -2938,8 +2994,10 @@ QByteArray EditorManager::saveState() stream << entriesCount; foreach (DocumentModel::Entry *entry, entries) { - if (!entry->document->isTemporary()) - stream << entry->fileName().toString() << entry->plainDisplayName() << entry->id(); + if (!entry->document->isTemporary()) { + stream << entry->fileName().toString() << entry->plainDisplayName() << entry->id() + << entry->pinned; + } } stream << d->m_editorAreas.first()->saveState(); // TODO @@ -2964,7 +3022,8 @@ bool EditorManager::restoreState(const QByteArray &state) QByteArray version; stream >> version; - if (version != "EditorManagerV4") + const bool isVersion5 = version == "EditorManagerV5"; + if (version != "EditorManagerV4" && !isVersion5) return false; QApplication::setOverrideCursor(Qt::WaitCursor); @@ -2980,16 +3039,22 @@ bool EditorManager::restoreState(const QByteArray &state) stream >> displayName; Id id; stream >> id; + bool pinned = false; + if (isVersion5) + stream >> pinned; if (!fileName.isEmpty() && !displayName.isEmpty()) { QFileInfo fi(fileName); if (!fi.exists()) continue; QFileInfo rfi(autoSaveName(fileName)); - if (rfi.exists() && fi.lastModified() < rfi.lastModified()) - openEditor(fileName, id, DoNotMakeVisible); - else - DocumentModelPrivate::addSuspendedDocument(fileName, displayName, id); + if (rfi.exists() && fi.lastModified() < rfi.lastModified()) { + if (IEditor *editor = openEditor(fileName, id, DoNotMakeVisible)) + DocumentModelPrivate::setPinned(DocumentModel::entryForDocument(editor->document()), pinned); + } else { + if (DocumentModel::Entry *entry = DocumentModelPrivate::addSuspendedDocument(fileName, displayName, id)) + DocumentModelPrivate::setPinned(entry, pinned); + } } } diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 2ad168a5902..808d5ca198d 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -128,7 +128,9 @@ public: static bool closeDocument(IDocument *document, bool askAboutModifiedEditors = true); static bool closeDocuments(const QList &documents, bool askAboutModifiedEditors = true); static void closeDocument(DocumentModel::Entry *entry); + static void closeDocuments(const QList &entries); static void closeOtherDocuments(IDocument *document); + static void closeAllDocuments(); static void addCurrentPositionToNavigationHistory(const QByteArray &saveState = QByteArray()); static void cutForwardNavigationHistory(); @@ -161,6 +163,7 @@ public: static void addSaveAndCloseEditorActions(QMenu *contextMenu, DocumentModel::Entry *entry, IEditor *editor = nullptr); + static void addPinEditorActions(QMenu *contextMenu, DocumentModel::Entry *entry); static void addNativeDirAndOpenWithActions(QMenu *contextMenu, DocumentModel::Entry *entry); static void populateOpenWithMenu(QMenu *menu, const QString &fileName); diff --git a/src/plugins/coreplugin/editormanager/editormanager_p.h b/src/plugins/coreplugin/editormanager/editormanager_p.h index b9e021bcb8c..4dd7f62e31d 100644 --- a/src/plugins/coreplugin/editormanager/editormanager_p.h +++ b/src/plugins/coreplugin/editormanager/editormanager_p.h @@ -180,6 +180,8 @@ private: static void openTerminal(); static void findInDirectory(); + static void togglePinned(); + static void removeCurrentSplit(); static void setCurrentEditorFromContextChange(); @@ -251,6 +253,7 @@ private: QAction *m_openTerminalAction; QAction *m_findInDirectoryAction; QAction *m_filePropertiesAction = nullptr; + QAction *m_pinAction = nullptr; DocumentModel::Entry *m_contextMenuEntry = nullptr; IEditor *m_contextMenuEditor = nullptr; diff --git a/src/plugins/coreplugin/editormanager/openeditorsview.cpp b/src/plugins/coreplugin/editormanager/openeditorsview.cpp index 234fe28e5a2..a467e089be4 100644 --- a/src/plugins/coreplugin/editormanager/openeditorsview.cpp +++ b/src/plugins/coreplugin/editormanager/openeditorsview.cpp @@ -115,10 +115,12 @@ void OpenEditorsWidget::contextMenuRequested(QPoint pos) { QMenu contextMenu; QModelIndex editorIndex = indexAt(pos); - DocumentModel::Entry *entry = DocumentModel::entryAtRow( - m_model->mapToSource(editorIndex).row()); + const int row = m_model->mapToSource(editorIndex).row(); + DocumentModel::Entry *entry = DocumentModel::entryAtRow(row); EditorManager::addSaveAndCloseEditorActions(&contextMenu, entry); contextMenu.addSeparator(); + EditorManager::addPinEditorActions(&contextMenu, entry); + contextMenu.addSeparator(); EditorManager::addNativeDirAndOpenWithActions(&contextMenu, entry); contextMenu.exec(mapToGlobal(pos)); } diff --git a/src/plugins/coreplugin/editortoolbar.cpp b/src/plugins/coreplugin/editortoolbar.cpp index c138d9d2045..b96e4e86e0e 100644 --- a/src/plugins/coreplugin/editortoolbar.cpp +++ b/src/plugins/coreplugin/editortoolbar.cpp @@ -354,6 +354,8 @@ void EditorToolBar::fillListContextMenu(QMenu *menu) : nullptr; EditorManager::addSaveAndCloseEditorActions(menu, entry, editor); menu->addSeparator(); + EditorManager::addPinEditorActions(menu, entry); + menu->addSeparator(); EditorManager::addNativeDirAndOpenWithActions(menu, entry); } } diff --git a/src/plugins/coreplugin/idocument.cpp b/src/plugins/coreplugin/idocument.cpp index e5a78b32d5b..1f0d2f8c249 100644 --- a/src/plugins/coreplugin/idocument.cpp +++ b/src/plugins/coreplugin/idocument.cpp @@ -79,6 +79,7 @@ public: bool hasWriteWarning = false; bool restored = false; bool isSuspendAllowed = false; + bool pinned = false; }; } // namespace Internal diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp index c3936edf5b1..4100d451ee2 100644 --- a/src/plugins/qmldesigner/shortcutmanager.cpp +++ b/src/plugins/qmldesigner/shortcutmanager.cpp @@ -159,7 +159,7 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex //Close All Core::ActionManager::registerAction(&m_closeAllEditorsAction, Core::Constants::CLOSEALL, qmlDesignerMainContext); - connect(&m_closeAllEditorsAction, &QAction::triggered, em, &Core::EditorManager::closeAllEditors); + connect(&m_closeAllEditorsAction, &QAction::triggered, em, &Core::EditorManager::closeAllDocuments); //Close All Others Action Core::ActionManager::registerAction(&m_closeOtherEditorsAction, Core::Constants::CLOSEOTHERS, qmlDesignerMainContext); diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 4a05e427bbb..d7dc0172eb1 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -6597,6 +6597,24 @@ d="m 210,595 -2.5,2.5 -2.5,-2.5 z" style="fill:#000000;fill-opacity:1;stroke:none" /> + + + +