Improvements to GUI extension points handling - added method to remove these from PluginManager (memory optimization).
Removed logging from most of the code.
This commit is contained in:
		
							parent
							
								
									5cce0a8ca9
								
							
						
					
					
						commit
						16ac65e58b
					
				
					 12 changed files with 226 additions and 131 deletions
				
			
		| 
						 | 
				
			
			@ -38,11 +38,8 @@ class AcronymsExpanderPlugin(GajimPlugin):
 | 
			
		|||
	description = u'''Replaces acronyms (or other strings) with given expansions/substitutes.'''
 | 
			
		||||
	authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
 | 
			
		||||
	homepage = u'http://blog.bilinski.it'
 | 
			
		||||
 | 
			
		||||
	#@log_calls('AcronymsExpanderPlugin')
 | 
			
		||||
	#def __init__(self):
 | 
			
		||||
		#super(AcronymsExpanderPlugin, self).__init__()
 | 
			
		||||
		
 | 
			
		||||
	@log_calls('AcronymsExpanderPlugin')
 | 
			
		||||
	def init(self):
 | 
			
		||||
		self.config_dialog = None
 | 
			
		||||
		
 | 
			
		||||
| 
						 | 
				
			
			@ -71,20 +68,20 @@ class AcronymsExpanderPlugin(GajimPlugin):
 | 
			
		|||
		ACRONYMS = self.config['ACRONYMS']
 | 
			
		||||
		INVOKER = self.config['INVOKER']
 | 
			
		||||
		t = tb.get_text(tb.get_start_iter(), tb.get_end_iter())
 | 
			
		||||
		log.debug('%s %d'%(t, len(t)))
 | 
			
		||||
		#log.debug('%s %d'%(t, len(t)))
 | 
			
		||||
		if t and t[-1] == INVOKER:
 | 
			
		||||
			log.debug("changing msg text")
 | 
			
		||||
			#log.debug("changing msg text")
 | 
			
		||||
			base,sep,head=t[:-1].rpartition(INVOKER)
 | 
			
		||||
			log.debug('%s | %s | %s'%(base, sep, head))
 | 
			
		||||
			#log.debug('%s | %s | %s'%(base, sep, head))
 | 
			
		||||
			if head in ACRONYMS:
 | 
			
		||||
				head = ACRONYMS[head]
 | 
			
		||||
				log.debug("head: %s"%(head))
 | 
			
		||||
				t = "".join((base, sep, head, INVOKER))
 | 
			
		||||
				log.debug("turning off notify")
 | 
			
		||||
				#log.debug("turning off notify")
 | 
			
		||||
				tb.freeze_notify()
 | 
			
		||||
				log.debug("setting text: '%s'"%(t))
 | 
			
		||||
				#log.debug("setting text: '%s'"%(t))
 | 
			
		||||
				tb.set_text(t)
 | 
			
		||||
				log.debug("turning on notify")
 | 
			
		||||
				#log.debug("turning on notify")
 | 
			
		||||
				tb.thaw_notify()
 | 
			
		||||
		
 | 
			
		||||
	@log_calls('AcronymsExpanderPlugin')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,7 +94,6 @@ http://trac.gajim.org/attachment/ticket/4133'''
 | 
			
		|||
		if self.config['show_banner_resource'] or self.config['banner_small_fonts']:
 | 
			
		||||
			banner_name_label = chat_control.xml.get_widget('banner_name_label')
 | 
			
		||||
			label_text = banner_name_label.get_label()
 | 
			
		||||
			log.debug('label_text = "%s"'%(label_text))
 | 
			
		||||
						
 | 
			
		||||
			contact = chat_control.contact
 | 
			
		||||
			jid = contact.jid
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
 | 
			
		||||
<!--Generated with glade3 3.4.5 on Tue Jul 29 19:58:18 2008 -->
 | 
			
		||||
<!--Generated with glade3 3.4.5 on Sun Aug  3 13:57:25 2008 -->
 | 
			
		||||
<glade-interface>
 | 
			
		||||
  <widget class="GtkWindow" id="window1">
 | 
			
		||||
    <child>
 | 
			
		||||
