[QGIS Commit] r8530 - in trunk/qgis/src: . app python

svn_qgis at osgeo.org svn_qgis at osgeo.org
Wed May 28 08:35:20 EDT 2008


Author: wonder
Date: 2008-05-28 08:35:20 -0400 (Wed, 28 May 2008)
New Revision: 8530

Added:
   trunk/qgis/src/python/
   trunk/qgis/src/python/CMakeLists.txt
   trunk/qgis/src/python/qgispython.cpp
   trunk/qgis/src/python/qgspythonutils.h
   trunk/qgis/src/python/qgspythonutilsimpl.cpp
   trunk/qgis/src/python/qgspythonutilsimpl.h
Removed:
   trunk/qgis/src/app/qgspythonutils.cpp
   trunk/qgis/src/app/qgspythonutils.h
   trunk/qgis/src/app/qgspythonutilsimpl.h
Modified:
   trunk/qgis/src/CMakeLists.txt
   trunk/qgis/src/app/CMakeLists.txt
   trunk/qgis/src/app/qgisapp.cpp
Log:
Moved python support to a library, QGIS app now during the initialization tries to load that library.


Modified: trunk/qgis/src/CMakeLists.txt
===================================================================
--- trunk/qgis/src/CMakeLists.txt	2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/CMakeLists.txt	2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,6 +1,10 @@
 
 SUBDIRS(core ui gui app providers plugins helpviewer)
 
+IF (HAVE_PYTHON AND WITH_BINDINGS)
+  SUBDIRS(python)
+ENDIF (HAVE_PYTHON AND WITH_BINDINGS)
+
 IF (APPLE)
   SUBDIRS(mac)
 ENDIF(APPLE)

Modified: trunk/qgis/src/app/CMakeLists.txt
===================================================================
--- trunk/qgis/src/app/CMakeLists.txt	2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/CMakeLists.txt	2008-05-28 12:35:20 UTC (rev 8530)
@@ -153,10 +153,6 @@
     )
 ENDIF (POSTGRES_FOUND)
 
-# Python support
-IF (PYTHON_FOUND)
-  SET (QGIS_APP_SRCS ${QGIS_APP_SRCS} qgspythonutils.cpp)
-ENDIF (PYTHON_FOUND)
 
 QT4_WRAP_CPP(QGIS_APP_MOC_SRCS ${QGIS_APP_MOC_HDRS})
 
@@ -198,6 +194,7 @@
   ../core/raster ../core/renderer ../core/symbology
   ../gui
   ../plugins
+  ../python
   ${PROJ_INCLUDE_DIR}
   ${SQLITE3_INCLUDE_DIR}
   ${GEOS_INCLUDE_DIR}
@@ -208,10 +205,6 @@
   INCLUDE_DIRECTORIES(${POSTGRES_INCLUDE_DIR})
 ENDIF (POSTGRES_FOUND)
 
-IF (PYTHON_FOUND)
-  INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
-ENDIF (PYTHON_FOUND)
-
 #############
 
 IF (WIN32)
@@ -250,10 +243,6 @@
   INSTALL_RPATH_USE_LINK_PATH true
   )
 
-IF (PYTHON_FOUND)
-  TARGET_LINK_LIBRARIES(qgis ${PYTHON_LIBRARIES})
-ENDIF (PYTHON_FOUND)
-
 IF (POSTGRES_FOUND)
   TARGET_LINK_LIBRARIES (qgis ${POSTGRES_LIBRARY})
 ENDIF (POSTGRES_FOUND)

Modified: trunk/qgis/src/app/qgisapp.cpp
===================================================================
--- trunk/qgis/src/app/qgisapp.cpp	2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgisapp.cpp	2008-05-28 12:35:20 UTC (rev 8530)
@@ -169,9 +169,6 @@
 
 #include "qgspythondialog.h"
 #include "qgspythonutils.h"
-#ifdef HAVE_PYTHON
-#include "qgspythonutilsimpl.h"
-#endif
 
 #ifndef WIN32
 #include <dlfcn.h>
@@ -360,17 +357,44 @@
   qApp->processEvents();
   QgsApplication::initQgis();
   
-#ifdef HAVE_PYTHON
   mSplash->showMessage(tr("Starting Python"), Qt::AlignHCenter | Qt::AlignBottom);
   qApp->processEvents();
+
+  // try to load python support
+  QLibrary pythonlib("qgispython");
+  // It's necessary to set these two load hints, otherwise Python library won't work correctly
+  // see http://lists.kde.org/?l=pykde&m=117190116820758&w=2
+  pythonlib.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);
+  if (pythonlib.load())
+  {
+    QgsDebugMsg("Python support library loaded successfully.");
+    typedef QgsPythonUtils* (*inst)();
+    inst pythonlib_inst = (inst) pythonlib.resolve("instance");
+    if (pythonlib_inst)
+    {
+      QgsDebugMsg("Python support library's instance() symbol resolved.");
+      mPythonUtils = pythonlib_inst();
+      mPythonUtils->initPython(mQgisInterface);
+    }
+    else
+    {
+      QgsDebugMsg("Couldn't resolve python support library's instance() symbol.");
+    }
+  }
+  else
+  {
+    QgsDebugMsg("Couldn't load Python support library.");
+  }
   
-  mPythonUtils = QgsPythonUtilsImpl::instance();
-  
-  mPythonUtils->initPython(mQgisInterface);
-#endif
-
-  if (!mPythonUtils || !mPythonUtils->isEnabled())
+  if (mPythonUtils && mPythonUtils->isEnabled())
+  {
+    QgsDebugMsg("Python support ENABLED :-)");
+  }
+  else
+  {
     mActionShowPythonDialog->setEnabled(false);
+    QgsDebugMsg("Python support DISABLED :-(");
+  }
 
   // Create the plugin registry and load plugins
   // load any plugins that were running in the last session

