Added new 'init' method to Plugin class that plugins can implement to make actions that need to be done only once - when plugin is added (not activated) to Gajim. In this method plugins should declare handlers for GUI extension points. This was created so that __init__ method doesn't have to be reimplemented in specific way (create config, load config) - it is all done by __init__ in Plugin class. If __init__ is reimplemented, it must call Plugin __init__ (eg. using super() ) to plugin work properly.

Example plug-ins were modified to use init() instead of __init__().

Added new category in configuration - 'plugins'. It only holds one option for each plugin - 'active', which determines whether plugin should be activated on startup.

Now, Gajim remembers which plugins are active on exit, and activates them on next startup.
This commit is contained in:
Mateusz Biliński 2008-06-18 20:45:22 +00:00
parent b6593b9493
commit 8581b862e1
8 changed files with 109 additions and 70 deletions

View file

@ -19,7 +19,7 @@
Acronyms expander plugin. Acronyms expander plugin.
:author: Mateusz Biliński <mateusz@bilinski.it> :author: Mateusz Biliński <mateusz@bilinski.it>
:since: 06/10/2008 :since: 9th June 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL :license: GPL
''' '''
@ -39,10 +39,11 @@ class AcronymsExpanderPlugin(GajimPlugin):
authors = [u'Mateusz Biliński <mateusz@bilinski.it>'] authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it' homepage = u'http://blog.bilinski.it'
@log_calls('AcronymsExpanderPlugin') #@log_calls('AcronymsExpanderPlugin')
def __init__(self): #def __init__(self):
super(AcronymsExpanderPlugin, self).__init__() #super(AcronymsExpanderPlugin, self).__init__()
def init(self):
self.gui_extension_points = { self.gui_extension_points = {
'chat_control_base' : (self.connect_with_chat_control_base, 'chat_control_base' : (self.connect_with_chat_control_base,
self.disconnect_from_chat_control_base) self.disconnect_from_chat_control_base)
@ -56,7 +57,7 @@ class AcronymsExpanderPlugin(GajimPlugin):
'GNT-' : 'http://trac.gajim.org/newticket', 'GNT-' : 'http://trac.gajim.org/newticket',
'GW-' : 'http://trac.gajim.org/', 'GW-' : 'http://trac.gajim.org/',
'GTS-' : 'http://trac.gajim.org/report' 'GTS-' : 'http://trac.gajim.org/report'
} }
@log_calls('AcronymsExpanderPlugin') @log_calls('AcronymsExpanderPlugin')
def textbuffer_live_acronym_expander(self, tb): def textbuffer_live_acronym_expander(self, tb):
@ -98,4 +99,5 @@ class AcronymsExpanderPlugin(GajimPlugin):
d = chat_control.acronyms_expander_plugin_data d = chat_control.acronyms_expander_plugin_data
tv = chat_control.msg_textview tv = chat_control.msg_textview
tv.get_buffer().disconnect(d['h_id']) tv.get_buffer().disconnect(d['h_id'])

View file