| 
						 | 
				
			
			@ -12,40 +12,58 @@
 | 
			
		|||
        <property name="column_spacing">7</property>
 | 
			
		||||
        <property name="row_spacing">5</property>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkHBox" id="hbox2">
 | 
			
		||||
          <widget class="GtkLabel" id="label1">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <child>
 | 
			
		||||
              <widget class="GtkSpinButton" id="message_length_spinbutton">
 | 
			
		||||
                <property name="visible">True</property>
 | 
			
		||||
                <property name="can_focus">True</property>
 | 
			
		||||
                <property name="tooltip" translatable="yes">Message length at which notification is invoked.</property>
 | 
			
		||||
                <property name="width_chars">6</property>
 | 
			
		||||
                <property name="adjustment">0 0 999999 1 10 10</property>
 | 
			
		||||
                <property name="snap_to_ticks">True</property>
 | 
			
		||||
                <property name="numeric">True</property>
 | 
			
		||||
                <signal name="value_changed" handler="on_message_length_spinbutton_value_changed"/>
 | 
			
		||||
              </widget>
 | 
			
		||||
              <packing>
 | 
			
		||||
                <property name="expand">False</property>
 | 
			
		||||
                <property name="fill">False</property>
 | 
			
		||||
              </packing>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <widget class="GtkAlignment" id="alignment2">
 | 
			
		||||
                <property name="visible">True</property>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <placeholder/>
 | 
			
		||||
                </child>
 | 
			
		||||
              </widget>
 | 
			
		||||
              <packing>
 | 
			
		||||
                <property name="position">1</property>
 | 
			
		||||
              </packing>
 | 
			
		||||
            </child>
 | 
			
		||||
            <property name="tooltip" translatable="yes">Message length at which notification is invoked.</property>
 | 
			
		||||
            <property name="xalign">0</property>
 | 
			
		||||
            <property name="label" translatable="yes">Message length:</property>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="x_options">GTK_FILL</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkLabel" id="label2">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <property name="tooltip" translatable="yes">Background color of text entry field in chat window when notification is invoked.</property>
 | 
			
		||||
            <property name="xalign">0</property>
 | 
			
		||||
            <property name="label" translatable="yes">Notification color:</property>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="top_attach">1</property>
 | 
			
		||||
            <property name="bottom_attach">2</property>
 | 
			
		||||
            <property name="x_options">GTK_FILL</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkLabel" id="label3">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <property name="tooltip" translatable="yes">JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). Use comma (without space) as separator. If empty plugin is used with every JID. </property>
 | 
			
		||||
            <property name="xalign">0</property>
 | 
			
		||||
            <property name="label" translatable="yes">JabberIDs to include:</property>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="top_attach">2</property>
 | 
			
		||||
            <property name="bottom_attach">3</property>
 | 
			
		||||
            <property name="x_options">GTK_FILL</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkEntry" id="jids_entry">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <property name="can_focus">True</property>
 | 
			
		||||
            <property name="tooltip" translatable="yes">JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). Use comma (without space) as separator. If empty plugin is used with every JID. </property>
 | 
			
		||||
            <signal name="changed" handler="on_jids_entry_changed"/>
 | 
			
		||||
            <signal name="editing_done" handler="on_jids_entry_editing_done"/>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="left_attach">1</property>
 | 
			
		||||
            <property name="right_attach">2</property>
 | 
			
		||||
            <property name="x_options">GTK_FILL</property>
 | 
			
		||||
            <property name="top_attach">2</property>
 | 
			
		||||
            <property name="bottom_attach">3</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