Deleted: trunk/qgis/src/app/qgspythonutils.cpp
===================================================================
--- trunk/qgis/src/app/qgspythonutils.cpp	2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgspythonutils.cpp	2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,515 +0,0 @@
-/***************************************************************************
-    qgspythonutils.cpp - routines for interfacing Python
-    ---------------------
-    begin                : October 2006
-    copyright            : (C) 2006 by Martin Dobias
-    email                : wonder.sk at gmail dot com
- ***************************************************************************
- *                                                                         *
- *   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.                                   *
- *                                                                         *
- ***************************************************************************/
-/* $Id$ */
-
-// python should be first include
-// otherwise issues some warnings
-#include <Python.h>
-
-#include "qgspythonutilsimpl.h"
-
-#include "qgsapplication.h"
-#include "qgslogger.h"
-#include "qgsmessageoutput.h"
-
-#include <QMessageBox>
-#include <QStringList>
-#include <QDir>
-
-QgsPythonUtilsImpl* QgsPythonUtilsImpl::mInstance = NULL;
-
-QgsPythonUtilsImpl::QgsPythonUtilsImpl()
-{
-  mMainModule = NULL;
-  mMainDict = NULL;
-  mPythonEnabled = false;
-}
-
-QgsPythonUtilsImpl::~QgsPythonUtilsImpl()
-{
-}
-
-QgsPythonUtilsImpl* QgsPythonUtilsImpl::instance()
-{
-  if (mInstance == NULL)
-    mInstance = new QgsPythonUtilsImpl();
-  return mInstance;
-}
-
-
-void QgsPythonUtilsImpl::initPython(QgisInterface* interface)
-{
-  // initialize python
-  Py_Initialize();
-  
-  mPythonEnabled = true;
-  
-  mMainModule = PyImport_AddModule("__main__"); // borrowed reference
-  mMainDict = PyModule_GetDict(mMainModule); // borrowed reference
-  
-  runString("import sys"); // import sys module (for display / exception hooks)
-  runString("import traceback"); // for formatting stack traces
-  runString("import __main__"); // to access explicitly global variables
-  
-  
-  // expect that bindings are installed locally, so add the path to modules
-  // also add path to plugins
-  runString("sys.path = [\"" + pythonPath() + "\", \"" + homePluginsPath()  + "\", \"" + pluginsPath() + "\"] + sys.path");
-
-  // import SIP
-  if (!runString("from sip import wrapinstance, unwrapinstance",
-       QObject::tr("Couldn't load SIP module.") + "\n" + QObject::tr("Python support will be disabled.")))
-  {
-    exitPython();
-    return;
-  }
-  
-  // import Qt bindings
-  if (!runString("from PyQt4 import QtCore, QtGui",
-       QObject::tr("Couldn't load PyQt4.") + "\n" + QObject::tr("Python support will be disabled.")))
-  {
-    exitPython();
-    return;
-  }
-  
-  // import QGIS bindings
-  QString error_msg = QObject::tr("Couldn't load PyQGIS.") + "\n" + QObject::tr("Python support will be disabled.");
-  if (!runString("from qgis.core import *", error_msg) || !runString("from qgis.gui import *", error_msg))
-  {
-    exitPython();
-    return;
-  }
-  
-  // hook that will show information and traceback in message box
-  runString(
-      "def qgis_except_hook_msg(type, value, tb, msg):\n"
-      "  lst = traceback.format_exception(type, value, tb)\n"
-      "  if msg == None: msg = '" + QObject::tr("An error has occured while executing Python code:") + "'\n"
-      "  txt = '<font color=\"red\">'+msg+'</font><br><br>'\n"
-      "  for s in lst:\n"
-      "    txt += s\n"
-      "  txt += '<br>" + QObject::tr("Python version:") + "<br>' + sys.version + '<br><br>'\n"
-      "  txt += '"+QObject::tr("Python path:") + "' + str(sys.path)\n"
-      "  txt = txt.replace('\\n', '<br>')\n"
-      "  txt = txt.replace('  ', '&nbsp; ')\n" // preserve whitespaces for nicer output
-      "  \n"
-      "  msg = QgsMessageOutput.createMessageOutput()\n"
-      "  msg.setTitle('" + QObject::tr("Python error") + "')\n"
-      "  msg.setMessage(txt, QgsMessageOutput.MessageHtml)\n"
-      "  msg.showMessage()\n");
-  runString(
-      "def qgis_except_hook(type, value, tb):\n"
-      "  qgis_except_hook_msg(type, value, tb, None)\n");
-  runString(
-      "class QgisOutputCatcher:\n"
-      "  def __init__(self):\n"
-      "    self.data = ''\n"
-      "  def write(self, stuff):\n"
-      "    self.data += stuff\n"
-      "  def get_and_clean_data(self):\n"
-      "    tmp = self.data\n"
-      "    self.data = ''\n"
-      "    return tmp\n");
-  
-  // hook for python console so all output will be redirected
-  // and then shown in console
-  runString(
-      "def console_display_hook(obj):\n"
-      "  __main__.__result = obj\n");
-  
-  installErrorHook();
-  
-  // initialize 'iface' object
-  runString("iface = wrapinstance(" + QString::number((unsigned long) interface) + ", QgisInterface)");
-  runString("plugins = {}");
-
-}
-
-void QgsPythonUtilsImpl::exitPython()
-{  
-  Py_Finalize();
-  mMainModule = NULL;
-  mMainDict = NULL;
-  mPythonEnabled = false;
-}
-
-
-bool QgsPythonUtilsImpl::isEnabled()
-{
-  return mPythonEnabled;
-}
-
-void QgsPythonUtilsImpl::installErrorHook()
-{
-  runString("sys.excepthook = qgis_except_hook");
-}
-
-void QgsPythonUtilsImpl::installConsoleHooks()
-{
-  runString("sys.displayhook = console_display_hook\n");
-  
-  runString("_old_stdout = sys.stdout\n");
-  runString("sys.stdout = QgisOutputCatcher()\n");
-}
-
-void QgsPythonUtilsImpl::uninstallConsoleHooks()
-{
-  runString("sys.displayhook = sys.__displayhook__");
-  runString("sys.stdout = _old_stdout");
-}
-
-
-bool QgsPythonUtilsImpl::runStringUnsafe(const QString& command)
-{
-  PyRun_String(command.toLocal8Bit().data(), Py_single_input, mMainDict, mMainDict);
-  return (PyErr_Occurred() == 0);
-}
-
-bool QgsPythonUtilsImpl::runString(const QString& command, QString msgOnError)
-{
-  bool res = runStringUnsafe(command);
-  if (res)
-    return true;
-    
-  if (msgOnError.isEmpty())
-  {
-    // use some default message if custom hasn't been specified
-    msgOnError = QObject::tr("An error occured during execution of following code:") + "\n<tt>" + command + "</tt>";
-  }
-  
-  QString traceback = getTraceback();
-  QString path, version;
-  evalString("str(sys.path)", path);
-  evalString("sys.version", version);
-  
-  QString str = "<font color=\"red\">"+ msgOnError + "</font><br><br>" + traceback + "<br>" +
-      QObject::tr("Python version:") + "<br>" + version + "<br><br>" +
-      QObject::tr("Python path:") + "<br>" + path;
-  str.replace("\n","<br>").replace("  ", "&nbsp; ");
-  
-  QgsMessageOutput* msg = QgsMessageOutput::createMessageOutput();
-  msg->setTitle(QObject::tr("Python error"));
-  msg->setMessage(str, QgsMessageOutput::MessageHtml);
-  msg->showMessage();
-  
-  return res;
-}
-
-
-QString QgsPythonUtilsImpl::getTraceback()
-{
-#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}
-
-
-    QString errMsg;
-    QString result;
-
-    PyObject *modStringIO = NULL;
-    PyObject *modTB = NULL;
-    PyObject *obStringIO = NULL;
-    PyObject *obResult = NULL;
-
-    PyObject *type, *value, *traceback;
-
-    PyErr_Fetch(&type, &value, &traceback);
-    PyErr_NormalizeException(&type, &value, &traceback);
-        
-    modStringIO = PyImport_ImportModule("cStringIO");
-    if (modStringIO==NULL)
-      TRACEBACK_FETCH_ERROR("can't import cStringIO");
-
-    obStringIO = PyObject_CallMethod(modStringIO, (char*) "StringIO", NULL);
-
-    /* Construct a cStringIO object */
-    if (obStringIO==NULL)
-      TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed");
-
-    modTB = PyImport_ImportModule("traceback");
-    if (modTB==NULL)
-      TRACEBACK_FETCH_ERROR("can't import traceback");
-
-    obResult = PyObject_CallMethod(modTB, (char*) "print_exception",
-                                   (char*) "OOOOO",
-                                   type, value ? value : Py_None,
-                                   traceback ? traceback : Py_None,
-                                   Py_None,
-                                   obStringIO);
-                                    
-    if (obResult==NULL) 
-      TRACEBACK_FETCH_ERROR("traceback.print_exception() failed");
-    Py_DECREF(obResult);
-
-    obResult = PyObject_CallMethod(obStringIO, (char*) "getvalue", NULL);
-    if (obResult==NULL) 
-      TRACEBACK_FETCH_ERROR("getvalue() failed.");
-
-    /* And it should be a string all ready to go - duplicate it. */
-    if (!PyString_Check(obResult))
-      TRACEBACK_FETCH_ERROR("getvalue() did not return a string");
-
-    result = PyString_AsString(obResult);
-    
-done:
-        
-  // All finished - first see if we encountered an error
-  if (result.isEmpty() && !errMsg.isEmpty())
-  {
-    result = errMsg;
-  }
-
-  Py_XDECREF(modStringIO);
-  Py_XDECREF(modTB);
-  Py_XDECREF(obStringIO);
-  Py_XDECREF(obResult);
-  Py_XDECREF(value);
-  Py_XDECREF(traceback);
-  Py_XDECREF(type);
-
-  return result;
-}
-
-QString QgsPythonUtilsImpl::getTypeAsString(PyObject* obj)
-{
-  if (obj == NULL)
-    return NULL;
-
-  if (PyClass_Check(obj))
-  {
-    QgsDebugMsg("got class");
-    return QString(PyString_AsString(((PyClassObject*)obj)->cl_name));
-  }
-  else if (PyType_Check(obj))
-  {
-    QgsDebugMsg("got type");
-	return QString(((PyTypeObject*)obj)->tp_name);
-  }
-  else
-  {
-    QgsDebugMsg("got object");
-    PyObject* s = PyObject_Str(obj);
-    QString str;
-    if (s && PyString_Check(s))
-      str = QString(PyString_AsString(s));
-    Py_XDECREF(s);
-    return str;
-  }
-}
-
-bool QgsPythonUtilsImpl::getError(QString& errorClassName, QString& errorText)
-{
-  if (!PyErr_Occurred())
-    return false;
-  
-  PyObject* obj_str;
-  PyObject* err_type;
-  PyObject* err_value;
-  PyObject* err_tb;
-  
-  // get the exception information and clear error
-  PyErr_Fetch(&err_type, &err_value, &err_tb);
-  
-  // get exception's class name
-  errorClassName = getTypeAsString(err_type);
-    
-  // get exception's text
-  if (err_value != NULL && err_value != Py_None)
-  {
-    obj_str = PyObject_Str(err_value); // new reference
-    errorText = PyString_AS_STRING(obj_str);
-    Py_XDECREF(obj_str);
-  }
-  else
-    errorText.clear();
-  
-  // cleanup
-  Py_XDECREF(err_type);
-  Py_XDECREF(err_value);
-  Py_XDECREF(err_tb);
-  
-  return true;
-}
-
-QString QgsPythonUtilsImpl::getResult()
-{
-  return getVariableFromMain("__result");
-}
-
-QString QgsPythonUtilsImpl::getVariableFromMain(QString name)
-{
-  PyObject* obj;
-  PyObject* obj_str;
-  
-  QString output;
-  
-  // get the result
-  obj = PyDict_GetItemString(mMainDict, name.toUtf8()); // obj is borrowed reference
-  
-  if (obj != NULL && obj != Py_None)
-  {
-    obj_str = PyObject_Str(obj); // obj_str is new reference
-    if (obj_str != NULL && obj_str != Py_None)
-    {
-      output = PyString_AsString(obj_str);
-    }
-    Py_XDECREF(obj_str);
-  }
-    
-  // erase result
-  PyDict_SetItemString(mMainDict, name.toUtf8(), Py_None);
-  
-  return output;
-}
-
-bool QgsPythonUtilsImpl::evalString(const QString& command, QString& result)
-{
-  PyObject* res = PyRun_String(command.toLocal8Bit().data(), Py_eval_input, mMainDict, mMainDict);
-  
-  if (res != NULL && PyString_Check(res))
-  {
-    result = PyString_AsString(res);
-    Py_XDECREF(res);
-    return true;
-  }
-  Py_XDECREF(res);
-  return false;
-}
-
-
-QString QgsPythonUtilsImpl::pythonPath()
-{
-  return QgsApplication::pkgDataPath() + "/python";
-}
-
-QString QgsPythonUtilsImpl::pluginsPath()
-{
-  return pythonPath() + "/plugins";
-}
-
-QString QgsPythonUtilsImpl::homePluginsPath()
-{
-  return QgsApplication::qgisSettingsDirPath() + "/python/plugins";
-}
-
-QStringList QgsPythonUtilsImpl::pluginList()
-{
-  QDir pluginDir(QgsPythonUtilsImpl::pluginsPath(), "*",
-                 QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
-
-  QDir homePluginDir(QgsPythonUtilsImpl::homePluginsPath(), "*",
-		     QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
-
-  QStringList pluginList = pluginDir.entryList();
-
-  for (uint i = 0; i < homePluginDir.count(); i++)
-  {
-    QString packageName = homePluginDir[i];
-    if(!pluginList.contains(packageName))
-        pluginList.append(packageName); 
-
-  }
-
-  return pluginList;
-}
-
-QString QgsPythonUtilsImpl::getPluginMetadata(QString pluginName, QString function)
-{
-  QString command = pluginName + "." + function + "()";
-  QString retval = "???";
-  
-  PyObject* obj = PyRun_String(command.toLocal8Bit().data(), Py_eval_input, mMainDict, mMainDict);
-  if (PyErr_Occurred())
-  {
-    PyErr_Print(); // just print it to console
-    PyErr_Clear();
-    return "__error__";
-  }
-  else if (PyString_Check(obj))
-  {
-    retval = PyString_AS_STRING(obj);
-  }
-  else
-  {
-    // bad python return value
-    retval = "__error__";
-  }
-  Py_XDECREF(obj);
-  return retval;
-}
-
-
-bool QgsPythonUtilsImpl::loadPlugin(QString packageName)
-{
-  // load plugin's package and ensure that plugin is reloaded when changed
-  runString(
-       "try:\n"
-       "  import " + packageName + "\n"
-       "  __main__.__plugin_result = 'OK'\n"
-       "except:\n"
-       "  __main__.__plugin_result = 'ERROR'\n");
-
-  if( getVariableFromMain("__plugin_result") == "OK" )
-    return true;
-
-  // snake in the grass, we know it's there
-  runString("sys.path_importer_cache.clear()");
-
-  // retry
-  runString(
-       "try:\n"
-       "  import " + packageName + "\n"
-       "  reload(" + packageName + ")\n"
-       "  __main__.__plugin_result = 'OK'\n"
-       "except:\n"
-       "  qgis_except_hook_msg(sys.exc_type, sys.exc_value, sys.exc_traceback, "
-            "'Couldn\\'t load plugin \"" + packageName + "\" from [\\'' + '\\', \\''.join(sys.path) + '\\']')\n"
-       "  __main__.__plugin_result = 'ERROR'\n");
-
-  return getVariableFromMain("__plugin_result") == "OK";
-}
-
-
-bool QgsPythonUtilsImpl::startPlugin(QString packageName)
-{
-  QString pluginPythonVar = "plugins['" + packageName + "']";
-  
-  QString errMsg = QObject::tr("Couldn't load plugin ") + packageName;
-    
-  // create an instance of the plugin
-  if (!runString(pluginPythonVar + " = " + packageName + ".classFactory(iface)",
-                 errMsg + QObject::tr(" due an error when calling its classFactory() method")))
-    return false;
-  
-  // initGui
-  if (!runString(pluginPythonVar + ".initGui()", errMsg + QObject::tr(" due an error when calling its initGui() method")))
-    return false;
-  
-  return true;
-}
-
-
-bool QgsPythonUtilsImpl::unloadPlugin(QString packageName)
-{
-  // unload and delete plugin!
-  QString varName = "plugins['" + packageName + "']";
-  
-  QString errMsg = QObject::tr("Error while unloading plugin ") + packageName;
-  
-  if (!runString(varName + ".unload()", errMsg))
-    return false;
-  if (!runString("del " + varName, errMsg))
-    return false;
-  
-  return true;
-}

Deleted: trunk/qgis/src/app/qgspythonutils.h
===================================================================
--- trunk/qgis/src/app/qgspythonutils.h	2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgspythonutils.h	2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,93 +0,0 @@
-/***************************************************************************
-    qgspythonutils.h - abstract interface for Python routines
-    ---------------------
-    begin                : October 2006
-    copyright            : (C) 2006 by Martin Dobias
-    email                : wonder.sk at gmail dot com
- ***************************************************************************
- *                                                                         *
- *   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.                                   *
- *                                                                         *
- ***************************************************************************/
-/* $Id$ */
-
-#ifndef QGSPYTHONUTILS_H
-#define QGSPYTHONUTILS_H
-
-#include <QString>
-#include <QStringList>
-
-
-class QgisInterface;
-
-/**
- All calls to Python functions in QGIS come here.
- This class is a singleton.
- 
- Default path for python plugins is:
- - QgsApplication::qgisSettingsDirPath() + "/python/plugins"
- - QgsApplication::pkgDataPath() + "/python/plugins"
-
- */
-
-class QgsPythonUtils
-{
-  public:
-    
-    virtual ~QgsPythonUtils() {}
-    
-    //! returns true if python support is ready to use (must be inited first)
-    virtual bool isEnabled() = 0;
-  
-    //! initialize python and import bindings
-    virtual void initPython(QgisInterface* interface) = 0;
-    
-    //! close python interpreter
-    virtual void exitPython() = 0;
-
-    /* console */
-    
-    //! run a statement, error reporting is not done
-    //! @return true if no error occured
-    virtual bool runStringUnsafe(const QString& command) = 0;
-    
-    virtual bool evalString(const QString& command, QString& result) = 0;
-    
-    //! change displayhook and excepthook
-    //! our hooks will just save the result to special variables
-    //! and those can be used in the program
-    virtual void installConsoleHooks() = 0;
-    
-    //! get back to the original settings (i.e. write output to stdout)
-    virtual void uninstallConsoleHooks() = 0;
-    
-    //! get result from the last statement as a string
-    virtual QString getResult() = 0;
-
-    //! get information about error to the supplied arguments
-    //! @return false if there was no python error
-    virtual bool getError(QString& errorClassName, QString& errorText) = 0;
-    
-    /* plugins */
-    
-    //! return list of all available python plugins
-    virtual QStringList pluginList() = 0;
-    
-    //! load python plugin (import)
-    virtual bool loadPlugin(QString packageName) = 0;
-    
-    //! start plugin: add to active plugins and call initGui()
-    virtual bool startPlugin(QString packageName) = 0;
-    
-    //! helper function to get some information about plugin
-    //! @param function one of these strings: name, tpye, version, description
-    virtual QString getPluginMetadata(QString pluginName, QString function) = 0;
-
-    //! unload plugin
-    virtual bool unloadPlugin(QString packageName) = 0;
-};
-
-#endif

Deleted: trunk/qgis/src/app/qgspythonutilsimpl.h
===================================================================
--- trunk/qgis/src/app/qgspythonutilsimpl.h	2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgspythonutilsimpl.h	2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,132 +0,0 @@
-/***************************************************************************
-    qgspythonutilsimpl.h - routines for interfacing Python
-    ---------------------
-    begin                : May 2008
-    copyright            : (C) 2008 by Martin Dobias
-    email                : wonder.sk at gmail dot com
- ***************************************************************************
- *                                                                         *
- *   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.                                   *
- *                                                                         *
- ***************************************************************************/
-/* $Id$ */
-
-
-#ifndef QGSPYTHONUTILSIMPL_H
-#define QGSPYTHONUTILSIMPL_H
-
-#include "qgspythonutils.h"
-
-// forward declaration for PyObject
-#ifndef PyObject_HEAD
-struct _object;
-typedef _object PyObject;
-#endif
-
-
-class QgsPythonUtilsImpl : public QgsPythonUtils
-{
-  public:
-    
-    QgsPythonUtilsImpl();
-    
-    virtual ~QgsPythonUtilsImpl();
-        
-    static QgsPythonUtilsImpl* instance();
-    
-    /* general purpose functions */
-
-    //! initialize python and import bindings
-    void initPython(QgisInterface* interface);
-    
-    //! close python interpreter
-    void exitPython();
-
-    //! returns true if python support is ready to use (must be inited first)
-    bool isEnabled();
-    
-    //! returns path where QGIS python stuff is located
-    QString pythonPath();
-    
-    //! run a statement (wrapper for PyRun_String)
-    //! this command is more advanced as enables error checking etc.
-    //! when an exception is raised, it shows dialog with exception details
-    //! @return true if no error occured
-    bool runString(const QString& command, QString msgOnError = QString());
-    
-    //! run a statement, error reporting is not done
-    //! @return true if no error occured
-    bool runStringUnsafe(const QString& command);
-    
-    bool evalString(const QString& command, QString& result);
-    
-    //! @return object's type name as a string
-    QString getTypeAsString(PyObject* obj);
-
-    //! get information about error to the supplied arguments
-    //! @return false if there was no python error
-    bool getError(QString& errorClassName, QString& errorText);
-    
-    //! get variable from main dictionary
-    QString getVariableFromMain(QString name);
-
-    /* python console related functions */
-    
-    //! change displayhook and excepthook
-    //! our hooks will just save the result to special variables
-    //! and those can be used in the program
-    void installConsoleHooks();
-    
-    //! get back to the original settings (i.e. write output to stdout)
-    void uninstallConsoleHooks();
-    
-    //! get result from the last statement as a string
-    QString getResult();
-
-    /* plugins related functions */
-    
-    //! return current path for python plugins
-    QString pluginsPath();
-
-    //! return current path for home directory python plugins
-    QString homePluginsPath();
-
-    //! return list of all available python plugins
-    QStringList pluginList();
-        
-    //! load python plugin (import)
-    bool loadPlugin(QString packageName);
-    
-    //! start plugin: add to active plugins and call initGui()
-    bool startPlugin(QString packageName);
-    
-    //! helper function to get some information about plugin
-    //! @param function one of these strings: name, tpye, version, description
-    QString getPluginMetadata(QString pluginName, QString function);
-
-    //! unload plugin
-    bool unloadPlugin(QString packageName);
-
-  protected:
-    
-    void installErrorHook();
-
-    QString getTraceback();
-
-    //! reference to module __main__
-    PyObject* mMainModule;
-    
-    //! dictionary of module __main__
-    PyObject* mMainDict;
-    
-    //! flag determining that python support is enabled
-    bool mPythonEnabled;
-    
-    static QgsPythonUtilsImpl* mInstance;
-};
-
-
-#endif

Added: trunk/qgis/src/python/CMakeLists.txt
===================================================================
--- trunk/qgis/src/python/CMakeLists.txt	                        (rev 0)
+++ trunk/qgis/src/python/CMakeLists.txt	2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,25 @@
+
+SET(QGISPYTHON_SRCS qgispython.cpp qgspythonutilsimpl.cpp)
+
+INCLUDE_DIRECTORIES(
+  ../core
+  ../core/raster ../core/renderer ../core/symbology
+  ../gui
+  ${PYTHON_INCLUDE_PATH})
+
+ADD_LIBRARY (qgispython SHARED ${QGISPYTHON_SRCS})
+
+SET_TARGET_PROPERTIES(qgispython PROPERTIES 
+			VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}
+			SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR})
+
+
+TARGET_LINK_LIBRARIES(qgispython
+  ${QT_QTCORE_LIBRARY} 
+  ${QT_QTGUI_LIBRARY} 
+  ${PYTHON_LIBRARIES}
+)
+
+INSTALL(TARGETS qgispython
+  RUNTIME DESTINATION ${QGIS_BIN_DIR}
+  LIBRARY DESTINATION ${QGIS_LIB_DIR})

