KDevelop API Documentation

languages/cpp/cppsupportpart.cpp

Go to the documentation of this file.
00001 /*************************************************************************** 00002 * Copyright (C) 1999 by Jonas Nordin * 00003 * jonas.nordin@syncom.se * 00004 * Copyright (C) 2000-2001 by Bernd Gehrmann * 00005 * bernd@kdevelop.org * 00006 * Copyright (C) 2002-2003 by Roberto Raggi * 00007 * roberto@kdevelop.org * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 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 // wizards 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 //kdDebug(9007) << "-----> file " << fileName << " parsed!" << endl; 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 // daniel 00223 connect( core( ), SIGNAL( projectConfigWidget( KDialogBase* ) ), this, 00224 SLOT( projectConfigWidget( KDialogBase* ) ) ); 00225 00226 new KDevCppSupportIface( this ); 00227 //(void) dcopClient(); 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 //QTimer::singleShot( 0, this, SLOT(recomputeCodeModel()) ); 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 // setup the driver 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 // kdDebug() << "CppSupportPart::contextMenu 2: candidate: " << candidate << endl; 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 // kdDebug() << "CppSupportPart::contextMenu 3: " << file2->name() << endl; 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 // kdDebug() << "CppSupportPart::contextMenu 3 text: " << text << endl; 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 // kdDebug() << "CppSupportPart::contextMenu 4" << endl; 00505 } 00506 00507 QString candidate1; 00508 if (isHeader(m_activeFileName)) 00509 candidate1 = sourceOrHeaderCandidate(); 00510 else 00511 candidate1 = m_activeFileName; 00512 // kdDebug() << "CppSupportPart::go to definition in " << candidate1 << endl; 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 // const FunctionDefinitionList functionDefinitionList = file->functionDefinitionList(); 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 // Makes sure that header files come first 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 // For debugging 00793 if( !project( ) ){ 00794 // messagebox ? 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 // Taken from qt-3.2/tools/qdatetime.cpp/QDateTime::toTime_t() and modified for normal function 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 //QLabel* label = new QLabel( "", mainWindow( )->statusBar( ) ); 00828 //label->setMinimumWidth( 600 ); 00829 //mainWindow( )->statusBar( )->addWidget( label ); 00830 //label->show( ); 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 //mainWindow( )->statusBar( )->removeWidget( label ); 00930 //delete label; 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 // @todo regenerate the pcs list 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; // dummy offset 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"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:01 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003