Even though the last alpha was .91 this one is going to be 82 as I'd like to have...
[kdevelopdvcssupport.git] / plugins / contextbrowser / browsemanager.cpp
blob7223fa9a711b1b7c53b272ccc2429d53d6d37d99
1 /*
2 * This file is part of KDevelop
4 * Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "browsemanager.h"
23 #include <QMouseEvent>
24 #include <QToolButton>
25 #include <kdebug.h>
26 #include <ktexteditor/view.h>
27 #include <ktexteditor/document.h>
28 #include <interfaces/icore.h>
29 #include <interfaces/idocumentcontroller.h>
30 #include "contextbrowserview.h"
31 #include <ktexteditor/smartinterface.h>
32 #include <interfaces/ilanguage.h>
33 #include <interfaces/ilanguagecontroller.h>
34 #include <language/interfaces/ilanguagesupport.h>
35 #include <language/editor/simplecursor.h>
36 #include <language/duchain/duchainutils.h>
37 #include <language/duchain/duchainlock.h>
38 #include <language/duchain/duchain.h>
39 #include <language/duchain/declaration.h>
41 using namespace KDevelop;
42 using namespace KTextEditor;
44 static QWidget* masterWidget(QWidget* w) {
45 while(w && w->parentWidget())
46 w = w->parentWidget();
47 return w;
50 EditorViewWatcher::EditorViewWatcher(QWidget* sameWindow) : m_childrenOf(masterWidget(sameWindow)) {
52 connect(ICore::self()->documentController(), SIGNAL(textDocumentCreated(KDevelop::IDocument*)), this, SLOT(documentCreated(KDevelop::IDocument*)));
53 foreach(KDevelop::IDocument* document, ICore::self()->documentController()->openDocuments())
54 documentCreated(document);
57 void EditorViewWatcher::documentCreated( KDevelop::IDocument* document ) {
58 KTextEditor::Document* textDocument = document->textDocument();
59 if(textDocument) {
60 connect(textDocument, SIGNAL(viewCreated(KTextEditor::Document*, KTextEditor::View*)), this, SLOT(viewCreated(KTextEditor::Document*, KTextEditor::View*)));
61 foreach(KTextEditor::View* view, textDocument->views()) {
62 Q_ASSERT(view->parentWidget());
63 // if(!m_childrenOf || masterWidget(view) == m_childrenOf)
64 addViewInternal(view);
69 void EditorViewWatcher::addViewInternal(KTextEditor::View* view) {
70 m_views << view;
71 viewAdded(view);
72 connect(view, SIGNAL(destroyed(QObject*)), this, SLOT(viewDestroyed(QObject*)));
75 void EditorViewWatcher::viewAdded(KTextEditor::View*) {
78 void EditorViewWatcher::viewDestroyed(QObject* view) {
79 m_views.removeAll(static_cast<KTextEditor::View*>(view));
82 void EditorViewWatcher::viewCreated(KTextEditor::Document* /*doc*/, KTextEditor::View* view) {
83 Q_ASSERT(view->parentWidget());
84 //The test doesn't work porperly at this point
85 // if(!m_childrenOf || masterWidget(view) == m_childrenOf)
86 addViewInternal(view);
89 QList<KTextEditor::View*> EditorViewWatcher::allViews() {
90 return m_views;
93 BrowseManager::BrowseManager(ContextController* controller) : QObject(controller), m_controller(controller), m_watcher(this), m_browsing(false), m_browsingByKey(false) {
96 KTextEditor::View* viewFromWidget(QWidget* widget) {
97 if(!widget)
98 return 0;
99 KTextEditor::View* view = qobject_cast<KTextEditor::View*>(widget);
100 if(view)
101 return view;
102 else
103 return viewFromWidget(widget->parentWidget());
106 bool BrowseManager::eventFilter(QObject * watched, QEvent * event) {
107 QWidget* widget = qobject_cast<QWidget*>(watched);
108 Q_ASSERT(widget);
109 KTextEditor::View* view = viewFromWidget(widget);
110 if(!view)
111 return false;
113 const int browseKey = Qt::Key_Control;
115 QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
116 if(keyEvent && keyEvent->key() == browseKey) {
117 if(!m_browsingByKey && keyEvent->type() == QEvent::KeyPress) {
118 m_browsingByKey = true;
119 if(!m_browsing)
120 m_controller->browseButton()->setChecked(true);
122 } else if(m_browsingByKey && keyEvent->type() == QEvent::KeyRelease) {
123 if(!m_browsing)
124 m_controller->browseButton()->setChecked(false);
125 m_browsingByKey = false;
129 if(!m_browsing && !m_browsingByKey) {
130 resetChangedCursor();
131 return false;
134 QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);
135 if(mouseEvent) {
136 KTextEditor::CoordinatesToCursorInterface* iface = dynamic_cast<KTextEditor::CoordinatesToCursorInterface*>(view);
137 if(!iface) {
138 kDebug() << "Update kdelibs for the browsing-mode to work";
139 return false;
142 QPoint coordinatesInView = widget->mapTo(view, mouseEvent->pos());
144 KTextEditor::Cursor textCursor = iface->coordinatesToCursor(coordinatesInView);
145 if(textCursor.isValid()) {
146 SmartInterface* iface = dynamic_cast<SmartInterface*>(view->document());
147 if (!iface) return false;
149 ///@todo find out why this is needed, fix the code in kate
150 if(textCursor.column() > 0)
151 textCursor.setColumn(textCursor.column()-1);
153 KUrl viewUrl = view->document()->url();
154 QList<ILanguage*> languages = ICore::self()->languageController()->languagesForUrl(viewUrl);
156 QPair<KUrl, KDevelop::SimpleCursor> jumpTo;
158 //Step 1: Look for a special language object(Macro, included header, etc.)
159 foreach( ILanguage* language, languages) {
160 jumpTo = language->languageSupport()->specialLanguageObjectJumpCursor(viewUrl, SimpleCursor(textCursor));
161 if(jumpTo.first.isValid() && jumpTo.second.isValid())
162 break; //Found a special object to jump to
165 //Step 2: Look for a declaration/use
166 if(!jumpTo.first.isValid() || !jumpTo.second.isValid()) {
167 Declaration* foundDeclaration = 0;
168 KDevelop::DUChainReadLocker lock( DUChain::lock() );
169 foundDeclaration = DUChainUtils::declarationForDefinition( DUChainUtils::itemUnderCursor(view->document()->url(), SimpleCursor(textCursor)) );
171 if( foundDeclaration ) {
172 jumpTo.first = foundDeclaration->url().toUrl();
173 jumpTo.second = foundDeclaration->range().start;
176 if(jumpTo.first.isValid() && jumpTo.second.isValid()) {
177 if(mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QEvent::MouseButtonPress) {
178 ICore::self()->documentController()->openDocument(jumpTo.first, jumpTo.second.textCursor());
179 event->accept();
180 return true;
181 }else if(mouseEvent->type() == QEvent::MouseMove) {
182 //Make the cursor a "hand"
183 setHandCursor(widget);
184 return false;
188 resetChangedCursor();
190 return false;
193 void BrowseManager::resetChangedCursor() {
194 QMap<QPointer<QWidget>, QCursor> cursors = m_oldCursors;
195 m_oldCursors.clear();
197 for(QMap<QPointer<QWidget>, QCursor>::iterator it = cursors.begin(); it != cursors.end(); ++it)
198 if(it.key())
199 it.key()->setCursor(QCursor(Qt::IBeamCursor));
202 void BrowseManager::setHandCursor(QWidget* widget) {
203 if(m_oldCursors.contains(widget))
204 return; //Nothing to do
205 m_oldCursors[widget] = widget->cursor();
206 widget->setCursor(QCursor(Qt::PointingHandCursor));
209 void BrowseManager::applyEventFilter(QWidget* object, bool install) {
210 if(install)
211 object->installEventFilter(this);
212 else
213 object->removeEventFilter(this);
215 foreach(QObject* child, object->children())
216 if(qobject_cast<QWidget*>(child))
217 applyEventFilter(qobject_cast<QWidget*>(child), install);
220 void BrowseManager::Watcher::viewAdded(KTextEditor::View* view) {
221 m_manager->applyEventFilter(view, true);
224 void BrowseManager::setBrowsing(bool enabled) {
225 if(m_browsingByKey)
226 return;
227 if(enabled == m_browsing)
228 return;
229 m_browsing = enabled;
231 //This collects all the views
232 if(enabled) {
233 kDebug() << "Enabled browsing-mode";
234 ///Enable browsing, install an event-filter on all events
235 foreach(KTextEditor::View* view, m_watcher.allViews())
236 applyEventFilter(view, true);
237 }else{
238 kDebug() << "Disabled browsing-mode";
239 resetChangedCursor();
243 BrowseManager::Watcher::Watcher(BrowseManager* manager) : EditorViewWatcher(masterWidget(manager->m_controller->view())), m_manager(manager) {
244 foreach(KTextEditor::View* view, allViews())
245 m_manager->applyEventFilter(view, true);