diff --git a/frontends/src/bridge/DBus.py b/frontends/src/bridge/DBus.py
index fd686bad..fe4783b5 100644
--- a/frontends/src/bridge/DBus.py
+++ b/frontends/src/bridge/DBus.py
@@ -96,6 +96,9 @@ class DBusBridgeFrontend(BridgeFrontend):
def getContacts(self, profile_key="@DEFAULT@"):
return self.db_core_iface.getContacts(profile_key)
+ def getContactsFromGroup(self, group, profile_key="@DEFAULT@"):
+ return self.db_core_iface.getContactsFromGroup(group, profile_key)
+
def getHistory(self, from_jid, to_jid, limit, between=True, callback=None, errback=None):
return self.db_core_iface.getHistory(from_jid, to_jid, limit, between, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:]))
diff --git a/frontends/src/primitivus/chat.py b/frontends/src/primitivus/chat.py
index 3e003cd1..edf18c6e 100644
--- a/frontends/src/primitivus/chat.py
+++ b/frontends/src/primitivus/chat.py
@@ -262,11 +262,8 @@ class Chat(urwid.WidgetWrap, QuickChat):
def startGame(self, game_type, referee, players):
"""Configure the chat window to start a game"""
if game_type=="Tarot":
- try:
- self.tarot_wid = CardGame(self, referee, players, self.nick)
- self.__appendGamePanel(self.tarot_wid)
- except e:
- self.host.debug()
+ self.tarot_wid = CardGame(self, referee, players, self.nick)
+ self.__appendGamePanel(self.tarot_wid)
def getGame(self, game_type):
"""Return class managing the game type"""
@@ -288,6 +285,11 @@ class Chat(urwid.WidgetWrap, QuickChat):
#MISC EVENTS#
def onFileSelected(self, filepath):
self.host.removePopUp()
- full_jid = self.host.CM.get_full(self.target)
+ #FIXME: check last_resource: what if self.target.resource exists ?
+ last_resource = self.host.bridge.getLastResource(unicode(self.target.short), self.host.profile)
+ if last_resource:
+ full_jid = JID("%s/%s" % (self.target.short, last_resource))
+ else:
+ full_jid = self.target
id = self.host.bridge.sendFile(full_jid, filepath, {}, self.host.profile)
self.host.addProgress(id,filepath)
diff --git a/frontends/src/primitivus/constants.py b/frontends/src/primitivus/constants.py
index 4ebaa27b..d7cd40b2 100644
--- a/frontends/src/primitivus/constants.py
+++ b/frontends/src/primitivus/constants.py
@@ -54,6 +54,7 @@ __builtin__.__dict__['const_PALETTE'] = [
('warning', 'light red', 'default'),
('progress_normal', 'default', 'black'),
('progress_complete', 'default', 'light red'),
+ ('show_disconnected', 'dark gray', 'default'),
('show_normal', 'default', 'default'),
('show_normal_focus', 'default, bold', 'default'),
('show_chat', 'dark green', 'default'),
@@ -67,7 +68,8 @@ __builtin__.__dict__['const_PALETTE'] = [
('status', 'yellow', 'default'),
('status_focus', 'yellow, bold', 'default'),
]
-__builtin__.__dict__['const_SHOW_ICON'] = {"": (u'✔', "show_normal"),
+__builtin__.__dict__['const_SHOW_ICON'] = {"unavailable": (u'⨯', "show_disconnected"),
+ "": (u'✔', "show_normal"),
"chat": (u'✆', "show_chat"),
"away": (u'✈', "show_away"),
"dnd": (u'✖', "show_dnd"),
diff --git a/frontends/src/primitivus/contact_list.py b/frontends/src/primitivus/contact_list.py
index ac122c52..46000a18 100644
--- a/frontends/src/primitivus/contact_list.py
+++ b/frontends/src/primitivus/contact_list.py
@@ -28,12 +28,13 @@ from sat.tools.jid import JID
class ContactList(urwid.WidgetWrap, QuickContactList):
signals = ['click','change']
- def __init__(self, host, CM, on_click=None, on_change=None, user_data=None):
+ def __init__(self, host, on_click=None, on_change=None, user_data=None):
self.host = host
self.selected = None
self.groups={}
self.alert_jid=set()
self.show_status = False
+ self.show_disconnected = False
#we now build the widget
self.frame = urwid.Frame(self.__buildList())
@@ -43,9 +44,9 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
urwid.connect_signal(self, 'click', on_click, user_data)
if on_change:
urwid.connect_signal(self, 'change', on_change, user_data)
- QuickContactList.__init__(self, CM)
+ QuickContactList.__init__(self)
- def _update(self):
+ def update(self):
"""Update display, keep focus"""
widget, position = self.frame.body.get_focus()
self.frame.body = self.__buildList()
@@ -53,10 +54,16 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
self.frame.body.set_focus(position)
self.host.redraw()
+ def update_jid(self, jid):
+ self.update()
+
def keypress(self, size, key):
if key == "meta s": #user wants to (un)hide contacts' statuses
self.show_status = not self.show_status
- self._update()
+ self.update()
+ elif key == "meta d": #user wants to (un)hide disconnected contacts
+ self.show_disconnected = not self.show_disconnected
+ self.update()
return super(ContactList, self).keypress(size, key)
def __contains__(self, jid):
@@ -77,12 +84,12 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
def putAlert(self, jid):
"""Put an alert on the jid to get attention from user (e.g. for new message)"""
self.alert_jid.add(jid.short)
- self._update()
+ self.update()
def __groupClicked(self, group_wid):
group = self.groups[group_wid.getValue()]
group[0] = not group[0]
- self._update()
+ self.update()
self.setFocus(group_wid.getValue())
def __contactClicked(self, contact_wid, selected):
@@ -92,7 +99,7 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
widget.setState(widget.data == self.selected, invisible=True)
if self.selected in self.alert_jid:
self.alert_jid.remove(self.selected)
- self._update()
+ self.update()
self._emit('click')
def __buildContact(self, content, param_contacts):
@@ -100,13 +107,20 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
@param content: widget list, e.g. SimpleListWalker
@param contacts: list of JID"""
contacts = list(param_contacts)
- contacts.sort()
+
+ widgets = [] #list of built widgets
+
for contact in contacts:
jid=JID(contact)
- name = self.CM.getAttr(jid,'name')
- nick = self.CM.getAttr(jid,'nick')
- status = self.CM.getAttr(jid, 'status')
- show = self.CM.getAttr(jid, 'show')
+ name = self.getCache(jid, 'name')
+ nick = self.getCache(jid, 'nick')
+ status = self.getCache(jid, 'status')
+ show = self.getCache(jid, 'show')
+ if show == None:
+ show = "unavailable"
+ if (not self.show_disconnected and show == "unavailable"
+ and not contact in self.alert_jid and contact != self.selected):
+ continue
show_icon, show_attr = const_SHOW_ICON.get(show,('','default'))
contact_disp = ('alert' if contact in self.alert_jid else show_attr, nick or name or jid.node or jid.short)
display = [ show_icon + " " , contact_disp]
@@ -118,6 +132,12 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
selected = contact==self.selected,
header=header)
widget.data = contact
+ widget.comp = contact_disp[1].lower() #value to use for sorting
+ widgets.append(widget)
+
+ widgets.sort(key=lambda widget: widget.comp)
+
+ for widget in widgets:
content.append(widget)
urwid.connect_signal(widget, 'change', self.__contactClicked)
@@ -125,7 +145,7 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
"""Build the main contact list widget"""
content = urwid.SimpleListWalker([])
group_keys = self.groups.keys()
- group_keys.sort()
+ group_keys.sort(key = lambda x: x.lower() if x else x)
for key in group_keys:
unfolded = self.groups[key][0]
if key!=None:
@@ -145,28 +165,30 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
widget.setState(False, invisible=True)
- def get_contact(self):
+ def getContact(self):
"""Return contact currently selected"""
return self.selected
- def clear_contacts(self):
+ def clearContacts(self):
"""clear all the contact list"""
self.groups={}
self.selected = None
self.unselectAll()
- self._update()
+ self.update()
- def replace(self, jid, groups=[None]):
+ def replace(self, jid, groups=None, attributes=None):
"""add a contact to the list if doesn't exist, else update it"""
+ if not groups:
+ groups = [None]
+ if not attributes:
+ attributes={}
assert isinstance(groups, list)
assert isinstance(jid, JID)
- if not groups:
- groups=[None]
for group in groups:
if not self.groups.has_key(group):
self.groups[group] = [True,set()] #[unfold,list_of_contacts]
self.groups[group][1].add(jid.short)
- self._update()
+ self.update()
"""contacts = self.list_wid.getAllValues()
@@ -176,10 +198,6 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
self.list_wid.changeValues(contacts)
self._emit('change')"""
- def disconnect(self, jid):
- """mark a contact disconnected"""
- self.remove(jid.short)
-
def remove(self, param_jid):
"""remove a contact from the list"""
groups_to_remove = []
@@ -192,7 +210,7 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
groups_to_remove.append(group)
for group in groups_to_remove:
del self.groups[group]
- self._update()
+ self.update()
def add(self, jid, param_groups=[None]):
"""add a contact to the list"""
diff --git a/frontends/src/primitivus/primitivus b/frontends/src/primitivus/primitivus
index 6c7ca853..1792ef7b 100755
--- a/frontends/src/primitivus/primitivus
+++ b/frontends/src/primitivus/primitivus
@@ -56,7 +56,6 @@ class ChatList(QuickChatList):
class PrimitivusApp(QuickApp):
def __init__(self):
- self.CM = QuickContactManagement() #FIXME: not the best place
QuickApp.__init__(self)
## main loop setup ##
@@ -141,12 +140,12 @@ class PrimitivusApp(QuickApp):
elif input == 'f2': #user wants to (un)hide the contact_list
try:
center_widgets = self.center_part.widget_list
- if self.contactList in center_widgets:
+ if self.contact_list in center_widgets:
self.center_part.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.center_part
- center_widgets.remove(self.contactList)
+ center_widgets.remove(self.contact_list)
del self.center_part.column_types[0]
else:
- center_widgets.insert(0, self.contactList)
+ center_widgets.insert(0, self.contact_list)
self.center_part.column_types.insert(0, ('weight', 2))
except AttributeError:
#The main widget is not built (probably in Profile Manager)
@@ -196,9 +195,9 @@ class PrimitivusApp(QuickApp):
return menu_roller
def __buildMainWidget(self):
- self.contactList = ContactList(self, self.CM, on_click = self.contactSelected, on_change=lambda w: self.redraw())
- #self.center_part = urwid.Columns([('weight',2,self.contactList),('weight',8,Chat('',self))])
- self.center_part = urwid.Columns([('weight',2,self.contactList), ('weight',8,urwid.Filler(urwid.Text('')))])
+ self.contact_list = ContactList(self, on_click = self.contactSelected, on_change=lambda w: self.redraw())
+ #self.center_part = urwid.Columns([('weight',2,self.contact_list),('weight',8,Chat('',self))])
+ self.center_part = urwid.Columns([('weight',2,self.contact_list), ('weight',8,urwid.Filler(urwid.Text('')))])
self.editBar = sat_widgets.AdvancedEdit(u'> ')
self.editBar.setCompletionMethod(self._nick_completion)
urwid.connect_signal(self.editBar,'click',self.onTextEntered)
@@ -209,7 +208,7 @@ class PrimitivusApp(QuickApp):
def _nick_completion(self, text, completion_data):
"""Completion method which complete pseudo in group chat
for params, see AdvancedEdit"""
- contact = self.contactList.get_contact() ###Based on the fact that there is currently only one contact selectable at once
+ contact = self.contact_list.getContact() ###Based on the fact that there is currently only one contact selectable at once
if contact:
chat = self.chat_wins[contact]
if chat.type != "group":
@@ -266,7 +265,7 @@ class PrimitivusApp(QuickApp):
wid_idx = len(self.center_part.widget_list)-1
self.center_part.widget_list[wid_idx] = widget
self.menu_roller.removeMenu(_('Chat menu'))
- self.contactList.unselectAll()
+ self.contact_list.unselectAll()
self.redraw()
def removeWindow(self):
@@ -289,7 +288,7 @@ class PrimitivusApp(QuickApp):
self.notBar.setProgress(percentage)
def contactSelected(self, contact_list):
- contact = contact_list.get_contact()
+ contact = contact_list.getContact()
if contact:
assert(len(self.center_part.widget_list)==2)
self.center_part.widget_list[1] = self.chat_wins[contact]
@@ -297,7 +296,7 @@ class PrimitivusApp(QuickApp):
def onTextEntered(self, editBar):
"""Called when text is entered in the main edit bar"""
- contact = self.contactList.get_contact() ###Based on the fact that there is currently only one contact selectableat once
+ contact = self.contact_list.getContact() ###Based on the fact that there is currently only one contact selectableat once
if contact:
chat = self.chat_wins[contact]
self.bridge.sendMessage(contact,
@@ -311,8 +310,8 @@ class PrimitivusApp(QuickApp):
return
QuickApp.newMessage(self, from_jid, msg, type, to_jid, profile)
sender = JID(from_jid)
- if JID(self.contactList.selected).short != sender.short:
- self.contactList.putAlert(sender)
+ if JID(self.contact_list.selected).short != sender.short:
+ self.contact_list.putAlert(sender)
def _dialogOkCb(self, widget, data):
self.removePopUp()
@@ -422,8 +421,8 @@ class PrimitivusApp(QuickApp):
def onRemoveContact(self, button):
self.removePopUp()
- info(_("Unsubscribing %s presence"),self.contactList.get_contact())
- self.bridge.delContact(self.contactList.get_contact(), profile_key=self.profile)
+ info(_("Unsubscribing %s presence"),self.contact_list.getContact())
+ self.bridge.delContact(self.contact_list.getContact(), profile_key=self.profile)
#MENU EVENTS#
def onConnectRequest(self, menu):
@@ -460,7 +459,7 @@ class PrimitivusApp(QuickApp):
self.showPopUp(pop_up_widget)
def onRemoveContactRequest(self, menu):
- contact = self.contactList.get_contact()
+ contact = self.contact_list.getContact()
if not contact:
self.showPopUp(sat_widgets.Alert(_("Error"), _("You have not selected any contact to delete !"), ok_cb=self.removePopUp))
else:
diff --git a/frontends/src/quick_frontend/quick_app.py b/frontends/src/quick_frontend/quick_app.py
index a1e0b09a..a7a4413e 100644
--- a/frontends/src/quick_frontend/quick_app.py
+++ b/frontends/src/quick_frontend/quick_app.py
@@ -19,7 +19,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
"""
-from logging import debug, info, error
+from logging import debug, info, warning, error
from sat.tools.jid import JID
from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService
from optparse import OptionParser
@@ -32,7 +32,6 @@ class QuickApp():
"""This class contain the main methods needed for the frontend"""
def __init__(self, single_profile=True):
- self.rosterList = {}
self.profiles = {}
self.single_profile = single_profile
self.check_options()
@@ -157,7 +156,7 @@ class QuickApp():
### now we fill the contact list ###
for contact in self.bridge.getContacts(profile):
- self.newContact(contact[0], contact[1], contact[2], profile)
+ self.newContact(*contact, profile=profile)
presences = self.bridge.getPresenceStatus(profile)
for contact in presences:
@@ -207,8 +206,7 @@ class QuickApp():
if not self.check_profile(profile):
return
debug(_("Disconnected"))
- self.CM.clear()
- self.contactList.clear_contacts()
+ self.contactList.clearContacts()
self.setStatusOnline(False)
def connectionError(self, error_type, profile):
@@ -227,10 +225,7 @@ class QuickApp():
return
entity=JID(JabberId)
_groups = list(groups)
- self.rosterList[entity.short]=(dict(attributes), _groups)
- if entity in self.CM:
- self.CM.update(entity, 'groups', _groups)
- self.contactList.replace(entity, self.CM.getAttr(entity, 'groups'))
+ self.contact_list._replace(entity, _groups, attributes)
def newMessage(self, from_jid, msg, type, to_jid, profile):
if not self.check_profile(profile):
@@ -266,36 +261,20 @@ class QuickApp():
self.setStatusOnline(False)
return
+ self.contact_list.updatePresence(from_jid, show, priority, statuses)
+
if show != 'unavailable':
- name=""
- groups = []
- if self.rosterList.has_key(from_jid.short):
- if self.rosterList[from_jid.short][0].has_key("name"):
- name=self.rosterList[from_jid.short][0]["name"]
- groups=self.rosterList[from_jid.short][1]
-
+
#FIXME: must be moved in a plugin
if from_jid.short in self.profiles[profile]['watched'] and not from_jid.short in self.profiles[profile]['onlineContact']:
self.showAlert(_("Watched jid [%s] is connected !") % from_jid.short)
self.profiles[profile]['onlineContact'].add(from_jid) #FIXME onlineContact is useless with CM, must be removed
- self.CM.add(from_jid)
- self.CM.update(from_jid, 'name', unicode(name))
- self.CM.update(from_jid, 'show', show)
- self.CM.update(from_jid, 'statuses', statuses)
- self.CM.update(from_jid, 'groups', groups)
- cache = self.bridge.getCardCache(from_jid, profile)
- if cache.has_key('nick'):
- self.CM.update(from_jid, 'nick', unicode(cache['nick']))
- if cache.has_key('avatar'):
- self.CM.update(from_jid, 'avatar', self.bridge.getAvatarFile(cache['avatar']))
- self.contactList.replace(from_jid, self.CM.getAttr(from_jid, 'groups'))
+
+ #TODO: vcard data (avatar)
if show=="unavailable" and from_jid in self.profiles[profile]['onlineContact']:
self.profiles[profile]['onlineContact'].remove(from_jid)
- self.CM.remove(from_jid)
- if not self.CM.isConnected(from_jid):
- self.contactList.disconnect(from_jid)
def roomJoined(self, room_jid, room_nicks, user_nick, profile):
"""Called when a MUC room is joined"""
@@ -491,27 +470,27 @@ class QuickApp():
if not self.check_profile(profile):
return
target = JID(jid)
- self.contactList.remove(self.CM.get_full(target))
- self.CM.remove(target)
+ self.contactList.remove(target)
try:
self.profiles[profile]['onlineContact'].remove(target.short)
except KeyError:
pass
def updatedValue(self, name, data, profile):
+ #FIXME: to be removed
if not self.check_profile(profile):
return
if name == "card_nick":
target = JID(data['jid'])
if target in self.contactList:
- self.CM.update(target, 'nick', unicode(data['nick']))
- self.contactList.replace(target)
+ #self.CM.update(target, 'nick', unicode(data['nick']))
+ self.contact_list._replace(target)
elif name == "card_avatar":
target = JID(data['jid'])
if target in self.contactList:
filename = self.bridge.getAvatarFile(data['avatar'])
- self.CM.update(target, 'avatar', filename)
- self.contactList.replace(target)
+ #self.CM.update(target, 'avatar', filename)
+ self.contact_list._replace(target)
def askConfirmation(self, type, id, data):
raise NotImplementedError
diff --git a/frontends/src/quick_frontend/quick_chat.py b/frontends/src/quick_frontend/quick_chat.py
index 6193d16a..ef66e8c6 100644
--- a/frontends/src/quick_frontend/quick_chat.py
+++ b/frontends/src/quick_frontend/quick_chat.py
@@ -99,7 +99,7 @@ class QuickChat():
def _get_nick(self, jid):
"""Return nick of this jid when possible"""
- return jid.resource if self.type == "group" else (self.host.CM.getAttr(jid,'nick') or self.host.CM.getAttr(jid,'name') or jid.node)
+ return jid.resource if self.type == "group" else (self.host.contact_list.getCache(jid,'nick') or self.host.contact_list.getCache(jid,'name') or jid.node)
def printMessage(self, from_jid, msg, profile, timestamp):
"""Print message in chat window. Must be implemented by child class"""
diff --git a/frontends/src/quick_frontend/quick_contact_list.py b/frontends/src/quick_frontend/quick_contact_list.py
index 729b245e..161c6f7c 100644
--- a/frontends/src/quick_frontend/quick_contact_list.py
+++ b/frontends/src/quick_frontend/quick_contact_list.py
@@ -19,33 +19,47 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
"""
-from logging import debug, info, error
-from sat.tools.jid import JID
+from logging import debug
class QuickContactList():
"""This class manage the visual representation of contacts"""
- def __init__(self, CM):
- """
- @param CM: instance of QuickContactManagement
- """
+ def __init__(self):
debug(_("Contact List init"))
- self.CM = CM
+ self._cache = {}
+
+ def update_jid(self, jid):
+ """Update the jid in the list when something changed"""
+ raise NotImplementedError
+
+ def getCache(self, jid, name):
+ try:
+ jid_cache = self._cache[jid.short]
+ if name == 'status': #XXX: we get the first status for 'status' key
+ return jid_cache['statuses'].get('default','')
+ return jid_cache[name]
+ except (KeyError, IndexError):
+ return None
+
+ def setCache(self, jid, name, value):
+ jid_cache = self._cache.setdefault(jid.short, {})
+ jid_cache[name] = value
def __contains__(self, jid):
raise NotImplementedError
- def clear_contacts(self, jid):
+ def clearContacts(self, jid):
"""Clear all the contact list"""
raise NotImplementedError
- def replace(self, jid, groups=None):
- """add a contact to the list if doesn't exist, else update it"""
- raise NotImplementedError
+ def _replace(self, jid, groups=None, attributes=None):
+ if 'name' in attributes:
+ self.setCache(jid, 'name', attributes['name'])
+ self.replace(jid, groups, attributes)
- def disconnect(self, jid):
- """mark a contact disconnected"""
+ def replace(self, jid, groups, attributes):
+ """add a contact to the list if doesn't exist, else update it"""
raise NotImplementedError
def remove(self, jid):
@@ -55,3 +69,14 @@ class QuickContactList():
def add(self, jid, param_groups=None):
"""add a contact to the list"""
raise NotImplementedError
+
+ def updatePresence(self, jid, show, priority, statuses):
+ """Update entity's presence status
+ @param jid: entity to update's jid
+ @param show: availability
+ @parap priority: resource's priority
+ @param statuses: dict of statuses"""
+ self.setCache(jid, 'show', show)
+ self.setCache(jid, 'prority', priority)
+ self.setCache(jid, 'statuses', statuses)
+ self.update_jid(jid)
diff --git a/frontends/src/wix/chat.py b/frontends/src/wix/chat.py
index e1a5a88e..c7ff1892 100644
--- a/frontends/src/wix/chat.py
+++ b/frontends/src/wix/chat.py
@@ -258,7 +258,12 @@ class Chat(wx.Frame, QuickChat):
filename = wx.FileSelector(_("Choose a file to send"), flags = wx.FD_FILE_MUST_EXIST)
if filename:
debug(_("filename: %s"),filename)
- full_jid = self.host.CM.get_full(self.target)
+ #FIXME: check last_resource: what if self.target.resource exists ?
+ last_resource = self.host.bridge.getLastResource(unicode(self.target.short), self.host.profile)
+ if last_resource:
+ full_jid = JID("%s/%s" % (self.target.short, last_resource))
+ else:
+ full_jid = self.target
id = self.host.bridge.sendFile(full_jid, filename, {}, self.host.profile)
self.host.waitProgress(id, _("File Transfer"), _("Copying %s") % os.path.basename(filename))
diff --git a/frontends/src/wix/contact_list.py b/frontends/src/wix/contact_list.py
index 9be1ea8c..95462963 100644
--- a/frontends/src/wix/contact_list.py
+++ b/frontends/src/wix/contact_list.py
@@ -44,7 +44,7 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
"CUSTOM" for a customized contact list (self.__presentItem must then be overrided)
"""
wx.SimpleHtmlListBox.__init__(self, parent, -1)
- QuickContactList.__init__(self, host.CM)
+ QuickContactList.__init__(self)
self.host = host
self.type = type
self.__typeSwitch()
@@ -72,17 +72,19 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
result.append(i)
return result
- def replace(self, contact, groups=None):
+ def update_jid(self, jid):
+ self.replace(jid)
+
+ def replace(self, contact, groups=None, attributes=None):
debug(_("update %s") % contact)
if not self.__find_idx(contact):
self.add(contact, groups)
else:
for i in self.__find_idx(contact):
- self.SetString(i, self.__presentItem(contact))
+ _present = self.__presentItem(contact)
+ if _present != None:
+ self.SetString(i, _present)
- def disconnect(self, contact):
- self.remove(contact) #for now, we only show online contacts
-
def __eraseGroup(self, group):
"""Erase all contacts in group
@param group: group to erase
@@ -108,15 +110,19 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
def __presentItemJID(self, jid):
"""Make a nice presentation of the contact in the list for JID contacts."""
- name = self.CM.getAttr(jid,'name')
- nick = self.CM.getAttr(jid,'nick')
- show = filter(lambda x:x[0]==self.CM.getAttr(jid,'show'), const_STATUS)[0]
+ name = self.getCache(jid,'name')
+ nick = self.getCache(jid,'nick')
+ _show = self.getCache(jid,'show')
+ if _show == None or _show == 'unavailable':
+ return None
+ show = filter(lambda x : x[0] == _show, const_STATUS)[0]
+
#show[0]==shortcut
#show[1]==human readable
#show[2]==color (or None)
show_html = "[%s]" % (show[2], show[1]) if show[2] else ""
- status = self.CM.getAttr(jid,'status') or ''
- avatar = self.CM.getAttr(jid,'avatar') or self.empty_avatar #XXX: there is a weird bug here: if the image has an extension (i.e. empty_avatar.png),
+ status = self.getCache(jid,'status') or ''
+ avatar = self.getCache(jid,'avatar') or self.empty_avatar #XXX: there is a weird bug here: if the image has an extension (i.e. empty_avatar.png),
#WxPython segfault, and it doesn't without nothing. I couldn't reproduce the case with a basic test script, so it need further investigation before reporting it
#to WxPython dev. Anyway, the program crash with a segfault, not a python exception, so there is definitely something wrong with WxPython.
#The case seems to happen when SimpleHtmlListBox parse the HTML with the
tag
@@ -138,7 +144,7 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
return html
- def clear_contacts(self):
+ def clearContacts(self):
"""Clear all the contact list"""
self.Clear()
@@ -146,7 +152,9 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
"""add a contact to the list"""
debug (_("adding %s"),contact)
if not groups:
- idx = self.Insert(self.__presentItem(contact), 0, contact)
+ _present = self.__presentItem(contact)
+ if _present:
+ idx = self.Insert(_present, 0, contact)
else:
for group in groups:
indexes = self.__find_idx(group)
@@ -156,7 +164,9 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
else:
gp_idx = indexes[0]
- self.Insert(self.__presentItem(contact), gp_idx+1, contact)
+ _present = self.__presentItem(contact)
+ if _present:
+ self.Insert(_present, gp_idx+1, contact)
@@ -176,11 +186,13 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
group = self.GetClientData(self.GetSelection())
erased = self.__eraseGroup(group)
if not erased: #the group was already erased, we can add again the contacts
- contacts = self.CM.getContFromGroup(group)
+ contacts = [JID(contact) for contact in self.host.bridge.getContactsFromGroup(group, self.host.profile)]
contacts.sort()
id_insert = self.GetSelection()+1
for contact in contacts:
- self.Insert(self.__presentItem(contact), id_insert, contact)
+ _present = self.__presentItem(contact)
+ if _present:
+ self.Insert(_present, id_insert, contact)
self.SetSelection(wx.NOT_FOUND)
self.ScrollToLine(first_visible)
event.Skip(False)
diff --git a/frontends/src/wix/main_window.py b/frontends/src/wix/main_window.py
index 8dcb98b1..a6a1c43b 100644
--- a/frontends/src/wix/main_window.py
+++ b/frontends/src/wix/main_window.py
@@ -64,17 +64,16 @@ class MainWindow(wx.Frame, QuickApp):
def __init__(self):
QuickApp.__init__(self)
wx.Frame.__init__(self,None, title="SàT Wix", size=(300,500))
- self.CM = QuickContactManagement() #FIXME: not the best place
#sizer
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.sizer)
#Frame elements
- self.contactList = ContactList(self, self)
- self.contactList.registerActivatedCB(self.onContactActivated)
- self.contactList.Hide()
- self.sizer.Add(self.contactList, 1, flag=wx.EXPAND)
+ self.contact_list = ContactList(self, self)
+ self.contact_list.registerActivatedCB(self.onContactActivated)
+ self.contact_list.Hide()
+ self.sizer.Add(self.contact_list, 1, flag=wx.EXPAND)
self.chat_wins=ChatList(self)
self.CreateStatusBar()
@@ -120,7 +119,7 @@ class MainWindow(wx.Frame, QuickApp):
"""Hide profile panel then plug profile"""
debug (_('plugin profile %s' % profile_key))
self.profile_pan.Hide()
- self.contactList.Show()
+ self.contact_list.Show()
self.sizer.Layout()
for i in range(self.menuBar.GetMenuCount()):
self.menuBar.EnableTop(i, True)
@@ -410,7 +409,7 @@ class MainWindow(wx.Frame, QuickApp):
def onRemoveContact(self, e):
debug(_("Remove contact request"))
- target = self.contactList.getSelection()
+ target = self.contact_list.getSelection()
if not target:
dlg = wx.MessageDialog(self, _("You haven't selected any contact !"),
_('Error'),
@@ -433,7 +432,7 @@ class MainWindow(wx.Frame, QuickApp):
def onShowProfile(self, e):
debug(_("Show contact's profile request"))
- target = self.contactList.getSelection()
+ target = self.contact_list.getSelection()
if not target:
dlg = wx.MessageDialog(self, _("You haven't selected any contact !"),
_('Error'),
diff --git a/src/bridge/DBus.py b/src/bridge/DBus.py
index 3efc1b37..fc85d6c2 100755
--- a/src/bridge/DBus.py
+++ b/src/bridge/DBus.py
@@ -255,6 +255,12 @@ class DbusObject(dbus.service.Object):
def getContacts(self, profile_key="@DEFAULT@"):
return self._callback("getContacts", unicode(profile_key))
+ @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
+ in_signature='ss', out_signature='as',
+ async_callbacks=None)
+ def getContactsFromGroup(self, group, profile_key="@DEFAULT@"):
+ return self._callback("getContactsFromGroup", unicode(group), unicode(profile_key))
+
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
in_signature='ssib', out_signature='a(dsss)',
async_callbacks=('callback', 'errback'))
@@ -366,7 +372,7 @@ class DbusObject(dbus.service.Object):
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
in_signature='sssss', out_signature='',
async_callbacks=None)
- def sendMessage(self, to_jid, message, subject='', mess_type="chat", profile_key="@DEFAULT@"):
+ def sendMessage(self, to_jid, message, subject='', mess_type="auto", profile_key="@DEFAULT@"):
return self._callback("sendMessage", unicode(to_jid), unicode(message), unicode(subject), unicode(mess_type), unicode(profile_key))
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
diff --git a/src/bridge/bridge_constructor/bridge_template.ini b/src/bridge/bridge_constructor/bridge_template.ini
index c03a530b..fafa8c42 100644
--- a/src/bridge/bridge_constructor/bridge_template.ini
+++ b/src/bridge/bridge_constructor/bridge_template.ini
@@ -271,6 +271,17 @@ doc_return=array of tuples with the following values:
- list of attributes as in [newContact]
- groups where the contact is
+[getContactsFromGroup]
+type=method
+category=core
+sig_in=ss
+sig_out=as
+param_1_default="@DEFAULT@"
+doc=Return informations about all contacts
+doc_param_0=group: name of the group to check
+doc_param_1=%(doc_profile_key)s
+doc_return=array of jids
+
[getLastResource]
type=method
category=core
diff --git a/src/core/exceptions.py b/src/core/exceptions.py
index 943163c3..3d2b9d09 100644
--- a/src/core/exceptions.py
+++ b/src/core/exceptions.py
@@ -30,3 +30,6 @@ class ConnectedProfileError(Exception):
class UnknownEntityError(Exception):
pass
+
+class UnknownGroupError(Exception):
+ pass
diff --git a/src/core/sat_main.py b/src/core/sat_main.py
index f8e67de8..bf3efbbc 100644
--- a/src/core/sat_main.py
+++ b/src/core/sat_main.py
@@ -126,6 +126,7 @@ class SAT(service.Service):
self.bridge.register("asyncConnect", self.asyncConnect)
self.bridge.register("disconnect", self.disconnect)
self.bridge.register("getContacts", self.getContacts)
+ self.bridge.register("getContactsFromGroup", self.getContactsFromGroup)
self.bridge.register("getLastResource", self.memory.getLastResource)
self.bridge.register("getPresenceStatus", self.memory.getPresenceStatus)
self.bridge.register("getWaitingSub", self.memory.getWaitingSub)
@@ -276,8 +277,7 @@ class SAT(service.Service):
def getContacts(self, profile_key):
client = self.getClient(profile_key)
if not client:
- error(_('Asking contacts for a non-existant profile'))
- return []
+ raise ProfileUnknownError(_('Asking contacts for a non-existant profile'))
ret = []
for item in client.roster.getItems(): #we get all item for client's roster
#and convert them to expected format
@@ -285,6 +285,12 @@ class SAT(service.Service):
ret.append([item.jid.userhost(), attr, item.groups])
return ret
+ def getContactsFromGroup(self, group, profile_key):
+ client = self.getClient(profile_key)
+ if not client:
+ raise ProfileUnknownError(_("Asking group's contacts for a non-existant profile"))
+ return client.roster.getJidsFromGroup(group)
+
def purgeClient(self, profile):
"""Remove reference to a profile client and purge cache
the garbage collector can then free the memory"""
diff --git a/src/core/xmpp.py b/src/core/xmpp.py
index 3a119656..f67b7953 100644
--- a/src/core/xmpp.py
+++ b/src/core/xmpp.py
@@ -23,6 +23,7 @@ from twisted.internet import task, defer
from twisted.words.protocols.jabber import jid, xmlstream
from wokkel import client, disco, xmppim, generic, compat
from logging import debug, info, error
+from sat.core import exceptions
class SatXMPPClient(client.XMPPClient):
@@ -164,9 +165,9 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
"""Return dictionary of attributes as used in bridge from a RosterItem
@param item: RosterItem
@return: dictionary of attributes"""
- item_attr = {'to': str(item.subscriptionTo),
- 'from': str(item.subscriptionFrom),
- 'ask': str(item.ask)
+ item_attr = {'to': unicode(item.subscriptionTo),
+ 'from': unicode(item.subscriptionFrom),
+ 'ask': unicode(item.ask)
}
if item.name:
item_attr['name'] = item.name
@@ -235,6 +236,12 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
def getItems(self):
"""Return all items of the roster"""
return self._jids.values()
+
+ def getJidsFromGroup(self, group):
+ try:
+ return self._groups[group]
+ except KeyError:
+ return exceptions.UnknownGroupError
class SatPresenceProtocol(xmppim.PresenceClientProtocol):
diff --git a/src/tools/misc.py b/src/tools/misc.py
index 9ddcd744..ba41c91b 100644
--- a/src/tools/misc.py
+++ b/src/tools/misc.py
@@ -55,7 +55,7 @@ class TriggerManager:
"""This put a trigger point
All the trigger for that point will be run
@param point_name: name of the trigger point
- @return: True if the action must be continue, False else"""
+ @return: True if the action must be continued, False else"""
if not self.__triggers.has_key(point_name):
return True