00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
#include "cppsupportpart.h"
00017
#include "cppsupport_events.h"
00018
#include "problemreporter.h"
00019
#include "backgroundparser.h"
00020
#include "store_walker.h"
00021
#include "ast.h"
00022
#include "ast_utils.h"
00023
#include "cppcodecompletion.h"
00024
#include "ccconfigwidget.h"
00025
#include "KDevCppSupportIface.h"
00026
#include "cppsupportfactory.h"
00027
#include "catalog.h"
00028
#include "cpp_tags.h"
00029
#include "kdevdriver.h"
00030
#include "cppcodecompletionconfig.h"
00031
#include "tag_creator.h"
00032
#include "cppsupport_utils.h"
00033
#include "classgeneratorconfig.h"
00034
#include "urlutil.h"
00035
00036
00037
#include "cppnewclassdlg.h"
00038
#include "subclassingdlg.h"
00039
#include "addmethoddialog.h"
00040
#include "addattributedialog.h"
00041
00042
#include <qheader.h>
00043
#include <qdir.h>
00044
#include <qdom.h>
00045
#include <qfileinfo.h>
00046
#include <qguardedptr.h>
00047
#include <qpopupmenu.h>
00048
#include <qprogressdialog.h>
00049
#include <qstringlist.h>
00050
#include <qtimer.h>
00051
#include <qstatusbar.h>
00052
#include <qprogressbar.h>
00053
#include <qregexp.h>
00054
#include <qlabel.h>
00055
#include <qvbox.h>
00056
#include <kmessagebox.h>
00057
#include <kaction.h>
00058
#include <kapplication.h>
00059
#include <kdebug.h>
00060
#include <kdialogbase.h>
00061
#include <kgenericfactory.h>
00062
#include <klocale.h>
00063
#include <kmessagebox.h>
00064
#include <kmainwindow.h>
00065
#include <kstatusbar.h>
00066
#include <kconfig.h>
00067
#include <kdeversion.h>
00068
#include <kstandarddirs.h>
00069
#include <kiconloader.h>
00070
00071
#include <ktexteditor/document.h>
00072
#include <ktexteditor/editinterface.h>
00073
#include <ktexteditor/view.h>
00074
#include <ktexteditor/selectioninterface.h>
00075
#include <ktexteditor/viewcursorinterface.h>
00076
#include <ktexteditor/clipboardinterface.h>
00077
00078
#if defined(KDE_MAKE_VERSION)
00079
# if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90)
00080
# include <ktexteditor/texthintinterface.h>
00081
# else
00082
# include <kde30x_texthintinterface.h>
00083
# endif
00084
#else
00085
# include <kde30x_texthintinterface.h>
00086
#endif
00087
00088
#include <kdevcore.h>
00089
#include <kdevproject.h>
00090
#include <kdevmainwindow.h>
00091
#include <kdevpartcontroller.h>
00092
#include <kdevmakefrontend.h>
00093
#include <kdevcoderepository.h>
00094
#include <codemodel_utils.h>
00095
00096
#include <domutil.h>
00097
#include <config.h>
00098
00099
enum {
KDEV_DB_VERSION = 5 };
00100
enum {
KDEV_PCS_VERSION = 5 };
00101
00102 QStringList CppSupportPart::m_sourceMimeTypes =
QStringList() <<
"text/x-csrc" <<
"text/x-c++src";
00103 QStringList
CppSupportPart::m_headerMimeTypes = QStringList() <<
"text/x-chdr" <<
"text/x-c++hdr";
00104
00105 QStringList
CppSupportPart::m_sourceExtensions = QStringList::split(
",",
"c,C,cc,cpp,c++,cxx,m,mm,M" );
00106 QStringList
CppSupportPart::m_headerExtensions = QStringList::split(
",",
"h,H,hh,hxx,hpp,inl,tlh,diff,ui.h" );
00107
00108 class CppDriver:
public KDevDriver
00109 {
00110
public:
00111 CppDriver(
CppSupportPart* cppSupport )
00112 :
KDevDriver( cppSupport )
00113 {
00114 }
00115
00116 void fileParsed(
const QString& fileName )
00117 {
00118
00119
TranslationUnitAST::Node ast = takeTranslationUnit( fileName );
00120
00121
if(
cppSupport()->
problemReporter() ){
00122
cppSupport()->
problemReporter()->
removeAllProblems( fileName );
00123
00124
QValueList<Problem> pl = problems( fileName );
00125
QValueList<Problem>::ConstIterator it = pl.begin();
00126
while( it != pl.end() ){
00127
const Problem& p = *it++;
00128
cppSupport()->
problemReporter()->
reportProblem( fileName, p );
00129 }
00130 }
00131
00132
StoreWalker walker( fileName,
cppSupport()->codeModel() );
00133
00134
if(
cppSupport()->
codeModel()->
hasFile(fileName) ){
00135
FileDom file =
cppSupport()->
codeModel()->
fileByName( fileName );
00136
cppSupport()->
removeWithReferences( fileName );
00137 }
00138
00139 walker.
parseTranslationUnit( ast.get() );
00140
cppSupport()->
codeModel()->
addFile( walker.
file() );
00141 remove( fileName );
00142 }
00143 };
00144
00145 CppSupportPart::CppSupportPart(
QObject *parent,
const char *name,
const QStringList &args)
00146 :
KDevLanguageSupport("CppSupport", "cpp", parent, name ? name : "KDevCppSupport"),
00147 m_activeDocument( 0 ), m_activeView( 0 ), m_activeSelection( 0 ), m_activeEditor( 0 ),
00148 m_activeViewCursor( 0 ), m_projectClosed( true ), m_valid( false )
00149 {
00150 setInstance(CppSupportFactory::instance());
00151
00152
m_pCompletionConfig =
new CppCodeCompletionConfig(
this,
projectDom() );
00153 connect(
m_pCompletionConfig, SIGNAL(stored()),
this, SLOT(
codeCompletionConfigStored()) );
00154
00155
m_driver =
new CppDriver(
this );
00156
m_problemReporter = 0;
00157
00158
m_functionHintTimer =
new QTimer(
this );
00159 connect(
m_functionHintTimer, SIGNAL(timeout()),
this, SLOT(
slotFunctionHint()) );
00160
00161 setXMLFile(
"kdevcppsupport.rc" );
00162
00163
m_catalogList.setAutoDelete(
true );
00164
00165 connect(
core(), SIGNAL(
projectOpened()),
this, SLOT(
projectOpened()) );
00166 connect(
core(), SIGNAL(
projectClosed()),
this, SLOT(
projectClosed()) );
00167 connect(
core(), SIGNAL(languageChanged()),
this, SLOT(
projectOpened()) );
00168 connect(
partController(), SIGNAL(
savedFile(
const QString&)),
00169
this, SLOT(
savedFile(
const QString&)) );
00170 connect(
core(), SIGNAL(
contextMenu(
QPopupMenu *,
const Context *)),
00171
this, SLOT(
contextMenu(
QPopupMenu *,
const Context *)) );
00172 connect(
partController(), SIGNAL(
activePartChanged(
KParts::Part*)),
00173
this, SLOT(
activePartChanged(
KParts::Part*)));
00174 connect(
partController(), SIGNAL(
partRemoved(
KParts::Part*)),
00175
this, SLOT(
partRemoved(
KParts::Part*)));
00176
00177 connect(
core(), SIGNAL(
configWidget(
KDialogBase*)),
00178
this, SLOT(
configWidget(
KDialogBase*)) );
00179
00180
KAction *action;
00181
00182 action =
new KAction(i18n(
"Switch Header/Implementation"), SHIFT+Key_F12,
00183
this, SLOT(
slotSwitchHeader()),
00184
actionCollection(),
"edit_switchheader");
00185 action->setToolTip( i18n(
"Switch between header and implementation files") );
00186 action->setWhatsThis( i18n(
"<b>Switch Header/Implementation</b><p>"
00187
"If you are currently looking at a header file, this "
00188
"brings you to the corresponding implementation file. "
00189
"If you are looking at an implementation file (.cpp etc.), "
00190
"this brings you to the corresponding header file.") );
00191 action->setEnabled(
false);
00192
00193 action =
new KAction(i18n(
"Complete Text"), CTRL+Key_Space,
00194
this, SLOT(
slotCompleteText()),
00195
actionCollection(),
"edit_complete_text");
00196 action->setToolTip( i18n(
"Complete current expression") );
00197 action->setWhatsThis( i18n(
"<b>Complete Text</p><p>Completes current expression using "
00198
"memory class store for the current project and persistant class stores "
00199
"for external libraries.") );
00200 action->setEnabled(
false);
00201
00202 action =
new KAction(i18n(
"Make Member"),
"makermember", Key_F2,
00203
this, SLOT(
slotMakeMember()),
00204
actionCollection(),
"edit_make_member");
00205 action->setToolTip(i18n(
"Make member"));
00206 action->setWhatsThis(i18n(
"<b>Make member</b><p>Creates a class member function in implementation file "
00207
"based on the member declaration at the current line."));
00208 action->setEnabled(
false);
00209
00210 action =
new KAction(i18n(
"New Class..."),
"classnew", 0,
00211
this, SLOT(
slotNewClass()),
00212
actionCollection(),
"project_newclass");
00213 action->setToolTip( i18n(
"Generate a new class") );
00214 action->setWhatsThis( i18n(
"<b>New Class</b><p>Calls the <b>New Class</b> wizard.") );
00215
00216
m_pCompletion = 0;
00217
00218
withcpp =
false;
00219
if ( args.count() == 1 && args[ 0 ] ==
"Cpp" )
00220
withcpp =
true;
00221
00222
00223 connect(
core( ), SIGNAL(
projectConfigWidget(
KDialogBase* ) ),
this,
00224 SLOT(
projectConfigWidget(
KDialogBase* ) ) );
00225
00226
new KDevCppSupportIface(
this );
00227
00228 }
00229
00230
00231 CppSupportPart::~CppSupportPart()
00232 {
00233
if (
project())
00234
projectClosed();
00235
00236
delete(
m_driver );
00237
m_driver = 0;
00238
00239
if(
m_backgroundParser ){
00240
m_backgroundParser->
close();
00241
m_backgroundParser->wait();
00242
delete m_backgroundParser;
00243
m_backgroundParser = 0;
00244 }
00245
00246
codeRepository()->
setMainCatalog( 0 );
00247
00248
QPtrListIterator<Catalog> it(
m_catalogList );
00249
while(
Catalog* catalog = it.current() ){
00250 ++it;
00251
codeRepository()->
unregisterCatalog( catalog );
00252 }
00253
00254
mainWindow( )->
removeView(
m_problemReporter );
00255
00256
delete m_pCompletion;
00257
delete m_problemReporter;
00258
00259
m_pCompletion = 0;
00260
m_problemReporter = 0;
00261 }
00262
00263 void CppSupportPart::customEvent(
QCustomEvent* ev )
00264 {
00265
kdDebug(9007) <<
"CppSupportPart::customEvent(" << ev->type() <<
")" <<
endl;
00266
00267
QTime t;
00268 t.start();
00269
00270
if( ev->type() == int(
Event_FileParsed) ){
00271
FileParsedEvent* event = (
FileParsedEvent*) ev;
00272
QString fileName = event->fileName();
00273
if(
m_problemReporter ){
00274
m_problemReporter->removeAllProblems( fileName );
00275
00276
bool hasErrors =
false;
00277
QValueList<Problem> problems = event->problems();
00278
QValueList<Problem>::ConstIterator it = problems.begin();
00279
while( it != problems.end() ){
00280
const Problem& p = *it++;
00281
if( p.
level() == Problem::Level_Error )
00282 hasErrors =
true;
00283
00284
m_problemReporter->reportProblem( fileName, p );
00285 }
00286
recomputeCodeModel( fileName );
00287
00288 }
00289
00290 emit
fileParsed( fileName );
00291 }
00292 }
00293
00294 void CppSupportPart::projectConfigWidget(
KDialogBase* dlg )
00295 {
00296
QVBox* vbox = 0;
00297
00298 vbox = dlg->
addVBoxPage( i18n(
"C++ Specific" ) );
00299
CCConfigWidget* w =
new CCConfigWidget(
this, vbox );
00300 connect( dlg, SIGNAL( okClicked( ) ), w, SLOT( accept( ) ) );
00301 }
00302
00303 void CppSupportPart::configWidget(
KDialogBase *dlg)
00304 {
00305
QVBox *vbox = dlg->
addVBoxPage(i18n(
"C++ New Class Generator"));
00306
ClassGeneratorConfig *w =
new ClassGeneratorConfig(vbox,
"classgenerator config widget");
00307 connect(dlg, SIGNAL(okClicked()), w, SLOT(storeConfig()));
00308 }
00309
00310 void CppSupportPart::activePartChanged(
KParts::Part *part)
00311 {
00312
kdDebug(9032) <<
"CppSupportPart::activePartChanged()" <<
endl;
00313
00314
bool enabled =
false;
00315
00316
m_functionHintTimer->stop();
00317
00318
if(
m_activeView )
00319 {
00320 disconnect(
m_activeView, SIGNAL(cursorPositionChanged()),
this, SLOT(
slotCursorPositionChanged()) );
00321 }
00322
00323
m_activeDocument = dynamic_cast<KTextEditor::Document*>( part );
00324
m_activeView = part ? dynamic_cast<KTextEditor::View*>( part->
widget() ) : 0;
00325
m_activeEditor = dynamic_cast<KTextEditor::EditInterface*>( part );
00326
m_activeSelection = dynamic_cast<KTextEditor::SelectionInterface*>( part );
00327
m_activeViewCursor = part ? dynamic_cast<KTextEditor::ViewCursorInterface*>(
m_activeView ) : 0;
00328
00329
m_activeFileName = QString::null;
00330
00331
if (
m_activeDocument) {
00332
m_activeFileName =
URLUtil::canonicalPath(
m_activeDocument->
url().
path() );
00333
QFileInfo fi(
m_activeFileName );
00334
QString ext = fi.extension();
00335
if(
isSource(
m_activeFileName) ||
isHeader(
m_activeFileName) )
00336 enabled =
true;
00337 }
00338
00339
actionCollection()->
action(
"edit_switchheader" )->
setEnabled( enabled );
00340
actionCollection()->
action(
"edit_complete_text" )->
setEnabled( enabled );
00341
actionCollection()->
action(
"edit_make_member" )->
setEnabled( enabled );
00342
00343
if( !part )
00344
return;
00345
00346
if( !
m_activeView )
00347
return;
00348
00349
if(
m_activeViewCursor )
00350 {
00351 connect(
m_activeView, SIGNAL(cursorPositionChanged()),
00352
this, SLOT(
slotCursorPositionChanged()) );
00353 }
00354
00355
#if 0
00356
KTextEditor::TextHintInterface* textHintIface = dynamic_cast<KTextEditor::TextHintInterface*>(
m_activeView );
00357
if( !textHintIface )
00358
return;
00359
00360 connect( view, SIGNAL(needTextHint(
int,
int,
QString&)),
00361
this, SLOT(
slotNeedTextHint(
int,
int,
QString&)) );
00362
00363 textHintIface->
enableTextHints( 1000 );
00364
#endif
00365
}
00366
00367
00368 void CppSupportPart::projectOpened( )
00369 {
00370
kdDebug( 9007 ) <<
"projectOpened( )" <<
endl;
00371
00372
m_backgroundParser =
new BackgroundParser(
this, &
m_eventConsumed );
00373
m_backgroundParser->start();
00374
00375
00376
QString conf_file_name =
specialHeaderName();
00377
if( QFile::exists(conf_file_name) )
00378
m_driver->
parseFile( conf_file_name,
true );
00379
00380
m_projectDirectory =
URLUtil::canonicalPath(
project()->projectDirectory() );
00381
m_projectFileList =
project()->
allFiles();
00382
00383
setupCatalog();
00384
00385
m_problemReporter =
new ProblemReporter(
this );
00386
m_problemReporter->setIcon( SmallIcon(
"info") );
00387
mainWindow( )->
embedOutputView(
m_problemReporter, i18n(
"Problems"), i18n(
"Problem reporter"));
00388
00389 connect(
core(), SIGNAL(
configWidget(
KDialogBase*)),
00390
m_problemReporter, SLOT(
configWidget(
KDialogBase*)) );
00391
00392 connect(
project( ), SIGNAL(
addedFilesToProject(
const QStringList & ) ),
00393
this, SLOT(
addedFilesToProject(
const QStringList & ) ) );
00394 connect(
project( ), SIGNAL(
removedFilesFromProject(
const QStringList &) ),
00395
this, SLOT(
removedFilesFromProject(
const QStringList & ) ) );
00396 connect(
project( ), SIGNAL(
changedFilesInProject(
const QStringList & ) ),
00397
this, SLOT(
changedFilesInProject(
const QStringList & ) ) );
00398 connect(
project(), SIGNAL(projectCompiled()),
00399
this, SLOT(
slotProjectCompiled()) );
00400
00401 QDir::setCurrent(
m_projectDirectory );
00402
00403
m_timestamp.clear();
00404
00405
m_pCompletion =
new CppCodeCompletion(
this );
00406
m_projectClosed =
false;
00407
00408 QTimer::singleShot( 500,
this, SLOT(
initialParse( ) ) );
00409 }
00410
00411
00412 void CppSupportPart::projectClosed( )
00413 {
00414
kdDebug( 9007 ) <<
"projectClosed( )" <<
endl;
00415
00416 QStringList enabledPCSs;
00417
QValueList<Catalog*> catalogs =
codeRepository()->
registeredCatalogs();
00418
for(
QValueList<Catalog*>::Iterator it=catalogs.begin(); it!=catalogs.end(); ++it )
00419 {
00420
Catalog* c = *it;
00421
if( c->
enabled() )
00422 enabledPCSs.push_back(
QFileInfo(c->
dbName()).baseName() );
00423 }
00424 DomUtil::writeListEntry( *
project()->
projectDom(),
"kdevcppsupport/references",
"pcs", enabledPCSs );
00425
00426
saveProjectSourceInfo();
00427
00428
m_pCompletionConfig->
store();
00429
00430
delete m_pCompletion;
00431
m_pCompletion = 0;
00432
m_projectClosed =
true;
00433 }
00434
00435
00436 QString CppSupportPart::findHeader(
const QStringList &list,
const QString &header)
00437 {
00438 QStringList::ConstIterator it;
00439
for (it = list.begin(); it != list.end(); ++it) {
00440
QString s = *it;
00441
int pos = s.findRev(
'.');
00442
if (pos != -1)
00443 s = s.left(pos) +
".h";
00444
if (s.right(header.length()) == header)
00445
return s;
00446 }
00447
00448
return QString::null;
00449 }
00450
00451
00452 void CppSupportPart::contextMenu(
QPopupMenu *popup,
const Context *context)
00453 {
00454
m_activeClass = 0;
00455
m_activeFunction = 0;
00456
m_activeVariable = 0;
00457
00458
if( context->
hasType(Context::EditorContext) ){
00459 popup->insertSeparator();
00460
int id = popup->insertItem( i18n(
"Switch Header/Implementation"),
00461
this, SLOT(
slotSwitchHeader() ) );
00462 popup->setWhatsThis(
id, i18n(
"<b>Switch Header/Implementation</b><p>"
00463
"If you are currently looking at a header file, this "
00464
"brings you to the corresponding implementation file. "
00465
"If you are looking at an implementation file (.cpp etc.), "
00466
"this brings you to the corresponding header file.") );
00467
00468
kdDebug(9007) <<
"======> code model has the file: " <<
m_activeFileName <<
" = " <<
codeModel()->
hasFile(
m_activeFileName ) <<
endl;
00469
if(
codeModel()->
hasFile(
m_activeFileName) ){
00470
kdDebug() <<
"CppSupportPart::contextMenu 1" <<
endl;
00471
QString candidate;
00472
if (
isSource(
m_activeFileName))
00473 candidate =
sourceOrHeaderCandidate();
00474
else
00475 candidate =
m_activeFileName;
00476
00477
if (!candidate.isEmpty() &&
codeModel()->
hasFile(candidate) )
00478 {
00479
QPopupMenu* m2 =
new QPopupMenu( popup );
00480
id = popup->insertItem( i18n(
"Go to Declaration"), m2 );
00481 popup->setWhatsThis(
id, i18n(
"<b>Go to declaration</b><p>Provides a menu to select available function declarations "
00482
"in the current file and in the corresponding header (if the current file is an implementation) or source (if the current file is a header) file."));
00483
00484
FileDom file2 =
codeModel()->
fileByName( candidate );
00485
00486
00487
FunctionList functionList2 =
CodeModelUtils::allFunctions(file2);
00488
for( FunctionList::ConstIterator it=functionList2.begin(); it!=functionList2.end(); ++it ){
00489
QString text = (*it)->scope().join(
"::");
00490
00491
if( !
text.isEmpty() )
00492
text +=
"::";
00493
text +=
formatModelItem( *it,
true );
00494
#if QT_VERSION >= 0x030100
00495
text =
text.replace( QString::fromLatin1(
"&"), QString::fromLatin1(
"&&") );
00496
#else
00497
text =
text.replace(
QRegExp(QString::fromLatin1(
"&")), QString::fromLatin1(
"&&") );
00498
#endif
00499
int id = m2->insertItem(
text,
this, SLOT(
gotoDeclarationLine(
int)) );
00500
int line, column;
00501 (*it)->getStartPosition( &line, &column );
00502 m2->setItemParameter(
id, line );
00503 }
00504
00505 }
00506
00507
QString candidate1;
00508
if (
isHeader(m_activeFileName))
00509 candidate1 =
sourceOrHeaderCandidate();
00510
else
00511 candidate1 = m_activeFileName;
00512
00513
00514
if(
codeModel()->
hasFile(candidate1) ){
00515
QPopupMenu* m =
new QPopupMenu( popup );
00516
id = popup->insertItem( i18n(
"Go to Definition"), m );
00517 popup->setWhatsThis(
id, i18n(
"<b>Go to definition</b><p>Provides a menu to select available function definitions "
00518
"in the current file and in the corresponding header (if the current file is an implementation) or source (if the current file is a header) file."));
00519
00520
const FileDom file =
codeModel()->
fileByName( candidate1 );
00521
00522
const FunctionDefinitionList functionDefinitionList =
CodeModelUtils::allFunctionDefinitionsDetailed(
file).functionList;
00523
for( FunctionDefinitionList::ConstIterator it=functionDefinitionList.begin(); it!=functionDefinitionList.end(); ++it ){
00524
QString text = (*it)->scope().join(
"::");
00525
if( !
text.isEmpty() )
00526
text +=
"::";
00527
text +=
formatModelItem( *it,
true );
00528
#if QT_VERSION >= 0x030100
00529
text =
text.replace( QString::fromLatin1(
"&"), QString::fromLatin1(
"&&") );
00530
#else
00531
text =
text.replace(
QRegExp(QString::fromLatin1(
"&")), QString::fromLatin1(
"&&") );
00532
#endif
00533
int id = m->insertItem(
text,
this, SLOT(
gotoLine(
int)) );
00534
int line, column;
00535 (*it)->getStartPosition( &line, &column );
00536 m->setItemParameter(
id, line );
00537 }
00538 }
00539 }
00540
00541
const EditorContext *econtext = static_cast<const EditorContext*>(context);
00542
QString str = econtext->
currentLine();
00543
if (str.isEmpty())
00544
return;
00545
00546
QRegExp re(
"[ \t]*#include[ \t]*[<\"](.*)[>\"][ \t]*");
00547
if (!re.exactMatch(str))
00548
return;
00549
00550
QString popupstr = re.cap(1);
00551
m_contextFileName =
findHeader(
m_projectFileList, popupstr);
00552
if (
m_contextFileName.isEmpty())
00553
return;
00554
00555
id = popup->insertItem( i18n(
"Goto Include File: %1").arg(popupstr),
00556
this, SLOT(
slotGotoIncludeFile()) );
00557 popup->setWhatsThis(
id, i18n(
"<b>Goto include file</b><p>Opens an include file under the cursor position."));
00558
00559 }
else if( context->
hasType(Context::CodeModelItemContext) ){
00560
const CodeModelItemContext* mcontext = static_cast<const CodeModelItemContext*>( context );
00561
00562
if( mcontext->
item()->
isClass() ){
00563
m_activeClass = (
ClassModel*) mcontext->
item();
00564
int id = popup->insertItem( i18n(
"Extract Interface..."),
this, SLOT(
slotExtractInterface()) );
00565 popup->setWhatsThis(
id, i18n(
"<b>Extract interface</b><p>Extracts interface from the selected class and creates a new class with this interface. "
00566
"No implementation code is extracted and no implementation code is created."));
00567 }
else if( mcontext->
item()->
isFunction() ){
00568
m_activeFunction = (
FunctionModel*) mcontext->
item();
00569 }
00570 }
00571 }
00572
00573
00574
00575 QStringList
CppSupportPart::reorder(
const QStringList &list)
00576 {
00577 QStringList headers, others;
00578
00579 QStringList headerExtensions = QStringList::split(
",",
"h,H,hh,hxx,hpp,tlh");
00580
00581 QStringList::ConstIterator it;
00582
for (it = list.begin(); it != list.end(); ++it){
00583
QString fileName = *it;
00584
if (headerExtensions.contains(
QFileInfo(*it).extension()))
00585 headers << (*it);
00586
else
00587 others << (*it);
00588 }
00589
00590
return headers + others;
00591 }
00592
00593 void CppSupportPart::addedFilesToProject(
const QStringList &fileList)
00594 {
00595
m_projectFileList =
project()->
allFiles();
00596 QStringList files =
reorder( fileList );
00597
00598
for ( QStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
00599 {
00600
QString path =
URLUtil::canonicalPath(
m_projectDirectory +
"/" + (*it) );
00601
00602
maybeParse( path );
00603 emit addedSourceInfo( path );
00604 }
00605 }
00606
00607 void CppSupportPart::removedFilesFromProject(
const QStringList &fileList)
00608 {
00609
m_projectFileList =
project()->
allFiles();
00610
for ( QStringList::ConstIterator it = fileList.begin(); it != fileList.end(); ++it )
00611 {
00612
QString path =
URLUtil::canonicalPath(
m_projectDirectory +
"/" + *it );
00613
kdDebug(9007) <<
"=====================> remove file: " << path <<
endl;
00614
00615
removeWithReferences( path );
00616
m_backgroundParser->
removeFile( path );
00617 }
00618 }
00619
00620 void CppSupportPart::changedFilesInProject(
const QStringList & fileList )
00621 {
00622 QStringList files =
reorder( fileList );
00623
00624
for ( QStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
00625 {
00626
QString path =
URLUtil::canonicalPath(
m_projectDirectory +
"/" + *it );
00627
00628
maybeParse( path );
00629 emit addedSourceInfo( path );
00630 }
00631 }
00632
00633 void CppSupportPart::savedFile(
const QString &fileName)
00634 {
00635 Q_UNUSED( fileName );
00636
00637
#if 0 // not needed anymore
00638
kdDebug(9007) <<
"savedFile(): " << fileName.mid (
m_projectDirectory.length() + 1 ) <<
endl;
00639
00640
if (
m_projectFileList.contains(fileName.mid (
m_projectDirectory.length() + 1 ))) {
00641
maybeParse( fileName );
00642 emit addedSourceInfo( fileName );
00643 }
00644
#endif
00645
}
00646
00647 QString CppSupportPart::findSourceFile()
00648 {
00649
QFileInfo fi(
m_activeFileName );
00650
QString path = fi.filePath();
00651
QString ext = fi.extension();
00652
QString base = path.left( path.length() - ext.length() );
00653 QStringList candidates;
00654
00655
if (ext ==
"h" || ext ==
"H" || ext ==
"hh" || ext ==
"hxx" || ext ==
"hpp" || ext ==
"tlh") {
00656 candidates << (base +
"c");
00657 candidates << (base +
"cc");
00658 candidates << (base +
"cpp");
00659 candidates << (base +
"c++");
00660 candidates << (base +
"cxx");
00661 candidates << (base +
"C");
00662 candidates << (base +
"m");
00663 candidates << (base +
"mm");
00664 candidates << (base +
"M");
00665 candidates << (base +
"inl");
00666 }
00667
00668 QStringList::ConstIterator it;
00669
for (it = candidates.begin(); it != candidates.end(); ++it) {
00670
kdDebug(9007) <<
"Trying " << (*it) <<
endl;
00671
if (
QFileInfo(*it).exists()) {
00672
return *it;
00673 }
00674 }
00675
00676
return m_activeFileName;
00677 }
00678
00679 QString CppSupportPart::sourceOrHeaderCandidate()
00680 {
00681
KTextEditor::Document *doc = dynamic_cast<KTextEditor::Document*>(
partController()->
activePart());
00682
if (!doc)
00683
return "";
00684
00685
QFileInfo fi(doc->
url().
path());
00686
QString path = fi.filePath();
00687
QString ext = fi.extension();
00688
QString base = path.left(path.length()-ext.length());
00689
kdDebug(9007) <<
"base: " << base <<
", ext: " << ext <<
endl;
00690 QStringList candidates;
00691
if (ext ==
"h" || ext ==
"H" || ext ==
"hh" || ext ==
"hxx" || ext ==
"hpp" || ext ==
"tlh") {
00692 candidates << (base +
"c");
00693 candidates << (base +
"cc");
00694 candidates << (base +
"cpp");
00695 candidates << (base +
"c++");
00696 candidates << (base +
"cxx");
00697 candidates << (base +
"C");
00698 candidates << (base +
"m");
00699 candidates << (base +
"mm");
00700 candidates << (base +
"M");
00701 candidates << (base +
"inl");
00702 }
else if (QStringList::split(
',',
"c,cc,cpp,c++,cxx,C,m,mm,M,inl").contains(ext)) {
00703 candidates << (base +
"h");
00704 candidates << (base +
"H");
00705 candidates << (base +
"hh");
00706 candidates << (base +
"hxx");
00707 candidates << (base +
"hpp");
00708 candidates << (base +
"tlh");
00709 }
00710
00711 QStringList::ConstIterator it;
00712
for (it = candidates.begin(); it != candidates.end(); ++it) {
00713
kdDebug(9007) <<
"Trying " << (*it) <<
endl;
00714
if (
QFileInfo(*it).exists()) {
00715
return *it;
00716 }
00717 }
00718
return QString::null;
00719 }
00720
00721 void CppSupportPart::slotSwitchHeader()
00722 {
00723
partController()->
editDocument(
sourceOrHeaderCandidate());
00724 }
00725
00726 void CppSupportPart::slotGotoIncludeFile()
00727 {
00728
if (!
m_contextFileName.isEmpty())
00729
partController()->
editDocument(
m_contextFileName, 0);
00730
00731 }
00732
00733 KDevLanguageSupport::Features
CppSupportPart::features()
00734 {
00735
if (
withcpp)
00736
return Features(Classes | Structs | Functions | Variables | Namespaces | Declarations
00737 | Signals | Slots | AddMethod | AddAttribute | NewClass);
00738
else
00739
return Features (Structs | Functions | Variables | Declarations);
00740 }
00741
00742 QString CppSupportPart::formatClassName(
const QString &name)
00743 {
00744
return name;
00745 }
00746
00747 QString CppSupportPart::unformatClassName(
const QString &name)
00748 {
00749
return name;
00750 }
00751
00752 void CppSupportPart::slotNewClass()
00753 {
00754
CppNewClassDialog dlg(
this);
00755 dlg.exec();
00756 }
00757
00758 void CppSupportPart::addMethod(
ClassDom klass )
00759 {
00760
if( !klass ){
00761 KMessageBox::error(0,i18n(
"Please select a class!"),i18n(
"Error"));
00762
return;
00763 }
00764
00765
AddMethodDialog dlg(
this, klass,
mainWindow()->
main() );
00766 dlg.exec();
00767 }
00768
00769 void CppSupportPart::addAttribute(
ClassDom klass )
00770 {
00771
if( !klass ){
00772 KMessageBox::error(0,i18n(
"Please select a class!"),i18n(
"Error"));
00773
return;
00774 }
00775
00776
AddAttributeDialog dlg(
this, klass,
mainWindow()->
main() );
00777 dlg.exec();
00778 }
00779
00780 void CppSupportPart::slotCompleteText()
00781 {
00782
if (!
m_pCompletion)
00783
return;
00784
m_pCompletion->
completeText();
00785 }
00786
00790 void CppSupportPart::initialParse( )
00791 {
00792
00793
if( !
project( ) ){
00794
00795
kdDebug( 9007 ) <<
"No project" <<
endl;
00796
return;
00797 }
00798
00799
parseProject( );
00800 emit
updatedSourceInfo();
00801
m_valid =
true;
00802
return;
00803 }
00804
00805
#if QT_VERSION < 0x030100
00806
00807 uint
toTime_t(
QDateTime t)
00808 {
00809 tm brokenDown;
00810 brokenDown.tm_sec = t.time().second();
00811 brokenDown.tm_min = t.time().minute();
00812 brokenDown.tm_hour = t.time().hour();
00813 brokenDown.tm_mday = t.date().day();
00814 brokenDown.tm_mon = t.date().month() - 1;
00815 brokenDown.tm_year = t.date().year() - 1900;
00816 brokenDown.tm_isdst = -1;
00817
int secsSince1Jan1970UTC = (
int) mktime( &brokenDown );
00818
if ( secsSince1Jan1970UTC < -1 )
00819 secsSince1Jan1970UTC = -1;
00820
return (uint) secsSince1Jan1970UTC;
00821 }
00822
#endif
00823
00824
bool
00825 CppSupportPart::parseProject(
bool force )
00826 {
00827
00828
00829
00830
00831
00832
mainWindow()->
statusBar()->message( i18n(
"Updating...") );
00833
00834 kapp->processEvents( );
00835 kapp->setOverrideCursor( waitCursor );
00836
00837 QStringList files =
reorder(
modifiedFileList() );
00838
00839
QProgressBar* bar =
new QProgressBar( files.count( ),
mainWindow( )->
statusBar( ) );
00840 bar->setMinimumWidth( 120 );
00841 bar->setCenterIndicator(
true );
00842
mainWindow( )->
statusBar( )->addWidget( bar );
00843 bar->show( );
00844
00845
QDir d(
m_projectDirectory );
00846
00847
QDataStream stream;
00848
QMap< QString, QPair<uint, Q_LONG> > pcs;
00849
00850
QString skip_file_name =
project()->
projectDirectory() +
"/" +
project()->
projectName() +
".ignore_pcs";
00851
00852
QFile f(
project()->projectDirectory() +
"/" +
project()->projectName() +
".pcs" );
00853
if( !force && !QFile::exists( skip_file_name ) && f.open(IO_ReadOnly) ){
00854 stream.setDevice( &f );
00855
00856
createIgnorePCSFile();
00857
00858
QString sig;
00859
int pcs_version = 0;
00860 stream >> sig >> pcs_version;
00861
if( sig ==
"PCS" && pcs_version ==
KDEV_PCS_VERSION ){
00862
00863
int numFiles = 0;
00864 stream >> numFiles;
00865
00866
for(
int i=0; i<numFiles; ++i ){
00867
QString fn;
00868 uint ts;
00869 Q_LONG offset;
00870
00871 stream >> fn >> ts >> offset;
00872 pcs[ fn ] = qMakePair( ts, offset );
00873 }
00874 }
00875 }
00876
00877
int n = 0;
00878
for( QStringList::Iterator it = files.begin( ); it != files.end( ); ++it ) {
00879 bar->setProgress( n++ );
00880
QFileInfo fileInfo( d, *it );
00881
00882
if( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ){
00883
QString absFilePath =
URLUtil::canonicalPath(fileInfo.absFilePath() );
00884
00885
if( (n%5) == 0 ){
00886 kapp->processEvents();
00887
00888
if(
m_projectClosed ){
00889
delete( bar );
00890
return false;
00891 }
00892 }
00893
00894
if(
isValidSource(absFilePath) ){
00895
QDateTime t = fileInfo.lastModified();
00896
if(
m_timestamp.contains(absFilePath) &&
m_timestamp[absFilePath] == t )
00897
continue;
00898
00899
#if QT_VERSION >= 0x030100
00900
if( pcs.contains(absFilePath) && t.toTime_t() == pcs[absFilePath].first ){
00901
#else
00902
if( pcs.contains(absFilePath) &&
toTime_t(t) == pcs[absFilePath].first ){
00903
#endif
00904
stream.device()->at( pcs[absFilePath].second );
00905
FileDom file =
codeModel()->
create<
FileModel>();
00906
file->read( stream );
00907
codeModel()->
addFile(
file );
00908 }
else {
00909
kdDebug(9007) <<
"newly parsing(" << absFilePath <<
")..." <<
endl;
00910
m_driver->
parseFile( absFilePath );
00911 }
00912
00913
m_timestamp[ absFilePath ] = t;
00914 }
00915 }
00916
00917
if(
m_projectClosed ){
00918
kdDebug(9007) <<
"ABORT" <<
endl;
00919 kapp->restoreOverrideCursor( );
00920
return false;
00921 }
00922 }
00923
00924
kdDebug( 9007 ) <<
"updating sourceinfo" <<
endl;
00925 emit
updatedSourceInfo();
00926
00927
mainWindow( )->
statusBar( )->removeWidget( bar );
00928
delete bar;
00929
00930
00931
00932 kapp->restoreOverrideCursor( );
00933
mainWindow( )->
statusBar( )->message( i18n(
"Done" ), 2000 );
00934
00935 QFile::remove( skip_file_name );
00936
00937
return true;
00938 }
00939
00940 void CppSupportPart::maybeParse(
const QString& fileName )
00941 {
00942
if( !
isValidSource(fileName) )
00943
return;
00944
00945
QFileInfo fileInfo( fileName );
00946
QString path =
URLUtil::canonicalPath(fileName);
00947
QDateTime t = fileInfo.lastModified();
00948
00949
if( !fileInfo.exists() ){
00950
removeWithReferences( path );
00951
return;
00952 }
00953
00954
QMap<QString, QDateTime>::Iterator it =
m_timestamp.find( path );
00955
if( it !=
m_timestamp.end() && *it == t ){
00956
return;
00957 }
00958
00959
m_timestamp[ path ] = t;
00960
m_driver->
parseFile( path );
00961 }
00962
00963 void CppSupportPart::slotNeedTextHint(
int line,
int column,
QString& textHint )
00964 {
00965
if( 1 || !
m_activeEditor )
00966
return;
00967
00968
m_backgroundParser->
lock();
00969
TranslationUnitAST* ast =
m_backgroundParser->
translationUnit(
m_activeFileName );
00970
AST* node = 0;
00971
if( ast && (node =
findNodeAt(ast, line, column)) ){
00972
00973
while( node && node->nodeType() !=
NodeType_FunctionDefinition )
00974 node = node->parent();
00975
00976
if( node ){
00977
int startLine, startColumn;
00978
int endLine, endColumn;
00979 node->getStartPosition( &startLine, &startColumn );
00980 node->getEndPosition( &endLine, &endColumn );
00981
00982
if( !node->text().isNull() )
00983 textHint = node->text();
00984
else
00985 textHint =
m_activeEditor->
textLine( startLine ).simplifyWhiteSpace();
00986 }
00987 }
00988
m_backgroundParser->
unlock();
00989 }
00990
00991 void CppSupportPart::slotMakeMember()
00992 {
00993
if( !
m_activeViewCursor || !
m_valid )
00994
return;
00995
00996
QString text;
00997
00998
m_backgroundParser->
lock();
00999
TranslationUnitAST* translationUnit =
m_backgroundParser->
translationUnit(
m_activeFileName );
01000
if( translationUnit ){
01001
unsigned int line, column;
01002
m_activeViewCursor->
cursorPositionReal( &line, &column );
01003
01004
AST* currentNode =
findNodeAt( translationUnit, line, column );
01005
DeclaratorAST* declarator = 0;
01006
while( currentNode && currentNode->
nodeType() !=
NodeType_SimpleDeclaration ){
01007
if( currentNode->
nodeType() ==
NodeType_Declarator )
01008 declarator = (
DeclaratorAST*) currentNode;
01009 currentNode = currentNode->
parent();
01010 }
01011
SimpleDeclarationAST* decl = currentNode ? (
SimpleDeclarationAST*) currentNode : 0;
01012
if( decl && decl->
initDeclaratorList() && !declarator ){
01013
InitDeclaratorAST* i = decl->
initDeclaratorList()->
initDeclaratorList().at( 0 );
01014
if( i )
01015 declarator = i->
declarator();
01016 }
01017
01018
if( decl && declarator && declarator->
parameterDeclarationClause() ){
01019
01020 QStringList scope;
01021
scopeOfNode( decl, scope );
01022
01023
QString scopeStr = scope.join(
"::" );
01024
if( !scopeStr.isEmpty() )
01025 scopeStr +=
"::";
01026
01027
QString declStr =
declaratorToString( declarator, scopeStr ).simplifyWhiteSpace();
01028
if( declarator->
exceptionSpecification() ){
01029 declStr += QString::fromLatin1(
" throw( ");
01030
QPtrList<AST> l = declarator->
exceptionSpecification()->
nodeList();
01031
QPtrListIterator<AST> type_it( l );
01032
while( type_it.current() ){
01033 declStr += type_it.current()->text();
01034 ++type_it;
01035
01036
if( type_it.current() )
01037 declStr += QString::fromLatin1(
", " );
01038 }
01039
01040 declStr += QString::fromLatin1(
" )");
01041 }
01042
01043
text +=
"\n\n";
01044
QString type =
typeSpecToString( decl->
typeSpec() );
01045
text += type;
01046
if( !type.isNull() )
01047
text += +
" ";
01048
01049
text += declStr +
"\n{\n}";
01050 }
01051
01052
m_backgroundParser->
unlock();
01053
01054
QString implFile =
findSourceFile();
01055
01056
if( !
text.isEmpty() && !implFile.isEmpty() ){
01057
partController()->
editDocument( implFile );
01058 kapp->processEvents( 500 );
01059 }
01060
01061
m_backgroundParser->
lock();
01062 translationUnit =
m_backgroundParser->
translationUnit(
m_activeFileName );
01063
int atLine, atColumn;
01064
if( translationUnit ){
01065 translationUnit->
getEndPosition( &atLine, &atColumn );
01066 }
else {
01067 atLine =
m_activeEditor->
numLines() - 1;
01068 atColumn = 0;
01069 }
01070
01071
if(
m_activeEditor )
01072
m_activeEditor->
insertText( atLine, atColumn,
text );
01073
if(
m_activeViewCursor )
01074
m_activeViewCursor->
setCursorPositionReal( atLine+3, 1 );
01075 }
01076
m_backgroundParser->
unlock();
01077 }
01078
01079 QStringList
CppSupportPart::subclassWidget(
const QString& formName)
01080 {
01081 QStringList newFileNames;
01082
SubclassingDlg *dlg =
new SubclassingDlg(
this, formName, newFileNames);
01083 dlg->exec();
01084
return newFileNames;
01085 }
01086
01087 QStringList
CppSupportPart::updateWidget(
const QString& formName,
const QString& fileName)
01088 {
01089 QStringList dummy;
01090
SubclassingDlg *dlg =
new SubclassingDlg(
this, formName, fileName, dummy);
01091 dlg->exec();
01092
return dummy;
01093 }
01094
01095 void CppSupportPart::partRemoved(
KParts::Part* part )
01096 {
01097
kdDebug(9032) <<
"CppSupportPart::partRemoved()" <<
endl;
01098
01099
if(
KTextEditor::Document* doc = dynamic_cast<KTextEditor::Document*>( part ) ){
01100
01101
QString fileName = doc->
url().
path();
01102
if( !
isValidSource(fileName) )
01103
return;
01104
01105
QString canonicalFileName =
URLUtil::canonicalPath( fileName );
01106
m_backgroundParser->
removeFile( canonicalFileName );
01107
m_backgroundParser->
addFile( canonicalFileName,
true );
01108 }
01109 }
01110
01111 void CppSupportPart::slotProjectCompiled()
01112 {
01113
kdDebug(9007) <<
"CppSupportPart::slotProjectCompiled()" <<
endl;
01114
parseProject();
01115 }
01116
01117 QStringList
CppSupportPart::modifiedFileList()
01118 {
01119 QStringList lst;
01120
01121 QStringList fileList =
m_projectFileList;
01122 QStringList::Iterator it = fileList.begin();
01123
while( it != fileList.end() ){
01124
QString fileName = *it;
01125 ++it;
01126
01127
QFileInfo fileInfo(
m_projectDirectory, fileName );
01128
QString path =
URLUtil::canonicalPath(fileInfo.absFilePath());
01129
01130
if( !(
isSource(path) ||
isHeader(path)) )
01131
continue;
01132
01133
QDateTime t = fileInfo.lastModified();
01134
01135
QMap<QString, QDateTime>::Iterator dictIt =
m_timestamp.find( path );
01136
if( fileInfo.exists() && dictIt !=
m_timestamp.end() && *dictIt == t )
01137
continue;
01138
01139 lst << fileName;
01140 }
01141
01142
return lst;
01143 }
01144
01145 KTextEditor::Document *
CppSupportPart::findDocument(
const KURL & url )
01146 {
01147
if( !
partController()->
parts() )
01148
return 0;
01149
01150
QPtrList<KParts::Part> parts( *
partController()->parts() );
01151
QPtrListIterator<KParts::Part> it( parts );
01152
while(
KParts::Part* part = it.current() ){
01153
KTextEditor::Document* doc = dynamic_cast<KTextEditor::Document*>( part );
01154
if( doc && doc->
url() == url )
01155
return doc;
01156 ++it;
01157 }
01158
01159
return 0;
01160 }
01161
01162 void CppSupportPart::setupCatalog( )
01163 {
01164
kdDebug(9007) <<
"CppSupportPart::setupCatalog()" <<
endl;
01165
01166
KStandardDirs *dirs = CppSupportFactory::instance()->dirs();
01167 QStringList pcsList = dirs->
findAllResources(
"pcs",
"*.db",
false,
true );
01168 QStringList pcsIdxList = dirs->
findAllResources(
"pcs",
"*.idx",
false,
true );
01169
01170 QStringList enabledPCSs;
01171
if( DomUtil::elementByPath( *
project()->
projectDom(),
"kdevcppsupport/references" ).isNull() ){
01172
for( QStringList::Iterator it=pcsList.begin(); it!=pcsList.end(); ++it ){
01173 enabledPCSs.push_back(
QFileInfo(*it).baseName() );
01174 }
01175 }
else {
01176 enabledPCSs = DomUtil::readListEntry( *
project()->
projectDom(),
"kdevcppsupport/references",
"pcs" );
01177 }
01178
01179 QStringList indexList = QStringList() <<
"kind" <<
"name" <<
"scope" <<
"fileName" <<
"prefix";
01180
01181
if( pcsList.size() &&
pcsVersion() <
KDEV_DB_VERSION ){
01182 QStringList l = pcsList + pcsIdxList;
01183
int rtn = KMessageBox::questionYesNoList( 0, i18n(
"Persistant class store will be disabled!! You have a wrong version of pcs installed.\nRemove old pcs files?"), l, i18n(
"C++ Support") );
01184
if( rtn == KMessageBox::Yes ){
01185 QStringList::Iterator it = l.begin();
01186
while( it != l.end() ){
01187 QFile::remove( *it );
01188 ++it;
01189 }
01190
01191 pcsList.clear();
01192 }
else {
01193
return;
01194 }
01195 }
01196
01197 QStringList::Iterator it = pcsList.begin();
01198
while( it != pcsList.end() ){
01199
Catalog* catalog =
new Catalog();
01200 catalog->
open( *it );
01201 catalog->
setEnabled( enabledPCSs.contains(
QFileInfo(*it).baseName()) );
01202 ++it;
01203
01204
for( QStringList::Iterator idxIt=indexList.begin(); idxIt!=indexList.end(); ++idxIt )
01205 catalog->
addIndex( (*idxIt).utf8() );
01206
01207
m_catalogList.append( catalog );
01208
codeRepository()->
registerCatalog( catalog );
01209 }
01210
01211
setPcsVersion(
KDEV_DB_VERSION );
01212 }
01213
01214 KMimeType::List CppSupportPart::mimeTypes( )
01215 {
01216 QStringList mimeList;
01217 mimeList +=
m_headerMimeTypes;
01218 mimeList +=
m_sourceMimeTypes;
01219
01220
KMimeType::List list;
01221
for( QStringList::Iterator it=mimeList.begin(); it!=mimeList.end(); ++it )
01222 {
01223
if(
KMimeType::Ptr mime = KMimeType::mimeType(*it) )
01224 list << mime;
01225 }
01226
01227
return list;
01228 }
01229
01230 int CppSupportPart::pcsVersion()
01231 {
01232
KConfig*
config = CppSupportFactory::instance()->config();
01233
KConfigGroupSaver cgs( config,
"PCS" );
01234
return config->
readNumEntry(
"Version", 0 );
01235 }
01236
01237 void CppSupportPart::setPcsVersion(
int version )
01238 {
01239
KConfig*
config = CppSupportFactory::instance()->config();
01240
KConfigGroupSaver cgs( config,
"PCS" );
01241 config->
writeEntry(
"Version", version );
01242 config->
sync();
01243 }
01244
01245 QString CppSupportPart::formatTag(
const Tag & inputTag )
01246 {
01247
Tag tag = inputTag;
01248
01249
switch( tag.
kind() )
01250 {
01251
case Tag::Kind_Namespace:
01252
return QString::fromLatin1(
"namespace ") + tag.
name();
01253
01254
case Tag::Kind_Class:
01255
return QString::fromLatin1(
"class ") + tag.
name();
01256
01257
case Tag::Kind_Function:
01258
case Tag::Kind_FunctionDeclaration:
01259 {
01260
CppFunction<Tag> tagInfo( tag );
01261
return tagInfo.
name() +
"( " + tagInfo.
arguments().join(
", ") +
" ) : " + tagInfo.
type();
01262 }
01263
break;
01264
01265
case Tag::Kind_Variable:
01266
case Tag::Kind_VariableDeclaration:
01267 {
01268
CppVariable<Tag> tagInfo( tag );
01269
return tagInfo.
name() +
" : " + tagInfo.
type();
01270 }
01271
break;
01272 }
01273
return tag.
name();
01274 }
01275
01276 void CppSupportPart::codeCompletionConfigStored( )
01277 {
01278
partController()->
setActivePart(
partController()->activePart() );
01279 }
01280
01281 void CppSupportPart::removeWithReferences(
const QString & fileName )
01282 {
01283
kdDebug(9007) <<
"remove with references: " << fileName <<
endl;
01284
m_timestamp.remove( fileName );
01285
if( !
codeModel()->
hasFile(fileName) )
01286
return;
01287
01288 emit aboutToRemoveSourceInfo( fileName );
01289
01290
codeModel()->
removeFile(
codeModel()->fileByName(fileName) );
01291 }
01292
01293 bool CppSupportPart::isValidSource(
const QString& fileName )
const
01294
{
01295
QFileInfo fileInfo( fileName );
01296
QString path =
URLUtil::canonicalPath( fileInfo.absFilePath() );
01297
01298
return project()->
isProjectFile( path )
01299 && (
isSource( path ) ||
isHeader( path ))
01300 && !QFile::exists(fileInfo.dirPath(
true) +
"/.kdev_ignore");
01301 }
01302
01303 QString CppSupportPart::formatModelItem(
const CodeModelItem *item,
bool shortDescription )
01304 {
01305
if (item->
isFunction() || item->
isFunctionDefinition() )
01306 {
01307
const FunctionModel *model = static_cast<const FunctionModel*>(item);
01308
QString function;
01309
QString args;
01310
ArgumentList argumentList = model->
argumentList();
01311
for (ArgumentList::const_iterator it = argumentList.begin(); it != argumentList.end(); ++it)
01312 {
01313 args.isEmpty() ? args +=
"" : args +=
", " ;
01314 args +=
formatModelItem((*it).data());
01315 }
01316
if( !shortDescription )
01317 function += (model->
isVirtual() ?
QString(
"virtual ") :
QString(
"") ) + model->
resultType() +
" ";
01318
01319 function += model->
name() +
"(" + args +
")" + (model->
isConstant() ?
QString(
" const") :
QString(
"") ) +
01320 (model->
isAbstract() ?
QString(
" = 0") :
QString(
"") );
01321
01322
return function;
01323 }
01324
else if (item->
isVariable())
01325 {
01326
const VariableModel *model = static_cast<const VariableModel*>(item);
01327
if( shortDescription )
01328
return model->
name();
01329
return model->
type() +
" " + model->
name();
01330 }
01331
else if (item->
isArgument())
01332 {
01333
const ArgumentModel *model = static_cast<const ArgumentModel*>(item);
01334
QString arg;
01335
if( !shortDescription )
01336 arg += model->
type() +
" ";
01337 arg += model->
name();
01338
if( !shortDescription )
01339 arg += model->
defaultValue().isEmpty() ?
QString(
"") :
QString(
" = ") + model->
defaultValue();
01340
return arg.stripWhiteSpace();
01341 }
01342
else
01343
return KDevLanguageSupport::formatModelItem( item, shortDescription );
01344 }
01345
01346 void CppSupportPart::addClass( )
01347 {
01348
slotNewClass();
01349 }
01350
01351 void CppSupportPart::saveProjectSourceInfo( )
01352 {
01353
const FileList fileList =
codeModel()->
fileList();
01354
01355
if( !
project() || fileList.isEmpty() )
01356
return;
01357
01358
QFile f(
project()->projectDirectory() +
"/" +
project()->projectName() +
".pcs" );
01359
if( !f.open( IO_WriteOnly ) )
01360
return;
01361
01362
createIgnorePCSFile();
01363
01364
QDataStream stream( &f );
01365
QMap<QString, Q_ULONG> offsets;
01366
01367
QString pcs(
"PCS" );
01368 stream << pcs <<
KDEV_PCS_VERSION;
01369
01370 stream << int( fileList.size() );
01371
for( FileList::ConstIterator it=fileList.begin(); it!=fileList.end(); ++it ){
01372
const FileDom dom = (*it);
01373
#if QT_VERSION >= 0x030100
01374
stream << dom->name() <<
m_timestamp[ dom->name() ].toTime_t();
01375
#else
01376
stream << dom->name() <<
toTime_t(
m_timestamp[ dom->name() ]);
01377
#endif
01378
offsets.insert( dom->name(), stream.device()->at() );
01379 stream << (Q_ULONG)0;
01380 }
01381
01382
for( FileList::ConstIterator it=fileList.begin(); it!=fileList.end(); ++it ){
01383
const FileDom dom = (*it);
01384
int offset = stream.device()->at();
01385
01386 dom->write( stream );
01387
01388
int end = stream.device()->at();
01389
01390 stream.device()->at( offsets[dom->name()] );
01391 stream << offset;
01392 stream.device()->at( end );
01393 }
01394
01395
QString skip_file_name =
project()->
projectDirectory() +
"/" +
project()->
projectName() +
".ignore_pcs";
01396 QFile::remove( skip_file_name );
01397 }
01398
01399 QString CppSupportPart::extractInterface(
const ClassDom& klass )
01400 {
01401
QString txt;
01402
QTextStream stream( &txt, IO_WriteOnly );
01403
01404
QString name = klass->name() +
"Interface";
01405
QString ind;
01406 ind.fill(
QChar(
' '), 4 );
01407
01408 stream
01409 <<
"class " << name <<
"\n"
01410 <<
"{" <<
"\n"
01411 <<
"public:" <<
"\n"
01412 << ind << name <<
"() {}" <<
"\n"
01413 << ind <<
"virtual ~" << name <<
"() {}" <<
"\n"
01414 <<
"\n";
01415
01416
const FunctionList functionList = klass->functionList();
01417
for( FunctionList::ConstIterator it=functionList.begin(); it!=functionList.end(); ++it ){
01418
const FunctionDom& fun = *it;
01419
01420
if( !fun->isVirtual() || fun->name().startsWith(
"~") )
01421
continue;
01422
01423 stream << ind <<
formatModelItem( fun );
01424
if( !fun->isAbstract() )
01425 stream <<
" = 0";
01426
01427 stream <<
";\n";
01428 }
01429
01430 stream
01431 <<
"\n"
01432 <<
"private:" <<
"\n"
01433 << ind << name <<
"( const " << name <<
"& source );" <<
"\n"
01434 << ind <<
"void operator = ( const " << name <<
"& source );" <<
"\n"
01435 <<
"};" <<
"\n\n";
01436
01437
return txt;
01438 }
01439
01440 void CppSupportPart::slotExtractInterface( )
01441 {
01442
if( !
m_activeClass )
01443
return;
01444
01445
QFileInfo fileInfo(
m_activeClass->fileName() );
01446
QString ifaceFileName = fileInfo.dirPath(
true ) +
"/" +
m_activeClass->name().lower() +
"_interface.h";
01447
if( QFile::exists(ifaceFileName) ){
01448 KMessageBox::error(
mainWindow()->
main(), i18n(
"File %1 already exists").arg(ifaceFileName),
01449 i18n(
"C++ Support") );
01450 }
else {
01451
QString text =
extractInterface(
m_activeClass );
01452
01453
QFile f( ifaceFileName );
01454
if( f.open(IO_WriteOnly) ){
01455
QTextStream stream( &f );
01456 stream
01457 <<
"#ifndef __" <<
m_activeClass->name().upper() <<
"_INTERFACE_H" <<
"\n"
01458 <<
"#define __" <<
m_activeClass->name().upper() <<
"_INTERFACE_H" <<
"\n"
01459 <<
"\n"
01460 << extractInterface(
m_activeClass )
01461 <<
"\n"
01462 <<
"#endif // __" <<
m_activeClass->name().upper() <<
"_INTERFACE_H" <<
"\n";
01463 f.close();
01464
01465
project()->
addFile( ifaceFileName );
01466 }
01467 }
01468
01469
m_activeClass = 0;
01470 }
01471
01472 void CppSupportPart::gotoLine(
int line )
01473 {
01474
if (
isHeader(
m_activeFileName))
01475 {
01476
KURL url;
01477 url.
setPath(
sourceOrHeaderCandidate());
01478
partController()->
editDocument(url, line);
01479 }
01480
else
01481
m_activeViewCursor->
setCursorPositionReal( line, 0 );
01482 }
01483
01484 void CppSupportPart::recomputeCodeModel(
const QString& fileName )
01485 {
01486
if(
codeModel()->
hasFile(fileName) ){
01487
FileDom file =
codeModel()->
fileByName( fileName );
01488
removeWithReferences( fileName );
01489 }
01490
01491
m_backgroundParser->
lock();
01492
if(
TranslationUnitAST* ast =
m_backgroundParser->
translationUnit(fileName) ){
01493
01494
if(
true ){
01495
StoreWalker walker( fileName,
codeModel() );
01496 walker.
parseTranslationUnit( ast );
01497
codeModel()->
addFile( walker.
file() );
01498 emit addedSourceInfo( fileName );
01499 }
01500 }
01501
m_backgroundParser->
unlock();
01502 }
01503
01504 void CppSupportPart::emitFileParsed( )
01505 {
01506 emit
fileParsed(
m_activeFileName );
01507 }
01508
01509 bool CppSupportPart::isHeader(
const QString& fileName )
const
01510
{
01511
KMimeType::Ptr ptr = KMimeType::findByPath( fileName );
01512
if( ptr &&
m_headerMimeTypes.contains( ptr->name() ) )
01513
return true;
01514
01515
return m_headerExtensions.contains(
QFileInfo(fileName).extension() );
01516 }
01517
01518 bool CppSupportPart::isSource(
const QString& fileName )
const
01519
{
01520
KMimeType::Ptr ptr = KMimeType::findByPath( fileName );
01521
if( ptr &&
m_sourceMimeTypes.contains( ptr->name() ) )
01522
return true;
01523
01524
return m_sourceExtensions.contains(
QFileInfo(fileName).extension() );
01525 }
01526
01527 void CppSupportPart::gotoDeclarationLine(
int line )
01528 {
01529
if (
isHeader(
m_activeFileName))
01530
m_activeViewCursor->
setCursorPositionReal( line, 0 );
01531
else
01532 {
01533
KURL url;
01534 url.
setPath(
sourceOrHeaderCandidate());
01535
partController()->
editDocument(url, line);
01536 }
01537 }
01538
01539 void CppSupportPart::removeCatalog(
const QString & dbName )
01540 {
01541
if( !QFile::exists(dbName) )
01542
return;
01543
01544
QValueList<Catalog*> catalogs =
codeRepository()->
registeredCatalogs();
01545
Catalog* c = 0;
01546
for(
QValueList<Catalog*>::Iterator it=catalogs.begin(); it!=catalogs.end(); ++it )
01547 {
01548
if( (*it)->dbName() == dbName ){
01549 c = *it;
01550
break;
01551 }
01552 }
01553
01554
if( c ){
01555
codeRepository()->
unregisterCatalog( c );
01556
m_catalogList.remove( c );
01557 }
01558
01559
QFileInfo fileInfo( dbName );
01560
QDir dir( fileInfo.dir(
true) );
01561 QStringList fileList = dir.entryList( fileInfo.baseName() +
"*.idx" );
01562
for( QStringList::Iterator it=fileList.begin(); it!=fileList.end(); ++it )
01563 {
01564
QString idxName = fileInfo.dirPath(
true ) +
"/" + *it;
01565
kdDebug(9007) <<
"=========> remove db index: " << idxName <<
endl;
01566 dir.remove( *it );
01567 }
01568
01569 dir.remove( fileInfo.fileName() );
01570 }
01571
01572 void CppSupportPart::addCatalog(
Catalog * catalog )
01573 {
01574
m_catalogList.append( catalog );
01575
codeRepository()->
registerCatalog( catalog );
01576 }
01577
01578 FunctionDefinitionDom CppSupportPart::functionDefinitionAt(
int line,
int column )
01579 {
01580
if( !
codeModel()->
hasFile(
m_activeFileName) )
01581
return FunctionDefinitionDom();
01582
01583
FileDom file =
codeModel()->
fileByName(
m_activeFileName );
01584
return functionDefinitionAt( model_cast<NamespaceDom>(
file), line, column );
01585 }
01586
01587 FunctionDefinitionDom CppSupportPart::currentFunctionDefinition( )
01588 {
01589
if( !this->
m_activeViewCursor )
01590
return FunctionDefinitionDom();
01591
01592
unsigned int line, column;
01593 this->
m_activeViewCursor->
cursorPositionReal( &line, &column );
01594
return functionDefinitionAt( line, column );
01595 }
01596
01597 FunctionDefinitionDom CppSupportPart::functionDefinitionAt(
NamespaceDom ns,
int line,
int column )
01598 {
01599
NamespaceList namespaceList = ns->namespaceList();
01600
for( NamespaceList::Iterator it=namespaceList.begin(); it!=namespaceList.end(); ++it )
01601 {
01602
if(
FunctionDefinitionDom def =
functionDefinitionAt(*it, line, column) )
01603
return def;
01604 }
01605
01606
ClassList classList = ns->classList();
01607
for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it )
01608 {
01609
if(
FunctionDefinitionDom def =
functionDefinitionAt(*it, line, column) )
01610
return def;
01611 }
01612
01613
FunctionDefinitionList functionDefinitionList = ns->functionDefinitionList();
01614
for( FunctionDefinitionList::Iterator it=functionDefinitionList.begin(); it!=functionDefinitionList.end(); ++it )
01615 {
01616
if(
FunctionDefinitionDom def =
functionDefinitionAt(*it, line, column) )
01617
return def;
01618 }
01619
01620
return FunctionDefinitionDom();
01621 }
01622
01623 FunctionDefinitionDom CppSupportPart::functionDefinitionAt(
ClassDom klass,
int line,
int column )
01624 {
01625
ClassList classList = klass->classList();
01626
for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it )
01627 {
01628
if(
FunctionDefinitionDom def =
functionDefinitionAt(*it, line, column) )
01629
return def;
01630 }
01631
01632
FunctionDefinitionList functionDefinitionList = klass->functionDefinitionList();
01633
for( FunctionDefinitionList::Iterator it=functionDefinitionList.begin(); it!=functionDefinitionList.end(); ++it )
01634 {
01635
if(
FunctionDefinitionDom def =
functionDefinitionAt(*it, line, column) )
01636
return def;
01637 }
01638
01639
return FunctionDefinitionDom();
01640 }
01641
01642 FunctionDefinitionDom CppSupportPart::functionDefinitionAt(
FunctionDefinitionDom fun,
int line,
int column )
01643 {
01644
int startLine, startColumn;
01645
int endLine, endColumn;
01646
01647 fun->getStartPosition( &startLine, &startColumn );
01648 fun->getEndPosition( &endLine, &endColumn );
01649
01650
if( ! (line >= startLine && line <= endLine) )
01651
return FunctionDefinitionDom();
01652
01653
if( line == startLine && column < startColumn )
01654
return FunctionDefinitionDom();
01655
01656
if( line == endLine && column > endColumn )
01657
return FunctionDefinitionDom();
01658
01659
return fun;
01660 }
01661
01662 void CppSupportPart::slotCursorPositionChanged()
01663 {
01664
m_functionHintTimer->changeInterval( 1000 );
01665 }
01666
01667 void CppSupportPart::slotFunctionHint( )
01668 {
01669
kdDebug(9007) <<
"=======> compute current function definition" <<
endl;
01670
m_functionHintTimer->stop();
01671
if(
FunctionDefinitionDom fun =
currentFunctionDefinition() )
01672 {
01673 QStringList scope = fun->scope();
01674
QString funName = scope.join(
"::" );
01675
if( !funName.isEmpty() )
01676 funName +=
"::";
01677
01678 funName +=
formatModelItem( fun,
true );
01679
01680
mainWindow()->
statusBar()->message( funName, 2000 );
01681 }
01682 }
01683
01684 void CppSupportPart::createIgnorePCSFile( )
01685 {
01686
static QCString skip_me(
"ignore me\n" );
01687
01688
QString skip_file_name =
project()->
projectDirectory() +
"/" +
project()->
projectName() +
".ignore_pcs";
01689
QFile skip_pcs_file( skip_file_name );
01690
if( skip_pcs_file.open(IO_WriteOnly) )
01691 {
01692 skip_pcs_file.writeBlock( skip_me );
01693 skip_pcs_file.close();
01694 }
01695 }
01696
01697 QString CppSupportPart::specialHeaderName(
bool local )
const
01698
{
01699
if( local )
01700
return ::locateLocal(
"data",
"kdevcppsupport/configuration", CppSupportFactory::instance() );
01701
01702
return ::locate(
"data",
"kdevcppsupport/configuration", CppSupportFactory::instance() );
01703 }
01704
01705 void CppSupportPart::updateParserConfiguration()
01706 {
01707
m_backgroundParser->
updateParserConfiguration();
01708
01709
QString conf_file_name =
specialHeaderName();
01710
m_driver->
removeAllMacrosInFile( conf_file_name );
01711
01712
m_driver->
parseFile( conf_file_name,
true );
01713
01714
parseProject(
true );
01715 }
01716
01717
#include "cppsupportpart.moc"