KDevelop API Documentation

parts/valgrind/valgrind_part.cpp

Go to the documentation of this file.
00001 #include <qwhatsthis.h> 00002 #include <qregexp.h> 00003 #include <qfile.h> 00004 00005 #include <kiconloader.h> 00006 #include <klocale.h> 00007 #include <kdevgenericfactory.h> 00008 #include <kaction.h> 00009 #include <kprocess.h> 00010 #include <kmessagebox.h> 00011 #include <kfiledialog.h> 00012 #include <kdebug.h> 00013 00014 #include "kdevcore.h" 00015 #include "kdevmainwindow.h" 00016 #include "kdevproject.h" 00017 00018 #include "valgrind_widget.h" 00019 #include "valgrind_part.h" 00020 #include "valgrind_dialog.h" 00021 #include "valgrinditem.h" 00022 00023 typedef KDevGenericFactory<ValgrindPart> ValgrindFactory; 00024 static const KAboutData data("kdevvalgrind", "Valgrind", "1.0"); 00025 K_EXPORT_COMPONENT_FACTORY( libkdevvalgrind, ValgrindFactory( &data ) ) 00026 00027 ValgrindPart::ValgrindPart( QObject *parent, const char *name, const QStringList& ) 00028 : KDevPlugin( "Valgrind", "valgrind", parent, name ? name : "ValgrindPart" ) 00029 { 00030 setInstance( ValgrindFactory::instance() ); 00031 setXMLFile( "kdevpart_valgrind.rc" ); 00032 00033 proc = new KShellProcess(); 00034 connect( proc, SIGNAL(receivedStdout( KProcess*, char*, int )), 00035 this, SLOT(receivedStdout( KProcess*, char*, int )) ); 00036 connect( proc, SIGNAL(receivedStderr( KProcess*, char*, int )), 00037 this, SLOT(receivedStderr( KProcess*, char*, int )) ); 00038 connect( proc, SIGNAL(processExited( KProcess* )), 00039 this, SLOT(processExited( KProcess* )) ); 00040 connect( core(), SIGNAL(stopButtonClicked(KDevPlugin*)), 00041 this, SLOT(slotStopButtonClicked(KDevPlugin*)) ); 00042 connect( core(), SIGNAL(projectOpened()), 00043 this, SLOT(projectOpened()) ); 00044 00045 m_widget = new ValgrindWidget( this ); 00046 m_widget->setIcon( SmallIcon("fork") ); 00047 00048 QWhatsThis::add( m_widget, i18n( "<b>Valgrind</b><p>Shows the output of the valgrind. Valgrind detects<br>" 00049 "use of uninitialised memory<br>" 00050 "reading/writing memory after it has been free'd<br>" 00051 "reading/writing off the end of malloc'd blocks<br>" 00052 "reading/writing inappropriate areas on the stack<br>" 00053 "memory leaks -- where pointers to malloc'd blocks are lost forever<br>" 00054 "passing of uninitialised and/or unaddressible memory to system calls<br>" 00055 "mismatched use of malloc/new/new [] vs free/delete/delete []<br>" 00056 "some abuses of the POSIX pthread API." ) ); 00057 00058 KAction* action = new KAction( i18n("&Valgrind Memory Leak Check"), 0, this, 00059 SLOT(slotExecValgrind()), actionCollection(), "tools_valgrind" ); 00060 action->setToolTip(i18n("Valgrind memory leak check")); 00061 action->setWhatsThis(i18n("<b>Valgrind memory leak check</b><p>Runs Valgrind - a tool to help you find memory-management problems in your programs.")); 00062 00063 mainWindow()->embedOutputView( m_widget, "Valgrind", i18n("Valgrind memory leak check") ); 00064 } 00065 00066 00067 ValgrindPart::~ValgrindPart() 00068 { 00069 if ( m_widget ) 00070 mainWindow()->removeView( m_widget ); 00071 delete m_widget; 00072 delete proc; 00073 } 00074 00075 void ValgrindPart::projectOpened() 00076 { 00077 _lastExec.truncate( 0 ); 00078 } 00079 00080 void ValgrindPart::loadOutput() 00081 { 00082 QString fName = KFileDialog::getOpenFileName(QString::null, "*", 0, i18n("Open Valgrind Output")); 00083 if ( fName.isEmpty() ) 00084 return; 00085 00086 QFile f( fName ); 00087 if ( !f.open( IO_ReadOnly ) ) { 00088 KMessageBox::sorry( 0, i18n("Could not open valgrind output: %1").arg(fName) ); 00089 return; 00090 } 00091 00092 clear(); 00093 getActiveFiles(); 00094 00095 QTextStream stream( &f ); 00096 while ( !stream.atEnd() ) { 00097 receivedString( stream.readLine() + "\n" ); 00098 } 00099 f.close(); 00100 } 00101 00102 void ValgrindPart::getActiveFiles() 00103 { 00104 activeFiles.clear(); 00105 if ( project() ) { 00106 QStringList projectFiles = project()->allFiles(); 00107 QString projectDirectory = project()->projectDirectory(); 00108 KURL url; 00109 for ( QStringList::Iterator it = projectFiles.begin(); it != projectFiles.end(); ++it ) { 00110 KURL url( projectDirectory + "/" + (*it) ); 00111 url.cleanPath( true ); 00112 activeFiles += url.path(); 00113 kdDebug() << "set project file: " << url.path().latin1() << endl; 00114 } 00115 } 00116 } 00117 00118 static void guessActiveItem( ValgrindItem& item, const QStringList activeFiles ) 00119 { 00120 if ( activeFiles.isEmpty() && item.backtrace().isEmpty() ) 00121 return; 00122 for ( ValgrindItem::BacktraceList::Iterator it = item.backtrace().begin(); it != item.backtrace().end(); ++it ) { 00123 // active: first line of backtrace that lies in project source file 00124 for ( QStringList::ConstIterator it2 = activeFiles.begin(); it2 != activeFiles.end(); ++it2 ) { 00125 if ( (*it).url() == (*it2) ) { 00126 (*it).setHighlighted( true ); 00127 return; 00128 } 00129 } 00130 } 00131 } 00132 00133 void ValgrindPart::appendMessage( const QString& message ) 00134 { 00135 if ( message.isEmpty() ) 00136 return; 00137 00138 ValgrindItem item( message ); 00139 guessActiveItem( item, activeFiles ); 00140 m_widget->addMessage( item ); 00141 } 00142 00143 void ValgrindPart::slotExecValgrind() 00144 { 00145 ValgrindDialog* dlg = new ValgrindDialog(); 00146 if ( project() && _lastExec.isEmpty() ) { 00147 dlg->setExecutable( project()->mainProgram() ); 00148 } else { 00149 dlg->setExecutable( _lastExec ); 00150 } 00151 dlg->setParameters( _lastParams ); 00152 dlg->setValExecutable( _lastValExec ); 00153 dlg->setValParams( _lastValParams ); 00154 if ( dlg->exec() == QDialog::Accepted ) { 00155 runValgrind( dlg->executableName(), dlg->parameters(), dlg->valExecutable(), dlg->valParams() ); 00156 } 00157 } 00158 00159 void ValgrindPart::slotKillValgrind() 00160 { 00161 if ( proc ) 00162 proc->kill(); 00163 } 00164 00165 void ValgrindPart::slotStopButtonClicked( KDevPlugin* which ) 00166 { 00167 if ( which != 0 && which != this ) 00168 return; 00169 slotKillValgrind(); 00170 } 00171 00172 void ValgrindPart::clear() 00173 { 00174 m_widget->clear(); 00175 currentMessage = QString::null; 00176 currentPid = -1; 00177 lastPiece = QString::null; 00178 } 00179 00180 void ValgrindPart::runValgrind( const QString& exec, const QString& params, const QString& valExec, const QString& valParams ) 00181 { 00182 if ( proc->isRunning() ) { 00183 KMessageBox::sorry( 0, i18n( "There is already an instance of valgrind running." ) ); 00184 return; 00186 } 00187 00188 clear(); 00189 00190 getActiveFiles(); 00191 00192 proc->clearArguments(); 00193 *proc << valExec << valParams << exec << params; 00194 proc->start( KProcess::NotifyOnExit, KProcess::AllOutput ); 00195 mainWindow()->raiseView( m_widget ); 00196 core()->running( this, true ); 00197 00198 _lastExec = exec; 00199 _lastParams = params; 00200 _lastValExec = valExec; 00201 _lastValParams = valParams; 00202 } 00203 00204 void ValgrindPart::receivedStdout( KProcess*, char* /* msg */, int /* len */ ) 00205 { 00206 //kdDebug() << "got StdOut: " <<QString::fromLocal8Bit( msg, len ) << endl; 00207 } 00208 00209 void ValgrindPart::receivedStderr( KProcess*, char* msg, int len ) 00210 { 00211 receivedString( QString::fromLocal8Bit( msg, len ) ); 00212 } 00213 00214 void ValgrindPart::receivedString( const QString& str ) 00215 { 00216 QString rmsg = lastPiece + str; 00217 QStringList lines = QStringList::split( "\n", rmsg ); 00218 00219 // kdDebug() << "got: " << QString::fromLocal8Bit( msg, len ) << endl; 00220 00221 if ( !rmsg.endsWith( "\n" ) ) { 00222 // the last message is trucated, we'll receive 00223 // the rest in the next call 00224 lastPiece = lines.back(); 00225 lines.pop_back(); 00226 } else { 00227 lastPiece = QString::null; 00228 } 00229 appendMessages( lines ); 00230 } 00231 00232 void ValgrindPart::appendMessages( const QStringList& lines ) 00233 { 00234 QRegExp valRe( "==(\\d+)== (.*)" ); 00235 00236 for ( QStringList::ConstIterator it = lines.begin(); it != lines.end(); ++it ) { 00237 if ( valRe.search( *it ) < 0 ) 00238 continue; 00239 00240 int cPid = valRe.cap( 1 ).toInt(); 00241 00242 if ( valRe.cap( 2 ).isEmpty() ) { 00243 appendMessage( currentMessage ); 00244 currentMessage = QString::null; 00245 } else if ( cPid != currentPid ) { 00246 appendMessage( currentMessage ); 00247 currentMessage = *it; 00248 currentPid = cPid; 00249 } else { 00250 if ( !currentMessage.isEmpty() ) 00251 currentMessage += "\n"; 00252 currentMessage += *it; 00253 } 00254 } 00255 } 00256 00257 void ValgrindPart::processExited( KProcess* p ) 00258 { 00259 if ( p == proc ) { 00260 appendMessage( currentMessage + lastPiece ); 00261 currentMessage = QString::null; 00262 lastPiece = QString::null; 00263 core()->running( this, false ); 00264 } 00265 } 00266 00267 void ValgrindPart::restorePartialProjectSession( const QDomElement* el ) 00268 { 00269 QDomElement execElem = el->namedItem( "executable" ).toElement(); 00270 _lastExec = execElem.attribute( "path", "" ); 00271 _lastParams = execElem.attribute( "params", "" ); 00272 00273 QDomElement valElem = el->namedItem( "valgrind" ).toElement(); 00274 _lastValExec = valElem.attribute( "path", "" ); 00275 _lastValParams = valElem.attribute( "params", "" ); 00276 } 00277 00278 void ValgrindPart::savePartialProjectSession( QDomElement* el ) 00279 { 00280 QDomDocument domDoc = el->ownerDocument(); 00281 if ( domDoc.isNull() ) 00282 return; 00283 00284 QDomElement execElem = domDoc.createElement( "executable" ); 00285 execElem.setAttribute( "path", _lastExec ); 00286 execElem.setAttribute( "params", _lastParams ); 00287 00288 QDomElement valElem = domDoc.createElement( "valgrind" ); 00289 valElem.setAttribute( "path", _lastValExec ); 00290 valElem.setAttribute( "params", _lastValParams ); 00291 00292 el->appendChild( execElem ); 00293 el->appendChild( valElem ); 00294 } 00295 00296 #include "valgrind_part.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:13 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003