/*************************************************************************** * Copyright (C) 1999 by Jonas Nordin * * jonas.nordin@syncom.se * * Copyright (C) 2000-2001 by Bernd Gehrmann * * bernd@kdevelop.org * * Copyright (C) 2002-2003 by Roberto Raggi * * roberto@kdevelop.org * * Copyright (C) 2003-2004 by Alexander Dymo * * adymo@mksat.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "cppsupportpart.h" #include "cppsupport_events.h" #include "problemreporter.h" #include "backgroundparser.h" #include "store_walker.h" #include "ast.h" #include "ast_utils.h" #include "cppcodecompletion.h" #include "ccconfigwidget.h" #include "TDevCppSupportIface.h" #include "cppsupportfactory.h" #include "catalog.h" #include "cpp_tags.h" #include "tdevdriver.h" #include "cppcodecompletionconfig.h" #include "cppsplitheadersourceconfig.h" #include "tag_creator.h" #include "cppsupport_utils.h" #include "classgeneratorconfig.h" #include "urlutil.h" #include "creategettersetterconfiguration.h" #include "tdevsourceformatter.h" #include "tdevcreatefile.h" #include "qtbuildconfig.h" #include "tdeveditorutil.h" #include #include // wizards #include "cppnewclassdlg.h" #include "subclassingdlg.h" #include "addmethoddialog.h" #include "addattributedialog.h" #include "creategettersetterdialog.h" // designer integration #include "qtdesignercppintegration.h" #include "cppimplementationwidget.h" #include "configproblemreporter.h" #include "codeinformationrepository.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const bool alwaysParseInBackground = true; enum { KDEV_DB_VERSION = 21 }; enum { KDEV_PCS_VERSION = 18 }; TQStringList CppSupportPart::m_sourceMimeTypes = TQStringList() << "text/x-csrc" << "text/x-c++src"; TQStringList CppSupportPart::m_headerMimeTypes = TQStringList() << "text/x-chdr" << "text/x-c++hdr"; TQStringList CppSupportPart::m_sourceExtensions = TQStringList::split( ",", "c,C,cc,cpp,c++,cxx,m,mm,M" ); TQStringList CppSupportPart::m_headerExtensions = TQStringList::split( ",", "h,H,hh,h++,hxx,hpp,inl,tlh,diff,ui.h" ); class CppDriver: public TDevDriver { public: CppDriver( CppSupportPart* cppSupport ) : TDevDriver( cppSupport, true ) {} void fileParsed( ParsedFile& fileName ) { //kdDebug(9007) << "-----> file " << fileName << " parsed!" << endl; ParsedFilePointer ast = takeTranslationUnit( fileName.fileName() ); if ( cppSupport() ->problemReporter() ) { cppSupport() ->problemReporter() ->removeAllProblems( fileName.fileName() ); TQValueList pl = problems( fileName.fileName() ); TQValueList::ConstIterator it = pl.begin(); while ( it != pl.end() ) { const Problem & p = *it++; cppSupport() ->problemReporter() ->reportProblem( fileName.fileName(), p ); } } StoreWalker walker( fileName.fileName(), cppSupport() ->codeModel() ); if ( cppSupport() ->codeModel() ->hasFile( fileName.fileName() ) ) { FileDom file = cppSupport() ->codeModel() ->fileByName( fileName.fileName() ); cppSupport() ->removeWithReferences( fileName.fileName() ); } walker.parseTranslationUnit( *ast ); cppSupport() ->codeModel() ->addFile( walker.file() ); remove ( fileName.fileName() ); if( cppSupport()->_jd ) { cppSupport()->_jd->backgroundState ++; cppSupport()->_jd->lastParse = TQTime::currentTime(); } TQFileInfo fileInfo( fileName.fileName() ); TQString path = URLUtil::canonicalPath( fileName.fileName() ); cppSupport()->m_timestamp[ path ] = fileInfo.lastModified(); cppSupport()->emitSynchronousParseReady( fileName.fileName(), ast ); } }; // ProblemReporter doesn't really depend on background parsing, so it's a bit of a mixup to // handle them together, but it's the same config widget so... class BackgroundParserConfig { bool m_useProblemReporter; bool m_useBackgroundParser; int m_backgroundParseDelay; public: void readConfig() { TDEConfig* config = kapp->config(); config->setGroup( "General Options" ); m_useProblemReporter = config->readBoolEntry( "EnableProblemReporter", true ); m_useBackgroundParser = config->readBoolEntry( "EnableCppBgParser", true ); m_backgroundParseDelay = config->readNumEntry( "BgParserDelay", 500 ); } bool useProblemReporter() { return m_useProblemReporter; } bool useBackgroundParser() { return m_useBackgroundParser; } int backgroudParseDelay() { return m_backgroundParseDelay; } }; CppSupportPart::CppSupportPart( TQObject *parent, const char *name, const TQStringList &args ) : TDevLanguageSupport( CppSupportFactory::info(), parent, name ? name : "TDevCppSupport" ), m_backgroundParser(0), m_activeDocument( 0 ), m_activeView( 0 ), m_activeSelection( 0 ), m_activeEditor( 0 ), m_activeViewCursor( 0 ), m_projectClosed( true ), m_projectClosing( false ), m_valid( false ), m_isTyping( false ), m_hadErrors( false ), _jd(0) { setInstance( CppSupportFactory::instance() ); m_pCompletionConfig = new CppCodeCompletionConfig( this, projectDom() ); m_pSplitHeaderSourceConfig = new CppSplitHeaderSourceConfig( this, projectDom() ); m_pCreateGetterSetterConfiguration = new CreateGetterSetterConfiguration( this ); connect( m_pSplitHeaderSourceConfig, TQT_SIGNAL( stored() ), this, TQT_SLOT( splitHeaderSourceConfigStored() ) ); connect( m_pCompletionConfig, TQT_SIGNAL( stored() ), this, TQT_SLOT( codeCompletionConfigStored() ) ); m_qtBuildConfig = new QtBuildConfig( this, projectDom() ); m_qtBuildConfig->store(); m_backgroundParserConfig = new BackgroundParserConfig; m_backgroundParserConfig->readConfig(); m_driver = new CppDriver( this ); m_problemReporter = 0; m_textChangedTimer = new TQTimer( this ); connect( m_textChangedTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotParseCurrentFile()) ); m_cursorMovedTimer = new TQTimer( this ); connect( m_cursorMovedTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotCursorPositionChanged()) ); // m_deleteParserStoreTimer = new TQTimer( this ); m_saveMemoryTimer = new TQTimer( this ); m_buildSafeFileSetTimer = new TQTimer( this ); // m_functionHintTimer = new TQTimer( this ); connect( m_buildSafeFileSetTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(buildSafeFileSet()) ); connect( m_saveMemoryTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotSaveMemory()) ); // connect( m_deleteParserStoreTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotDeleteParserStore()) ); resetParserStoreTimer(); m_saveMemoryTimer->start( 240000, false ); //Free some memory every 4 minutes // connect( m_functionHintTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotFunctionHint()) ); setXMLFile( "tdevcppsupport.rc" ); m_catalogList.setAutoDelete( true ); connect( core(), TQT_SIGNAL( projectOpened() ), this, TQT_SLOT( projectOpened() ) ); connect( core(), TQT_SIGNAL( projectClosed() ), this, TQT_SLOT( projectClosed() ) ); connect( core(), TQT_SIGNAL( languageChanged() ), this, TQT_SLOT( projectOpened() ) ); connect( partController(), TQT_SIGNAL( savedFile( const KURL& ) ), this, TQT_SLOT( savedFile( const KURL& ) ) ); connect( core(), TQT_SIGNAL( contextMenu( TQPopupMenu *, const Context * ) ), this, TQT_SLOT( contextMenu( TQPopupMenu *, const Context * ) ) ); connect( partController(), TQT_SIGNAL( activePartChanged( KParts::Part* ) ), this, TQT_SLOT( activePartChanged( KParts::Part* ) ) ); connect( partController(), TQT_SIGNAL( partRemoved( KParts::Part* ) ), this, TQT_SLOT( partRemoved( KParts::Part* ) ) ); connect( core(), TQT_SIGNAL( configWidget( KDialogBase* ) ), this, TQT_SLOT( configWidget( KDialogBase* ) ) ); m_switchHeaderSourceAction = new TDEAction( i18n( "Switch Header/Implementation" ), SHIFT + Key_F12, this, TQT_SLOT( slotSwitchHeader() ), actionCollection(), "edit_switchheader" ); m_switchHeaderSourceAction->setToolTip( i18n( "Switch between header and implementation files" ) ); m_switchHeaderSourceAction->setWhatsThis( i18n( "Switch Header/Implementation

" "If you are currently looking at a header file, this " "brings you to the corresponding implementation file. " "If you are looking at an implementation file (.cpp etc.), " "this brings you to the corresponding header file." ) ); m_switchHeaderSourceAction->setEnabled( false ); TDEAction *action; action = new TDEAction( i18n( "Complete Text" ), CTRL + Key_Space, this, TQT_SLOT( slotCompleteText() ), actionCollection(), "edit_complete_text" ); action->setToolTip( i18n( "Complete current expression" ) ); action->setWhatsThis( i18n( "Complete Text

Completes current expression using " "memory class store for the current project and persistent class stores " "for external libraries." ) ); action->setEnabled( false ); m_createGetterSetterAction = new TDEAction( i18n( "Create Accessor Methods" ), 0, this, TQT_SLOT( slotCreateAccessMethods() ), actionCollection(), "edit_create_getter_setter" ); action = new TDEAction( i18n( "Make Member" ), 0, Key_F2, this, TQT_SLOT( slotMakeMember() ), actionCollection(), "edit_make_member" ); action->setToolTip( i18n( "Make member" ) ); action->setWhatsThis( i18n( "Make member

Creates a class member function in implementation file " "based on the member declaration at the current line." ) ); action->plug( &m_DummyActionWidget ); action = new TDEAction( i18n( "Navigation Menu" ), 0, CTRL + ALT + Key_Space, this, TQT_SLOT( slotNavigate() ), actionCollection(), "edit_navigate" ); action->setToolTip( i18n( "Show the navigation-menu" ) ); action->setWhatsThis( i18n( "Navigate

Shows a navigation-menu based on the type-evaluation of the item under the cursor." ) ); action->plug( &m_DummyActionWidget ); action = new TDEAction( i18n( "New Class..." ), "classnew", 0, this, TQT_SLOT( slotNewClass() ), actionCollection(), "project_newclass" ); action->setToolTip( i18n( "Generate a new class" ) ); action->setWhatsThis( i18n( "New Class

Calls the New Class wizard." ) ); m_pCompletion = 0; withcpp = false; if ( args.count() == 1 && args[ 0 ] == "Cpp" ) withcpp = true; // daniel connect( core( ), TQT_SIGNAL( projectConfigWidget( KDialogBase* ) ), this, TQT_SLOT( projectConfigWidget( KDialogBase* ) ) ); new TDevCppSupportIface( this ); //(void) dcopClient(); m_lockupTester = new UIBlockTester( 100 ); } CppSupportPart::~CppSupportPart() { delete m_lockupTester; if ( !m_projectClosed ) projectClosed(); delete( m_driver ); m_driver = 0; if ( m_backgroundParser ) { m_backgroundParser->close(); // m_backgroundParser->wait(); delete m_backgroundParser; m_backgroundParser = 0; } codeRepository() ->setMainCatalog( 0 ); TQPtrListIterator it( m_catalogList ); while ( Catalog * catalog = it.current() ) { ++it; codeRepository() ->unregisterCatalog( catalog ); } delete m_backgroundParserConfig; m_backgroundParserConfig = 0; delete m_pCompletion; m_pCompletion = 0; /* mainWindow()->removeView( m_problemReporter ); delete m_problemReporter; m_problemReporter = 0; */ delete _jd; _jd = 0; kdDebug( 9007 ) << k_funcinfo << endl; } void CppSupportPart::customEvent( TQCustomEvent* ev ) { kdDebug( 9007 ) << "CppSupportPart::customEvent(" << ev->type() << ")" << endl; TQTime t; t.start(); bool fromDisk = false; if ( ev->type() == int( Event_FileParsed ) ) { resetParserStoreTimer(); FileParsedEvent * event = ( FileParsedEvent* ) ev; fromDisk = event->fromDisk(); TQString fileName = event->fileName(); bool hasErrors = false; if ( m_problemReporter ) { m_problemReporter->removeAllProblems( fileName ); TQValueList problems = event->problems(); TQValueList::ConstIterator it = problems.begin(); while ( it != problems.end() ) { const Problem & p = *it++; if ( p.level() == Problem::Level_Error ) hasErrors = true; m_problemReporter->reportProblem( fileName, p ); } } ParsedFilePointer p = m_backgroundParser->translationUnit( fileName ); if( p && !p->includedFrom().isEmpty() ) { kdDebug( 9007 ) << "customEvent() parsed included file \"" << fileName << "\" included from \"" << p->includedFrom() << "\"" << endl; } else { kdDebug( 9007 ) << "customEvent() parsed file \"" << fileName << "\"" << endl; } if( p && !p->includedFrom().isEmpty() ) { if( !project()->isProjectFile( fileName ) ) { //The file was parsed to resolve a dependency, and is not a project file addToRepository( p ); } else { //It is a project-file that was parsed for whatever reason to resolve a dependency(currently it isn't handled this way) } } else if( !project()->isProjectFile( fileName ) || !m_parseEmitWaiting.reject( fileName ) ) { ParseEmitWaiting::Processed p = m_parseEmitWaiting.processFile( fileName, ( !m_hadErrors && hasErrors && !fromDisk && m_isTyping && fileName == m_activeFileName ) ? ParseEmitWaiting::HadErrors : ParseEmitWaiting::None ); parseEmit( p ); //Increase status-bar if( p.hasFlag( ParseEmitWaiting::Silent ) && _jd ) { _jd->backgroundState ++; _jd->lastParse = TQTime::currentTime(); } } else { ParseEmitWaiting::Processed p = m_fileParsedEmitWaiting.processFile( fileName ); if( !p.hasFlag( ParseEmitWaiting::Silent ) ) emitFileParsed( p ); //Increase status-bar if( p.hasFlag( ParseEmitWaiting::Silent ) && _jd ) { _jd->backgroundState ++; _jd->lastParse = TQTime::currentTime(); } } } } void CppSupportPart::projectConfigWidget( KDialogBase* dlg ) { TQVBox * vbox = 0; vbox = dlg->addVBoxPage( i18n( "C++ Support" ), i18n( "C++ Support" ), BarIcon( info() ->icon(), TDEIcon::SizeMedium ) ); CCConfigWidget* w = new CCConfigWidget( this, vbox ); connect( dlg, TQT_SIGNAL( okClicked( ) ), w, TQT_SLOT( accept( ) ) ); } void CppSupportPart::configWidget( KDialogBase *dlg ) { TQVBox * vbox = dlg->addVBoxPage( i18n( "C++ Class Generator" ), i18n( "C++ Class Generator" ), BarIcon( info() ->icon(), TDEIcon::SizeMedium ) ); ClassGeneratorConfig *w = new ClassGeneratorConfig( vbox, "classgenerator config widget" ); connect( dlg, TQT_SIGNAL( okClicked() ), w, TQT_SLOT( storeConfig() ) ); vbox = dlg->addVBoxPage(i18n("C++ Parsing"), i18n("C++ Parsing"), BarIcon( "source_cpp", TDEIcon::SizeMedium) ); ConfigureProblemReporter* ww = new ConfigureProblemReporter( vbox ); ww->setPart( this ); connect(dlg, TQT_SIGNAL(okClicked()), ww, TQT_SLOT(accept())); } void CppSupportPart::activePartChanged( KParts::Part *part ) { kdDebug( 9032 ) << "CppSupportPart::activePartChanged()" << endl; bool enabled = false; // m_functionHintTimer->stop(); if ( m_activeView ) { disconnect( m_activeView, TQT_SIGNAL( cursorPositionChanged() ), this, 0 ); } if ( m_activeDocument ) { disconnect( m_activeDocument, TQT_SIGNAL(textChanged()), this, 0 ); } m_isTyping = false; m_hadErrors = true; m_activeDocument = dynamic_cast( part ); m_activeView = part ? dynamic_cast( part->widget() ) : 0; m_activeEditor = dynamic_cast( part ); m_activeSelection = dynamic_cast( part ); m_activeViewCursor = dynamic_cast( m_activeView ); m_activeFileName = TQString(); if ( m_activeDocument ) { m_activeFileName = URLUtil::canonicalPath( m_activeDocument->url().path() ); TQFileInfo fi( m_activeFileName ); TQString ext = fi.extension(); if ( isSource( m_activeFileName ) || isHeader( m_activeFileName ) ) enabled = true; } actionCollection() ->action( "edit_switchheader" ) ->setEnabled( enabled ); actionCollection() ->action( "edit_complete_text" ) ->setEnabled( enabled ); actionCollection() ->action( "edit_make_member" ) ->setEnabled( enabled ); if ( !part || !part->widget() ) return ; if ( m_activeDocument ) { connect( m_activeDocument, TQT_SIGNAL(textChanged()), this, TQT_SLOT(slotTextChanged()) ); m_textChangedTimer->start( 250, true ); // kick the parse timer, we might want to parse the current file } if ( m_activeViewCursor ) { connect( m_activeView, TQT_SIGNAL( cursorPositionChanged() ), this, TQT_SLOT(slotCursorMoved()) ); // this, TQT_SLOT( slotCursorPositionChanged() ) ); } #if 0 KTextEditor::TextHintInterface* textHintIface = dynamic_cast( m_activeView ); if ( !textHintIface ) return ; connect( view, TQT_SIGNAL( needTextHint( int, int, TQString& ) ), this, TQT_SLOT( slotNeedTextHint( int, int, TQString& ) ) ); textHintIface->enableTextHints( 1000 ); #endif } void CppSupportPart::setTyping( bool typing ) { m_isTyping = typing; if( m_problemReporter) { m_hadErrors &= m_problemReporter->hasErrors(m_activeFileName);///m_hadErrors generally stores whether there was an error-free state of the file. } } void CppSupportPart::projectOpened( ) { kdDebug( 9007 ) << "projectOpened( )" << endl; m_backgroundParser = new BackgroundParser( this, &m_eventConsumed ); m_backgroundParser->start( TQThread::IdlePriority ); // setup the driver TQString conf_file_name = specialHeaderName(); if ( TQFile::exists( conf_file_name ) ) m_driver->parseFile( conf_file_name, true, true, true ); m_projectDirectory = URLUtil::canonicalPath( project() ->projectDirectory() ); m_projectFileList = project() ->allFiles(); setupCatalog(); embedProblemReporter(); connect( core(), TQT_SIGNAL( configWidget( KDialogBase* ) ), m_problemReporter, TQT_SLOT( configWidget( KDialogBase* ) ) ); connect( project( ), TQT_SIGNAL( addedFilesToProject( const TQStringList & ) ), this, TQT_SLOT( addedFilesToProject( const TQStringList & ) ) ); connect( project( ), TQT_SIGNAL( removedFilesFromProject( const TQStringList & ) ), this, TQT_SLOT( removedFilesFromProject( const TQStringList & ) ) ); connect( project( ), TQT_SIGNAL( changedFilesInProject( const TQStringList & ) ), this, TQT_SLOT( changedFilesInProject( const TQStringList & ) ) ); connect( project(), TQT_SIGNAL( projectCompiled() ), this, TQT_SLOT( slotProjectCompiled() ) ); m_timestamp.clear(); m_parseEmitWaiting.clear(); m_fileParsedEmitWaiting.clear(); m_pCompletion = new CppCodeCompletion( this ); m_projectClosed = false; m_buildSafeFileSetTimer->start( 500, true ); updateParserConfiguration(); //Necessary to respect custom include-paths and such TQTimer::singleShot( 500, this, TQT_SLOT( initialParse( ) ) ); } void CppSupportPart::embedProblemReporter( bool force ) { if ( force || m_backgroundParserConfig->useProblemReporter() ) { m_problemReporter = new ProblemReporter( this, 0, "problemReporterWidget" ); m_problemReporter->setIcon( SmallIcon( "info" ) ); m_problemReporter->setCaption( i18n( "Problem Reporter" ) ); mainWindow( ) ->embedOutputView( m_problemReporter, i18n( "Problems" ), i18n( "Problem reporter" ) ); } } void CppSupportPart::removeProblemReporter() { mainWindow()->removeView( m_problemReporter ); delete m_problemReporter; m_problemReporter = 0; } void CppSupportPart::projectClosed( ) { kdDebug( 9007 ) << "projectClosed( )" << endl; m_projectClosing = true; TQStringList enabledPCSs; TQValueList catalogs = codeRepository() ->registeredCatalogs(); for ( TQValueList::Iterator it = catalogs.begin(); it != catalogs.end(); ++it ) { Catalog* c = *it; if ( c->enabled() ) enabledPCSs.push_back( TQFileInfo( c->dbName() ).baseName(true) ); } DomUtil::writeListEntry( *project() ->projectDom(), "kdevcppsupport/references", "pcs", enabledPCSs ); for ( TQMap::const_iterator it = m_designers.begin(); it != m_designers.end(); ++it ) { kdDebug( 9007 ) << "calling save settings fro designer integration" << endl; it.data() ->saveSettings( *project() ->projectDom(), "kdevcppsupport/designerintegration" ); } saveProjectSourceInfo(); m_pCompletionConfig->store(); delete _jd; _jd = 0; removeProblemReporter(); delete m_pCompletion; m_parseEmitWaiting.clear(); m_fileParsedEmitWaiting.clear(); m_pCompletion = 0; m_projectClosed = true; m_projectClosing = false; } void CppSupportPart::slotNavigate() { if( codeCompletion() && m_activeView && m_activeViewCursor ) { unsigned int curLine = 0, curCol = 0; m_activeViewCursor->cursorPositionReal( &curLine, &curCol ); if( m_navigationMenu ) delete (TDEPopupMenu*)m_navigationMenu; m_navigationMenu = new TDEPopupMenu( m_activeView ); codeCompletion()->contextEvaluationMenus( m_navigationMenu, 0, curLine, curCol ); m_navigationMenu->move( m_activeView->mapToGlobal( m_activeViewCursor->cursorCoordinates() ) ); if ( m_navigationMenu->count() > 0 ) { m_navigationMenu->show(); } } } void CppSupportPart::contextMenu( TQPopupMenu *popup, const Context *context ) { m_activeClass = 0; m_activeFunction = 0; m_activeVariable = 0; m_curAttribute = 0; m_curClass = 0; if ( context->hasType( Context::EditorContext ) ) { int id; m_switchHeaderSourceAction->plug( popup ); // CodeModelItemContext if ( context->type() == Context::EditorContext ) { m_curClass = currentClass(); if ( m_curClass != 0 ) { m_curAttribute = currentAttribute( m_curClass ); if ( m_curAttribute != 0 ) m_createGetterSetterAction->plug( popup ); } } TQString text; int atline, atcol; MakeMemberHelper( text, atline, atcol ); if ( !text.isEmpty() ) { id = popup->insertItem( i18n( "Make Member" ), this, TQT_SLOT( slotMakeMember() ) ); popup->setWhatsThis( id, i18n( "Make member

Creates a class member function in implementation file " "based on the member declaration at the current line." ) ); } kdDebug( 9007 ) << "======> code model has the file: " << m_activeFileName << " = " << codeModel() ->hasFile( m_activeFileName ) << endl; bool showContextMenuExplosion = false; bool showContextTypeEvaluation = false; TDEConfig *config = CppSupportFactory::instance() ->config(); if ( config ) { config->setGroup( "General" ); showContextMenuExplosion = config->readBoolEntry( "ShowContextMenuExplosion", false ); config->setGroup( "General" ); showContextTypeEvaluation = config->readBoolEntry( "ShowContextTypeEvaluation", true ); } if( codeModel() ->hasFile( m_activeFileName ) ) { if( showContextTypeEvaluation && m_activeViewCursor != 0 ) { if( codeCompletion() ) { unsigned int curLine = 0, curCol = 0; m_activeViewCursor->cursorPositionReal( &curLine, &curCol ); codeCompletion()->contextEvaluationMenus( popup, context, curLine, curCol ); } } if ( showContextMenuExplosion ) { //kdDebug( 9007 ) << "CppSupportPart::contextMenu 1" << endl; TQString candidate; if ( isSource( m_activeFileName ) ) candidate = sourceOrHeaderCandidate(); else candidate = m_activeFileName; unsigned int curLine = 0, curCol = 0; if ( m_activeViewCursor != 0 ) m_activeViewCursor->cursorPositionReal( &curLine, &curCol ); //kdDebug( 9007 ) << "CppSupportPart::contextMenu 2: candidate: " << candidate << endl; if ( !candidate.isEmpty() && codeModel() ->hasFile( candidate ) ) { TQPopupMenu * m2 = new TQPopupMenu( popup ); id = popup->insertItem( i18n( "Go to Declaration" ), m2 ); popup->setWhatsThis( id, i18n( "Go to declaration

Provides a menu to select available function declarations " "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." ) ); FileDom file2 = codeModel() ->fileByName( candidate ); //kdDebug( 9007 ) << "CppSupportPart::contextMenu 3: " << file2->name() << endl; FunctionList functionList2 = CodeModelUtils::allFunctions( file2 ); for ( FunctionList::ConstIterator it = functionList2.begin(); it != functionList2.end(); ++it ) { TQString text = ( *it ) ->scope().join( "::" ); //kdDebug( 9007 ) << "CppSupportPart::contextMenu 3 text: " << text << endl; if ( !text.isEmpty() ) { text += "::"; } text += formatModelItem( *it, true ); text = text.replace( TQString::fromLatin1( "&" ), TQString::fromLatin1( "&&" ) ); int id = m2->insertItem( text, this, TQT_SLOT( gotoDeclarationLine( int ) ) ); int line, column; ( *it ) ->getStartPosition( &line, &column ); m2->setItemParameter( id, line ); } if ( m2->count() == 0 ) { popup->removeItem( id ); } //kdDebug( 9007 ) << "CppSupportPart::contextMenu 4" << endl; } TQString candidate1; if ( isHeader( m_activeFileName ) ) { candidate1 = sourceOrHeaderCandidate(); } else { candidate1 = m_activeFileName; } //kdDebug( 9007 ) << "CppSupportPart::go to definition in " << candidate1 << endl; if ( codeModel() ->hasFile( candidate1 ) ) { TQPopupMenu * m = new TQPopupMenu( popup ); id = popup->insertItem( i18n( "Go to Definition" ), m ); popup->setWhatsThis( id, i18n( "Go to definition

Provides a menu to select available function definitions " "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." ) ); const FileDom file = codeModel() ->fileByName( candidate1 ); const FunctionDefinitionList functionDefinitionList = CodeModelUtils::allFunctionDefinitionsDetailed( file ).functionList; for ( FunctionDefinitionList::ConstIterator it = functionDefinitionList.begin(); it != functionDefinitionList.end(); ++it ) { TQString text = ( *it ) ->scope().join( "::" ); if ( !text.isEmpty() ) { text += "::"; } text += formatModelItem( *it, true ); text = text.replace( TQString::fromLatin1( "&" ), TQString::fromLatin1( "&&" ) ); int id = m->insertItem( text, this, TQT_SLOT( gotoLine( int ) ) ); int line, column; ( *it ) ->getStartPosition( &line, &column ); m->setItemParameter( id, line ); } if ( m->count() == 0 ) { popup->removeItem( id ); } } } } const EditorContext *econtext = static_cast( context ); TQString str = econtext->currentLine(); if ( str.isEmpty() ) return ; } else if ( context->hasType( Context::CodeModelItemContext ) ) { const CodeModelItemContext * mcontext = static_cast( context ); if ( mcontext->item() ->isClass() ) { m_activeClass = ( ClassModel* ) mcontext->item(); int id = popup->insertItem( i18n( "Extract Interface..." ), this, TQT_SLOT( slotExtractInterface() ) ); popup->setWhatsThis( id, i18n( "Extract interface

Extracts interface from the selected class and creates a new class with this interface. " "No implementation code is extracted and no implementation code is created." ) ); } else if ( mcontext->item() ->isFunction() ) { m_activeFunction = ( FunctionModel* ) mcontext->item(); } } else if ( context->hasType( Context::FileContext ) ) { const FileContext * fc = static_cast( context ); //this is a .ui file and only selection contains only one such file KURL url = fc->urls().first(); kdDebug( 9007 ) << "file context with " << url.path() << endl; if ( url.fileName().endsWith( ".ui" ) ) { m_contextFileName = url.path(); int id = popup->insertItem( i18n( "Create or Select Implementation..." ), this, TQT_SLOT( slotCreateSubclass() ) ); popup->setWhatsThis( id, i18n( "Create or select implementation

Creates or selects a subclass of selected form for use with integrated TDevDesigner." ) ); } } } TQStringList makeListUnique( const TQStringList& rhs ) { TQMap map; TQStringList ret; for( TQStringList::const_iterator it = rhs.begin(); it != rhs.end(); ++it ) { if( map.find( *it ) == map.end() ) { ret << *it; map.insert( *it, true ); } } return ret; } // Makes sure that header files come first TQStringList CppSupportPart::reorder( const TQStringList &list ) { TQStringList headers, others; TQStringList headerExtensions = TQStringList::split( ",", "h,H,hh,hxx,hpp,tlh" ); TQString projectPath = project()->projectDirectory(); TQStringList::ConstIterator it; for ( it = list.begin(); it != list.end(); ++it ) { TQString filePath = *it; // brilliant stuff.. this method is apparently called both with // relative and absolute paths.. if ( !filePath.startsWith("/") ) { filePath = projectPath + "/" + filePath; } if( !isValidSource( filePath ) ) continue; if ( headerExtensions.contains( TQFileInfo( filePath ).extension() ) ) headers << ( filePath ); else others << ( filePath ); } return makeListUnique( headers + others ); } void CppSupportPart::addedFilesToProject( const TQStringList &fileList ) { m_projectFileList = project() ->allFiles(); TQStringList files = reorder( fileList ); for ( TQStringList::ConstIterator it = files.begin(); it != files.end(); ++it ) { TQString path = *it; if (!path.startsWith("/")) path = URLUtil::canonicalPath( m_projectDirectory + "/" + ( *it ) ); maybeParse( path ); //emit addedSourceInfo( path ); } m_buildSafeFileSetTimer->start( 500, true ); } void CppSupportPart::removedFilesFromProject( const TQStringList &fileList ) { m_projectFileList = project() ->allFiles(); for ( TQStringList::ConstIterator it = fileList.begin(); it != fileList.end(); ++it ) { TQString path = URLUtil::canonicalPath( m_projectDirectory + "/" + *it ); kdDebug( 9007 ) << "=====================> remove file: " << path << endl; removeWithReferences( path ); m_backgroundParser->removeFile( path ); } m_buildSafeFileSetTimer->start( 500, true ); } void CppSupportPart::changedFilesInProject( const TQStringList & fileList ) { TQStringList files = reorder( fileList ); for ( TQStringList::ConstIterator it = files.begin(); it != files.end(); ++it ) { TQString path = URLUtil::canonicalPath( m_projectDirectory + "/" + *it ); maybeParse( path ); //emit addedSourceInfo( path ); } } void CppSupportPart::savedFile( const KURL &file ) { if( file.path() == m_activeFileName ) { m_isTyping = false; m_hadErrors = false; maybeParse( file.path() ); } Q_UNUSED( file.path() ); #if 0 // not needed anymore kdDebug( 9007 ) << "savedFile(): " << fileName.mid ( m_projectDirectory.length() + 1 ) << endl; if ( m_projectFileList.contains( fileName.mid ( m_projectDirectory.length() + 1 ) ) ) { maybeParse( fileName ); emit addedSourceInfo( fileName ); } #endif } TQString CppSupportPart::findSourceFile() { // get the path of the currently active document TQFileInfo fi( m_activeFileName ); TQString path = fi.filePath(); TQString ext = fi.extension(); // extract the base path (full path without '.' and extension) TQString base = path.left( path.length() - ext.length() - 1 ); TQStringList candidates; if ( TQStringList::split( ',', "h,H,hh,hxx,hpp,tlh" ).contains( ext ) ) { candidates << ( base + ".c" ); candidates << ( base + ".cc" ); candidates << ( base + ".cpp" ); candidates << ( base + ".c++" ); candidates << ( base + ".cxx" ); candidates << ( base + ".C" ); candidates << ( base + ".m" ); candidates << ( base + ".mm" ); candidates << ( base + ".M" ); candidates << ( base + ".inl" ); candidates << ( base + "_impl.h" ); } TQStringList::ConstIterator it; for ( it = candidates.begin(); it != candidates.end(); ++it ) { kdDebug( 9007 ) << "Trying " << ( *it ) << endl; if ( TQFileInfo( *it ).exists() ) { return * it; } } return m_activeFileName; } TQString CppSupportPart::sourceOrHeaderCandidate( const KURL &url ) { TQString urlPath; if ( url.isEmpty() ) { KTextEditor::Document * doc = dynamic_cast( partController() ->activePart() ); if ( !doc ) return TQString(); urlPath = doc->url().path(); } else { urlPath = url.path(); } // get the path of the currently active document TQFileInfo fi( urlPath ); TQString path = fi.filePath(); // extract the exension TQString ext = fi.extension(); if ( ext.isEmpty() ) return TQString(); // extract the base path (full path without '.' and extension) TQString base = path.left( path.length() - ext.length() - 1 ); //kdDebug( 9007 ) << "base: " << base << ", ext: " << ext << endl; // just the filename without the extension TQString fileNameWoExt = fi.fileName(); if ( !ext.isEmpty() ) fileNameWoExt.replace( "." + ext, "" ); TQString possibleExts; // depending on the current extension assemble a list of // candidate files to look for TQStringList candidates; // special case for template classes created by the new class dialog if ( path.endsWith( "_impl.h" ) ) { TQString headerpath = path; headerpath.replace( "_impl.h", ".h" ); candidates << headerpath; fileNameWoExt.replace( "_impl", "" ); possibleExts = "h"; } // if file is a header file search for implementation file else if ( TQStringList::split( ',', "h,H,hh,hxx,hpp,tlh" ).contains( ext ) ) { candidates << ( base + ".c" ); candidates << ( base + ".cc" ); candidates << ( base + ".cpp" ); candidates << ( base + ".c++" ); candidates << ( base + ".cxx" ); candidates << ( base + ".C" ); candidates << ( base + ".m" ); candidates << ( base + ".mm" ); candidates << ( base + ".M" ); candidates << ( base + ".inl" ); candidates << ( base + "_impl.h" ); possibleExts = "c,cc,cpp,c++,cxx,C,m,mm,M,inl,_impl.h"; } // if file is an implementation file, search for header file else if ( TQStringList::split( ',', "c,cc,cpp,c++,cxx,C,m,mm,M,inl" ).contains( ext ) ) { candidates << ( base + ".h" ); candidates << ( base + ".H" ); candidates << ( base + ".hh" ); candidates << ( base + ".hxx" ); candidates << ( base + ".hpp" ); candidates << ( base + ".tlh" ); possibleExts = "h,H,hh,hxx,hpp,tlh"; } // search for files from the assembled candidate lists, return the first // candidate file that actually exists or TQString() if nothing is found. TQStringList::ConstIterator it; for ( it = candidates.begin(); it != candidates.end(); ++it ) { //kdDebug( 9007 ) << "Trying " << ( *it ) << endl; if ( TQFileInfo( *it ).exists() ) { kdDebug( 9007 ) << "using: " << *it << endl; return * it; } } //kdDebug( 9007 ) << "Now searching in project files." << endl; // Our last resort: search the project file list for matching files TQStringList::iterator fileIt; TQFileInfo candidateFileWoExt; TQString candidateFileWoExtString; TQStringList possibleExtsList = TQStringList::split( ',', possibleExts ); for ( fileIt = m_projectFileList.begin(); fileIt != m_projectFileList.end(); ++fileIt ) { candidateFileWoExt.setFile(*fileIt); //kdDebug( 9007 ) << "candidate file: " << *fileIt << endl; if( !candidateFileWoExt.extension().isEmpty() ) candidateFileWoExtString = candidateFileWoExt.fileName().replace( "." + candidateFileWoExt.extension(), "" ); if ( candidateFileWoExtString == fileNameWoExt ) { if ( possibleExtsList.contains( candidateFileWoExt.extension() ) || candidateFileWoExt.extension().isEmpty() ) { //kdDebug( 9007 ) << "checking if " << *fileIt << " exists" << endl; if ( TQFileInfo( *fileIt ).exists() ) kdDebug( 9007 ) << "using: " << *fileIt << endl; return *fileIt; } } } return TQString(); } void CppSupportPart::slotSaveMemory() { if( m_backgroundParser ) { ///This is done so the caches are completely empty after tdevelop was idle for some time(else it would be waste of memory). The background-parsers internal lexer-cache-manager just cares about keeping the count of cached files under a specific count, but doesn't decrease that count when tdevelop is idle. m_backgroundParser->lock(); m_backgroundParser->saveMemory(); m_backgroundParser->unlock(); } } void CppSupportPart::slotSwitchHeader( bool scrollOnly ) { bool attemptMatch = true; TDEConfig *config = CppSupportFactory::instance() ->config(); if ( config ) { config->setGroup( "General" ); attemptMatch = config->readBoolEntry( "SwitchShouldMatch", true ); } // ok, both files exist. Do the codemodel have them? if ( codeModel() ->hasFile( m_activeFileName ) && m_activeViewCursor && attemptMatch ) { unsigned int currentline, column; m_activeViewCursor->cursorPositionReal( ¤tline, &column ); if ( switchHeaderImpl( m_activeFileName, currentline, column, scrollOnly ) ) return; } // last chance KURL url; url.setPath( sourceOrHeaderCandidate() ); if ( scrollOnly ) return; else if ( !splitHeaderSourceConfig()->splitEnabled() ) partController() ->editDocument( url ); else partController() ->splitCurrentDocument( url ); } bool CppSupportPart::switchHeaderImpl( const TQString& file, int line, int col, bool scrollOnly ) { bool handled = false; FunctionDom d; FileDom fd = codeModel() ->fileByName( file ); if ( fd ) { CodeModelUtils::CodeModelHelper h( codeModel(), fd ); d = h.functionAt( line, col ); } if ( d ) { if( d->isFunctionDefinition() ) { FunctionDom decl = findFunction( d ); if ( decl ) { if ( (void*)&decl != (void*)d.data() && ( !scrollOnly || decl->fileName() != file ) ) { jumpToCodeModelItem( model_cast(decl), scrollOnly ); handled = true; } } } else { FunctionDom def = findFunctionDefinition( d ); if ( def ) { if ( def != d && ( !scrollOnly || def->fileName() != file ) ) { jumpToCodeModelItem( model_cast(def), scrollOnly ); handled = true; } } } } return handled; } FunctionDom CppSupportPart::findFunction( const FunctionDom& def ) { // We have a definition so we're looking for a declaration. The declaration will either be the child of a namespace node (non class members) // or the child of a class node (class member). Search recursively until we find a declaration that matches. FunctionDom bestMatch; FunctionDom decl = findFunctionInNamespace( codeModel()->globalNamespace(), def, codeModel()->globalNamespace()->namespaceImports(), sourceOrHeaderCandidate( def->fileName() ), 0, bestMatch ); return decl ? decl : bestMatch; } FunctionDom CppSupportPart::findFunctionInNamespace( const NamespaceDom& ns, const FunctionDom& def, const std::set& nsImports, const TQString& candidateFile, int scopeIndex, FunctionDom& bestMatch ) { FunctionDom d; TQStringList scope = def->scope(); if ( !(scopeIndex >= (signed) scope.size()) ) { NamespaceDom ns_next = ns->namespaceByName( scope[ scopeIndex ] ); if ( ns_next ) { d = findFunctionInNamespace( ns_next, def, ns_next->namespaceImports(), candidateFile, scopeIndex+1, bestMatch ); } if ( !d ) { for ( std::set::const_iterator it_ns = nsImports.begin(); it_ns != nsImports.end(); ++it_ns ) { if ( (*it_ns).fileName().str() == def->fileName() ) { ns_next = ns->namespaceByName( (*it_ns).name() ); if ( ns_next ) { if ( d = findFunctionInNamespace( ns_next, def, nsImports, candidateFile, scopeIndex, bestMatch ) ) break; } } } } if ( !d ) { ClassList classList = ns->classByName( scope[ scopeIndex ] ); for ( ClassList::ConstIterator it_cs = classList.begin(); it_cs != classList.end(); ) { if ( d = findFunctionInClass( *(it_cs++), def, nsImports, candidateFile, scopeIndex+1, bestMatch ) ) break; } } } if ( !d ) { FunctionList functionList = ns->functionByName( def->name() ); for ( FunctionList::ConstIterator it_decl = functionList.begin(); it_decl != functionList.end(); ++it_decl ) { if ( CodeModelUtils::compareDeclarationToDefinition( *it_decl, (FunctionDefinitionModel*) def.data(), nsImports ) ) { ParsedFile* p = dynamic_cast( def->file()->parseResult().data() ); if ( p ) { if ( p->includeFiles()[ (*it_decl)->fileName() ] ) { d = *it_decl; break; } else if ( (*it_decl)->fileName() == candidateFile ) { d = *it_decl; break; } } if ( !bestMatch ) { bestMatch = *it_decl; } } } } return d; } FunctionDom CppSupportPart::findFunctionInClass( const ClassDom& cs, const FunctionDom& def, const std::set& nsImports, const TQString& candidateFile, int scopeIndex, FunctionDom& bestMatch ) { FunctionDom d; TQStringList scope = def->scope(); if ( !(scopeIndex >= (signed) scope.size()) ) { ClassList classList = cs->classByName( scope[ scopeIndex ] ); for ( ClassList::ConstIterator it_cs = classList.begin(); it_cs != classList.end(); ) { if ( d = findFunctionInClass( *(it_cs++), def, nsImports, candidateFile, scopeIndex+1, bestMatch ) ) break; } } if ( !d ) { FunctionList functionList = cs->functionByName( def->name() ); for ( FunctionList::ConstIterator it_decl = functionList.begin(); it_decl != functionList.end(); ++it_decl ) { if ( CodeModelUtils::compareDeclarationToDefinition( *it_decl, (FunctionDefinitionModel*) def.data(), nsImports ) ) { ParsedFile* p = dynamic_cast( def->file()->parseResult().data() ); if ( p ) { if ( p->includeFiles()[ (*it_decl)->fileName() ] ) { d = *it_decl; break; } else if ( (*it_decl)->fileName() == candidateFile ) { d = *it_decl; break; } } if ( !bestMatch ) { bestMatch = *it_decl; } } } } return d; } FunctionDom CppSupportPart::findFunctionDefinition( const FunctionDom& decl ) { // We have a declaration so we're looking for a definition. The definition will be the child of some namespace node (never a class node). // Since the definition can be the child of any namespace in its scope depending on syntax, we have to check every one. FunctionDom def, bestMatch; NamespaceDom ns = codeModel()->globalNamespace(); TQString candidateFile = sourceOrHeaderCandidate( decl->fileName() ); FunctionDefinitionList functionList = ns->functionDefinitionByName( decl->name() ); for ( FunctionDefinitionList::ConstIterator it_def = functionList.begin(); it_def != functionList.end() && !def; ++it_def ) { if ( CodeModelUtils::compareDeclarationToDefinition( decl, *it_def, ns->namespaceImports() ) ) { ParsedFile* p = dynamic_cast( (*it_def)->file()->parseResult().data() ); if ( p ) { if ( p->includeFiles()[ decl->fileName() ] ) { def = *it_def; } else if ( (*it_def)->fileName() == candidateFile ) { def = *it_def; break; } } if ( !bestMatch ) { bestMatch = *it_def; } } } TQStringList scope = decl->scope(); for ( TQStringList::ConstIterator it_scope = scope.begin(); it_scope != scope.end() && !def; ++it_scope ) { NamespaceDom ns_next = ns->namespaceByName( *it_scope ); if ( ns_next ) { ns = ns_next; FunctionDefinitionList functionList = ns->functionDefinitionByName( decl->name() ); for ( FunctionDefinitionList::ConstIterator it_def = functionList.begin(); it_def != functionList.end() && !def; ++it_def ) { if ( CodeModelUtils::compareDeclarationToDefinition( decl, *it_def, ns->namespaceImports() ) ) { ParsedFile* p = dynamic_cast( (*it_def)->file()->parseResult().data() ); if ( p ) { if ( p->includeFiles()[ decl->fileName() ] ) { def = *it_def; } else if ( (*it_def)->fileName() == candidateFile ) { def = *it_def; break; } } if ( !bestMatch ) { bestMatch = *it_def; } } } } } return def ? def : bestMatch; } void CppSupportPart::jumpToCodeModelItem( const ItemDom& item, bool scrollOnly ) { static KURL lastSyncedUrl; static int lastSyncedLine = -1; int line, col; item->getStartPosition( &line, &col ); KURL url( item->fileName() ); if ( scrollOnly ) { KParts::ReadOnlyPart* part = partController()->partForURL( url ); int currentLine = lastSyncedLine; if ( part ) { KTextEditor::ViewCursorInterface *iface = dynamic_cast(part->widget()); if( iface ) iface->cursorPosition( (uint*) ¤tLine, (uint*) &col ); } partController() ->scrollToLineColumn( url, line, -1, lastSyncedLine != currentLine || lastSyncedUrl != url ); } else if ( !splitHeaderSourceConfig()->splitEnabled() ) partController() ->editDocument( url, line ); else partController() ->splitCurrentDocument( url, line ); lastSyncedLine = line; lastSyncedUrl = url; } TDevLanguageSupport::Features CppSupportPart::features() { if ( withcpp ) return Features( Classes | Structs | Functions | Variables | Namespaces | Declarations | Signals | Slots | AddMethod | AddAttribute | NewClass | CreateAccessMethods ); else return Features ( Structs | Functions | Variables | Declarations ); } TQString CppSupportPart::formatClassName( const TQString &name ) { TQString n = name; return n.replace( ".", "::" ); } TQString CppSupportPart::unformatClassName( const TQString &name ) { TQString n = name; return n.replace( "::", "." ); } bool CppSupportPart::shouldSplitDocument(const KURL &url) { if ( !splitHeaderSourceConfig()->splitEnabled() ) return false; KURL::List list = partController()->openURLs(); KURL::List::ConstIterator it = list.begin(); while ( it != list.end() ) { TQString candidate = sourceOrHeaderCandidate( ( *it ) ); if ( candidate.isEmpty() ) { ++it; continue; } KURL urlCandidate; urlCandidate.setPath( candidate ); if ( url == urlCandidate ) { // It is already open, so switch to it so // our split view will open with it partController() ->editDocument( ( *it ) ); return true; } ++it; } return false; } Qt::Orientation CppSupportPart::splitOrientation() const { TQString o = splitHeaderSourceConfig()->orientation(); if ( o == "Vertical" ) return Qt::Vertical; else return Qt::Horizontal; } void CppSupportPart::slotNewClass() { CppNewClassDialog dlg( this ); dlg.exec(); } void CppSupportPart::addMethod( ClassDom klass ) { if ( !klass ) { KMessageBox::error( 0, i18n( "Please select a class." ), i18n( "Error" ) ); return ; } AddMethodDialog dlg( this, klass, mainWindow() ->main() ); dlg.exec(); } void CppSupportPart::addAttribute( ClassDom klass ) { if ( !klass ) { KMessageBox::error( 0, i18n( "Please select a class." ), i18n( "Error" ) ); return ; } AddAttributeDialog dlg( this, klass, mainWindow() ->main() ); dlg.exec(); } void CppSupportPart::slotCompleteText() { if ( !m_pCompletion ) return ; m_pCompletion->completeText( true ); } /** * parsing stuff for project persistent classstore and code completion */ void CppSupportPart::initialParse( ) { // For debugging if ( !project( ) ) { // messagebox ? kdDebug( 9007 ) << "No project" << endl; return ; } parseProject( ); m_valid = true; return ; } bool CppSupportPart::parseProject( bool force ) { if( _jd ) delete _jd->progressBar; ///Make sure the progress-bar is open mainWindow() ->statusBar() ->message( i18n( "Updating..." ) ); kapp->setOverrideCursor( waitCursor ); _jd = new JobData; if( TQFileInfo( project() ->projectDirectory() + "/" + project()->projectName().lower() + ".tdevelop.pcs" ).exists()) { TQDir d( project() ->projectDirectory()); d.rename(project() ->projectName().lower() + ".tdevelop.pcs", project() ->projectName() +".tdevelop.pcs"); } _jd->file.setName( project() ->projectDirectory() + "/" + project()->projectName() + ".tdevelop.pcs" ); TQString skip_file_name = project() ->projectDirectory() + "/" + project() ->projectName() + ".tdevelop.ignore_pcs"; TQString skip_lower_file_name = project() ->projectDirectory() + "/" + project() ->projectName().lower() + ".tdevelop.ignore_pcs"; if ( !force && !TQFile::exists( skip_file_name ) && !TQFile::exists( skip_lower_file_name ) && _jd->file.open( IO_ReadOnly ) ) { _jd->stream.setDevice( &( _jd->file ) ); createIgnorePCSFile(); TQString sig; int pcs_version = 0; _jd->stream >> sig >> pcs_version; if ( sig == "PCS" && pcs_version == KDEV_PCS_VERSION ) { int numFiles = 0; _jd->stream >> numFiles; kdDebug( 9007 ) << "Read " << numFiles << " files from pcs" << endl; for ( int i = 0; i < numFiles; ++i ) { TQString fn; uint ts; uint offset; _jd->stream >> fn >> ts >> offset; _jd->pcs[ fn ] = tqMakePair( ts, offset ); } } } _jd->files = reorder( modifiedFileList() ); TQProgressBar* bar = new TQProgressBar( _jd->files.count( ), mainWindow( ) ->statusBar( ) ); bar->setMinimumWidth( 120 ); bar->setCenterIndicator( true ); mainWindow( ) ->statusBar( ) ->addWidget( bar ); bar->show( ); _jd->progressBar = bar; _jd->dir.setPath( m_projectDirectory ); _jd->it = _jd->files.begin(); _jd->reparseList = TQStringList(); _jd->backgroundCount = 0; _jd->cycle = 0; TQTimer::singleShot( 0, this, TQT_SLOT( slotParseFiles() ) ); m_saveMemoryTimer->stop(); //Do not regularly remove cached files that may still be needed while parsing(the cache anyway be full for the whole parsing-process) return true; } void CppSupportPart::slotParseFiles() { // NOTE: The checking for m_projectClosed is actually (currently) not needed. // When the project is closed, the language support plugin is destroyed // and as a consequence, the timer job signal never arrives at this method if ( !_jd ) return; // how can this possibly happen?! if ( _jd->cycle == 0 && !m_projectClosed && _jd->it != _jd->files.end() ) { _jd->progressBar->setProgress( _jd->progressBar->progress() + 1 ); TQFileInfo fileInfo( _jd->dir, *( _jd->it ) ); if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) { TQString absFilePath = URLUtil::canonicalPath( fileInfo.absFilePath() ); if ( isValidSource( absFilePath ) ) { TQDateTime t = fileInfo.lastModified(); if ( ! ( m_timestamp.contains( absFilePath ) && m_timestamp[ absFilePath ] == t ) ) { if ( _jd->pcs.contains( absFilePath ) ) { _jd->stream.device() ->at( _jd->pcs[ absFilePath ].second ); FileDom file = codeModel() ->create(); file->read( _jd->stream ); codeModel() ->addFile( file ); if( t.toTime_t() != _jd->pcs[ absFilePath ].first ) { ///The FileDom had to be created first, so the dependencies are known _jd->reparseList << file->name(); /* kdDebug( 9007 ) << "File timestamp: " << ": " << t.toTime_t() << endl; kdDebug( 9007 ) << "Stored timestamp: " << ": " << _jd->pcs[ absFilePath ].first << endl;*/ } else { m_timestamp[ absFilePath ] = t; /* kdDebug( 9007 ) << "timestamp ok" << endl;*/ } } else { _jd->reparseList << absFilePath; /* kdDebug( 9007 ) << absFilePath << " put into reparse-list" << endl; */ } } else { /* kdDebug( 9007 ) << absFilePath << " is already in code-model" << endl;*/ } } } ++( _jd->it ); TQTimer::singleShot( 0, this, TQT_SLOT( slotParseFiles() ) ); if( _jd->it == _jd->files.end()) { if( _jd->reparseList.isEmpty() ) { _jd->backgroundCount = 0; } else { if( alwaysParseInBackground ) { _jd->backgroundCount = parseFilesAndDependencies( _jd->reparseList, true, false, true ); } else { _jd->reparseList = reorder( _jd->reparseList ); _jd->it = _jd->reparseList.begin(); _jd->backgroundCount = _jd->reparseList.count(); } _jd->progressBar->setProgress( 0 ); ///restart progress-bar for reparsing _jd->progressBar->setTotalSteps( _jd->backgroundCount ); } _jd->lastBackgroundState = -1; _jd->backgroundState = 0; _jd->cycle = 1; _jd->lastParse = TQTime::currentTime(); kapp->restoreOverrideCursor( ); } } else // finished or interrupted { if( _jd->backgroundCount <= _jd->backgroundState || m_projectClosed ) { mainWindow( ) ->statusBar( ) ->removeWidget( _jd->progressBar ); if ( !m_projectClosed ) { kdDebug( 9007 ) << "updating sourceinfo" << endl; kapp->restoreOverrideCursor( ); emit updatedSourceInfo(); mainWindow( ) ->statusBar( ) ->message( i18n( "Done" ), 2000 ); TQFile::remove( project() ->projectDirectory() + "/" + project() ->projectName() + ".tdevelop.ignore_pcs" ); TQFile::remove( project() ->projectDirectory() + "/" + project() ->projectName().lower() + ".tdevelop.ignore_pcs" ); } else { kdDebug( 9007 ) << "ABORT" << endl; } delete _jd; _jd = 0; m_saveMemoryTimer->start( 240000, false ); } else { _jd->progressBar->setProgress( _jd->backgroundState ); ///restart _jd->progressBar->setTotalSteps( _jd->backgroundCount ); if( _jd->lastParse.msecsTo( TQTime::currentTime()) > 60000 && !m_backgroundParser->filesInQueue()) { _jd->backgroundCount = _jd->backgroundState; ///Stop waiting if there is no progress and no file in the background-parser TQTimer::singleShot( 0, this, TQT_SLOT( slotParseFiles() ) ); } else { int timeStep = 0; if( alwaysParseInBackground ) { TQTimer::singleShot( 10, this, TQT_SLOT( slotParseFiles() ) ); } else { if( _jd->it == _jd->reparseList.end() ) { /*_jd->it = _jd->files.end(); _jd->backgroundCount = _jd->backgroundState; ///finish processing*/ timeStep = 1; } else { /*///Parse the files one by one if( _jd->lastParse.msecsTo( TQTime::currentTime()) > 100 || _jd->backgroundState != _jd->lastBackgroundState ) {*/ maybeParse( *_jd->it, false ); ++(_jd->it); _jd->lastBackgroundState = _jd->backgroundState; /*}else{ timeStep = 1; }*/ } TQTimer::singleShot( timeStep, this, TQT_SLOT( slotParseFiles() ) ); } } } } } void CppSupportPart::maybeParse( const TQString& fn, bool background ) { if ( !isValidSource( fn ) ) return ; TQFileInfo fileInfo( fn ); TQString path = URLUtil::canonicalPath( fn ); TQDateTime t = fileInfo.lastModified(); if ( !fileInfo.exists() ) return; TQMap::Iterator it = m_timestamp.find( path ); if ( codeModel()->hasFile( fn ) && it != m_timestamp.end() && *it == t ) return; TQStringList l; l << fn; parseFilesAndDependencies( l, background ); } bool CppSupportPart::isQueued( const TQString& file ) const { //int c = m_backgroundParser->countInQueue( file ); //if( c == 0 ) return false; return m_parseEmitWaiting.waiting( file, ParseEmitWaiting::Silent, 2 ); //Since it may be possible that the background-parser is currently parsing the file(in an obselete state), it is allowed to have the file in the queue twice. } void CppSupportPart::slotNeedTextHint( int line, int column, TQString& textHint ) { if ( 1 || !m_activeEditor ) return ; m_backgroundParser->lock(); TranslationUnitAST* ast = *m_backgroundParser->translationUnit( m_activeFileName ); AST* node = 0; if ( ast && ( node = findNodeAt( ast, line, column ) ) ) { while ( node && node->nodeType() != NodeType_FunctionDefinition ) node = node->parent(); if ( node ) { int startLine, startColumn; int endLine, endColumn; node->getStartPosition( &startLine, &startColumn ); node->getEndPosition( &endLine, &endColumn ); if ( !node->text().isNull() ) textHint = node->text(); else textHint = m_activeEditor->textLine( startLine ).simplifyWhiteSpace(); } } m_backgroundParser->unlock(); } void CppSupportPart::MakeMemberHelper( TQString& text, int& atLine, int& atColumn ) { if ( !m_activeViewCursor || !m_valid ) return ; atLine = -2; atColumn = 0; TQString implFile = findSourceFile(); m_backgroundParser->lock(); TranslationUnitAST* translationUnit = *m_backgroundParser->translationUnit( m_activeFileName ); if ( translationUnit ) { bool fail = false; unsigned int line, column; m_activeViewCursor->cursorPositionReal( &line, &column ); AST* currentNode = findNodeAt( translationUnit, line, column ); DeclaratorAST* declarator = 0; while ( currentNode && currentNode->nodeType() != NodeType_SimpleDeclaration ) { if ( currentNode->nodeType() == NodeType_Declarator ) declarator = ( DeclaratorAST* ) currentNode; currentNode = currentNode->parent(); } SimpleDeclarationAST* decl = currentNode ? ( SimpleDeclarationAST* ) currentNode : 0; if ( decl && decl->storageSpecifier() && decl->storageSpecifier()->text().contains("friend") ) { kdDebug(9007) << "this is a friend declaration, don't create any definition" << endl; fail = true; } if ( !fail && decl && decl->initDeclaratorList() && !declarator ) { InitDeclaratorAST * i = decl->initDeclaratorList() ->initDeclaratorList().at( 0 ); if ( i ) declarator = i->declarator(); } if ( !fail && decl && declarator && declarator->parameterDeclarationClause() ) { TQStringList scope; scopeOfNode( decl, scope ); TQString scopeStr = scope.join( "::" ); if ( !scopeStr.isEmpty() ) scopeStr += "::"; TQString declStr = declaratorToString( declarator, scopeStr ).simplifyWhiteSpace(); if ( declarator->exceptionSpecification() ) { declStr += TQString::fromLatin1( " throw( " ); TQPtrList l = declarator->exceptionSpecification() ->nodeList(); TQPtrListIterator type_it( l ); while ( type_it.current() ) { declStr += type_it.current() ->text(); ++type_it; if ( type_it.current() ) declStr += TQString::fromLatin1( ", " ); } declStr += TQString::fromLatin1( " )" ); } text += "\n\n"; TQString type = typeSpecToString( decl->typeSpec() ); text += type; if ( !type.isNull() ) text += + " "; text += declStr + "\n{\n}"; } if ( !fail ) { translationUnit = *m_backgroundParser->translationUnit( implFile ); if ( translationUnit ) translationUnit->getEndPosition( &atLine, &atColumn ); } kdDebug( 9007 ) << "at line in mm: " << atLine << endl; } m_backgroundParser->unlock(); } void CppSupportPart::slotMakeMember() { TQString text; int atColumn, atLine; MakeMemberHelper( text, atLine, atColumn ); if ( !text.isEmpty() ) { TQString implFile = findSourceFile(); if ( !implFile.isEmpty() ) { partController() ->editDocument( KURL( implFile ) ); kapp->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput | TQEventLoop::ExcludeSocketNotifiers, 500 ); } if ( atLine == -2 ) atLine = m_activeEditor->numLines() - 1; m_backgroundParser->lock () ; kdDebug( 9007 ) << "at line in mm: " << atLine << " atCol: " << atColumn << endl; kdDebug( 9007 ) << "text: " << text << endl; if ( m_activeEditor ) m_activeEditor->insertText( atLine, atColumn, text ); if ( m_activeViewCursor ) m_activeViewCursor->setCursorPositionReal( atLine + 3, 1 ); m_backgroundParser->unlock(); } } TQStringList CppSupportPart::subclassWidget( const TQString& formName ) { TQStringList newFileNames; SubclassingDlg *dlg = new SubclassingDlg( this, formName, newFileNames ); dlg->exec(); return newFileNames; } TQStringList CppSupportPart::updateWidget( const TQString& formName, const TQString& fileName ) { TQStringList dummy; SubclassingDlg *dlg = new SubclassingDlg( this, formName, fileName, dummy ); dlg->exec(); return dummy; } void CppSupportPart::partRemoved( KParts::Part* part ) { kdDebug( 9032 ) << "CppSupportPart::partRemoved()" << endl; if ( KTextEditor::Document * doc = dynamic_cast( part ) ) { TQString fileName = doc->url().path(); if ( !isValidSource( fileName ) ) return ; TQString canonicalFileName = URLUtil::canonicalPath( fileName ); m_backgroundParser->removeFile( canonicalFileName ); m_backgroundParser->addFile( canonicalFileName, true ); } } void CppSupportPart::slotProjectCompiled() { kdDebug( 9007 ) << "CppSupportPart::slotProjectCompiled()" << endl; parseProject(); } TQStringList CppSupportPart::modifiedFileList() { TQStringList lst; TQStringList fileList = m_projectFileList; TQStringList::Iterator it = fileList.begin(); while ( it != fileList.end() ) { TQString fileName = *it; ++it; TQFileInfo fileInfo( m_projectDirectory, fileName ); TQString path = URLUtil::canonicalPath( fileInfo.absFilePath() ); if ( !( isSource( path ) || isHeader( path ) ) ) continue; TQDateTime t = fileInfo.lastModified(); TQMap::Iterator dictIt = m_timestamp.find( path ); if ( fileInfo.exists() && dictIt != m_timestamp.end() && *dictIt == t ) continue; lst << fileName; } return lst; } KTextEditor::Document * CppSupportPart::findDocument( const KURL & url ) { if ( !partController() ->parts() ) return 0; TQPtrList parts( *partController() ->parts() ); TQPtrListIterator it( parts ); while ( KParts::Part * part = it.current() ) { KTextEditor::Document * doc = dynamic_cast( part ); if ( doc && doc->url() == url ) return doc; ++it; } return 0; } void CppSupportPart::setupCatalog( ) { kdDebug( 9007 ) << "CppSupportPart::setupCatalog()" << endl; TDEStandardDirs *dirs = CppSupportFactory::instance() ->dirs(); TQStringList pcsList = dirs->findAllResources( "pcs", "*.db", false, true ); TQStringList pcsIdxList = dirs->findAllResources( "pcs", "*.idx", false, true ); TQStringList enabledPCSs; if ( DomUtil::elementByPath( *project() ->projectDom(), "kdevcppsupport/references" ).isNull() ) { for ( TQStringList::Iterator it = pcsList.begin(); it != pcsList.end(); ++it ) { kdDebug( 9007 ) << "CppSupportPart::setupCatalog()1 " << *it << endl; enabledPCSs.push_back( TQFileInfo( *it ).baseName(true) ); } } else { enabledPCSs = DomUtil::readListEntry( *project() ->projectDom(), "kdevcppsupport/references", "pcs" ); } TQStringList indexList = TQStringList() << "kind" << "name" << "scope" << "fileName" << "prefix"; if ( pcsList.size() && pcsVersion() < KDEV_DB_VERSION ) { TQStringList l = pcsList + pcsIdxList; int rtn = KMessageBox::questionYesNoList( 0, i18n( "Persistent class store will be disabled: you have a wrong version of pcs installed.\nRemove old pcs files?" ), l, i18n( "C++ Support" ), KStdGuiItem::del(), KStdGuiItem::cancel() ); if ( rtn == KMessageBox::Yes ) { TQStringList::Iterator it = l.begin(); while ( it != l.end() ) { TQFile::remove ( *it ); ++it; } // @todo regenerate the pcs list pcsList.clear(); } else { return ; } } TQStringList::Iterator it = pcsList.begin(); while ( it != pcsList.end() ) { kdDebug( 9007 ) << "CppSupportPart::setupCatalog()2 " << *it << endl; Catalog * catalog = new Catalog(); catalog->open( *it ); catalog->setEnabled( enabledPCSs.contains( TQFileInfo( *it ).baseName(true) ) ); ++it; for ( TQStringList::Iterator idxIt = indexList.begin(); idxIt != indexList.end(); ++idxIt ) catalog->addIndex( ( *idxIt ).utf8() ); m_catalogList.append( catalog ); codeRepository() ->registerCatalog( catalog ); } setPcsVersion( KDEV_DB_VERSION ); } KMimeType::List CppSupportPart::mimeTypes( ) { TQStringList mimeList; mimeList += m_headerMimeTypes; mimeList += m_sourceMimeTypes; KMimeType::List list; for ( TQStringList::Iterator it = mimeList.begin(); it != mimeList.end(); ++it ) { if ( KMimeType::Ptr mime = KMimeType::mimeType( *it ) ) list << mime; } return list; } int CppSupportPart::pcsVersion() { TDEConfig * config = CppSupportFactory::instance() ->config(); TDEConfigGroupSaver cgs( config, "PCS" ); return config->readNumEntry( "Version", 0 ); } void CppSupportPart::setPcsVersion( int version ) { TDEConfig * config = CppSupportFactory::instance() ->config(); TDEConfigGroupSaver cgs( config, "PCS" ); config->writeEntry( "Version", version ); config->sync(); } TQString CppSupportPart::formatTag( const Tag & inputTag ) { Tag tag = inputTag; switch ( tag.kind() ) { case Tag::Kind_Namespace: return TQString::fromLatin1( "namespace " ) + tag.name(); case Tag::Kind_Class: return TQString::fromLatin1( "class " ) + tag.name(); case Tag::Kind_Function: case Tag::Kind_FunctionDeclaration: { CppFunction tagInfo( tag ); return tagInfo.name() + "( " + tagInfo.arguments().join( ", " ) + " ) : " + tagInfo.type(); } break; case Tag::Kind_Variable: case Tag::Kind_VariableDeclaration: { CppVariable tagInfo( tag ); return tagInfo.name() + " : " + tagInfo.type(); } break; } return tag.name(); } void CppSupportPart::codeCompletionConfigStored( ) { if ( m_projectClosing ) return; updateParserConfiguration(); /* m_backgroundParser->updateParserConfiguration(); TDevDriver* d = dynamic_cast( m_driver ); //The foreground-parse isn't used anymore, and could be removed if( d ) { d->setup(); d->makeMacrosPersistent(); }*/ partController() ->setActivePart( partController()->activePart() ); } void CppSupportPart::splitHeaderSourceConfigStored( ) { TQString o = splitHeaderSourceConfig()->orientation(); if ( o == "Vertical" ) emit splitOrientationChanged( Qt::Vertical ); else if ( o == "Horizontal" ) emit splitOrientationChanged( Qt::Horizontal ); } void CppSupportPart::removeWithReferences( const TQString & fileName ) { kdDebug( 9007 ) << "remove with references: " << fileName << endl; m_timestamp.remove( fileName ); if ( !codeModel() ->hasFile( fileName ) ) return ; emit aboutToRemoveSourceInfo( fileName ); codeModel() ->removeFile( codeModel() ->fileByName( fileName ) ); } bool CppSupportPart::isValidSource( const TQString& fileName ) const { TQFileInfo fileInfo( fileName ); TQString path = URLUtil::canonicalPath( fileInfo.absFilePath() ); return /*project() && project() ->isProjectFile( path ) &&*/ ( isSource( path ) || isHeader( path ) ) && !TQFile::exists( fileInfo.dirPath( true ) + "/.tdev_ignore" ); } TQString CppSupportPart::formatModelItem( const CodeModelItem *item, bool shortDescription ) { if ( item->isFunction() || item->isFunctionDefinition() ) { const FunctionModel * model = static_cast( item ); TQString function; TQString args; ArgumentList argumentList = model->argumentList(); for ( ArgumentList::const_iterator it = argumentList.begin(); it != argumentList.end(); ++it ) { args.isEmpty() ? args += "" : args += ", " ; args += formatModelItem( ( *it ).data() ); } if ( !shortDescription ) function += ( model->isVirtual() ? TQString( "virtual " ) : TQString( "" ) ) + model->resultType() + " "; function += model->name() + "(" + args + ")" + ( model->isConstant() ? TQString( " const" ) : TQString( "" ) ) + ( model->isAbstract() ? TQString( " = 0" ) : TQString( "" ) ); return function; } else if ( item->isVariable() ) { const VariableModel * model = static_cast( item ); if ( shortDescription ) return model->name(); return model->type() + " " + model->name(); } else if ( item->isArgument() ) { const ArgumentModel * model = static_cast( item ); TQString arg; if ( !shortDescription ) arg += model->type() + " "; arg += model->name(); if ( !shortDescription ) arg += model->defaultValue().isEmpty() ? TQString( "" ) : TQString( " = " ) + model->defaultValue(); return arg.stripWhiteSpace(); } else return TDevLanguageSupport::formatModelItem( item, shortDescription ); } void CppSupportPart::addClass() { slotNewClass(); } void CppSupportPart::saveProjectSourceInfo() { const FileList fileList = codeModel() ->fileList(); if ( !project() || fileList.isEmpty() ) return ; TQFile f( project() ->projectDirectory() + "/" + project() ->projectName() + ".tdevelop.pcs" ); if ( !f.open( IO_WriteOnly ) ) return ; m_backgroundParser->lock(); createIgnorePCSFile(); TQDataStream stream( &f ); TQMap offsets; TQString pcs( "PCS" ); stream << pcs << KDEV_PCS_VERSION; stream << int( fileList.size() ); for ( FileList::ConstIterator it = fileList.begin(); it != fileList.end(); ++it ) { const FileDom dom = ( *it ); stream << dom->name() << m_timestamp[ dom->name() ].toTime_t(); if( m_timestamp.find( dom->name() ) == m_timestamp.end() ) { kdDebug( 9007 ) << dom->name() << ": timestamp is missing " << endl; } offsets.insert( dom->name(), stream.device() ->at() ); stream << ( uint ) 0; // dummy offset } for ( FileList::ConstIterator it = fileList.begin(); it != fileList.end(); ++it ) { const FileDom dom = ( *it ); int offset = stream.device() ->at(); dom->write( stream ); int end = stream.device() ->at(); stream.device() ->at( offsets[ dom->name() ] ); stream << offset; stream.device() ->at( end ); } TQFile::remove( project() ->projectDirectory() + "/" + project() ->projectName() + ".tdevelop.ignore_pcs" ); TQFile::remove( project() ->projectDirectory() + "/" + project() ->projectName().lower() + ".tdevelop.ignore_pcs" ); m_backgroundParser->unlock(); } TQString CppSupportPart::extractInterface( const ClassDom& klass ) { TQString txt; TQTextStream stream( &txt, IO_WriteOnly ); TQString name = klass->name() + "Interface"; TQString ind; ind.fill( TQChar( ' ' ), 4 ); stream << "class " << name << "\n" << "{" << "\n" << "public:" << "\n" << ind << name << "() {}" << "\n" << ind << "virtual ~" << name << "() {}" << "\n" << "\n"; const FunctionList functionList = klass->functionList(); for ( FunctionList::ConstIterator it = functionList.begin(); it != functionList.end(); ++it ) { const FunctionDom& fun = *it; if ( !fun->isVirtual() || fun->name().startsWith( "~" ) ) continue; stream << ind << formatModelItem( fun ); if ( !fun->isAbstract() ) stream << " = 0"; stream << ";\n"; } stream << "\n" << "private:" << "\n" << ind << name << "( const " << name << "& source );" << "\n" << ind << "void operator = ( const " << name << "& source );" << "\n" << "};" << "\n\n"; return txt; } void CppSupportPart::slotExtractInterface( ) { if ( !m_activeClass ) return ; TQFileInfo fileInfo( m_activeClass->fileName() ); TQString ifaceFileName = fileInfo.dirPath( true ) + "/" + m_activeClass->name().lower() + "_interface.h"; if ( TQFile::exists( ifaceFileName ) ) { KMessageBox::error( mainWindow() ->main(), i18n( "File %1 already exists" ).arg( ifaceFileName ), i18n( "C++ Support" ) ); } else { TQString text = extractInterface( m_activeClass ); TQFile f( ifaceFileName ); if ( f.open( IO_WriteOnly ) ) { TQTextStream stream( &f ); stream << "#ifndef __" << m_activeClass->name().upper() << "_INTERFACE_H" << "\n" << "#define __" << m_activeClass->name().upper() << "_INTERFACE_H" << "\n" << "\n" << extractInterface( m_activeClass ) << "\n" << "#endif // __" << m_activeClass->name().upper() << "_INTERFACE_H" << "\n"; f.close(); project() ->addFile( ifaceFileName ); } } m_activeClass = 0; } void CppSupportPart::gotoLine( int line ) { if ( isHeader( m_activeFileName ) ) { KURL url; url.setPath( sourceOrHeaderCandidate() ); partController() ->editDocument( url, line ); } else m_activeViewCursor->setCursorPositionReal( line, 0 ); } FileDom CppSupportPart::fileByName( const TQString& name) { return codeModel()->fileByName( name ); } int CppSupportPart::parseFilesAndDependencies( TQStringList files, bool background, bool parseFirst, bool silent ) { TQMap fileGroups; int nextGroup = 0; for( TQStringList::iterator it = files.begin(); it != files.end(); ++it ) { FileDom d = fileByName( *it ); TQStringList lst; if( !d ) { lst << *it; }else{ lst = codeModel()->getGroupStrings( d->groupId() ); /* kdDebug( 9007 ) << "adding group of: " << *it << ":\n" << " which is " << lst.join("\n") << "\n\n";*/ if( lst.count() > 10 ) { lst = codeModel()->getGroupStrings( d->groupId() ); } } int cgroup = nextGroup; nextGroup++; if( fileGroups.find( *it ) != fileGroups.end() ) cgroup = fileGroups[*it]; for( TQStringList::iterator lit = lst.begin(); lit != lst.end(); ++lit ) fileGroups[*lit] = cgroup; } TQValueVector groups; groups.resize( nextGroup ); ///put the groups together for( TQMap::iterator it = fileGroups.begin(); it != fileGroups.end(); ++it ) { groups[*it] << it.key(); } for( int a = 0; a < nextGroup; a++ ) { TQStringList group = reorder( groups[a] ); /* kdDebug( 9007 ) << "reparsing the following group: " << ":\n" << group.join("\n") << "\n\n";*/ if( background ) { m_backgroundParser->lock(); if( !group.isEmpty() ) { if( !parseFirst ) m_parseEmitWaiting.addGroup( group, silent ? ParseEmitWaiting::Silent : ParseEmitWaiting::None ); else m_parseEmitWaiting.addGroupFront( group, silent ? ParseEmitWaiting::Silent : ParseEmitWaiting::None ); if( !silent ) { if( !parseFirst ) m_fileParsedEmitWaiting.addGroup( group, silent ? ParseEmitWaiting::Silent : ParseEmitWaiting::None ); else m_fileParsedEmitWaiting.addGroupFront( group, silent ? ParseEmitWaiting::Silent : ParseEmitWaiting::None ); } } if( parseFirst && !group.empty() ) { for(TQStringList::iterator it = --group.end(); it != group.end(); ) { backgroundParser()->addFileFront(*it); if( it == group.begin() ) { it = group.end(); } else { --it; } } } else { for(TQStringList::iterator it = group.begin(); it != group.end(); ++it) { backgroundParser()->addFile(*it); } } m_backgroundParser->unlock(); } else { for(TQStringList::iterator it = group.begin(); it != group.end(); ++it) { m_driver->parseFile( *it ); } } } return fileGroups.count(); } int CppSupportPart::parseFileAndDependencies( const TQString & fileName, bool background, bool parseFirst, bool silent ) { if(! isValidSource( fileName ) ) return 0; // kdDebug( 9007 ) << "reparsing dependencies of " << fileName << "\n"; return parseFilesAndDependencies( fileName, background, parseFirst, silent ); } void CppSupportPart::parseEmit( ParseEmitWaiting::Processed files ) { if( files.res.isEmpty() ) return; bool modelHasFiles = true; for( TQStringList::iterator it = files.res.begin(); it != files.res.end(); ++it ) { if( !codeModel()->hasFile( *it ) ) modelHasFiles = false; } int oldFileCount = codeModel()->fileList().count(); if( (files.flag & ParseEmitWaiting::HadErrors) && modelHasFiles && !files.hasFlag( ParseEmitWaiting::Silent ) ) { mainWindow() ->statusBar() ->message( "File parsed, but not updating code-model because of errors", 2000 ); kdDebug( 9007 ) << "not updating code-model because at least one file has errors" << endl; // for( TQStringList::iterator it = files.res.begin(); it != files.res.end(); ++it ) // m_backgroundParser->removeFile( *it ); } else { ///update timestamps for( TQStringList::iterator it = files.res.begin(); it != files.res.end(); ++it ) { if( !codeModel()->hasFile( *it ) ) modelHasFiles = false; TQString& fileName = *it; TQFileInfo fileInfo( fileName ); TQString path = URLUtil::canonicalPath( fileName ); if ( !fileInfo.exists() ) { removeWithReferences( path ); continue ; } m_timestamp[ path ] = fileInfo.lastModified(); } if( files.hasFlag( ParseEmitWaiting::Silent ) && !alwaysParseInBackground ) return; m_backgroundParser->lock(); TQStringList l = files.res; TQMap wholeResult; TQStringList missing; TQMap newFiles; while(!l.isEmpty() ) { TQString fileName = l.front(); if( !m_backgroundParser->hasTranslationUnit( fileName ) ) { kdDebug( 9007 ) << "error: translation-unit is missing: " << fileName << endl; missing << fileName; } else { if ( ParsedFilePointer ast = m_backgroundParser->translationUnit( fileName ) ) { if ( true /*!hasErrors*/ ) { FileDom oldFile = codeModel()->fileByName( fileName ); StoreWalker walker( fileName, codeModel() ); walker.setOverrides( newFiles ); walker.parseTranslationUnit( *ast ); if( oldFile ) { newFiles[fileName] = walker.file(); ///update timestamps TQFileInfo fileInfo( fileName ); TQString path = URLUtil::canonicalPath( fileName ); m_timestamp[ path ] = fileInfo.lastModified(); } else { codeModel() ->addFile( walker.file() ); } if( walker.file() ) { TQStringList grp = walker.file()->wholeGroupStrings(); for( TQStringList::const_iterator it = grp.begin(); it != grp.end(); ++it ) wholeResult[*it] = true; } } } else { kdDebug( 9007 ) << "failed to parse " << fileName << endl; } } l.pop_front(); } bool canUpdate = true; for( TQMap::const_iterator it = newFiles.begin(); it != newFiles.end(); ++it ) { FileDom oldFile = codeModel()->fileByName( it.key() ); if( !oldFile || !oldFile->canUpdate( *it ) ) { canUpdate = false; break; } } if( canUpdate ) { ///Update the code-model for( TQMap::const_iterator it = newFiles.begin(); it != newFiles.end(); ++it ) { FileDom oldFile = codeModel()->fileByName( it.key() ); oldFile->update( *it ); codeModel()->mergeGroups( oldFile->groupId(), (*it)->groupId() ); ///Merge parsing-groups together } } else { ///Remove the current files and replace them with the new ones for( TQMap::const_iterator it = newFiles.begin(); it != newFiles.end(); ++it ) { removeWithReferences( it.key() ); codeModel()->addFile( *it ); } } /* ///make the list unique l.clear(); for( TQMap::const_iterator it = wholeResult.begin(); it != wholeResult.end(); ++it ) l << it.key();*/ m_backgroundParser->unlock(); if( !missing.isEmpty() ) { kdDebug( 9007 ) << "error: translation-units were missing: " << missing << endl; //don't reparse missing units, because it may cause the whole project to be reparsed // parseFilesAndDependencies( missing, true, false, files.hasFlag( ParseEmitWaiting::Silent ) ); } if( files.hasFlag( ParseEmitWaiting::Silent ) ) { if( alwaysParseInBackground ) for( TQStringList::iterator it = files.res.begin(); it != files.res.end(); ++it ) m_backgroundParser->removeFile( *it ); } else { if( !canUpdate ) { ///If the current model could be updated, do not emit addedSourceInfo(..) and remove the units from the parser, because nobody will be using them TQStringList l = files.res; while(!l.isEmpty() ) { emit aboutToRemoveSourceInfo( l.front() ); emit removedSourceInfo( l.front() ); emit addedSourceInfo( l.front() ); l.pop_front(); } if( !files.hasFlag( ParseEmitWaiting::Silent ) ) emitFileParsed( files ); } else { TQStringList l = files.res; while( !l.isEmpty() ) { emit codeModelUpdated( l.front() ); emit aboutToRemoveSourceInfo( l.front() ); emit removedSourceInfo( l.front() ); emit addedSourceInfo( l.front() ); l.pop_front(); } } } kdDebug( 9007 ) << "files in code-model after parseEmit: " << codeModel()->fileList().count() << " before: " << oldFileCount << endl; } } /*void CppSupportPart::recomputeCodeModel( const TQString& fileName ) {*/ //} void CppSupportPart::emitSynchronousParseReady( const TQString& file, ParsedFilePointer unit ) { emit synchronousParseReady( file, unit ); } void CppSupportPart::emitFileParsed( TQStringList l ) { while( !l.isEmpty() ) { emit fileParsed( l.front() ); l.pop_front(); } } bool CppSupportPart::isHeader( const TQString& fileName ) const { /*KMimeType::Ptr ptr = KMimeType::findByPath( fileName ); if ( ptr && m_headerMimeTypes.contains( ptr->name() ) ) return true;*/ return ( m_headerExtensions.findIndex( TQFileInfo( fileName ).extension() ) != -1 ); } bool CppSupportPart::isSource( const TQString& fileName ) const { /*KMimeType::Ptr ptr = KMimeType::findByPath( fileName ); if ( ptr && m_sourceMimeTypes.contains( ptr->name() ) ) return true;*/ return ( m_sourceExtensions.findIndex( TQFileInfo( fileName ).extension() ) != -1 ); } void CppSupportPart::gotoDeclarationLine( int line ) { if ( isHeader( m_activeFileName ) ) m_activeViewCursor->setCursorPositionReal( line, 0 ); else { KURL url; url.setPath( sourceOrHeaderCandidate() ); partController() ->editDocument( url, line ); } } void CppSupportPart::removeCatalog( const TQString & dbName ) { if ( !TQFile::exists( dbName ) ) return ; TQValueList catalogs = codeRepository() ->registeredCatalogs(); Catalog* c = 0; for ( TQValueList::Iterator it = catalogs.begin(); it != catalogs.end(); ++it ) { if ( ( *it ) ->dbName() == dbName ) { c = *it; break; } } if ( c ) { codeRepository() ->unregisterCatalog( c ); m_catalogList.remove( c ); } TQFileInfo fileInfo( dbName ); TQDir dir( fileInfo.dir( true ) ); TQStringList indexList = TQStringList() << "kind" << "name" << "scope" << "fileName" << "prefix"; for(TQStringList::Iterator iter = indexList.begin(); iter != indexList.end(); iter++) { TQStringList fileList = dir.entryList( fileInfo.baseName(true) +"." +(*iter) + ".idx" ); for ( TQStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it ) { TQString idxName = fileInfo.dirPath( true ) + "/" + *it; kdDebug( 9007 ) << "=========> remove db index: " << idxName << endl; dir.remove( *it ); } } dir.remove( fileInfo.fileName() ); } void CppSupportPart::addCatalog( Catalog * catalog ) { m_catalogList.append( catalog ); codeRepository() ->registerCatalog( catalog ); } FunctionDefinitionDom CppSupportPart::functionDefinitionAt( int line, int column ) { if ( !codeModel() ->hasFile( m_activeFileName ) ) return FunctionDefinitionDom(); CodeModelUtils::CodeModelHelper h( codeModel(), codeModel()->fileByName( m_activeFileName ) ); FunctionDom d = h.functionAt( line, column, CodeModelUtils::CodeModelHelper::Definition ); if( d ) { FunctionDefinitionModel* m = dynamic_cast( d.data() ); if( m ) return FunctionDefinitionDom( m ); } return FunctionDefinitionDom(); } FunctionDefinitionDom CppSupportPart::currentFunctionDefinition( ) { if ( !this->m_activeViewCursor ) return FunctionDefinitionDom(); unsigned int line, column; this->m_activeViewCursor->cursorPositionReal( &line, &column ); return functionDefinitionAt( line, column ); } void CppSupportPart::slotCursorPositionChanged() { if ( codeCompletion() ) { unsigned int line = 0; unsigned int column = 0; if ( TDevEditorUtil::currentPositionReal( &line, &column, dynamic_cast( partController()->activePart() ) ) ) { TQString typeInfoString = codeCompletion()->createTypeInfoString( line, column ); mainWindow()->statusBar()->message( typeInfoString ); } } // m_functionHintTimer->changeInterval( 1000 ); if ( splitHeaderSourceConfig()->splitEnabled() && splitHeaderSourceConfig()->autoSync() ) slotSwitchHeader( true ); } /* void CppSupportPart::slotFunctionHint( ) { kdDebug( 9007 ) << "=======> compute current function definition" << endl; // m_functionHintTimer->stop(); if ( FunctionDefinitionDom fun = currentFunctionDefinition() ) { TQStringList scope = fun->scope(); TQString funName = scope.join( "::" ); if ( !funName.isEmpty() ) funName += "::"; funName += formatModelItem( fun, true ); mainWindow() ->statusBar() ->message( funName, 2000 ); } } */ void CppSupportPart::createIgnorePCSFile( ) { static TQCString skip_me( "ignore me\n" ); TQString skip_file_name = project() ->projectDirectory() + "/" + project() ->projectName() + ".tdevelop.ignore_pcs"; TQFile skip_pcs_file( skip_file_name ); if ( skip_pcs_file.open( IO_WriteOnly ) ) { skip_pcs_file.writeBlock( skip_me ); skip_pcs_file.close(); } } TQString CppSupportPart::specialHeaderName( bool local ) const { if ( local ) return ::locateLocal( "data", "kdevcppsupport/configuration", CppSupportFactory::instance() ); return ::locate( "data", "kdevcppsupport/configuration", CppSupportFactory::instance() ); } void CppSupportPart::updateParserConfiguration() { m_backgroundParser->updateParserConfiguration(); TQString conf_file_name = specialHeaderName(); m_driver->removeAllMacrosInFile( conf_file_name ); dynamic_cast(m_driver)->setup(); m_driver->parseFile( conf_file_name, true, true, true ); m_buildSafeFileSetTimer->start( 500, true ); parseProject( true ); } const Driver* CppSupportPart::driver() const { return m_driver; } Driver* CppSupportPart::driver() { return m_driver; } TDevDesignerIntegration * CppSupportPart::designer( KInterfaceDesigner::DesignerType type ) { TDevDesignerIntegration * des = 0; switch ( type ) { case KInterfaceDesigner::Glade: case KInterfaceDesigner::TQtDesigner: des = m_designers[ type ]; if ( des == 0 ) { CppImplementationWidget * impl = new CppImplementationWidget( this ); des = new QtDesignerCppIntegration( this, impl ); des->loadSettings( *project() ->projectDom(), "kdevcppsupport/designerintegration" ); m_designers[ type ] = des; } break; } return des; } void CppSupportPart::resetParserStoreTimer() { // m_deleteParserStoreTimer->start(10000); ///try to empty the store regularly } void CppSupportPart::slotDeleteParserStore() { /* if( !m_backgroundParser->filesInQueue() ) m_backgroundParser->removeAllFiles(); else resetParserStoreTimer();*/ } void CppSupportPart::slotCreateSubclass() { TQFileInfo fi( m_contextFileName ); if ( fi.extension( false ) != "ui" ) return ; QtDesignerCppIntegration *des = dynamic_cast( designer( KInterfaceDesigner::TQtDesigner ) ); if ( des ) des->selectImplementation( m_contextFileName ); } void CppSupportPart::addMethod( ClassDom aClass, const TQString& name, const TQString type, const TQString& parameters, CodeModelItem::Access accessType, bool isConst, bool isInline, bool isVirtual, bool isPureVirtual, const TQString& implementation ) { partController() ->editDocument( KURL( aClass->fileName() ) ); KTextEditor::EditInterface* editIface = dynamic_cast( partController() ->activePart() ); if ( !editIface ) { /// @fixme show messagebox return ; } TQString declarationString = type + " " + name + "(" + parameters + ")" + ( isConst ? " const" : "" ); KDevSourceFormatter* sourceFormatter = extension( "TDevelop/SourceFormatter" ); TQString finalDeclaration = ( ( isVirtual || isPureVirtual ) ? "\nvirtual " : "\n" + declarationString + ( isPureVirtual ? " = 0 " : "" ) + ( isInline ? "\n{\n" + implementation + "\n}\n" : ";" ) ); if ( sourceFormatter != 0 ) finalDeclaration = sourceFormatter->formatSource( finalDeclaration ); TQString indentString = "\t"; if ( sourceFormatter != 0 ) indentString = sourceFormatter->indentString(); editIface->insertText( findInsertionLineMethod( aClass, accessType ), 0, finalDeclaration.replace( "\n", "\n\t" ) + "\n" ); backgroundParser() ->addFile( aClass->fileName() ); if ( isInline || isPureVirtual ) return ; // construct fully qualified name for method definition TQString fullyQualifiedName = aClass->scope().join("::"); if (! fullyQualifiedName.isEmpty()) { fullyQualifiedName += "::"; } fullyQualifiedName += aClass->name() + "::" + name; TQString definitionString = "\n" + type + " " + fullyQualifiedName + "(" + parameters + ")" + ( isConst ? " const" : "" ) + "\n{\n" + implementation + "\n}\n"; if ( sourceFormatter != 0 ) definitionString = sourceFormatter->formatSource( definitionString ); TQFileInfo info( aClass->fileName() ); TQString implementationFile = info.dirPath( true ) + "/" + info.baseName() + ".cpp" ; TQFileInfo fileInfo( implementationFile ); TDevCreateFile* createFileSupport = extension( "TDevelop/CreateFile" ); if ( !TQFile::exists( fileInfo.absFilePath() ) && createFileSupport != 0 ) createFileSupport->createNewFile( fileInfo.extension(), fileInfo.dirPath( true ), fileInfo.baseName() ); partController() ->editDocument( KURL( implementationFile ) ); editIface = dynamic_cast( partController() ->activePart() ); if ( !editIface ) return ; //@fixme errorverdoedelung editIface->insertLine( editIface->numLines(), TQString::fromLatin1( "" ) ); editIface->insertText( editIface->numLines() - 1, 0, definitionString ); backgroundParser() ->addFile( implementationFile ); } ClassDom CppSupportPart::currentClass( ) const { FileDom file = codeModel() ->fileByName( m_activeFileName ); if ( file == 0 || m_activeViewCursor == 0 ) return 0; unsigned int curLine, curCol; m_activeViewCursor->cursorPositionReal( &curLine, &curCol ); CodeModelUtils::CodeModelHelper h( codeModel(), file ); return h.classAt( curLine, curCol ); } VariableDom CppSupportPart::currentAttribute( ClassDom curClass ) const { if ( m_activeViewCursor == 0 || curClass == 0 ) return 0; unsigned int line, col; m_activeViewCursor->cursorPositionReal( &line, &col ); VariableList vars = curClass->variableList(); for ( VariableList::iterator i = vars.begin(); i != vars.end(); ++i ) { int startLine, startCol; ( *i ) ->getStartPosition( &startLine, &startCol ); if ( startLine < (int)line || ( startLine == (int)line && startCol <= (int)col ) ) { int endLine, endCol; ( *i ) ->getEndPosition( &endLine, &endCol ); if ( endLine > (int)line || ( endLine == (int)line && endCol >= (int)col ) ) return * i; } } return 0; } void CppSupportPart::slotCreateAccessMethods( ) { if ( m_curAttribute == 0 || m_curClass == 0 ) return ; CreateGetterSetterDialog dlg ( this, m_curClass, m_curAttribute ); dlg.exec(); } int CppSupportPart::findInsertionLineMethod( ClassDom aClass, CodeModelItem::Access access ) { int line, column; aClass->getEndPosition( &line, &column ); int point = CodeModelUtils::findLastMethodLine( aClass, access ); if ( point == -1 ) { KTextEditor::EditInterface * editIface = dynamic_cast( partController() ->activePart() ); if ( !editIface ) return -1; editIface->insertLine( line - 1, CodeModelUtils::accessSpecifierToString( access ) + ":\n" ); return line; } return point + 1; } int CppSupportPart::findInsertionLineVariable( ClassDom aClass, CodeModelItem::Access access ) { int line, column; aClass->getEndPosition( &line, &column ); int point = CodeModelUtils::findLastVariableLine( aClass, access ); if ( point == -1 ) { KTextEditor::EditInterface * editIface = dynamic_cast( partController() ->activePart() ); if ( !editIface ) return -1; editIface->insertLine( line - 1, CodeModelUtils::accessSpecifierToString( access ) + ":\n" ); return line; } return point; } void CppSupportPart::createAccessMethods( ClassDom theClass, VariableDom theVariable ) { m_curClass = theClass; m_curAttribute = theVariable; slotCreateAccessMethods(); } void CppSupportPart::slotCursorMoved() { m_cursorMovedTimer->start( 250, true ); } void CppSupportPart::slotTextChanged() { setTyping( true ); ///@todo check if this is really needed if ( m_backgroundParserConfig->useBackgroundParser() ) { m_textChangedTimer->start( m_backgroundParserConfig->backgroudParseDelay(), true ); } } void CppSupportPart::slotParseCurrentFile() { if( isValid() && !isQueued( m_activeFileName ) ) { parseFileAndDependencies( m_activeFileName, true, true ); } } void CppSupportPart::updateBackgroundParserConfig() { BackgroundParserConfig config; config.readConfig(); if ( m_backgroundParserConfig->useProblemReporter() && !config.useProblemReporter() ) { removeProblemReporter(); } else if ( !m_backgroundParserConfig->useProblemReporter() && config.useProblemReporter() ) { embedProblemReporter( true ); } *m_backgroundParserConfig = config; } const SynchronizedFileSet& CppSupportPart::safeFileSet() const { return m_safeProjectFiles; } SynchronizedFileSet& CppSupportPart::safeFileSet() { return m_safeProjectFiles; } void CppSupportPart::buildSafeFileSet() { if( codeCompletion() == 0 ) //probably the project has already been closed return; SynchronizedFileSet::SetType files; //everything that goes into this set must be deep-copied kdDebug( 9007 ) << "CppSupportPart:: rebuilding safe-file-set" << endl; for( TQStringList::const_iterator it = m_projectFileList.begin(); it != m_projectFileList.end(); ++it ) { TQFileInfo fi( *it ); TQString file = *it; if( fi.isRelative() ) { fi.setFile( TQDir(m_projectDirectory), *it ); file = fi.absFilePath(); } //deep-copy files.insert( TQString::fromUtf8(file.utf8()) ); } ///Now get all translation-units from the code-repository TQValueList args; args << Catalog::QueryArgument( "kind", Tag::Kind_TranslationUnit ); TQValueList tags( codeCompletion()->repository()->query( args ) ); for( TQValueList::const_iterator it = tags.begin(); it != tags.end(); ++it ) { files.insert( (*it).fileName() + "||" + (*it).attribute("macroValueHash").toString() + "||" + (*it).attribute("macroIdHash").toString() ); } m_safeProjectFiles.setFiles( files ); } void CppSupportPart::addToRepository( ParsedFilePointer file ) { TQString catalogString( "automatic_" + KURL::encode_string_no_slash(m_projectDirectory) ); TDEStandardDirs *dirs = CppSupportFactory::instance() ->dirs(); TQString dbName = dirs->saveLocation( "data", "kdevcppsupport/pcs" ) + catalogString + ".db"; Catalog* catalog = 0; ///First check if the catalog is already there TQValueList catalogs = codeRepository()->registeredCatalogs(); for( TQValueList::const_iterator it = catalogs.begin(); it != catalogs.end(); ++it ) { if( (*it)->dbName() == dbName ) { catalog = *it; break; } } if( !catalog ) { kdDebug( 9007 ) << "creating new catalog named " << catalogString << " for automatic filling" << endl; //TQStringList indexList = TQStringList() << "kind" << "name" << "scope" << "fileName" << "prefix"; catalog = new Catalog; catalog->open( dbName ); catalog->addIndex( "kind" ); catalog->addIndex( "name" ); catalog->addIndex( "scope" ); catalog->addIndex( "prefix" ); catalog->addIndex( "fileName" ); /* for ( TQStringList::Iterator idxIt = indexList.begin(); idxIt != indexList.end(); ++idxIt ) catalog->addIndex( ( *idxIt ).utf8() );*/ addCatalog( catalog ); } catalog->setEnabled( true ); ///Now check if the file was already parsed with the same parameters, if yes don't parse again(auto-update is currently not supported, when major changes have been done in the libraries, the repository should be deleted) TQValueList args; bool compatibleParsed = false; Tag compatibleParsedTag; args << Catalog::QueryArgument( "kind", Tag::Kind_TranslationUnit ); args << Catalog::QueryArgument( "fileName", file->fileName() ); TQValueList tags( catalog->query( args ) ); if( !tags.isEmpty() ) { for( TQValueList::const_iterator it = tags.begin(); it != tags.end(); ++it ) { if( (*it).hasAttribute( "cppparsedfile" ) ) { TQVariant v = (*it).attribute( "cppparsedfile" ); ///@todo reenable this /*TQByteArray b = v.toByteArray(); if( !b.isEmpty() ) { //Would be much more efficient not to do this deserialization ParsedFile f(b); if( f.usedMacros().valueHash() == file->usedMacros().valueHash() && f.usedMacros().idHash() == file->usedMacros().idHash() && f.includeFiles().hash() == file->includeFiles().hash() ) { ///Do not reparse the file, it seems to already be in the repository in a similar state if( (*it).attribute( "includedFrom" ).toString() == file->includedFrom() ) return; ///It is probable that the same state has already been parsed, but there seems to be no such tag yet(the tag will be added) compatibleParsed = true; compatibleParsedTag = *it; break; } }*/ } } } if( compatibleParsed ) { ///Add a Tag that makes sure that the file will not be parsed again compatibleParsedTag.setAttribute( "includedFrom", file->includedFrom() ); TQByteArray data; TQDataStream s( data, IO_WriteOnly ); file->write( s ); compatibleParsedTag.setAttribute( "cppparsedfile", data ); catalog->addItem( compatibleParsedTag ); return; } kdDebug( 9007 ) << "parsing translation-unit " << file->fileName() << " into catalog " << catalogString << endl; TagCreator w( file->fileName(), catalog ); w.parseTranslationUnit( *file ); codeRepository()->touchCatalog( catalog ); m_safeProjectFiles.insert( file->fileName() + "||" + TQString("%1").arg(file->usedMacros().valueHash()) + "||" + TQString("%1").arg(file->usedMacros().idHash()) ); } TQString CppSupportPart::findHeaderSimple( const TQString &header ) { TQStringList::ConstIterator it; for ( it = m_projectFileList.begin(); it != m_projectFileList.end(); ++it ) { TQString s = *it; if (s == header) return s; if ( ( s.right( header.length() ) == header ) && ( s[s.length() - header.length() - 1] == '/' ) ) return s; } return TQString(); } UIBlockTester::UIBlockTesterThread::UIBlockTesterThread( UIBlockTester& parent ) : TQThread(), m_parent( parent ), m_stop(false) { } void UIBlockTester::UIBlockTesterThread::run() { while(!m_stop) { msleep( m_parent.m_msecs / 10 ); m_parent.m_timeMutex.lock(); TQDateTime t = TQDateTime::currentDateTime(); uint msecs = m_parent.m_lastTime.time().msecsTo( t.time() ); if( msecs > m_parent.m_msecs ) { m_parent.lockup(); m_parent.m_lastTime = t; } m_parent.m_timeMutex.unlock(); } } void UIBlockTester::UIBlockTesterThread::stop() { m_stop = true; } UIBlockTester::UIBlockTester( uint milliseconds ) : m_thread( *this ), m_msecs( milliseconds ) { m_timer = new TQTimer( this ); m_timer->start( milliseconds/10 ); connect( m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(timer()) ); timer(); m_thread.start(); } UIBlockTester::~UIBlockTester() { m_thread.stop(); m_thread.wait(); } void UIBlockTester::timer() { m_timeMutex.lock(); m_lastTime = TQDateTime::currentDateTime(); m_timeMutex.unlock(); } void UIBlockTester::lockup() { //std::cout << "UIBlockTester: lockup of the UI for " << m_msecs << endl; ///kdDebug(..) is not thread-safe.. int a = 1; ///Place breakpoint here } #include "cppsupportpart.moc" //kate: indent-mode csands; tab-width 4; space-indent off;