@ -19,7 +19,7 @@
Message length notifier plugin. Message length notifier plugin.
:author: Mateusz Biliński <mateusz@bilinski.it> :author: Mateusz Biliński <mateusz@bilinski.it>
:since: 06/01/2008 :since: 1st June 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL :license: GPL
''' '''
@ -39,10 +39,12 @@ class LengthNotifierPlugin(GajimPlugin):
authors = [u'Mateusz Biliński <mateusz@bilinski.it>'] authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it' homepage = u'http://blog.bilinski.it'
#@log_calls('LengthNotifierPlugin')
#def __init__(self):
#super(LengthNotifierPlugin, self).__init__()
@log_calls('LengthNotifierPlugin') @log_calls('LengthNotifierPlugin')
def __init__(self): def init(self):
super(LengthNotifierPlugin, self).__init__()
self.gui_extension_points = { self.gui_extension_points = {
'chat_control' : (self.connect_with_chat_control, 'chat_control' : (self.connect_with_chat_control,
self.disconnect_from_chat_control) self.disconnect_from_chat_control)

View file

@ -19,7 +19,7 @@
Roster buttons plug-in. Roster buttons plug-in.
:author: Mateusz Biliński <mateusz@bilinski.it> :author: Mateusz Biliński <mateusz@bilinski.it>
:since: 06/10/2008 :since: 14th June 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL :license: GPL
''' '''
@ -44,23 +44,24 @@ class RosterButtonsPlugin(GajimPlugin):
#@log_calls('RosterButtonsPlugin') #@log_calls('RosterButtonsPlugin')
#def __init__(self): #def __init__(self):
#super(RosterButtonsPlugin, self).__init__() #super(RosterButtonsPlugin, self).__init__()
@log_calls('RosterButtonsPlugin') @log_calls('RosterButtonsPlugin')
def activate(self): def init(self):
#log.debug('self.__path__==%s'%(self.__path__)) #log.debug('self.__path__==%s'%(self.__path__))
self.GLADE_FILE_PATH = self.local_file_path('roster_buttons.glade') self.GLADE_FILE_PATH = self.local_file_path('roster_buttons.glade')
self.roster_vbox = gajim.interface.roster.xml.get_widget('roster_vbox2')
self.show_offline_contacts_menuitem = gajim.interface.roster.xml.get_widget('show_offline_contacts_menuitem')
@log_calls('RosterButtonsPlugin')
def activate(self):
self.xml = gtk.glade.XML(self.GLADE_FILE_PATH, root='roster_buttons_buttonbox', domain=i18n.APP) self.xml = gtk.glade.XML(self.GLADE_FILE_PATH, root='roster_buttons_buttonbox', domain=i18n.APP)
self.buttonbox = self.xml.get_widget('roster_buttons_buttonbox') self.buttonbox = self.xml.get_widget('roster_buttons_buttonbox')
self.roster_vbox = gajim.interface.roster.xml.get_widget('roster_vbox2')
self.roster_vbox.pack_start(self.buttonbox, expand=False) self.roster_vbox.pack_start(self.buttonbox, expand=False)
self.roster_vbox.reorder_child(self.buttonbox, 0) self.roster_vbox.reorder_child(self.buttonbox, 0)
self.show_offline_contacts_menuitem = gajim.interface.roster.xml.get_widget('show_offline_contacts_menuitem')
self.xml.signal_autoconnect(self) self.xml.signal_autoconnect(self)
@log_calls('RosterButtonsPlugin') @log_calls('RosterButtonsPlugin')
def deactivate(self): def deactivate(self):
self.roster_vbox.remove(self.buttonbox) self.roster_vbox.remove(self.buttonbox)
@ -72,7 +73,6 @@ class RosterButtonsPlugin(GajimPlugin):
def on_roster_button_1_clicked(self, button): def on_roster_button_1_clicked(self, button):
#gajim.interface.roster.on_show_offline_contacts_menuitem_activate(None) #gajim.interface.roster.on_show_offline_contacts_menuitem_activate(None)
self.show_offline_contacts_menuitem.set_active(not self.show_offline_contacts_menuitem.get_active()) self.show_offline_contacts_menuitem.set_active(not self.show_offline_contacts_menuitem.get_active())
@log_calls('RosterButtonsPlugin') @log_calls('RosterButtonsPlugin')
def on_roster_button_2_clicked(self, button): def on_roster_button_2_clicked(self, button):

View file

@ -390,6 +390,9 @@ class Config:
'roster': [opt_str, '', _("'yes', 'no' or ''")], 'roster': [opt_str, '', _("'yes', 'no' or ''")],
'urgency_hint': [opt_bool, False], 'urgency_hint': [opt_bool, False],
}, {}), }, {}),
'plugins': ({
'active': [opt_bool, False, _('State whether plugins should be activated on exit (this is saved on Gajim exit). This option SHOULD NOT be used to (de)activate plug-ins. Use GUI instead.')],
},{}),
} }
statusmsg_default = { statusmsg_default = {

View file

@ -377,6 +377,8 @@ class GajimRemote:
except: except:
raise exceptions.SessionBusNotPresent raise exceptions.SessionBusNotPresent
from pprint import pprint
pprint(list(self.sbus.list_names()))
if not self.check_gajim_running(): if not self.check_gajim_running():
send_error(_('It seems Gajim is not running. So you can\'t use gajim-remote.')) send_error(_('It seems Gajim is not running. So you can\'t use gajim-remote.'))
obj = self.sbus.get_object(SERVICE, OBJ_PATH) obj = self.sbus.get_object(SERVICE, OBJ_PATH)

View file

@ -139,20 +139,20 @@ class PluginsWindow(object):
self.installed_plugins_model.clear() self.installed_plugins_model.clear()
self.installed_plugins_model.set_sort_column_id(0, gtk.SORT_ASCENDING) self.installed_plugins_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
for plugin_class in pm.plugins: for plugin in pm.plugins:
self.installed_plugins_model.append([plugin_class, self.installed_plugins_model.append([plugin,
plugin_class.name, plugin.name,
plugin_class._active]) plugin.active])
@log_calls('PluginsWindow') @log_calls('PluginsWindow')
def installed_plugins_toggled_cb(self, cell, path): def installed_plugins_toggled_cb(self, cell, path):
is_active = self.installed_plugins_model[path][2] is_active = self.installed_plugins_model[path][2]
plugin_class = self.installed_plugins_model[path][0] plugin = self.installed_plugins_model[path][0]
if is_active: if is_active:
gajim.plugin_manager.deactivate_plugin(plugin_class._instance) gajim.plugin_manager.deactivate_plugin(plugin)
else: else:
gajim.plugin_manager.activate_plugin(plugin_class) gajim.plugin_manager.activate_plugin(plugin)
self.installed_plugins_model[path][2] = not is_active self.installed_plugins_model[path][2] = not is_active

View file

@ -19,7 +19,7 @@
Base class for implementing plugin. Base class for implementing plugin.
:author: Mateusz Biliński <mateusz@bilinski.it> :author: Mateusz Biliński <mateusz@bilinski.it>
:since: 06/01/2008 :since: 1st June 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL :license: GPL
''' '''
@ -104,15 +104,15 @@ class GajimPlugin(object):
:type: `plugins.plugin.Config` :type: `plugins.plugin.Config`
''' '''
self.load_config()
self._load_config() self.init()
@log_calls('GajimPlugin') @log_calls('GajimPlugin')
def _save_config(self): def save_config(self):
pass pass
@log_calls('GajimPlugin') @log_calls('GajimPlugin')
def _load_config(self): def load_config(self):
pass pass
@log_calls('GajimPlugin') @log_calls('GajimPlugin')
@ -122,6 +122,10 @@ class GajimPlugin(object):
@log_calls('GajimPlugin') @log_calls('GajimPlugin')
def local_file_path(self, file_name): def local_file_path(self, file_name):
return os.path.join(self.__path__, file_name) return os.path.join(self.__path__, file_name)
@log_calls('GajimPlugin')
def init(self):
pass
@log_calls('GajimPlugin') @log_calls('GajimPlugin')
def activate(self): def activate(self):

View file

@ -19,7 +19,7 @@
Plug-in management related classes. Plug-in management related classes.
:author: Mateusz Biliński <mateusz@bilinski.it> :author: Mateusz Biliński <mateusz@bilinski.it>
:since: 05/30/2008 :since: 30th May 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL :license: GPL
''' '''
@ -94,29 +94,42 @@ class PluginManager(object):
''' '''
for path in gajim.PLUGINS_DIRS: for path in gajim.PLUGINS_DIRS:
self._add_plugins(PluginManager.scan_dir_for_plugins(path)) self.add_plugins(PluginManager.scan_dir_for_plugins(path))
log.debug('plugins: %s'%(self.plugins)) log.debug('plugins: %s'%(self.plugins))
self.activate_all_plugins() self._activate_all_plugins_from_global_config()
log.debug('active: %s'%(self.active_plugins)) log.debug('active: %s'%(self.active_plugins))
@log_calls('PluginManager')
def _plugin_has_entry_in_global_config(self, plugin):
if gajim.config.get_per('plugins', plugin.short_name) is None:
return False
else:
return True
@log_calls('PluginManager')
def _create_plugin_entry_in_global_config(self, plugin):
gajim.config.add_per('plugins', plugin.short_name)
@log_calls('PluginManager') @log_calls('PluginManager')
def _add_plugin(self, plugin_class): def add_plugin(self, plugin_class):
''' '''
:todo: what about adding plug-ins that are already added? Module reload :todo: what about adding plug-ins that are already added? Module reload
and adding class from reloaded module or ignoring adding plug-in? and adding class from reloaded module or ignoring adding plug-in?
''' '''
plugin_class._active = False plugin = plugin_class()
plugin_class._instance = None if not self._plugin_has_entry_in_global_config(plugin):
self.plugins.append(plugin_class) self._create_plugin_entry_in_global_config(plugin)
self.plugins.append(plugin)
plugin.active = False
@log_calls('PluginManager') @log_calls('PluginManager')
def _add_plugins(self, plugin_classes): def add_plugins(self, plugin_classes):
for plugin_class in plugin_classes: for plugin_class in plugin_classes:
self._add_plugin(plugin_class) self.add_plugin(plugin_class)
@log_calls('PluginManager') @log_calls('PluginManager')
def gui_extension_point(self, gui_extpoint_name, *args): def gui_extension_point(self, gui_extpoint_name, *args):
@ -156,33 +169,36 @@ class PluginManager(object):
handlers[0](*args) handlers[0](*args)
@log_calls('PluginManager') @log_calls('PluginManager')
def activate_plugin(self, plugin_class): def activate_plugin(self, plugin):
''' '''
:param plugin: plugin to be activated :param plugin: plugin to be activated
:type plugin: class object of `GajimPlugin` subclass :type plugin: class object of `GajimPlugin` subclass
'''
plugin_object = plugin_class() :todo: success checks should be implemented using exceptions. Such
control should also be implemented in deactivation.
success = True '''
success = False
self._add_gui_extension_points_handlers_from_plugin(plugin_object) if not plugin.active:
self._handle_all_gui_extension_points_with_plugin(plugin_object)
self._add_gui_extension_points_handlers_from_plugin(plugin)
if success: self._handle_all_gui_extension_points_with_plugin(plugin)
self.active_plugins.append(plugin_object)
plugin_object.activate() success = True
plugin_class._instance = plugin_object
plugin_class._active = True if success:
self.active_plugins.append(plugin)
plugin.activate()
self._set_plugin_active_in_global_config(plugin)
plugin.active = True
return success return success
def deactivate_plugin(self, plugin_object): def deactivate_plugin(self, plugin):
# detaching plug-in from handler GUI extension points (calling # detaching plug-in from handler GUI extension points (calling
# cleaning up method that must be provided by plug-in developer # cleaning up method that must be provided by plug-in developer
# for each handled GUI extension point) # for each handled GUI extension point)
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin_object.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
if gui_extpoint_name in self.gui_extension_points: if gui_extpoint_name in self.gui_extension_points:
for gui_extension_point_args in self.gui_extension_points[gui_extpoint_name]: for gui_extension_point_args in self.gui_extension_points[gui_extpoint_name]:
gui_extpoint_handlers[1](*gui_extension_point_args) gui_extpoint_handlers[1](*gui_extension_point_args)
@ -190,45 +206,55 @@ class PluginManager(object):
# remove GUI extension points handlers (provided by plug-in) from # remove GUI extension points handlers (provided by plug-in) from
# handlers list # handlers list
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin_object.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers[gui_extpoint_name].remove(gui_extpoint_handlers) self.gui_extension_points_handlers[gui_extpoint_name].remove(gui_extpoint_handlers)
# removing plug-in from active plug-ins list # removing plug-in from active plug-ins list
plugin_object.deactivate() plugin.deactivate()
self.active_plugins.remove(plugin_object) self.active_plugins.remove(plugin)
plugin_object.__class__._active = False self._set_plugin_active_in_global_config(plugin, False)
plugin_object.__class__._instance = None plugin.active = False
del plugin_object
def deactivate_all_plugins(self): def _deactivate_all_plugins(self):
for plugin_object in self.active_plugins: for plugin_object in self.active_plugins:
self.deactivate_plugin(plugin_object) self.deactivate_plugin(plugin_object)
@log_calls('PluginManager') @log_calls('PluginManager')
def _add_gui_extension_points_handlers_from_plugin(self, plugin_object): def _add_gui_extension_points_handlers_from_plugin(self, plugin):
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin_object.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers.setdefault(gui_extpoint_name, []).append( self.gui_extension_points_handlers.setdefault(gui_extpoint_name, []).append(
gui_extpoint_handlers) gui_extpoint_handlers)
@log_calls('PluginManager') @log_calls('PluginManager')
def _handle_all_gui_extension_points_with_plugin(self, plugin_object): def _handle_all_gui_extension_points_with_plugin(self, plugin):
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin_object.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
if gui_extpoint_name in self.gui_extension_points: if gui_extpoint_name in self.gui_extension_points:
for gui_extension_point_args in self.gui_extension_points[gui_extpoint_name]: for gui_extension_point_args in self.gui_extension_points[gui_extpoint_name]:
gui_extpoint_handlers[0](*gui_extension_point_args) gui_extpoint_handlers[0](*gui_extension_point_args)
@log_calls('PluginManager') @log_calls('PluginManager')
def activate_all_plugins(self): def _activate_all_plugins(self):
''' '''
Activates all plugins in `plugins`. Activates all plugins in `plugins`.
Activated plugins are appended to `active_plugins` list. Activated plugins are appended to `active_plugins` list.
''' '''
self.active_plugins = [] #self.active_plugins = []
for plugin in self.plugins: for plugin in self.plugins:
self.activate_plugin(plugin) self.activate_plugin(plugin)
def _activate_all_plugins_from_global_config(self):
for plugin in self.plugins:
if self._plugin_is_active_in_global_config(plugin):
self.activate_plugin(plugin)
def _plugin_is_active_in_global_config(self, plugin):
return gajim.config.get_per('plugins', plugin.short_name, 'active')
def _set_plugin_active_in_global_config(self, plugin, active=True):
gajim.config.set_per('plugins', plugin.short_name, 'active', active)
@staticmethod @staticmethod
@log_calls('PluginManager') @log_calls('PluginManager')