You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/languages/cpp/cppsupportpart.cpp

3187 lines
100 KiB

/***************************************************************************
* 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 "KDevCppSupportIface.h"
#include "cppsupportfactory.h"
#include "catalog.h"
#include "cpp_tags.h"
#include "kdevdriver.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 "kdevsourceformatter.h"
#include "kdevcreatefile.h"
#include "qtbuildconfig.h"
#include "kdeveditorutil.h"
#include <tdetexteditor/viewcursorinterface.h>
#include <tdepopupmenu.h>
// wizards
#include "cppnewclassdlg.h"
#include "subclassingdlg.h"
#include "addmethoddialog.h"
#include "addattributedialog.h"
#include "creategettersetterdialog.h"
// designer integration
#include "tqtdesignercppintegration.h"
#include "cppimplementationwidget.h"
#include "configproblemreporter.h"
#include "codeinformationrepository.h"
#include <tqeventloop.h>
#include <tqheader.h>
#include <tqdir.h>
#include <tqdom.h>
#include <tqfileinfo.h>
#include <tqguardedptr.h>
#include <tqpopupmenu.h>
#include <tqprogressdialog.h>
#include <tqstringlist.h>
#include <tqtimer.h>
#include <tqstatusbar.h>
#include <tqprogressbar.h>
#include <tqregexp.h>
#include <tqlabel.h>
#include <tqvbox.h>
#include <tdemessagebox.h>
#include <tdeaction.h>
#include <tdeapplication.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <kgenericfactory.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <tdemainwindow.h>
#include <kstatusbar.h>
#include <tdeconfig.h>
#include <tdeversion.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <tdetexteditor/document.h>
#include <tdetexteditor/editinterface.h>
#include <tdetexteditor/view.h>
#include <tdetexteditor/selectioninterface.h>
#include <tdetexteditor/viewcursorinterface.h>
#include <tdetexteditor/clipboardinterface.h>
#include <tdetexteditor/texthintinterface.h>
#include <kdevcore.h>
#include <kdevproject.h>
#include <kdevmainwindow.h>
#include <kdevpartcontroller.h>
#include <kdevmakefrontend.h>
#include <kdevcoderepository.h>
#include <codemodel_utils.h>
#include <kdevplugininfo.h>
#include <domutil.h>
#include <config.h>
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 KDevDriver
{
public:
CppDriver( CppSupportPart* cppSupport ) : KDevDriver( 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<Problem> pl = problems( fileName.fileName() );
TQValueList<Problem>::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 )
: KDevLanguageSupport( CppSupportFactory::info(), parent, name ? name : "KDevCppSupport" ), 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( "kdevcppsupport.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( "<b>Switch Header/Implementation</b><p>"
"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( "<b>Complete Text</p><p>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( "<b>Make member</b><p>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( "<b>Navigate</b><p>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( "<b>New Class</b><p>Calls the <b>New Class</b> 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 KDevCppSupportIface( 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<Catalog> 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<Problem> problems = event->problems();
TQValueList<Problem>::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( "text-x-c++src", 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<KTextEditor::Document*>( part );
m_activeView = part ? dynamic_cast<KTextEditor::View*>( part->widget() ) : 0;
m_activeEditor = dynamic_cast<KTextEditor::EditInterface*>( part );
m_activeSelection = dynamic_cast<KTextEditor::SelectionInterface*>( part );
m_activeViewCursor = dynamic_cast<KTextEditor::ViewCursorInterface*>( 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<KTextEditor::TextHintInterface*>( 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( "application-vnd.tde.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<Catalog*> catalogs = codeRepository() ->registeredCatalogs();
for ( TQValueList<Catalog*>::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<KInterfaceDesigner::DesignerType, KDevDesignerIntegration*>::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( "<b>Make member</b><p>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( "<b>Go to declaration</b><p>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( "<b>Go to definition</b><p>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<const EditorContext*>( context );
TQString str = econtext->currentLine();
if ( str.isEmpty() )
return ;
}
else if ( context->hasType( Context::CodeModelItemContext ) )
{
const CodeModelItemContext * mcontext = static_cast<const CodeModelItemContext*>( 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( "<b>Extract interface</b><p>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<const FileContext*>( 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( "<b>Create or select implementation</b><p>Creates or selects a subclass of selected form for use with integrated KDevDesigner." ) );
}
}
}
TQStringList makeListUnique( const TQStringList& rhs ) {
TQMap<TQString, bool> 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<KTextEditor::Document*>( 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( &currentline, &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<ItemDom>(decl), scrollOnly );
handled = true;
}
}
} else {
FunctionDom def = findFunctionDefinition( d );
if ( def ) {
if ( def != d && ( !scrollOnly || def->fileName() != file ) ) {
jumpToCodeModelItem( model_cast<ItemDom>(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<NamespaceImportModel>& 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<NamespaceImportModel>::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<ParsedFile*>( 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<NamespaceImportModel>& 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<ParsedFile*>( 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<ParsedFile*>( (*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<ParsedFile*>( (*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<KTextEditor::ViewCursorInterface*>(part->widget());
if( iface )
iface->cursorPosition( (uint*) &currentLine, (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;
}
KDevLanguageSupport::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()
+ ".kdevelop.pcs" ).exists())
{
TQDir d( project() ->projectDirectory());
d.rename(project() ->projectName().lower() + ".kdevelop.pcs",
project() ->projectName() +".kdevelop.pcs");
}
_jd->file.setName( project() ->projectDirectory() + "/" + project()->projectName()
+ ".kdevelop.pcs" );
TQString skip_file_name = project() ->projectDirectory() + "/" +
project() ->projectName() + ".kdevelop.ignore_pcs";
TQString skip_lower_file_name = project() ->projectDirectory() + "/" +
project() ->projectName().lower() + ".kdevelop.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<FileModel>();
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()
+ ".kdevelop.ignore_pcs" );
TQFile::remove( project() ->projectDirectory()
+ "/" + project() ->projectName().lower()
+ ".kdevelop.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<TQString, TQDateTime>::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<AST> l = declarator->exceptionSpecification() ->nodeList();
TQPtrListIterator<AST> 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<KTextEditor::Document*>( 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<TQString, TQDateTime>::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<KParts::Part> parts( *partController() ->parts() );
TQPtrListIterator<KParts::Part> it( parts );
while ( KParts::Part * part = it.current() )
{
KTextEditor::Document * doc = dynamic_cast<KTextEditor::Document*>( 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<Tag> tagInfo( tag );
return tagInfo.name() + "( " + tagInfo.arguments().join( ", " ) + " ) : " + tagInfo.type();
}
break;
case Tag::Kind_Variable:
case Tag::Kind_VariableDeclaration:
{
CppVariable<Tag> tagInfo( tag );
return tagInfo.name() + " : " + tagInfo.type();
}
break;
}
return tag.name();
}
void CppSupportPart::codeCompletionConfigStored( )
{
if ( m_projectClosing ) return;
updateParserConfiguration();
/*
m_backgroundParser->updateParserConfiguration();
KDevDriver* d = dynamic_cast<KDevDriver*>( 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<const FunctionModel*>( 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<const VariableModel*>( item );
if ( shortDescription )
return model->name();
return model->type() + " " + model->name();
}
else if ( item->isArgument() )
{
const ArgumentModel * model = static_cast<const ArgumentModel*>( 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 KDevLanguageSupport::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() + ".kdevelop.pcs" );
if ( !f.open( IO_WriteOnly ) )
return ;
m_backgroundParser->lock();
createIgnorePCSFile();
TQDataStream stream( &f );
TQMap<TQString, uint> 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() + ".kdevelop.ignore_pcs" );
TQFile::remove( project() ->projectDirectory() + "/"
+ project() ->projectName().lower() + ".kdevelop.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<TQString, int> 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<TQStringList> groups;
groups.resize( nextGroup );
///put the groups together
for( TQMap<TQString, int>::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<TQString, bool> wholeResult;
TQStringList missing;
TQMap<TQString, FileDom> 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<TQString, FileDom>::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<TQString, FileDom>::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<TQString, FileDom>::const_iterator it = newFiles.begin(); it != newFiles.end(); ++it ) {
removeWithReferences( it.key() );
codeModel()->addFile( *it );
}
}
/*
///make the list unique
l.clear();
for( TQMap<TQString, bool>::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<Catalog*> catalogs = codeRepository() ->registeredCatalogs();
Catalog* c = 0;
for ( TQValueList<Catalog*>::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<FunctionDefinitionModel*>( 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 ( KDevEditorUtil::currentPositionReal( &line, &column, dynamic_cast<KTextEditor::Document*>( 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() + ".kdevelop.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<KDevDriver*>(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;
}
KDevDesignerIntegration * CppSupportPart::designer( KInterfaceDesigner::DesignerType type )
{
KDevDesignerIntegration * 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<QtDesignerCppIntegration*>( 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<KTextEditor::EditInterface*>( partController() ->activePart() );
if ( !editIface )
{
/// @fixme show messagebox
return ;
}
TQString declarationString = type + " " + name + "(" + parameters + ")" + ( isConst ? " const" : "" );
KDevSourceFormatter* sourceFormatter = extension<KDevSourceFormatter>( "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 );
KDevCreateFile* createFileSupport = extension<KDevCreateFile>( "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<KTextEditor::EditInterface*>( 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<KTextEditor::EditInterface*>( 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<KTextEditor::EditInterface*>( 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<Catalog::QueryArgument> args;
args << Catalog::QueryArgument( "kind", Tag::Kind_TranslationUnit );
TQValueList<Tag> tags( codeCompletion()->repository()->query( args ) );
for( TQValueList<Tag>::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<Catalog*> catalogs = codeRepository()->registeredCatalogs();
for( TQValueList<Catalog*>::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<Catalog::QueryArgument> args;
bool compatibleParsed = false;
Tag compatibleParsedTag;
args << Catalog::QueryArgument( "kind", Tag::Kind_TranslationUnit );
args << Catalog::QueryArgument( "fileName", file->fileName() );
TQValueList<Tag> tags( catalog->query( args ) );
if( !tags.isEmpty() ) {
for( TQValueList<Tag>::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;