Merge PEP refactorings back to the default branch.

This commit is contained in:
Stephan Erb 2009-11-16 20:05:09 +01:00
commit 5c32304740
14 changed files with 516 additions and 949 deletions

View File

@ -1279,14 +1279,12 @@ class ChatControl(ChatControlBase):
self.video_state = self.JINGLE_STATE_NOT_AVAILABLE self.video_state = self.JINGLE_STATE_NOT_AVAILABLE
self.update_toolbar() self.update_toolbar()
self._mood_image = self.xml.get_widget('mood_image') self._pep_images = {}
self._activity_image = self.xml.get_widget('activity_image') self._pep_images['mood'] = self.xml.get_widget('mood_image')
self._tune_image = self.xml.get_widget('tune_image') self._pep_images['activity'] = self.xml.get_widget('activity_image')
self._pep_images['tune'] = self.xml.get_widget('tune_image')
self.update_mood() self.update_all_pep_types()
self.update_activity()
self.update_tune()
# keep timeout id and window obj for possible big avatar # keep timeout id and window obj for possible big avatar
# it is on enter-notify and leave-notify so no need to be # it is on enter-notify and leave-notify so no need to be
@ -1430,118 +1428,24 @@ class ChatControl(ChatControlBase):
self._convert_to_gc_button.set_sensitive(True) self._convert_to_gc_button.set_sensitive(True)
else: else:
self._convert_to_gc_button.set_sensitive(False) self._convert_to_gc_button.set_sensitive(False)
def update_all_pep_types(self):
for pep_type in self._pep_images:
self.update_pep(pep_type)
def update_mood(self): def update_pep(self, pep_type):
mood = None
text = None
if isinstance(self.contact, GC_Contact): if isinstance(self.contact, GC_Contact):
return return
if pep_type not in self._pep_images:
if 'mood' in self.contact.mood:
mood = self.contact.mood['mood'].strip()
if 'text' in self.contact.mood:
text = self.contact.mood['text'].strip()
if mood is not None:
if mood in MOODS:
self._mood_image.set_from_pixbuf(gtkgui_helpers.load_mood_icon(
mood).get_pixbuf())
# Translate standard moods
mood = MOODS[mood]
else:
self._mood_image.set_from_pixbuf(gtkgui_helpers.load_mood_icon(
'unknown').get_pixbuf())
mood = gobject.markup_escape_text(mood)
tooltip = '<b>%s</b>' % mood
if text:
text = gobject.markup_escape_text(text)
tooltip += '\n' + text
self._mood_image.set_tooltip_markup(tooltip)
self._mood_image.show()
else:
self._mood_image.hide()
def update_activity(self):
activity = None
subactivity = None
text = None
if isinstance(self.contact, GC_Contact):
return return
pep = self.contact.pep
if 'activity' in self.contact.activity: img = self._pep_images[pep_type]
activity = self.contact.activity['activity'].strip() if pep_type in pep:
if 'subactivity' in self.contact.activity: img.set_from_pixbuf(pep[pep_type].asPixbufIcon())
subactivity = self.contact.activity['subactivity'].strip() img.set_tooltip_markup(pep[pep_type].asMarkupText())
if 'text' in self.contact.activity: img.show()
text = self.contact.activity['text'].strip()
if activity is not None:
if activity in ACTIVITIES:
# Translate standard activities
if subactivity in ACTIVITIES[activity]:
self._activity_image.set_from_pixbuf(
gtkgui_helpers.load_activity_icon(activity, subactivity). \
get_pixbuf())
subactivity = ACTIVITIES[activity][subactivity]
else:
self._activity_image.set_from_pixbuf(
gtkgui_helpers.load_activity_icon(activity).get_pixbuf())
activity = ACTIVITIES[activity]['category']
else:
self._activity_image.set_from_pixbuf(
gtkgui_helpers.load_activity_icon('unknown').get_pixbuf())
# Translate standard subactivities
tooltip = '<b>' + gobject.markup_escape_text(activity)
if subactivity:
tooltip += ': ' + gobject.markup_escape_text(subactivity)
tooltip += '</b>'
if text:
tooltip += '\n' + gobject.markup_escape_text(text)
self._activity_image.set_tooltip_markup(tooltip)
self._activity_image.show()
else: else:
self._activity_image.hide() img.hide()
def update_tune(self):
artist = None
title = None
source = None
if isinstance(self.contact, GC_Contact):
return
if 'artist' in self.contact.tune:
artist = self.contact.tune['artist'].strip()
artist = gobject.markup_escape_text(artist)
if 'title' in self.contact.tune:
title = self.contact.tune['title'].strip()
title = gobject.markup_escape_text(title)
if 'source' in self.contact.tune:
source = self.contact.tune['source'].strip()
source = gobject.markup_escape_text(source)
if artist or title:
if not artist:
artist = _('Unknown Artist')
if not title:
title = _('Unknown Title')
if not source:
source = _('Unknown Source')
self._tune_image.set_tooltip_markup(
_('<b>"%(title)s"</b> by <i>%(artist)s</i>\n'
'from <i>%(source)s</i>') % {'title': title, 'artist': artist,
'source': source})
self._tune_image.show()
else:
self._tune_image.hide()
def _update_jingle(self, jingle_type): def _update_jingle(self, jingle_type):
if jingle_type not in ('audio', 'video'): if jingle_type not in ('audio', 'video'):

View File

@ -168,9 +168,7 @@ class Connection(ConnectionHandlers):
self.pubsub_supported = False self.pubsub_supported = False
self.pubsub_publish_options_supported = False self.pubsub_publish_options_supported = False
self.pep_supported = False self.pep_supported = False
self.mood = {} self.pep = {}
self.tune = {}
self.activity = {}
# Do we continue connection when we get roster (send presence,get vcard..) # Do we continue connection when we get roster (send presence,get vcard..)
self.continue_connect_info = None self.continue_connect_info = None
# Do we auto accept insecure connection # Do we auto accept insecure connection

View File

