From 545902be7d625f29d00eceb1707afa36af20d137 Mon Sep 17 00:00:00 2001 From: "louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13" Date: Wed, 10 Nov 2010 21:15:08 +0000 Subject: ConversationTab interface --- src/contact.py | 6 ++-- src/core.py | 25 +++++++++----- src/roster.py | 11 ++++-- src/tab.py | 52 +++++++++++++--------------- src/window.py | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 145 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/contact.py b/src/contact.py index 35a4a4a8..1eb41f72 100644 --- a/src/contact.py +++ b/src/contact.py @@ -14,12 +14,12 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see . - """ Defines the Resource and Contact classes """ - from sleekxmpp.xmlstream.stanzabase import JID +import logging +log = logging.getLogger(__name__) class Resource(object): """ @@ -54,7 +54,7 @@ class Resource(object): def get_status(self): return self._status - def set__status(self, s): + def set_status(self, s): self._status = s class Contact(object): diff --git a/src/core.py b/src/core.py index 9dd72861..01770a49 100644 --- a/src/core.py +++ b/src/core.py @@ -94,7 +94,7 @@ class Core(object): self.ignores = {} self.resize_timer = None self.previous_tab_nb = 0 - + self.own_nick = config.get('own_nick', self.xmpp.boundjid.bare) self.commands = { 'help': (self.command_help, '\_o< KOIN KOIN KOIN'), 'join': (self.command_join, _("Usage: /join [room_name][@server][/nick] [password]\nJoin: Join the specified room. You can specify a nickname after a slash (/). If no nickname is specified, you will use the default_nick in the configuration file. You can omit the room name: you will then join the room you\'re looking at (useful if you were kicked). You can also provide a room_name without specifying a server, the server of the room you're currently in will be used. You can also provide a password to join the room.\nExamples:\n/join room@server.tld\n/join room@server.tld/John\n/join room2\n/join /me_again\n/join\n/join room@server.tld/my_nick password\n/join / password")), @@ -199,7 +199,9 @@ class Core(object): assert not resource resource = Resource(jid.full) status = presence['type'] + status_message = presence['status'] priority = presence.getPriority() or 0 + resource.set_status(status_message) resource.set_presence(status) resource.set_priority(priority) contact.add_resource(resource) @@ -216,7 +218,7 @@ class Core(object): # request the roster self.xmpp.getRoster() # send initial presence - self.xmpp.makePresence(pfrom=self.xmpp.boundjid.bare).send() + self.xmpp.makePresence().send() rooms = config.get('rooms', '') if rooms == '' or not isinstance(rooms, str): return @@ -478,16 +480,21 @@ class Core(object): """ """ jid = presence['from'] + log.debug('Presence Received: %s\n' % presence) contact = roster.get_contact_by_jid(jid.bare) + log.debug('Contact: %s\n' % contact) if not contact: return resource = contact.get_resource_by_fulljid(jid.full) + log.debug('Resource: %s\n' % resource) if not resource: return status = presence['type'] + status_message = presence['status'] priority = presence.getPriority() or 0 resource.set_presence(status) resource.set_priority(priority) + resource.set_status(status_message) if isinstance(self.current_tab(), RosterInfoTab): self.refresh_window() @@ -738,12 +745,12 @@ class Core(object): self.add_message_to_text_buffer(room, _('You can join the room with an other nick, by typing "/join /other_nick"')) self.refresh_window() - def open_conversation_window(self, room_name, focus=True): + def open_conversation_window(self, jid, focus=True): """ open a new conversation tab and focus it if needed """ - r = Room(room_name, self.xmpp.boundjid.full) - new_tab = ConversationTab(self.stdscr, self, r) + text_buffer = TextBuffer() + new_tab = ConversationTab(self.stdscr, self, text_buffer, jid) # insert it in the rooms if self.current_tab().nb == 0: self.tabs.append(new_tab) @@ -754,9 +761,8 @@ class Core(object): break if focus: # focus the room if needed self.command_win('%s' % (new_tab.nb)) - # self.window.new_room(r) self.refresh_window() - return r + return text_buffer def open_private_window(self, room_name, user_nick, focus=True): complete_jid = room_name+'/'+user_nick @@ -1393,11 +1399,12 @@ class Core(object): def command_say(self, line): if isinstance(self.current_tab(), PrivateTab): muc.send_private_message(self.xmpp, self.current_tab().get_name(), line) - elif isinstance(self.current_tab(), ConversationTab): # todo, special case + elif isinstance(self.current_tab(), ConversationTab): # todo, special case # hu, I can't remember what special case was needed when I wrote that… muc.send_private_message(self.xmpp, self.current_tab().get_name(), line) if isinstance(self.current_tab(), PrivateTab) or\ isinstance(self.current_tab(), ConversationTab): - self.add_message_to_text_buffer(self.current_tab().get_room(), line, None, self.current_tab().get_room().own_nick) + log.debug('ALLO ICI\n\n') + self.add_message_to_text_buffer(self.current_tab().get_room(), line, None, self.own_nick) elif isinstance(self.current_tab(), MucTab): muc.send_groupchat_message(self.xmpp, self.current_tab().get_name(), line) self.doupdate() diff --git a/src/roster.py b/src/roster.py index 09bc7b6b..610d73dc 100644 --- a/src/roster.py +++ b/src/roster.py @@ -18,9 +18,12 @@ """ Defines the Roster and RosterGroup classes """ +import logging +log = logging.getLogger(__name__) from config import config from contact import Contact, Resource +from sleekxmpp.xmlstream.stanzabase import JID class Roster(object): def __init__(self): @@ -47,8 +50,10 @@ class Roster(object): """ Returns the contact with the given bare JID """ - if jid in self._contacts: - return self._contacts[jid] + # Use only the bare jid + jid = JID(jid) + if jid.bare in self._contacts: + return self._contacts[jid.bare] return None def edit_groups_of_contact(self, contact, groups): @@ -59,7 +64,7 @@ class Roster(object): # add the contact to each group he is in # If the contact hasn't any group, we put her in # the virtual default 'none' group - if not len(groups): + if not len(groups): groups = ['none'] for group in groups: if group not in contact._groups: diff --git a/src/tab.py b/src/tab.py index 767ee353..3f3805cc 100644 --- a/src/tab.py +++ b/src/tab.py @@ -37,7 +37,6 @@ class Tab(object): def __init__(self, stdscr, core): self.core = core # a pointer to core, to access its attributes (ugly?) - self.tab_type = "Tab" self.nb = Tab.number Tab.number += 1 self.size = (self.height, self.width) = stdscr.getmaxyx() @@ -134,7 +133,6 @@ class InfoTab(Tab): """ def __init__(self, stdscr, core, name): Tab.__init__(self, stdscr, core) - self.tab_type = "InfoTab" self.tab_win = window.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) self.text_win = window.TextWin(self.height-2, self.width, 0, 0, stdscr, self.visible) self.input = window.Input(1, self.width, self.height-1, 0, stdscr, self.visible) @@ -195,7 +193,6 @@ class MucTab(Tab): terminal """ Tab.__init__(self, stdscr, core) - self.tab_type = "MucTab" self._room = room self.topic_win = window.Topic(1, self.width, 0, 0, stdscr, self.visible) self.text_win = window.TextWin(self.height-4-self.core.information_win_size, (self.width//10)*9, 1, 0, stdscr, self.visible) @@ -313,7 +310,6 @@ class PrivateTab(Tab): """ def __init__(self, stdscr, core, room): Tab.__init__(self, stdscr, core) - self.tab_type = "PrivateTab" self._room = room self.text_win = window.TextWin(self.height-3-self.core.information_win_size, self.width, 0, 0, stdscr, self.visible) self.info_header = window.PrivateInfoWin(1, self.width, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) @@ -358,10 +354,7 @@ class PrivateTab(Tab): def on_gain_focus(self): self._room.set_color_state(theme.COLOR_TAB_CURRENT) - if not self.input.input_mode: - curses.curs_set(1) - else: - curses.curs_set(0) + curses.curs_set(1) def on_scroll_up(self): self._room.scroll_up(self.text_win.height-1) @@ -397,7 +390,6 @@ class RosterInfoTab(Tab): "^F": self.start_search, } Tab.__init__(self, stdscr, core) - self.tab_type = "RosterInfoTab" self.name = "Roster" roster_width = self.width//2 info_width = self.width-roster_width-1 @@ -534,11 +526,13 @@ class ConversationTab(Tab): """ The tab containg a normal conversation (someone from our roster) """ - def __init__(self, stdscr, core, room): + def __init__(self, stdscr, core, text_buffer, jid): Tab.__init__(self, stdscr, core) - self.tab_type = "ConversationTab" - self._room = room - self.text_win = window.TextWin(self.height-3-self.core.information_win_size, self.width, 0, 0, stdscr, self.visible) + self._text_buffer = text_buffer + self.color_state = theme.COLOR_TAB_NORMAL + self._name = jid # a conversation tab is linked to one specific full jid OR bare jid + self.text_win = window.TextWin(self.height-4-self.core.information_win_size, self.width, 1, 0, stdscr, self.visible) + self.upper_bar = window.ConversationStatusMessageWin(1, self.width, 0, 0, stdscr, self.visible) self.info_header = window.ConversationInfoWin(1, self.width, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) self.info_win = window.TextWin(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) self.tab_win = window.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) @@ -547,47 +541,49 @@ class ConversationTab(Tab): def resize(self, stdscr): Tab.resize(self, stdscr) self.text_win.resize(self.height-3-self.core.information_win_size, self.width, 0, 0, stdscr, self.visible) + self.upper_bar.resize(1, self.width, 0, 0, stdscr, self.visible) self.info_header.resize(1, self.width, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) self.info_win.resize(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) self.tab_win.resize(1, self.width, self.height-2, 0, stdscr, self.visible) self.input.resize(1, self.width, self.height-1, 0, stdscr, self.visible) def refresh(self, tabs, informations, roster): - self.text_win.refresh(self._room) - # self.info_header.refresh(self._room, roster.get_contact_by_jid(self._room.name)) + self.text_win.refresh(self._text_buffer) + self.upper_bar.refresh(self.get_name(), roster.get_contact_by_jid(self.get_name())) + self.info_header.refresh(self.get_name(), roster.get_contact_by_jid(self.get_name()), self._text_buffer) self.info_win.refresh(informations) self.tab_win.refresh(tabs, tabs[0]) self.input.refresh() - curses.curs_set(1) def get_color_state(self): - if self._room.color_state == theme.COLOR_TAB_NORMAL or\ - self._room.color_state == theme.COLOR_TAB_CURRENT: - return self._room.color_state + if self.color_state == theme.COLOR_TAB_NORMAL or\ + self.color_state == theme.COLOR_TAB_CURRENT: + return self.color_state return theme.COLOR_TAB_PRIVATE def set_color_state(self, color): - self._room.color_state = color + self.color_state = color def get_name(self): - return self._room.name + return self._name def on_input(self, key): return self.input.do_command(key) def on_lose_focus(self): - self._room.set_color_state(theme.COLOR_TAB_NORMAL) - self._room.remove_line_separator() - self._room.add_line_separator() + self.set_color_state(theme.COLOR_TAB_NORMAL) + self._text_buffer.remove_line_separator() + self._text_buffer.add_line_separator() def on_gain_focus(self): - self._room.set_color_state(theme.COLOR_TAB_CURRENT) + self.set_color_state(theme.COLOR_TAB_CURRENT) + curses.curs_set(1) def on_scroll_up(self): - self._room.scroll_up(self.text_win.height-1) + self._text_buffer.scroll_up(self.text_win.height-1) def on_scroll_down(self): - self._room.scroll_down(self.text_win.height-1) + self._text_buffer.scroll_down(self.text_win.height-1) def on_info_win_size_changed(self, stdscr): self.text_win.resize(self.height-3-self.core.information_win_size, self.width, 0, 0, stdscr, self.visible) @@ -595,7 +591,7 @@ class ConversationTab(Tab): self.info_win.resize(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) def get_room(self): - return self._room + return self._text_buffer def just_before_refresh(self): return diff --git a/src/window.py b/src/window.py index 1c3f32d9..64113cfb 100644 --- a/src/window.py +++ b/src/window.py @@ -18,6 +18,9 @@ from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset, gettext as _) from os.path import isfile +import logging +log = logging.getLogger(__name__) + import locale locale.setlocale(locale.LC_ALL, '') @@ -33,6 +36,8 @@ from roster import RosterGroup, roster from message import Line from tab import MIN_WIDTH, MIN_HEIGHT +from sleekxmpp.xmlstream.stanzabase import JID + import theme g_lock = Lock() @@ -239,35 +244,113 @@ class PrivateInfoWin(InfoWin): class ConversationInfoWin(InfoWin): """ The line above the information window, displaying informations - about the MUC user we are talking to + about the user we are talking to """ + color_show = {'xa':theme.COLOR_STATUS_XA, + 'none':theme.COLOR_STATUS_ONLINE, + '':theme.COLOR_STATUS_ONLINE, + 'available':theme.COLOR_STATUS_ONLINE, + 'dnd':theme.COLOR_STATUS_DND, + 'away':theme.COLOR_STATUS_AWAY, + 'chat':theme.COLOR_STATUS_CHAT, + 'unavailable':theme.COLOR_STATUS_UNAVAILABLE + } + def __init__(self, height, width, y, x, parent_win, visible): InfoWin.__init__(self, height, width, y, x, parent_win, visible) def resize(self, height, width, y, x, stdscr, visible): self._resize(height, width, y, x, stdscr, visible) - def refresh(self, room, contact): + def refresh(self, jid, contact, text_buffer): if not self.visible: return # contact can be None, if we receive a message # from someone not in our roster. In this case, we display # only the maximum information from the message we can get. - # Also, contact can be a resource, if we're talking to a - # specific resource. + jid = JID(jid) + if contact: + if jid.resource: + resource = contact.get_resource_by_fulljid(jid.full) + else: + resource = contact.get_highest_priority_resource() + else: + resource = None + # if contact is None, then resource is None too: user is not in the roster + # so we don't know almost anything about it + # If contact is a Contact, then + # resource can now be a Resource: user is in the roster and online + # or resource is None: user is in the roster but offline with g_lock: self._win.erase() - # self.write_room_name(resource, room) - # self.print_scroll_position(room) - # self.finish_line(theme.COLOR_INFORMATION_BAR) + self.write_contact_jid(jid) + self.write_contact_informations(contact) + self.write_resource_information(resource) + self.print_scroll_position(text_buffer) + self.finish_line(theme.COLOR_INFORMATION_BAR) self._refresh() - def write_room_name(self, contact, room): + def write_resource_information(self, resource): + """ + Write the informations about the resource + """ + if not resource: + presence = "unavailable" + else: + presence = resource.get_presence() + color = RosterWin.color_show[presence] + self.addstr('[', curses.color_pair(theme.COLOR_INFORMATION_BAR)) + self.addstr(" ", curses.color_pair(color)) + self.addstr(']', curses.color_pair(theme.COLOR_INFORMATION_BAR)) + + def write_contact_informations(self, contact): + """ + Write the informations about the contact + """ if not contact: - txt = '%s' % room.name + self.addstr("(contact not in roster)", curses.color_pair(theme.COLOR_INFORMATION_BAR)) + return + display_name = contact.get_name() or contact.get_bare_jid() + self.addstr('%s '%(display_name), curses.color_pair(theme.COLOR_INFORMATION_BAR)) + + def write_contact_jid(self, jid): + """ + Just write the jid that we are talking to + """ + self.addstr('[', curses.color_pair(theme.COLOR_INFORMATION_BAR)) + self.addstr(jid.full, curses.color_pair(10)) + self.addstr('] ', curses.color_pair(theme.COLOR_INFORMATION_BAR)) + +class ConversationStatusMessageWin(InfoWin): + """ + The upper bar displaying the status message of the contact + """ + def __init__(self, height, width, y, x, parent_win, visible): + InfoWin.__init__(self, height, width, y, x, parent_win, visible) + + def resize(self, height, width, y, x, stdscr, visible): + self._resize(height, width, y, x, stdscr, visible) + + def refresh(self, jid, contact): + if not self.visible: + return + jid = JID(jid) + if contact: + if jid.resource: + resource = contact.get_resource_by_fulljid(jid.full) + else: + resource = contact.get_highest_priority_resource() else: - txt = '%s' % contact.get_jid().bare - self.addstr(txt, curses.color_pair(theme.COLOR_INFORMATION_BAR)) + resource = None + with g_lock: + self._win.erase() + if resource: + self.write_status_message(resource) + self.finish_line(theme.COLOR_INFORMATION_BAR) + self._refresh() + + def write_status_message(self, resource): + self.addstr(resource.get_status(), curses.color_pair(theme.COLOR_INFORMATION_BAR)) class MucInfoWin(InfoWin): """ -- cgit v1.2.3