kde-extraapps/kdevplatform/plugins/contextbrowser/contextbrowserview.cpp
2015-07-26 14:23:17 +03:00

324 lines
11 KiB
C++

/*
* This file is part of KDevelop
*
* Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "contextbrowserview.h"
///TODO: cleanup includes
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QToolButton>
#include <QShowEvent>
#include <QAction>
#include <QMenu>
#include <KIcon>
#include <KTextBrowser>
#include <KLocale>
#include <KComboBox>
#include <ktexteditor/document.h>
#include <ktexteditor/view.h>
#include <language/duchain/declaration.h>
#include <language/duchain/topducontext.h>
#include <language/duchain/ducontext.h>
#include <language/duchain/duchain.h>
#include <language/duchain/duchainlock.h>
#include <language/duchain/indexedstring.h>
#include <interfaces/icore.h>
#include <interfaces/idocumentcontroller.h>
#include "contextbrowser.h"
#include <language/duchain/duchainutils.h>
#include <language/duchain/types/functiontype.h>
#include <language/duchain/specializationstore.h>
#include "browsemanager.h"
#include <language/duchain/navigation/abstractnavigationwidget.h>
#include <kparts/part.h>
#include <qapplication.h>
#include <language/interfaces/codecontext.h>
#include <language/duchain/navigation/abstractdeclarationnavigationcontext.h>
#include <language/duchain/navigation/useswidget.h>
#include <interfaces/contextmenuextension.h>
#include <interfaces/iplugincontroller.h>
using namespace KDevelop;
QWidget* ContextBrowserView::createWidget(KDevelop::DUContext* context) {
m_context = IndexedDUContext(context);
if(m_context.data()) {
return m_context.data()->createNavigationWidget();
}
return 0;
}
KDevelop::IndexedDeclaration ContextBrowserView::declaration() const {
return m_declaration;
}
QWidget* ContextBrowserView::createWidget(Declaration* decl, TopDUContext* topContext) {
m_declaration = IndexedDeclaration(decl);
return decl->context()->createNavigationWidget(decl, topContext);
}
void ContextBrowserView::resetWidget()
{
if (m_navigationWidget) {
delete m_navigationWidget;
m_navigationWidget = 0;
}
}
void ContextBrowserView::declarationMenu() {
DUChainReadLocker lock(DUChain::lock());
AbstractNavigationWidget* navigationWidget = dynamic_cast<AbstractNavigationWidget*>(m_navigationWidget.data());
if(navigationWidget) {
AbstractDeclarationNavigationContext* navigationContext = dynamic_cast<AbstractDeclarationNavigationContext*>(navigationWidget->context().data());
if(navigationContext && navigationContext->declaration().data()) {
KDevelop::DeclarationContext* c = new KDevelop::DeclarationContext(navigationContext->declaration().data());
lock.unlock();
QMenu menu;
QList<ContextMenuExtension> extensions = ICore::self()->pluginController()->queryPluginsForContextMenuExtensions( c );
ContextMenuExtension::populateMenu(&menu, extensions);
menu.exec(QCursor::pos());
}
}
}
void ContextBrowserView::updateLockIcon(bool checked) {
m_lockButton->setIcon(KIcon(checked ? "document-encrypt" : "document-decrypt"));
}
ContextBrowserView::ContextBrowserView( ContextBrowserPlugin* plugin, QWidget* parent ) : QWidget(parent), m_plugin(plugin), m_navigationWidget(new KTextBrowser()), m_autoLocked(false) {
setWindowIcon( KIcon("applications-development-web") );
m_allowLockedUpdate = false;
m_buttons = new QHBoxLayout;
m_buttons->addStretch();
m_declarationMenuButton = new QToolButton();
m_declarationMenuButton->setIcon(KIcon("code-class"));
m_declarationMenuButton->setToolTip(i18n("Declaration menu"));
connect(m_declarationMenuButton, SIGNAL(clicked(bool)), SLOT(declarationMenu()));
m_buttons->addWidget(m_declarationMenuButton);
m_lockButton = new QToolButton();
m_lockButton->setCheckable(true);
m_lockButton->setChecked(false);
m_lockButton->setToolTip(i18n("Lock current view"));
updateLockIcon(m_lockButton->isChecked());
connect(m_lockButton, SIGNAL(toggled(bool)), SLOT(updateLockIcon(bool)));
m_buttons->addWidget(m_lockButton);
m_layout = new QVBoxLayout;
m_layout->setSpacing(0);
m_layout->setMargin(0);
m_layout->addLayout(m_buttons);
m_layout->addWidget(m_navigationWidget);
//m_layout->addStretch();
setLayout(m_layout);
m_plugin->registerToolView(this);
}
ContextBrowserView::~ContextBrowserView() {
m_plugin->unRegisterToolView(this);
}
void ContextBrowserView::focusInEvent(QFocusEvent* event) {
//Indicate that we have focus
kDebug() << "got focus";
// parentWidget()->setBackgroundRole(QPalette::ToolTipBase);
/* m_layout->removeItem(m_buttons);*/
return QWidget::focusInEvent(event);
}
void ContextBrowserView::focusOutEvent(QFocusEvent* event) {
kDebug() << "lost focus";
// parentWidget()->setBackgroundRole(QPalette::Background);
/* m_layout->insertLayout(0, m_buttons);
for(int a = 0; a < m_buttons->count(); ++a) {
QWidgetItem* item = dynamic_cast<QWidgetItem*>(m_buttons->itemAt(a));
}*/
QWidget::focusOutEvent(event);
}
bool ContextBrowserView::event(QEvent* event) {
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
if(hasFocus() && keyEvent) {
AbstractNavigationWidget* navigationWidget = dynamic_cast<AbstractNavigationWidget*>(m_navigationWidget.data());
if(navigationWidget && event->type() == QEvent::KeyPress) {
int key = keyEvent->key();
if(key == Qt::Key_Left)
navigationWidget->previous();
if(key == Qt::Key_Right)
navigationWidget->next();
if(key == Qt::Key_Up)
navigationWidget->up();
if(key == Qt::Key_Down)
navigationWidget->down();
if(key == Qt::Key_Return || key == Qt::Key_Enter)
navigationWidget->accept();
if(key == Qt::Key_L)
m_lockButton->toggle();
}
}
return QWidget::event(event);
}
void ContextBrowserView::showEvent(QShowEvent* event) {
DUChainReadLocker lock(DUChain::lock());
TopDUContext* top = m_lastUsedTopContext.data();
if(top && m_navigationWidgetDeclaration.isValid() && m_navigationWidgetDeclaration.getDeclaration(top)) {
if(top) {
//Update the navigation-widget
Declaration* decl = m_navigationWidgetDeclaration.getDeclaration(top);
setDeclaration(decl, top, true);
//Update the declaration combo-box
/*
TODO: bring this back if required
DUContext* context = 0;
KDevelop::IDocument* doc = ICore::self()->documentController()->activeDocument();
if(doc && doc->textDocument() && doc->textDocument()->activeView()) {
KTextEditor::Cursor c = doc->textDocument()->activeView()->cursorPosition();
context = getContextAt(top->url().toUrl(), c);
}
m_plugin->updateDeclarationListBox(context);
*/
}
}
QWidget::showEvent(event);
}
bool ContextBrowserView::isLocked() const {
bool isLocked;
if (m_allowLockedUpdate) {
isLocked = false;
} else {
isLocked = m_lockButton->isChecked();
}
return isLocked;
}
void ContextBrowserView::updateMainWidget(QWidget* widget)
{
if (widget) {
setUpdatesEnabled(false);
kDebug() << "";
resetWidget();
m_navigationWidget = widget;
m_layout->insertWidget(1, widget, 1);
m_allowLockedUpdate = false;
setUpdatesEnabled(true);
connect(widget, SIGNAL(contextChanged(bool,bool)), this, SLOT(navigationContextChanged(bool,bool)));
}
}
void ContextBrowserView::navigationContextChanged(bool wasInitial, bool isInitial)
{
if(wasInitial && !isInitial && !m_lockButton->isChecked())
{
m_autoLocked = true;
m_lockButton->setChecked(true);
}else if(!wasInitial && isInitial && m_autoLocked)
{
m_autoLocked = false;
m_lockButton->setChecked(false);
}else if(isInitial) {
m_autoLocked = false;
}
}
void ContextBrowserView::setDeclaration(KDevelop::Declaration* decl, KDevelop::TopDUContext* topContext, bool force) {
m_lastUsedTopContext = IndexedTopDUContext(topContext);
if(isLocked() && (!m_navigationWidget.data() || !isVisible()))
{
// Automatically remove the locked state if the view is not visible or the widget was deleted,
// because the locked state has side-effects on other navigation functionality.
m_autoLocked = false;
m_lockButton->setChecked(false);
}
if(m_navigationWidgetDeclaration == decl->id() && !force)
return;
m_navigationWidgetDeclaration = decl->id();
if (!isLocked() && (isVisible() || force)) { // NO-OP if toolview is hidden, for performance reasons
QWidget* w = createWidget(decl, topContext);
updateMainWidget(w);
}
}
KDevelop::IndexedDeclaration ContextBrowserView::lockedDeclaration() const {
if(m_lockButton->isChecked())
return declaration();
else
return KDevelop::IndexedDeclaration();
}
void ContextBrowserView::allowLockedUpdate() {
m_allowLockedUpdate = true;
}
void ContextBrowserView::setNavigationWidget(QWidget* widget) {
updateMainWidget(widget);
}
void ContextBrowserView::setContext(KDevelop::DUContext* context) {
if(!context)
return;
m_lastUsedTopContext = IndexedTopDUContext(context->topContext());
if(context->owner()) {
if(context->owner()->id() == m_navigationWidgetDeclaration)
return;
m_navigationWidgetDeclaration = context->owner()->id();
}else{
m_navigationWidgetDeclaration = DeclarationId();
}
if (!isLocked() && isVisible()) { // NO-OP if toolview is hidden, for performance reasons
QWidget* w = createWidget(context);
updateMainWidget(w);
}
}
void ContextBrowserView::setSpecialNavigationWidget(QWidget* widget) {
if (!isLocked() && isVisible()) {
Q_ASSERT(widget);
updateMainWidget(widget);
} else if(widget) {
widget->deleteLater();
}
}
#include "moc_contextbrowserview.cpp"