diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h index 1c5cffee98f..1d4c0cc18b4 100644 --- a/src/plugins/cppeditor/cppeditorconstants.h +++ b/src/plugins/cppeditor/cppeditorconstants.h @@ -22,9 +22,6 @@ const char M_REFACTORING_MENU_INSERTION_POINT[] = "CppEditor.RefactorGroup"; const char UPDATE_CODEMODEL[] = "CppEditor.UpdateCodeModel"; const char INSPECT_CPP_CODEMODEL[] = "CppEditor.InspectCppCodeModel"; -const char TYPE_HIERARCHY_ID[] = "CppEditor.TypeHierarchy"; -const char OPEN_TYPE_HIERARCHY[] = "CppEditor.OpenTypeHierarchy"; - const char INCLUDE_HIERARCHY_ID[] = "CppEditor.IncludeHierarchy"; const char OPEN_INCLUDE_HIERARCHY[] = "CppEditor.OpenIncludeHierarchy"; diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 5b9e360be79..a98a76ec423 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -144,6 +144,7 @@ public: | TextEditorActionHandler::FollowSymbolUnderCursor | TextEditorActionHandler::FollowTypeUnderCursor | TextEditorActionHandler::RenameSymbol + | TextEditorActionHandler::TypeHierarchy | TextEditorActionHandler::FindUsage); } }; @@ -358,6 +359,7 @@ void CppEditorPlugin::addPerSymbolActions() setupCppTypeHierarchy(); + addSymbolActionToMenus(TextEditor::Constants::OPEN_TYPE_HIERARCHY); addSymbolActionToMenus(TextEditor::Constants::OPEN_CALL_HIERARCHY); // Refactoring sub-menu diff --git a/src/plugins/cppeditor/cpptypehierarchy.cpp b/src/plugins/cppeditor/cpptypehierarchy.cpp index 57b3e95f1a7..d0a523ce133 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.cpp +++ b/src/plugins/cppeditor/cpptypehierarchy.cpp @@ -4,6 +4,7 @@ #include "cpptypehierarchy.h" #include "cppeditorconstants.h" +#include "cppeditordocument.h" #include "cppeditortr.h" #include "cppeditorwidget.h" #include "cppelementevaluator.h" @@ -11,11 +12,10 @@ #include #include #include -#include -#include #include #include +#include #include #include @@ -53,7 +53,7 @@ public: QMimeData *mimeData(const QModelIndexList &indexes) const override; }; -class CppTypeHierarchyWidget : public QWidget +class CppTypeHierarchyWidget : public TextEditor::TypeHierarchyWidget { public: CppTypeHierarchyWidget(); @@ -61,6 +61,8 @@ public: void perform(); private: + void reload() override { perform(); } + void displayHierarchy(); typedef QList CppClass::*HierarchyMember; void performFromExpression(const QString &expression, const FilePath &filePath); @@ -87,6 +89,7 @@ private: ProgressIndicator *m_progressIndicator = nullptr; QString m_oldClass; bool m_showOldClass = false; + int m_runningIndexers = 0; }; enum ItemRole { @@ -197,10 +200,22 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget() connect(&m_futureWatcher, &QFutureWatcher::finished, this, &CppTypeHierarchyWidget::displayHierarchy); + + connect(ProgressManager::instance(), &ProgressManager::taskStarted, [this](Id type) { + if (type == Constants::TASK_INDEX) + ++m_runningIndexers; + }); + connect(ProgressManager::instance(), &ProgressManager::allTasksFinished, [this](Id type) { + if (type == Constants::TASK_INDEX) + --m_runningIndexers; + }); } void CppTypeHierarchyWidget::perform() { + if (m_runningIndexers > 0) + return; + if (m_future.isRunning()) m_future.cancel(); @@ -397,47 +412,19 @@ QMimeData *CppTypeHierarchyModel::mimeData(const QModelIndexList &indexes) const // CppTypeHierarchyFactory -class CppTypeHierarchyFactory final : public INavigationWidgetFactory +class CppTypeHierarchyFactory final : public TextEditor::TypeHierarchyWidgetFactory { -public: - CppTypeHierarchyFactory() + TextEditor::TypeHierarchyWidget *createWidget(Core::IEditor *editor) final { - setDisplayName(Tr::tr("Type Hierarchy")); - setPriority(700); - setId(Constants::TYPE_HIERARCHY_ID); + const auto textEditor = qobject_cast(editor); + if (!textEditor) + return nullptr; + const auto cppDoc = qobject_cast(textEditor->textDocument()); + if (!cppDoc /* || cppDoc->usesClangd() */) + return nullptr; - ActionBuilder openTypeHierarchy(this, Constants::OPEN_TYPE_HIERARCHY); - openTypeHierarchy.setText(Tr::tr("Open Type Hierarchy")); - openTypeHierarchy.setContext(Context(Constants::CPPEDITOR_ID)); - openTypeHierarchy.bindContextAction(&m_openTypeHierarchyAction); - openTypeHierarchy.setDefaultKeySequence(Tr::tr("Meta+Shift+T"), Tr::tr("Ctrl+Shift+T")); - openTypeHierarchy.addToContainers({Constants::M_TOOLS_CPP, Constants::M_CONTEXT}, - Constants::G_SYMBOL); - - connect(m_openTypeHierarchyAction, &QAction::triggered, this, [] { - NavigationWidget::activateSubWidget(Constants::TYPE_HIERARCHY_ID, Side::Left); - }); - - connect(ProgressManager::instance(), &ProgressManager::taskStarted, [this](Id type) { - if (type == Constants::TASK_INDEX) - m_openTypeHierarchyAction->setEnabled(false); - }); - connect(ProgressManager::instance(), &ProgressManager::allTasksFinished, [this](Id type) { - if (type == Constants::TASK_INDEX) - m_openTypeHierarchyAction->setEnabled(true); - }); + return new CppTypeHierarchyWidget; } - - NavigationView createWidget() final - { - auto w = new CppTypeHierarchyWidget; - connect(m_openTypeHierarchyAction, &QAction::triggered, w, &CppTypeHierarchyWidget::perform); - w->perform(); - - return {w, {}}; - } - - QAction *m_openTypeHierarchyAction = nullptr; }; static CppTypeHierarchyFactory &cppTypeHierarchyFactory() @@ -446,11 +433,6 @@ static CppTypeHierarchyFactory &cppTypeHierarchyFactory() return theCppTypeHierarchyFactory; } -void openCppTypeHierarchy() -{ - cppTypeHierarchyFactory().m_openTypeHierarchyAction->trigger(); -} - void setupCppTypeHierarchy() { (void) cppTypeHierarchyFactory(); // Trigger instantiation diff --git a/src/plugins/cppeditor/cpptypehierarchy.h b/src/plugins/cppeditor/cpptypehierarchy.h index c6c99f214f7..ffe7edbc134 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.h +++ b/src/plugins/cppeditor/cpptypehierarchy.h @@ -4,8 +4,5 @@ #pragma once namespace CppEditor::Internal { - -void openCppTypeHierarchy(); void setupCppTypeHierarchy(); - } // CppEditor::Internal diff --git a/src/plugins/cppeditor/fileandtokenactions_test.cpp b/src/plugins/cppeditor/fileandtokenactions_test.cpp index f341cc1808d..5acca7fa116 100644 --- a/src/plugins/cppeditor/fileandtokenactions_test.cpp +++ b/src/plugins/cppeditor/fileandtokenactions_test.cpp @@ -9,7 +9,6 @@ #include "cppinsertvirtualmethods.h" #include "cppmodelmanager.h" #include "cpptoolstestcase.h" -#include "cpptypehierarchy.h" #include "cppworkingcopy.h" #include "projectinfo.h" @@ -18,6 +17,7 @@ #include #include #include +#include #include #include @@ -383,7 +383,7 @@ public: void OpenTypeHierarchyTokenAction::run(CppEditorWidget *) { - openCppTypeHierarchy(); + TextEditor::openTypeHierarchy(); QApplication::processEvents(); } diff --git a/src/plugins/texteditor/CMakeLists.txt b/src/plugins/texteditor/CMakeLists.txt index 886b98390ce..c36d4121ece 100644 --- a/src/plugins/texteditor/CMakeLists.txt +++ b/src/plugins/texteditor/CMakeLists.txt @@ -113,6 +113,7 @@ add_qtc_plugin(TextEditor textindenter.cpp textindenter.h textmark.cpp textmark.h textstyles.h + typehierarchy.cpp typehierarchy.h typingsettings.cpp typingsettings.h ) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 3256ee91b79..42daeeff6d3 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -8759,6 +8759,11 @@ void TextEditorWidget::appendStandardContextMenuActions(QMenu *menu) if (!menu->actions().contains(action)) menu->addAction(action); } + if (optionalActions() & TextEditorActionHandler::TypeHierarchy) { + const auto action = ActionManager::command(Constants::OPEN_TYPE_HIERARCHY)->action(); + if (!menu->actions().contains(action)) + menu->addAction(action); + } menu->addSeparator(); appendMenuActionsFromContext(menu, Constants::M_STANDARDCONTEXTMENU); diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index 821d9a4a479..41fe08d51b5 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -137,7 +137,8 @@ QtcPlugin { "texteditor.cpp", "texteditor.h", "texteditor.qrc", - "texteditor_global.h", "texteditortr.h", + "texteditor_global.h", + "texteditortr.h", "texteditoractionhandler.cpp", "texteditoractionhandler.h", "texteditorconstants.cpp", @@ -152,6 +153,8 @@ QtcPlugin { "textmark.cpp", "textmark.h", "textstyles.h", + "typehierarchy.cpp", + "typehierarchy.h", "typingsettings.cpp", "typingsettings.h", ] diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp index 240e8498ed1..2cf553689cc 100644 --- a/src/plugins/texteditor/texteditoractionhandler.cpp +++ b/src/plugins/texteditor/texteditoractionhandler.cpp @@ -9,6 +9,7 @@ #include "linenumberfilter.h" #include "texteditortr.h" #include "texteditorsettings.h" +#include "typehierarchy.h" #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +139,7 @@ public: QAction *m_followToTypeInNextSplitAction = nullptr; QAction *m_findUsageAction = nullptr; QAction *m_openCallHierarchyAction = nullptr; + QAction *m_openTypeHierarchyAction = nullptr; QAction *m_renameSymbolAction = nullptr; QAction *m_jumpToFileAction = nullptr; QAction *m_jumpToFileInNextSplitAction = nullptr; @@ -269,7 +272,17 @@ void TextEditorActionHandlerPrivate::createActions() QKeySequence(Utils::HostOsInfo::isMacHost() ? Tr::tr("Meta+E, F2") : Tr::tr("Ctrl+E, F2")).toString()); m_openCallHierarchyAction = registerAction(OPEN_CALL_HIERARCHY, [] (TextEditorWidget *w) { w->openCallHierarchy(); }, true, Tr::tr("Open Call Hierarchy")); - + m_openTypeHierarchyAction = registerAction( + OPEN_TYPE_HIERARCHY, + [](TextEditorWidget *) { + updateTypeHierarchy( + NavigationWidget::activateSubWidget(Constants::TYPE_HIERARCHY_FACTORY_ID, + Side::Left)); + }, + true, + Tr::tr("Open Type Hierarchy"), + QKeySequence(Utils::HostOsInfo::isMacHost() ? Tr::tr("Meta+Shift+T") + : Tr::tr("Ctrl+Shift+T"))); registerAction(VIEW_PAGE_UP, [] (TextEditorWidget *w) { w->viewPageUp(); }, true, Tr::tr("Move the View a Page Up and Keep the Cursor Position"), QKeySequence(Tr::tr("Ctrl+PgUp"))); @@ -550,6 +563,8 @@ void TextEditorActionHandlerPrivate::updateOptionalActions() optionalActions & TextEditorActionHandler::RenameSymbol); m_openCallHierarchyAction->setEnabled( optionalActions & TextEditorActionHandler::CallHierarchy); + m_openTypeHierarchyAction->setEnabled( + optionalActions & TextEditorActionHandler::TypeHierarchy); bool formatEnabled = (optionalActions & TextEditorActionHandler::Format) && m_currentEditorWidget && !m_currentEditorWidget->isReadOnly(); diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h index 344a4a553e1..ce969b7b6f1 100644 --- a/src/plugins/texteditor/texteditoractionhandler.h +++ b/src/plugins/texteditor/texteditoractionhandler.h @@ -38,7 +38,8 @@ public: JumpToFileUnderCursor = 32, RenameSymbol = 64, FindUsage = 128, - CallHierarchy = 256 + CallHierarchy = 256, + TypeHierarchy = 512, }; using TextEditorWidgetResolver = std::function; diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index e2115261882..2597deb6bba 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -212,6 +212,8 @@ const char FIND_USAGES[] = "TextEditor.FindUsages"; // moved from CppEditor to TextEditor avoid breaking the setting by using the old key const char RENAME_SYMBOL[] = "CppEditor.RenameSymbolUnderCursor"; const char OPEN_CALL_HIERARCHY[] = "TextEditor.OpenCallHierarchy"; +const char OPEN_TYPE_HIERARCHY[] = "TextEditor.OpenTypeHierarchy"; +const char TYPE_HIERARCHY_FACTORY_ID[] = "TextEditor.TypeHierarchy"; const char JUMP_TO_FILE_UNDER_CURSOR[] = "TextEditor.JumpToFileUnderCursor"; const char JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.JumpToFileUnderCursorInNextSplit"; diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index 04f11bcbb0b..d279b6254f4 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -26,6 +26,7 @@ #include "texteditorsettings.h" #include "texteditortr.h" #include "textmark.h" +#include "typehierarchy.h" #include "typingsettings.h" #ifdef WITH_TESTS @@ -105,6 +106,7 @@ void TextEditorPlugin::initialize() setupTextMarkRegistry(this); setupOutlineFactory(); + setupTypeHierarchyFactory(); setupLineNumberFilter(); // Goto line functionality for quick open setupPlainTextEditor(); diff --git a/src/plugins/texteditor/typehierarchy.cpp b/src/plugins/texteditor/typehierarchy.cpp new file mode 100644 index 00000000000..53924a2b9d6 --- /dev/null +++ b/src/plugins/texteditor/typehierarchy.cpp @@ -0,0 +1,136 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "typehierarchy.h" + +#include "texteditorconstants.h" +#include "texteditortr.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace Utils; + +namespace TextEditor { +namespace Internal { + +static QList g_widgetFactories; + +class TypeHierarchyFactory : public Core::INavigationWidgetFactory +{ +public: + TypeHierarchyFactory() + { + setDisplayName(Tr::tr("Type Hierarchy")); + setPriority(649); + setId(Constants::TYPE_HIERARCHY_FACTORY_ID); + } + +private: + Core::NavigationView createWidget() override; +}; + +class TypeHierarchyWidgetStack : public QStackedWidget +{ + Q_OBJECT + +public: + TypeHierarchyWidgetStack(); + + void reload(); +}; + +static TypeHierarchyFactory &typeHierarchyFactory() +{ + static TypeHierarchyFactory theFactory; + return theFactory; +} + +void setupTypeHierarchyFactory() +{ + (void) typeHierarchyFactory(); +} + +TypeHierarchyWidgetStack::TypeHierarchyWidgetStack() +{ + QLabel *label = new QLabel(Tr::tr("No type hierarchy available"), this); + label->setAlignment(Qt::AlignCenter); + + label->setAutoFillBackground(true); + label->setBackgroundRole(QPalette::Base); + + addWidget(label); + reload(); +} + +void TypeHierarchyWidgetStack::reload() +{ + const auto editor = Core::EditorManager::currentEditor(); + TypeHierarchyWidget *newWidget = nullptr; + + if (editor) { + for (TypeHierarchyWidgetFactory * const widgetFactory : std::as_const(g_widgetFactories)) { + if ((newWidget = widgetFactory->createWidget(editor))) + break; + } + } + + QWidget * const current = currentWidget(); + if (current) { + removeWidget(current); + current->deleteLater(); + } + if (newWidget) { + addWidget(newWidget); + setCurrentWidget(newWidget); + setFocusProxy(newWidget); + newWidget->reload(); + } +} + +Core::NavigationView TypeHierarchyFactory::createWidget() +{ + const auto placeholder = new TypeHierarchyWidgetStack; + const auto reloadButton = new QToolButton; + reloadButton->setIcon(Icons::RELOAD_TOOLBAR.icon()); + reloadButton->setToolTip(Tr::tr("Reloads the type hierarchy for the symbol under the cursor.")); + connect(reloadButton, &QToolButton::clicked, placeholder, &TypeHierarchyWidgetStack::reload); + return {placeholder, {reloadButton}}; +} + +void updateTypeHierarchy(QWidget *widget) +{ + if (const auto w = qobject_cast(widget)) + w->reload(); +} + +} // namespace Internal + +TypeHierarchyWidgetFactory::TypeHierarchyWidgetFactory() +{ + Internal::g_widgetFactories.append(this); +} + +TypeHierarchyWidgetFactory::~TypeHierarchyWidgetFactory() +{ + Internal::g_widgetFactories.removeOne(this); +} + +void openTypeHierarchy() +{ + if (const auto action = Core::ActionManager::command(Constants::OPEN_TYPE_HIERARCHY)->action()) + action->trigger(); +} + +} // namespace TextEditor + +#include diff --git a/src/plugins/texteditor/typehierarchy.h b/src/plugins/texteditor/typehierarchy.h new file mode 100644 index 00000000000..ee7c1fa1a7b --- /dev/null +++ b/src/plugins/texteditor/typehierarchy.h @@ -0,0 +1,39 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include + +namespace Core { class IEditor; } + +namespace TextEditor { +namespace Internal { +void setupTypeHierarchyFactory(); +void updateTypeHierarchy(QWidget *widget); +} + +class TEXTEDITOR_EXPORT TypeHierarchyWidget : public QWidget +{ + Q_OBJECT +public: + virtual void reload() = 0; +}; + +class TEXTEDITOR_EXPORT TypeHierarchyWidgetFactory : public QObject +{ + Q_OBJECT + +public: + virtual TypeHierarchyWidget *createWidget(Core::IEditor *editor) = 0; + +protected: + TypeHierarchyWidgetFactory(); + ~TypeHierarchyWidgetFactory() override; +}; + +TEXTEDITOR_EXPORT void openTypeHierarchy(); + +} // namespace TextEditor