| 
						 | 
				
			
			@ -91,57 +109,39 @@
 | 
			
		|||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkEntry" id="jids_entry">
 | 
			
		||||
          <widget class="GtkHBox" id="hbox2">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <property name="can_focus">True</property>
 | 
			
		||||
            <property name="tooltip" translatable="yes">JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). If empty plugin is used with every JID. [not implemented]</property>
 | 
			
		||||
            <signal name="changed" handler="on_jids_entry_changed"/>
 | 
			
		||||
            <signal name="editing_done" handler="on_jids_entry_editing_done"/>
 | 
			
		||||
            <child>
 | 
			
		||||
              <widget class="GtkSpinButton" id="message_length_spinbutton">
 | 
			
		||||
                <property name="visible">True</property>
 | 
			
		||||
                <property name="can_focus">True</property>
 | 
			
		||||
                <property name="tooltip" translatable="yes">Message length at which notification is invoked.</property>
 | 
			
		||||
                <property name="width_chars">6</property>
 | 
			
		||||
                <property name="adjustment">0 0 999999 1 10 10</property>
 | 
			
		||||
                <property name="snap_to_ticks">True</property>
 | 
			
		||||
                <property name="numeric">True</property>
 | 
			
		||||
                <signal name="value_changed" handler="on_message_length_spinbutton_value_changed"/>
 | 
			
		||||
              </widget>
 | 
			
		||||
              <packing>
 | 
			
		||||
                <property name="expand">False</property>
 | 
			
		||||
                <property name="fill">False</property>
 | 
			
		||||
              </packing>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <widget class="GtkAlignment" id="alignment2">
 | 
			
		||||
                <property name="visible">True</property>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <placeholder/>
 | 
			
		||||
                </child>
 | 
			
		||||
              </widget>
 | 
			
		||||
              <packing>
 | 
			
		||||
                <property name="position">1</property>
 | 
			
		||||
              </packing>
 | 
			
		||||
            </child>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="left_attach">1</property>
 | 
			
		||||
            <property name="right_attach">2</property>
 | 
			
		||||
            <property name="top_attach">2</property>
 | 
			
		||||
            <property name="bottom_attach">3</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkLabel" id="label3">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <property name="tooltip" translatable="yes">JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). If empty plugin is used with every JID. [not implemented]</property>
 | 
			
		||||
            <property name="xalign">0</property>
 | 
			
		||||
            <property name="label" translatable="yes">JabberIDs to include:</property>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="top_attach">2</property>
 | 
			
		||||
            <property name="bottom_attach">3</property>
 | 
			
		||||
            <property name="x_options">GTK_FILL</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkLabel" id="label2">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <property name="tooltip" translatable="yes">Background color of text entry field in chat window when notification is invoked.</property>
 | 
			
		||||
            <property name="xalign">0</property>
 | 
			
		||||
            <property name="label" translatable="yes">Notification color:</property>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="top_attach">1</property>
 | 
			
		||||
            <property name="bottom_attach">2</property>
 | 
			
		||||
            <property name="x_options">GTK_FILL</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <widget class="GtkLabel" id="label1">
 | 
			
		||||
            <property name="visible">True</property>
 | 
			
		||||
            <property name="tooltip" translatable="yes">Message length at which notification is invoked.</property>
 | 
			
		||||
            <property name="xalign">0</property>
 | 
			
		||||
            <property name="label" translatable="yes">Message length:</property>
 | 
			
		||||
          </widget>
 | 
			
		||||
          <packing>
 | 
			
		||||
            <property name="x_options">GTK_FILL</property>
 | 
			
		||||
            <property name="y_options">GTK_FILL</property>
 | 
			
		||||
          </packing>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,10 +40,6 @@ class LengthNotifierPlugin(GajimPlugin):
 | 
			
		|||
	description = u'''Highlights message entry field in chat window when given length of message is exceeded.'''
 | 
			
		||||
	authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
 | 
			
		||||
	homepage = u'http://blog.bilinski.it'
 | 
			
		||||
 | 
			
		||||
	#@log_calls('LengthNotifierPlugin')
 | 
			
		||||
	#def __init__(self):
 | 
			
		||||
		#super(LengthNotifierPlugin, self).__init__()
 | 
			
		||||
	
 | 
			
		||||
	@log_calls('LengthNotifierPlugin')
 | 
			
		||||
	def init(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +103,8 @@ class LengthNotifierPlugin(GajimPlugin):
 | 
			
		|||
			if d['prev_color']:
 | 
			
		||||
				tv.modify_base(gtk.STATE_NORMAL, d['prev_color'])
 | 
			
		||||
		except AttributeError, error:
 | 
			
		||||
			log.debug('Length Notifier Plugin was (probably) never connected with this chat window.\n Error: %s' % (error))
 | 
			
		||||
			pass
 | 
			
		||||
			#log.debug('Length Notifier Plugin was (probably) never connected with this chat window.\n Error: %s' % (error))
 | 
			
		||||
	
 | 
			
		||||
	@log_calls('LengthNotifierPlugin')
 | 
			
		||||
	def jid_is_ok(self, jid):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,14 +40,9 @@ class RosterButtonsPlugin(GajimPlugin):
 | 
			
		|||
	description = u'''Adds quick action buttons to roster window.'''
 | 
			
		||||
	authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
 | 
			
		||||
	homepage = u'http://blog.bilinski.it'
 | 
			
		||||
	
 | 
			
		||||
	#@log_calls('RosterButtonsPlugin')
 | 
			
		||||
	#def __init__(self):
 | 
			
		||||
		#super(RosterButtonsPlugin, self).__init__()
 | 
			
		||||
 | 
			
		||||
	@log_calls('RosterButtonsPlugin')	
 | 
			
		||||
	def init(self):
 | 
			
		||||
		#log.debug('self.__path__==%s'%(self.__path__))
 | 
			
		||||
		self.GLADE_FILE_PATH = self.local_file_path('roster_buttons.glade')
 | 
			
		||||
		
 | 
			
		||||
		self.roster_vbox = gajim.interface.roster.xml.get_widget('roster_vbox2')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -294,7 +294,15 @@ class ChatControlBase(MessageControl):
 | 
			
		|||
 | 
			
		||||
		self.smooth = True
 | 
			
		||||
		
 | 
			
		||||
		# PluginSystem: adding GUI extension point for ChatControlBase
 | 
			
		||||
		# instance object (also subclasses, eg. ChatControl or GroupchatControl)
 | 
			
		||||
		gajim.plugin_manager.gui_extension_point('chat_control_base', self)
 | 
			
		||||
		
 | 
			
		||||
	def shutdown(self):
 | 
			
		||||
		# PluginSystem: removing GUI extension points connected with ChatControlBase
 | 
			
		||||
		# instance object
 | 
			
		||||
		gajim.plugin_manager.remove_gui_extension_point('chat_control_base', self)
 | 
			
		||||
		gajim.plugin_manager.remove_gui_extension_point('chat_control_base_draw_banner', self)
 | 
			
		||||
 | 
			
		||||
	def on_msg_textview_populate_popup(self, textview, menu):
 | 
			
		||||
		'''we override the default context menu and we prepend an option to switch languages'''
 | 
			
		||||
| 
						 | 
				
			
			@ -1144,6 +1152,8 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
		# restore previous conversation
 | 
			
		||||
		self.restore_conversation()
 | 
			
		||||
		
 | 
			
		||||
		# PluginSystem: adding GUI extension point for this ChatControl 
 | 
			
		||||
		# instance object
 | 
			
		||||
		gajim.plugin_manager.gui_extension_point('chat_control', self)
 | 
			
		||||
 | 
			
		||||
	def on_avatar_eventbox_enter_notify_event(self, widget, event):
 | 
			
		||||
| 
						 | 
				
			
			@ -2022,6 +2032,13 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
			self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
 | 
			
		||||
	def shutdown(self):
 | 
			
		||||
		# PluginSystem: calling shutdown of super class (ChatControlBase) to let it remove
 | 
			
		||||
		# it's GUI extension points
 | 
			
		||||
		super(ChatControl, self).shutdown()
 | 
			
		||||
		# PluginSystem: removing GUI extension points connected with ChatControl
 | 
			
		||||
		# instance object
 | 
			
		||||
		gajim.plugin_manager.remove_gui_extension_point('chat_control', self)
 | 
			
		||||
		
 | 
			
		||||
		# destroy banner tooltip - bug #pygtk for that!
 | 
			
		||||
		self.status_tooltip.destroy()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1636,6 +1636,11 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
			status = self.subject)
 | 
			
		||||
 | 
			
		||||
	def shutdown(self, status='offline'):
 | 
			
		||||
		# PluginSystem: calling shutdown of super class (ChatControlBase) 
 | 
			
		||||
		# to let it remove it's GUI extension points
 | 
			
		||||
		super(GroupchatControl, self).shutdown()
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		# destroy banner tooltip - bug #pygtk for that!
 | 
			
		||||
		self.subject_tooltip.destroy()
 | 
			
		||||
		gajim.connections[self.account].send_gc_status(self.nick, self.room_jid,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ TYPE_PM = 'pm'
 | 
			
		|||
 | 
			
		||||
####################
 | 
			
		||||
 | 
			
		||||
class MessageControl:
 | 
			
		||||
class MessageControl(object):
 | 
			
		||||
	'''An abstract base widget that can embed in the gtk.Notebook of a MessageWindow'''
 | 
			
		||||
 | 
			
		||||
	def __init__(self, type_id, parent_win, widget_name, contact, account, resource = None):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -170,7 +170,7 @@ class PluginsWindow(object):
 | 
			
		|||
	
 | 
			
		||||
	@log_calls('PluginsWindow')
 | 
			
		||||
	def on_configure_plugin_button_clicked(self, widget):
 | 
			
		||||
		log.debug('widget: %s'%(widget))
 | 
			
		||||
		#log.debug('widget: %s'%(widget))
 | 
			
		||||
		selection = self.installed_plugins_treeview.get_selection()
 | 
			
		||||
		model, iter = selection.get_selected()
 | 
			
		||||
		if iter:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,8 @@ class log_calls(object):
 | 
			
		|||
    Decorator class for functions to easily log when they are entered and left.
 | 
			
		||||
    '''
 | 
			
		||||
    
 | 
			
		||||
    filter_out_classes = ['PluginManager']
 | 
			
		||||
    filter_out_classes = ['GajimPlugin', 'GajimPluginConfig',
 | 
			
		||||
                          'GajimPluginConfigDialog', 'PluginsWindow']
 | 
			
		||||
    '''
 | 
			
		||||
    List of classes from which no logs should be emited when methods are called,
 | 
			
		||||
    eventhough `log_calls` decorator is used.
 | 
			
		||||
| 
						 | 
				
			
			@ -129,10 +130,11 @@ class Singleton(type):
 | 
			
		|||
    def __call__(cls,*args,**kw):
 | 
			
		||||
        if cls.instance is None:
 | 
			
		||||
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
 | 
			
		||||
            log.debug('%(classname)s - new instance created'%{
 | 
			
		||||
                'classname' : cls.__name__})
 | 
			
		||||
            #log.debug('%(classname)s - new instance created'%{
 | 
			
		||||
                #'classname' : cls.__name__})
 | 
			
		||||
        else:
 | 
			
		||||
            log.debug('%(classname)s - returning already existing instance'%{
 | 
			
		||||
                'classname' : cls.__name__})
 | 
			
		||||
            pass
 | 
			
		||||
            #log.debug('%(classname)s - returning already existing instance'%{
 | 
			
		||||
                #'classname' : cls.__name__})
 | 
			
		||||
            
 | 
			
		||||
        return cls.instance
 | 
			
		||||
| 
						 | 
				
			
			@ -130,10 +130,22 @@ class GajimPlugin(object):
 | 
			
		|||
	def save_config(self):
 | 
			
		||||
		self.config.save()
 | 
			
		||||
	
 | 
			
		||||
	@log_calls('GajimPlugin')	
 | 
			
		||||
	@log_calls('GajimPlugin')
 | 
			
		||||
	def load_config(self):
 | 
			
		||||
		self.config.load()
 | 
			
		||||
		
 | 
			
		||||
	def __eq__(self, plugin):
 | 
			
		||||
		if self.short_name == plugin.short_name:
 | 
			
		||||
			return True
 | 
			
		||||
		
 | 
			
		||||
		return False
 | 
			
		||||
	
 | 
			
		||||
	def __ne__(self, plugin):
 | 
			
		||||
		if self.short_name != plugin.short_name:
 | 
			
		||||
			return True
 | 
			
		||||
		
 | 
			
		||||
		return False
 | 
			
		||||
		
 | 
			
		||||
	@log_calls('GajimPlugin')
 | 
			
		||||
	def local_file_path(self, file_name):
 | 
			
		||||
		return os.path.join(self.__path__, file_name)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,11 +96,11 @@ class PluginManager(object):
 | 
			
		|||
		for path in gajim.PLUGINS_DIRS:
 | 
			
		||||
			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_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):
 | 
			
		||||