@ -46,11 +46,10 @@ import common.xmpp
from common import helpers from common import helpers
from common import gajim from common import gajim
from common import atom
from common import pep
from common import exceptions from common import exceptions
from common.commands import ConnectionCommands from common.commands import ConnectionCommands
from common.pubsub import ConnectionPubSub from common.pubsub import ConnectionPubSub
from common.pep import ConnectionPEP
from common.caps import ConnectionCaps from common.caps import ConnectionCaps
if gajim.HAVE_FARSIGHT: if gajim.HAVE_FARSIGHT:
from common.jingle import ConnectionJingle from common.jingle import ConnectionJingle
@ -1453,7 +1452,7 @@ sent a message to.'''
return sess return sess
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps, ConnectionHandlersBase, ConnectionJingle): class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionPEP, ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
def __init__(self): def __init__(self):
ConnectionVcard.__init__(self) ConnectionVcard.__init__(self)
ConnectionBytestream.__init__(self) ConnectionBytestream.__init__(self)
@ -1874,15 +1873,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
def _messageCB(self, con, msg): def _messageCB(self, con, msg):
'''Called when we receive a message''' '''Called when we receive a message'''
log.debug('MessageCB') log.debug('MessageCB')
mtype = msg.getType() mtype = msg.getType()
# check if the message is pubsub#event
if msg.getTag('event') is not None:
if mtype == 'groupchat':
return
if msg.getTag('error') is None:
self._pubsubEventCB(con, msg)
return
# check if the message is a roster item exchange (XEP-0144) # check if the message is a roster item exchange (XEP-0144)
if msg.getTag('x', namespace=common.xmpp.NS_ROSTERX): if msg.getTag('x', namespace=common.xmpp.NS_ROSTERX):
@ -2148,42 +2139,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.dispatch('GC_INVITATION',(frm, jid_from, reason, password, self.dispatch('GC_INVITATION',(frm, jid_from, reason, password,
is_continued)) is_continued))
def _pubsubEventCB(self, con, msg):
''' Called when we receive <message/> with pubsub event. '''
# TODO: Logging? (actually services where logging would be useful, should
# TODO: allow to access archives remotely...)
jid = helpers.get_full_jid_from_iq(msg)
event = msg.getTag('event')
# XEP-0107: User Mood
items = event.getTag('items', {'node': common.xmpp.NS_MOOD})
if items: pep.user_mood(items, self.name, jid)
# XEP-0118: User Tune
items = event.getTag('items', {'node': common.xmpp.NS_TUNE})
if items: pep.user_tune(items, self.name, jid)
# XEP-0080: User Geolocation
items = event.getTag('items', {'node': common.xmpp.NS_GEOLOC})
if items: pep.user_geoloc(items, self.name, jid)
# XEP-0108: User Activity
items = event.getTag('items', {'node': common.xmpp.NS_ACTIVITY})
if items: pep.user_activity(items, self.name, jid)
# XEP-0172: User Nickname
items = event.getTag('items', {'node': common.xmpp.NS_NICK})
if items: pep.user_nickname(items, self.name, jid)
items = event.getTag('items')
if items is None: return
for item in items.getTags('item'):
entry = item.getTag('entry')
if entry is not None:
# for each entry in feed (there shouldn't be more than one,
# but to be sure...
self.dispatch('ATOM_ENTRY', (atom.OldEntry(node=entry),))
continue
# unknown type... probably user has another client who understands that event
raise common.xmpp.NodeProcessed
def _presenceCB(self, con, prs): def _presenceCB(self, con, prs):
'''Called when we receive a presence''' '''Called when we receive a presence'''
ptype = prs.getType() ptype = prs.getType()
@ -2751,6 +2706,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
con.RegisterHandler('message', self._messageCB) con.RegisterHandler('message', self._messageCB)
con.RegisterHandler('presence', self._presenceCB) con.RegisterHandler('presence', self._presenceCB)
con.RegisterHandler('presence', self._capsPresenceCB) con.RegisterHandler('presence', self._capsPresenceCB)
con.RegisterHandler('message', self._pubsubEventCB,
ns=common.xmpp.NS_PUBSUB_EVENT)
con.RegisterHandler('iq', self._vCardCB, 'result', con.RegisterHandler('iq', self._vCardCB, 'result',
common.xmpp.NS_VCARD) common.xmpp.NS_VCARD)
con.RegisterHandler('iq', self._rosterSetCB, 'set', con.RegisterHandler('iq', self._rosterSetCB, 'set',

View File

@ -94,7 +94,7 @@ class Contact(CommonContact):
def __init__(self, jid, account, name='', groups=[], show='', status='', sub='', def __init__(self, jid, account, name='', groups=[], show='', status='', sub='',
ask='', resource='', priority=0, keyID='', client_caps=None, ask='', resource='', priority=0, keyID='', client_caps=None,
our_chatstate=None, chatstate=None, last_status_time=None, msg_id = None, our_chatstate=None, chatstate=None, last_status_time=None, msg_id = None,
composing_xep=None, mood={}, tune={}, activity={}): composing_xep=None):
CommonContact.__init__(self, jid, account, resource, show, status, name, CommonContact.__init__(self, jid, account, resource, show, status, name,
our_chatstate, composing_xep, chatstate, client_caps=client_caps) our_chatstate, composing_xep, chatstate, client_caps=client_caps)
@ -110,9 +110,7 @@ class Contact(CommonContact):
self.msg_id = msg_id self.msg_id = msg_id
self.last_status_time = last_status_time self.last_status_time = last_status_time
self.mood = mood.copy() self.pep = {}
self.tune = tune.copy()
self.activity = activity.copy()
def get_full_jid(self): def get_full_jid(self):
if self.resource: if self.resource:
@ -229,23 +227,25 @@ class Contacts:
def create_contact(self, jid, account, name='', groups=[], show='', status='', def create_contact(self, jid, account, name='', groups=[], show='', status='',
sub='', ask='', resource='', priority=0, keyID='', client_caps=None, sub='', ask='', resource='', priority=0, keyID='', client_caps=None,
our_chatstate=None, chatstate=None, last_status_time=None, our_chatstate=None, chatstate=None, last_status_time=None,
composing_xep=None, mood={}, tune={}, activity={}): composing_xep=None):
account = self._accounts.get(account, account) # Use Account object if available account = self._accounts.get(account, account) # Use Account object if available
return Contact(jid=jid, account=account, name=name, groups=groups, return Contact(jid=jid, account=account, name=name, groups=groups,
show=show, status=status, sub=sub, ask=ask, resource=resource, priority=priority, show=show, status=status, sub=sub, ask=ask, resource=resource, priority=priority,
keyID=keyID, client_caps=client_caps, our_chatstate=our_chatstate, keyID=keyID, client_caps=client_caps, our_chatstate=our_chatstate,
chatstate=chatstate, last_status_time=last_status_time, chatstate=chatstate, last_status_time=last_status_time,
composing_xep=composing_xep, mood=mood, tune=tune, activity=activity) composing_xep=composing_xep)
def create_self_contact(self, jid, account, resource, show, status, priority, keyID=''): def create_self_contact(self, jid, account, resource, show, status, priority,
name='', keyID=''):
conn = common.gajim.connections[account] conn = common.gajim.connections[account]
nick = common.gajim.nicks[account] nick = name or common.gajim.nicks[account]
account = self._accounts.get(account, account) # Use Account object if available account = self._accounts.get(account, account) # Use Account object if available
return self.create_contact(jid=jid, account=account, self_contact = self.create_contact(jid=jid, account=account,
name=nick, groups=['self_contact'], show=show, status=status, name=nick, groups=['self_contact'], show=show, status=status,
sub='both', ask='none', priority=priority, keyID=keyID, sub='both', ask='none', priority=priority, keyID=keyID,
resource=resource, mood=conn.mood, tune=conn.tune, resource=resource)
activity=conn.activity) self_contact.pep = conn.pep
return self_contact
def create_not_in_roster_contact(self, jid, account, resource='', name='', keyID=''): def create_not_in_roster_contact(self, jid, account, resource='', name='', keyID=''):
account = self._accounts.get(account, account) # Use Account object if available account = self._accounts.get(account, account) # Use Account object if available

View File

@ -569,8 +569,6 @@ def datetime_tuple(timestamp):
# import gajim only when needed (after decode_string is defined) see #4764 # import gajim only when needed (after decode_string is defined) see #4764
import gajim import gajim
import pep
def convert_bytes(string): def convert_bytes(string):
suffix = '' suffix = ''
@ -777,53 +775,6 @@ def get_global_status():
status = gajim.connections[account].status status = gajim.connections[account].status
return status return status
def get_pep_dict(account):
pep_dict = {}
con = gajim.connections[account]
# activity
if 'activity' in con.activity and con.activity['activity'] in pep.ACTIVITIES:
activity = con.activity['activity']
if 'subactivity' in con.activity and con.activity['subactivity'] in \
pep.ACTIVITIES[activity]:
subactivity = con.activity['subactivity']
else:
subactivity = 'other'
else:
activity = ''
subactivity = ''
if 'text' in con.activity:
text = con.activity['text']
else:
text = ''
pep_dict['activity'] = activity
pep_dict['subactivity'] = subactivity
pep_dict['activity_text'] = text
# mood
if 'mood' in con.mood and con.mood['mood'] in pep.MOODS:
mood = con.mood['mood']
else:
mood = ''
if 'text' in con.mood:
text = con.mood['text']
else:
text = ''
pep_dict['mood'] = mood
pep_dict['mood_text'] = text
return pep_dict
def get_global_pep():
maxi = 0
pep_dict = {'activity': '', 'mood': ''}
for account in gajim.connections:
if not gajim.config.get_per('accounts', account,
'sync_with_global_status'):
continue
connected = gajim.connections[account].connected
if connected > maxi:
maxi = connected
pep_dict = get_pep_dict(account)
return pep_dict
def statuses_unified(): def statuses_unified():
'''testing if all statuses are the same.''' '''testing if all statuses are the same.'''

View File

@ -192,390 +192,371 @@ ACTIVITIES = {
'studying': _('Studying'), 'studying': _('Studying'),
'writing': _('Writing')}} 'writing': _('Writing')}}
def user_mood(items, name, jid): TUNE_DATA = ['artist', 'title', 'source', 'track', 'length']
has_child = False
retract = False
mood = None
text = None
for item in items.getTags('item'):
child = item.getTag('mood')
if child is not None:
has_child = True
for ch in child.getChildren():
if ch.getName() != 'text':
mood = ch.getName()
else:
text = ch.getData()
if items.getTag('retract') is not None:
retract = True
if jid == common.gajim.get_jid_from_account(name): import logging
acc = common.gajim.connections[name] log = logging.getLogger('gajim.c.pep')
if has_child:
if 'mood' in acc.mood:
del acc.mood['mood']
if 'text' in acc.mood:
del acc.mood['text']
if mood is not None:
acc.mood['mood'] = mood
if text is not None:
acc.mood['text'] = text
elif retract:
if 'mood' in acc.mood:
del acc.mood['mood']
if 'text' in acc.mood:
del acc.mood['text']
(user, resource) = common.gajim.get_room_and_nick_from_fjid(jid) import helpers
for contact in common.gajim.contacts.get_contacts(name, user): import atom
if has_child: import gtkgui_helpers
if 'mood' in contact.mood: import gobject
del contact.mood['mood'] import gajim
if 'text' in contact.mood: import gtk
del contact.mood['text']
if mood is not None:
contact.mood['mood'] = mood
if text is not None:
contact.mood['text'] = text
elif retract:
if 'mood' in contact.mood:
del contact.mood['mood']
if 'text' in contact.mood:
del contact.mood['text']
if jid == common.gajim.get_jid_from_account(name):
common.gajim.interface.roster.draw_account(name)
common.gajim.interface.roster.draw_mood(user, name)
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name)
if ctrl:
ctrl.update_mood()
def user_tune(items, name, jid): def translate_mood(mood):
has_child = False if mood in MOODS:
retract = False return MOODS[mood]
artist = None else:
title = None return mood
source = None
track = None
length = None
for item in items.getTags('item'):
child = item.getTag('tune')
if child is not None:
has_child = True
for ch in child.getChildren():
if ch.getName() == 'artist':
artist = ch.getData()
elif ch.getName() == 'title':
title = ch.getData()
elif ch.getName() == 'source':
source = ch.getData()
elif ch.getName() == 'track':
track = ch.getData()
elif ch.getName() == 'length':
length = ch.getData()
if items.getTag('retract') is not None:
retract = True
if jid == common.gajim.get_jid_from_account(name): class AbstractPEP(object):
acc = common.gajim.connections[name]
if has_child: type = ''
if 'artist' in acc.tune: namespace = ''
del acc.tune['artist']
if 'title' in acc.tune: @classmethod
del acc.tune['title'] def get_tag_as_PEP(cls, jid, account, event_tag):
if 'source' in acc.tune: items = event_tag.getTag('items', {'node': cls.namespace})
del acc.tune['source'] if items:
if 'track' in acc.tune: log.debug("Received PEP 'user %s' from %s" % (cls.type, jid))
del acc.tune['track'] return cls(jid, account, items)
if 'length' in acc.tune: else:
del acc.tune['length'] return None
if artist is not None:
acc.tune['artist'] = artist def __init__(self, jid, account, items):
if title is not None: self._pep_specific_data, self._retracted = self._extract_info(items)
acc.tune['title'] = title
if source is not None: self._update_contacts(jid, account)
acc.tune['source'] = source if jid == common.gajim.get_jid_from_account(account):
if track is not None: self._update_account(account)
acc.tune['track'] = track
if length is not None: def _extract_info(self, items):
acc.tune['length'] = length '''To be implemented by subclasses'''
elif retract: raise NotImplementedError
if 'artist' in acc.tune:
del acc.tune['artist'] def _update_contacts(self, jid, account):
if 'title' in acc.tune: for contact in common.gajim.contacts.get_contacts(account, jid):
del acc.tune['title'] if self._retracted:
if 'source' in acc.tune: if self.type in contact.pep:
del acc.tune['source'] del contact.pep[self.type]
if 'track' in acc.tune: else:
del acc.tune['track'] contact.pep[self.type] = self
if 'length' in acc.tune:
del acc.tune['length'] def _update_account(self, account):
acc = common.gajim.connections[account]
if self._retracted:
if self.type in acc.pep:
del acc.pep[self.type]
else:
acc.pep[self.type] = self
def asPixbufIcon(self):
'''To be implemented by subclasses'''
raise NotImplementedError
def asMarkupText(self):
'''To be implemented by subclasses'''
raise NotImplementedError
class UserMoodPEP(AbstractPEP):
'''XEP-0107: User Mood'''
type = 'mood'
namespace = common.xmpp.NS_MOOD
def _extract_info(self, items):
mood_dict = {}
for item in items.getTags('item'):
mood_tag = item.getTag('mood')
if mood_tag:
for child in mood_tag.getChildren():
name = child.getName().strip()
if name == 'text':
mood_dict['text'] = child.getData()
else:
mood_dict['mood'] = name
retracted = items.getTag('retract') or not 'mood' in mood_dict
return (mood_dict, retracted)
def asPixbufIcon(self):
assert not self._retracted
received_mood = self._pep_specific_data['mood']
mood = received_mood if received_mood in MOODS else 'unknown'
pixbuf = gtkgui_helpers.load_mood_icon(mood).get_pixbuf()
return pixbuf
def asMarkupText(self):
assert not self._retracted
untranslated_mood = self._pep_specific_data['mood']
mood = translate_mood(untranslated_mood)
markuptext = '<b>%s</b>' % gobject.markup_escape_text(mood)
if 'text' in self._pep_specific_data:
text = self._pep_specific_data['text']
markuptext += ' (%s)' % gobject.markup_escape_text(text)
return markuptext
user = common.gajim.get_room_and_nick_from_fjid(jid)[0]
for contact in common.gajim.contacts.get_contacts(name, user):
if has_child:
if 'artist' in contact.tune:
del contact.tune['artist']
if 'title' in contact.tune:
del contact.tune['title']
if 'source' in contact.tune:
del contact.tune['source']
if 'track' in contact.tune:
del contact.tune['track']
if 'length' in contact.tune:
del contact.tune['length']
if artist is not None:
contact.tune['artist'] = artist
if title is not None:
contact.tune['title'] = title
if source is not None:
contact.tune['source'] = source
if track is not None:
contact.tune['track'] = track
if length is not None:
contact.tune['length'] = length
elif retract:
if 'artist' in contact.tune:
del contact.tune['artist']
if 'title' in contact.tune:
del contact.tune['title']
if 'source' in contact.tune:
del contact.tune['source']
if 'track' in contact.tune:
del contact.tune['track']
if 'length' in contact.tune:
del contact.tune['length']
if jid == common.gajim.get_jid_from_account(name): class UserTunePEP(AbstractPEP):
common.gajim.interface.roster.draw_account(name) '''XEP-0118: User Tune'''
common.gajim.interface.roster.draw_tune(user, name)
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name) type = 'tune'
if ctrl: namespace = common.xmpp.NS_TUNE
ctrl.update_tune()
def _extract_info(self, items):
tune_dict = {}
for item in items.getTags('item'):
tune_tag = item.getTag('tune')
if tune_tag:
for child in tune_tag.getChildren():
name = child.getName().strip()
data = child.getData().strip()
if child.getName() in TUNE_DATA:
tune_dict[name] = data
retracted = items.getTag('retract') or not ('artist' in tune_dict or
'title' in tune_dict)
return (tune_dict, retracted)
def asPixbufIcon(self):
import os
path = os.path.join(gajim.DATA_DIR, 'emoticons', 'static', 'music.png')
return gtk.gdk.pixbuf_new_from_file(path)
def asMarkupText(self):
assert not self._retracted
tune = self._pep_specific_data
def user_geoloc(items, name, jid): artist = tune.get('artist', _('Unknown Artist'))
pass artist = gobject.markup_escape_text(artist)
title = tune.get('title', _('Unknown Title'))
title = gobject.markup_escape_text(title)
def user_activity(items, name, jid): source = tune.get('source', _('Unknown Source'))
has_child = False source = gobject.markup_escape_text(source)
retract = False
activity = None
subactivity = None
text = None
for item in items.getTags('item'): tune_string = _('<b>"%(title)s"</b> by <i>%(artist)s</i>\n'
child = item.getTag('activity') 'from <i>%(source)s</i>') % {'title': title,
if child is not None: 'artist': artist, 'source': source}
has_child = True return tune_string
for ch in child.getChildren():
if ch.getName() != 'text':
activity = ch.getName()
for chi in ch.getChildren():
subactivity = chi.getName()
else:
text = ch.getData()
if items.getTag('retract') is not None:
retract = True
if jid == common.gajim.get_jid_from_account(name): class UserActivityPEP(AbstractPEP):
acc = common.gajim.connections[name] '''XEP-0108: User Activity'''
if has_child:
if 'activity' in acc.activity: type = 'activity'
del acc.activity['activity'] namespace = common.xmpp.NS_ACTIVITY
if 'subactivity' in acc.activity:
del acc.activity['subactivity'] def _extract_info(self, items):
if 'text' in acc.activity: activity_dict = {}
del acc.activity['text']
if activity is not None: for item in items.getTags('item'):
acc.activity['activity'] = activity activity_tag = item.getTag('activity')
if subactivity is not None and subactivity != 'other': if activity_tag:
acc.activity['subactivity'] = subactivity for child in activity_tag.getChildren():
if text is not None: name = child.getName().strip()
acc.activity['text'] = text data = child.getData().strip()
elif retract: if name == 'text':
if 'activity' in acc.activity: activity_dict['text'] = data
del acc.activity['activity'] else:
if 'subactivity' in acc.activity: activity_dict['activity'] = name
del acc.activity['subactivity'] for subactivity in child.getChildren():
if 'text' in acc.activity: subactivity_name = subactivity.getName().strip()
del acc.activity['text'] activity_dict['subactivity'] = subactivity_name
retracted = items.getTag('retract') or not 'activity' in activity_dict
return (activity_dict, retracted)
def asPixbufIcon(self):
assert not self._retracted
pep = self._pep_specific_data
activity = pep['activity']
has_known_activity = activity in ACTIVITIES
has_known_subactivity = (has_known_activity and ('subactivity' in pep)
and (pep['subactivity'] in ACTIVITIES[activity]))
if has_known_activity:
if has_known_subactivity:
subactivity = pep['subactivity']
return gtkgui_helpers.load_activity_icon(activity, subactivity).get_pixbuf()
else:
return gtkgui_helpers.load_activity_icon(activity).get_pixbuf()
else:
return gtkgui_helpers.load_activity_icon('unknown').get_pixbuf()
def asMarkupText(self):
assert not self._retracted
pep = self._pep_specific_data
activity = pep['activity']
subactivity = pep['subactivity'] if 'subactivity' in pep else None
text = pep['text'] if 'text' in pep else None
user = common.gajim.get_room_and_nick_from_fjid(jid)[0] if activity in ACTIVITIES:
for contact in common.gajim.contacts.get_contacts(name, user): # Translate standard activities
if has_child: if subactivity in ACTIVITIES[activity]:
if 'activity' in contact.activity: subactivity = ACTIVITIES[activity][subactivity]
del contact.activity['activity'] activity = ACTIVITIES[activity]['category']
if 'subactivity' in contact.activity:
del contact.activity['subactivity'] markuptext = '<b>' + gobject.markup_escape_text(activity)
if 'text' in contact.activity: if subactivity:
del contact.activity['text'] markuptext += ': ' + gobject.markup_escape_text(subactivity)
if activity is not None: markuptext += '</b>'
contact.activity['activity'] = activity if text:
if subactivity is not None and subactivity != 'other': markuptext += ' (%s)' % gobject.markup_escape_text(text)
contact.activity['subactivity'] = subactivity return markuptext
if text is not None:
contact.activity['text'] = text
elif retract: class UserNicknamePEP(AbstractPEP):
if 'activity' in contact.activity: '''XEP-0172: User Nickname'''
del contact.activity['activity']
if 'subactivity' in contact.activity: type = 'nickname'
del contact.activity['subactivity'] namespace = common.xmpp.NS_NICK
if 'text' in contact.activity:
del contact.activity['text'] def _extract_info(self, items):
nick = ''
for item in items.getTags('item'):
child = item.getTag('nick')
if child:
nick = child.getData()
break
retracted = items.getTag('retract') or not nick
return (nick, retracted)
def _update_contacts(self, jid, account):
# TODO: use dict instead
nick = '' if self._retracted else self._pep_specific_data
for contact in common.gajim.contacts.get_contacts(account, jid):
contact.contact_name = nick
def _update_account(self, account):
# TODO: use dict instead
if self._retracted:
common.gajim.nicks[account] = common.gajim.config.get_per('accounts',
account, 'name')
else:
common.gajim.nicks[account] = self._pep_specific_data
if jid == common.gajim.get_jid_from_account(name):
common.gajim.interface.roster.draw_account(name) SUPPORTED_PERSONAL_USER_EVENTS = [UserMoodPEP, UserTunePEP, UserActivityPEP,
common.gajim.interface.roster.draw_activity(user, name) UserNicknamePEP]
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name)
if ctrl:
ctrl.update_activity()
def user_nickname(items, name, jid): class ConnectionPEP(object):
has_child = False
retract = False def _pubsubEventCB(self, xmpp_dispatcher, msg):
nick = None ''' Called when we receive <message /> with pubsub event. '''
if msg.getTag('error'):
log.warning('PubsubEventCB received error stanza')
return
jid = helpers.get_full_jid_from_iq(msg)
event_tag = msg.getTag('event')
for item in items.getTags('item'): for pep_class in SUPPORTED_PERSONAL_USER_EVENTS:
child = item.getTag('nick') pep = pep_class.get_tag_as_PEP(jid, self.name, event_tag)
if child is not None: if pep:
has_child = True self.dispatch('PEP_RECEIVED', (jid, pep.type))
nick = child.getData()
break items = event_tag.getTag('items')
if items:
for item in items.getTags('item'):
entry = item.getTag('entry')
if entry:
# for each entry in feed (there shouldn't be more than one,
# but to be sure...
self.dispatch('ATOM_ENTRY', (atom.OldEntry(node=entry),))
raise common.xmpp.NodeProcessed
def send_activity(self, activity, subactivity=None, message=None):
if not self.pep_supported:
return
item = xmpp.Node('activity', {'xmlns': xmpp.NS_ACTIVITY})
if activity:
i = item.addChild(activity)
if subactivity:
i.addChild(subactivity)
if message:
i = item.addChild('text')
i.addData(message)
self.send_pb_publish('', xmpp.NS_ACTIVITY, item, '0')
def retract_activity(self):
if not self.pep_supported:
return
# not all server support retract, so send empty pep first
self.send_activity(None)
self.send_pb_retract('', xmpp.NS_ACTIVITY, '0')
if items.getTag('retract') is not None: def send_mood(self, mood, message=None):
retract = True if not self.pep_supported:
return
item = xmpp.Node('mood', {'xmlns': xmpp.NS_MOOD})
if mood:
item.addChild(mood)
if message:
i = item.addChild('text')
i.addData(message)
self.send_pb_publish('', xmpp.NS_MOOD, item, '0')
def retract_mood(self):
if not self.pep_supported:
return
self.send_mood(None)
self.send_pb_retract('', xmpp.NS_MOOD, '0')
def send_tune(self, artist='', title='', source='', track=0, length=0,
items=None):
if not self.pep_supported:
return
item = xmpp.Node('tune', {'xmlns': xmpp.NS_TUNE})
if artist:
i = item.addChild('artist')
i.addData(artist)
if title:
i = item.addChild('title')
i.addData(title)
if source:
i = item.addChild('source')
i.addData(source)
if track:
i = item.addChild('track')
i.addData(track)
if length:
i = item.addChild('length')
i.addData(length)
if items:
item.addChild(payload=items)
self.send_pb_publish('', xmpp.NS_TUNE, item, '0')
if jid == common.gajim.get_jid_from_account(name): def retract_tune(self):
if has_child: if not self.pep_supported:
common.gajim.nicks[name] = nick return
if retract: # not all server support retract, so send empty pep first
common.gajim.nicks[name] = common.gajim.config.get_per('accounts', self.send_tune(None)
name, 'name') self.send_pb_retract('', xmpp.NS_TUNE, '0')
user = common.gajim.get_room_and_nick_from_fjid(jid)[0] def send_nickname(self, nick):
if has_child: if not self.pep_supported:
if nick is not None: return
for contact in common.gajim.contacts.get_contacts(name, user): item = xmpp.Node('nick', {'xmlns': xmpp.NS_NICK})
contact.contact_name = nick item.addData(nick)
common.gajim.interface.roster.draw_contact(user, name) self.send_pb_publish('', xmpp.NS_NICK, item, '0')
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name) def retract_nickname(self):
if ctrl: if not self.pep_supported:
ctrl.update_ui() return
win = ctrl.parent_win # not all server support retract, so send empty pep first
win.redraw_tab(ctrl) self.send_tune(None)
win.show_title() self.send_pb_retract('', xmpp.NS_NICK, '0')
elif retract:
contact.contact_name = ''
def user_send_mood(account, mood, message=''):
if not common.gajim.connections[account].pep_supported:
return
item = xmpp.Node('mood', {'xmlns': xmpp.NS_MOOD})
if mood != '':
item.addChild(mood)
if message != '':
i = item.addChild('text')
i.addData(message)
common.gajim.connections[account].send_pb_publish('', xmpp.NS_MOOD, item,
'0')
def user_send_activity(account, activity, subactivity='', message=''):
if not common.gajim.connections[account].pep_supported:
return
item = xmpp.Node('activity', {'xmlns': xmpp.NS_ACTIVITY})
if activity != '':
i = item.addChild(activity)
if subactivity != '':
i.addChild(subactivity)
if message != '':
i = item.addChild('text')
i.addData(message)
common.gajim.connections[account].send_pb_publish('', xmpp.NS_ACTIVITY, item,
'0')
def user_send_tune(account, artist='', title='', source='', track=0, length=0,
items=None):
if not (common.gajim.config.get_per('accounts', account, 'publish_tune') and\
common.gajim.connections[account].pep_supported):
return
item = xmpp.Node('tune', {'xmlns': xmpp.NS_TUNE})
if artist != '':
i = item.addChild('artist')
i.addData(artist)
if title != '':
i = item.addChild('title')
i.addData(title)
if source != '':
i = item.addChild('source')
i.addData(source)
if track != 0:
i = item.addChild('track')
i.addData(track)
if length != 0:
i = item.addChild('length')
i.addData(length)
if items is not None:
item.addChild(payload=items)
common.gajim.connections[account].send_pb_publish('', xmpp.NS_TUNE, item,
'0')
def user_send_nickname(account, nick):
if not common.gajim.connections[account].pep_supported:
return
item = xmpp.Node('nick', {'xmlns': xmpp.NS_NICK})
item.addData(nick)
common.gajim.connections[account].send_pb_publish('', xmpp.NS_NICK, item,
'0')
def user_retract_mood(account):
common.gajim.connections[account].send_pb_retract('', xmpp.NS_MOOD, '0')
def user_retract_activity(account):
common.gajim.connections[account].send_pb_retract('', xmpp.NS_ACTIVITY, '0')
def user_retract_tune(account):
common.gajim.connections[account].send_pb_retract('', xmpp.NS_TUNE, '0')
def user_retract_nickname(account):
common.gajim.connections[account].send_pb_retract('', xmpp.NS_NICK, '0')
def delete_pep(jid, name):
user = common.gajim.get_room_and_nick_from_fjid(jid)[0]
if jid == common.gajim.get_jid_from_account(name):
acc = common.gajim.connections[name]
del acc.activity
acc.activity = {}
user_send_tune(name)
del acc.tune
acc.tune = {}
del acc.mood
acc.mood = {}
for contact in common.gajim.contacts.get_contacts(name, user):
del contact.activity
contact.activity = {}
del contact.tune
contact.tune = {}
del contact.mood
contact.mood = {}
if jid == common.gajim.get_jid_from_account(name):
common.gajim.interface.roster.draw_account(name)
common.gajim.interface.roster.draw_activity(user, name)
common.gajim.interface.roster.draw_tune(user, name)
common.gajim.interface.roster.draw_mood(user, name)
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name)
if ctrl:
ctrl.update_activity()
ctrl.update_tune()
ctrl.update_mood()
# vim: se ts=3: # vim: se ts=3:

View File

@ -247,25 +247,23 @@ class XMPPDispatcher(PlugIn):
''' '''
Register user callback as stanzas handler of declared type. Register user callback as stanzas handler of declared type.
Callback must take (if chained, see later) arguments: Callback arguments:
dispatcher instance (for replying), incoming return of previous handlers. dispatcher instance (for replying), incoming return of previous handlers.
The callback must raise xmpp.NodeProcessed just before return if it wants The callback must raise xmpp.NodeProcessed just before return if it wants
other callbacks to be called with the same stanza as argument _and_, more to prevent other callbacks to be called with the same stanza as argument
importantly library from returning stanza to sender with error set. _and_, more importantly library from returning stanza to sender with error set.
:param name: name of stanza. F.e. "iq". :param name: name of stanza. F.e. "iq".
:param handler: user callback. :param handler: user callback.
:param typ: value of stanza's "type" attribute. If not specified any :param typ: value of stanza's "type" attribute. If not specified any
value will match value will match
:param ns: namespace of child that stanza must contain. :param ns: namespace of child that stanza must contain.
:param chained: chain together output of several handlers. :param makefirst: insert handler in the beginning of handlers list instead
:param makefirst: insert handler in the beginning of handlers list instea
of adding it to the end. Note that more common handlers i.e. w/o "typ" of adding it to the end. Note that more common handlers i.e. w/o "typ"
and " will be called first nevertheless. and " will be called first nevertheless.
:param system: call handler even if NodeProcessed Exception were raised :param system: call handler even if NodeProcessed Exception were raised
already. already.
''' '''
# FIXME: What does chain mean and where is it handled?
if not xmlns: if not xmlns:
xmlns=self._owner.defaultNamespace xmlns=self._owner.defaultNamespace
log.debug('Registering handler %s for "%s" type->%s ns->%s(%s)' % log.debug('Registering handler %s for "%s" type->%s ns->%s(%s)' %

View File

@ -88,6 +88,7 @@ NS_PRIVACY ='jabber:iq:privacy'
NS_PRIVATE ='jabber:iq:private' NS_PRIVATE ='jabber:iq:private'
NS_PROFILE ='http://jabber.org/protocol/profile' # XEP-0154 NS_PROFILE ='http://jabber.org/protocol/profile' # XEP-0154
NS_PUBSUB ='http://jabber.org/protocol/pubsub' # XEP-0060 NS_PUBSUB ='http://jabber.org/protocol/pubsub' # XEP-0060
NS_PUBSUB_EVENT = 'http://jabber.org/protocol/pubsub#event'
NS_PUBSUB_PUBLISH_OPTIONS = NS_PUBSUB + '#publish-options' # XEP-0060 NS_PUBSUB_PUBLISH_OPTIONS = NS_PUBSUB + '#publish-options' # XEP-0060
NS_PUBSUB_OWNER ='http://jabber.org/protocol/pubsub#owner' # JEP-0060 NS_PUBSUB_OWNER ='http://jabber.org/protocol/pubsub#owner' # JEP-0060
NS_REGISTER ='jabber:iq:register' NS_REGISTER ='jabber:iq:register'

View File

@ -88,9 +88,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
self.no_log_for = False self.no_log_for = False
self.pep_supported = False self.pep_supported = False
self.mood = {} self.pep = {}
self.tune = {}
self.activity = {}
# Do we continue connection when we get roster (send presence,get vcard...) # Do we continue connection when we get roster (send presence,get vcard...)
self.continue_connect_info = None self.continue_connect_info = None
if gajim.HAVE_GPG: if gajim.HAVE_GPG:

View File

@ -1989,6 +1989,27 @@ class Interface:
_('PEP node %(node)s was not removed: %(message)s') % { _('PEP node %(node)s was not removed: %(message)s') % {
'node': data[1], 'message': data[2]}) 'node': data[1], 'message': data[2]})
def handle_event_pep_received(self, account, data):
# ('PEP_RECEIVED', account, (jid, pep_type))
jid = data[0]
pep_type = data[1]
ctrl = common.gajim.interface.msg_win_mgr.get_control(jid, account)
if jid == common.gajim.get_jid_from_account(account):
self.roster.draw_account(account)
if pep_type == 'nickname':
self.roster.draw_contact(jid, account)
if ctrl:
ctrl.update_ui()
win = ctrl.parent_win
win.redraw_tab(ctrl)
win.show_title()
else:
self.roster.draw_pep(jid, account, pep_type)
if ctrl:
ctrl.update_pep(pep_type)
def register_handler(self, event, handler): def register_handler(self, event, handler):
if event not in self.handlers: if event not in self.handlers:
self.handlers[event] = [] self.handlers[event] = []
@ -2088,6 +2109,7 @@ class Interface:
'JINGLE_CONNECTED': [self.handle_event_jingle_connected], 'JINGLE_CONNECTED': [self.handle_event_jingle_connected],
'JINGLE_DISCONNECTED': [self.handle_event_jingle_disconnected], 'JINGLE_DISCONNECTED': [self.handle_event_jingle_disconnected],
'JINGLE_ERROR': [self.handle_event_jingle_error], 'JINGLE_ERROR': [self.handle_event_jingle_error],
'PEP_RECEIVED': [self.handle_event_pep_received]
} }
def dispatch(self, event, account, data): def dispatch(self, event, account, data):
@ -2774,33 +2796,27 @@ class Interface:
listener.disconnect(self.music_track_changed_signal) listener.disconnect(self.music_track_changed_signal)
self.music_track_changed_signal = None self.music_track_changed_signal = None
def music_track_changed(self, unused_listener, music_track_info, account=''): def music_track_changed(self, unused_listener, music_track_info, account=None):
if account == '': if not account:
accounts = gajim.connections.keys() accounts = gajim.connections.keys()
else: else:
accounts = [account] accounts = [account]
if music_track_info is None:
artist = '' is_paused = hasattr(music_track_info, 'paused') and music_track_info.paused == 0
title = '' if not music_track_info or is_paused:
source = '' artist = title = source = ''
elif hasattr(music_track_info, 'paused') and music_track_info.paused == 0:
artist = ''
title = ''
source = ''
else: else:
artist = music_track_info.artist artist = music_track_info.artist
title = music_track_info.title title = music_track_info.title
source = music_track_info.album source = music_track_info.album
for acct in accounts: for acct in accounts:
if acct not in gajim.connections:
continue
if not gajim.account_is_connected(acct): if not gajim.account_is_connected(acct):
continue continue
if not gajim.connections[acct].pep_supported: if not gajim.config.get_per('accounts', acct, 'publish_tune'):
continue continue
if gajim.connections[acct].music_track_info == music_track_info: if gajim.connections[acct].music_track_info == music_track_info:
continue continue
pep.user_send_tune(acct, artist, title, source) gajim.connections[acct].send_tune(artist, title, source)
gajim.connections[acct].music_track_info = music_track_info gajim.connections[acct].music_track_info = music_track_info
def get_bg_fg_colors(self): def get_bg_fg_colors(self):

View File

@ -322,8 +322,7 @@ class ProfileWindow:
nick = '' nick = ''
if 'NICKNAME' in vcard_: if 'NICKNAME' in vcard_:
nick = vcard_['NICKNAME'] nick = vcard_['NICKNAME']
from common import pep gajim.connections[self.account].send_nickname(self.account, nick)
pep.user_send_nickname(self.account, nick)
if nick == '': if nick == '':
nick = gajim.config.get_per('accounts', self.account, 'name') nick = gajim.config.get_per('accounts', self.account, 'name')
gajim.nicks[self.account] = nick gajim.nicks[self.account] = nick

View File

@ -1022,55 +1022,21 @@ class RosterWindow:
self.model[child_iter][C_NAME] = account_name self.model[child_iter][C_NAME] = account_name
if gajim.config.get('show_mood_in_roster') \ pep = gajim.connections[account].pep
and 'mood' in gajim.connections[account].mood \ if gajim.config.get('show_mood_in_roster') and 'mood' in pep:
and gajim.connections[account].mood['mood'].strip() in MOODS: self.model[child_iter][C_MOOD_PIXBUF] = pep['mood'].asPixbufIcon()
self.model[child_iter][C_MOOD_PIXBUF] = gtkgui_helpers.load_mood_icon(
gajim.connections[account].mood['mood'].strip()).get_pixbuf()
elif gajim.config.get('show_mood_in_roster') \
and 'mood' in gajim.connections[account].mood:
self.model[child_iter][C_MOOD_PIXBUF] = \
gtkgui_helpers.load_mood_icon('unknown'). \
get_pixbuf()
else: else:
self.model[child_iter][C_MOOD_PIXBUF] = None self.model[child_iter][C_MOOD_PIXBUF] = None
if gajim.config.get('show_activity_in_roster') \ if gajim.config.get('show_activity_in_roster') and 'activity' in pep:
and 'activity' in gajim.connections[account].activity \ self.model[child_iter][C_ACTIVITY_PIXBUF] = pep['activity'].asPixbufIcon()
and gajim.connections[account].activity['activity'].strip() \
in ACTIVITIES:
if 'subactivity' in gajim.connections[account].activity \
and gajim.connections[account].activity['subactivity'].strip() \
in ACTIVITIES[gajim.connections[account].activity['activity'].strip()]:
self.model[child_iter][C_ACTIVITY_PIXBUF] = \
gtkgui_helpers.load_activity_icon(
gajim.connections[account].activity['activity'].strip(),
gajim.connections[account].activity['subactivity'].strip()). \
get_pixbuf()
else:
self.model[child_iter][C_ACTIVITY_PIXBUF] = \
gtkgui_helpers.load_activity_icon(
gajim.connections[account].activity['activity'].strip()). \
get_pixbuf()
elif gajim.config.get('show_activity_in_roster') \
and 'activity' in gajim.connections[account].activity:
self.model[child_iter][C_ACTIVITY_PIXBUF] = \
gtkgui_helpers.load_activity_icon('unknown'). \
get_pixbuf()
else: else:
self.model[child_iter][C_ACTIVITY_PIXBUF] = None self.model[child_iter][C_ACTIVITY_PIXBUF] = None
if gajim.config.get('show_tunes_in_roster') \ if gajim.config.get('show_tunes_in_roster') and 'tune' in pep:
and ('artist' in gajim.connections[account].tune \ self.model[child_iter][C_TUNE_PIXBUF] = pep['tune'].asPixbufIcon()
or 'title' in gajim.connections[account].tune):
path = os.path.join(gajim.DATA_DIR, 'emoticons', 'static', 'music.png')
self.model[child_iter][C_TUNE_PIXBUF] = \
gtk.gdk.pixbuf_new_from_file(path)
else: else:
self.model[child_iter][C_TUNE_PIXBUF] = None self.model[child_iter][C_TUNE_PIXBUF] = None
return False return False
def draw_group(self, group, account): def draw_group(self, group, account):
@ -1276,71 +1242,39 @@ class RosterWindow:
return False return False
def _is_pep_shown_in_roster(self, pep_type):
def draw_mood(self, jid, account): if pep_type == 'mood':
return gajim.config.get('show_mood_in_roster')
elif pep_type == 'activity':
return gajim.config.get('show_activity_in_roster')
elif pep_type == 'tune':
return gajim.config.get('show_tunes_in_roster')
else:
return False
def draw_all_pep_types(self, jid, account):
for pep_type in self._pep_type_to_model_column:
self.draw_pep(jid, account, pep_type)
def draw_pep(self, jid, account, pep_type):
if pep_type not in self._pep_type_to_model_column:
return
if not self._is_pep_shown_in_roster(pep_type):
return
model_column = self._pep_type_to_model_column[pep_type]
iters = self._get_contact_iter(jid, account, model=self.model) iters = self._get_contact_iter(jid, account, model=self.model)
if not iters or not gajim.config.get('show_mood_in_roster'): if not iters:
return return
jid = self.model[iters[0]][C_JID] jid = self.model[iters[0]][C_JID]
jid = jid.decode('utf-8') jid = jid.decode('utf-8')
contact = gajim.contacts.get_contact(account, jid) contact = gajim.contacts.get_contact(account, jid)
if 'mood' in contact.mood and contact.mood['mood'].strip() in MOODS: if pep_type in contact.pep:
pixbuf = gtkgui_helpers.load_mood_icon( pixbuf = contact.pep[pep_type].asPixbufIcon()
contact.mood['mood'].strip()).get_pixbuf()
elif 'mood' in contact.mood:
pixbuf = gtkgui_helpers.load_mood_icon(
'unknown').get_pixbuf()
else: else:
pixbuf = None pixbuf = None
for child_iter in iters: for child_iter in iters:
self.model[child_iter][C_MOOD_PIXBUF] = pixbuf self.model[child_iter][model_column] = pixbuf
return False
def draw_activity(self, jid, account):
iters = self._get_contact_iter(jid, account, model=self.model)
if not iters or not gajim.config.get('show_activity_in_roster'):
return
jid = self.model[iters[0]][C_JID]
jid = jid.decode('utf-8')
contact = gajim.contacts.get_contact(account, jid)
if 'activity' in contact.activity \
and contact.activity['activity'].strip() in ACTIVITIES:
if 'subactivity' in contact.activity \
and contact.activity['subactivity'].strip() in \
ACTIVITIES[contact.activity['activity'].strip()]:
pixbuf = gtkgui_helpers.load_activity_icon(
contact.activity['activity'].strip(),
contact.activity['subactivity'].strip()).get_pixbuf()
else:
pixbuf = gtkgui_helpers.load_activity_icon(
contact.activity['activity'].strip()).get_pixbuf()
elif 'activity' in contact.activity:
pixbuf = gtkgui_helpers.load_activity_icon(
'unknown').get_pixbuf()
else:
pixbuf = None
for child_iter in iters:
self.model[child_iter][C_ACTIVITY_PIXBUF] = pixbuf
return False
def draw_tune(self, jid, account):
iters = self._get_contact_iter(jid, account, model=self.model)
if not iters or not gajim.config.get('show_tunes_in_roster'):
return
jid = self.model[iters[0]][C_JID]
jid = jid.decode('utf-8')
contact = gajim.contacts.get_contact(account, jid)
if 'artist' in contact.tune or 'title' in contact.tune:
path = os.path.join(gajim.DATA_DIR, 'emoticons', 'static', 'music.png')
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
else:
pixbuf = None
for child_iter in iters:
self.model[child_iter][C_TUNE_PIXBUF] = pixbuf
return False
def draw_avatar(self, jid, account): def draw_avatar(self, jid, account):
iters = self._get_contact_iter(jid, account, model=self.model) iters = self._get_contact_iter(jid, account, model=self.model)
@ -1359,9 +1293,7 @@ class RosterWindow:
def draw_completely(self, jid, account): def draw_completely(self, jid, account):
self.draw_contact(jid, account) self.draw_contact(jid, account)
self.draw_mood(jid, account) self.draw_all_pep_types(jid, account)
self.draw_activity(jid, account)
self.draw_tune(jid, account)
self.draw_avatar(jid, account) self.draw_avatar(jid, account)
def adjust_and_draw_contact_context(self, jid, account): def adjust_and_draw_contact_context(self, jid, account):
@ -1964,36 +1896,36 @@ class RosterWindow:
self.send_status_continue(account, status, txt, auto, to) self.send_status_continue(account, status, txt, auto, to)
def send_pep(self, account, pep_dict=None): def send_pep(self, account, pep_dict):
'''Sends pep information (activity, mood)''' connection = gajim.connections[account]
if not pep_dict:
return if 'activity' in pep_dict:
# activity
if 'activity' in pep_dict and pep_dict['activity'] in pep.ACTIVITIES:
activity = pep_dict['activity'] activity = pep_dict['activity']
if 'subactivity' in pep_dict and \ subactivity = pep_dict.get('subactivity', None)
pep_dict['subactivity'] in pep.ACTIVITIES[activity]: activity_text = pep_dict.get('activity_text', None)
subactivity = pep_dict['subactivity'] connection.send_activity(activity, subactivity, activity_text)
else:
subactivity = 'other'
if 'activity_text' in pep_dict:
activity_text = pep_dict['activity_text']
else:
activity_text = ''
pep.user_send_activity(account, activity, subactivity, activity_text)
else: else:
pep.user_send_activity(account, '') connection.retract_activity()
# mood if 'mood' in pep_dict:
if 'mood' in pep_dict and pep_dict['mood'] in pep.MOODS:
mood = pep_dict['mood'] mood = pep_dict['mood']
if 'mood_text' in pep_dict: mood_text = pep_dict.get('mood_text', None)
mood_text = pep_dict['mood_text'] connection.send_mood(mood, mood_text)
else:
mood_text = ''
pep.user_send_mood(account, mood, mood_text)
else: else:
pep.user_send_mood(account, '') connection.retract_mood()
def delete_pep(self, jid, account):
if jid == gajim.get_jid_from_account(account):
gajim.connections[account].pep = {}
self.draw_account(account)
for contact in gajim.contacts.get_contacts(account, jid):
contact.pep = {}
self.draw_all_pep_types(jid, account)
ctrl = gajim.interface.msg_win_mgr.get_control(jid, account)
if ctrl:
ctrl.update_all_pep_types()
def send_status_continue(self, account, status, txt, auto, to): def send_status_continue(self, account, status, txt, auto, to):
if gajim.account_is_connected(account) and not to: if gajim.account_is_connected(account) and not to:
@ -2008,8 +1940,7 @@ class RosterWindow:
gajim.connections[account].send_custom_status(status, txt, to) gajim.connections[account].send_custom_status(status, txt, to)
else: else:
if status in ('invisible', 'offline'): if status in ('invisible', 'offline'):
pep.delete_pep(gajim.get_jid_from_account(account), \ self.delete_pep(gajim.get_jid_from_account(account), account)
account)
was_invisible = gajim.connections[account].connected == \ was_invisible = gajim.connections[account].connected == \
gajim.SHOW_LIST.index('invisible') gajim.SHOW_LIST.index('invisible')
gajim.connections[account].change_status(status, txt, auto) gajim.connections[account].change_status(status, txt, auto)
@ -2087,7 +2018,7 @@ class RosterWindow:
contact_instances) contact_instances)
if not keep_pep and contact.jid != gajim.get_jid_from_account(account) \ if not keep_pep and contact.jid != gajim.get_jid_from_account(account) \
and not contact.is_groupchat(): and not contact.is_groupchat():
pep.delete_pep(contact.jid, account) self.delete_pep(contact.jid, account)
# Redraw everything and select the sender # Redraw everything and select the sender
self.adjust_and_draw_contact_context(contact.jid, account) self.adjust_and_draw_contact_context(contact.jid, account)
@ -2501,11 +2432,10 @@ class RosterWindow:
account_name = account account_name = account
if gajim.account_is_connected(account): if gajim.account_is_connected(account):
account_name += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total)) account_name += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total))
contact = gajim.contacts.create_contact(jid=jid, account=account, name=account_name, contact = gajim.contacts.create_self_contact(jid=jid, account=account,
show=connection.get_status(), sub='', status=connection.status, name=account_name, show=connection.get_status(),
resource=connection.server_resource, status=connection.status, resource=connection.server_resource,
priority=connection.priority, mood=connection.mood, priority=connection.priority)
tune=connection.tune, activity=connection.activity)
if gajim.connections[account].gpg: if gajim.connections[account].gpg:
contact.keyID = gajim.config.get_per('accounts', connection.name, contact.keyID = gajim.config.get_per('accounts', connection.name,
'keyid') 'keyid')
@ -3388,23 +3318,19 @@ class RosterWindow:
gajim.interface.instances['preferences'] = config.PreferencesWindow() gajim.interface.instances['preferences'] = config.PreferencesWindow()
def on_publish_tune_toggled(self, widget, account): def on_publish_tune_toggled(self, widget, account):
act = widget.get_active() active = widget.get_active()
gajim.config.set_per('accounts', account, 'publish_tune', act) gajim.config.set_per('accounts', account, 'publish_tune', active)
if act: if active:
gajim.interface.enable_music_listener() gajim.interface.enable_music_listener()
else: else:
# disable it only if no other account use it gajim.connections[account].retract_tune()
for acct in gajim.connections: # disable music listener only if no other account uses it
if gajim.config.get_per('accounts', acct, 'publish_tune'): for acc in gajim.connections:
if gajim.config.get_per('accounts', acc, 'publish_tune'):
break break
else: else:
gajim.interface.disable_music_listener() gajim.interface.disable_music_listener()
if gajim.connections[account].pep_supported:
# As many implementations don't support retracting items, we send a
# "Stopped" event first
pep.user_send_tune(account, '')
pep.user_retract_tune(account)
helpers.update_optional_features(account) helpers.update_optional_features(account)
def on_pep_services_menuitem_activate(self, widget, account): def on_pep_services_menuitem_activate(self, widget, account):
@ -4481,9 +4407,9 @@ class RosterWindow:
renderer.set_property('xpad', 8) renderer.set_property('xpad', 8)
def _fill_mood_pixbuf_renderer(self, column, renderer, model, titer, def _fill_pep_pixbuf_renderer(self, column, renderer, model, titer,
data = None): data=None):
'''When a row is added, set properties for avatar renderer''' '''When a row is added, draw the respective pep icon'''
theme = gajim.config.get('roster_theme') theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE] type_ = model[titer][C_TYPE]
if type_ == 'group': if type_ == 'group':
@ -4491,155 +4417,37 @@ class RosterWindow:
return return
# allocate space for the icon only if needed # allocate space for the icon only if needed
if model[titer][C_MOOD_PIXBUF]: if model[titer][data]:
renderer.set_property('visible', True) renderer.set_property('visible', True)
else: else:
renderer.set_property('visible', False) renderer.set_property('visible', False)
if type_ == 'account': if type_ == 'account':
color = gajim.config.get_per('themes', theme, color = gajim.config.get_per('themes', theme, 'accountbgcolor')
'accountbgcolor')
if color: if color:
renderer.set_property('cell-background', color) renderer.set_property('cell-background', color)
else: else:
self.set_renderer_color(renderer, self.set_renderer_color(renderer, gtk.STATE_ACTIVE)
gtk.STATE_ACTIVE)
# align pixbuf to the right) # align pixbuf to the right)
renderer.set_property('xalign', 1) renderer.set_property('xalign', 1)
# prevent type_ = None, see http://trac.gajim.org/ticket/2534 # prevent type_ = None, see http://trac.gajim.org/ticket/2534
elif type_: elif type_:
if not model[titer][C_JID] \ if not model[titer][C_JID] or not model[titer][C_ACCOUNT]:
or not model[titer][C_ACCOUNT]:
# This can append at the moment we add the row # This can append at the moment we add the row
return return
jid = model[titer][C_JID].decode('utf-8') jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8') account = model[titer][C_ACCOUNT].decode('utf-8')
if jid in gajim.newly_added[account]: if jid in gajim.newly_added[account]:
renderer.set_property('cell-background', renderer.set_property('cell-background', gajim.config.get(
gajim.config.get(
'just_connected_bg_color')) 'just_connected_bg_color'))
elif jid in gajim.to_be_removed[account]: elif jid in gajim.to_be_removed[account]:
renderer.set_property('cell-background', renderer.set_property('cell-background', gajim.config.get(
gajim.config.get(
'just_disconnected_bg_color')) 'just_disconnected_bg_color'))
else: else:
color = gajim.config.get_per('themes', color = gajim.config.get_per('themes', theme, 'contactbgcolor')
theme, 'contactbgcolor') renderer.set_property('cell-background', color if color else None)
if color:
renderer.set_property(
'cell-background', color)
else:
renderer.set_property(
'cell-background', None)
# align pixbuf to the right # align pixbuf to the right
renderer.set_property('xalign', 1) renderer.set_property('xalign', 1)
def _fill_activity_pixbuf_renderer(self, column, renderer, model, titer,
data = None):
'''When a row is added, set properties for avatar renderer'''
theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE]
if type_ == 'group':
renderer.set_property('visible', False)
return
# allocate space for the icon only if needed
if model[titer][C_ACTIVITY_PIXBUF]:
renderer.set_property('visible', True)
else:
renderer.set_property('visible', False)
if type_ == 'account':
color = gajim.config.get_per('themes', theme,
'accountbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
self.set_renderer_color(renderer,
gtk.STATE_ACTIVE)
# align pixbuf to the right)
renderer.set_property('xalign', 1)
# prevent type_ = None, see http://trac.gajim.org/ticket/2534
elif type_:
if not model[titer][C_JID] \
or not model[titer][C_ACCOUNT]:
# This can append at the moment we add the row
return
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
if jid in gajim.newly_added[account]:
renderer.set_property('cell-background',
gajim.config.get(
'just_connected_bg_color'))
elif jid in gajim.to_be_removed[account]:
renderer.set_property('cell-background',
gajim.config.get(
'just_disconnected_bg_color'))
else:
color = gajim.config.get_per('themes',
theme, 'contactbgcolor')
if color:
renderer.set_property(
'cell-background', color)
else:
renderer.set_property(
'cell-background', None)
# align pixbuf to the right
renderer.set_property('xalign', 1)
def _fill_tune_pixbuf_renderer(self, column, renderer, model, titer,
data = None):
'''When a row is added, set properties for avatar renderer'''
theme = gajim.config.get('roster_theme')
type_ = model[titer][C_TYPE]
if type_ == 'group':
renderer.set_property('visible', False)
return
# allocate space for the icon only if needed
if model[titer][C_TUNE_PIXBUF]:
renderer.set_property('visible', True)
else:
renderer.set_property('visible', False)
if type_ == 'account':
color = gajim.config.get_per('themes', theme,
'accountbgcolor')
if color:
renderer.set_property('cell-background', color)
else:
self.set_renderer_color(renderer,
gtk.STATE_ACTIVE)
# align pixbuf to the right)
renderer.set_property('xalign', 1)
# prevent type_ = None, see http://trac.gajim.org/ticket/2534
elif type_:
if not model[titer][C_JID] \
or not model[titer][C_ACCOUNT]:
# This can append at the moment we add the row
return
jid = model[titer][C_JID].decode('utf-8')
account = model[titer][C_ACCOUNT].decode('utf-8')
if jid in gajim.newly_added[account]:
renderer.set_property('cell-background',
gajim.config.get(
'just_connected_bg_color'))
elif jid in gajim.to_be_removed[account]:
renderer.set_property('cell-background',
gajim.config.get(
'just_disconnected_bg_color'))
else:
color = gajim.config.get_per('themes',
theme, 'contactbgcolor')
if color:
renderer.set_property(
'cell-background', color)
else:
renderer.set_property(
'cell-background', None)
# align pixbuf to the right
renderer.set_property('xalign', 1)
def _fill_avatar_pixbuf_renderer(self, column, renderer, model, titer, def _fill_avatar_pixbuf_renderer(self, column, renderer, model, titer,
data = None): data = None):
'''When a row is added, set properties for avatar renderer''' '''When a row is added, set properties for avatar renderer'''
@ -5933,19 +5741,23 @@ class RosterWindow:
col.pack_start(render_pixbuf, expand=False) col.pack_start(render_pixbuf, expand=False)
col.add_attribute(render_pixbuf, 'pixbuf', C_MOOD_PIXBUF) col.add_attribute(render_pixbuf, 'pixbuf', C_MOOD_PIXBUF)
col.set_cell_data_func(render_pixbuf, col.set_cell_data_func(render_pixbuf,
self._fill_mood_pixbuf_renderer, None) self._fill_pep_pixbuf_renderer, C_MOOD_PIXBUF)
render_pixbuf = gtk.CellRendererPixbuf() render_pixbuf = gtk.CellRendererPixbuf()
col.pack_start(render_pixbuf, expand=False) col.pack_start(render_pixbuf, expand=False)
col.add_attribute(render_pixbuf, 'pixbuf', C_ACTIVITY_PIXBUF) col.add_attribute(render_pixbuf, 'pixbuf', C_ACTIVITY_PIXBUF)
col.set_cell_data_func(render_pixbuf, col.set_cell_data_func(render_pixbuf,
self._fill_activity_pixbuf_renderer, None) self._fill_pep_pixbuf_renderer, C_ACTIVITY_PIXBUF)
render_pixbuf = gtk.CellRendererPixbuf() render_pixbuf = gtk.CellRendererPixbuf()
col.pack_start(render_pixbuf, expand=False) col.pack_start(render_pixbuf, expand=False)
col.add_attribute(render_pixbuf, 'pixbuf', C_TUNE_PIXBUF) col.add_attribute(render_pixbuf, 'pixbuf', C_TUNE_PIXBUF)
col.set_cell_data_func(render_pixbuf, col.set_cell_data_func(render_pixbuf,
self._fill_tune_pixbuf_renderer, None) self._fill_pep_pixbuf_renderer, C_TUNE_PIXBUF)
self._pep_type_to_model_column = {'mood': C_MOOD_PIXBUF,
'activity': C_ACTIVITY_PIXBUF,
'tune': C_TUNE_PIXBUF}
if gajim.config.get('avatar_position_in_roster') == 'right': if gajim.config.get('avatar_position_in_roster') == 'right':
add_avatar_renderer() add_avatar_renderer()

View File

@ -579,65 +579,19 @@ class RosterTooltip(NotificationAreaTooltip):
Append Tune, Mood, Activity information of the specified contact Append Tune, Mood, Activity information of the specified contact
to the given property list. to the given property list.
''' '''
if 'mood' in contact.mood: if 'mood' in contact.pep:
mood = contact.mood['mood'].strip() mood = contact.pep['mood'].asMarkupText()
mood = MOODS.get(mood, mood) mood_string = _('Mood:') + ' %s' % mood
mood = gobject.markup_escape_text(mood)
mood_string = _('Mood:') + ' <b>%s</b>' % mood
if 'text' in contact.mood \
and contact.mood['text'] != '':
mood_text = contact.mood['text'].strip()
mood_text = \
gobject.markup_escape_text(mood_text)
mood_string += ' (%s)' % mood_text
properties.append((mood_string, None)) properties.append((mood_string, None))
if 'activity' in contact.activity: if 'activity' in contact.pep:
activity = act_plain = \ activity = contact.pep['activity'].asMarkupText()
contact.activity['activity'].strip() activity_string = _('Activity:') + ' %s' % activity
activity = gobject.markup_escape_text(activity)
if act_plain in ACTIVITIES:
activity = ACTIVITIES[activity]['category']
activity_string = _('Activity:') + ' <b>%s' % activity
if 'subactivity' in contact.activity:
activity_sub = \
contact.activity['subactivity'].strip()
if act_plain in ACTIVITIES and activity_sub in \
ACTIVITIES[act_plain]:
activity_sub = ACTIVITIES[act_plain][activity_sub]
activity_sub = \
gobject.markup_escape_text(activity_sub)
activity_string += ': %s</b>' % activity_sub
else:
activity_string += '</b>'
if 'text' in contact.activity:
activity_text = contact.activity['text'].strip()
activity_text = gobject.markup_escape_text(
activity_text)
activity_string += ' (%s)' % activity_text
properties.append((activity_string, None)) properties.append((activity_string, None))
if 'artist' in contact.tune \ if 'tune' in contact.pep:
or 'title' in contact.tune: tune = contact.pep['tune'].asMarkupText()
if 'artist' in contact.tune: tune_string = _('Tune:') + ' %s' % tune
artist = contact.tune['artist'].strip()
artist = gobject.markup_escape_text(artist)
else:
artist = _('Unknown Artist')
if 'title' in contact.tune:
title = contact.tune['title'].strip()
title = gobject.markup_escape_text(title)
else:
title = _('Unknown Title')
if 'source' in contact.tune:
source = contact.tune['source'].strip()
source = gobject.markup_escape_text(source)
else:
source = _('Unknown Source')
tune_string = _('Tune:') + ' ' + \
_('<b>"%(title)s"</b> by <i>%(artist)s</i>\n'
'from <i>%(source)s</i>') % {'title': title,
'artist': artist, 'source': source}
properties.append((tune_string, None)) properties.append((tune_string, None))

View File

@ -14,9 +14,7 @@ class MockConnection(Mock, ConnectionHandlersBase):
self.name = account self.name = account
self.connected = 2 self.connected = 2
self.mood = {} self.pep = {}
self.activity = {}
self.tune = {}
self.blocked_contacts = {} self.blocked_contacts = {}
self.blocked_groups = {} self.blocked_groups = {}
self.sessions = {} self.sessions = {}