00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 import __builtin__
00032 import os
00033 import sys
00034 import traceback
00035 from xml.etree import ElementTree
00036
00037 from python_qt_binding.QtCore import qCritical
00038
00039 from qt_gui.plugin_descriptor import PluginDescriptor
00040 from qt_gui.plugin_provider import PluginProvider
00041 from qt_gui.ros_package_helper import get_package_path
00042
00043
00044 class RosPluginProvider(PluginProvider):
00045
00046 """Base class for providing plugins based on the ROS package system."""
00047
00048 def __init__(self, export_tag, base_class_type):
00049 super(RosPluginProvider, self).__init__()
00050 self.setObjectName('RosPluginProvider')
00051
00052 self._export_tag = export_tag
00053 self._base_class_type = base_class_type
00054 self._plugin_descriptors = {}
00055
00056 def discover(self, discovery_data):
00057 """
00058 Discover the plugins.
00059 The information of the `PluginDescriptor`s are extracted from the plugin manifests.
00060 """
00061
00062 plugin_descriptors = []
00063 plugin_file_list = self._find_plugins(self._export_tag, discovery_data)
00064 for package_name, plugin_xml in plugin_file_list:
00065 plugin_descriptors += self._parse_plugin_xml(package_name, plugin_xml)
00066
00067 for plugin_descriptor in plugin_descriptors:
00068 self._plugin_descriptors[plugin_descriptor.plugin_id()] = plugin_descriptor
00069 return plugin_descriptors
00070
00071 def load(self, plugin_id, plugin_context):
00072
00073 attributes = self._plugin_descriptors[plugin_id].attributes()
00074 sys.path.append(os.path.join(attributes['plugin_path'], attributes['library_path']))
00075
00076 try:
00077 module = __builtin__.__import__(attributes['module_name'], fromlist=[attributes['class_from_class_type']], level=0)
00078 except NotImplementedError as e:
00079 qCritical('RosPluginProvider.load(%s): raised an exception:\n%s' % (plugin_id, e))
00080 return None
00081 except Exception as e:
00082 qCritical('RosPluginProvider.load(%s) exception raised in __builtin__.__import__(%s, [%s]):\n%s' % (plugin_id, attributes['module_name'], attributes['class_from_class_type'], traceback.format_exc()))
00083 raise e
00084
00085 class_ref = getattr(module, attributes['class_from_class_type'], None)
00086 if class_ref is None:
00087 qCritical('RosPluginProvider.load(%s): could not find class "%s" in module "%s"' % (plugin_id, attributes['class_from_class_type'], module))
00088 return None
00089
00090
00091 if class_ref.__init__.func_code.co_argcount == 1 and plugin_context is None:
00092 return class_ref()
00093
00094 return class_ref(plugin_context)
00095
00096 def unload(self, plugin_instance):
00097 pass
00098
00099 def _find_plugins(self, export_tag, discovery_data):
00100 raise NotImplementedError
00101
00102 def _parse_plugin_xml(self, package_name, plugin_xml):
00103 plugin_descriptors = []
00104
00105 if not os.path.isfile(plugin_xml):
00106 qCritical('RosPluginProvider._parse_plugin_xml() plugin file "%s" in package "%s" not found' % (plugin_xml, package_name))
00107 return plugin_descriptors
00108
00109 try:
00110 root = ElementTree.parse(plugin_xml)
00111 except Exception:
00112 qCritical('RosPluginProvider._parse_plugin_xml() could not parse "%s" in package "%s"' % (plugin_xml, package_name))
00113 return plugin_descriptors
00114 for library_el in root.getiterator('library'):
00115 library_path = library_el.attrib['path']
00116
00117 for class_el in library_el.getiterator('class'):
00118
00119 attributes = {
00120 'package_name': package_name,
00121 'plugin_path': os.path.dirname(plugin_xml),
00122 'library_path': library_path,
00123 }
00124
00125
00126 for key, value in class_el.items():
00127 attributes['class_' + key] = value
00128
00129
00130 class_base_class_type = attributes.get('class_base_class_type', None)
00131 if class_base_class_type != self._base_class_type:
00132 continue
00133
00134
00135 plugin_id = package_name
00136 if 'class_name' in attributes:
00137 plugin_id = plugin_id + '/' + attributes['class_name']
00138 attributes['plugin_id'] = plugin_id
00139
00140
00141 module_name, class_from_class_type = attributes['class_type'].rsplit('.', 1)
00142 attributes['module_name'] = module_name
00143 attributes['class_from_class_type'] = class_from_class_type
00144
00145
00146 attributes['not_available'] = ''
00147
00148 plugin_descriptor = PluginDescriptor(plugin_id, attributes)
00149
00150
00151 action_attributes, groups = self._parse_plugin(class_el)
00152 if len(action_attributes) > 0:
00153 plugin_descriptor.set_action_attributes(
00154 action_attributes['label'],
00155 action_attributes.get('statustip', None),
00156 action_attributes.get('icon', None),
00157 action_attributes.get('icontype', None),
00158 )
00159
00160 for group in groups:
00161 plugin_descriptor.add_group_attributes(
00162 group['label'],
00163 group.get('statustip', None),
00164 group.get('icon', None),
00165 group.get('icontype', None),
00166 )
00167
00168
00169 plugin_descriptors.append(plugin_descriptor)
00170
00171 return plugin_descriptors
00172
00173 def _parse_plugin(self, class_el):
00174
00175 plugin_attributes = {}
00176 groups = []
00177
00178
00179 guiplugin_el = class_el.find('qtgui')
00180 if guiplugin_el is not None:
00181 plugin_attributes.update(self._parse_action_group(guiplugin_el))
00182 for group_el in guiplugin_el.getiterator('group'):
00183 groups.append(self._parse_action_group(group_el))
00184
00185 return plugin_attributes, groups
00186
00187 def _parse_action_group(self, group_el):
00188 attributes = {}
00189 for tag in ['label', 'icon', 'statustip']:
00190 text = group_el.findtext(tag)
00191 if text:
00192 attributes[tag] = str(text)
00193
00194 icon_el = group_el.find('icon')
00195 if icon_el is not None:
00196 icon_type_attrib = icon_el.get('type')
00197 if icon_type_attrib is not None:
00198 attributes['icontype'] = str(icon_type_attrib)
00199
00200 return attributes