def __init__(self, ui, channel): self.ui = ui self.channel = channel self.cache = Cache(ui.client.boundjid.bare, channel.jid) self.active = False self.unread_ids = set() # Init sub-widgets w = urwid.Text("", wrap="clip") w = urwid.AttrMap(w, "channel user", "focused channel user") self.widget_user = w w = urwid.Text("", wrap="clip") w = urwid.AttrMap(w, "channel domain", "focused channel domain") self.widget_domain = w w = urwid.Text("", align="right", wrap="clip") w = urwid.AttrMap(w, "channel notif", "focused channel notif") self.widget_notif = w w = urwid.Text("") w = urwid.AttrMap(w, "channel status", "focused channel status") self.widget_status = w # Set title to JID until we now more self.set_title(channel.jid) # Channel configuration self.chan_title = "" self.chan_description = "" self.chan_creation = None self.chan_type = "" # Load data from cache self.set_config(self.cache.config, False) status = self.cache.status if status is not None: self.widget_status.original_widget.set_text(status) self.last_update = self.cache.last_update # Channel callbacks _callbacks = { "cb_post": ui.safe_callback(self.pubsub_posts_callback), "cb_retract": ui.safe_callback(self.pubsub_retract_callback), "cb_status": ui.safe_callback(self.pubsub_status_callback), "cb_config": ui.safe_callback(self.pubsub_config_clalback), } channel.set_callbacks(**_callbacks) # Request missing informations channel.pubsub_get_config() if self.last_update == Cache.never: channel.pubsub_get_status() channel.pubsub_get_posts(max=20)
class ChannelBox(urwid.widget.BoxWidget): def __init__(self, ui, channel): self.ui = ui self.channel = channel self.cache = Cache(ui.client.boundjid.bare, channel.jid) self.active = False self.unread_ids = set() # Init sub-widgets w = urwid.Text("", wrap="clip") w = urwid.AttrMap(w, "channel user", "focused channel user") self.widget_user = w w = urwid.Text("", wrap="clip") w = urwid.AttrMap(w, "channel domain", "focused channel domain") self.widget_domain = w w = urwid.Text("", align="right", wrap="clip") w = urwid.AttrMap(w, "channel notif", "focused channel notif") self.widget_notif = w w = urwid.Text("") w = urwid.AttrMap(w, "channel status", "focused channel status") self.widget_status = w # Set title to JID until we now more self.set_title(channel.jid) # Channel configuration self.chan_title = "" self.chan_description = "" self.chan_creation = None self.chan_type = "" # Load data from cache self.set_config(self.cache.config, False) status = self.cache.status if status is not None: self.widget_status.original_widget.set_text(status) self.last_update = self.cache.last_update # Channel callbacks _callbacks = { "cb_post": ui.safe_callback(self.pubsub_posts_callback), "cb_retract": ui.safe_callback(self.pubsub_retract_callback), "cb_status": ui.safe_callback(self.pubsub_status_callback), "cb_config": ui.safe_callback(self.pubsub_config_clalback), } channel.set_callbacks(**_callbacks) # Request missing informations channel.pubsub_get_config() if self.last_update == Cache.never: channel.pubsub_get_status() channel.pubsub_get_posts(max=20) # {{{ PubSub Callbacks def pubsub_posts_callback(self, atoms): new_atoms = [] for atom in atoms: if self.cache.add_item(atom): new_atoms.append(atom) # Find most recent atom recent_changed = self.last_update != self.cache.last_update self.last_update = self.cache.last_update # Tell the ChannelsList to sort channels again if recent_changed: self.ui.channels.sort_channels() if self.active: # Notify the content pane # TODO: more? self.ui.threads_list.add_new_items(new_atoms) else: # Update unread counter for a in new_atoms: self.unread_ids.add(a.id) nb_unread = len(self.unread_ids) if nb_unread > 0: self.widget_notif.original_widget.set_text(" [{}]".format(nb_unread)) self._invalidate() self.ui.notify() def pubsub_retract_callback(self, item_ids): for id_ in item_ids: self.unread_ids.discard(id_) self.cache.del_item(id_) if self.active: self.ui.threads_list.remove_items(item_ids) self.ui.channels.sort_channels() def pubsub_status_callback(self, atom): txt = atom.content self.widget_status.original_widget.set_text(txt) self.cache.status = txt self._invalidate() def pubsub_config_clalback(self, conf): self.set_config(conf) # }}} # {{{ Channel management def set_active(self, active): self.active = active if active: self.widget_user.set_attr_map({None: "active channel user"}) self.widget_user.set_focus_map({None: "focused active channel user"}) self.widget_domain.set_attr_map({None: "active channel domain"}) self.widget_domain.set_focus_map({None: "focused active channel domain"}) self.widget_notif.set_attr_map({None: "active channel notif"}) self.widget_notif.set_focus_map({None: "focused active channel notif"}) self.widget_status.set_attr_map({None: "active channel status"}) self.widget_status.set_focus_map({None: "focused active channel status"}) self.widget_notif.original_widget.set_text("") self.unread_ids.clear() self.display_config() else: self.widget_user.set_attr_map({None: "channel user"}) self.widget_user.set_focus_map({None: "focused channel user"}) self.widget_domain.set_attr_map({None: "channel domain"}) self.widget_domain.set_focus_map({None: "focused channel domain"}) self.widget_notif.set_attr_map({None: "channel notif"}) self.widget_notif.set_focus_map({None: "focused channel notif"}) self.widget_status.set_attr_map({None: "channel status"}) self.widget_status.set_focus_map({None: "focused channel status"}) def display_config(self): if self.active: self.ui.infobar_left.set_text("{} - {}".format(self.chan_title, self.chan_description)) self.ui.infobar_right.set_text(self.channel.jid) def set_status(self, status): self.widget_status.original_widget.set_text(status) self._invalidate() def set_title(self, title): self.chan_title = title # What should we display in the sidebar? user, domain = title, "" jid = self.channel.jid if len(title) == 0: title = jid if jid.lower() == title.lower(): user, domain = title.split("@", 1) # Shorten my.long.domain.name into "mldn" domain = "@" + "".join([w[0] for w in domain.split(".")]) self.widget_user.original_widget.set_text(user) self.widget_domain.original_widget.set_text(domain) def set_config(self, config, cache=True): if "title" in config: self.set_title(config["title"].strip()) if "description" in config: self.chan_description = config["description"].strip() if "creation" in config: self.chan_creation = config["creation"] if "type" in config: self.chan_type = config["type"] if cache: self.cache.config = { "title": self.chan_title, "description": self.chan_description, "creation": self.chan_creation, "type": self.chan_type, } self.display_config() self._invalidate() # }}} # {{{ Widget management def keypress(self, size, key): return key def rows(self, size, focus=False): return 1 + self.widget_status.rows(size, focus) def render(self, size, focus=False): maxcol = size[0] # First line: user, shortened domain, notif canv1, comb1 = None, None user_col, _ = self.widget_user.pack(focus=focus) if len(self.unread_ids) == 0: # No notification: just user + domain domain_col = maxcol - user_col if domain_col > 0: canv_user = self.widget_user.render((user_col,), focus) canv_domain = self.widget_domain.render((domain_col,), focus) comb1 = [(canv_user, None, True, user_col), (canv_domain, None, True, domain_col)] else: canv1 = self.widget_user.render(size, focus) else: # There are notifications: now it's tricker notif_col, _ = self.widget_notif.pack(focus=focus) domain_col = maxcol - user_col - notif_col if domain_col > 0: # Render everything! canv_user = self.widget_user.render((user_col,), focus) canv_domain = self.widget_domain.render((domain_col,), focus) canv_notif = self.widget_notif.render((notif_col,), focus) comb1 = [ (canv_user, None, True, user_col), (canv_domain, None, True, domain_col), (canv_notif, None, True, notif_col), ] else: # Only user and notif. user_col = min(user_col, maxcol - notif_col) if user_col > 0: # User + notif canv_user = self.widget_user.render((user_col,), focus) canv_notif = self.widget_notif.render((notif_col,), focus) comb1 = [(canv_user, None, True, user_col), (canv_notif, None, True, notif_col)] else: # Notif only canv1 = self.widget_notif.render(size, focus) if comb1 is not None: canv1 = urwid.CanvasJoin(comb1) # Second (status) canv_status = self.widget_status.render(size, focus) # Combine lines combinelist = [(c, None, True) for c in (canv1, canv_status)] return urwid.CanvasCombine(combinelist)