00001
00002
00003
00004
00005
00006
00007
00008
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");
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){
00149 disconnect(part, 0,
this, 0 );
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
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
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
00252
partController()->
saveAllFiles();
00253
00254
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
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
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* ,
const QByteArray& data){
00294
kdDebug(9018) <<
"slotWebData()" <<
endl;
00295
QString strData(
data);
00296
m_phpExeOutput += strData;
00297 }
00298
00299 void PHPSupportPart::slotWebResult(
KIO::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
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
00336 }
00337 void PHPSupportPart::slotReceivedPHPExeStdout (
KProcess* ,
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* ,
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* ){
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
00365
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
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
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
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"