00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
#include "pythonsupportpart.h"
00013
#include "pythonconfigwidget.h"
00014
00015
#include <kdevcore.h>
00016
#include <kdevproject.h>
00017
#include <kdevappfrontend.h>
00018
#include <kdevpartcontroller.h>
00019
#include <codemodel.h>
00020
#include <domutil.h>
00021
00022
#include <qfileinfo.h>
00023
#include <qpopupmenu.h>
00024
#include <qstringlist.h>
00025
#include <qtextstream.h>
00026
#include <qtimer.h>
00027
#include <qvbox.h>
00028
#include <kaction.h>
00029
#include <kapplication.h>
00030
#include <kdebug.h>
00031
#include <kdialogbase.h>
00032
#include <kdevgenericfactory.h>
00033
#include <klineeditdlg.h>
00034
#include <klocale.h>
00035
#include <qregexp.h>
00036
00037
00038 typedef KDevGenericFactory<PythonSupportPart> PythonSupportFactory;
00039
static const KAboutData data(
"kdevpythonsupport",
I18N_NOOP(
"Language"),
"1.0");
00040 K_EXPORT_COMPONENT_FACTORY( libkdevpythonsupport,
PythonSupportFactory( &data ) )
00041
00042
PythonSupportPart::
PythonSupportPart(
QObject *parent, const
char *name, const
QStringList &)
00043 :
KDevLanguageSupport("PythonSupport", "python", parent, name ? name : "
PythonSupportPart")
00044 {
00045 setInstance(PythonSupportFactory::instance());
00046
00047 setXMLFile(
"kdevpythonsupport.rc");
00048
00049 connect( core(), SIGNAL(projectOpened()),
this, SLOT(projectOpened()) );
00050 connect( core(), SIGNAL(projectClosed()),
this, SLOT(projectClosed()) );
00051 connect( partController(), SIGNAL(savedFile(
const QString&)),
00052
this, SLOT(savedFile(
const QString&)) );
00053 connect( core(), SIGNAL(projectConfigWidget(
KDialogBase*)),
00054
this, SLOT(projectConfigWidget(
KDialogBase*)) );
00055
00056
KAction *action;
00057
00058 action =
new KAction( i18n(
"Execute Program"),
"exec", 0,
00059
this, SLOT(slotExecute()),
00060 actionCollection(),
"build_exec" );
00061 action->setToolTip( i18n(
"Execute program") );
00062 action->setWhatsThis(i18n(
"<b>Execute program</b><p>Runs the Python program."));
00063
00064 action =
new KAction( i18n(
"Execute String..."),
"exec", 0,
00065
this, SLOT(slotExecuteString()),
00066 actionCollection(),
"build_execstring" );
00067 action->setToolTip( i18n(
"Execute string") );
00068 action->setWhatsThis(i18n(
"<b>Execute String</b><p>Executes a string as Python code."));
00069
00070 action =
new KAction( i18n(
"Start Python Interpreter"),
"exec", 0,
00071
this, SLOT(slotStartInterpreter()),
00072 actionCollection(),
"build_runinterpreter" );
00073 action->setToolTip( i18n(
"Start python interpreter") );
00074 action->setWhatsThis(i18n(
"<b>Start python interpreter</b><p>Starts the Python interpreter without a program"));
00075
00076 action =
new KAction( i18n(
"Python Documentation..."), 0,
00077
this, SLOT(slotPydoc()),
00078 actionCollection(),
"help_pydoc" );
00079 action->setToolTip( i18n(
"Python documentation") );
00080 action->setWhatsThis(i18n(
"<b>Python documentation</b><p>Shows a Python documentation page."));
00081 }
00082
00083
00084 PythonSupportPart::~PythonSupportPart()
00085 {}
00086
00087
00088 void PythonSupportPart::projectConfigWidget(
KDialogBase *dlg)
00089 {
00090
QVBox *vbox = dlg->
addVBoxPage(i18n(
"Python"));
00091
PythonConfigWidget *w =
new PythonConfigWidget(*
projectDom(), vbox,
"python config widget");
00092 connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) );
00093 }
00094
00095
00096 void PythonSupportPart::projectOpened()
00097 {
00098
kdDebug(9014) <<
"projectOpened()" <<
endl;
00099
00100 connect(
project(), SIGNAL(
addedFilesToProject(
const QStringList &)),
00101
this, SLOT(
addedFilesToProject(
const QStringList &)) );
00102 connect(
project(), SIGNAL(
removedFilesFromProject(
const QStringList &)),
00103
this, SLOT(
removedFilesFromProject(
const QStringList &)) );
00104
00105
00106
00107 QTimer::singleShot(0,
this, SLOT(
initialParse()));
00108 }
00109
00110
00111 void PythonSupportPart::projectClosed()
00112 {
00113 }
00114
00115
00116 void PythonSupportPart::maybeParse(
const QString fileName)
00117 {
00118
QFileInfo fi(fileName);
00119
if (fi.extension() ==
"py") {
00120
00121
if(
codeModel()->
hasFile(fileName) ){
00122 emit aboutToRemoveSourceInfo( fileName );
00123
codeModel()->
removeFile(
codeModel()->fileByName(fileName) );
00124 }
00125
00126
parse( fileName );
00127 }
00128 }
00129
00130
00131 void PythonSupportPart::initialParse()
00132 {
00133
kdDebug(9014) <<
"initialParse()" <<
endl;
00134
00135
if (
project()) {
00136 kapp->setOverrideCursor(waitCursor);
00137
QStringList files =
project()->
allFiles();
00138
for (QStringList::Iterator it = files.begin(); it != files.end() ;++it) {
00139
kdDebug(9014) <<
"maybe parse " <<
project()->
projectDirectory() +
"/" + (*it) <<
endl;
00140
maybeParse(
project()->projectDirectory() +
"/" + *it);
00141 }
00142
00143 emit
updatedSourceInfo();
00144 kapp->restoreOverrideCursor();
00145 }
else {
00146
kdDebug(9014) <<
"No project" <<
endl;
00147 }
00148 }
00149
00150
00151 void PythonSupportPart::addedFilesToProject(
const QStringList &fileList)
00152 {
00153
kdDebug(9014) <<
"addedFilesToProject()" <<
endl;
00154
00155 QStringList::ConstIterator it;
00156
00157
for ( it = fileList.begin(); it != fileList.end(); ++it )
00158 {
00159
QString fileName =
project()->
projectDirectory() +
"/" + ( *it );
00160
maybeParse( fileName );
00161 emit addedSourceInfo( fileName );
00162 }
00163
00164
00165 }
00166
00167
00168 void PythonSupportPart::removedFilesFromProject(
const QStringList &fileList)
00169 {
00170
kdDebug(9014) <<
"removedFilesFromProject()" <<
endl;
00171
00172 QStringList::ConstIterator it;
00173
00174
for ( it = fileList.begin(); it != fileList.end(); ++it )
00175 {
00176
QString fileName =
project()->
projectDirectory() +
"/" + ( *it );
00177
00178
if(
codeModel()->
hasFile(fileName) ){
00179 emit aboutToRemoveSourceInfo( fileName );
00180
codeModel()->
removeFile(
codeModel()->fileByName(fileName) );
00181 }
00182 }
00183
00184
00185 }
00186
00187
00188 void PythonSupportPart::savedFile(
const QString &fileName)
00189 {
00190
kdDebug(9014) <<
"savedFile()" <<
endl;
00191
00192
if (
project()->
allFiles().contains(fileName.mid ( project()->projectDirectory().
length() + 1 ))) {
00193
maybeParse(fileName);
00194 emit addedSourceInfo( fileName );
00195 }
00196 }
00197
00198
00199 KDevLanguageSupport::Features
PythonSupportPart::features()
00200 {
00201
return Features(Classes | Functions);
00202 }
00203
00204
00205 KMimeType::List PythonSupportPart::mimeTypes( )
00206 {
00207
KMimeType::List list;
00208
KMimeType::Ptr mime = KMimeType::mimeType(
"text/x-python" );
00209
if( mime )
00210 list << mime;
00211
00212 mime = KMimeType::mimeType(
"application/x-python" );
00213
if( mime )
00214 list << mime;
00215
00216
return list;
00217 }
00218
00219 void PythonSupportPart::parse(
const QString &fileName)
00220 {
00221
QFile f(QFile::encodeName(fileName));
00222
if (!f.open(IO_ReadOnly))
00223
return;
00224
QTextStream stream(&f);
00225
00226
QRegExp classre(
"^[ \t]*class[ \t]+([A-Za-z0-9_]+)[ \t]*(\\(([A-Za-z0-9_, \t]+)\\))?.*$");
00227
QRegExp methodre(
"^[ \t]*def[ \t]+([A-Za-z0-9_]+).*$");
00228
00229
FileDom m_file =
codeModel()->
create<
FileModel>();
00230 m_file->setName( fileName );
00231
00232
ClassDom lastClass;
00233
QString rawline;
00234
QCString line;
00235
int lineNo = 0;
00236
while (!stream.atEnd()) {
00237 rawline = stream.readLine();
00238 line = rawline.stripWhiteSpace().local8Bit();
00239
if (classre.search(line) != -1) {
00240
00241 lastClass =
codeModel()->
create<
ClassModel>();
00242 lastClass->setName(classre.cap(1));
00243 lastClass->setFileName( fileName );
00244 lastClass->setStartPosition( lineNo, 0 );
00245
00246
QStringList parentList = QStringList::split(
",", classre.cap(3));
00247 QStringList::ConstIterator it;
00248
for (it = parentList.begin(); it != parentList.end(); ++it) {
00249
QString baseName = (*it).stripWhiteSpace();
00250
kdDebug(9014) <<
"Add parent" << baseName <<
endl;
00251 lastClass->addBaseClass( baseName );
00252 }
00253
00254
if (m_file->hasClass(lastClass->name())) {
00255
ClassDom old = m_file->classByName( lastClass->name() )[ 0 ];
00256 old->setFileName( lastClass->fileName() );
00257
00258
int line, col;
00259 lastClass->getStartPosition( &line, &col );
00260 old->setStartPosition( line, col );
00261
00262 lastClass = old;
00263 }
else {
00264
kdDebug(9014) <<
"Add class " << lastClass->name() <<
endl;
00265 m_file->addClass( lastClass );
00266 }
00267
00268 }
else if (methodre.search(line) != -1 ) {
00269
00270
FunctionDom method =
codeModel()->
create<
FunctionModel>();
00271 method->setName(methodre.cap(1));
00272 method->setFileName( fileName );
00273 method->setStartPosition( lineNo, 0 );
00274
00275
if (lastClass && rawline.left(3) !=
"def") {
00276
if( !lastClass->hasFunction(method->name()) )
00277 lastClass->addFunction( method );
00278 }
else if( !m_file->hasFunction(method->name()) ){
00279 m_file->addFunction( method );
00280 lastClass = 0;
00281 }
00282 }
00283 ++lineNo;
00284 }
00285
00286 f.close();
00287
00288
codeModel()->
addFile( m_file );
00289 }
00290
00291
00292 QString PythonSupportPart::interpreter()
00293 {
00294
QString prog = DomUtil::readEntry(*
projectDom(),
"/kdevpythonsupport/run/interpreter");
00295
if (prog.isEmpty())
00296 prog =
"python";
00297
00298
return prog;
00299 }
00300
00301
00302 void PythonSupportPart::startApplication(
const QString &program)
00303 {
00304
bool inTerminal = DomUtil::readBoolEntry(*
projectDom(),
"/kdevpythonsupport/run/terminal");
00305
appFrontend()->
startAppCommand(QString::QString(), program, inTerminal);
00306 }
00307
00308
00309 void PythonSupportPart::slotExecute()
00310 {
00311
QString program =
project()->
mainProgram();
00312
QString cmd =
interpreter() +
" " + program;
00313
startApplication(cmd);
00314 }
00315
00316
00317 void PythonSupportPart::slotStartInterpreter()
00318 {
00319
startApplication(
interpreter());
00320 }
00321
00322
00323 void PythonSupportPart::slotExecuteString()
00324 {
00325
bool ok;
00326
QString cmd = KLineEditDlg::getText(i18n(
"String to execute"), QString::null, &ok, 0);
00327
if (ok) {
00328 cmd.prepend(
"'");
00329 cmd.append(
"'");
00330
startApplication(cmd);
00331 }
00332 }
00333
00334
00335 void PythonSupportPart::slotPydoc()
00336 {
00337
bool ok;
00338
QString key = KLineEditDlg::getText(i18n(
"Show Python documentation on keyword:"),
"", &ok, 0);
00339
if (ok && !key.isEmpty()) {
00340
QString url =
"pydoc:";
00341 url += key;
00342
partController()->
showDocument(
KURL(url));
00343 }
00344 }
00345
00346
#include "pythonsupportpart.moc"