KDevelop API Documentation

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 KURL&)),
00073              this, SLOT(savedFile(const KURL&)) );
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(this);
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       //Seems, that removeView already frees the pointer, so we don't need to free it here
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(this);
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 KURL &fileName)
00463 {
00464     kdDebug(9018) << "savedFile()" << endl;
00465 
00466     if (project()->allFiles().contains(fileName.path().mid ( project()->projectDirectory().length() + 1 ))) {
00467         maybeParse(fileName.path());
00468         emit addedSourceInfo( fileName.path() );
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.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:33 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003