/*************************************************************************** * Copyright (C) 2001-2002 by Bernd Gehrmann * * bernd@tdevelop.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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qtdesignerpythonintegration.h" #include "pythonimplementationwidget.h" typedef KDevGenericFactory PythonSupportFactory; static const KDevPluginInfo data("kdevpythonsupport"); K_EXPORT_COMPONENT_FACTORY( libkdevpythonsupport, PythonSupportFactory( data ) ) PythonSupportPart::PythonSupportPart(TQObject *parent, const char *name, const TQStringList &) : KDevLanguageSupport(&data, parent, name ? name : "PythonSupportPart") { setInstance(PythonSupportFactory::instance()); setXMLFile("kdevpythonsupport.rc"); connect( core(), TQT_SIGNAL(projectOpened()), this, TQT_SLOT(projectOpened()) ); connect( core(), TQT_SIGNAL(projectClosed()), this, TQT_SLOT(projectClosed()) ); connect( partController(), TQT_SIGNAL(savedFile(const KURL&)), this, TQT_SLOT(savedFile(const KURL&)) ); connect( core(), TQT_SIGNAL(projectConfigWidget(KDialogBase*)), this, TQT_SLOT(projectConfigWidget(KDialogBase*)) ); connect( core(), TQT_SIGNAL(contextMenu(TQPopupMenu *, const Context *)), this, TQT_SLOT(contextMenu(TQPopupMenu *, const Context *)) ); TDEAction *action; action = new TDEAction( i18n("Execute Program"), "exec", 0, this, TQT_SLOT(slotExecute()), actionCollection(), "build_exec" ); action->setToolTip( i18n("Execute program") ); action->setWhatsThis(i18n("Execute program

Runs the Python program.")); action = new TDEAction( i18n("Execute String..."), "exec", 0, this, TQT_SLOT(slotExecuteString()), actionCollection(), "build_execstring" ); action->setToolTip( i18n("Execute string") ); action->setWhatsThis(i18n("Execute String

Executes a string as Python code.")); action = new TDEAction( i18n("Start Python Interpreter"), "exec", 0, this, TQT_SLOT(slotStartInterpreter()), actionCollection(), "build_runinterpreter" ); action->setToolTip( i18n("Start Python interpreter") ); action->setWhatsThis(i18n("Start python interpreter

Starts the Python interpreter without a program")); action = new TDEAction( i18n("Python Documentation..."), 0, this, TQT_SLOT(slotPydoc()), actionCollection(), "help_pydoc" ); action->setToolTip( i18n("Python documentation") ); action->setWhatsThis(i18n("Python documentation

Shows a Python documentation page.")); } PythonSupportPart::~PythonSupportPart() {} void PythonSupportPart::contextMenu(TQPopupMenu *popup, const Context *context) { if (context->hasType(Context::FileContext)){ const FileContext *fc = static_cast(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, TQT_SLOT(slotCreateSubclass())); popup->setWhatsThis(id, i18n("Create or select implementation

Creates or selects a subclass of selected form for use with integrated KDevDesigner.")); } } } void PythonSupportPart::projectConfigWidget(KDialogBase *dlg) { TQVBox *vbox = dlg->addVBoxPage(i18n("Python")); PythonConfigWidget *w = new PythonConfigWidget(*projectDom(), vbox, "python config widget"); connect( dlg, TQT_SIGNAL(okClicked()), w, TQT_SLOT(accept()) ); } void PythonSupportPart::projectOpened() { kdDebug(9014) << "projectOpened()" << endl; connect( project(), TQT_SIGNAL(addedFilesToProject(const TQStringList &)), this, TQT_SLOT(addedFilesToProject(const TQStringList &)) ); connect( project(), TQT_SIGNAL(removedFilesFromProject(const TQStringList &)), this, TQT_SLOT(removedFilesFromProject(const TQStringList &)) ); // We want to parse only after all components have been // properly initialized TQTimer::singleShot(0, this, TQT_SLOT(initialParse())); } void PythonSupportPart::projectClosed() { } void PythonSupportPart::maybeParse(const TQString fileName) { TQFileInfo 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); TQStringList files = project()->allFiles(); for (TQStringList::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 TQStringList &fileList) { kdDebug(9014) << "addedFilesToProject()" << endl; TQStringList::ConstIterator it; for ( it = fileList.begin(); it != fileList.end(); ++it ) { TQString fileName = project()->projectDirectory() + "/" + ( *it ); maybeParse( fileName ); emit addedSourceInfo( fileName ); } //emit updatedSourceInfo(); } void PythonSupportPart::removedFilesFromProject(const TQStringList &fileList) { kdDebug(9014) << "removedFilesFromProject()" << endl; TQStringList::ConstIterator it; for ( it = fileList.begin(); it != fileList.end(); ++it ) { TQString 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 TQString &fileName) { TQFile f(TQFile::encodeName(fileName)); if (!f.open(IO_ReadOnly)) return; TQTextStream stream(&f); TQRegExp classre("^[ \t]*class[ \t]+([A-Za-z0-9_]+)[ \t]*(\\(([A-Za-z0-9_, \t]+)\\))?.*$"); TQRegExp methodre("^[ \t]*def[ \t]+([A-Za-z0-9_]+).*$"); FileDom m_file = codeModel()->create(); m_file->setName( fileName ); ClassDom lastClass; TQString rawline; TQCString line; int lineNo = 0; while (!stream.atEnd()) { rawline = stream.readLine(); line = rawline.stripWhiteSpace().local8Bit(); if (classre.search(line) != -1) { lastClass = codeModel()->create(); lastClass->setName(classre.cap(1)); lastClass->setFileName( fileName ); lastClass->setStartPosition( lineNo, 0 ); TQStringList parentList = TQStringList::split(",", classre.cap(3)); TQStringList::ConstIterator it; for (it = parentList.begin(); it != parentList.end(); ++it) { TQString 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(); 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 ); TQStringList 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 ); } TQString PythonSupportPart::interpreter() { TQString prog = DomUtil::readEntry(*projectDom(), "/kdevpythonsupport/run/interpreter"); if (prog.isEmpty()) prog = "python"; return prog; } void PythonSupportPart::startApplication(const TQString &program) { bool inTerminal = DomUtil::readBoolEntry(*projectDom(), "/kdevpythonsupport/run/terminal"); if (KDevAppFrontend *appFrontend = extension("TDevelop/AppFrontend")) appFrontend->startAppCommand(TQString(), program, inTerminal); } void PythonSupportPart::slotExecute() { TQString program = project()->mainProgram(); TQString cmd = interpreter() + " " + program; startApplication(cmd); } void PythonSupportPart::slotStartInterpreter() { startApplication(interpreter()); } void PythonSupportPart::slotExecuteString() { bool ok; TQString cmd = KInputDialog::getText(i18n("String to Execute"), i18n("String to execute:"), TQString(), &ok, 0); if (ok) { cmd.prepend("'"); cmd.append("'"); startApplication(cmd); } } void PythonSupportPart::slotPydoc() { bool ok; TQString key = KInputDialog::getText(i18n("Show Python Documentation"), i18n("Show Python documentation on keyword:"), "", &ok, 0); if (ok && !key.isEmpty()) { TQString url = "pydoc:"; url += key; partController()->showDocument(KURL(url)); } } KDevDesignerIntegration *PythonSupportPart::designer(KInterfaceDesigner::DesignerType type) { KDevDesignerIntegration *des = 0; switch (type) { case KInterfaceDesigner::TQtDesigner: 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() { TQFileInfo 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(designer(KInterfaceDesigner::TQtDesigner)); if (des) { kdDebug(9014) << "ok: " << des << endl; kdDebug(9014) << "have impl: " << des->selectImplementation(m_contextFileName); } kdDebug(9014) << "end: " << des << endl; } #include "pythonsupportpart.moc"