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