| 
						 | 
				
			
			@ -120,11 +120,16 @@ class PluginManager(object):
 | 
			
		|||
		and adding class from reloaded module or ignoring adding plug-in?
 | 
			
		||||
		'''
 | 
			
		||||
		plugin = plugin_class()
 | 
			
		||||
		if not self._plugin_has_entry_in_global_config(plugin):
 | 
			
		||||
			self._create_plugin_entry_in_global_config(plugin)
 | 
			
		||||
			
 | 
			
		||||
		self.plugins.append(plugin)
 | 
			
		||||
		plugin.active = False
 | 
			
		||||
		
 | 
			
		||||
		if plugin not in self.plugins:
 | 
			
		||||
			if not self._plugin_has_entry_in_global_config(plugin):
 | 
			
		||||
				self._create_plugin_entry_in_global_config(plugin)
 | 
			
		||||
				
 | 
			
		||||
			self.plugins.append(plugin)
 | 
			
		||||
			plugin.active = False
 | 
			
		||||
		else:
 | 
			
		||||
			log.info('Not loading plugin %s v%s from module %s (identified by short name: %s). Plugin already loaded.'%(
 | 
			
		||||
				plugin.name, plugin.version, plugin.__module__, plugin.short_name))
 | 
			
		||||
	
 | 
			
		||||
	@log_calls('PluginManager')
 | 
			
		||||
	def add_plugins(self, plugin_classes):
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +139,9 @@ class PluginManager(object):
 | 
			
		|||
	@log_calls('PluginManager')
 | 
			
		||||
	def gui_extension_point(self, gui_extpoint_name, *args):
 | 
			
		||||
		'''
 | 
			
		||||
		Invokes all handlers (from plugins) for particular GUI extension point.
 | 
			
		||||
		Invokes all handlers (from plugins) for particular GUI extension point
 | 
			
		||||
		and adds it to collection for further processing (eg. by plugins not active
 | 
			
		||||
		yet).
 | 
			
		||||
		
 | 
			
		||||
		:param gui_extpoint_name: name of GUI extension point.
 | 
			
		||||
		:type gui_extpoint_name: unicode
 | 
			
		||||
