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