These assertions do trigger, exit gracefully instead. The pickedLanguage one happens...
[kdevelopdvcssupport.git] / plugins / contextbrowser / contextbrowser.cpp
blob06ee52b4b86beee6fb87c9c6aada8bfc0e56c4e7
1 /*
2 * This file is part of KDevelop
4 * Copyright 2007 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 "contextbrowser.h"
24 #include <QTimer>
25 #include <QApplication>
26 #include <qalgorithms.h>
27 #include <klocale.h>
28 #include <kaction.h>
29 #include <kpluginfactory.h>
30 #include <kpluginloader.h>
31 #include <ktexteditor/view.h>
32 #include <ktexteditor/document.h>
33 #include <ktexteditor/smartinterface.h>
34 #include <KTextEditor/TextHintInterface>
35 #include <kactioncollection.h>
36 #include <kdebug.h>
37 #include <interfaces/icore.h>
38 #include <interfaces/idocumentcontroller.h>
39 #include <interfaces/ilanguage.h>
40 #include <interfaces/iuicontroller.h>
41 #include <interfaces/ilanguagecontroller.h>
42 #include <language/duchain/duchainlock.h>
43 #include <language/duchain/duchain.h>
44 #include <language/duchain/ducontext.h>
45 #include <language/duchain/declaration.h>
46 #include <language/duchain/use.h>
47 #include <language/duchain/duchainutils.h>
48 #include <language/duchain/functiondefinition.h>
49 #include <language/interfaces/ilanguagesupport.h>
50 #include <language/backgroundparser/backgroundparser.h>
51 #include <language/backgroundparser/parsejob.h>
52 #include "contextbrowserview.h"
53 #include <language/duchain/uses.h>
55 const unsigned int highlightingTimeout = 150;
57 using KDevelop::ILanguage;
58 using KTextEditor::Attribute;
59 using KTextEditor::SmartInterface;
60 using KTextEditor::View;
62 class ContextBrowserViewFactory: public KDevelop::IToolViewFactory
64 public:
65 ContextBrowserViewFactory(ContextBrowserPlugin *plugin): m_plugin(plugin) {}
67 virtual QWidget* create(QWidget */*parent*/ = 0)
69 return new ContextBrowserView(m_plugin);
72 virtual Qt::DockWidgetArea defaultPosition()
74 return Qt::LeftDockWidgetArea;
77 virtual QString id() const
79 return "org.kdevelop.ContextBrowser";
82 private:
83 ContextBrowserPlugin *m_plugin;
86 K_PLUGIN_FACTORY(ContextBrowserFactory, registerPlugin<ContextBrowserPlugin>(); )
87 K_EXPORT_PLUGIN(ContextBrowserFactory("kdevcontextbrowser"))
89 ContextBrowserPlugin::ContextBrowserPlugin(QObject *parent, const QVariantList&)
90 : KDevelop::IPlugin(ContextBrowserFactory::componentData(), parent)
91 , m_viewFactory(new ContextBrowserViewFactory(this))
93 setXMLFile( "kdevcontextbrowser.rc" );
95 KActionCollection* actions = actionCollection();
97 core()->uiController()->addToolView(i18n("Code Browser"), m_viewFactory);
99 connect( core()->documentController(), SIGNAL( textDocumentCreated( KDevelop::IDocument* ) ), this, SLOT( textDocumentCreated( KDevelop::IDocument* ) ) );
100 connect( core()->documentController(), SIGNAL( documentClosed( KDevelop::IDocument* ) ), this, SLOT( documentClosed( KDevelop::IDocument* ) ) );
101 connect( core()->languageController()->backgroundParser(), SIGNAL(parseJobFinished(KDevelop::ParseJob*)), this, SLOT(parseJobFinished(KDevelop::ParseJob*)));
103 connect( DUChain::self(), SIGNAL( declarationSelected(DeclarationPointer) ), this, SLOT( declarationSelectedInUI(DeclarationPointer) ) );
106 m_updateTimer = new QTimer(this);
107 m_updateTimer->setSingleShot(true);
108 connect( m_updateTimer, SIGNAL( timeout() ), this, SLOT( updateViews() ) );
110 QAction* previousContext = actions->addAction("previous_context");
111 previousContext->setText( i18n("&Previous Context") );
112 previousContext->setShortcut( Qt::META | Qt::Key_Left );
113 connect(previousContext, SIGNAL(triggered(bool)), this, SIGNAL(previousContextShortcut()));
115 QAction* nextContext = actions->addAction("next_context");
116 nextContext->setText( i18n("&Next Context") );
117 nextContext->setShortcut( Qt::META | Qt::Key_Right );
118 connect(nextContext, SIGNAL(triggered(bool)), this, SIGNAL(nextContextShortcut()));
120 QAction* previousUse = actions->addAction("previous_use");
121 previousUse->setText( i18n("&Previous Use") );
122 previousUse->setShortcut( Qt::META | Qt::SHIFT | Qt::Key_Left );
123 connect(previousUse, SIGNAL(triggered(bool)), this, SLOT(previousUseShortcut()));
125 QAction* nextUse = actions->addAction("next_use");
126 nextUse->setText( i18n("&Next Use") );
127 nextUse->setShortcut( Qt::META | Qt::SHIFT | Qt::Key_Right );
128 connect(nextUse, SIGNAL(triggered(bool)), this, SLOT(nextUseShortcut()));
131 ContextBrowserPlugin::~ContextBrowserPlugin()
133 foreach (KTextEditor::SmartRange* range, m_watchedRanges)
134 range->removeWatcher(this);
137 void ContextBrowserPlugin::watchRange(KTextEditor::SmartRange* range)
139 if (range->watchers().contains( this ))
140 return;
142 range->addWatcher(this);
143 m_watchedRanges.insert(range);
146 void ContextBrowserPlugin::ignoreRange(KTextEditor::SmartRange* range)
148 if (!range->watchers().contains( this ))
149 return;
151 range->removeWatcher(this);
152 m_watchedRanges.remove(range);
155 void ContextBrowserPlugin::unload()
157 core()->uiController()->removeToolView(m_viewFactory);
160 void ContextBrowserPlugin::rangeDeleted( KTextEditor::SmartRange *range ) {
161 m_backups.remove( range );
162 m_watchedRanges.remove(range);
164 for(QMap<View*, KTextEditor::SmartRange*>::iterator it = m_highlightedRange.begin(); it != m_highlightedRange.end(); ++it)
165 if(*it == range) {
166 m_highlightedRange.erase(it);
167 return;
171 ///@todo this doesn't work, we use TextHintInterface instead atm.
172 void ContextBrowserPlugin::mouseEnteredRange( KTextEditor::SmartRange* range, View* view ) {
173 m_mouseHoverCursor = SimpleCursor(range->start());
174 m_mouseHoverDocument = view->document()->url();
175 m_updateViews << view;
176 m_updateTimer->start(1);
179 void ContextBrowserPlugin::mouseExitedRange( KTextEditor::SmartRange* /*range*/, View* view ) {
180 clearMouseHover();
181 m_updateViews << view;
182 m_updateTimer->start(1); // triggers updateViews()
185 void ContextBrowserPlugin::textHintRequested(const KTextEditor::Cursor& cursor, QString&) {
186 m_mouseHoverCursor = SimpleCursor(cursor);
187 View* view = dynamic_cast<View*>(sender());
188 if(!view) {
189 kWarning() << "could not cast to view";
190 }else{
191 m_mouseHoverDocument = view->document()->url();
192 m_updateViews << view;
194 m_updateTimer->start(1); // triggers updateViews()
197 void ContextBrowserPlugin::clearMouseHover() {
198 m_mouseHoverCursor = SimpleCursor::invalid();
199 m_mouseHoverDocument = KUrl();
203 Attribute::Ptr highlightedUseAttribute(bool /*mouseHighlight*/) {
204 static Attribute::Ptr standardAttribute = Attribute::Ptr();
205 if( !standardAttribute ) {
206 standardAttribute = Attribute::Ptr( new Attribute() );
207 standardAttribute->setBackgroundFillWhitespace(true);
208 standardAttribute->setBackground(Qt::yellow);//QApplication::palette().toolTipBase());
210 return standardAttribute;
213 Attribute::Ptr highlightedDeclarationAttribute() {
214 static Attribute::Ptr standardAttribute = Attribute::Ptr();
215 if( !standardAttribute ) {
216 standardAttribute = Attribute::Ptr( new Attribute() );
217 standardAttribute->setBackgroundFillWhitespace(true);
218 standardAttribute->setBackground(Qt::red);
220 return standardAttribute;
223 Attribute::Ptr highlightedSpecialObjectAttribute() {
224 static Attribute::Ptr standardAttribute = Attribute::Ptr();
225 if( !standardAttribute ) {
226 standardAttribute = Attribute::Ptr( new Attribute() );
227 standardAttribute->setBackgroundFillWhitespace(true);
228 QColor color(Qt::yellow);
229 color.setRed(90);
230 standardAttribute->setBackground(color);
232 return standardAttribute;
235 void ContextBrowserPlugin::changeHighlight( KTextEditor::SmartRange* range, bool highlight, bool /*declaration*/, bool mouseHighlight ) {
236 if( !range )
237 return;
239 Attribute::Ptr attrib;
240 if( highlight ) {
241 if( !m_backups.contains(range) ) {
242 m_backups[range] = range->attribute();
243 watchRange(range);
245 /* if( declaration )
246 attrib = highlightedDeclarationAttribute();
247 else*/
248 attrib = highlightedUseAttribute(mouseHighlight);
249 }else{
250 if( m_backups.contains(range) ) {
251 attrib = m_backups[range];
252 m_backups.remove(range);
254 ignoreRange(range);
257 range->setAttribute(attrib);
260 void ContextBrowserPlugin::changeHighlight( View* view, KDevelop::Declaration* decl, bool highlight, bool mouseHighlight ) {
261 if( !view || !decl || !decl->context() ) {
262 kDebug() << "invalid view/declaration";
263 return;
266 KTextEditor::SmartRange* range = decl->smartRange();
267 if( range )
268 changeHighlight( range, highlight, true, mouseHighlight );
271 QList<KTextEditor::SmartRange*> uses;
273 KDevelop::DUChainReadLocker lock( DUChain::lock() );
274 uses = decl->smartUses();
277 foreach(KTextEditor::SmartRange* range, uses)
278 changeHighlight( range, highlight, false, mouseHighlight );
280 if( FunctionDefinition* def = FunctionDefinition::definition(decl) )
281 if( def->smartRange() )
282 changeHighlight( def->smartRange(), highlight, false, mouseHighlight );
285 QWidget* masterWidget(QWidget* w) {
286 while(w && w->parent() && qobject_cast<QWidget*>(w->parent()))
287 w = qobject_cast<QWidget*>(w->parent());
288 return w;
291 bool ContextBrowserPlugin::findSpecialObject(View* view, const SimpleCursor& position, ILanguage*& pickedLanguage)
293 SmartInterface* iface = dynamic_cast<SmartInterface*>(view->document());
294 if (!iface) return false;
296 if(m_highlightedRange.contains(view)) { // remove old highlighting
297 QMutexLocker lock(iface->smartMutex());
298 //Q_ASSERT(m_highlightedRange[view]->document() == view->document());
299 if (m_highlightedRange[view]->document() == view->document()) {
300 delete m_highlightedRange[view];
301 m_highlightedRange.remove(view);
302 } else {
303 kDebug() << "m_highlightedRange[view]->document() != view->document()";
307 KUrl viewUrl = view->document()->url();
308 QList<ILanguage*> languages = ICore::self()->languageController()->languagesForUrl(viewUrl);
310 SimpleRange r;
311 foreach( ILanguage* language, languages) {
312 r = language->languageSupport()->specialLanguageObjectRange(viewUrl, position);
313 if(r.isValid()) {
314 pickedLanguage = language;
315 break;
319 if (r.isValid()) {
320 m_highlightedRange[view] = iface->newSmartRange( r.textRange(), m_highlightedRange[view] );//iface->newSmartRange( view->document()->documentRange() );
321 iface->addHighlightToDocument(m_highlightedRange[view]);
322 m_highlightedRange[view]->setAttribute( highlightedSpecialObjectAttribute() );
323 watchRange(m_highlightedRange[view]);
324 return true;
325 } else {
326 pickedLanguage = 0;
327 return false;
331 Declaration* ContextBrowserPlugin::findDeclaration(View* view, const SimpleCursor& position, bool mouseHighlight)
333 Declaration* foundDeclaration = 0;
334 if(m_useDeclaration) {
335 foundDeclaration = m_useDeclaration.data();
336 }else{
337 //If we haven't found a special language object, search for a use/declaration and eventually highlight it
338 foundDeclaration = DUChainUtils::declarationForDefinition( DUChainUtils::itemUnderCursor(view->document()->url(), position) );
340 if( foundDeclaration ) {
341 m_highlightedDeclarations[view] = foundDeclaration;
342 changeHighlight( view, foundDeclaration, true, mouseHighlight );
343 }else{
344 m_highlightedDeclarations.remove(view);
346 return foundDeclaration;
349 bool ContextBrowserPlugin::showDeclarationView(View* view, const SimpleCursor& position, Declaration* foundDeclaration, DUContext* ctx)
351 Q_ASSERT(foundDeclaration);
352 bool success = false;
353 foreach(ContextBrowserView* contextView, m_views) {
354 if(masterWidget(contextView) == masterWidget(view)) {
355 contextView->updateHistory(ctx, position);
356 contextView->setDeclaration(foundDeclaration, ctx->topContext());
357 success = true;
360 return success;
363 bool ContextBrowserPlugin::showSpecialObjectView(View* view, const SimpleCursor& position, ILanguage* pickedLanguage, DUContext* ctx)
365 //Q_ASSERT(pickedLanguage != 0); // specialObject was found, pickedLanguage must have been set
366 if (!pickedLanguage) {
367 kDebug() << "Special's object language turned null.";
368 return false;
370 bool success = false;
371 foreach(ContextBrowserView* contextView, m_views) {
372 if(masterWidget(contextView) == masterWidget(view)) {
373 ILanguageSupport* ls = pickedLanguage->languageSupport();
374 QWidget* w = ls->specialLanguageObjectNavigationWidget(view->document()->url(), position);
375 contextView->updateHistory(ctx, position);
376 contextView->setSpecialNavigationWidget(w);
377 success = true;
380 return success;
383 void ContextBrowserPlugin::showContextView(View* view, const SimpleCursor& position, DUContext* ctx)
385 Q_ASSERT(ctx);
386 foreach(ContextBrowserView* contextView, m_views) {
387 if(masterWidget(contextView) == masterWidget(view)) {
388 contextView->updateHistory(ctx, position);
389 contextView->setContext(ctx);
394 namespace
397 DUContext* contextAt(const SimpleCursor& position, TopDUContext* topContext)
399 DUContext* ctx = topContext->findContextAt(position);
400 while(ctx && (ctx->type() == DUContext::Template || ctx->type() == DUContext::Helper || ctx->localScopeIdentifier().isEmpty()) && ctx->parentContext())
401 ctx = ctx->parentContext();
402 return ctx;
405 } // end anonymous namespace
407 void ContextBrowserPlugin::updateBrowserWidgetFor(View* view)
409 bool mouseHighlight =
410 (view->document()->url() == m_mouseHoverDocument) &&
411 (m_mouseHoverCursor.isValid());
413 SimpleCursor position;
414 if (mouseHighlight) {
415 position = m_mouseHoverCursor;
416 } else {
417 position = SimpleCursor(view->cursorPosition());
420 ///First: Check whether there is a special language object
421 ///@todo Maybe make this optional, because it can be slow
422 ILanguage* pickedLanguage = 0;
423 bool foundSpecialObject = findSpecialObject(view,position, pickedLanguage);
425 KDevelop::DUChainReadLocker lock( DUChain::lock(), 100 );
426 if(!lock.locked()) {
427 kDebug() << "Failed to lock du-chain in time";
428 return;
431 if( m_highlightedDeclarations.contains(view) ) ///unhighlight the old uses
432 changeHighlight( view, m_highlightedDeclarations[view].data(), false, mouseHighlight );
434 TopDUContext* topContext = DUChainUtils::standardContextForUrl(view->document()->url());
435 if (!topContext) return;
436 DUContext* ctx = contextAt(position, topContext);
437 if (!ctx) return;
438 Declaration* foundDeclaration = (foundSpecialObject) ? 0 : findDeclaration(view, position, mouseHighlight);
440 bool addedWidget = false;
441 // try to add a declaration navigation widget
442 if(foundDeclaration || foundSpecialObject) {
443 IDocument* doc = core()->documentController()->activeDocument();
444 if(mouseHighlight || (view->isActiveView() && doc && doc->textDocument() == view->document())) {
445 addedWidget = foundSpecialObject ?
446 showSpecialObjectView(view, position, pickedLanguage, ctx) :
447 showDeclarationView(view, position, foundDeclaration, ctx);
448 ///@todo show tooltip
452 // if that failed, try to add a context navigation widget
453 if(!addedWidget && !mouseHighlight) {
454 showContextView(view, position, ctx);
458 void ContextBrowserPlugin::updateViews()
460 foreach( View* view, m_updateViews ) {
461 updateBrowserWidgetFor(view);
463 m_updateViews.clear();
464 m_useDeclaration = DeclarationPointer();
467 void ContextBrowserPlugin::declarationSelectedInUI(DeclarationPointer decl)
469 m_useDeclaration = decl;
470 if(core()->documentController()->activeDocument() && core()->documentController()->activeDocument()->textDocument() && core()->documentController()->activeDocument()->textDocument()->activeView())
471 m_updateViews << core()->documentController()->activeDocument()->textDocument()->activeView();
473 m_updateTimer->start(highlightingTimeout); // triggers updateViews()
476 void ContextBrowserPlugin::parseJobFinished(KDevelop::ParseJob* job)
478 KDevelop::DUChainWriteLocker lock( DUChain::lock() );
479 registerAsRangeWatcher(job->duChain());
482 void ContextBrowserPlugin::registerAsRangeWatcher(KDevelop::DUChainBase* base)
484 if(base->smartRange())
485 watchRange(base->smartRange());
488 void ContextBrowserPlugin::registerAsRangeWatcher(KDevelop::DUContext* ctx)
490 if(!ctx)
491 return;
492 if(dynamic_cast<TopDUContext*>(ctx) && static_cast<TopDUContext*>(ctx)->flags() & TopDUContext::ProxyContextFlag && !ctx->importedParentContexts().isEmpty())
493 return registerAsRangeWatcher(ctx->importedParentContexts()[0].context());
495 foreach(Declaration* decl, ctx->localDeclarations())
496 registerAsRangeWatcher(decl);
498 for(int a = 0; a < ctx->usesCount(); ++a) {
499 KTextEditor::SmartRange* range = ctx->useSmartRange(a);
500 if(range)
501 watchRange(range);
504 foreach(DUContext* child, ctx->childContexts())
505 registerAsRangeWatcher(child);
508 void ContextBrowserPlugin::textDocumentCreated( KDevelop::IDocument* document )
510 Q_ASSERT(document->textDocument());
512 connect( document->textDocument(), SIGNAL(destroyed( QObject* )), this, SLOT( documentDestroyed( QObject* ) ) );
513 connect( document->textDocument(), SIGNAL( viewCreated( KTextEditor::Document* , KTextEditor::View* ) ), this, SLOT( viewCreated( KTextEditor::Document*, KTextEditor::View* ) ) );
515 foreach( View* view, document->textDocument()->views() )
516 viewCreated( document->textDocument(), view );
518 KDevelop::DUChainWriteLocker lock( DUChain::lock() );
519 QList<TopDUContext*> chains = DUChain::self()->chainsForDocument( document->url() );
521 foreach( TopDUContext* chain, chains )
522 registerAsRangeWatcher( chain );
525 void ContextBrowserPlugin::documentClosed( KDevelop::IDocument* /*document*/ )
529 void ContextBrowserPlugin::documentDestroyed( QObject* /*obj*/ )
533 void ContextBrowserPlugin::viewDestroyed( QObject* obj )
535 m_highlightedDeclarations.remove(static_cast<KTextEditor::View*>(obj));
536 m_updateViews.remove(static_cast<View*>(obj));
539 void ContextBrowserPlugin::cursorPositionChanged( View* view, const KTextEditor::Cursor& /*newPosition*/ )
541 clearMouseHover();
542 m_updateViews.insert(view);
543 m_updateTimer->start(highlightingTimeout/2); // triggers updateViews()
546 void ContextBrowserPlugin::viewCreated( KTextEditor::Document* , View* v )
548 disconnect( v, SIGNAL( cursorPositionChanged( KTextEditor::View*, const KTextEditor::Cursor& ) ), this, SLOT( cursorPositionChanged( KTextEditor::View*, const KTextEditor::Cursor& ) ) ); ///Just to make sure that multiple connections don't happen
549 connect( v, SIGNAL( cursorPositionChanged( KTextEditor::View*, const KTextEditor::Cursor& ) ), this, SLOT( cursorPositionChanged( KTextEditor::View*, const KTextEditor::Cursor& ) ) );
550 connect( v, SIGNAL(destroyed( QObject* )), this, SLOT( viewDestroyed( QObject* ) ) );
552 KTextEditor::TextHintInterface *iface = dynamic_cast<KTextEditor::TextHintInterface*>(v);
553 if( !iface )
554 return;
556 iface->enableTextHints(highlightingTimeout);
558 connect(v, SIGNAL(needTextHint(const KTextEditor::Cursor&, QString&)), this, SLOT(textHintRequested(const KTextEditor::Cursor&, QString&)));
561 void ContextBrowserPlugin::registerToolView(ContextBrowserView* view)
563 m_views << view;
566 void ContextBrowserPlugin::previousUseShortcut()
568 switchUse(false);
571 void ContextBrowserPlugin::nextUseShortcut()
573 switchUse(true);
576 void ContextBrowserPlugin::switchUse(bool forward)
578 if(core()->documentController()->activeDocument() && core()->documentController()->activeDocument()->textDocument() && core()->documentController()->activeDocument()->textDocument()->activeView()) {
579 KTextEditor::Document* doc = core()->documentController()->activeDocument()->textDocument();
580 KDevelop::SimpleCursor c(doc->activeView()->cursorPosition());
583 KDevelop::DUChainReadLocker lock( DUChain::lock() );
584 KDevelop::TopDUContext* chosen = DUChainUtils::standardContextForUrl(doc->url());
586 if( chosen )
588 DUContext* ctx = chosen->findContextAt(c);
590 //Try finding a declaration under the cursor
591 Declaration* decl = DUChainUtils::itemUnderCursor(doc->url(), c);
592 if(decl) {
593 KDevVarLengthArray<IndexedTopDUContext> usingFiles = DUChain::uses()->uses(decl->id());
595 if(decl->topContext()->indexForUsedDeclaration(decl, false) != std::numeric_limits<int>::max() && usingFiles.indexOf(decl->topContext()) == -1)
596 usingFiles.insert(decl->topContext(), 0);
598 if(decl->range().contains(c) && decl->url() == chosen->url()) {
599 //The cursor is directly on the declaration. Jump to the first or last use.
600 if(!usingFiles.isEmpty()) {
601 TopDUContext* top = (forward ? usingFiles[0] : usingFiles.back()).data();
602 if(top) {
603 QList<SimpleRange> useRanges = allUses(top, decl, true);
604 qSort(useRanges);
605 if(!useRanges.isEmpty()) {
606 SimpleRange selectUse = forward ? useRanges.first() : useRanges.back();
607 lock.unlock();
608 core()->documentController()->openDocument(KUrl(top->url().str()), KTextEditor::Range(selectUse.start.textCursor(), selectUse.start.textCursor()));
612 return;
614 //Check whether we are within a use
615 QList<SimpleRange> localUses = allUses(chosen, decl, true);
616 qSort(localUses);
617 for(int a = 0; a < localUses.size(); ++a) {
618 if(localUses[a].contains(c)) {
619 int nextUse = (forward ? a+1 : a-1);
621 //Make sure we end up behind the use
622 while(forward && nextUse < localUses.size() && (localUses[nextUse].start <= localUses[a].end || localUses[nextUse].isEmpty()))
623 ++nextUse;
625 //Make sure we end up before the use
626 while(!forward && nextUse >= 0 && (localUses[nextUse].start >= localUses[a].start || localUses[nextUse].isEmpty()))
627 --nextUse;
628 //Jump to the next use
630 kDebug() << "count of uses:" << localUses.size() << "nextUse" << nextUse;
632 if(nextUse < 0 || nextUse == localUses.size()) {
633 kDebug() << "jumping to next file";
634 //Jump to the first use in the next using top-context
635 int indexInFiles = usingFiles.indexOf(chosen);
636 if(indexInFiles != -1) {
638 int nextFile = (forward ? indexInFiles+1 : indexInFiles-1);
639 kDebug() << "current file" << indexInFiles << "nextFile" << nextFile;
641 if(nextFile < 0 || nextFile >= usingFiles.size()) {
642 //Open the declaration
643 KUrl u(decl->url().str());
644 SimpleRange range = decl->range();
645 range.end = range.start;
646 lock.unlock();
647 core()->documentController()->openDocument(u, range.textRange());
648 return;
649 }else{
650 TopDUContext* nextTop = usingFiles[nextFile].data();
652 KUrl u(nextTop->url().str());
654 QList<SimpleRange> nextTopUses = allUses(nextTop, decl, true);
655 qSort(nextTopUses);
657 if(!nextTopUses.isEmpty()) {
658 SimpleRange range = forward ? nextTopUses.front() : nextTopUses.back();
659 range.end = range.start;
660 lock.unlock();
661 core()->documentController()->openDocument(u, range.textRange());
663 return;
665 }else{
666 kDebug() << "not found own file in use list";
668 }else{
669 KUrl url(chosen->url().str());
670 SimpleRange range = localUses[nextUse];
671 range.end = range.start;
672 lock.unlock();
673 core()->documentController()->openDocument(url, range.textRange());
674 return;
680 ctx = ctx->parentContext(); //It may happen, for example in the case of function-declarations, that the use is one context higher.
685 void ContextBrowserPlugin::unRegisterToolView(ContextBrowserView* view)
687 m_views.removeAll(view);
691 #include "contextbrowser.moc"
693 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on