kde-extraapps/kdevplatform/shell/documentationcontroller.cpp
2015-07-26 14:23:17 +03:00

245 lines
8 KiB
C++

/*
Copyright 2009 Aleix Pol Gonzalez <aleixpol@kde.org>
Copyright 2010 Benjamin Port <port.benjamin@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "documentationcontroller.h"
#include <interfaces/iplugin.h>
#include <interfaces/idocumentationprovider.h>
#include <interfaces/idocumentationproviderprovider.h>
#include <interfaces/icore.h>
#include <interfaces/iplugincontroller.h>
#include <interfaces/iuicontroller.h>
#include <shell/core.h>
#include <ktexteditor/document.h>
#include <ktexteditor/view.h>
#include <KDebug>
#include <interfaces/contextmenuextension.h>
#include <interfaces/idocumentcontroller.h>
#include <language/interfaces/codecontext.h>
#include <language/duchain/duchain.h>
#include <language/duchain/duchainlock.h>
#include <language/duchain/duchainutils.h>
#include <language/duchain/types/identifiedtype.h>
#include <language/duchain/types/typeutils.h>
#include <documentation/documentationview.h>
#include <KParts/MainWindow>
#include <KActionCollection>
using namespace KDevelop;
namespace {
/**
* Return a "more useful" declaration that documentation providers can look-up
*
* @code
* QPoint point;
* ^-- cursor here
* @endcode
*
* In this case, this method returns a Declaration pointer to the *type*
* instead of a pointer to the instance, which is more useful when looking for help
*
* @return A more appropriate Declaration pointer or the given parameter @p decl
*/
Declaration* usefulDeclaration(Declaration* decl)
{
if (!decl)
return nullptr;
// First: Attempt to find the declaration of a definition
decl = DUChainUtils::declarationForDefinition(decl);
// Convenience feature: Retrieve the type declaration of instances,
// it makes no sense to pass the declaration pointer of instances of types
if (decl->kind() == Declaration::Instance) {
AbstractType::Ptr type = TypeUtils::targetTypeKeepAliases(decl->abstractType(), decl->topContext());
IdentifiedType* idType = dynamic_cast<IdentifiedType*>(type.unsafeData());
Declaration* idDecl = idType ? idType->declaration(decl->topContext()) : 0;
if (idDecl) {
decl = idDecl;
}
}
return decl;
}
}
class DocumentationViewFactory: public KDevelop::IToolViewFactory
{
public:
DocumentationViewFactory()
: mProvidersModel(0)
{}
virtual QWidget* create( QWidget *parent = 0 )
{
return new DocumentationView( parent, providers() );
}
virtual Qt::DockWidgetArea defaultPosition() { return Qt::RightDockWidgetArea; }
virtual QString id() const { return "org.kdevelop.DocumentationView"; }
private:
ProvidersModel* providers() {
if(!mProvidersModel)
mProvidersModel = new ProvidersModel;
return mProvidersModel;
}
ProvidersModel* mProvidersModel;
};
DocumentationController::DocumentationController(Core* core)
: m_factory(new DocumentationViewFactory)
{
m_showDocumentation = core->uiController()->activeMainWindow()->actionCollection()->addAction("showDocumentation");
m_showDocumentation->setText(i18n("Show Documentation"));
m_showDocumentation->setIcon(KIcon("documentation"));
connect(m_showDocumentation, SIGNAL(triggered(bool)), SLOT(doShowDocumentation()));
}
void DocumentationController::initialize()
{
if(!documentationProviders().isEmpty() && !(Core::self()->setupFlags() & Core::NoUi)) {
Core::self()->uiController()->addToolView( i18n("Documentation"), m_factory );
}
}
void KDevelop::DocumentationController::doShowDocumentation()
{
IDocument* doc = ICore::self()->documentController()->activeDocument();
if(!doc)
return;
KTextEditor::Document* textDoc = doc->textDocument();
if(!textDoc)
return;
KTextEditor::View* view = textDoc->activeView();
if(!view)
return;
KDevelop::DUChainReadLocker lock( DUChain::lock() );
Declaration* decl = usefulDeclaration(DUChainUtils::itemUnderCursor(doc->url(), SimpleCursor(view->cursorPosition())));
KSharedPtr<IDocumentation> documentation = documentationForDeclaration(decl);
if(documentation) {
showDocumentation(documentation);
}
}
Q_DECLARE_METATYPE(KSharedPtr<KDevelop::IDocumentation>)
KDevelop::ContextMenuExtension KDevelop::DocumentationController::contextMenuExtension ( Context* context )
{
ContextMenuExtension menuExt;
qRegisterMetaType<KSharedPtr<KDevelop::IDocumentation> >("KSharedPtr<KDevelop::IDocumentation>");
DeclarationContext* ctx = dynamic_cast<DeclarationContext*>(context);
if(ctx) {
DUChainReadLocker lock(DUChain::lock());
if(!ctx->declaration().data())
return menuExt;
KSharedPtr< IDocumentation > doc = documentationForDeclaration(ctx->declaration().data());
if(doc) {
menuExt.addAction(ContextMenuExtension::ExtensionGroup, m_showDocumentation);;
}
}
return menuExt;
}
KSharedPtr< KDevelop::IDocumentation > DocumentationController::documentationForDeclaration(Declaration* decl)
{
if (!decl)
return KSharedPtr<IDocumentation>();
KSharedPtr<KDevelop::IDocumentation> ret;
foreach(IDocumentationProvider* doc, documentationProviders())
{
kDebug(9529) << "Documentation provider found:" << doc;
ret=doc->documentationForDeclaration(decl);
kDebug(9529) << "Documentation proposed: " << ret;
if(ret)
break;
}
return ret;
}
QList< IDocumentationProvider* > DocumentationController::documentationProviders() const
{
QList<IPlugin*> plugins=ICore::self()->pluginController()->allPluginsForExtension("org.kdevelop.IDocumentationProvider");
QList<IPlugin*> pluginsProvider=ICore::self()->pluginController()->allPluginsForExtension("org.kdevelop.IDocumentationProviderProvider");
QList<IDocumentationProvider*> ret;
foreach(IPlugin* p, pluginsProvider)
{
IDocumentationProviderProvider *docProvider=p->extension<IDocumentationProviderProvider>();
if (!docProvider) {
kWarning() << "plugin" << p << "does not implement ProviderProvider extension, rerun kbuildsycoca4";
continue;
}
ret.append(docProvider->providers());
}
foreach(IPlugin* p, plugins)
{
IDocumentationProvider *doc=p->extension<IDocumentationProvider>();
if (!doc) {
kWarning() << "plugin" << p << "does not implement Provider extension, rerun kbuildsycoca4";
continue;
}
ret.append(doc);
}
return ret;
}
void KDevelop::DocumentationController::showDocumentation(KSharedPtr< KDevelop::IDocumentation > doc)
{
QWidget* w = ICore::self()->uiController()->findToolView(i18n("Documentation"), m_factory, KDevelop::IUiController::CreateAndRaise);
if(!w) {
kWarning() << "Could not add documentation toolview";
return;
}
DocumentationView* view = dynamic_cast<DocumentationView*>(w);
if( !view ) {
kWarning() << "Could not cast toolview" << w << "to DocumentationView class!";
return;
}
view->showDocumentation(doc);
}
void DocumentationController::changedDocumentationProviders()
{
emit providersChanged();
}
#include "moc_documentationcontroller.cpp"