File indexing completed on 2024-04-28 04:38:10

0001 /*
0002     SPDX-FileCopyrightText: 2006 Adam Treat <treat@kde.org>
0003     SPDX-FileCopyrightText: 2006-2008 Hamish Rodda <rodda@kde.org>
0004     SPDX-FileCopyrightText: 2009 Lior Mualem <lior.m.kde@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "classbrowserplugin.h"
0010 
0011 #include <QAction>
0012 
0013 #include <KLocalizedString>
0014 #include <KPluginFactory>
0015 
0016 #include "interfaces/icore.h"
0017 #include "interfaces/iuicontroller.h"
0018 #include "interfaces/idocumentcontroller.h"
0019 #include "interfaces/contextmenuextension.h"
0020 
0021 #include "language/interfaces/codecontext.h"
0022 #include "language/duchain/duchainbase.h"
0023 #include "language/duchain/duchain.h"
0024 #include "language/duchain/duchainlock.h"
0025 #include "language/duchain/declaration.h"
0026 
0027 #include "debug.h"
0028 #include "classtree.h"
0029 #include "classwidget.h"
0030 #include <language/duchain/persistentsymboltable.h>
0031 #include <language/duchain/functiondeclaration.h>
0032 #include <language/duchain/classfunctiondeclaration.h>
0033 #include <language/duchain/functiondefinition.h>
0034 #include <interfaces/iprojectcontroller.h>
0035 
0036 K_PLUGIN_FACTORY_WITH_JSON(KDevClassBrowserFactory, "kdevclassbrowser.json", registerPlugin<ClassBrowserPlugin>(); )
0037 
0038 using namespace KDevelop;
0039 
0040 class ClassBrowserFactory
0041     : public KDevelop::IToolViewFactory
0042 {
0043 public:
0044     explicit ClassBrowserFactory(ClassBrowserPlugin* plugin) : m_plugin(plugin) {}
0045 
0046     QWidget* create(QWidget* parent = nullptr) override
0047     {
0048         return new ClassWidget(parent, m_plugin);
0049     }
0050 
0051     Qt::DockWidgetArea defaultPosition() const override
0052     {
0053         return Qt::LeftDockWidgetArea;
0054     }
0055 
0056     QString id() const override
0057     {
0058         return QStringLiteral("org.kdevelop.ClassBrowserView");
0059     }
0060 
0061 private:
0062     ClassBrowserPlugin* m_plugin;
0063 };
0064 
0065 ClassBrowserPlugin::ClassBrowserPlugin(QObject* parent, const QVariantList&)
0066     : KDevelop::IPlugin(QStringLiteral("kdevclassbrowser"), parent)
0067     , m_factory(new ClassBrowserFactory(this))
0068     , m_activeClassTree(nullptr)
0069 {
0070     core()->uiController()->addToolView(i18nc("@title:window", "Classes"), m_factory);
0071     setXMLFile(QStringLiteral("kdevclassbrowser.rc"));
0072 
0073     m_findInBrowser = new QAction(i18nc("@action", "Find in &Class Browser"), this);
0074     connect(m_findInBrowser, &QAction::triggered, this, &ClassBrowserPlugin::findInClassBrowser);
0075 }
0076 
0077 ClassBrowserPlugin::~ClassBrowserPlugin()
0078 {
0079 }
0080 
0081 void ClassBrowserPlugin::unload()
0082 {
0083     core()->uiController()->removeToolView(m_factory);
0084 }
0085 
0086 KDevelop::ContextMenuExtension ClassBrowserPlugin::contextMenuExtension(KDevelop::Context* context, QWidget* parent)
0087 {
0088     KDevelop::ContextMenuExtension menuExt = KDevelop::IPlugin::contextMenuExtension(context, parent);
0089 
0090     // No context menu if we don't have a class browser at hand.
0091     if (m_activeClassTree == nullptr)
0092         return menuExt;
0093 
0094     auto* codeContext = dynamic_cast<KDevelop::DeclarationContext*>(context);
0095 
0096     if (!codeContext)
0097         return menuExt;
0098 
0099     DUChainReadLocker readLock(DUChain::lock());
0100     Declaration* decl(codeContext->declaration().data());
0101 
0102     if (decl) {
0103         if (decl->inSymbolTable()) {
0104             if (!ClassTree::populatingClassBrowserContextMenu() &&
0105                 ICore::self()->projectController()->findProjectForUrl(decl->url().toUrl()) &&
0106                 decl->kind() == Declaration::Type && decl->internalContext() &&
0107                 decl->internalContext()->type() == DUContext::Class) {
0108                 //Currently "Find in Class Browser" seems to only work for classes, so only show it in that case
0109 
0110                 m_findInBrowser->setData(QVariant::fromValue(DUChainBasePointer(decl)));
0111                 menuExt.addAction(KDevelop::ContextMenuExtension::NavigationGroup, m_findInBrowser);
0112             }
0113         }
0114     }
0115 
0116     return menuExt;
0117 }
0118 
0119 void ClassBrowserPlugin::findInClassBrowser()
0120 {
0121     ICore::self()->uiController()->findToolView(i18nc("@title:window", "Classes"), m_factory, KDevelop::IUiController::CreateAndRaise);
0122 
0123     Q_ASSERT(qobject_cast<QAction*>(sender()));
0124 
0125     if (m_activeClassTree == nullptr)
0126         return;
0127 
0128     DUChainReadLocker readLock(DUChain::lock());
0129 
0130     auto* a = static_cast<QAction*>(sender());
0131 
0132     Q_ASSERT(a->data().canConvert<DUChainBasePointer>());
0133 
0134     DeclarationPointer decl = qvariant_cast<DUChainBasePointer>(a->data()).dynamicCast<Declaration>();
0135     if (decl)
0136         m_activeClassTree->highlightIdentifier(decl->qualifiedIdentifier());
0137 }
0138 
0139 void ClassBrowserPlugin::showDefinition(const DeclarationPointer& declaration)
0140 {
0141     DUChainReadLocker readLock(DUChain::lock());
0142 
0143     if (!declaration)
0144         return;
0145 
0146     Declaration* decl = declaration.data();
0147     // If it's a function, find the function definition to go to the actual declaration.
0148     if (decl && decl->isFunctionDeclaration()) {
0149         if (auto* funcDefinition = FunctionDefinition::definition(decl))
0150             decl = funcDefinition;
0151     }
0152 
0153     if (decl) {
0154         QUrl url = decl->url().toUrl();
0155         KTextEditor::Range range = decl->rangeInCurrentRevision();
0156 
0157         readLock.unlock();
0158 
0159         ICore::self()->documentController()->openDocument(url, range.start());
0160     }
0161 }
0162 
0163 #include "classbrowserplugin.moc"
0164 #include "moc_classbrowserplugin.cpp"