merge presence handling modifications changes

This commit is contained in:
Yann Leboulanger 2010-09-23 21:43:07 +02:00
commit e0ac19678c
31 changed files with 290 additions and 199 deletions

View File

@ -270,6 +270,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
@ -292,6 +294,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of formattings</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
@ -324,6 +328,8 @@
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Add this contact to roster (Ctrl+D)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image9">
@ -365,6 +371,8 @@
<object class="GtkToggleButton" id="audio_togglebutton">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Toggle audio session</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="audio_image">
@ -383,6 +391,8 @@
<object class="GtkToggleButton" id="video_togglebutton">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Toggle video session</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="video_image">
@ -403,6 +413,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Invite contacts to the conversation (Ctrl+G)</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
@ -425,6 +437,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show the contact's profile (Ctrl+I)</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
@ -447,6 +461,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Browse the chat history (Ctrl+H)</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
@ -480,6 +496,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a menu of advanced functions (Alt+D)</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>

View File

@ -166,6 +166,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="emoticons_button_image">
@ -193,6 +195,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of formattings</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
@ -224,6 +228,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Change your nickname (Ctrl+N)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image4">
@ -246,6 +252,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Change the room's subject (Alt+T)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image6">
@ -269,6 +277,8 @@
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Bookmark this room (Ctrl+B)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image7">
@ -291,6 +301,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Browse the chat history (Ctrl+H)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image8">
@ -323,6 +335,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a menu of advanced functions (Alt+D)</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>

View File

@ -3,8 +3,8 @@ INCLUDES = \
gajimpluginsdir = $(gajim_pluginsdir)
nobase_dist_gajimplugins_PYTHON = \
$(srcdir)/*.py \
$(srcdir)/*/*.py \
$(srcdir)/*/manifest.ini \
$(srcdir)/*/*.ui
MAINTAINERCLEANFILES = Makefile.in

View File

@ -0,0 +1 @@
from acronyms_expander import AcronymsExpanderPlugin

View File

@ -33,12 +33,6 @@ from plugins import GajimPlugin
from plugins.helpers import log, log_calls
class AcronymsExpanderPlugin(GajimPlugin):
name = u'Acronyms Expander'
short_name = u'acronyms_expander'
version = u'0.1'
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):

View File

@ -0,0 +1,9 @@
[info]
name: Acronyms Expander
short_name: acronyms_expander
version: 0.1
description: Replaces acronyms (or other strings) with given expansions/substitutes.
authors: Mateusz Biliński <mateusz@bilinski.it>
homepage: http://blog.bilinski.it

View File

@ -0,0 +1,10 @@
[info]
name: Banner Tweaks
short_name: banner_tweaks
version: 0.1
description: Allows user to tweak chat window banner appearance (eg. make it compact).
Based on patch by pb in ticket #4133:
http://trac.gajim.org/attachment/ticket/4133.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -43,15 +43,6 @@ from plugins.helpers import log, log_calls
from plugins.gui import GajimPluginConfigDialog
class BannerTweaksPlugin(GajimPlugin):
name = u'Banner Tweaks'
short_name = u'banner_tweaks'
version = u'0.1'
description = u'''Allows user to tweak chat window banner appearance (eg. make it compact).
Based on patch by pb in ticket #4133:
http://trac.gajim.org/attachment/ticket/4133'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('BannerTweaksPlugin')
def init(self):

View File

@ -0,0 +1,10 @@
[info]
name: D-Bus Support
short_name: dbus
version: 0.1
description: D-Bus support. Based on remote_control module from
Gajim core but uses new events handling system.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -680,13 +680,6 @@ from plugins.helpers import log_calls, log
from common import ged
class DBusPlugin(GajimPlugin):
name = u'D-Bus Support'
short_name = u'dbus'
version = u'0.1'
description = u'''D-Bus support. Based on remote_control module from
Gajim core but uses new events handling system.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('DBusPlugin')
def init(self):

View File

