00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "navigator.h"
00023
00024 #include <qtimer.h>
00025
00026 #include <kconfig.h>
00027 #include <kdebug.h>
00028 #include <kiconloader.h>
00029 #include <kapplication.h>
00030 #include <ktexteditor/viewcursorinterface.h>
00031
00032 #include <kcomboview.h>
00033 #include <klistviewaction.h>
00034 #include <kdevpartcontroller.h>
00035 #include <kdevlanguagesupport.h>
00036 #include <codemodel_utils.h>
00037
00038 #include "classviewpart.h"
00039
00040
00041 struct NavOp
00042 {
00043 NavOp(Navigator *navigator, const QString &fullName)
00044 :m_navigator(navigator), m_fullName(fullName) {}
00045
00046 bool operator() ( const FunctionDefinitionDom& def ) const
00047 {
00048 return (m_navigator->fullFunctionDefinitionName(def) == m_fullName);
00049 }
00050 bool operator() ( const FunctionDom& def ) const
00051 {
00052 return (m_navigator->fullFunctionDeclarationName(def) == m_fullName);
00053 }
00054
00055 private:
00056 Navigator *m_navigator;
00057 QString m_fullName;
00058 };
00059
00060
00061
00062 class FunctionNavItem: public QListViewItem {
00063 public:
00064 enum Type { Declaration, Definition };
00065
00066 FunctionNavItem(ClassViewPart *part, QListView *parent, QString name, Type type)
00067 :QListViewItem(parent, name), m_part(part), m_type(type) {}
00068 FunctionNavItem(ClassViewPart *part, QListViewItem *parent, QString name, Type type)
00069 :QListViewItem(parent, name), m_part(part), m_type(type) {}
00070 ~FunctionNavItem() {}
00071
00072 virtual void setup()
00073 {
00074 QListViewItem::setup();
00075 setPixmap( 0, UserIcon("CVpublic_meth", KIcon::DefaultState, m_part->instance()) );
00076 }
00077 Type type() { return m_type; }
00078
00079 private:
00080 ClassViewPart *m_part;
00081 Type m_type;
00082 };
00083
00084
00085 Navigator::Navigator(ClassViewPart *parent, const char *name)
00086 : QObject(parent, name), m_part(parent)
00087 {
00088 m_state = GoToDefinitions;
00089 m_navNoDefinition = true;
00090
00091 m_syncTimer = new QTimer(this);
00092 connect(m_syncTimer, SIGNAL(timeout()), this, SLOT(syncFunctionNav()));
00093 }
00094
00095 Navigator::~Navigator()
00096 {
00097 }
00098
00099 void Navigator::selectFunctionNav(QListViewItem *item)
00100 {
00101 FunctionNavItem *nav = dynamic_cast<FunctionNavItem*>(item);
00102 if (!nav)
00103 return;
00104
00105 FileDom file = m_part->codeModel()->fileByName(m_part->m_activeFileName);
00106 if (!file)
00107 return;
00108
00109 switch (nav->type())
00110 {
00111 case FunctionNavItem::Definition:
00112 {
00113 FileList files;
00114 files.append(file);
00115 FunctionDefinitionList deflist;
00116 CodeModelUtils::findFunctionDefinitions(NavOp(this, nav->text(0)), files, deflist);
00117 if (deflist.count() < 1)
00118 return;
00119
00120 FunctionDefinitionDom fun = deflist.first();
00121 if (!fun)
00122 return;
00123 int startLine = 0, startColumn = 0;
00124 fun->getStartPosition(&startLine, &startColumn);
00125 m_part->partController()->editDocument(KURL(fun->fileName()), startLine);
00126 break;
00127 }
00128 case FunctionNavItem::Declaration:
00129 {
00130 FileList files;
00131 files.append(file);
00132 FunctionList declist;
00133 CodeModelUtils::findFunctionDeclarations(NavOp(this, nav->text(0)), files, declist);
00134 if (declist.count() < 1)
00135 return;
00136
00137 FunctionDom fun = declist.first();
00138 if (!fun)
00139 return;
00140 int startLine = 0, startColumn = 0;
00141 fun->getStartPosition(&startLine, &startColumn);
00142 m_part->partController()->editDocument(KURL(fun->fileName()), startLine);
00143 break;
00144 }
00145 }
00146 }
00147
00148 void Navigator::functionNavUnFocused()
00149 {
00150
00151
00152
00153 if (m_part->m_functionsnav->view()->currentItem())
00154 m_part->m_functionsnav->view()->setCurrentText(m_part->m_functionsnav->view()->currentItem()->text(0));
00155 else
00156 m_part->m_functionsnav->view()->setCurrentText(NAV_NODEFINITION);
00157 }
00158
00159 void Navigator::functionNavFocused()
00160 {
00161 m_navNoDefinition = (m_part->m_functionsnav->view()->currentText() == NAV_NODEFINITION);
00162 m_part->m_functionsnav->view()->setCurrentText("");
00163 }
00164
00165 void Navigator::slotCursorPositionChanged()
00166 {
00167
00168
00169
00170 KConfig* config = kapp->config();
00171 config->setGroup( "General Options" );
00172 int m_delay = config->readNumEntry( "BgParserDelay", 250 );
00173
00174 m_syncTimer->changeInterval(500 >= m_delay+100 ? 500 : m_delay+100 );
00175 }
00176
00177 void Navigator::stopTimer( )
00178 {
00179 m_syncTimer->stop();
00180 }
00181
00182 void Navigator::syncFunctionNavDelayed(int delay)
00183 {
00184 m_syncTimer->changeInterval(delay);
00185 }
00186
00187 void Navigator::syncFunctionNav()
00188 {
00189 m_syncTimer->stop();
00190
00191 if (FunctionDefinitionDom fun = currentFunctionDefinition())
00192 {
00193 if (functionNavDefs[fullFunctionDefinitionName(fun)])
00194 {
00195 m_part->m_functionsnav->view()->blockSignals(true);
00196 m_part->m_functionsnav->view()->setCurrentActiveItem(functionNavDefs[fullFunctionDefinitionName(fun)]);
00197 m_part->m_functionsnav->view()->blockSignals(false);
00198 }
00199 }
00200 else if (FunctionDom fun = currentFunctionDeclaration())
00201 {
00202 if (functionNavDecls[fullFunctionDeclarationName(fun)])
00203 {
00204 m_part->m_functionsnav->view()->blockSignals(true);
00205 m_part->m_functionsnav->view()->setCurrentActiveItem(functionNavDecls[fullFunctionDeclarationName(fun)]);
00206 m_part->m_functionsnav->view()->blockSignals(false);
00207 }
00208 }
00209 else
00210 m_part->m_functionsnav->view()->setCurrentText(NAV_NODEFINITION);
00211 }
00212
00213 void Navigator::refreshNavBars(const QString &activeFileName, bool clear)
00214 {
00215 kdDebug() << "Navigator::refreshNavBars" << endl;
00216 if (clear)
00217 {
00218 m_part->m_functionsnav->view()->clear();
00219 functionNavDefs.clear();
00220 functionNavDecls.clear();
00221 }
00222
00223 FileDom file = m_part->codeModel()->fileByName(activeFileName);
00224 if (!file)
00225 return;
00226
00227 QStringList toLeave;
00228
00229 FunctionList list1 = CodeModelUtils::allFunctions(file);
00230 for (FunctionList::const_iterator it = list1.begin(); it != list1.end(); ++it)
00231 {
00232 QString fullName = fullFunctionDeclarationName(*it);
00233
00234 if (clear || !functionNavDecls[fullName])
00235 {
00236 FunctionNavItem *item = new FunctionNavItem(m_part,
00237 m_part->m_functionsnav->view()->listView(), fullName,
00238 FunctionNavItem::Declaration);
00239 functionNavDecls[fullName] = item;
00240 m_part->m_functionsnav->view()->addItem(item);
00241 }
00242 toLeave << fullName;
00243 }
00244 kdDebug() << "leave list: " << toLeave << endl;
00245
00246
00247 for (QMap<QString, QListViewItem*>::iterator it = functionNavDecls.begin();
00248 it != functionNavDecls.end(); ++it)
00249 {
00250 if (!toLeave.contains(it.key()))
00251 {
00252 if (it.data())
00253 m_part->m_functionsnav->view()->removeItem(it.data());
00254 functionNavDecls.remove(it);
00255 }
00256 }
00257
00258 toLeave.clear();
00259 FunctionDefinitionList list = CodeModelUtils::allFunctionDefinitionsDetailed(file).functionList;
00260 for (FunctionDefinitionList::const_iterator it = list.begin(); it != list.end(); ++it)
00261 {
00262 QString fullName = fullFunctionDefinitionName(*it);
00263
00264 if (clear || !functionNavDefs[fullName])
00265 {
00266 FunctionNavItem *item = new FunctionNavItem(m_part,
00267 m_part->m_functionsnav->view()->listView(), fullName, FunctionNavItem::Definition);
00268 functionNavDefs[fullName] = item;
00269 m_part->m_functionsnav->view()->addItem(item);
00270 }
00271
00272
00273 if (functionNavDecls[fullName])
00274 {
00275 m_part->m_functionsnav->view()->removeItem(functionNavDecls[fullName]);
00276 functionNavDecls.remove(fullName);
00277 }
00278
00279 toLeave << fullName;
00280 }
00281
00282 kdDebug() << "leave list: " << toLeave << endl;
00283
00284 for (QMap<QString, QListViewItem*>::iterator it = functionNavDefs.begin();
00285 it != functionNavDefs.end(); ++it)
00286 {
00287 if (!toLeave.contains(it.key()))
00288 {
00289 if (it.data())
00290 m_part->m_functionsnav->view()->removeItem(it.data());
00291 functionNavDefs.remove(it);
00292 }
00293 }
00294 }
00295
00296 void Navigator::refresh()
00297 {
00298 refreshNavBars(m_part->m_activeFileName, true);
00299 }
00300
00301 void Navigator::addFile(const QString & file)
00302 {
00303 kdDebug() << "Navigator::addFile" << endl;
00304 if (file == m_part->m_activeFileName)
00305 {
00306 kdDebug() << "Navigator::addFile, processing active file" << endl;
00307 refreshNavBars(m_part->m_activeFileName, false);
00308 }
00309 }
00310
00311
00312
00313 FunctionDefinitionDom Navigator::currentFunctionDefinition()
00314 {
00315 if (!m_part->m_activeViewCursor)
00316 return FunctionDefinitionDom();
00317
00318 unsigned int line, column;
00319 m_part->m_activeViewCursor->cursorPositionReal(&line, &column);
00320 return functionDefinitionAt(line, column);
00321 }
00322
00323 FunctionDefinitionDom Navigator::functionDefinitionAt(int line, int column)
00324 {
00325 if (!m_part->codeModel()->hasFile(m_part->m_activeFileName))
00326 return FunctionDefinitionDom();
00327
00328 FileDom file = m_part->codeModel()->fileByName(m_part->m_activeFileName);
00329 return functionDefinitionAt(model_cast<NamespaceDom>(file), line, column);
00330 }
00331
00332 FunctionDefinitionDom Navigator::functionDefinitionAt(NamespaceDom ns, int line, int column)
00333 {
00334 NamespaceList namespaceList = ns->namespaceList();
00335 for (NamespaceList::iterator it=namespaceList.begin(); it!=namespaceList.end(); ++it)
00336 {
00337 if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
00338 return def;
00339 }
00340
00341 ClassList classList = ns->classList();
00342 for (ClassList::iterator it=classList.begin(); it!=classList.end(); ++it)
00343 {
00344 if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
00345 return def;
00346 }
00347
00348 FunctionDefinitionList functionDefinitionList = ns->functionDefinitionList();
00349 for (FunctionDefinitionList::iterator it=functionDefinitionList.begin();
00350 it!=functionDefinitionList.end(); ++it )
00351 {
00352 if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
00353 return def;
00354 }
00355
00356 return FunctionDefinitionDom();
00357 }
00358
00359 FunctionDefinitionDom Navigator::functionDefinitionAt(ClassDom klass, int line, int column)
00360 {
00361 ClassList classList = klass->classList();
00362 for (ClassList::iterator it=classList.begin(); it!=classList.end(); ++it)
00363 {
00364 if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
00365 return def;
00366 }
00367
00368 FunctionDefinitionList functionDefinitionList = klass->functionDefinitionList();
00369 for (FunctionDefinitionList::Iterator it=functionDefinitionList.begin();
00370 it!=functionDefinitionList.end(); ++it)
00371 {
00372 if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
00373 return def;
00374 }
00375
00376 return FunctionDefinitionDom();
00377 }
00378
00379 FunctionDefinitionDom Navigator::functionDefinitionAt(FunctionDefinitionDom fun, int line, int column)
00380 {
00381 int startLine, startColumn;
00382 int endLine, endColumn;
00383
00384 fun->getStartPosition(&startLine, &startColumn);
00385 fun->getEndPosition(&endLine, &endColumn);
00386
00387 if (!(line >= startLine && line <= endLine))
00388 return FunctionDefinitionDom();
00389
00390
00391
00392
00393
00394
00395
00396 return fun;
00397 }
00398
00399
00400 FunctionDom Navigator::currentFunctionDeclaration()
00401 {
00402 if (!m_part->m_activeViewCursor)
00403 return FunctionDom();
00404
00405 unsigned int line, column;
00406 m_part->m_activeViewCursor->cursorPositionReal(&line, &column);
00407 return functionDeclarationAt(line, column);
00408 }
00409
00410 FunctionDom Navigator::functionDeclarationAt(int line, int column)
00411 {
00412 if (!m_part->codeModel()->hasFile(m_part->m_activeFileName))
00413 return FunctionDom();
00414
00415 FileDom file = m_part->codeModel()->fileByName(m_part->m_activeFileName);
00416 return functionDeclarationAt(model_cast<NamespaceDom>(file), line, column);
00417 }
00418
00419 FunctionDom Navigator::functionDeclarationAt(NamespaceDom ns, int line, int column)
00420 {
00421 NamespaceList namespaceList = ns->namespaceList();
00422 for (NamespaceList::iterator it=namespaceList.begin(); it!=namespaceList.end(); ++it)
00423 {
00424 if (FunctionDom def = functionDeclarationAt(*it, line, column))
00425 return def;
00426 }
00427
00428 ClassList classList = ns->classList();
00429 for (ClassList::iterator it=classList.begin(); it!=classList.end(); ++it)
00430 {
00431 if (FunctionDom def = functionDeclarationAt(*it, line, column))
00432 return def;
00433 }
00434
00435 FunctionList functionList = ns->functionList();
00436 for (FunctionList::iterator it=functionList.begin();
00437 it!=functionList.end(); ++it )
00438 {
00439 if (FunctionDom def = functionDeclarationAt(*it, line, column))
00440 return def;
00441 }
00442
00443 return FunctionDom();
00444 }
00445
00446 FunctionDom Navigator::functionDeclarationAt(ClassDom klass, int line, int column)
00447 {
00448 ClassList classList = klass->classList();
00449 for (ClassList::iterator it=classList.begin(); it!=classList.end(); ++it)
00450 {
00451 if (FunctionDom def = functionDeclarationAt(*it, line, column))
00452 return def;
00453 }
00454
00455 FunctionList functionList = klass->functionList();
00456 for (FunctionList::Iterator it=functionList.begin();
00457 it!=functionList.end(); ++it)
00458 {
00459 if (FunctionDom def = functionDeclarationAt(*it, line, column))
00460 return def;
00461 }
00462
00463 return FunctionDom();
00464 }
00465
00466 FunctionDom Navigator::functionDeclarationAt(FunctionDom fun, int line, int column)
00467 {
00468 int startLine, startColumn;
00469 int endLine, endColumn;
00470
00471 fun->getStartPosition(&startLine, &startColumn);
00472 fun->getEndPosition(&endLine, &endColumn);
00473
00474 if (!(line >= startLine && line <= endLine))
00475 return FunctionDom();
00476
00477
00478
00479
00480
00481
00482
00483 return fun;
00484 }
00485
00486
00487 QString Navigator::fullFunctionDefinitionName(FunctionDefinitionDom fun)
00488 {
00489 QStringList scope = fun->scope();
00490 QString funName = scope.join(".");
00491 if (!funName.isEmpty())
00492 funName += ".";
00493 funName += m_part->languageSupport()->formatModelItem(fun, true);
00494 funName = m_part->languageSupport()->formatClassName(funName);
00495
00496 return funName;
00497 }
00498
00499 QString Navigator::fullFunctionDeclarationName(FunctionDom fun)
00500 {
00501 QStringList scope = fun->scope();
00502 QString funName = scope.join(".");
00503 if (!funName.isEmpty())
00504 funName += ".";
00505 funName += m_part->languageSupport()->formatModelItem(fun, true);
00506 funName = m_part->languageSupport()->formatClassName(funName);
00507
00508 return funName;
00509 }
00510
00511 #include "navigator.moc"