00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00370 m_cppSupport->partController()->editDocument( url, line-1 );
00371
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"