diff --git a/src/gui.py b/src/gui.py index 1c6332b5..8f515ebc 100644 --- a/src/gui.py +++ b/src/gui.py @@ -484,9 +484,9 @@ class Gui(object): hide_exit_join = config.get('hide_exit_join', -1) if hide_exit_join != 0: if not jid: - self.add_message_to_room(room, _("%(nick)s joined the room") % {'nick':from_nick}) + self.add_message_to_room(room, _("%(spec)s [%(nick)s] joined the room") % {'nick':from_nick, 'spec':theme.CHAR_JOIN}, colorized=True) else: - self.add_message_to_room(room, _("%(nick)s (%(jid)s) joined the room") % {'nick':from_nick, 'jid':jid}) + self.add_message_to_room(room, _("%(spec)s [%(nick)s] (%(jid)s) joined the room") % {'spec':theme.CHAR_JOIN, 'nick':from_nick, 'jid':jid}, colorized=True) # nick change elif change_nick: if user.nick == room.own_nick: @@ -496,11 +496,11 @@ class Gui(object): if _room.jid is not None and is_jid_the_same(_room.jid, room.name): _room.own_nick = stanza.getNick() user.change_nick(stanza.getNick()) - self.add_message_to_room(room, _('%(old)s is now known as %(new)s') % {'old':from_nick, 'new':stanza.getNick()}) + self.add_message_to_room(room, _('[%(old)s] is now known as [%(new)s]') % {'old':from_nick, 'new':stanza.getNick()}, colorized=True) # rename the private tabs if needed private_room = self.get_room_by_name(stanza.getFrom()) if private_room: - self.add_message_to_room(private_room, _('%(old_nick)s is now known as %(new_nick)s') % {'old_nick':from_nick, 'new_nick':stanza.getNick()}) + self.add_message_to_room(private_room, _('[%(old_nick)s] is now known as [%(new_nick)s]') % {'old_nick':from_nick, 'new_nick':stanza.getNick()}, colorized=True) new_jid = private_room.name.split('/')[0]+'/'+stanza.getNick() private_room.jid = new_jid private_room.name = new_jid @@ -519,29 +519,29 @@ class Gui(object): if from_nick == room.own_nick: # we are kicked room.disconnect() if by: - self.add_message_to_room(room, _("You have been kicked by %(by)s. Reason: %(reason)s") % {'by':by, 'reason':reason}) + self.add_message_to_room(room, _("%(spec) [You] have been kicked by [%(by)s]. Reason: {%(reason)s}") % {'spec': theme.CHAR_KICK, 'by':by, 'reason':reason}, colorized=True) else: - self.add_message_to_room(room, _("You have been kicked. Reason: %s") % (reason)) + self.add_message_to_room(room, _("%(spec)s [You] have been kicked. Reason: %(reason)s") % {'reason':reason, 'spec':theme.CHAR_KICK}, colorized=True) # try to auto-rejoin if config.get('autorejoin', 'false') == 'true': self.muc.join_room(room.name, room.own_nick) else: if by: - self.add_message_to_room(room, _("%(nick)s has been kicked by %(by)s. Reason: %(reason)s") % {'nick':from_nick, 'by':by, 'reason':reason}) + self.add_message_to_room(room, _("%(spec)s [%(nick)s] has been kicked by %(by)s. Reason: %(reason)s") % {'spec':theme.CHAR_KICK, 'nick':from_nick, 'by':by, 'reason':reason}, colorized=True) else: - self.add_message_to_room(room, _("%(nick)s has been kicked. Reason: %(reason)s") % {'nick':from_nick, 'reason':reason}) + self.add_message_to_room(room, _("%(spec)s [%(nick)s] has been kicked. Reason: %(reason)s") % {'nick':from_nick, 'reason':reason, 'spec':theme.CHAR_KICK}, colorized=True) # user quit elif status == 'offline' or role == 'none': room.users.remove(user) hide_exit_join = config.get('hide_exit_join', -1) if config.get('hide_exit_join', -1) >= -1 else -1 if hide_exit_join == -1 or user.has_talked_since(hide_exit_join): if not jid: - self.add_message_to_room(room, _('%s has left the room') % (from_nick)) + self.add_message_to_room(room, _('%(spec)s [%(nick)s] has left the room') % {'nick':from_nick, 'spec':theme.CHAR_QUIT}, colorized=True) else: - self.add_message_to_room(room, _('%(nick)s (%(jid)s) has left the room') % {'nick':from_nick, 'jid':jid}) + self.add_message_to_room(room, _('%(spec)s [%(nick)s] (%(jid)s) has left the room') % {'spec':theme.CHAR_QUIT, 'nick':from_nick, 'jid':jid}, colorized=True) private_room = self.get_room_by_name(stanza.getFrom()) if private_room: - self.add_message_to_room(private_room, _('%s has left the room') % (from_nick)) + self.add_message_to_room(private_room, _('%(spec)s [%(nick)s] has left the room') % {'nick':from_nick, 'spec':theme.CHAR_KICK}, colorized=True) # status change else: # build the message @@ -576,14 +576,14 @@ class Gui(object): self.window.input.refresh() doupdate() - def add_message_to_room(self, room, txt, time=None, nickname=None): + def add_message_to_room(self, room, txt, time=None, nickname=None, colorized=False): """ Add the message to the room and refresh the associated component of the interface """ if room != self.current_room(): room.add_line_separator() - room.add_message(txt, time, nickname) + room.add_message(txt, time, nickname, colorized) if room == self.current_room(): self.window.text_win.refresh(room) else: diff --git a/src/message.py b/src/message.py index c5d3d47e..078bc8fd 100644 --- a/src/message.py +++ b/src/message.py @@ -21,21 +21,25 @@ from datetime import datetime class Message(object): """ A message with all the associated data (nickname, time, color, etc) + The color can be a single number OR a list of numbers, for + specials cases like join or quit messages. """ - def __init__(self, txt, time=None, nickname=None, user=None, color=None): + def __init__(self, txt, time=None, nickname=None, user=None, color=None, colorized=False): """ time is a datetime object, None means 'now'. If no nickname is specified, it's an information. user is an User object (used for the color, etc) + """ self.txt = txt self.nickname = nickname self.time = time self.user = user self.color = color + self.colorized = colorized def __repr__(self): - return "" % (self.txt, self.nickname, str(self.time), str(self.user)) + return "" % (self.txt, self.nickname, str(self.time), str(self.user), self.colorized) def __str__(self): return self.__repr__() @@ -43,6 +47,8 @@ class Line(object): """ A line, corresponding to ONE row of the text area. A message is composed of ONE line or MORE. + The same particularity for colors in Message class applies + here too. Example: Text area limit text area limit @@ -67,10 +73,11 @@ class Line(object): Line(None, None, None, "informations here:", 0, 23) Line(None, None, None, "http://blablablabla", 0, 23) """ - def __init__(self, nickname, nickname_color, time, text, text_color, text_offset): + def __init__(self, nickname, nickname_color, time, text, text_color, text_offset, colorized=False): self.nickname = nickname self.nickname_color = nickname_color self.time = time self.text = text self.text_color = text_color self.text_offset = text_offset + self.colorized = colorized diff --git a/src/room.py b/src/room.py index 391f6f79..02aa336f 100644 --- a/src/room.py +++ b/src/room.py @@ -91,7 +91,7 @@ class Room(object): break return color - def add_message(self, txt, time=None, nickname=None): + def add_message(self, txt, time=None, nickname=None, colorized=False): """ Note that user can be None even if nickname is not None. It happens when we receive an history message said by someone who is not @@ -116,7 +116,7 @@ class Room(object): if time: # History messages are colored to be distinguished color = theme.COLOR_INFORMATION_TEXT time = time if time is not None else datetime.now() - self.messages.append(Message(txt, time, nickname, user, color)) + self.messages.append(Message(txt, time, nickname, user, color, colorized)) def remove_line_separator(self): """ diff --git a/src/theme.py b/src/theme.py index 58a51717..da485f16 100644 --- a/src/theme.py +++ b/src/theme.py @@ -42,6 +42,10 @@ COLOR_USER_PARTICIPANT = 73 COLOR_USER_NONE = 80 COLOR_USER_MODERATOR = 77 +# The character printed in color (COLOR_STATUS_*) before the nickname +# in the user list +CHAR_STATUS = ' ' + # Separators COLOR_VERTICAL_SEPARATOR = 73 COLOR_NEW_TEXT_SEPARATOR = 75 @@ -77,8 +81,24 @@ COLOR_TOPIC_BAR = 15 COLOR_PRIVATE_ROOM_BAR = 33 COLOR_SCROLLABLE_NUMBER = 16 -# Chars -STATUS_CHAR = ' ' +# Strings for special messages (like join, quit, nick change, etc) + +# Special messages +CHAR_JOIN = '---->' +CHAR_QUIT = '<----' +CHAR_KICK = '-!-' + +COLOR_JOIN_CHAR = 73 +COLOR_QUIT_CHAR = 77 +COLOR_KICK_CHAR = 77 + +# words between () +COLOR_CURLYBRACKETED_WORD = 72 +# words between {} +COLOR_ACCOLADE_WORD = 74 +# words between [] +COLOR_BRACKETED_WORD = 73 + def init_colors(): """ @@ -123,7 +143,7 @@ def reload_theme(): except: # TODO warning: theme not found return for var in dir(theme): - if var.startswith('COLOR_') or var.startswith('STATUS_'): + if var.startswith('COLOR_') or var.startswith('CHAR_'): globals()[var] = getattr(theme, var) if __name__ == '__main__': diff --git a/src/window.py b/src/window.py index dcbb14ab..8054903a 100644 --- a/src/window.py +++ b/src/window.py @@ -102,7 +102,7 @@ class UserList(Win): except KeyError: show_col = theme.COLOR_STATUS_NONE self.win.attron(curses.color_pair(show_col)) - self.win.addnstr(y, 0, theme.STATUS_CHAR, 1) + self.win.addnstr(y, 0, theme.CHAR_STATUS, 1) self.win.attroff(curses.color_pair(show_col)) self.win.attron(curses.color_pair(role_col)) try: @@ -267,7 +267,8 @@ class TextWin(Win): l = Line(nick, color, time, txt[:limit], message.color, - offset) + offset, + message.colorized) lines.append(l) if this_line_was_broken_by_space: txt = txt[limit+1:] # jump the space at the start of the line @@ -308,7 +309,7 @@ class TextWin(Win): self.write_time(line.time) if line.nickname is not None: self.write_nickname(line.nickname.encode('utf-8'), line.nickname_color) - self.write_text(y, line.text_offset, line.text, line.text_color) + self.write_text(y, line.text_offset, line.text, line.text_color, line.colorized) y += 1 self.win.refresh() g_lock.release() @@ -320,19 +321,49 @@ class TextWin(Win): self.win.addstr(' -'*(self.width/2)) self.win.attroff(curses.color_pair(theme.COLOR_NEW_TEXT_SEPARATOR)) - def write_text(self, y, x, txt, color): + def write_text(self, y, x, txt, color, colorized): """ write the text of a line. """ txt = txt.encode('utf-8') - if color: - self.win.attron(curses.color_pair(color)) - try: - self.win.addstr(y, x, txt) - except: # bug 1665 - pass - if color: - self.win.attroff(curses.color_pair(color)) + if not colorized: + if color: + self.win.attron(curses.color_pair(color)) + try: + self.win.addstr(y, x, txt) + except: # bug 1665 + pass + if color: + self.win.attroff(curses.color_pair(color)) + + else: # Special messages like join or quit + from common import debug + special_words = { + theme.CHAR_JOIN: theme.COLOR_JOIN_CHAR, + theme.CHAR_QUIT: theme.COLOR_QUIT_CHAR, + theme.CHAR_KICK: theme.COLOR_KICK_CHAR, + } + for word in txt.split(): + if word in special_words.keys(): + self.win.attron(curses.color_pair(special_words[word])) + self.win.addstr(word) + self.win.attroff(curses.color_pair(special_words[word])) + elif word.startswith('(') and word.endswith(')'): + self.win.addstr('(', curses.color_pair(color)) + self.win.addstr(word[1:-1], curses.color_pair(theme.COLOR_CURLYBRACKETED_WORD)) + self.win.addstr(')', curses.color_pair(color)) + elif word.startswith('{') and word.endswith('}'): + self.win.addstr(word[1:-1], curses.color_pair(theme.COLOR_ACCOLADE_WORD)) + elif word.startswith('[') and word.endswith(']'): + self.win.addstr(word[1:-1], curses.color_pair(theme.COLOR_BRACKETED_WORD)) + else: + self.win.attron(curses.color_pair(color)) + self.win.addstr(word) + self.win.attroff(curses.color_pair(color)) + try: + self.win.addstr(' ') + except: + pass def write_nickname(self, nickname, color): """ @@ -712,10 +743,7 @@ class Input(Win): Refresh the line onscreen, from the pos and pos_line """ self.clear_text() - try: # FIXME: this try should NOT be needed - self.win.addstr(self.text[self.line_pos:self.line_pos+self.width-1].encode('utf-8')) - except: - pass + self.win.addstr(self.text[self.line_pos:self.line_pos+self.width-1].encode('utf-8')) self.win.move(0, self.pos) self.refresh()