2010-01-07 14:59:27 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2009-11-07 12:04:42 +00:00
|
|
|
"""
|
|
|
|
QGIS utilities module
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
from PyQt4.QtCore import QCoreApplication
|
|
|
|
import sys
|
|
|
|
import traceback
|
2010-01-07 14:59:27 +00:00
|
|
|
import glob
|
|
|
|
import os.path
|
|
|
|
import re
|
2009-11-07 12:04:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
#######################
|
|
|
|
# ERROR HANDLING
|
|
|
|
|
|
|
|
def showException(type, value, tb, msg):
|
|
|
|
lst = traceback.format_exception(type, value, tb)
|
|
|
|
if msg == None:
|
|
|
|
msg = QCoreApplication.translate('Python', 'An error has occured while executing Python code:')
|
|
|
|
txt = '<font color="red">%s</font><br><br>' % msg
|
|
|
|
for s in lst:
|
|
|
|
txt += s
|
|
|
|
txt += '<br>%s<br>%s<br><br>' % (QCoreApplication.translate('Python','Python version:'), sys.version)
|
|
|
|
txt += '%s %s' % (QCoreApplication.translate('Python','Python path:'), str(sys.path))
|
|
|
|
txt = txt.replace('\n', '<br>')
|
|
|
|
txt = txt.replace(' ', ' ') # preserve whitespaces for nicer output
|
|
|
|
|
|
|
|
from qgis.core import QgsMessageOutput
|
|
|
|
msg = QgsMessageOutput.createMessageOutput()
|
|
|
|
msg.setTitle(QCoreApplication.translate('Python', 'Python error'))
|
|
|
|
msg.setMessage(txt, QgsMessageOutput.MessageHtml)
|
|
|
|
msg.showMessage()
|
|
|
|
|
|
|
|
def qgis_excepthook(type, value, tb):
|
|
|
|
showException(type, value, tb, None)
|
|
|
|
|
|
|
|
def installErrorHook():
|
|
|
|
sys.excepthook = qgis_excepthook
|
|
|
|
|
|
|
|
def uninstallErrorHook():
|
|
|
|
sys.excepthook = sys.__excepthook__
|
|
|
|
|
|
|
|
# install error hook() on module load
|
|
|
|
installErrorHook()
|
|
|
|
|
|
|
|
# initialize 'iface' object
|
|
|
|
iface = None
|
|
|
|
|
|
|
|
def initInterface(pointer):
|
|
|
|
from qgis.gui import QgisInterface
|
|
|
|
from sip import wrapinstance
|
|
|
|
global iface
|
|
|
|
iface = wrapinstance(pointer, QgisInterface)
|
|
|
|
|
|
|
|
|
|
|
|
#######################
|
|
|
|
# PLUGINS
|
|
|
|
|
|
|
|
# dictionary of plugins
|
|
|
|
plugins = {}
|
|
|
|
|
2009-12-20 22:12:16 +00:00
|
|
|
# list of active (started) plugins
|
|
|
|
active_plugins = []
|
|
|
|
|
2010-01-07 14:59:27 +00:00
|
|
|
# list of plugins in plugin directory and home plugin directory
|
|
|
|
available_plugins = []
|
|
|
|
|
2010-01-09 20:50:14 +00:00
|
|
|
def findPlugins(path):
|
|
|
|
plugins = []
|
|
|
|
for plugin in glob.glob(path + "/plugins/*"):
|
|
|
|
if os.path.isdir(plugin):
|
|
|
|
plugins.append( os.path.basename(plugin) )
|
|
|
|
|
|
|
|
return plugins
|
2010-01-07 14:59:27 +00:00
|
|
|
|
|
|
|
def updateAvailablePlugins():
|
|
|
|
from qgis.core import QgsApplication
|
|
|
|
pythonPath = unicode(QgsApplication.pkgDataPath()) + "/python"
|
|
|
|
homePythonPath = unicode(QgsApplication.qgisSettingsDirPath()) + "/python"
|
|
|
|
|
2010-01-09 20:50:14 +00:00
|
|
|
plugins = findPlugins( pythonPath )
|
|
|
|
homePlugins = findPlugins( homePythonPath )
|
2010-01-07 14:59:27 +00:00
|
|
|
|
|
|
|
# merge the lists
|
|
|
|
for p in homePlugins:
|
|
|
|
if p not in plugins:
|
|
|
|
plugins.append(p)
|
|
|
|
|
|
|
|
global available_plugins
|
|
|
|
available_plugins = plugins
|
|
|
|
|
|
|
|
# update list on start
|
|
|
|
updateAvailablePlugins()
|
|
|
|
|
|
|
|
|
2009-11-07 12:04:42 +00:00
|
|
|
def pluginMetadata(packageName, fct):
|
|
|
|
""" fetch metadata from a plugin """
|
|
|
|
try:
|
|
|
|
package = sys.modules[packageName]
|
|
|
|
return getattr(package, fct)()
|
|
|
|
except:
|
|
|
|
return "__error__"
|
|
|
|
|
|
|
|
def loadPlugin(packageName):
|
2010-01-07 14:59:27 +00:00
|
|
|
""" load plugin's package """
|
2009-11-07 12:04:42 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
__import__(packageName)
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
pass # continue...
|
|
|
|
|
|
|
|
# snake in the grass, we know it's there
|
|
|
|
sys.path_importer_cache.clear()
|
|
|
|
|
|
|
|
# retry
|
|
|
|
try:
|
|
|
|
__import__(packageName)
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
msgTemplate = QCoreApplication.translate("Python", "Couldn't load plugin '%1' from ['%2']")
|
|
|
|
msg = msgTemplate.arg(packageName).arg("', '".join(sys.path))
|
|
|
|
showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def startPlugin(packageName):
|
|
|
|
""" initialize the plugin """
|
2009-12-20 22:12:16 +00:00
|
|
|
global plugins, active_plugins, iface
|
|
|
|
|
|
|
|
if packageName in active_plugins: return False
|
2009-11-07 12:04:42 +00:00
|
|
|
|
|
|
|
package = sys.modules[packageName]
|
|
|
|
|
|
|
|
errMsg = QCoreApplication.translate("Python", "Couldn't load plugin %1" ).arg(packageName)
|
|
|
|
|
|
|
|
# create an instance of the plugin
|
|
|
|
try:
|
|
|
|
plugins[packageName] = package.classFactory(iface)
|
|
|
|
except:
|
2010-01-07 14:59:27 +00:00
|
|
|
_unloadPluginModules(packageName)
|
2009-11-07 12:04:42 +00:00
|
|
|
msg = QCoreApplication.translate("Python", "%1 due an error when calling its classFactory() method").arg(errMsg)
|
|
|
|
showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
|
|
|
|
return False
|
|
|
|
|
|
|
|
# initGui
|
|
|
|
try:
|
|
|
|
plugins[packageName].initGui()
|
|
|
|
except:
|
2010-01-07 14:59:27 +00:00
|
|
|
del plugins[packageName]
|
|
|
|
_unloadPluginModules(packageName)
|
2009-11-07 12:04:42 +00:00
|
|
|
msg = QCoreApplication.translate("Python", "%1 due an error when calling its initGui() method" ).arg( errMsg )
|
|
|
|
showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
|
|
|
|
return False
|
|
|
|
|
2009-12-20 22:12:16 +00:00
|
|
|
# add to active plugins
|
|
|
|
active_plugins.append(packageName)
|
|
|
|
|
2009-11-07 12:04:42 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def unloadPlugin(packageName):
|
|
|
|
""" unload and delete plugin! """
|
2009-12-20 22:12:16 +00:00
|
|
|
global plugins, active_plugins
|
2009-12-16 00:37:01 +00:00
|
|
|
|
|
|
|
if not plugins.has_key(packageName): return False
|
2009-12-20 22:12:16 +00:00
|
|
|
if packageName not in active_plugins: return False
|
2009-11-07 12:04:42 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
plugins[packageName].unload()
|
|
|
|
del plugins[packageName]
|
2009-12-20 22:12:16 +00:00
|
|
|
active_plugins.remove(packageName)
|
2010-01-07 14:59:27 +00:00
|
|
|
_unloadPluginModules(packageName)
|
2009-11-07 12:04:42 +00:00
|
|
|
return True
|
|
|
|
except Exception, e:
|
2009-12-15 17:47:00 +00:00
|
|
|
msg = QCoreApplication.translate("Python", "Error while unloading plugin %1").arg(packageName)
|
2009-11-07 12:04:42 +00:00
|
|
|
showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
|
|
|
|
return False
|
2009-12-20 22:12:16 +00:00
|
|
|
|
2010-01-07 14:59:27 +00:00
|
|
|
|
|
|
|
def _unloadPluginModules(packageName):
|
|
|
|
""" unload plugin package with all its modules (files) """
|
|
|
|
global _plugin_modules
|
|
|
|
mods = _plugin_modules[packageName]
|
|
|
|
|
|
|
|
for mod in mods:
|
|
|
|
# if it looks like a Qt resource file, try to do a cleanup
|
|
|
|
# otherwise we might experience a segfault next time the plugin is loaded
|
|
|
|
# because Qt will try to access invalid plugin resource data
|
|
|
|
if "resources" in mod:
|
|
|
|
try:
|
|
|
|
sys.modules[mod].qCleanupResources()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
# try to remove the module from python
|
|
|
|
try:
|
|
|
|
del sys.modules[mod]
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
# remove the plugin entry
|
|
|
|
del _plugin_modules[packageName]
|
|
|
|
|
|
|
|
|
2009-12-20 22:12:16 +00:00
|
|
|
def isPluginLoaded(packageName):
|
|
|
|
""" find out whether a plugin is active (i.e. has been started) """
|
|
|
|
global plugins, active_plugins
|
|
|
|
|
|
|
|
if not plugins.has_key(packageName): return False
|
|
|
|
return (packageName in active_plugins)
|
2010-01-07 14:59:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
def reloadPlugin(packageName):
|
|
|
|
""" unload and start again a plugin """
|
|
|
|
global active_plugins
|
|
|
|
if packageName not in active_plugins:
|
|
|
|
return # it's not active
|
|
|
|
|
|
|
|
unloadPlugin(packageName)
|
|
|
|
loadPlugin(packageName)
|
|
|
|
startPlugin(packageName)
|
|
|
|
|
|
|
|
|
|
|
|
#######################
|
|
|
|
# IMPORT wrapper
|
|
|
|
|
|
|
|
import __builtin__
|
|
|
|
|
|
|
|
_builtin_import = __builtin__.__import__
|
|
|
|
_plugin_modules = { }
|
|
|
|
|
|
|
|
def _import(name, globals={}, locals={}, fromlist=[], level=-1):
|
|
|
|
""" wrapper around builtin import that keeps track of loaded plugin modules """
|
|
|
|
mod = _builtin_import(name, globals, locals, fromlist, level)
|
|
|
|
|
|
|
|
if mod and '__file__' in mod.__dict__:
|
|
|
|
module_name = mod.__name__
|
|
|
|
package_name = module_name.split('.')[0]
|
|
|
|
# check whether the module belongs to one of our plugins
|
|
|
|
if package_name in available_plugins:
|
|
|
|
if package_name not in _plugin_modules:
|
|
|
|
_plugin_modules[package_name] = set()
|
|
|
|
_plugin_modules[package_name].add(module_name)
|
|
|
|
|
|
|
|
return mod
|
|
|
|
|
|
|
|
__builtin__.__import__ = _import
|