Mercurial > libervia-backend
comparison frontends/src/primitivus/contact_list.py @ 1938:011eff37e21d
quick frontend, primitivus: quickContactList refactored to handle several profiles at once
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 18 Apr 2016 18:31:13 +0200 |
parents | 2daf7b4c6756 |
children | 02d21a589be2 |
comparison
equal
deleted
inserted
replaced
1937:14a33c2b1b2a | 1938:011eff37e21d |
---|---|
26 from sat_frontends.primitivus.keys import action_key_map as a_key | 26 from sat_frontends.primitivus.keys import action_key_map as a_key |
27 from sat_frontends.primitivus.widget import PrimitivusWidget | 27 from sat_frontends.primitivus.widget import PrimitivusWidget |
28 from sat_frontends.tools import jid | 28 from sat_frontends.tools import jid |
29 from sat.core import log as logging | 29 from sat.core import log as logging |
30 log = logging.getLogger(__name__) | 30 log = logging.getLogger(__name__) |
31 from sat_frontends.quick_frontend import quick_widgets | |
31 | 32 |
32 | 33 |
33 class ContactList(PrimitivusWidget, QuickContactList): | 34 class ContactList(PrimitivusWidget, QuickContactList): |
35 PROFILES_MULTIPLE=False | |
36 PROFILES_ALLOW_NONE=False | |
34 signals = ['click','change'] | 37 signals = ['click','change'] |
35 | 38 # FIXME: Only single profile is managed so far |
36 def __init__(self, host, on_click=None, on_change=None, user_data=None, profile=None): | 39 |
37 QuickContactList.__init__(self, host, profile) | 40 def __init__(self, host, target, on_click=None, on_change=None, user_data=None, profiles=None): |
41 QuickContactList.__init__(self, host, profiles) | |
42 self.contact_list = self.host.contact_lists[self.profile] | |
38 | 43 |
39 #we now build the widget | 44 #we now build the widget |
40 self.status_bar = StatusBar(host) | 45 self.status_bar = StatusBar(host) |
41 self.frame = sat_widgets.FocusFrame(self._buildList(), None, self.status_bar) | 46 self.frame = sat_widgets.FocusFrame(self._buildList(), None, self.status_bar) |
42 PrimitivusWidget.__init__(self, self.frame, _(u'Contacts')) | 47 PrimitivusWidget.__init__(self, self.frame, _(u'Contacts')) |
43 if on_click: | 48 if on_click: |
44 urwid.connect_signal(self, 'click', on_click, user_data) | 49 urwid.connect_signal(self, 'click', on_click, user_data) |
45 if on_change: | 50 if on_change: |
46 urwid.connect_signal(self, 'change', on_change, user_data) | 51 urwid.connect_signal(self, 'change', on_change, user_data) |
47 | 52 |
48 def update(self): | 53 def update(self, entities=None, type_=None, profile=None): |
49 """Update display, keep focus""" | 54 """Update display, keep focus""" |
55 # FIXME: full update is done each time, must handle entities, type_ and profile | |
50 widget, position = self.frame.body.get_focus() | 56 widget, position = self.frame.body.get_focus() |
51 self.frame.body = self._buildList() | 57 self.frame.body = self._buildList() |
52 if position: | 58 if position: |
53 try: | 59 try: |
54 self.frame.body.focus_position = position | 60 self.frame.body.focus_position = position |
63 if key in sat_widgets.FOCUS_KEYS: | 69 if key in sat_widgets.FOCUS_KEYS: |
64 if (key == a_key['FOCUS_SWITCH'] or (key == a_key['FOCUS_UP'] and self.frame.focus_position == 'body') or | 70 if (key == a_key['FOCUS_SWITCH'] or (key == a_key['FOCUS_UP'] and self.frame.focus_position == 'body') or |
65 (key == a_key['FOCUS_DOWN'] and self.frame.focus_position == 'footer')): | 71 (key == a_key['FOCUS_DOWN'] and self.frame.focus_position == 'footer')): |
66 return key | 72 return key |
67 if key == a_key['STATUS_HIDE']: #user wants to (un)hide contacts' statuses | 73 if key == a_key['STATUS_HIDE']: #user wants to (un)hide contacts' statuses |
68 self.show_status = not self.show_status | 74 self.contact_list.show_status = not self.contact_list.show_status |
69 self.update() | 75 self.update() |
70 elif key == a_key['DISCONNECTED_HIDE']: #user wants to (un)hide disconnected contacts | 76 elif key == a_key['DISCONNECTED_HIDE']: #user wants to (un)hide disconnected contacts |
71 self.host.bridge.setParam(C.SHOW_OFFLINE_CONTACTS, C.boolConst(not self.show_disconnected), "General", profile_key=self.profile) | 77 self.host.bridge.setParam(C.SHOW_OFFLINE_CONTACTS, C.boolConst(not self.contact_list.show_disconnected), "General", profile_key=self.profile) |
72 elif key == a_key['RESOURCES_HIDE']: #user wants to (un)hide contacts resources | 78 elif key == a_key['RESOURCES_HIDE']: #user wants to (un)hide contacts resources |
73 self.showResources(not self.show_resources) | 79 self.contact_list.showResources(not self.contact_list.show_resources) |
74 self.update() | 80 self.update() |
75 return super(ContactList, self).keypress(size, key) | 81 return super(ContactList, self).keypress(size, key) |
82 | |
83 # QuickWidget methods | |
84 | |
85 @staticmethod | |
86 def getWidgetHash(target, profiles): | |
87 profiles = sorted(profiles) | |
88 return tuple(profiles) | |
76 | 89 |
77 # modify the contact list | 90 # modify the contact list |
78 | 91 |
79 def setFocus(self, text, select=False): | 92 def setFocus(self, text, select=False): |
80 """give focus to the first element that matches the given text. You can also | 93 """give focus to the first element that matches the given text. You can also |
120 | 133 |
121 # events | 134 # events |
122 | 135 |
123 def _groupClicked(self, group_wid): | 136 def _groupClicked(self, group_wid): |
124 group = group_wid.getValue() | 137 group = group_wid.getValue() |
125 data = self.getGroupData(group) | 138 data = self.contact_list.getGroupData(group) |
126 data[C.GROUP_DATA_FOLDED] = not data.setdefault(C.GROUP_DATA_FOLDED, False) | 139 data[C.GROUP_DATA_FOLDED] = not data.setdefault(C.GROUP_DATA_FOLDED, False) |
127 self.setFocus(group) | 140 self.setFocus(group) |
128 self.update() | 141 self.update() |
129 | 142 |
130 def _contactClicked(self, use_bare_jid, contact_wid, selected): | 143 def _contactClicked(self, use_bare_jid, contact_wid, selected): |
134 If True, all jids in self._alerts with the same bare jid has contact_wid.data will be removed | 147 If True, all jids in self._alerts with the same bare jid has contact_wid.data will be removed |
135 @param contact_wid: widget of the contact, must have the entity set in data attribute | 148 @param contact_wid: widget of the contact, must have the entity set in data attribute |
136 @param selected: boolean returned by the widget, telling if it is selected | 149 @param selected: boolean returned by the widget, telling if it is selected |
137 """ | 150 """ |
138 entity = contact_wid.data | 151 entity = contact_wid.data |
139 self.removeAlerts(entity, use_bare_jid) | 152 self.contact_list.removeAlerts(entity, use_bare_jid) |
140 self.host.modeHint(C.MODE_INSERTION) | 153 self.host.modeHint(C.MODE_INSERTION) |
141 self._emit('click', entity) | 154 self._emit('click', entity) |
142 | |
143 def onNickUpdate(self, entity, new_nick, profile): | |
144 self.update() | |
145 | 155 |
146 # Methods to build the widget | 156 # Methods to build the widget |
147 | 157 |
148 def _buildEntityWidget(self, entity, keys=None, use_bare_jid=False, with_alert=True, with_show_attr=True, markup_prepend=None, markup_append = None): | 158 def _buildEntityWidget(self, entity, keys=None, use_bare_jid=False, with_alert=True, with_show_attr=True, markup_prepend=None, markup_append = None): |
149 """Build one contact markup data | 159 """Build one contact markup data |
161 @param markup_append (list): markup to append to the generated one before building the widget | 171 @param markup_append (list): markup to append to the generated one before building the widget |
162 @return (list): markup data are expected by Urwid text widgets | 172 @return (list): markup data are expected by Urwid text widgets |
163 """ | 173 """ |
164 markup = [] | 174 markup = [] |
165 if use_bare_jid: | 175 if use_bare_jid: |
166 selected = {entity.bare for entity in self._selected} | 176 selected = {entity.bare for entity in self.contact_list._selected} |
167 else: | 177 else: |
168 selected = self._selected | 178 selected = self.contact_list._selected |
169 if keys is None: | 179 if keys is None: |
170 entity_txt = entity | 180 entity_txt = entity |
171 else: | 181 else: |
172 cache = self.getCache(entity) | 182 cache = self.contact_list.getCache(entity) |
173 for key in keys: | 183 for key in keys: |
174 if key.startswith('cache_'): | 184 if key.startswith('cache_'): |
175 entity_txt = cache.get(key[6:]) | 185 entity_txt = cache.get(key[6:]) |
176 else: | 186 else: |
177 entity_txt = getattr(entity, key) | 187 entity_txt = getattr(entity, key) |
179 break | 189 break |
180 if not entity_txt: | 190 if not entity_txt: |
181 entity_txt = entity | 191 entity_txt = entity |
182 | 192 |
183 if with_show_attr: | 193 if with_show_attr: |
184 show = self.getCache(entity, C.PRESENCE_SHOW) | 194 show = self.contact_list.getCache(entity, C.PRESENCE_SHOW) |
185 if show is None: | 195 if show is None: |
186 show = C.PRESENCE_UNAVAILABLE | 196 show = C.PRESENCE_UNAVAILABLE |
187 show_icon, entity_attr = C.PRESENCE.get(show, ('', 'default')) | 197 show_icon, entity_attr = C.PRESENCE.get(show, ('', 'default')) |
188 markup.insert(0, u"{} ".format(show_icon)) | 198 markup.insert(0, u"{} ".format(show_icon)) |
189 else: | 199 else: |
190 entity_attr = 'default' | 200 entity_attr = 'default' |
191 | 201 |
192 alerts_count = self.getAlerts(entity, use_bare_jid=use_bare_jid) | 202 alerts_count = len(self.contact_list.getAlerts(entity, use_bare_jid=use_bare_jid)) |
193 if with_alert and alerts_count: | 203 if with_alert and alerts_count: |
194 entity_attr = 'alert' | 204 entity_attr = 'alert' |
195 header = C.ALERT_HEADER % alerts_count | 205 header = C.ALERT_HEADER % alerts_count |
196 else: | 206 else: |
197 header = '' | 207 header = '' |
219 if not entities: | 229 if not entities: |
220 return | 230 return |
221 widgets = [] # list of built widgets | 231 widgets = [] # list of built widgets |
222 | 232 |
223 for entity in entities: | 233 for entity in entities: |
224 if entity in self._specials or not self.entityToShow(entity): | 234 if entity in self.contact_list._specials or not self.contact_list.entityToShow(entity): |
225 continue | 235 continue |
226 markup_extra = [] | 236 markup_extra = [] |
227 if self.show_resources: | 237 if self.contact_list.show_resources: |
228 for resource in self.getCache(entity, C.CONTACT_RESOURCES): | 238 for resource in self.contact_list.getCache(entity, C.CONTACT_RESOURCES): |
229 resource_disp = ('resource_main' if resource == self.getCache(entity, C.CONTACT_MAIN_RESOURCE) else 'resource', "\n " + resource) | 239 resource_disp = ('resource_main' if resource == self.getCache(entity, C.CONTACT_MAIN_RESOURCE) else 'resource', "\n " + resource) |
230 markup_extra.append(resource_disp) | 240 markup_extra.append(resource_disp) |
231 if self.show_status: | 241 if self.contact_list.show_status: |
232 status = self.getCache(jid.JID('%s/%s' % (entity, resource)), 'status') | 242 status = self.contact_list.getCache(jid.JID('%s/%s' % (entity, resource)), 'status') |
233 status_disp = ('status', "\n " + status) if status else "" | 243 status_disp = ('status', "\n " + status) if status else "" |
234 markup_extra.append(status_disp) | 244 markup_extra.append(status_disp) |
235 | 245 |
236 | 246 |
237 else: | 247 else: |
238 if self.show_status: | 248 if self.contact_list.show_status: |
239 status = self.getCache(entity, 'status') | 249 status = self.contact_list.getCache(entity, 'status') |
240 status_disp = ('status', "\n " + status) if status else "" | 250 status_disp = ('status', "\n " + status) if status else "" |
241 markup_extra.append(status_disp) | 251 markup_extra.append(status_disp) |
242 widget = self._buildEntityWidget(entity, ('cache_nick', 'cache_name', 'node'), use_bare_jid=True, markup_append=markup_extra) | 252 widget = self._buildEntityWidget(entity, ('cache_nick', 'cache_name', 'node'), use_bare_jid=True, markup_append=markup_extra) |
243 widgets.append(widget) | 253 widgets.append(widget) |
244 | 254 |
247 for widget in widgets: | 257 for widget in widgets: |
248 content.append(widget) | 258 content.append(widget) |
249 | 259 |
250 def _buildSpecials(self, content): | 260 def _buildSpecials(self, content): |
251 """Build the special entities""" | 261 """Build the special entities""" |
252 specials = list(self._specials) | 262 specials = list(self.contact_list._specials) |
253 specials.sort() | 263 specials.sort() |
254 extra_shown = set() | 264 extra_shown = set() |
255 for entity in specials: | 265 for entity in specials: |
256 # the special widgets | 266 # the special widgets |
257 widget = self._buildEntityWidget(entity, ('cache_nick', 'cache_name', 'node'), with_show_attr=False) | 267 widget = self._buildEntityWidget(entity, ('cache_nick', 'cache_name', 'node'), with_show_attr=False) |
258 content.append(widget) | 268 content.append(widget) |
259 | 269 |
260 # resources which must be displayed (e.g. MUC private conversations) | 270 # resources which must be displayed (e.g. MUC private conversations) |
261 extras = [extra for extra in self._special_extras if extra.bare == entity.bare] | 271 extras = [extra for extra in self.contact_list._special_extras if extra.bare == entity.bare] |
262 extras.sort() | 272 extras.sort() |
263 for extra in extras: | 273 for extra in extras: |
264 widget = self._buildEntityWidget(extra, ('resource',), markup_prepend = ' ') | 274 widget = self._buildEntityWidget(extra, ('resource',), markup_prepend = ' ') |
265 content.append(widget) | 275 content.append(widget) |
266 extra_shown.add(extra) | 276 extra_shown.add(extra) |
267 | 277 |
268 # entities which must be visible but not resource of current special entities | 278 # entities which must be visible but not resource of current special entities |
269 for extra in self._special_extras.difference(extra_shown): | 279 for extra in self.contact_list._special_extras.difference(extra_shown): |
270 widget = self._buildEntityWidget(extra, ('resource',)) | 280 widget = self._buildEntityWidget(extra, ('resource',)) |
271 content.append(widget) | 281 content.append(widget) |
272 | 282 |
273 def _buildList(self): | 283 def _buildList(self): |
274 """Build the main contact list widget""" | 284 """Build the main contact list widget""" |
275 content = urwid.SimpleListWalker([]) | 285 content = urwid.SimpleListWalker([]) |
276 | 286 |
277 self._buildSpecials(content) | 287 self._buildSpecials(content) |
278 if self._specials: | 288 if self.contact_list._specials: |
279 content.append(urwid.Divider('=')) | 289 content.append(urwid.Divider('=')) |
280 | 290 |
281 groups = list(self._groups) | 291 groups = list(self.contact_list._groups) |
282 groups.sort(key=lambda x: x.lower() if x else x) | 292 groups.sort(key=lambda x: x.lower() if x else x) |
283 for group in groups: | 293 for group in groups: |
284 data = self.getGroupData(group) | 294 data = self.contact_list.getGroupData(group) |
285 folded = data.get(C.GROUP_DATA_FOLDED, False) | 295 folded = data.get(C.GROUP_DATA_FOLDED, False) |
286 jids = list(data['jids']) | 296 jids = list(data['jids']) |
287 if group is not None and (self.anyEntityToShow(jids) or self.show_empty_groups): | 297 if group is not None and (self.contact_list.anyEntityToShow(jids) or self.contact_list.show_empty_groups): |
288 header = '[-]' if not folded else '[+]' | 298 header = '[-]' if not folded else '[+]' |
289 widget = sat_widgets.ClickableText(group, header=header + ' ') | 299 widget = sat_widgets.ClickableText(group, header=header + ' ') |
290 content.append(widget) | 300 content.append(widget) |
291 urwid.connect_signal(widget, 'click', self._groupClicked) | 301 urwid.connect_signal(widget, 'click', self._groupClicked) |
292 if not folded: | 302 if not folded: |
293 self._buildEntities(content, jids) | 303 self._buildEntities(content, jids) |
294 not_in_roster = set(self._cache).difference(self._roster).difference(self._specials).difference((self.whoami.bare,)) | 304 not_in_roster = set(self.contact_list._cache).difference(self.contact_list._roster).difference(self.contact_list._specials).difference((self.contact_list.whoami.bare,)) |
295 if not_in_roster: | 305 if not_in_roster: |
296 content.append(urwid.Divider('-')) | 306 content.append(urwid.Divider('-')) |
297 self._buildEntities(content, not_in_roster) | 307 self._buildEntities(content, not_in_roster) |
298 | 308 |
299 return urwid.ListBox(content) | 309 return urwid.ListBox(content) |
310 | |
311 quick_widgets.register(QuickContactList, ContactList) |