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

@ -1280,13 +1280,11 @@ class ChatControl(ChatControlBase):
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
@ -1431,117 +1429,23 @@ class ChatControl(ChatControlBase):
else: else:
self._convert_to_gc_button.set_sensitive(False) self._convert_to_gc_button.set_sensitive(False)
def update_mood(self): def update_all_pep_types(self):
mood = None for pep_type in self._pep_images:
text = None self.update_pep(pep_type)
def update_pep(self, pep_type):
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:
if 'artist' in acc.tune:
del acc.tune['artist']
if 'title' in acc.tune:
del acc.tune['title']
if 'source' in acc.tune:
del acc.tune['source']
if 'track' in acc.tune:
del acc.tune['track']
if 'length' in acc.tune:
del acc.tune['length']
if artist is not None:
acc.tune['artist'] = artist
if title is not None:
acc.tune['title'] = title
if source is not None:
acc.tune['source'] = source
if track is not None:
acc.tune['track'] = track
if length is not None:
acc.tune['length'] = length
elif retract:
if 'artist' in acc.tune:
del acc.tune['artist']
if 'title' in acc.tune:
del acc.tune['title']
if 'source' in acc.tune:
del acc.tune['source']
if 'track' in acc.tune:
del acc.tune['track']
if 'length' in acc.tune:
del acc.tune['length']
user = common.gajim.get_room_and_nick_from_fjid(jid)[0] type = ''
for contact in common.gajim.contacts.get_contacts(name, user): namespace = ''
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): @classmethod
common.gajim.interface.roster.draw_account(name) def get_tag_as_PEP(cls, jid, account, event_tag):
common.gajim.interface.roster.draw_tune(user, name) items = event_tag.getTag('items', {'node': cls.namespace})
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name) if items:
if ctrl: log.debug("Received PEP 'user %s' from %s" % (cls.type, jid))
ctrl.update_tune() return cls(jid, account, items)
else:
return None
def user_geoloc(items, name, jid): def __init__(self, jid, account, items):
pass self._pep_specific_data, self._retracted = self._extract_info(items)
def user_activity(items, name, jid): self._update_contacts(jid, account)
has_child = False if jid == common.gajim.get_jid_from_account(account):
retract = False self._update_account(account)
activity = None
subactivity = None
text = None
for item in items.getTags('item'): def _extract_info(self, items):
child = item.getTag('activity') '''To be implemented by subclasses'''
if child is not None: raise NotImplementedError
has_child = True
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): def _update_contacts(self, jid, account):
acc = common.gajim.connections[name] for contact in common.gajim.contacts.get_contacts(account, jid):
if has_child: if self._retracted:
if 'activity' in acc.activity: if self.type in contact.pep:
del acc.activity['activity'] del contact.pep[self.type]
if 'subactivity' in acc.activity: else:
del acc.activity['subactivity'] contact.pep[self.type] = self
if 'text' in acc.activity:
del acc.activity['text']
if activity is not None:
acc.activity['activity'] = activity
if subactivity is not None and subactivity != 'other':
acc.activity['subactivity'] = subactivity
if text is not None:
acc.activity['text'] = text
elif retract:
if 'activity' in acc.activity:
del acc.activity['activity']
if 'subactivity' in acc.activity:
del acc.activity['subactivity']
if 'text' in acc.activity:
del acc.activity['text']
user = common.gajim.get_room_and_nick_from_fjid(jid)[0] def _update_account(self, account):
for contact in common.gajim.contacts.get_contacts(name, user): acc = common.gajim.connections[account]
if has_child: if self._retracted:
if 'activity' in contact.activity: if self.type in acc.pep:
del contact.activity['activity'] del acc.pep[self.type]
if 'subactivity' in contact.activity: else:
del contact.activity['subactivity'] acc.pep[self.type] = self
if 'text' in contact.activity:
del contact.activity['text']
if activity is not None:
contact.activity['activity'] = activity
if subactivity is not None and subactivity != 'other':
contact.activity['subactivity'] = subactivity
if text is not None:
contact.activity['text'] = text
elif retract:
if 'activity' in contact.activity:
del contact.activity['activity']
if 'subactivity' in contact.activity:
del contact.activity['subactivity']
if 'text' in contact.activity:
del contact.activity['text']
if jid == common.gajim.get_jid_from_account(name): def asPixbufIcon(self):
common.gajim.interface.roster.draw_account(name) '''To be implemented by subclasses'''
common.gajim.interface.roster.draw_activity(user, name) raise NotImplementedError
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name)
if ctrl:
ctrl.update_activity()
def user_nickname(items, name, jid): def asMarkupText(self):
has_child = False '''To be implemented by subclasses'''
retract = False raise NotImplementedError
nick = None
for item in items.getTags('item'):
child = item.getTag('nick')
if child is not None:
has_child = True
nick = child.getData()
break
if items.getTag('retract') is not None: class UserMoodPEP(AbstractPEP):
retract = True '''XEP-0107: User Mood'''
if jid == common.gajim.get_jid_from_account(name): type = 'mood'
if has_child: namespace = common.xmpp.NS_MOOD
common.gajim.nicks[name] = nick
if retract:
common.gajim.nicks[name] = common.gajim.config.get_per('accounts',
name, 'name')
user = common.gajim.get_room_and_nick_from_fjid(jid)[0] def _extract_info(self, items):
if has_child: mood_dict = {}
if nick is not None:
for contact in common.gajim.contacts.get_contacts(name, user):
contact.contact_name = nick
common.gajim.interface.roster.draw_contact(user, name)
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name) for item in items.getTags('item'):
if ctrl: mood_tag = item.getTag('mood')
ctrl.update_ui() if mood_tag:
win = ctrl.parent_win for child in mood_tag.getChildren():
win.redraw_tab(ctrl) name = child.getName().strip()
win.show_title() if name == 'text':
elif retract: mood_dict['text'] = child.getData()
contact.contact_name = '' else:
mood_dict['mood'] = name
def user_send_mood(account, mood, message=''): retracted = items.getTag('retract') or not 'mood' in mood_dict
if not common.gajim.connections[account].pep_supported: return (mood_dict, retracted)
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, def asPixbufIcon(self):
'0') 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 user_send_activity(account, activity, subactivity='', message=''): def asMarkupText(self):
if not common.gajim.connections[account].pep_supported: assert not self._retracted
return untranslated_mood = self._pep_specific_data['mood']
item = xmpp.Node('activity', {'xmlns': xmpp.NS_ACTIVITY}) mood = translate_mood(untranslated_mood)
if activity != '': markuptext = '<b>%s</b>' % gobject.markup_escape_text(mood)
i = item.addChild(activity) if 'text' in self._pep_specific_data:
if subactivity != '': text = self._pep_specific_data['text']
i.addChild(subactivity) markuptext += ' (%s)' % gobject.markup_escape_text(text)
if message != '': return markuptext
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, class UserTunePEP(AbstractPEP):
items=None): '''XEP-0118: User Tune'''
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, type = 'tune'
'0') namespace = common.xmpp.NS_TUNE
def user_send_nickname(account, nick): def _extract_info(self, items):
if not common.gajim.connections[account].pep_supported: tune_dict = {}
return
item = xmpp.Node('nick', {'xmlns': xmpp.NS_NICK})
item.addData(nick)
common.gajim.connections[account].send_pb_publish('', xmpp.NS_NICK, item, for item in items.getTags('item'):
'0') 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
def user_retract_mood(account): retracted = items.getTag('retract') or not ('artist' in tune_dict or
common.gajim.connections[account].send_pb_retract('', xmpp.NS_MOOD, '0') 'title' in tune_dict)
return (tune_dict, retracted)
def user_retract_activity(account): def asPixbufIcon(self):
common.gajim.connections[account].send_pb_retract('', xmpp.NS_ACTIVITY, '0') import os
path = os.path.join(gajim.DATA_DIR, 'emoticons', 'static', 'music.png')
return gtk.gdk.pixbuf_new_from_file(path)
def user_retract_tune(account): def asMarkupText(self):
common.gajim.connections[account].send_pb_retract('', xmpp.NS_TUNE, '0') assert not self._retracted
tune = self._pep_specific_data
def user_retract_nickname(account): artist = tune.get('artist', _('Unknown Artist'))
common.gajim.connections[account].send_pb_retract('', xmpp.NS_NICK, '0') artist = gobject.markup_escape_text(artist)
def delete_pep(jid, name): title = tune.get('title', _('Unknown Title'))
user = common.gajim.get_room_and_nick_from_fjid(jid)[0] title = gobject.markup_escape_text(title)
if jid == common.gajim.get_jid_from_account(name): source = tune.get('source', _('Unknown Source'))
acc = common.gajim.connections[name] source = gobject.markup_escape_text(source)
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): tune_string = _('<b>"%(title)s"</b> by <i>%(artist)s</i>\n'
del contact.activity 'from <i>%(source)s</i>') % {'title': title,
contact.activity = {} 'artist': artist, 'source': source}
del contact.tune return tune_string
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) class UserActivityPEP(AbstractPEP):
common.gajim.interface.roster.draw_tune(user, name) '''XEP-0108: User Activity'''
common.gajim.interface.roster.draw_mood(user, name)
ctrl = common.gajim.interface.msg_win_mgr.get_control(user, name) type = 'activity'
if ctrl: namespace = common.xmpp.NS_ACTIVITY
ctrl.update_activity()
ctrl.update_tune() def _extract_info(self, items):
ctrl.update_mood() activity_dict = {}
for item in items.getTags('item'):
activity_tag = item.getTag('activity')
if activity_tag:
for child in activity_tag.getChildren():
name = child.getName().strip()
data = child.getData().strip()
if name == 'text':
activity_dict['text'] = data
else:
activity_dict['activity'] = name
for subactivity in child.getChildren():
subactivity_name = subactivity.getName().strip()
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
if activity in ACTIVITIES:
# Translate standard activities
if subactivity in ACTIVITIES[activity]:
subactivity = ACTIVITIES[activity][subactivity]
activity = ACTIVITIES[activity]['category']
markuptext = '<b>' + gobject.markup_escape_text(activity)
if subactivity:
markuptext += ': ' + gobject.markup_escape_text(subactivity)
markuptext += '</b>'
if text:
markuptext += ' (%s)' % gobject.markup_escape_text(text)
return markuptext
class UserNicknamePEP(AbstractPEP):
'''XEP-0172: User Nickname'''
type = 'nickname'
namespace = common.xmpp.NS_NICK
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
SUPPORTED_PERSONAL_USER_EVENTS = [UserMoodPEP, UserTunePEP, UserActivityPEP,
UserNicknamePEP]
class ConnectionPEP(object):
def _pubsubEventCB(self, xmpp_dispatcher, msg):
''' 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 pep_class in SUPPORTED_PERSONAL_USER_EVENTS:
pep = pep_class.get_tag_as_PEP(jid, self.name, event_tag)
if pep:
self.dispatch('PEP_RECEIVED', (jid, pep.type))
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')
def send_mood(self, mood, message=None):
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')
def retract_tune(self):
if not self.pep_supported:
return
# not all server support retract, so send empty pep first
self.send_tune(None)
self.send_pb_retract('', xmpp.NS_TUNE, '0')
def send_nickname(self, nick):
if not self.pep_supported:
return
item = xmpp.Node('nick', {'xmlns': xmpp.NS_NICK})
item.addData(nick)
self.send_pb_publish('', xmpp.NS_NICK, item, '0')
def retract_nickname(self):
if not self.pep_supported:
return
# not all server support retract, so send empty pep first
self.send_tune(None)
self.send_pb_retract('', xmpp.NS_NICK, '0')
# 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):
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_mood(self, jid, account): 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
# activity
if 'activity' in pep_dict and pep_dict['activity'] in pep.ACTIVITIES:
activity = pep_dict['activity']
if 'subactivity' in pep_dict and \
pep_dict['subactivity'] in pep.ACTIVITIES[activity]:
subactivity = pep_dict['subactivity']
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:
pep.user_send_activity(account, '')
# mood if 'activity' in pep_dict:
if 'mood' in pep_dict and pep_dict['mood'] in pep.MOODS: activity = pep_dict['activity']
mood = pep_dict['mood'] subactivity = pep_dict.get('subactivity', None)
if 'mood_text' in pep_dict: activity_text = pep_dict.get('activity_text', None)
mood_text = pep_dict['mood_text'] connection.send_activity(activity, subactivity, activity_text)
else:
mood_text = ''
pep.user_send_mood(account, mood, mood_text)
else: else:
pep.user_send_mood(account, '') connection.retract_activity()
if 'mood' in pep_dict:
mood = pep_dict['mood']
mood_text = pep_dict.get('mood_text', None)
connection.send_mood(mood, mood_text)
else:
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 = {}