KDevelop API Documentation

languages/php/phpsupportpart.cpp

Go to the documentation of this file.
00001 /*************************************************************************** 00002 * Copyright (C) 2001 by Sandy Meier * 00003 * smeier@kdevelop.org * 00004 * * 00005 * This program is free software; you can redistribute it and/or modify * 00006 * it under the terms of the GNU General Public License as published by * 00007 * the Free Software Foundation; either version 2 of the License, or * 00008 * (at your option) any later version. * 00009 * * 00010 ***************************************************************************/ 00011 00012 #include "phpsupportpart.h" 00013 00014 #include <iostream> 00015 00016 #include <qdir.h> 00017 #include <qfileinfo.h> 00018 #include <qpopupmenu.h> 00019 #include <qprogressbar.h> 00020 #include <qstringlist.h> 00021 #include <qtextstream.h> 00022 #include <qtimer.h> 00023 #include <qvbox.h> 00024 #include <qwhatsthis.h> 00025 00026 #include <kaction.h> 00027 #include <kapplication.h> 00028 #include <kdebug.h> 00029 #include <khtmlview.h> 00030 #include <klocale.h> 00031 #include <kmessagebox.h> 00032 #include <kprocess.h> 00033 #include <kregexp.h> 00034 #include <kstatusbar.h> 00035 #include <kparts/browserextension.h> 00036 00037 #include <kdevcore.h> 00038 #include <kdevproject.h> 00039 #include <kdevmainwindow.h> 00040 #include <kdevpartcontroller.h> 00041 #include <codemodel.h> 00042 #include <domutil.h> 00043 00044 #include "phpconfigdata.h" 00045 #include "phpconfigwidget.h" 00046 #include "phpconfigparserwidget.h" 00047 #include "phpcodecompletion.h" 00048 #include "phpparser.h" 00049 #include "phpnewclassdlg.h" 00050 00051 00052 #include "phphtmlview.h" 00053 #include "phperrorview.h" 00054 00055 00056 using namespace std; 00057 00058 static const KAboutData data("kdevphpsupport", I18N_NOOP("Language"), "1.0"); 00059 K_EXPORT_COMPONENT_FACTORY( libkdevphpsupport, PHPSupportFactory( &data ) ) 00060 00061 PHPSupportPart::PHPSupportPart(QObject *parent, const char *name, const QStringList &) 00062 : KDevLanguageSupport("PHPSupport", "php", parent, name ? name : "PHPSupportPart") 00063 { 00064 m_htmlView=0; 00065 phpExeProc=0; 00066 setInstance(PHPSupportFactory::instance()); 00067 00068 setXMLFile("kdevphpsupport.rc"); 00069 00070 connect( core(), SIGNAL(projectOpened()), this, SLOT(projectOpened()) ); 00071 connect( core(), SIGNAL(projectClosed()), this, SLOT(projectClosed()) ); 00072 connect( partController(), SIGNAL(savedFile(const QString&)), 00073 this, SLOT(savedFile(const QString&)) ); 00074 connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)), 00075 this, SLOT(projectConfigWidget(KDialogBase*)) ); 00076 00077 KAction *action; 00078 00079 action = new KAction( i18n("&Run"), "exec",Key_F9, 00080 this, SLOT(slotRun()), 00081 actionCollection(), "build_execute" ); 00082 action->setToolTip(i18n("Run")); 00083 action->setWhatsThis(i18n("<b>Run</b><p>Executes script on a terminal or a webserver.")); 00084 00085 action = new KAction( i18n("&New Class..."),0, 00086 this, SLOT(slotNewClass()), 00087 actionCollection(), "project_new_class" ); 00088 action->setToolTip(i18n("New class")); 00089 action->setWhatsThis(i18n("<b>New class</b><p>Runs New Class wizard.")); 00090 00091 m_phpErrorView = new PHPErrorView(this); 00092 QWhatsThis::add(m_phpErrorView, i18n("<b>PHP problems</b><p>This view shows PHP parser warnings, errors, and fatal errors.")); 00093 mainWindow()->embedOutputView(m_phpErrorView, i18n("PHP Problems"), i18n("PHP Problems")); 00094 connect(m_phpErrorView,SIGNAL(fileSelected(const QString&,int)), 00095 this,SLOT(slotErrorMessageSelected(const QString&,int))); 00096 00097 phpExeProc = new KShellProcess("/bin/sh"); 00098 connect(phpExeProc, SIGNAL(receivedStdout (KProcess*, char*, int)), 00099 this, SLOT(slotReceivedPHPExeStdout (KProcess*, char*, int))); 00100 connect(phpExeProc, SIGNAL(receivedStderr (KProcess*, char*, int)), 00101 this, SLOT(slotReceivedPHPExeStderr (KProcess*, char*, int))); 00102 connect(phpExeProc, SIGNAL(processExited(KProcess*)), 00103 this, SLOT(slotPHPExeExited(KProcess*))); 00104 00105 m_htmlView = new PHPHTMLView(); 00106 mainWindow()->embedPartView(m_htmlView->view(), i18n("PHP"), "PHP"); // @fixme after stringfreeze - last argument should be i18n() 00107 connect(m_htmlView, SIGNAL(started(KIO::Job*)), 00108 this, SLOT(slotWebJobStarted(KIO::Job*))); 00109 00110 configData = new PHPConfigData(projectDom()); 00111 connect(configData, SIGNAL(configStored()), 00112 this, SLOT(slotConfigStored())); 00113 00114 m_parser = new PHPParser(core(),codeModel()); 00115 m_codeCompletion = new PHPCodeCompletion(configData, core(),codeModel()); 00116 00117 connect(partController(), SIGNAL(activePartChanged(KParts::Part*)), 00118 this, SLOT(slotActivePartChanged(KParts::Part *))); 00119 } 00120 00121 00122 PHPSupportPart::~PHPSupportPart() 00123 { 00124 delete( m_parser ); 00125 delete( m_codeCompletion ); 00126 delete( configData ); 00127 00128 if( m_htmlView ){ 00129 mainWindow()->removeView( m_htmlView->view() ); 00130 delete( m_htmlView ); 00131 m_htmlView = 0; 00132 } 00133 00134 delete( phpExeProc ); 00135 00136 if(m_phpErrorView){ 00137 mainWindow()->removeView( m_phpErrorView ); 00138 delete( m_phpErrorView ); 00139 m_phpErrorView = 0; 00140 } 00141 } 00142 00143 void PHPSupportPart::slotActivePartChanged(KParts::Part *part){ 00144 kdDebug(9018) << "enter slotActivePartChanged" << endl; 00145 if (!part || !part->widget()) 00146 return; 00147 m_editInterface = dynamic_cast<KTextEditor::EditInterface*>(part); 00148 if(m_editInterface){ // connect to the editor 00149 disconnect(part, 0, this, 0 ); // to make sure that it is't connected twice 00150 if(configData->getRealtimeParsing()){ 00151 connect(part,SIGNAL(textChanged()),this,SLOT(slotTextChanged())); 00152 } 00153 m_codeCompletion->setActiveEditorPart(part); 00154 } 00155 kdDebug(9018) << "exit slotActivePartChanged" << endl; 00156 } 00157 00158 void PHPSupportPart::slotTextChanged(){ 00159 kdDebug(9018) << "enter text changed" << endl; 00160 00161 KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(partController()->activePart()); 00162 if (!ro_part) 00163 return; 00164 00165 QString fileName = ro_part->url().directory() + "/" + ro_part->url().fileName(); 00166 kdDebug(9018) << "filename:" << fileName << endl; 00167 int numLines = m_editInterface->numLines(); 00168 00169 //Abort if the file which was changed is not part of the project 00170 if (!project()->allFiles().contains(fileName.mid ( project()->projectDirectory().length() + 1 ))) { 00171 kdDebug(9018) << "Not Parsing file " << fileName << ", file is not part of the project" << endl; 00172 return; 00173 } 00174 00175 QStringList lines; 00176 for(int i=0;i<numLines;i++){ 00177 lines.append(m_editInterface->textLine(i)); 00178 } 00179 00180 if( codeModel()->hasFile(fileName) ){ 00181 emit aboutToRemoveSourceInfo( fileName ); 00182 codeModel()->removeFile( codeModel()->fileByName(fileName) ); 00183 } 00184 m_parser->parseLines(&lines,fileName); 00185 00186 emit addedSourceInfo( fileName ); 00187 kdDebug(9018) << "exit text changed" << endl; 00188 } 00189 00190 void PHPSupportPart::slotConfigStored(){ 00191 // fake a changing, this will read the configuration again and install the connects 00192 slotActivePartChanged(partController()->activePart()); 00193 } 00194 00195 00196 void PHPSupportPart::slotErrorMessageSelected(const QString& filename,int line){ 00197 kdDebug(9018) << endl << "slotWebResult()" << filename.latin1() << line; 00198 partController()->editDocument(KURL( filename ),line); 00199 } 00200 void PHPSupportPart::projectConfigWidget(KDialogBase *dlg){ 00201 QVBox *vbox = dlg->addVBoxPage(i18n("PHP Settings")); 00202 PHPConfigWidget* w = new PHPConfigWidget(configData,vbox, "php config widget"); 00203 connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) ); 00204 00205 vbox = dlg->addVBoxPage(i18n("PHP Parser")); 00206 PHPConfigParserWidget* wp = new PHPConfigParserWidget(configData,vbox, "php parser config widget"); 00207 connect( dlg, SIGNAL(okClicked()), wp, SLOT(accept()) ); 00208 } 00209 00210 void PHPSupportPart::slotNewClass(){ 00211 QStringList classNames = sortedNameList( codeModel()->globalNamespace()->classList() ); 00212 PHPNewClassDlg dlg(classNames,project()->projectDirectory()); 00213 dlg.exec(); 00214 } 00215 00216 void PHPSupportPart::slotRun(){ 00217 configData = new PHPConfigData(projectDom()); 00218 if(validateConfig()){ 00219 mainWindow()->raiseView(m_phpErrorView); 00220 mainWindow()->raiseView(m_htmlView->view()); 00221 PHPConfigData::InvocationMode mode = configData->getInvocationMode() ; 00222 if(mode == PHPConfigData::Web){ 00223 executeOnWebserver(); 00224 } 00225 else if(mode == PHPConfigData::Shell){ 00226 executeInTerminal(); 00227 } 00228 } 00229 } 00230 00231 bool PHPSupportPart::validateConfig(){ 00232 if(!configData->validateConfig()){ 00233 KMessageBox::information(0,i18n("There is no configuration for executing a PHP file.\nPlease set the correct values in the next dialog.")); 00234 KDialogBase dlg(KDialogBase::TreeList, i18n("Customize PHP Mode"), 00235 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, 0, 00236 "php config dialog"); 00237 00238 QVBox *vbox = dlg.addVBoxPage(i18n("PHP Settings")); 00239 PHPConfigWidget* w = new PHPConfigWidget(configData,vbox, "php config widget"); 00240 connect( &dlg, SIGNAL(okClicked()), w, SLOT(accept()) ); 00241 dlg.exec(); 00242 } 00243 if(configData->validateConfig()){ 00244 return true; 00245 } 00246 return false; 00247 } 00248 00249 void PHPSupportPart::executeOnWebserver(){ 00250 00251 // Save all files once 00252 partController()->saveAllFiles(); 00253 00254 // Figure out the name of the remote file 00255 QString file; 00256 PHPConfigData::WebFileMode mode = configData->getWebFileMode(); 00257 QString weburl = configData->getWebURL(); 00258 if(mode == PHPConfigData::Current){ 00259 KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(partController()->activePart()); 00260 if(ro_part){ 00261 file = QFileInfo(ro_part->url().url()).fileName(); 00262 } 00263 } 00264 if(mode == PHPConfigData::Default){ 00265 file = configData->getWebDefaultFile(); 00266 } 00267 00268 // Force KHTMLPart to reload the page 00269 KParts::BrowserExtension* be = m_htmlView->browserExtension(); 00270 if(be){ 00271 KParts::URLArgs urlArgs( be->urlArgs() ); 00272 urlArgs.reload = true; 00273 be->setURLArgs( urlArgs ); 00274 } 00275 00276 // Acutally do the request 00277 m_phpExeOutput=""; 00278 m_htmlView->openURL(KURL(weburl + file)); 00279 m_htmlView->show(); 00280 } 00281 00282 void PHPSupportPart::slotWebJobStarted(KIO::Job* job){ 00283 if (job && job->className() == QString("KIO::TransferJob")){ 00284 kdDebug(9018) << endl << "job started" << job->progressId(); 00285 KIO::TransferJob *tjob = static_cast<KIO::TransferJob*>(job); 00286 connect(tjob, SIGNAL(data(KIO::Job*, const QByteArray&)), 00287 this, SLOT(slotWebData(KIO::Job*, const QByteArray&))); 00288 connect(tjob, SIGNAL(result(KIO::Job*)), 00289 this, SLOT(slotWebResult(KIO::Job*))); 00290 } 00291 } 00292 00293 void PHPSupportPart::slotWebData(KIO::Job* /*job*/,const QByteArray& data){ 00294 kdDebug(9018) << "slotWebData()" << endl; 00295 QString strData(data); 00296 m_phpExeOutput += strData; 00297 } 00298 00299 void PHPSupportPart::slotWebResult(KIO::Job* /*job*/){ 00300 kdDebug(9018) << "slotWebResult()" << endl; 00301 m_phpErrorView->parse(m_phpExeOutput); 00302 } 00303 00304 void PHPSupportPart::executeInTerminal(){ 00305 kdDebug(9018) << "slotExecuteInTerminal()" << endl; 00306 00307 // Save all files once 00308 partController()->saveAllFiles(); 00309 00310 QString file; 00311 if(m_htmlView==0){ 00312 m_htmlView = new PHPHTMLView(); 00313 mainWindow()->embedPartView(m_htmlView->view(), i18n("PHP")); 00314 } 00315 m_htmlView->show(); 00316 m_htmlView->begin(); 00317 00318 m_phpExeOutput=""; 00319 phpExeProc->clearArguments(); 00320 *phpExeProc << configData->getPHPExecPath(); 00321 *phpExeProc << "-f"; 00322 00323 00324 KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(partController()->activePart()); 00325 if(ro_part){ 00326 file = ro_part->url().path(); 00327 } 00328 00329 *phpExeProc << KShellProcess::quote(file); 00330 kdDebug(9018) << "" << file.latin1() << endl; 00331 phpExeProc->start(KProcess::NotifyOnExit,KProcess::All); 00332 00333 00334 00335 // core()->gotoDocumentationFile(KURL("http://www.php.net")); 00336 } 00337 void PHPSupportPart::slotReceivedPHPExeStdout (KProcess* /*proc*/, char* buffer, int buflen){ 00338 kdDebug(9018) << "slotPHPExeStdout()" << endl; 00339 m_htmlView->write(buffer,buflen+1); 00340 m_phpExeOutput += QString::fromLocal8Bit(buffer,buflen+1); 00341 } 00342 00343 void PHPSupportPart::slotReceivedPHPExeStderr (KProcess* /*proc*/, char* buffer, int buflen){ 00344 kdDebug(9018) << "slotPHPExeStderr()" << endl; 00345 m_htmlView->write(buffer,buflen+1); 00346 m_phpExeOutput += QString::fromLocal8Bit(buffer,buflen+1); 00347 } 00348 00349 void PHPSupportPart::slotPHPExeExited (KProcess* /*proc*/){ 00350 kdDebug(9018) << "slotPHPExeExited()" << endl; 00351 m_htmlView->end(); 00352 m_phpErrorView->parse(m_phpExeOutput); 00353 } 00354 00355 void PHPSupportPart::projectOpened() 00356 { 00357 kdDebug(9018) << "projectOpened()" << endl; 00358 00359 connect( project(), SIGNAL(addedFilesToProject(const QStringList &)), 00360 this, SLOT(addedFilesToProject(const QStringList &)) ); 00361 connect( project(), SIGNAL(removedFilesFromProject(const QStringList &)), 00362 this, SLOT(removedFilesFromProject(const QStringList &)) ); 00363 00364 // We want to parse only after all components have been 00365 // properly initialized 00366 QTimer::singleShot(0, this, SLOT(initialParse())); 00367 } 00368 00369 00370 void PHPSupportPart::projectClosed() 00371 { 00372 } 00373 00374 00375 void PHPSupportPart::maybeParse(const QString fileName) 00376 { 00377 // kdDebug(9007) << "maybeParse()" << endl; 00378 QFileInfo fi(fileName); 00379 QString path = fi.filePath(); 00380 if ((fi.extension().contains("inc") || fi.extension().contains("php") 00381 || fi.extension().contains("html") 00382 || fi.extension().contains("php3")) && !fi.extension().contains("~")) { 00383 kdDebug(9018) << "remove and parse" << fileName.latin1() << endl; 00384 if( codeModel()->hasFile(fileName) ){ 00385 emit aboutToRemoveSourceInfo( fileName ); 00386 codeModel()->removeFile( codeModel()->fileByName(fileName) ); 00387 } 00388 m_parser->parseFile(fileName); 00389 } 00390 } 00391 00392 00393 void PHPSupportPart::initialParse(){ 00394 kdDebug(9018) << "initialParse()" << endl; 00395 00396 if (project()) { 00397 kdDebug(9018) << "project" << endl; 00398 kapp->setOverrideCursor(waitCursor); 00399 QStringList files = project()->allFiles(); 00400 int n = 0; 00401 QProgressBar *bar = new QProgressBar(files.count(), mainWindow()->statusBar()); 00402 bar->setMinimumWidth(120); 00403 bar->setCenterIndicator(true); 00404 mainWindow()->statusBar()->addWidget(bar); 00405 bar->show(); 00406 00407 for (QStringList::Iterator it = files.begin(); it != files.end() ;++it) { 00408 QFileInfo fileInfo( project()->projectDirectory(), *it ); 00409 kdDebug(9018) << "maybe parse " << fileInfo.absFilePath() << endl; 00410 bar->setProgress(n); 00411 kapp->processEvents(); 00412 maybeParse( fileInfo.absFilePath() ); 00413 ++n; 00414 } 00415 mainWindow()->statusBar()->removeWidget(bar); 00416 delete bar; 00417 emit updatedSourceInfo(); 00418 kapp->restoreOverrideCursor(); 00419 } else { 00420 kdDebug(9018) << "No project" << endl; 00421 } 00422 } 00423 00424 00425 void PHPSupportPart::addedFilesToProject(const QStringList &fileList) 00426 { 00427 kdDebug(9018) << "addedFilesToProject()" << endl; 00428 00429 QStringList::ConstIterator it; 00430 00431 for ( it = fileList.begin(); it != fileList.end(); ++it ) 00432 { 00433 QFileInfo fileInfo( project()->projectDirectory(), *it ); 00434 maybeParse( fileInfo.absFilePath() ); 00435 emit addedSourceInfo( fileInfo.absFilePath() ); 00436 } 00437 00438 //emit updatedSourceInfo(); 00439 } 00440 00441 00442 void PHPSupportPart::removedFilesFromProject(const QStringList &fileList) 00443 { 00444 kdDebug(9018) << "removedFilesFromProject()" << endl; 00445 00446 QStringList::ConstIterator it; 00447 00448 for ( it = fileList.begin(); it != fileList.end(); ++it ) 00449 { 00450 QFileInfo fileInfo( project()->projectDirectory(), *it ); 00451 QString path = fileInfo.absFilePath(); 00452 if( codeModel()->hasFile(path) ){ 00453 emit aboutToRemoveSourceInfo( path ); 00454 codeModel()->removeFile( codeModel()->fileByName(path) ); 00455 } 00456 } 00457 00458 //emit updatedSourceInfo(); 00459 } 00460 00461 00462 void PHPSupportPart::savedFile(const QString &fileName) 00463 { 00464 kdDebug(9018) << "savedFile()" << endl; 00465 00466 if (project()->allFiles().contains(fileName.mid ( project()->projectDirectory().length() + 1 ))) { 00467 maybeParse(fileName); 00468 emit addedSourceInfo( fileName ); 00469 } 00470 } 00471 00472 00473 KDevLanguageSupport::Features PHPSupportPart::features() 00474 { 00475 return Features(Classes | Functions); 00476 } 00477 00478 KMimeType::List PHPSupportPart::mimeTypes( ) 00479 { 00480 KMimeType::List list; 00481 KMimeType::Ptr mime = KMimeType::mimeType( "application/x-php" ); 00482 if( mime ) 00483 list << mime; 00484 00485 mime = KMimeType::mimeType( "text/plain" ); 00486 if( mime ) 00487 list << mime; 00488 return list; 00489 } 00490 00491 #include "phpsupportpart.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 Tue Oct 19 08:01:46 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003