diff --git a/plugins/acronyms_expander.py b/plugins/acronyms_expander.py index dda47cf17..a575fe555 100644 --- a/plugins/acronyms_expander.py +++ b/plugins/acronyms_expander.py @@ -51,32 +51,35 @@ class AcronymsExpanderPlugin(GajimPlugin): self.disconnect_from_chat_control_base) } - self.INVOKER = ' ' - self.ACRONYMS = {'RTFM' : 'Read The Friendly Manual', - '/slap' : '/me slaps', - 'PS-' : 'plug-in system', - 'G-' : 'Gajim', - 'GNT-' : 'http://trac.gajim.org/newticket', - 'GW-' : 'http://trac.gajim.org/', - 'GTS-' : 'http://trac.gajim.org/report' - } + self.config_default_values = {'INVOKER' : (' ', _('')), + 'ACRONYMS' : ({'RTFM' : 'Read The Friendly Manual', + '/slap' : '/me slaps', + 'PS-' : 'plug-in system', + 'G-' : 'Gajim', + 'GNT-' : 'http://trac.gajim.org/newticket', + 'GW-' : 'http://trac.gajim.org/', + 'GTS-' : 'http://trac.gajim.org/report' + }, _('')), + } @log_calls('AcronymsExpanderPlugin') def textbuffer_live_acronym_expander(self, tb): """ @param tb gtk.TextBuffer """ - assert isinstance(tb,gtk.TextBuffer) + #assert isinstance(tb,gtk.TextBuffer) + 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))) - if t and t[-1] == self.INVOKER: + if t and t[-1] == INVOKER: log.debug("changing msg text") - base,sep,head=t[:-1].rpartition(self.INVOKER) + base,sep,head=t[:-1].rpartition(INVOKER) log.debug('%s | %s | %s'%(base, sep, head)) - if head in self.ACRONYMS: - head = self.ACRONYMS[head] + if head in ACRONYMS: + head = ACRONYMS[head] log.debug("head: %s"%(head)) - t = "".join((base, sep, head, self.INVOKER)) + t = "".join((base, sep, head, INVOKER)) log.debug("turning off notify") tb.freeze_notify() log.debug("setting text: '%s'"%(t)) @@ -101,5 +104,4 @@ class AcronymsExpanderPlugin(GajimPlugin): d = chat_control.acronyms_expander_plugin_data tv = chat_control.msg_textview tv.get_buffer().disconnect(d['h_id']) - - \ No newline at end of file + \ No newline at end of file diff --git a/plugins/length_notifier/__init__.py b/plugins/length_notifier/__init__.py new file mode 100644 index 000000000..fc433a0af --- /dev/null +++ b/plugins/length_notifier/__init__.py @@ -0,0 +1,2 @@ + +from length_notifier import LengthNotifierPlugin \ No newline at end of file diff --git a/plugins/length_notifier/config_dialog.glade b/plugins/length_notifier/config_dialog.glade new file mode 100644 index 000000000..0267bb184 --- /dev/null +++ b/plugins/length_notifier/config_dialog.glade @@ -0,0 +1,152 @@ + + + + + + + + True + 9 + 3 + 2 + 7 + 5 + + + True + + + True + True + Message length at which notification is invoked. + 6 + 0 0 999999 1 10 10 + True + True + + + + False + False + + + + + True + + + + + + 1 + + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + + + True + True + True + Background color of text entry field in chat window when notification is invoked. + 0 + 0 + Pick a color for notification + #000000000000 + + + + False + False + + + + + True + + + + + + 1 + + + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + + True + True + JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). If empty plugin is used with every JID. [not implemented] + + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). If empty plugin is used with every JID. [not implemented] + 0 + JabberIDs to include: + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + Background color of text entry field in chat window when notification is invoked. + 0 + Notification color: + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + Message length at which notification is invoked. + 0 + Message length: + + + GTK_FILL + GTK_FILL + + + + + + diff --git a/plugins/length_notifier/length_notifier.py b/plugins/length_notifier/length_notifier.py new file mode 100644 index 000000000..e9e5fbcd5 --- /dev/null +++ b/plugins/length_notifier/length_notifier.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- + +## This file is part of Gajim. +## +## Gajim is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## Gajim is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Gajim. If not, see . +## + +''' +Message length notifier plugin. + +:author: Mateusz Biliński +:since: 1st June 2008 +:copyright: Copyright (2008) Mateusz Biliński +:license: GPL +''' + +import sys + +import gtk +from common import i18n + +from plugins import GajimPlugin +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 '] + homepage = u'http://blog.bilinski.it' + + #@log_calls('LengthNotifierPlugin') + #def __init__(self): + #super(LengthNotifierPlugin, self).__init__() + + @log_calls('LengthNotifierPlugin') + def init(self): + self.config_dialog = LengthNotifierPluginConfigDialog(self) + + self.gui_extension_points = { + 'chat_control' : (self.connect_with_chat_control, + self.disconnect_from_chat_control) + } + + self.config_default_values = {'MESSAGE_WARNING_LENGTH' : (140, _('Message length at which notification is invoked.')), + 'WARNING_COLOR' : ('#F0DB3E', _('Background color of text entry field in chat window when notification is invoked.')), + 'JIDS' : ([], _('JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). If empty plugin is used with every JID. [not implemented]')) + } + + @log_calls('LengthNotifierPlugin') + def textview_length_warning(self, tb, chat_control): + tv = chat_control.msg_textview + d = chat_control.length_notifier_plugin_data + t = tb.get_text(tb.get_start_iter(), tb.get_end_iter()) + if t: + len_t = len(t) + #print("len_t: %d"%(len_t)) + if len_t>self.config['MESSAGE_WARNING_LENGTH']: + if not d['prev_color']: + d['prev_color'] = tv.style.copy().base[gtk.STATE_NORMAL] + tv.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.config['WARNING_COLOR'])) + elif d['prev_color']: + tv.modify_base(gtk.STATE_NORMAL, d['prev_color']) + d['prev_color'] = None + + @log_calls('LengthNotifierPlugin') + def connect_with_chat_control(self, chat_control): + jid = chat_control.contact.jid + if self.jid_is_ok(jid): + d = {'prev_color' : None} + tv = chat_control.msg_textview + tb = tv.get_buffer() + h_id = tb.connect('changed', self.textview_length_warning, chat_control) + d['h_id'] = h_id + + t = tb.get_text(tb.get_start_iter(), tb.get_end_iter()) + if t: + len_t = len(t) + if len_t>self.config['MESSAGE_WARNING_LENGTH']: + d['prev_color'] = tv.style.copy().base[gtk.STATE_NORMAL] + tv.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.config['WARNING_COLOR'])) + + chat_control.length_notifier_plugin_data = d + + return True + + return False + + @log_calls('LengthNotifierPlugin') + def disconnect_from_chat_control(self, chat_control): + try: + d = chat_control.length_notifier_plugin_data + tv = chat_control.msg_textview + tv.get_buffer().disconnect(d['h_id']) + 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)) + + @log_calls('LengthNotifierPlugin') + def jid_is_ok(self, jid): + if jid in self.config['JIDS'] or not self.config['JIDS']: + return True + + return False + +class LengthNotifierPluginConfigDialog(GajimPluginConfigDialog): + def init(self): + self.GLADE_FILE_PATH = self.plugin.local_file_path('config_dialog.glade') + self.xml = gtk.glade.XML(self.GLADE_FILE_PATH, root='length_notifier_config_table', domain=i18n.APP) + self.config_table = self.xml.get_widget('length_notifier_config_table') + self.child.pack_start(self.config_table) + + self.message_length_spinbutton = self.xml.get_widget('message_length_spinbutton') + self.notification_colorbutton = self.xml.get_widget('notification_colorbutton') + self.jids_entry = self.xml.get_widget('jids_entry') + + self.xml.signal_autoconnect(self) + + def on_run(self): + self.message_length_spinbutton.set_value(self.plugin.config['MESSAGE_WARNING_LENGTH']) + self.notification_colorbutton.set_color(gtk.gdk.color_parse(self.plugin.config['WARNING_COLOR'])) + #self.jids_entry.set_text(self.plugin.config['JIDS']) + self.jids_entry.set_text(','.join(self.plugin.config['JIDS'])) + + @log_calls('LengthNotifierPluginConfigDialog') + def on_message_length_spinbutton_value_changed(self, spinbutton): + self.plugin.config['MESSAGE_WARNING_LENGTH'] = spinbutton.get_value() + + @log_calls('LengthNotifierPluginConfigDialog') + def on_notification_colorbutton_color_set(self, colorbutton): + self.plugin.config['WARNING_COLOR'] = colorbutton.get_color().to_string() + + @log_calls('LengthNotifierPluginConfigDialog') + def on_jids_entry_changed(self, entry): + text = entry.get_text() + if len(text)>0: + self.plugin.config['JIDS'] = entry.get_text().split(',') + else: + self.plugin.config['JIDS'] = [] + + @log_calls('LengthNotifierPluginConfigDialog') + def on_jids_entry_editing_done(self, entry): + pass + \ No newline at end of file diff --git a/src/common/check_paths.py b/src/common/check_paths.py index 970c5a4b2..f63344448 100644 --- a/src/common/check_paths.py +++ b/src/common/check_paths.py @@ -101,6 +101,8 @@ def check_and_possibly_create_paths(): VCARD_PATH = gajim.VCARD_PATH AVATAR_PATH = gajim.AVATAR_PATH dot_gajim = os.path.dirname(VCARD_PATH) + PLUGINS_CONFIG_PATH = gajim.PLUGINS_CONFIG_DIR + if os.path.isfile(dot_gajim): print _('%s is a file but it should be a directory') % dot_gajim print _('Gajim will now exit') @@ -123,7 +125,7 @@ def check_and_possibly_create_paths(): print _('%s is a file but it should be a directory') % AVATAR_PATH print _('Gajim will now exit') sys.exit() - + if not os.path.exists(LOG_DB_PATH): create_log_db() gajim.logger.init_vars() @@ -132,6 +134,14 @@ def check_and_possibly_create_paths(): print _('Gajim will now exit') sys.exit() + if not os.path.exists(PLUGINS_CONFIG_PATH): + create_path(PLUGINS_CONFIG_PATH) + elif os.path.isfile(PLUGINS_CONFIG_PATH): + print _('%s is a file but it should be a directory') % PLUGINS_CONFIG_PATH + print _('Gajim will now exit') + sys.exit() + + else: # dot_gajim doesn't exist if dot_gajim: # is '' on win9x so avoid that create_path(dot_gajim) diff --git a/src/common/configpaths.py b/src/common/configpaths.py index e950b3e1a..986235196 100644 --- a/src/common/configpaths.py +++ b/src/common/configpaths.py @@ -110,15 +110,19 @@ class ConfigPaths: conffile = windowsify(u'config') pidfile = windowsify(u'gajim') secretsfile = windowsify(u'secrets') + pluginsconfdir = windowsify(u'pluginsconfig') if len(profile) > 0: conffile += u'.' + profile pidfile += u'.' + profile secretsfile += u'.' + profile + pluginsconfdir += u'.' + profile + pidfile += u'.pid' self.add_from_root('CONFIG_FILE', conffile) self.add_from_root('PID_FILE', pidfile) self.add_from_root('SECRETS_FILE', secretsfile) + self.add_from_root('PLUGINS_CONFIG_DIR', pluginsconfdir) # for k, v in paths.iteritems(): # print "%s: %s" % (repr(k), repr(v)) diff --git a/src/common/gajim.py b/src/common/gajim.py index 4cbdf609b..ca015d3e1 100644 --- a/src/common/gajim.py +++ b/src/common/gajim.py @@ -88,6 +88,7 @@ DATA_DIR = gajimpaths['DATA'] HOME_DIR = gajimpaths['HOME'] PLUGINS_DIRS = [gajimpaths['PLUGINS_BASE'], gajimpaths['PLUGINS_USER']] +PLUGINS_CONFIG_DIR = gajimpaths['PLUGINS_CONFIG_DIR'] try: LANG = locale.getdefaultlocale()[0] # en_US, fr_FR, el_GR etc.. diff --git a/src/plugins/gui.py b/src/plugins/gui.py index 1aa4d0140..fff2a2ded 100644 --- a/src/plugins/gui.py +++ b/src/plugins/gui.py @@ -202,15 +202,24 @@ class GajimPluginConfigDialog(gtk.Dialog): self.child.set_spacing(3) + self.init() + #label = gtk.Label(_('%s Configuration') % (plugin.name)) #label.set_markup(label.get_label()) #self.child.pack_start(label, False, False) + @log_calls('GajimPluginConfigDialog') def run(self, parent=None): self.reparent(parent) + self.on_run() self.show_all() result = super(GajimPluginConfigDialog, self).run() self.hide() return result - \ No newline at end of file + + def init(self): + pass + + def on_run(self): + pass \ No newline at end of file diff --git a/src/plugins/helpers.py b/src/plugins/helpers.py index fc6ff9c5d..9dce2bf93 100644 --- a/src/plugins/helpers.py +++ b/src/plugins/helpers.py @@ -50,6 +50,12 @@ class log_calls(object): Decorator class for functions to easily log when they are entered and left. ''' + filter_out_classes = ['PluginManager'] + ''' + List of classes from which no logs should be emited when methods are called, + eventhough `log_calls` decorator is used. + ''' + def __init__(self, classname='', log=log): ''' :Keywords: @@ -71,9 +77,19 @@ class log_calls(object): :type: str ''' + self.log_this_class = True + ''' + Determines whether wrapper of given function should log calls of this + function or not. + + :type: bool + ''' if classname: self.full_func_name = classname+'.' + + if classname in self.filter_out_classes: + self.log_this_class = False def __call__(self, f): ''' @@ -82,15 +98,24 @@ class log_calls(object): :return: given function wrapped by *log.debug* statements :rtype: function ''' + self.full_func_name += f.func_name - @functools.wraps(f) - def wrapper(*args, **kwargs): - log.debug('%(funcname)s() '%{ - 'funcname': self.full_func_name}) - result = f(*args, **kwargs) - log.debug('%(funcname)s() '%{ - 'funcname': self.full_func_name}) - return result + if self.log_this_class: + @functools.wraps(f) + def wrapper(*args, **kwargs): + + log.debug('%(funcname)s() '%{ + 'funcname': self.full_func_name}) + result = f(*args, **kwargs) + log.debug('%(funcname)s() '%{ + 'funcname': self.full_func_name}) + return result + else: + @functools.wraps(f) + def wrapper(*args, **kwargs): + result = f(*args, **kwargs) + return result + return wrapper class Singleton(type): diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py index 3a6144472..b08009072 100644 --- a/src/plugins/plugin.py +++ b/src/plugins/plugin.py @@ -133,10 +133,6 @@ class GajimPlugin(object): @log_calls('GajimPlugin') def load_config(self): self.config.load() - - @log_calls('GajimPlugin') - def __del__(self): - self.save_config() @log_calls('GajimPlugin') def local_file_path(self, file_name): @@ -155,20 +151,38 @@ class GajimPlugin(object): pass import shelve +import UserDict -class GajimPluginConfig(dict): +class GajimPluginConfig(UserDict.DictMixin): @log_calls('GajimPluginConfig') def __init__(self, plugin): self.plugin = plugin - self.FILE_PATH = gajim.HOME_DIR - log.debug('FILE_PATH = %s'%(self.FILE_PATH)) - #self.data = shelve.open(self.FILE_PATH) + self.FILE_PATH = os.path.join(gajim.PLUGINS_CONFIG_DIR, self.plugin.short_name) + #log.debug('FILE_PATH = %s'%(self.FILE_PATH)) + self.data = None + self.load() + + @log_calls('GajimPluginConfig') + def __getitem__(self, key): + if not key in self.data: + self.data[key] = self.plugin.config_default_values[key][0] + self.save() + + return self.data[key] + @log_calls('GajimPluginConfig') + def __setitem__(self, key, value): + self.data[key] = value + self.save() + + def keys(self): + return self.data.keys() + @log_calls('GajimPluginConfig') def save(self): - pass - + self.data.sync() + log.debug(str(self.data)) + @log_calls('GajimPluginConfig') def load(self): - pass - \ No newline at end of file + self.data = shelve.open(self.FILE_PATH)