diff options
Diffstat (limited to 'languages/python/pythonsupportpart.cpp')
-rw-r--r-- | languages/python/pythonsupportpart.cpp | 410 |
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 * + * [email protected] * + * * + * 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" |