Mercurial > libervia-backend
diff frontends/src/quick_frontend/quick_app.py @ 1337:f29beedb33b0 frontends_multi_profiles
merged souliane changes
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 23 Feb 2015 18:08:22 +0100 |
parents | 2ecc07a8f91b 0f92b6a150ff |
children | 139263ee85c5 |
line wrap: on
line diff
--- a/frontends/src/quick_frontend/quick_app.py Mon Feb 23 18:04:25 2015 +0100 +++ b/frontends/src/quick_frontend/quick_app.py Mon Feb 23 18:08:22 2015 +0100 @@ -17,16 +17,25 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from sat.core.i18n import _ -import sys from sat.core.log import getLogger log = getLogger(__name__) + +from sat.core.i18n import _ from sat.core import exceptions + from sat_frontends.tools import jid from sat_frontends.quick_frontend.quick_widgets import QuickWidgetsManager from sat_frontends.quick_frontend import quick_chat +from sat_frontends.quick_frontend.constants import Const as C -from sat_frontends.quick_frontend.constants import Const as C +import sys +from collections import OrderedDict + +try: + # FIXME: to be removed when an acceptable solution is here + unicode('') # XXX: unicode doesn't exist in pyjamas +except (TypeError, AttributeError): # Error raised is not the same depending on pyjsbuild options + unicode = str class ProfileManager(object): @@ -75,11 +84,14 @@ def _plug_profile_gotCachedValues(self, cached_values): # TODO: watched plugin + + # add the contact list and its listener contact_list = self.host.addContactList(self.profile) + self.host.contact_lists[self.profile] = contact_list for entity, data in cached_values.iteritems(): for key, value in data.iteritems(): - self.host.contact_lists[self.profile].setCache(jid.JID(entity), key, value) + contact_list.setCache(jid.JID(entity), key, value) if not self.bridge.isConnected(self.profile): self.host.setStatusOnline(False, profile=self.profile) @@ -169,11 +181,18 @@ def unplug(self, profile): if profile not in self._profiles: raise ValueError('The profile [{}] is not plugged'.format(profile)) + + # remove the contact list and its listener + host = self._profiles[profile].host + host.contact_lists[profile].onDelete() + del host.contact_lists[profile] + del self._profiles[profile] def chooseOneProfile(self): return self._profiles.keys()[0] + class QuickApp(object): """This class contain the main methods needed for the frontend""" @@ -196,7 +215,7 @@ self.selected_widget = None # widget currently selected (must be filled by frontend) # listeners - self._listeners = {} # key: listerner type ("avatar", "selected", etc), value: list of callbacks + self._listeners = {} # key: listener type ("avatar", "selected", etc), value: list of callbacks ## bridge ## try: @@ -287,31 +306,38 @@ handler(*args, **kwargs) self.bridge.register(functionName, signalReceived, iface) - def addListerner(self, type_, callback): - """Add a listerner for an event + def addListener(self, type_, callback, profiles_filter=None): + """Add a listener for an event /!\ don't forget to remove listener when not used anymore (e.g. if you delete a widget) @param type_: type of event, can be: - avatar: called when avatar data is updated - args: (entity, avatar file, profile) + args: (entity, avatar file) + - presence: called when a presence is received + args: (entity, show, priority, statuses) @param callback: method to call on event + @param profiles_filter (set[unicode]): if set and not empty, the + listener will be callable only by one of the given profiles. """ assert type_ in C.LISTENERS - self._listeners.setdefault(type_, []).append(callback) + self._listeners.setdefault(type_, OrderedDict())[callback] = profiles_filter def removeListener(self, type_, callback): """Remove a callback from listeners - @param type_: same as for [addListerner] + @param type_: same as for [addListener] @param callback: callback to remove """ assert type_ in C.LISTENERS - self._listeners[type_].remove(callback) + self._listeners[type_].pop(callback) - def callListeners(self, type_, *args): - """Call all methods which listen of type_ event + def callListeners(self, type_, profile, *args): + """Call the methods which listen type_ event. If a profiles filter has + been register with a listener and profile argument is not None, the + listener will be called only if profile is in the profiles filter list. - @param type_: same as for [addListerner] + @param type_: same as for [addListener] + @param profile (unicode): %(doc_profile)s @param *args: arguments sent to callback """ assert type_ in C.LISTENERS @@ -320,8 +346,9 @@ except KeyError: pass else: - for listener in listeners: - listener(*args) + for listener, profiles_filter in listeners.iteritems(): + if profile is None or not profiles_filter or profile in profiles_filter: + listener(*args) def check_profile(self, profile): """Tell if the profile is currently followed by the application""" @@ -374,7 +401,7 @@ """Tell the application to not follow anymore the profile""" if not profile in self.profiles: raise ValueError("The profile [{}] is not plugged".format(profile)) - self.profiles.remove(profile) + self.profiles.unplug(profile) def clear_profile(self): self.profiles.clear() @@ -468,7 +495,7 @@ # if entity.bare in self.profiles[profile].data.get('watched',[]) and not entity.bare in self.profiles[profile]['onlineContact']: # self.showAlert(_("Watched jid [%s] is connected !") % entity.bare) - self.contact_lists[profile].updatePresence(entity, show, priority, statuses) + self.callListeners('presence', profile, entity, show, priority, statuses) def roomJoinedHandler(self, room_jid_s, room_nicks, user_nick, profile): """Called when a MUC room is joined""" @@ -614,10 +641,8 @@ def _subscribe_cb(self, answer, data): entity, profile = data - if answer: - self.bridge.subscription("subscribed", entity.bare, profile_key=profile) - else: - self.bridge.subscription("unsubscribed", entity.bare, profile_key=profile) + type_ = "subscribed" if answer else "unsubscribed" + self.bridge.subscription(type_, unicode(entity.bare), profile_key=profile) def subscribeHandler(self, type, raw_jid, profile): """Called when a subsciption management signal is received""" @@ -632,7 +657,7 @@ # this is a subscriptionn request, we have to ask for user confirmation self.showDialog(_("The contact %s wants to subscribe to your presence.\nDo you accept ?") % entity.bare, _('Subscription confirmation'), 'yes/no', answer_cb=self._subscribe_cb, answer_data=(entity, profile)) - def showDialog(self, message, title, type="info", answer_cb=None): + def showDialog(self, message, title, type="info", answer_cb=None, answer_data=None): raise NotImplementedError def showAlert(self, message): @@ -650,8 +675,8 @@ elif (namespace, name) == ('General', C.SHOW_EMPTY_GROUPS): self.contact_lists[profile].showEmptyGroups(C.bool(value)) - def contactDeletedHandler(self, jid, profile): - target = jid.JID(jid) + def contactDeletedHandler(self, jid_s, profile): + target = jid.JID(jid_s) self.contact_lists[profile].remove(target) def entityDataUpdatedHandler(self, entity_s, key, value, profile): @@ -663,7 +688,7 @@ if entity in self.contact_lists[profile]: def gotFilename(filename): self.contact_lists[profile].setCache(entity, 'avatar', filename) - self.callListeners('avatar', entity, filename, profile) + self.callListeners('avatar', profile, entity, filename) self.bridge.getAvatarFile(value, callback=gotFilename) def askConfirmationHandler(self, confirm_id, confirm_type, data, profile): @@ -687,8 +712,12 @@ def onExit(self): """Must be called when the frontend is terminating""" + to_unplug = [] for profile in self.profiles: if self.bridge.isConnected(profile): if C.bool(self.bridge.getParamA("autodisconnect", "Connection", profile_key=profile)): #The user wants autodisconnection self.bridge.disconnect(profile) + to_unplug.append(profile) + for profile in to_unplug: + self.unplug_profile(profile)