@ -0,0 +1,8 @@
[info]
name: Events Dump
short_name: events_dump
version: 0.1
description: Dumps info about selected events to console.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -33,12 +33,6 @@ from plugins.helpers import log_calls, log
from common import ged
class EventsDumpPlugin(GajimPlugin):
name = u'Events Dump'
short_name = u'events_dump'
version = u'0.1'
description = u'''Dumps info about selected events to console.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('EventsDumpPlugin')
def init(self):

View File

@ -0,0 +1,8 @@
[info]
name: Google Translation
short_name: google_translation
version: 0.1
description: Translates (currently only incoming) messages using Google Translate.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -41,12 +41,6 @@ from common import ged
from common import nec
class GoogleTranslationPlugin(GajimPlugin):
name = u'Google Translation'
short_name = u'google_translation'
version = u'0.1'
description = u'''Translates (currently only incoming) messages using Google Translate.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('GoogleTranslationPlugin')
def init(self):

View File

@ -34,12 +34,6 @@ from plugins.helpers import log, log_calls
from plugins.gui import GajimPluginConfigDialog
class LengthNotifierPlugin(GajimPlugin):
name = u'Message Length Notifier'
short_name = u'length_notifier'
version = u'0.1'
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):

View File

@ -0,0 +1,9 @@
[info]
name: Message Length Notifier
short_name: length_notifier
version: 0.1
description: Highlights message entry field in chat window when given length of message is exceeded.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -0,0 +1,11 @@
[info]
name: New Events Example
short_name: new_events_example
version: 0.1
description: Shows how to generate new network events based on existing one using Network Events Controller.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -38,12 +38,6 @@ from common import ged
from common import nec
class NewEventsExamplePlugin(GajimPlugin):
name = u'New Events Example'
short_name = u'new_events_example'
version = u'0.1'
description = u'''Shows how to generate new network events based on existing one using Network Events Controller.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('NewEventsExamplePlugin')
def init(self):

View File

@ -0,0 +1,10 @@
[info]
name: Roster Buttons
short_name: roster_buttons
version: 0.1
description: Adds quick action buttons to roster window.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -34,12 +34,6 @@ from plugins import GajimPlugin
from plugins.helpers import log, log_calls
class RosterButtonsPlugin(GajimPlugin):
name = u'Roster Buttons'
short_name = u'roster_buttons'
version = u'0.1'
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):

View File

@ -0,0 +1,11 @@
[info]
name: Snarl Notifications
short_name: snarl_notifications
version: 0.1
description: Shows events notification using Snarl (http://www.fullphat.net/) under Windows. Snarl needs to be installed in system.
PySnarl bindings are used (http://code.google.com/p/pysnarl/).
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View File

@ -38,13 +38,6 @@ from plugins.helpers import log_calls, log
from common import ged
class SnarlNotificationsPlugin(GajimPlugin):
name = u'Snarl Notifications'
short_name = u'snarl_notifications'
version = u'0.1'
description = u'''Shows events notification using Snarl (http://www.fullphat.net/) under Windows. Snarl needs to be installed in system.
PySnarl bindings are used (http://code.google.com/p/pysnarl/).'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('SnarlNotificationsPlugin')
def init(self):

View File

@ -1777,7 +1777,6 @@ ConnectionJingle, ConnectionIBBytestream):
obj.contact.contact_name != obj.contact_nickname:
obj.contact.contact_name = obj.contact_nickname
obj.need_redraw = True
# gajim.interface.roster.draw_contact(jid, account)
if obj.old_show == obj.new_show and obj.contact.status == \
obj.status and obj.contact.priority == obj.prio: # no change
@ -1811,7 +1810,6 @@ ConnectionJingle, ConnectionIBBytestream):
obj.contact.resource = resource
obj.need_add_in_roster = True
# gajim.interface.roster.add_contact(jid, account)
if not gajim.jid_is_transport(jid) and len(obj.contact_list) == 1:
# It's not an agent
@ -1827,7 +1825,6 @@ ConnectionJingle, ConnectionIBBytestream):
if jid in gajim.newly_added[account]:
gajim.newly_added[account].remove(jid)
obj.need_redraw = True
# self.roster.draw_contact(jid, account)
obj.contact.show = obj.show
obj.contact.status = obj.status

View File

@ -632,9 +632,6 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
[]))
return
jid_list = gajim.contacts.get_jid_list(self.conn.name)
# if self.jid not in jid_list and self.jid != gajim.get_jid_from_account(
# self.conn.name):
# return
self.timestamp = None
self.get_id()
self.is_gc = False # is it a GC presence ?

View File

