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"
25 #include <QApplication>
26 #include <qalgorithms.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>
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
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";
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 ))
142 range
->addWatcher(this);
143 m_watchedRanges
.insert(range
);
146 void ContextBrowserPlugin::ignoreRange(KTextEditor::SmartRange
* range
)
148 if (!range
->watchers().contains( this ))
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
)
166 m_highlightedRange
.erase(it
);
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
) {
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());
189 kWarning() << "could not cast to view";
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
);
230 standardAttribute
->setBackground(color
);
232 return standardAttribute
;
235 void ContextBrowserPlugin::changeHighlight( KTextEditor::SmartRange
* range
, bool highlight
, bool /*declaration*/, bool mouseHighlight
) {
239 Attribute::Ptr attrib
;
241 if( !m_backups
.contains(range
) ) {
242 m_backups
[range
] = range
->attribute();
246 attrib = highlightedDeclarationAttribute();
248 attrib
= highlightedUseAttribute(mouseHighlight
);
250 if( m_backups
.contains(range
) ) {
251 attrib
= m_backups
[range
];
252 m_backups
.remove(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";
266 KTextEditor::SmartRange
* range
= decl
->smartRange();
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());
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
);
303 kDebug() << "m_highlightedRange[view]->document() != view->document()";
307 KUrl viewUrl
= view
->document()->url();
308 QList
<ILanguage
*> languages
= ICore::self()->languageController()->languagesForUrl(viewUrl
);
311 foreach( ILanguage
* language
, languages
) {
312 r
= language
->languageSupport()->specialLanguageObjectRange(viewUrl
, position
);
314 pickedLanguage
= language
;
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
]);
331 Declaration
* ContextBrowserPlugin::findDeclaration(View
* view
, const SimpleCursor
& position
, bool mouseHighlight
)
333 Declaration
* foundDeclaration
= 0;
334 if(m_useDeclaration
) {
335 foundDeclaration
= m_useDeclaration
.data();
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
);
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());
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.";
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
);
383 void ContextBrowserPlugin::showContextView(View
* view
, const SimpleCursor
& position
, DUContext
* ctx
)
386 foreach(ContextBrowserView
* contextView
, m_views
) {
387 if(masterWidget(contextView
) == masterWidget(view
)) {
388 contextView
->updateHistory(ctx
, position
);
389 contextView
->setContext(ctx
);
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();
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
;
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 );
427 kDebug() << "Failed to lock du-chain in time";
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
);
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
)
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
);
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*/ )
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
);
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
)
566 void ContextBrowserPlugin::previousUseShortcut()
571 void ContextBrowserPlugin::nextUseShortcut()
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());
588 DUContext
* ctx
= chosen
->findContextAt(c
);
590 //Try finding a declaration under the cursor
591 Declaration
* decl
= DUChainUtils::itemUnderCursor(doc
->url(), c
);
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();
603 QList
<SimpleRange
> useRanges
= allUses(top
, decl
, true);
605 if(!useRanges
.isEmpty()) {
606 SimpleRange selectUse
= forward
? useRanges
.first() : useRanges
.back();
608 core()->documentController()->openDocument(KUrl(top
->url().str()), KTextEditor::Range(selectUse
.start
.textCursor(), selectUse
.start
.textCursor()));
614 //Check whether we are within a use
615 QList
<SimpleRange
> localUses
= allUses(chosen
, decl
, true);
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()))
625 //Make sure we end up before the use
626 while(!forward
&& nextUse
>= 0 && (localUses
[nextUse
].start
>= localUses
[a
].start
|| localUses
[nextUse
].isEmpty()))
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
;
647 core()->documentController()->openDocument(u
, range
.textRange());
650 TopDUContext
* nextTop
= usingFiles
[nextFile
].data();
652 KUrl
u(nextTop
->url().str());
654 QList
<SimpleRange
> nextTopUses
= allUses(nextTop
, decl
, true);
657 if(!nextTopUses
.isEmpty()) {
658 SimpleRange range
= forward
? nextTopUses
.front() : nextTopUses
.back();
659 range
.end
= range
.start
;
661 core()->documentController()->openDocument(u
, range
.textRange());
666 kDebug() << "not found own file in use list";
669 KUrl
url(chosen
->url().str());
670 SimpleRange range
= localUses
[nextUse
];
671 range
.end
= range
.start
;
673 core()->documentController()->openDocument(url
, range
.textRange());
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