Added: trunk/qgis/src/python/qgispython.cpp
===================================================================
--- trunk/qgis/src/python/qgispython.cpp	                        (rev 0)
+++ trunk/qgis/src/python/qgispython.cpp	2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,23 @@
+/***************************************************************************
+    qgispython.cpp - python support in QGIS
+    ---------------------
+    begin                : May 2008
+    copyright            : (C) 2008 by Martin Dobias
+    email                : wonder.sk at gmail dot com
+ ***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+/* $Id$ */
+
+#include "qgis.h"
+#include "qgspythonutilsimpl.h"
+
+QGISEXTERN QgsPythonUtils* instance()
+{
+  return new QgsPythonUtilsImpl();
+}

Copied: trunk/qgis/src/python/qgspythonutils.h (from rev 8517, trunk/qgis/src/app/qgspythonutils.h)
===================================================================
--- trunk/qgis/src/python/qgspythonutils.h	                        (rev 0)
+++ trunk/qgis/src/python/qgspythonutils.h	2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,93 @@
+/***************************************************************************
+    qgspythonutils.h - abstract interface for Python routines
+    ---------------------
+    begin                : October 2006
+    copyright            : (C) 2006 by Martin Dobias
+    email                : wonder.sk at gmail dot com
+ ***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+/* $Id$ */
+
+#ifndef QGSPYTHONUTILS_H
+#define QGSPYTHONUTILS_H
+
+#include <QString>
+#include <QStringList>
+
+
+class QgisInterface;
+
+/**
+ All calls to Python functions in QGIS come here.
+ This class is a singleton.
+ 
+ Default path for python plugins is:
+ - QgsApplication::qgisSettingsDirPath() + "/python/plugins"
+ - QgsApplication::pkgDataPath() + "/python/plugins"
+
+ */
+
+class QgsPythonUtils
+{
+  public:
+    
+    virtual ~QgsPythonUtils() {}
+    
+    //! returns true if python support is ready to use (must be inited first)
+    virtual bool isEnabled() = 0;
+  
+    //! initialize python and import bindings
+    virtual void initPython(QgisInterface* interface) = 0;
+    
+    //! close python interpreter
+    virtual void exitPython() = 0;
+
+    /* console */
+    
+    //! run a statement, error reporting is not done
+    //! @return true if no error occured
+    virtual bool runStringUnsafe(const QString& command) = 0;
+    
+    virtual bool evalString(const QString& command, QString& result) = 0;
+    
+    //! change displayhook and excepthook
+    //! our hooks will just save the result to special variables
+    //! and those can be used in the program
+    virtual void installConsoleHooks() = 0;
+    
+    //! get back to the original settings (i.e. write output to stdout)
+    virtual void uninstallConsoleHooks() = 0;
+    
+    //! get result from the last statement as a string
+    virtual QString getResult() = 0;
+
+    //! get information about error to the supplied arguments
+    //! @return false if there was no python error
+    virtual bool getError(QString& errorClassName, QString& errorText) = 0;
+    
+    /* plugins */
+    
+    //! return list of all available python plugins
+    virtual QStringList pluginList() = 0;
+    
+    //! load python plugin (import)
+    virtual bool loadPlugin(QString packageName) = 0;
+    
+    //! start plugin: add to active plugins and call initGui()
+    virtual bool startPlugin(QString packageName) = 0;
+    
+    //! helper function to get some information about plugin
+    //! @param function one of these strings: name, tpye, version, description
+    virtual QString getPluginMetadata(QString pluginName, QString function) = 0;
+
+    //! unload plugin
+    virtual bool unloadPlugin(QString packageName) = 0;
+};
+
+#endif