| 
						 | 
				
			
			@ -157,10 +164,69 @@ class PluginManager(object):
 | 
			
		|||
 | 
			
		||||
		self._add_gui_extension_point_call_to_list(gui_extpoint_name, *args)
 | 
			
		||||
		self._execute_all_handlers_of_gui_extension_point(gui_extpoint_name, *args)
 | 
			
		||||
	
 | 
			
		||||
	@log_calls('PluginManager')
 | 
			
		||||
	def remove_gui_extension_point(self, gui_extpoint_name, *args):
 | 
			
		||||
		'''
 | 
			
		||||
		Removes GUI extension point from collection held by `PluginManager`.
 | 
			
		||||
		
 | 
			
		||||
		From this point this particular extension point won't be visible
 | 
			
		||||
		to plugins (eg. it won't invoke any handlers when plugin is activated).
 | 
			
		||||
		
 | 
			
		||||
		GUI extension point is removed completely (there is no way to recover it
 | 
			
		||||
		from inside `PluginManager`).
 | 
			
		||||
		
 | 
			
		||||
		Removal is needed when instance object that given extension point was
 | 
			
		||||
		connect with is destroyed (eg. ChatControl is closed or context menu
 | 
			
		||||
		is hidden).
 | 
			
		||||
		
 | 
			
		||||
		Each `PluginManager.gui_extension_point` call should have a call of 
 | 
			
		||||
		`PluginManager.remove_gui_extension_point` related to it.
 | 
			
		||||
 | 
			
		||||
		:note: in current implementation different arguments mean different
 | 
			
		||||
			extension points. The same arguments and the same name mean
 | 
			
		||||
			the same extension point.
 | 
			
		||||
		:todo: instead of using argument to identify which extpoint should be
 | 
			
		||||
			removed, maybe add additional 'id' argument - this would work similar
 | 
			
		||||
			hash in Python objects. 'id' would be calculated based on arguments
 | 
			
		||||
			passed or on anything else (even could be constant). This would give
 | 
			
		||||
			core developers (that add new extpoints) more freedom, but is this 
 | 
			
		||||
			necessary?
 | 
			
		||||
		
 | 
			
		||||
		:param gui_extpoint_name: name of GUI extension point.
 | 
			
		||||
		:type gui_extpoint_name: unicode
 | 
			
		||||
		:param args: arguments that `PluginManager.gui_extension_point` was
 | 
			
		||||
			called with for this extension point. This is used (along with
 | 
			
		||||
			extension point name) to identify element to be removed.
 | 
			
		||||
		:type args: tuple
 | 
			
		||||
		'''
 | 
			
		||||
		log.debug('name: %s\n args: %s'%(gui_extpoint_name, args))
 | 
			
		||||
		
 | 
			
		||||
				
 | 
			
		||||
	@log_calls('PluginManager')
 | 
			
		||||
	def _add_gui_extension_point_call_to_list(self, gui_extpoint_name, *args):
 | 
			
		||||
		self.gui_extension_points.setdefault(gui_extpoint_name, []).append(args)
 | 
			
		||||
		'''
 | 
			
		||||
		Adds GUI extension point call to list of calls.
 | 
			
		||||
		
 | 
			
		||||
		This is done only if such call hasn't been added already
 | 
			
		||||
		(same extension point name and same arguments).
 | 
			
		||||
		
 | 
			
		||||
		:note: This is assumption that GUI extension points are different only
 | 
			
		||||
		if they have different name or different arguments. 
 | 
			
		||||
		
 | 
			
		||||
		:param gui_extpoint_name: GUI extension point name used to identify it
 | 
			
		||||
			by plugins.
 | 
			
		||||
		:type gui_extpoint_name: str
 | 
			
		||||
		
 | 
			
		||||
		:param args: parameters to be passed to extension point handlers 
 | 
			
		||||
			(typically and object that invokes `gui_extension_point`; however, 
 | 
			
		||||
			this can be practically anything)
 | 
			
		||||
		:type args: tuple
 | 
			
		||||
		
 | 
			
		||||
		'''
 | 
			
		||||
		if ((gui_extpoint_name not in self.gui_extension_points)
 | 
			
		||||
			or (args not in self.gui_extension_points[gui_extpoint_name])):
 | 
			
		||||
			self.gui_extension_points.setdefault(gui_extpoint_name, []).append(args)
 | 
			
		||||
	
 | 
			
		||||
	@log_calls('PluginManager')
 | 
			
		||||
	def _execute_all_handlers_of_gui_extension_point(self, gui_extpoint_name, *args):
 | 
			
		||||
