KDevelop API Documentation

ctagspart.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2001 by Bernd Gehrmann                                  *
00003  *   bernd@kdevelop.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00012 #include "ctagspart.h"
00013 
00014 #include <qapplication.h>
00015 #include <qfileinfo.h>
00016 #include <qpopupmenu.h>
00017 #include <klocale.h>
00018 #include <kdevgenericfactory.h>
00019 #include <kaction.h>
00020 #include <kdebug.h>
00021 #include <kmainwindow.h>
00022 #include <kmessagebox.h>
00023 #include <kprocess.h>
00024 #include <qregexp.h>
00025 #include <ktempfile.h>
00026 #include <kstringhandler.h>
00027 
00028 #include "kdevcore.h"
00029 #include "kdevproject.h"
00030 #include "kdevmainwindow.h"
00031 #include "kdevpartcontroller.h"
00032 #include "ctagskinds.h"
00033 #include "ctagsdlg.h"
00034 
00035 
00036 typedef KDevGenericFactory<CTagsPart> CTagsFactory;
00037 static const KAboutData data("kdevctags", I18N_NOOP("CTags..."), "1.0");
00038 K_EXPORT_COMPONENT_FACTORY( libkdevctags, CTagsFactory( &data ) )
00039 
00040 CTagsPart::CTagsPart( QObject *parent, const char *name, const QStringList & )
00041     : KDevPlugin("CTags", "ctags", parent, name ? name : "CTagsPart")
00042 {
00043     setInstance(CTagsFactory::instance());
00044     setXMLFile("kdevctags.rc");
00045 
00046     KAction *action;
00047 
00048     action = new KAction( i18n("CTags..."), 0,
00049                           this, SLOT(slotSearchTags()),
00050                           actionCollection(), "tools_ctags" );
00051     action->setToolTip(i18n("CTags dialog"));
00052     action->setWhatsThis(i18n("<b>CTags</b><p>Creates a tags database and provides a dialog to search it."));
00053 
00054     mOccuresTagsDlg = 0;
00055     mOccuresTagsDlg = new OccuresTagsDlg;
00056     mOccuresTagsDlg->hide();
00057 
00058     connect( mOccuresTagsDlg->mOcurresList, SIGNAL(clicked( QListBoxItem * )),
00059              this, SLOT(slotGotoTag( QListBoxItem * )) );
00060     connect( core(), SIGNAL(projectClosed()),
00061              this, SLOT(projectClosed()) );
00062     connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
00063              this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
00064 
00065     m_tags = 0;
00066     m_dialog = 0;
00067 }
00068 
00069 
00070 CTagsPart::~CTagsPart()
00071 {
00072     delete m_dialog;
00073     delete m_tags;
00074     delete mOccuresTagsDlg;
00075 }
00076 
00077 
00078 void CTagsPart::projectClosed()
00079 {
00080     delete m_dialog;
00081     delete m_tags;
00082     delete mOccuresTagsDlg;
00083     m_dialog = 0;
00084     m_tags = 0;
00085     mOccuresTagsDlg = 0;
00086 }
00087 
00088 
00089 void CTagsPart::contextMenu(QPopupMenu *popup, const Context *context)
00090 {
00091     if (!context->hasType( Context::EditorContext ))
00092         return;
00093 
00094     const EditorContext *econtext = static_cast<const EditorContext*>(context);
00095     QString ident = econtext->currentWord();
00096     if (ident.isEmpty())
00097         return;
00098 
00099     m_contextString = ident;
00100     QString squeezed = KStringHandler::csqueeze(ident, 30);
00101     int id = popup->insertItem( i18n("Go to ctags Declaration: %1").arg(squeezed),
00102                        this, SLOT(slotGotoDeclaration()) );
00103     popup->setWhatsThis(id, i18n("<b>Go to ctags declaration</b><p>Searches in the tags database for a symbol "
00104         "under the cursor and opens a file that contains the symbol declaration."));
00105     id = popup->insertItem( i18n("Go to ctags Definition: %1").arg(squeezed),
00106                        this, SLOT(slotGotoDefinition()) );
00107     popup->setWhatsThis(id, i18n("<b>Go to ctags definition</b><p>Searches in the tags database for a symbol "
00108         "under the cursor and opens a file that contains the symbol definition."));
00109 }
00110 
00111 
00112 void CTagsPart::gotoTag(const QString &tag, const QString &kindChars)
00113 {
00114     if (!ensureTagsLoaded())
00115         return;
00116 
00117     QString fileName, pattern;
00118     QStringList occuresList;
00119 
00120     CTagsMapIterator result = m_tags->find(tag);
00121     if (result != m_tags->end()) {
00122         CTagsTagInfoListConstIterator it;
00123         for (it = (*result).begin(); it != (*result).end(); ++it)
00124         {
00125             if (kindChars.find((*it).kind) != -1) {
00126                 fileName = (*it).fileName;
00127                 pattern = (*it).pattern;
00128                 occuresList.append( fileName+":"+pattern );
00129             }
00130         }
00131     }
00132 
00133     if (fileName.isNull()) {
00134         KMessageBox::sorry(0, i18n("Tag not found"));
00135         return;
00136     }
00137 
00138     if ( occuresList.count() > 1 ) {
00139         mOccuresTagsDlg->mOcurresList->clear();
00140         mOccuresTagsDlg->mOcurresList->insertStringList( occuresList );
00141         mOccuresTagsDlg->show();
00142     }
00143     else
00144        gotoFinalTag( occuresList[0] );
00145 }
00146 
00147 void CTagsPart::slotGotoTag( QListBoxItem *item )
00148 {
00149     if ( item )
00150        gotoFinalTag( item->text() );
00151 }
00152 
00153 void CTagsPart::gotoFinalTag( const QString & contextStr )
00154 {
00155     mOccuresTagsDlg->hide();
00156 
00157     QString fileName = contextStr.section( ':', 0, 0 );
00158     QString pattern  = contextStr.section( ':', -1 );
00159 
00160     bool ok;
00161     int lineNum = pattern.toInt(&ok);
00162     if (!ok) {
00163         KMessageBox::sorry(0, i18n("Currently, only tags with line numbers (option -n) are supported"));
00164         return;
00165     }
00166 
00167     partController()->editDocument(KURL::fromPathOrURL( fileName ), lineNum-1);
00168 }
00169 
00170 
00171 void CTagsPart::slotGotoDeclaration()
00172 {
00173     gotoTag(m_contextString, "Lcegmnpsux");
00174 }
00175 
00176 
00177 void CTagsPart::slotGotoDefinition()
00178 {
00179     gotoTag(m_contextString, "Sdftv");
00180 }
00181 
00182 
00183 void CTagsPart::slotSearchTags()
00184 {
00185     if (!m_dialog) {
00186         if( ensureTagsLoaded() )
00187             m_dialog = new CTagsDialog(this);
00188     }
00189 
00190     if (m_dialog)
00191         m_dialog->show();
00192 }
00193 
00194 
00195 bool CTagsPart::ensureTagsLoaded()
00196 {
00197     if (m_tags)
00198         return true;
00199     if (!project())
00200         return false;
00201 
00202     kdDebug(9022) << "create/load tags" << endl;
00203 
00204     QFileInfo fi(project()->projectDirectory() + "/tags");
00205     if (!fi.exists()) {
00206         int r = KMessageBox::questionYesNo(mainWindow()->main(), i18n("A ctags file for this project does not exist yet. Create it now?"));
00207         if (r != KMessageBox::Yes)
00208             return false;
00209         if (!createTagsFile()) {
00210             KMessageBox::sorry(mainWindow()->main(), i18n("Could not create tags file.\n\nPlease make sure 'ctags' can be found in your PATH."));
00211             return false;
00212         }
00213     }
00214 
00215     kdDebug(9022) << "load tags from " << endl;
00216     return loadTagsFile();
00217 }
00218 
00219 
00220 bool CTagsPart::loadTagsFile()
00221 {
00222     kdDebug(9022) << "load tags file" << endl;
00223 
00224     QFile f(project()->projectDirectory() + "/tags");
00225     if (!f.open(IO_ReadOnly))
00226         return false;
00227 
00228     if (m_tags)
00229         m_tags->clear();
00230     else
00231         m_tags = new CTagsMap;
00232     m_kindStrings.clear();
00233 
00234     QTextStream stream(&f);
00235     QRegExp re("^([^\t]*)\t([^\t]*)\t([^;]*);\"\t(.*)$");
00236 
00237     QString line;
00238     while (!stream.atEnd()) {
00239         line = stream.readLine().latin1();
00240         //        kdDebug() << "Line: " << line << endl;
00241         if (re.search(line) == -1)
00242             continue;
00243 
00244 
00245         QString tag = re.cap(1);
00246         QString file = re.cap(2);
00247         QString pattern = re.cap(3);
00248         QString extfield = re.cap(4);
00249         //        kdDebug() <<"Tag " << tag << ", file " << file << ", pattern "
00250         //                  << pattern << ", extfield " << extfield << endl;
00251         CTagsMapIterator tiit = m_tags->find(tag);
00252         if (tiit == m_tags->end())
00253             tiit = m_tags->insert(tag, CTagsTagInfoList());
00254 
00255         CTagsTagInfo ti;
00256         ti.fileName = re.cap(2);
00257         ti.pattern = re.cap(3);
00258         ti.kind = re.cap(4)[0].latin1();
00259         (*tiit).append(ti);
00260 
00261         // Put kind in kind list if not already there
00262         QString extension;
00263         if (ti.fileName.right(9) == "/Makefile")
00264             extension = "mak";
00265         else {
00266             int pos = ti.fileName.findRev('.');
00267             if (pos > 0)
00268                 extension = ti.fileName.mid(pos+1);
00269         }
00270         if (extension.isNull())
00271             continue;
00272 
00273         QString kindString = CTagsKinds::findKind(ti.kind, extension);
00274         if (kindString.isNull())
00275             continue;
00276 
00277         if (!m_kindStrings.contains(kindString))
00278             m_kindStrings.append(kindString);
00279     }
00280 
00281     f.close();
00282 
00283     return true;
00284 
00285 #if 0
00286     QDictIterator<CTagsTagInfoList> it(tags);
00287     for (; it.current(); ++it) {
00288         kdDebug() << "Id: " << it.currentKey() << endl;
00289         CTagsTagInfoList *l = it.current();
00290         QValueList<CTagsTagInfo>::ConstIterator it2;
00291         for (it2 = l->begin(); it2 != l->end(); ++it2)
00292             kdDebug() << "at " << (*it2).fileName << "," << (*it2).pattern << endl;
00293     }
00294 #endif
00295 }
00296 
00297 
00298 bool CTagsPart::createTagsFile()
00299 {
00300     kdDebug(9022) << "create tags file" << endl;
00301 
00302     KProcess proc;
00303     proc.setWorkingDirectory( project()->projectDirectory() );
00304 
00305     QStringList l = project()->allFiles();
00306 
00307         KTempFile ifile;
00308         QTextStream& is = *ifile.textStream();
00309         is << l.join( "\n" );
00310         is << "\n";
00311         ifile.close();
00312 
00313     proc << "ctags";
00314     proc << "-n";
00315     proc << "--c++-types=+px";
00316         proc << "-L" << ifile.name();
00317 
00318        QApplication::setOverrideCursor(Qt::waitCursor);
00319        bool success = proc.start(KProcess::Block);
00320        QApplication::restoreOverrideCursor();
00321 
00322        return success;
00323 }
00324 
00325 #include "ctagspart.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:38 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003