@ -246,6 +246,9 @@ class JingleRTPContent(JingleContent):
codecs = []
for codec in content.getTag('description').iterTags('payload-type'):
if not codec['id'] or not codec['name'] or not codec['clockrate']:
# ignore invalid payload-types
continue
c = farsight.Codec(int(codec['id']), codec['name'],
self.farsight_media, int(codec['clockrate']))
if 'channels' in codec:

View File

@ -847,12 +847,10 @@ class PreferencesWindow:
gajim.config.set('trayicon', 'on_event')
gajim.interface.systray_enabled = True
gajim.interface.systray.show_icon()
gajim.interface.systray.set_img()
else:
gajim.config.set('trayicon', 'always')
gajim.interface.systray_enabled = True
gajim.interface.systray.show_icon()
gajim.interface.systray.set_img()
def on_advanced_notifications_button_clicked(self, widget):
dialogs.AdvancedNotificationsWindow()

View File

@ -1480,12 +1480,15 @@ class WarningDialog(HigDialog):
HIG compliant warning dialog
"""
def __init__(self, pritext, sectext=''):
def __init__(self, pritext, sectext='', transient_for=None):
HigDialog.__init__(self, None, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK,
pritext, sectext)
self.set_modal(False)
if hasattr(gajim.interface, 'roster') and gajim.interface.roster:
self.set_transient_for(gajim.interface.roster.window)
if transient_for is None and hasattr(gajim.interface, 'roster') and \
gajim.interface.roster:
transient_for = gajim.interface.roster.window
if transient_for:
self.set_transient_for(transient_for)
self.popup()
class InformationDialog(HigDialog):

View File

@ -1444,8 +1444,6 @@ class GroupchatControl(ChatControlBase):
con = gajim.connections[self.account]
if gc_c and gc_c.jid:
real_jid = gc_c.jid
if gc_c.resource:
real_jid += '/' + gc_c.resource
else:
real_jid = fake_jid
if fake_jid in con.vcard_shas:

View File

@ -30,7 +30,7 @@ import pango
import gtk, gobject
import gtkgui_helpers
import dialogs
from dialogs import WarningDialog, YesNoDialog, ArchiveChooserDialog
from common import gajim
from plugins.helpers import log_calls, log
from common.exceptions import PluginsystemError
@ -104,7 +104,7 @@ class PluginsWindow(object):
def _display_installed_plugin_info(self, plugin):
self.plugin_name_label.set_text(plugin.name)
self.plugin_version_label.set_text(plugin.version)
self.plugin_authors_label.set_text(", ".join(plugin.authors))
self.plugin_authors_label.set_text(plugin.authors)
self.plugin_homepage_linkbutton.set_uri(plugin.homepage)
self.plugin_homepage_linkbutton.set_label(plugin.homepage)
self.plugin_homepage_linkbutton.set_property('sensitive', True)
@ -194,17 +194,26 @@ class PluginsWindow(object):
try:
gajim.plugin_manager.remove_plugin(plugin)
except PluginsystemError, e:
dialogs.WarningDialog(_('Unable to properly remove the plugin'),
str(e))
WarningDialog(_('Unable to properly remove the plugin'),
str(e), self.window)
return
model.remove(iter)
@log_calls('PluginsWindow')
def on_install_plugin_button_clicked(self, widget):
def show_warn_dialog():
text = _('Archive is malformed')
dialog = WarningDialog(text, '', transient_for=self.window)
dialog.set_modal(False)
dialog.popup()
def _on_plugin_exists(zip_filename):
def on_yes(is_checked):
plugin = gajim.plugin_manager.install_from_zip(zip_filename,
True)
if not plugin:
show_warn_dialog()
return
model = self.installed_plugins_model
for row in xrange(len(model)):
@ -216,8 +225,8 @@ class PluginsWindow(object):
sel = self.installed_plugins_treeview.get_selection()
sel.select_iter(iter_)
dialogs.YesNoDialog(_('Plugin already exists'),
sectext=_('Overwrite?'), on_response_yes=on_yes)
YesNoDialog(_('Plugin already exists'), sectext=_('Overwrite?'),
on_response_yes=on_yes)
def _try_install(zip_filename):
try:
@ -228,15 +237,17 @@ class PluginsWindow(object):
_on_plugin_exists(zip_filename)
return
dialogs.WarningDialog(error_text, '"%s"' % zip_filename)
WarningDialog(error_text, '"%s"' % zip_filename, self.window)
return
if not plugin:
show_warn_dialog()
return
model = self.installed_plugins_model
iter_ = model.append([plugin, plugin.name, False])
sel = self.installed_plugins_treeview.get_selection()
sel.select_iter(iter_)
self.dialog = dialogs.ArchiveChooserDialog(on_response_ok=_try_install)
self.dialog = ArchiveChooserDialog(on_response_ok=_try_install)
class GajimPluginConfigDialog(gtk.Dialog):

View File

@ -31,6 +31,7 @@ import sys
import fnmatch
import zipfile
from shutil import rmtree
import ConfigParser
from common import gajim
from common import nec
@ -46,8 +47,9 @@ class PluginManager(object):
Currently:
- scans for plugins
- activates them
- handles GUI extension points, when called by GUI objects after plugin
is activated (by dispatching info about call to handlers in plugins)
- handles GUI extension points, when called by GUI objects after
plugin is activated (by dispatching info about call to handlers
in plugins)
:todo: add more info about how GUI extension points work
:todo: add list of available GUI extension points
@ -58,10 +60,11 @@ class PluginManager(object):
deactivation handler) [DONE?]
:todo: when plug-in is deactivated all GUI extension points are removed
from `PluginManager.gui_extension_points_handlers`. But when
object that invoked GUI extension point is abandoned by Gajim, eg.
closed ChatControl object, the reference to called GUI extension
points is still in `PluginManager.gui_extension_points`. These
should be removed, so that object can be destroyed by Python.
object that invoked GUI extension point is abandoned by Gajim,
eg. closed ChatControl object, the reference to called GUI
extension points is still in `PluginManager.gui_extension_points`
These should be removed, so that object can be destroyed by
Python.
Possible solution: add call to clean up method in classes
'destructors' (classes that register GUI extension points)
'''
@ -96,16 +99,11 @@ class PluginManager(object):
'''
Registered handlers of GUI extension points.
'''
for path in gajim.PLUGINS_DIRS:
self.add_plugins(PluginManager.scan_dir_for_plugins(path))
#log.debug('plugins: %s'%(self.plugins))
pc = PluginManager.scan_dir_for_plugins(path)
self.add_plugins(pc)
self._activate_all_plugins_from_global_config()
#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:
@ -117,6 +115,9 @@ class PluginManager(object):
def _create_plugin_entry_in_global_config(self, plugin):
gajim.config.add_per('plugins', plugin.short_name)
def _remove_plugin_entry_in_global_config(self, plugin):
gajim.config.del_per('plugins', plugin.short_name)
@log_calls('PluginManager')
def add_plugin(self, plugin_class):
'''
@ -132,8 +133,9 @@ class PluginManager(object):
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.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):
@ -144,14 +146,14 @@ class PluginManager(object):
def gui_extension_point(self, gui_extpoint_name, *args):
'''
Invokes all handlers (from plugins) for particular GUI extension point
and adds it to collection for further processing (eg. by plugins not active
yet).
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
:param args: parameters to be passed to extension point handlers
(typically and object that invokes `gui_extension_point`; however,
this can be practically anything)
(typically and object that invokes `gui_extension_point`;
however, this can be practically anything)
:type args: tuple
:todo: GUI extension points must be documented well - names with
@ -162,12 +164,13 @@ class PluginManager(object):
:bug: what if only some handlers are successfully connected? we should
revert all those connections that where successfully made. Maybe
call 'self._deactivate_plugin()' or sth similar.
Looking closer - we only rewrite tuples here. Real check should be
made in method that invokes gui_extpoints handlers.
Looking closer - we only rewrite tuples here. Real check should
be made in method that invokes gui_extpoints handlers.
'''
self._add_gui_extension_point_call_to_list(gui_extpoint_name, *args)
self._execute_all_handlers_of_gui_extension_point(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):
@ -191,11 +194,11 @@ class PluginManager(object):
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?
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
@ -206,10 +209,8 @@ class PluginManager(object):
'''
if gui_extpoint_name in self.gui_extension_points:
#log.debug('Removing GUI extpoint\n name: %s\n args: %s'%(gui_extpoint_name, args))
self.gui_extension_points[gui_extpoint_name].remove(args)
@log_calls('PluginManager')
def _add_gui_extension_point_call_to_list(self, gui_extpoint_name, *args):
'''
@ -226,36 +227,37 @@ class PluginManager(object):
: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)
(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)
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):
def _execute_all_handlers_of_gui_extension_point(self, gui_extpoint_name,
*args):
if gui_extpoint_name in self.gui_extension_points_handlers:
for handlers in self.gui_extension_points_handlers[gui_extpoint_name]:
for handlers in self.gui_extension_points_handlers[
gui_extpoint_name]:
handlers[0](*args)
def _register_events_handlers_in_ged(self, plugin):
for event_name, handler in plugin.events_handlers.iteritems():
priority = handler[0]
handler_function = handler[1]
gajim.ged.register_event_handler(event_name,
priority,
handler_function)
gajim.ged.register_event_handler(event_name, priority,
handler_function)
def _remove_events_handler_from_ged(self, plugin):
for event_name, handler in plugin.events_handlers.iteritems():
priority = handler[0]
handler_function = handler[1]
gajim.ged.remove_event_handler(event_name,
priority,
handler_function)
gajim.ged.remove_event_handler(event_name, priority,
handler_function)
def _register_network_events_in_nec(self, plugin):
for event_class in plugin.events:
@ -305,16 +307,18 @@ class PluginManager(object):
# remove GUI extension points handlers (provided by plug-in) from
# handlers list
for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers[gui_extpoint_name].remove(gui_extpoint_handlers)
plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers[gui_extpoint_name].remove(
gui_extpoint_handlers)
# detaching plug-in from handler GUI extension points (calling
# cleaning up method that must be provided by plug-in developer
# for each handled GUI extension point)
for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems():
plugin.gui_extension_points.iteritems():
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]:
handler = gui_extpoint_handlers[1]
if handler:
handler(*gui_extension_point_args)
@ -335,16 +339,17 @@ class PluginManager(object):
@log_calls('PluginManager')
def _add_gui_extension_points_handlers_from_plugin(self, plugin):
for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers.setdefault(gui_extpoint_name, []).append(
gui_extpoint_handlers)
plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers.setdefault(gui_extpoint_name,
[]).append(gui_extpoint_handlers)
@log_calls('PluginManager')
def _handle_all_gui_extension_points_with_plugin(self, plugin):
for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems():
plugin.gui_extension_points.iteritems():
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]:
handler = gui_extpoint_handlers[0]
if handler:
handler(*gui_extension_point_args)
@ -356,7 +361,6 @@ class PluginManager(object):
Activated plugins are appended to `active_plugins` list.
'''
#self.active_plugins = []
for plugin in self.plugins:
self.activate_plugin(plugin)
@ -390,71 +394,78 @@ class PluginManager(object):
:todo: add scanning zipped modules
'''
plugins_found = []
if os.path.isdir(path):
dir_list = os.listdir(path)
#log.debug(dir_list)
conf = ConfigParser.ConfigParser()
fields = ('name', 'short_name', 'version', 'description', 'authors',
'homepage')
if not os.path.isdir(path):
return plugins_found
sys.path.insert(0, path)
#log.debug(sys.path)
dir_list = os.listdir(path)
for elem_name in dir_list:
#log.debug('- "%s"'%(elem_name))
file_path = os.path.join(path, elem_name)
#log.debug(' "%s"'%(file_path))
sys.path.insert(0, path)
module = None
for elem_name in dir_list:
file_path = os.path.join(path, elem_name)
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.')
try:
module = __import__(module_name)
#log.debug('Module imported.')
except ValueError, value_error:
pass
#log.debug('Module not imported successfully. ValueError: %s'%(value_error))
except ImportError, import_error:
pass
#log.debug('Module not imported successfully. ImportError: %s'%(import_error))
module = None
elif os.path.isdir(file_path) and scan_dirs:
module_name = elem_name
file_path += os.path.sep
#log.debug('Possible package detected.')
try:
module = __import__(module_name)
#log.debug('Package imported.')
except ValueError, value_error:
pass
#log.debug('Package not imported successfully. ValueError: %s'%(value_error))
except ImportError, import_error:
pass
#log.debug('Package not imported successfully. ImportError: %s'%(import_error))
if os.path.isfile(file_path) and fnmatch.fnmatch(file_path, '*.py'):
module_name = os.path.splitext(elem_name)[0]
try:
module = __import__(module_name)
except ValueError, value_error:
pass
except ImportError, import_error:
pass
elif os.path.isdir(file_path) and scan_dirs:
module_name = elem_name
file_path += os.path.sep
try:
module = __import__(module_name)
except ValueError, value_error:
pass
except ImportError, import_error:
pass
if module:
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))
if module is None:
continue
try:
if issubclass(module_attr, GajimPlugin) and \
not module_attr is 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:
pass
#log.debug('module_attr: %s, error : %s'%(
#module_name+'.'+module_attr_name,
#type_error))
manifest_path = os.path.join(os.path.dirname(file_path),
'manifest.ini')
if scan_dirs and (not os.path.isfile(manifest_path)):
continue
#log.debug(module)
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))
try:
if not issubclass(module_attr, GajimPlugin) or \
module_attr is GajimPlugin:
continue
log.debug('is subclass of GajimPlugin')
module_attr.__path__ = os.path.abspath(
os.path.dirname(file_path))
# read metadata from manifest.ini
conf.readfp(open(manifest_path, 'r'))
for option in fields:
if conf.get('info', option) is '':
raise ConfigParser.NoOptionError, 'field empty'
setattr(module_attr, option, conf.get('info', option))
conf.remove_section('info')
plugins_found.append(module_attr)
except TypeError, type_error:
pass
except ConfigParser.NoOptionError, type_error:
# all fields are required
pass
return plugins_found
@ -475,6 +486,7 @@ class PluginManager(object):
raise PluginsystemError(_('Archive corrupted'))
dirs = []
manifest = None
for filename in zip_file.namelist():
if filename.startswith('.') or filename.startswith('/') or \
('/' not in filename):
@ -482,16 +494,18 @@ class PluginManager(object):
raise PluginsystemError(_('Archive is malformed'))
if filename.endswith('/') and filename.find('/', 0, -1) < 0:
dirs.append(filename)
if 'manifest.ini' in filename.split('/')[1]:
manifest = True
if not manifest:
return
if len(dirs) > 1:
# several directories in the root of the archive
raise PluginsystemError(_('Archive is malformed'))
base_dir, user_dir = gajim.PLUGINS_DIRS
plugin_dir = os.path.join(user_dir, dirs[0])
if os.path.isdir(plugin_dir):
# Plugin already exists
# Plugin dir already exists
if not owerwrite:
raise PluginsystemError(_('Plugin already exists'))
self.remove_plugin(self.get_plugin_by_path(plugin_dir))
@ -499,7 +513,10 @@ class PluginManager(object):
zip_file.extractall(user_dir)
zip_file.close()
path = os.path.join(user_dir, dirs[0])
self.add_plugin(self.scan_dir_for_plugins(plugin_dir, False)[0])
plugins = self.scan_dir_for_plugins(plugin_dir, False)
if not plugins:
return
self.add_plugin(plugins[0])
plugin = self.plugins[-1]
return plugin
@ -513,12 +530,15 @@ class PluginManager(object):
os.unlink(path)
return
# access is denied or other
raise PluginsystemError(error[1])
raise PluginsystemError(error[1][1])
if plugin.active:
self.deactivate_plugin(plugin)
rmtree(plugin.__path__, False, on_error)
self.plugins.remove(plugin)
if plugin:
if plugin.active:
self.deactivate_plugin(plugin)
rmtree(plugin.__path__, False, on_error)
self.plugins.remove(plugin)
if self._plugin_has_entry_in_global_config(plugin):
self._remove_plugin_entry_in_global_config(plugin)
def get_plugin_by_path(self, plugin_dir):
for plugin in self.plugins:

View File

@ -97,7 +97,6 @@ class StatusIcon:
self.on_status_icon_size_changed)
self.set_img()
self.status_icon.set_visible(True)
self.subscribe_events()
def on_status_icon_right_clicked(self, widget, event_button, event_time):
@ -131,9 +130,14 @@ class StatusIcon:
"""
if not gajim.interface.systray_enabled:
return
if gajim.config.get('trayicon') == 'always':
self.status_icon.set_visible(True)
if gajim.events.get_nb_systray_events():
self.status_icon.set_visible(True)
self.status_icon.set_blinking(True)
else:
if gajim.config.get('trayicon') == 'on_event':
self.status_icon.set_visible(False)
self.status_icon.set_blinking(False)
image = gajim.interface.jabber_state_images[self.statusicon_size][