Copied: trunk/qgis/src/python/qgspythonutilsimpl.cpp (from rev 8517, trunk/qgis/src/app/qgspythonutils.cpp)
===================================================================
--- trunk/qgis/src/python/qgspythonutilsimpl.cpp	                        (rev 0)
+++ trunk/qgis/src/python/qgspythonutilsimpl.cpp	2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,505 @@
+/***************************************************************************
+    qgspythonutils.cpp - routines for interfacing Python
+    ---------------------
+    begin                : October 2006
+    copyright            : (C) 2006 by Martin Dobias
+    email                : wonder.sk at gmail dot com
+ ***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+/* $Id$ */
+
+// python should be first include
+// otherwise issues some warnings
+#include <Python.h>
+
+#include "qgspythonutilsimpl.h"
+
+#include "qgsapplication.h"
+#include "qgslogger.h"
+#include "qgsmessageoutput.h"
+
+#include <QMessageBox>
+#include <QStringList>
+#include <QDir>
+
+
+QgsPythonUtilsImpl::QgsPythonUtilsImpl()
+{
+  mMainModule = NULL;
+  mMainDict = NULL;
+  mPythonEnabled = false;
+}
+
+QgsPythonUtilsImpl::~QgsPythonUtilsImpl()
+{
+}
+
+void QgsPythonUtilsImpl::initPython(QgisInterface* interface)
+{
+  // initialize python
+  Py_Initialize();
+  
+  mPythonEnabled = true;
+  
+  mMainModule = PyImport_AddModule("__main__"); // borrowed reference
+  mMainDict = PyModule_GetDict(mMainModule); // borrowed reference
+  
+  runString("import sys"); // import sys module (for display / exception hooks)
+  runString("import traceback"); // for formatting stack traces
+  runString("import __main__"); // to access explicitly global variables
+  
+  // expect that bindings are installed locally, so add the path to modules
+  // also add path to plugins
+  runString("sys.path = [\"" + pythonPath() + "\", \"" + homePluginsPath()  + "\", \"" + pluginsPath() + "\"] + sys.path");
+
+  // import SIP
+  if (!runString("from sip import wrapinstance, unwrapinstance",
+       QObject::tr("Couldn't load SIP module.") + "\n" + QObject::tr("Python support will be disabled.")))
+  {
+    exitPython();
+    return;
+  }
+  
+  // import Qt bindings
+  if (!runString("from PyQt4 import QtCore, QtGui",
+       QObject::tr("Couldn't load PyQt4.") + "\n" + QObject::tr("Python support will be disabled.")))
+  {
+    exitPython();
+    return;
+  }
+  
+  // import QGIS bindings
+  QString error_msg = QObject::tr("Couldn't load PyQGIS.") + "\n" + QObject::tr("Python support will be disabled.");
+  if (!runString("from qgis.core import *", error_msg) || !runString("from qgis.gui import *", error_msg))
+  {
+    exitPython();
+    return;
+  }
+  
+  // hook that will show information and traceback in message box
+  runString(
+      "def qgis_except_hook_msg(type, value, tb, msg):\n"
+      "  lst = traceback.format_exception(type, value, tb)\n"
+      "  if msg == None: msg = '" + QObject::tr("An error has occured while executing Python code:") + "'\n"
+      "  txt = '<font color=\"red\">'+msg+'</font><br><br>'\n"
+      "  for s in lst:\n"
+      "    txt += s\n"
+      "  txt += '<br>" + QObject::tr("Python version:") + "<br>' + sys.version + '<br><br>'\n"
+      "  txt += '"+QObject::tr("Python path:") + "' + str(sys.path)\n"
+      "  txt = txt.replace('\\n', '<br>')\n"
+      "  txt = txt.replace('  ', '&nbsp; ')\n" // preserve whitespaces for nicer output
+      "  \n"
+      "  msg = QgsMessageOutput.createMessageOutput()\n"
+      "  msg.setTitle('" + QObject::tr("Python error") + "')\n"
+      "  msg.setMessage(txt, QgsMessageOutput.MessageHtml)\n"
+      "  msg.showMessage()\n");
+  runString(
+      "def qgis_except_hook(type, value, tb):\n"
+      "  qgis_except_hook_msg(type, value, tb, None)\n");
+  runString(
+      "class QgisOutputCatcher:\n"
+      "  def __init__(self):\n"
+      "    self.data = ''\n"
+      "  def write(self, stuff):\n"
+      "    self.data += stuff\n"
+      "  def get_and_clean_data(self):\n"
+      "    tmp = self.data\n"
+      "    self.data = ''\n"
+      "    return tmp\n");
+  
+  // hook for python console so all output will be redirected
+  // and then shown in console
+  runString(
+      "def console_display_hook(obj):\n"
+      "  __main__.__result = obj\n");
+  
+  installErrorHook();
+  
+  // initialize 'iface' object
+  runString("iface = wrapinstance(" + QString::number((unsigned long) interface) + ", QgisInterface)");
+  runString("plugins = {}");
+
+}
+
+void QgsPythonUtilsImpl::exitPython()
+{  
+  Py_Finalize();
+  mMainModule = NULL;
+  mMainDict = NULL;
+  mPythonEnabled = false;
+}
+
+
+bool QgsPythonUtilsImpl::isEnabled()
+{
+  return mPythonEnabled;
+}
+
+void QgsPythonUtilsImpl::installErrorHook()
+{
+  runString("sys.excepthook = qgis_except_hook");
+}
+
+void QgsPythonUtilsImpl::installConsoleHooks()
+{
+  runString("sys.displayhook = console_display_hook\n");
+  
+  runString("_old_stdout = sys.stdout\n");
+  runString("sys.stdout = QgisOutputCatcher()\n");
+}
+
+void QgsPythonUtilsImpl::uninstallConsoleHooks()
+{
+  runString("sys.displayhook = sys.__displayhook__");
+  runString("sys.stdout = _old_stdout");
+}
+
+
+bool QgsPythonUtilsImpl::runStringUnsafe(const QString& command)
+{
+  PyRun_String(command.toLocal8Bit().data(), Py_single_input, mMainDict, mMainDict);
+  return (PyErr_Occurred() == 0);
+}
+
+bool QgsPythonUtilsImpl::runString(const QString& command, QString msgOnError)
+{
+  bool res = runStringUnsafe(command);
+  if (res)
+    return true;
+    
+  if (msgOnError.isEmpty())
+  {
+    // use some default message if custom hasn't been specified
+    msgOnError = QObject::tr("An error occured during execution of following code:") + "\n<tt>" + command + "</tt>";
+  }
+  
+  QString traceback = getTraceback();
+  QString path, version;
+  evalString("str(sys.path)", path);
+  evalString("sys.version", version);
+  
+  QString str = "<font color=\"red\">"+ msgOnError + "</font><br><br>" + traceback + "<br>" +
+      QObject::tr("Python version:") + "<br>" + version + "<br><br>" +
+      QObject::tr("Python path:") + "<br>" + path;
+  str.replace("\n","<br>").replace("  ", "&nbsp; ");
+  
+  QgsMessageOutput* msg = QgsMessageOutput::createMessageOutput();
+  msg->setTitle(QObject::tr("Python error"));
+  msg->setMessage(str, QgsMessageOutput::MessageHtml);
+  msg->showMessage();
+  
+  return res;
+}
+
+
+QString QgsPythonUtilsImpl::getTraceback()
+{
+#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}
+
+
+    QString errMsg;
+    QString result;
+
+    PyObject *modStringIO = NULL;
+    PyObject *modTB = NULL;
+    PyObject *obStringIO = NULL;
+    PyObject *obResult = NULL;
+
+    PyObject *type, *value, *traceback;
+
+    PyErr_Fetch(&type, &value, &traceback);
+    PyErr_NormalizeException(&type, &value, &traceback);
+        
+    modStringIO = PyImport_ImportModule("cStringIO");
+    if (modStringIO==NULL)
+      TRACEBACK_FETCH_ERROR("can't import cStringIO");
+
+    obStringIO = PyObject_CallMethod(modStringIO, (char*) "StringIO", NULL);
+
+    /* Construct a cStringIO object */
+    if (obStringIO==NULL)
+      TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed");
+
+    modTB = PyImport_ImportModule("traceback");
+    if (modTB==NULL)
+      TRACEBACK_FETCH_ERROR("can't import traceback");
+
+    obResult = PyObject_CallMethod(modTB, (char*) "print_exception",
+                                   (char*) "OOOOO",
+                                   type, value ? value : Py_None,
+                                   traceback ? traceback : Py_None,
+                                   Py_None,
+                                   obStringIO);
+                                    
+    if (obResult==NULL) 
+      TRACEBACK_FETCH_ERROR("traceback.print_exception() failed");
+    Py_DECREF(obResult);
+
+    obResult = PyObject_CallMethod(obStringIO, (char*) "getvalue", NULL);
+    if (obResult==NULL) 
+      TRACEBACK_FETCH_ERROR("getvalue() failed.");
+
+    /* And it should be a string all ready to go - duplicate it. */
+    if (!PyString_Check(obResult))
+      TRACEBACK_FETCH_ERROR("getvalue() did not return a string");
+
+    result = PyString_AsString(obResult);
+    
+done:
+        
+  // All finished - first see if we encountered an error
+  if (result.isEmpty() && !errMsg.isEmpty())
+  {
+    result = errMsg;
+  }
+
+  Py_XDECREF(modStringIO);
+  Py_XDECREF(modTB);
+  Py_XDECREF(obStringIO);
+  Py_XDECREF(obResult);
+  Py_XDECREF(value);
+  Py_XDECREF(traceback);
+  Py_XDECREF(type);
+
+  return result;
+}
+
+QString QgsPythonUtilsImpl::getTypeAsString(PyObject* obj)
+{
+  if (obj == NULL)
+    return NULL;
+
+  if (PyClass_Check(obj))
+  {
+    QgsDebugMsg("got class");
+    return QString(PyString_AsString(((PyClassObject*)obj)->cl_name));
+  }
+  else if (PyType_Check(obj))
+  {
+    QgsDebugMsg("got type");
+	return QString(((PyTypeObject*)obj)->tp_name);
+  }
+  else
+  {
+    QgsDebugMsg("got object");
+    PyObject* s = PyObject_Str(obj);
+    QString str;
+    if (s && PyString_Check(s))
+      str = QString(PyString_AsString(s));
+    Py_XDECREF(s);
+    return str;
+  }
+}
+
+bool QgsPythonUtilsImpl::getError(QString& errorClassName, QString& errorText)
+{
+  if (!PyErr_Occurred())
+    return false;
+  
+  PyObject* obj_str;
+  PyObject* err_type;
+  PyObject* err_value;
+  PyObject* err_tb;
+  
+  // get the exception information and clear error
+  PyErr_Fetch(&err_type, &err_value, &err_tb);
+  
+  // get exception's class name
+  errorClassName = getTypeAsString(err_type);
+    
+  // get exception's text
+  if (err_value != NULL && err_value != Py_None)
+  {
+    obj_str = PyObject_Str(err_value); // new reference
+    errorText = PyString_AS_STRING(obj_str);
+    Py_XDECREF(obj_str);
+  }
+  else
+    errorText.clear();
+  
+  // cleanup
+  Py_XDECREF(err_type);
+  Py_XDECREF(err_value);
+  Py_XDECREF(err_tb);
+  
+  return true;
+}
+
+QString QgsPythonUtilsImpl::getResult()
+{
+  return getVariableFromMain("__result");
+}
+
+QString QgsPythonUtilsImpl::getVariableFromMain(QString name)
+{
+  PyObject* obj;
+  PyObject* obj_str;
+  
+  QString output;
+  
+  // get the result
+  obj = PyDict_GetItemString(mMainDict, name.toUtf8()); // obj is borrowed reference
+  
+  if (obj != NULL && obj != Py_None)
+  {
+    obj_str = PyObject_Str(obj); // obj_str is new reference
+    if (obj_str != NULL && obj_str != Py_None)
+    {
+      output = PyString_AsString(obj_str);
+    }
+    Py_XDECREF(obj_str);
+  }
+    
+  // erase result
+  PyDict_SetItemString(mMainDict, name.toUtf8(), Py_None);
+  
+  return output;
+}
+
+bool QgsPythonUtilsImpl::evalString(const QString& command, QString& result)
+{
+  PyObject* res = PyRun_String(command.toLocal8Bit().data(), Py_eval_input, mMainDict, mMainDict);
+  
+  if (res != NULL && PyString_Check(res))
+  {
+    result = PyString_AsString(res);
+    Py_XDECREF(res);
+    return true;
+  }
+  Py_XDECREF(res);
+  return false;
+}
+
+
+QString QgsPythonUtilsImpl::pythonPath()
+{
+  return QgsApplication::pkgDataPath() + "/python";
+}
+
+QString QgsPythonUtilsImpl::pluginsPath()
+{
+  return pythonPath() + "/plugins";
+}
+
+QString QgsPythonUtilsImpl::homePluginsPath()
+{
+  return QgsApplication::qgisSettingsDirPath() + "/python/plugins";
+}
+
+QStringList QgsPythonUtilsImpl::pluginList()
+{
+  QDir pluginDir(QgsPythonUtilsImpl::pluginsPath(), "*",
+                 QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
+
+  QDir homePluginDir(QgsPythonUtilsImpl::homePluginsPath(), "*",
+		     QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
+
+  QStringList pluginList = pluginDir.entryList();
+
+  for (uint i = 0; i < homePluginDir.count(); i++)
+  {
+    QString packageName = homePluginDir[i];
+    if(!pluginList.contains(packageName))
+        pluginList.append(packageName); 
+
+  }
+
+  return pluginList;
+}
+
+QString QgsPythonUtilsImpl::getPluginMetadata(QString pluginName, QString function)
+{
+  QString command = pluginName + "." + function + "()";
+  QString retval = "???";
+  
+  PyObject* obj = PyRun_String(command.toLocal8Bit().data(), Py_eval_input, mMainDict, mMainDict);
+  if (PyErr_Occurred())
+  {
+    PyErr_Print(); // just print it to console
+    PyErr_Clear();
+    return "__error__";
+  }
+  else if (PyString_Check(obj))
+  {
+    retval = PyString_AS_STRING(obj);
+  }
+  else
+  {
+    // bad python return value
+    retval = "__error__";
+  }
+  Py_XDECREF(obj);
+  return retval;
+}
+
+
+bool QgsPythonUtilsImpl::loadPlugin(QString packageName)
+{
+  // load plugin's package and ensure that plugin is reloaded when changed
+  runString(
+       "try:\n"
+       "  import " + packageName + "\n"
+       "  __main__.__plugin_result = 'OK'\n"
+       "except:\n"
+       "  __main__.__plugin_result = 'ERROR'\n");
+
+  if( getVariableFromMain("__plugin_result") == "OK" )
+    return true;
+
+  // snake in the grass, we know it's there
+  runString("sys.path_importer_cache.clear()");
+
+  // retry
+  runString(
+       "try:\n"
+       "  import " + packageName + "\n"
+       "  reload(" + packageName + ")\n"
+       "  __main__.__plugin_result = 'OK'\n"
+       "except:\n"
+       "  qgis_except_hook_msg(sys.exc_type, sys.exc_value, sys.exc_traceback, "
+            "'Couldn\\'t load plugin \"" + packageName + "\" from [\\'' + '\\', \\''.join(sys.path) + '\\']')\n"
+       "  __main__.__plugin_result = 'ERROR'\n");
+
+  return getVariableFromMain("__plugin_result") == "OK";
+}
+
+
+bool QgsPythonUtilsImpl::startPlugin(QString packageName)
+{
+  QString pluginPythonVar = "plugins['" + packageName + "']";
+  
+  QString errMsg = QObject::tr("Couldn't load plugin ") + packageName;
+    
+  // create an instance of the plugin
+  if (!runString(pluginPythonVar + " = " + packageName + ".classFactory(iface)",
+                 errMsg + QObject::tr(" due an error when calling its classFactory() method")))
+    return false;
+  
+  // initGui
+  if (!runString(pluginPythonVar + ".initGui()", errMsg + QObject::tr(" due an error when calling its initGui() method")))
+    return false;
+  
+  return true;
+}
+
+
+bool QgsPythonUtilsImpl::unloadPlugin(QString packageName)
+{
+  // unload and delete plugin!
+  QString varName = "plugins['" + packageName + "']";
+  
+  QString errMsg = QObject::tr("Error while unloading plugin ") + packageName;
+  
+  if (!runString(varName + ".unload()", errMsg))
+    return false;
+  if (!runString("del " + varName, errMsg))
+    return false;
+  
+  return true;
+}

Copied: trunk/qgis/src/python/qgspythonutilsimpl.h (from rev 8517, trunk/qgis/src/app/qgspythonutilsimpl.h)
===================================================================
--- trunk/qgis/src/python/qgspythonutilsimpl.h	                        (rev 0)
+++ trunk/qgis/src/python/qgspythonutilsimpl.h	2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,128 @@
+/***************************************************************************
+    qgspythonutilsimpl.h - routines for interfacing Python
+    ---------------------
+    begin                : May 2008
+    copyright            : (C) 2008 by Martin Dobias
+    email                : wonder.sk at gmail dot com
+ ***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+/* $Id$ */
+
+
+#ifndef QGSPYTHONUTILSIMPL_H
+#define QGSPYTHONUTILSIMPL_H
+
+#include "qgspythonutils.h"
+
+// forward declaration for PyObject
+#ifndef PyObject_HEAD
+struct _object;
+typedef _object PyObject;
+#endif
+
+
+class QgsPythonUtilsImpl : public QgsPythonUtils
+{
+  public:
+    
+    QgsPythonUtilsImpl();
+    
+    virtual ~QgsPythonUtilsImpl();
+        
+    /* general purpose functions */
+
+    //! initialize python and import bindings
+    void initPython(QgisInterface* interface);
+    
+    //! close python interpreter
+    void exitPython();
+
+    //! returns true if python support is ready to use (must be inited first)
+    bool isEnabled();
+    
+    //! returns path where QGIS python stuff is located
+    QString pythonPath();
+    
+    //! run a statement (wrapper for PyRun_String)
+    //! this command is more advanced as enables error checking etc.
+    //! when an exception is raised, it shows dialog with exception details
+    //! @return true if no error occured
+    bool runString(const QString& command, QString msgOnError = QString());
+    
+    //! run a statement, error reporting is not done
+    //! @return true if no error occured
+    bool runStringUnsafe(const QString& command);
+    
+    bool evalString(const QString& command, QString& result);
+    
+    //! @return object's type name as a string
+    QString getTypeAsString(PyObject* obj);
+
+    //! get information about error to the supplied arguments
+    //! @return false if there was no python error
+    bool getError(QString& errorClassName, QString& errorText);
+    
+    //! get variable from main dictionary
+    QString getVariableFromMain(QString name);
+
+    /* python console related functions */
+    
+    //! change displayhook and excepthook
+    //! our hooks will just save the result to special variables
+    //! and those can be used in the program
+    void installConsoleHooks();
+    
+    //! get back to the original settings (i.e. write output to stdout)
+    void uninstallConsoleHooks();
+    
+    //! get result from the last statement as a string
+    QString getResult();
+
+    /* plugins related functions */
+    
+    //! return current path for python plugins
+    QString pluginsPath();
+
+    //! return current path for home directory python plugins
+    QString homePluginsPath();
+
+    //! return list of all available python plugins
+    QStringList pluginList();
+        
+    //! load python plugin (import)
+    bool loadPlugin(QString packageName);
+    
+    //! start plugin: add to active plugins and call initGui()
+    bool startPlugin(QString packageName);
+    
+    //! helper function to get some information about plugin
+    //! @param function one of these strings: name, tpye, version, description
+    QString getPluginMetadata(QString pluginName, QString function);
+
+    //! unload plugin
+    bool unloadPlugin(QString packageName);
+
+  protected:
+    
+    void installErrorHook();
+
+    QString getTraceback();
+
+    //! reference to module __main__
+    PyObject* mMainModule;
+    
+    //! dictionary of module __main__
+    PyObject* mMainDict;
+    
+    //! flag determining that python support is enabled
+    bool mPythonEnabled;
+};
+
+
+#endif



More information about the QGIS-commit mailing list