summaryrefslogtreecommitdiffstats
path: root/languages/python/pythonsupportpart.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/python/pythonsupportpart.cpp')
-rw-r--r--languages/python/pythonsupportpart.cpp410
1 files changed, 410 insertions, 0 deletions
diff --git a/languages/python/pythonsupportpart.cpp b/languages/python/pythonsupportpart.cpp
new file mode 100644
index 00000000..1b0e76da
--- /dev/null
+++ b/languages/python/pythonsupportpart.cpp
@@ -0,0 +1,410 @@
+/***************************************************************************
+ * Copyright (C) 2001-2002 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "pythonsupportpart.h"
+#include "pythonconfigwidget.h"
+
+#include <kdevcore.h>
+#include <kdevproject.h>
+#include <kdevappfrontend.h>
+#include <kdevpartcontroller.h>
+#include <codemodel.h>
+#include <domutil.h>
+
+#include <qfileinfo.h>
+#include <qpopupmenu.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qvbox.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <kdevgenericfactory.h>
+#include <kdevplugininfo.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <qregexp.h>
+
+#include "qtdesignerpythonintegration.h"
+#include "pythonimplementationwidget.h"
+
+typedef KDevGenericFactory<PythonSupportPart> PythonSupportFactory;
+static const KDevPluginInfo data("kdevpythonsupport");
+K_EXPORT_COMPONENT_FACTORY( libkdevpythonsupport, PythonSupportFactory( data ) )
+
+PythonSupportPart::PythonSupportPart(QObject *parent, const char *name, const QStringList &)
+ : KDevLanguageSupport(&data, parent, name ? name : "PythonSupportPart")
+{
+ setInstance(PythonSupportFactory::instance());
+
+ setXMLFile("kdevpythonsupport.rc");
+
+ connect( core(), SIGNAL(projectOpened()), this, SLOT(projectOpened()) );
+ connect( core(), SIGNAL(projectClosed()), this, SLOT(projectClosed()) );
+ connect( partController(), SIGNAL(savedFile(const KURL&)),
+ this, SLOT(savedFile(const KURL&)) );
+ connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)),
+ this, SLOT(projectConfigWidget(KDialogBase*)) );
+ connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
+ this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
+
+ KAction *action;
+
+ action = new KAction( i18n("Execute Program"), "exec", 0,
+ this, SLOT(slotExecute()),
+ actionCollection(), "build_exec" );
+ action->setToolTip( i18n("Execute program") );
+ action->setWhatsThis(i18n("<b>Execute program</b><p>Runs the Python program."));
+
+ action = new KAction( i18n("Execute String..."), "exec", 0,
+ this, SLOT(slotExecuteString()),
+ actionCollection(), "build_execstring" );
+ action->setToolTip( i18n("Execute string") );
+ action->setWhatsThis(i18n("<b>Execute String</b><p>Executes a string as Python code."));
+
+ action = new KAction( i18n("Start Python Interpreter"), "exec", 0,
+ this, SLOT(slotStartInterpreter()),
+ actionCollection(), "build_runinterpreter" );
+ action->setToolTip( i18n("Start Python interpreter") );
+ action->setWhatsThis(i18n("<b>Start python interpreter</b><p>Starts the Python interpreter without a program"));
+
+ action = new KAction( i18n("Python Documentation..."), 0,
+ this, SLOT(slotPydoc()),
+ actionCollection(), "help_pydoc" );
+ action->setToolTip( i18n("Python documentation") );
+ action->setWhatsThis(i18n("<b>Python documentation</b><p>Shows a Python documentation page."));
+}
+
+
+PythonSupportPart::~PythonSupportPart()
+{}
+
+
+void PythonSupportPart::contextMenu(QPopupMenu *popup, const Context *context)
+{
+ if (context->hasType(Context::FileContext)){
+ const FileContext *fc = static_cast<const FileContext*>(context);
+ //this is a .ui file and only selection contains only one such file
+ KURL url = fc->urls().first();
+ if (url.fileName().endsWith(".ui"))
+ {
+ m_contextFileName = url.fileName();
+ int id = popup->insertItem(i18n("Create or Select Implementation..."), this, SLOT(slotCreateSubclass()));
+ popup->setWhatsThis(id, i18n("<b>Create or select implementation</b><p>Creates or selects a subclass of selected form for use with integrated KDevDesigner."));
+ }
+ }
+}
+
+
+void PythonSupportPart::projectConfigWidget(KDialogBase *dlg)
+{
+ QVBox *vbox = dlg->addVBoxPage(i18n("Python"));
+ PythonConfigWidget *w = new PythonConfigWidget(*projectDom(), vbox, "python config widget");
+ connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) );
+}
+
+
+void PythonSupportPart::projectOpened()
+{
+ kdDebug(9014) << "projectOpened()" << endl;
+
+ connect( project(), SIGNAL(addedFilesToProject(const QStringList &)),
+ this, SLOT(addedFilesToProject(const QStringList &)) );
+ connect( project(), SIGNAL(removedFilesFromProject(const QStringList &)),
+ this, SLOT(removedFilesFromProject(const QStringList &)) );
+
+ // We want to parse only after all components have been
+ // properly initialized
+ QTimer::singleShot(0, this, SLOT(initialParse()));
+}
+
+
+void PythonSupportPart::projectClosed()
+{
+}
+
+
+void PythonSupportPart::maybeParse(const QString fileName)
+{
+ QFileInfo fi(fileName);
+ if (fi.extension() == "py") {
+
+ if( codeModel()->hasFile(fileName) ){
+ emit aboutToRemoveSourceInfo( fileName );
+ codeModel()->removeFile( codeModel()->fileByName(fileName) );
+ }
+
+ parse( fileName );
+ }
+}
+
+
+void PythonSupportPart::initialParse()
+{
+ kdDebug(9014) << "initialParse()" << endl;
+
+ if (project()) {
+ kapp->setOverrideCursor(waitCursor);
+ QStringList files = project()->allFiles();
+ for (QStringList::Iterator it = files.begin(); it != files.end() ;++it) {
+ kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + (*it) << endl;
+ maybeParse(project()->projectDirectory() + "/" + *it);
+ }
+
+ emit updatedSourceInfo();
+ kapp->restoreOverrideCursor();
+ } else {
+ kdDebug(9014) << "No project" << endl;
+ }
+}
+
+
+void PythonSupportPart::addedFilesToProject(const QStringList &fileList)
+{
+ kdDebug(9014) << "addedFilesToProject()" << endl;
+
+ QStringList::ConstIterator it;
+
+ for ( it = fileList.begin(); it != fileList.end(); ++it )
+ {
+ QString fileName = project()->projectDirectory() + "/" + ( *it );
+ maybeParse( fileName );
+ emit addedSourceInfo( fileName );
+ }
+
+ //emit updatedSourceInfo();
+}
+
+
+void PythonSupportPart::removedFilesFromProject(const QStringList &fileList)
+{
+ kdDebug(9014) << "removedFilesFromProject()" << endl;
+
+ QStringList::ConstIterator it;
+
+ for ( it = fileList.begin(); it != fileList.end(); ++it )
+ {
+ QString fileName = project()->projectDirectory() + "/" + ( *it );
+
+ if( codeModel()->hasFile(fileName) ){
+ emit aboutToRemoveSourceInfo( fileName );
+ codeModel()->removeFile( codeModel()->fileByName(fileName) );
+ }
+ }
+
+ //emit updatedSourceInfo();
+}
+
+
+void PythonSupportPart::savedFile(const KURL &fileName)
+{
+ kdDebug(9014) << "savedFile()" << endl;
+
+ if (project()->allFiles().contains(fileName.path().mid ( project()->projectDirectory().length() + 1 ))) {
+ maybeParse(fileName.path());
+ emit addedSourceInfo( fileName.path() );
+ }
+}
+
+
+KDevLanguageSupport::Features PythonSupportPart::features()
+{
+ return Features(Classes | Functions);
+}
+
+
+KMimeType::List PythonSupportPart::mimeTypes( )
+{
+ KMimeType::List list;
+ KMimeType::Ptr mime = KMimeType::mimeType( "text/x-python" );
+ if( mime )
+ list << mime;
+
+ mime = KMimeType::mimeType( "application/x-python" );
+ if( mime )
+ list << mime;
+
+ return list;
+}
+
+void PythonSupportPart::parse(const QString &fileName)
+{
+ QFile f(QFile::encodeName(fileName));
+ if (!f.open(IO_ReadOnly))
+ return;
+ QTextStream stream(&f);
+
+ QRegExp classre("^[ \t]*class[ \t]+([A-Za-z0-9_]+)[ \t]*(\\(([A-Za-z0-9_, \t]+)\\))?.*$");
+ QRegExp methodre("^[ \t]*def[ \t]+([A-Za-z0-9_]+).*$");
+
+ FileDom m_file = codeModel()->create<FileModel>();
+ m_file->setName( fileName );
+
+ ClassDom lastClass;
+ QString rawline;
+ QCString line;
+ int lineNo = 0;
+ while (!stream.atEnd()) {
+ rawline = stream.readLine();
+ line = rawline.stripWhiteSpace().local8Bit();
+ if (classre.search(line) != -1) {
+
+ lastClass = codeModel()->create<ClassModel>();
+ lastClass->setName(classre.cap(1));
+ lastClass->setFileName( fileName );
+ lastClass->setStartPosition( lineNo, 0 );
+
+ QStringList parentList = QStringList::split(",", classre.cap(3));
+ QStringList::ConstIterator it;
+ for (it = parentList.begin(); it != parentList.end(); ++it) {
+ QString baseName = (*it).stripWhiteSpace();
+ kdDebug(9014) << "Add parent" << baseName << endl;
+ lastClass->addBaseClass( baseName );
+ }
+
+ if (m_file->hasClass(lastClass->name())) {
+ ClassDom old = m_file->classByName( lastClass->name() )[ 0 ];
+ old->setFileName( lastClass->fileName() );
+
+ int line, col;
+ lastClass->getStartPosition( &line, &col );
+ old->setStartPosition( line, col );
+
+ lastClass = old;
+ } else {
+ kdDebug(9014) << "Add class " << lastClass->name() << endl;
+ m_file->addClass( lastClass );
+ }
+
+ } else if (methodre.search(line) != -1 ) {
+
+ FunctionDom method = codeModel()->create<FunctionModel>();
+ method->setName(methodre.cap(1));
+ method->setFileName( fileName );
+ method->setStartPosition( lineNo, 0 );
+
+ if (lastClass && rawline.left(3) != "def") {
+ if( !lastClass->hasFunction(method->name()) )
+ lastClass->addFunction( method );
+ QStringList scope;
+ scope << lastClass->name();
+ method->setScope( scope );
+
+ } else if( !m_file->hasFunction(method->name()) ){
+ m_file->addFunction( method );
+ lastClass = 0;
+ }
+ }
+ ++lineNo;
+ }
+
+ f.close();
+
+ codeModel()->addFile( m_file );
+}
+
+
+QString PythonSupportPart::interpreter()
+{
+ QString prog = DomUtil::readEntry(*projectDom(), "/kdevpythonsupport/run/interpreter");
+ if (prog.isEmpty())
+ prog = "python";
+
+ return prog;
+}
+
+
+void PythonSupportPart::startApplication(const QString &program)
+{
+ bool inTerminal = DomUtil::readBoolEntry(*projectDom(), "/kdevpythonsupport/run/terminal");
+ if (KDevAppFrontend *appFrontend = extension<KDevAppFrontend>("KDevelop/AppFrontend"))
+ appFrontend->startAppCommand(QString::QString(), program, inTerminal);
+}
+
+
+void PythonSupportPart::slotExecute()
+{
+ QString program = project()->mainProgram();
+ QString cmd = interpreter() + " " + program;
+ startApplication(cmd);
+}
+
+
+void PythonSupportPart::slotStartInterpreter()
+{
+ startApplication(interpreter());
+}
+
+
+void PythonSupportPart::slotExecuteString()
+{
+ bool ok;
+ QString cmd = KInputDialog::getText(i18n("String to Execute"), i18n("String to execute:"), QString::null, &ok, 0);
+ if (ok) {
+ cmd.prepend("'");
+ cmd.append("'");
+ startApplication(cmd);
+ }
+}
+
+
+void PythonSupportPart::slotPydoc()
+{
+ bool ok;
+ QString key = KInputDialog::getText(i18n("Show Python Documentation"), i18n("Show Python documentation on keyword:"), "", &ok, 0);
+ if (ok && !key.isEmpty()) {
+ QString url = "pydoc:";
+ url += key;
+ partController()->showDocument(KURL(url));
+ }
+}
+
+KDevDesignerIntegration *PythonSupportPart::designer(KInterfaceDesigner::DesignerType type)
+{
+ KDevDesignerIntegration *des = 0;
+ switch (type)
+ {
+ case KInterfaceDesigner::QtDesigner:
+ des = m_designers[type];
+ if (des == 0)
+ {
+ PythonImplementationWidget *impl = new PythonImplementationWidget(this);
+ des = new QtDesignerPythonIntegration(this, impl);
+ des->loadSettings(*project()->projectDom(),
+ "kdevpythonsupport/designerintegration");
+ m_designers[type] = des;
+ }
+ break;
+ case KInterfaceDesigner::Glade:
+ break;
+ }
+ return des;
+
+}
+
+void PythonSupportPart::slotCreateSubclass()
+{
+ QFileInfo fi(m_contextFileName);
+ kdDebug(9014) << k_funcinfo << " file: " << m_contextFileName << " ext: " << fi.extension(false) << endl;
+ if (fi.extension(false) != "ui")
+ return;
+ QtDesignerPythonIntegration *des = dynamic_cast<QtDesignerPythonIntegration*>(designer(KInterfaceDesigner::QtDesigner));
+ if (des)
+ {
+ kdDebug(9014) << "ok: " << des << endl;
+ kdDebug(9014) << "have impl: " << des->selectImplementation(m_contextFileName);
+ }
+ kdDebug(9014) << "end: " << des << endl;
+}
+
+#include "pythonsupportpart.moc"