| 
						 | 
				
			
			@ -287,57 +353,62 @@ class PluginManager(object):
 | 
			
		|||
			#log.debug(sys.path)
 | 
			
		||||
 | 
			
		||||
			for elem_name in dir_list:
 | 
			
		||||
				log.debug('- "%s"'%(elem_name))
 | 
			
		||||
				#log.debug('- "%s"'%(elem_name))
 | 
			
		||||
				file_path = os.path.join(path, elem_name)
 | 
			
		||||
				log.debug('  "%s"'%(file_path))
 | 
			
		||||
				#log.debug('  "%s"'%(file_path))
 | 
			
		||||
				
 | 
			
		||||
				module = None
 | 
			
		||||
				
 | 
			
		||||
				if os.path.isfile(file_path) and fnmatch.fnmatch(file_path,'*.py'):
 | 
			
		||||
					module_name = os.path.splitext(elem_name)[0]
 | 
			
		||||
					log.debug('Possible module detected.')
 | 
			
		||||
					#log.debug('Possible module detected.')
 | 
			
		||||
					try:
 | 
			
		||||
						module = __import__(module_name)
 | 
			
		||||
						log.debug('Module imported.')
 | 
			
		||||
						#log.debug('Module imported.')
 | 
			
		||||
					except ValueError, value_error:
 | 
			
		||||
						log.debug('Module not imported successfully. ValueError: %s'%(value_error))
 | 
			
		||||
						pass
 | 
			
		||||
						#log.debug('Module not imported successfully. ValueError: %s'%(value_error))
 | 
			
		||||
					except ImportError, import_error:
 | 
			
		||||
						log.debug('Module not imported successfully. ImportError: %s'%(import_error))
 | 
			
		||||
						pass
 | 
			
		||||
						#log.debug('Module not imported successfully. ImportError: %s'%(import_error))
 | 
			
		||||
					
 | 
			
		||||
				elif os.path.isdir(file_path):
 | 
			
		||||
					module_name = elem_name
 | 
			
		||||
					file_path += os.path.sep
 | 
			
		||||
					log.debug('Possible package detected.')
 | 
			
		||||
					#log.debug('Possible package detected.')
 | 
			
		||||
					try:
 | 
			
		||||
						module = __import__(module_name)
 | 
			
		||||
						log.debug('Package imported.')
 | 
			
		||||
						#log.debug('Package imported.')
 | 
			
		||||
					except ValueError, value_error:
 | 
			
		||||
						log.debug('Package not imported successfully. ValueError: %s'%(value_error))
 | 
			
		||||
						pass
 | 
			
		||||
						#log.debug('Package not imported successfully. ValueError: %s'%(value_error))
 | 
			
		||||
					except ImportError, import_error:
 | 
			
		||||
						log.debug('Package not imported successfully. ImportError: %s'%(import_error))
 | 
			
		||||
						pass
 | 
			
		||||
						#log.debug('Package not imported successfully. ImportError: %s'%(import_error))
 | 
			
		||||
					
 | 
			
		||||
					
 | 
			
		||||
				if module:
 | 
			
		||||
					log.debug('Attributes processing started')
 | 
			
		||||
					#log.debug('Attributes processing started')
 | 
			
		||||
					for module_attr_name in [attr_name for attr_name in dir(module) 
 | 
			
		||||
											 if not (attr_name.startswith('__') or 
 | 
			
		||||
													 attr_name.endswith('__'))]:
 | 
			
		||||
						module_attr = getattr(module, module_attr_name)
 | 
			
		||||
						log.debug('%s : %s'%(module_attr_name, module_attr))
 | 
			
		||||
						#log.debug('%s : %s'%(module_attr_name, module_attr))
 | 
			
		||||
						
 | 
			
		||||
						try:
 | 
			
		||||
							if issubclass(module_attr, GajimPlugin) and \
 | 
			
		||||
							   not module_attr is GajimPlugin:
 | 
			
		||||
								log.debug('is subclass of GajimPlugin')
 | 
			
		||||
								#log.debug('is subclass of GajimPlugin')
 | 
			
		||||
								#log.debug('file_path: %s\nabspath: %s\ndirname: %s'%(file_path, os.path.abspath(file_path), os.path.dirname(os.path.abspath(file_path))))
 | 
			
		||||
								#log.debug('file_path: %s\ndirname: %s\nabspath: %s'%(file_path, os.path.dirname(file_path), os.path.abspath(os.path.dirname(file_path))))
 | 
			
		||||
								module_attr.__path__ = os.path.abspath(os.path.dirname(file_path))
 | 
			
		||||
								plugins_found.append(module_attr)
 | 
			
		||||
						except TypeError, type_error:
 | 
			
		||||
							log.debug('module_attr: %s, error : %s'%(
 | 
			
		||||
								module_name+'.'+module_attr_name,
 | 
			
		||||
								type_error))
 | 
			
		||||
							pass
 | 
			
		||||
							#log.debug('module_attr: %s, error : %s'%(
 | 
			
		||||
								#module_name+'.'+module_attr_name,
 | 
			
		||||
								#type_error))
 | 
			
		||||
 | 
			
		||||
					log.debug(module)
 | 
			
		||||
					#log.debug(module)
 | 
			
		||||
 | 
			
		||||
		return plugins_found
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue