KDevelop API Documentation

problemreporter.cpp

Go to the documentation of this file.
00001 /*
00002    Copyright (C) 2002 by Roberto Raggi <roberto@kdevelop.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    version 2, License as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00016    Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "problemreporter.h"
00020 #include "cppsupportpart.h"
00021 #include "configproblemreporter.h"
00022 #include "backgroundparser.h"
00023 
00024 #include <kdevpartcontroller.h>
00025 #include <kdevmainwindow.h>
00026 #include <kdevproject.h>
00027 
00028 #include <kdeversion.h>
00029 #include <kparts/part.h>
00030 #include <ktexteditor/editinterface.h>
00031 #include <ktexteditor/document.h>
00032 #include <ktexteditor/markinterface.h>
00033 
00034 #if (KDE_VERSION > 305)
00035 # include <ktexteditor/markinterfaceextension.h>
00036 #else
00037 # include "kde30x_markinterfaceextension.h"
00038 #endif
00039 #include <ktexteditor/view.h>
00040 
00041 #include <kdebug.h>
00042 #include <klocale.h>
00043 #include <kstatusbar.h>
00044 #include <kurl.h>
00045 #include <kapplication.h>
00046 #include <kiconloader.h>
00047 #include <kdialogbase.h>
00048 #include <kurl.h>
00049 
00050 #include <kconfig.h>
00051 
00052 #include <qtimer.h>
00053 #include <qregexp.h>
00054 #include <qvbox.h>
00055 #include <qfileinfo.h>
00056 #include <qwhatsthis.h>
00057 #include <qtabbar.h>
00058 #include <qwidgetstack.h>
00059 #include <qlayout.h>
00060 #include <qlineedit.h>
00061 
00062 class ProblemItem: public KListViewItem
00063 {
00064 public:
00065     ProblemItem( QListView* parent, const QString& problem,
00066          const QString& file, const QString& line, const QString& column  )
00067     : KListViewItem( parent, problem, file, line, column ) {}
00068 
00069     ProblemItem( QListViewItem* parent, const QString& problem,
00070          const QString& file, const QString& line, const QString& column  )
00071     : KListViewItem( parent,  problem, file, line, column ) {}
00072 
00073     int compare( QListViewItem* item, int column, bool ascending ) const {
00074     if( column == 2 || column == 3 ){
00075         int a = text( column ).toInt();
00076         int b = item->text( column ).toInt();
00077         if( a == b )
00078         return 0;
00079         return( a > b ? 1 : -1 );
00080     }
00081     return KListViewItem::compare( item, column, ascending );
00082     }
00083 
00084 };
00085 
00086 ProblemReporter::ProblemReporter( CppSupportPart* part, QWidget* parent, const char* name )
00087     : QWidget( parent, name ? name : "problemreporter" ),
00088       m_cppSupport( part ),
00089       m_document( 0 ),
00090       m_markIface( 0 )
00091 {
00092     QWhatsThis::add(this, i18n("<b>Problem reporter</b><p>This window shows various \"problems\" in your project. "
00093         "It displays TODO entries, FIXME's and errors reported by a language parser. "
00094         "To add a TODO or FIXME entry, just type<br>"
00095         "<tt>//@todo my todo</tt><br>"
00096         "<tt>//TODO: my todo</tt><br>"
00097         "<tt>//FIXME fix this</tt>"));
00098 
00099     m_canParseFile = true;
00100     
00101     m_gridLayout = new QGridLayout(this,2,3);
00102     
00103     m_errorList = new KListView(this);
00104     m_fixmeList = new KListView(this);
00105     m_todoList = new KListView(this);
00106     m_filteredList = new KListView(this);  
00107     m_currentList = new KListView(this);  
00108           
00109     m_filteredList->addColumn( i18n("Level") );    
00110     m_currentList->addColumn( i18n("Level") );
00111         
00112     //addColumn( i18n("Level") );
00113     InitListView(m_errorList);
00114     InitListView(m_fixmeList);
00115     InitListView(m_todoList);  
00116     InitListView(m_filteredList);
00117     InitListView(m_currentList);
00118     m_currentList->removeColumn(1);      
00119     
00120     m_widgetStack = new QWidgetStack(this);
00121     m_widgetStack->addWidget(m_currentList,0);      
00122     m_widgetStack->addWidget(m_errorList,1);    
00123     m_widgetStack->addWidget(m_fixmeList,2);    
00124     m_widgetStack->addWidget(m_todoList,3);        
00125     m_widgetStack->addWidget(m_filteredList,4);       
00126     
00127     m_tabBar = new QTabBar(this);
00128     m_tabBar->insertTab(new QTab(i18n("Current")),0);    
00129     m_tabBar->insertTab(new QTab(i18n("Errors")),1);
00130     m_tabBar->insertTab(new QTab(i18n("Fixme")),2);
00131     m_tabBar->insertTab(new QTab(i18n("Todo")),3);
00132     m_tabBar->insertTab(new QTab(i18n("Filtered")),4);
00133     m_tabBar->setTabEnabled(0,false);       
00134     m_tabBar->setTabEnabled(4,false);
00135     
00136     m_timer = new QTimer( this );
00137     
00138     m_filterEdit = new QLineEdit(this);
00139     
00140     QLabel* m_filterLabel = new QLabel(i18n("Lookup:"),this);
00141     
00142     m_gridLayout->addWidget(m_tabBar,0,0);
00143     m_gridLayout->addMultiCellWidget(m_widgetStack,1,1,0,2);
00144     m_gridLayout->addWidget(m_filterLabel,0,1,Qt::AlignRight); 
00145     m_gridLayout->addWidget(m_filterEdit,0,2,Qt::AlignLeft);     
00146 
00147     connect( m_filterEdit, SIGNAL(returnPressed()),
00148              this, SLOT(slotFilter()) );    
00149     connect( m_filterEdit, SIGNAL(textChanged( const QString & )),
00150              this, SLOT(slotFilter()) );             
00151     connect( m_tabBar, SIGNAL(selected(int)),
00152              this, SLOT(slotTabSelected(int)) );    
00153     connect( part->partController(), SIGNAL(activePartChanged(KParts::Part*)),
00154              this, SLOT(slotActivePartChanged(KParts::Part*)) );
00155     connect( part->partController(), SIGNAL(partAdded(KParts::Part*)),
00156              this, SLOT(slotPartAdded(KParts::Part*)) );
00157     connect( part->partController(), SIGNAL(partRemoved(KParts::Part*)),
00158              this, SLOT(slotPartRemoved(KParts::Part*)) );
00159 
00160     connect( part, SIGNAL(fileParsed(const QString&)), this, SLOT(slotFileParsed(const QString&)) );
00161 
00162     connect( m_timer, SIGNAL(timeout()), this, SLOT(reparse()) );
00163 
00164     connect( part->partController(), SIGNAL(closedFile(const KURL&)),
00165              this, SLOT(closedFile(const KURL&)) );    
00166     
00167     configure();
00168 
00169     slotActivePartChanged( part->partController()->activePart() );
00170 }
00171 
00172 void ProblemReporter::slotFilter()
00173 {
00174     if(!m_tabBar->isTabEnabled(4))
00175       m_tabBar->setTabEnabled(4,true);
00176 
00177     m_tabBar->tab(4)->setText(i18n("Filtered")+": " + m_filterEdit->text());
00178     m_tabBar->setCurrentTab(4);
00179     
00180     m_filteredList->clear();
00181 
00182     filterList(m_errorList,QString(i18n("Error")));
00183     filterList(m_fixmeList,QString(i18n("Fixme")));
00184     filterList(m_todoList,QString(i18n("Todo")));            
00185 
00186 }
00187 
00188 void ProblemReporter::filterList(KListView* listview, const QString& level)
00189 {
00190     QListViewItemIterator it( listview );
00191     while ( it.current() ) {
00192         if ( it.current()->text(3).contains(m_filterEdit->text(),false))
00193         new KListViewItem(m_filteredList,level,
00194         it.current()->text(0),it.current()->text(1),it.current()->text(2),it.current()->text(3));
00195         ++it;
00196     }
00197 }
00198 
00199 void ProblemReporter::slotTabSelected( int tabindex )
00200 {
00201     m_widgetStack->raiseWidget(tabindex);
00202 }
00203 
00204 void ProblemReporter::InitListView(KListView* listview)
00205 {
00206     listview->addColumn( i18n("File") );
00207     listview->addColumn( i18n("Line") );
00208     listview->addColumn( i18n("Column") );
00209     listview->addColumn( i18n("Problem") );
00210     listview->setAllColumnsShowFocus( TRUE );
00211     
00212     connect( listview, SIGNAL(executed(QListViewItem*)),
00213              this, SLOT(slotSelected(QListViewItem*)) );
00214 
00215     connect( listview, SIGNAL(returnPressed(QListViewItem*)),
00216              this, SLOT(slotSelected(QListViewItem* )) );
00217            
00218 }
00219 
00220 ProblemReporter::~ProblemReporter()
00221 {
00222 }
00223 
00224 void ProblemReporter::slotActivePartChanged( KParts::Part* part )
00225 {
00226     if( !part )
00227     {
00228         m_tabBar->setTabEnabled(0,false);           
00229     return; 
00230     }
00231     
00232     m_timer->stop();
00233 
00234     if( m_document )
00235     disconnect( m_document, 0, this, 0 );
00236 
00237     m_document = dynamic_cast<KTextEditor::Document*>( part );
00238     m_markIface = 0;
00239 
00240     if( !m_document )
00241      {
00242         m_tabBar->setTabEnabled(0,false);   
00243         return;
00244      }
00245 
00246     m_fileName = m_document->url().path();
00247 
00248     initCurrentList();
00249 
00250     if( !m_cppSupport->isValidSource(m_fileName) )
00251         return;
00252     
00253     connect( m_document, SIGNAL(textChanged()), this, SLOT(slotTextChanged()) );
00254     m_markIface = dynamic_cast<KTextEditor::MarkInterface*>( part );
00255 
00256     if( !m_cppSupport->backgroundParser() )
00257         return;
00258 
00259     m_cppSupport->backgroundParser()->lock();
00260     bool needReparse = false;
00261     if( !m_cppSupport->backgroundParser()->translationUnit(m_fileName) )
00262         needReparse = true;
00263     m_cppSupport->backgroundParser()->unlock();
00264 
00265     if( needReparse )
00266         reparse();
00267 }
00268 
00269 void ProblemReporter::closedFile(const KURL &fileName)
00270 {
00271    QValueList<Problem> problems = m_cppSupport->backgroundParser()->problems( fileName.path() , true , true);
00272 }
00273 
00274 void ProblemReporter::slotTextChanged()
00275 {
00276     if( !m_active )
00277         return;
00278 
00279     m_timer->changeInterval( m_delay );
00280 }
00281 
00282 void ProblemReporter::removeAllItems( QListView* listview, const QString& filename )
00283 {
00284     QListViewItem* current = listview->firstChild();
00285     while( current ){
00286     QListViewItem* i = current;
00287     current = current->nextSibling();
00288 
00289     if( i->text(0) == filename )
00290         delete( i );
00291     }
00292 }
00293 
00294 void ProblemReporter::removeAllProblems( const QString& filename )
00295 {
00296   QString relFileName = filename;
00297   relFileName.remove(m_cppSupport->project()->projectDirectory());
00298 
00299     kdDebug(9008) << "ProblemReporter::removeAllProblems()" << relFileName << endl;
00300   
00301   removeAllItems(m_errorList,relFileName);
00302   removeAllItems(m_fixmeList,relFileName);
00303   removeAllItems(m_todoList,relFileName);
00304 
00305     if( m_document && m_markIface ){
00306     QPtrList<KTextEditor::Mark> marks = m_markIface->marks();
00307     QPtrListIterator<KTextEditor::Mark> it( marks );
00308     while( it.current() ){
00309         m_markIface->removeMark( it.current()->line, KTextEditor::MarkInterface::markType07 );
00310         ++it;
00311     }
00312     }
00313 }
00314 
00315 void ProblemReporter::reparse()
00316 {
00317     m_timer->stop();
00318 
00319     if( !m_cppSupport->isValid() )
00320     return;
00321 
00322     m_currentList->clear();
00323     
00324     if( m_canParseFile ){
00325         m_cppSupport->backgroundParser()->addFile( m_fileName );
00326         m_canParseFile = false;
00327         kdDebug(9007) << "---> file added" << endl;
00328     }
00329 }
00330 
00331 void ProblemReporter::initCurrentList()
00332 {
00333     m_tabBar->setTabEnabled(0,true);
00334     
00335     QString relFileName = m_fileName;
00336     relFileName.remove(m_cppSupport->project()->projectDirectory());
00337     
00338     m_currentList->clear();         
00339     
00340     updateCurrentWith(m_errorList, QString(i18n("Error")),relFileName);
00341     updateCurrentWith(m_fixmeList,QString(i18n("Fixme")),relFileName);
00342     updateCurrentWith(m_todoList,QString(i18n("Todo")),relFileName);
00343     
00344     m_tabBar->setCurrentTab(0);
00345 }
00346 
00347 void ProblemReporter::updateCurrentWith(QListView* listview, const QString& level, const QString& filename)
00348 {
00349     QListViewItemIterator it(listview);
00350     while ( it.current() ) {
00351         if( it.current()->text(0) == filename)
00352     new QListViewItem(m_currentList,level,it.current()->text(1),it.current()->text(2),it.current()->text(3));   
00353         ++it;
00354     }
00355 }
00356 
00357 void ProblemReporter::slotSelected( QListViewItem* item )
00358 {
00359     bool is_filtered = false;
00360     bool is_current = false;
00361     if(item->listView() == m_filteredList)
00362       is_filtered = true;
00363     else if(item->listView() == m_currentList)
00364       is_current = true;
00365 
00366 
00367     KURL url( is_current ? m_fileName : m_cppSupport->project()->projectDirectory() + item->text(0 + is_filtered) );
00368     int line = item->text( 1 + is_filtered).toInt();
00369     // int column = item->text( 3 ).toInt();
00370     m_cppSupport->partController()->editDocument( url, line-1 );
00371 //    m_cppSupport->mainWindow()->lowerView( this );
00372 }
00373 
00374 void ProblemReporter::reportProblem( const QString& fileName, const Problem& p )
00375 {
00376     int markType = levelToMarkType( p.level() );
00377     if( markType != -1 && m_document && m_markIface && m_fileName == fileName ){
00378     m_markIface->addMark( p.line(), markType );
00379     }
00380 
00381     QString msg = p.text();
00382     msg = msg.replace( QRegExp("\n"), "" );
00383 
00384     QString relFileName = fileName;
00385     relFileName.remove(m_cppSupport->project()->projectDirectory());
00386     
00387     KListView* list;
00388     
00389     switch( p.level() )
00390     {
00391     case Problem::Level_Error:
00392     list = m_errorList;
00393     break;
00394     case Problem::Level_Warning:
00395     list = m_errorList;
00396     break;
00397     case Problem::Level_Todo:
00398     list = m_todoList;
00399     break;
00400     case Problem::Level_Fixme:
00401     list = m_fixmeList;
00402     break;
00403     default:
00404         list = NULL;
00405     }
00406     
00407     if(list)
00408     new ProblemItem( list,
00409              relFileName,
00410              QString::number( p.line() + 1 ),
00411              QString::number( p.column() + 1 ),
00412              msg );
00413     
00414     if(fileName == m_fileName)
00415     new QListViewItem(m_currentList,levelToString(p.level()),
00416              QString::number( p.line() + 1 ),
00417              QString::number( p.column() + 1 ),
00418              msg);  
00419 }
00420 
00421 void ProblemReporter::configure()
00422 {
00423     kdDebug(9007) << "ProblemReporter::configure()" << endl;
00424     KConfig* config = kapp->config();
00425     config->setGroup( "General Options" );
00426     m_active = config->readBoolEntry( "EnableCppBgParser", TRUE );
00427     m_delay = config->readNumEntry( "BgParserDelay", 250 );
00428 }
00429 
00430 void ProblemReporter::configWidget( KDialogBase* dlg )
00431 {
00432     QVBox *vbox = dlg->addVBoxPage(i18n("C++ Parsing"), i18n("C++ Parsing"), BarIcon( "source_cpp", KIcon::SizeMedium) );
00433     ConfigureProblemReporter* w = new ConfigureProblemReporter( vbox );
00434     w->setPart( m_cppSupport );
00435     connect(dlg, SIGNAL(okClicked()), w, SLOT(accept()));
00436     connect(dlg, SIGNAL(okClicked()), this, SLOT(configure()));
00437 }
00438 
00439 void ProblemReporter::slotPartAdded( KParts::Part* part )
00440 {
00441     KTextEditor::MarkInterfaceExtension* iface = dynamic_cast<KTextEditor::MarkInterfaceExtension*>( part );
00442 
00443     if( !iface )
00444     return;
00445 
00446     iface->setPixmap( KTextEditor::MarkInterface::markType07, SmallIcon("stop") );
00447 }
00448 
00449 void ProblemReporter::slotPartRemoved( KParts::Part* part )
00450 {
00451     kdDebug(9007) << "ProblemReporter::slotPartRemoved()" << endl;
00452     if( part == m_document ){
00453     m_document = 0;
00454     m_timer->stop();
00455     }
00456 }
00457 
00458 QString ProblemReporter::levelToString( int level ) const
00459 {
00460     switch( level )
00461     {
00462     case Problem::Level_Error:
00463     return QString( i18n("Error") );
00464     case Problem::Level_Warning:
00465     return QString( i18n("Warning") );
00466     case Problem::Level_Todo:
00467     return QString( i18n("Todo") );
00468     case Problem::Level_Fixme:
00469     return QString( i18n("Fixme") );
00470     default:
00471         return QString::null;
00472     }
00473 }
00474 
00475 int ProblemReporter::levelToMarkType( int level ) const
00476 {
00477     switch( level )
00478     {
00479     case Problem::Level_Error:
00480     return KTextEditor::MarkInterface::markType07;
00481     case Problem::Level_Warning:
00482         return -1;
00483     case Problem::Level_Todo:
00484         return -1;
00485     case Problem::Level_Fixme:
00486         return -1;
00487     default:
00488         return -1;
00489     }
00490 }
00491 
00492 void ProblemReporter::slotFileParsed( const QString& fileName )
00493 {
00494     if( m_active && fileName == m_fileName ){
00495         m_canParseFile = true;
00496     }
00497 }
00498 
00499 #include "problemreporter.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:28 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003