From f36fefdce5d9369516a7d88528902b5081080876 Mon Sep 17 00:00:00 2001 From: "louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13" Date: Thu, 21 Jan 2010 01:54:50 +0000 Subject: on peut parler, recevoir des messages, rejoindre des salons (/join), changer de tab (/next, /prev), mais ca blink et c'est nul --- src/gui.py | 351 +++++++++++++++++++++++-------------------------------------- 1 file changed, 129 insertions(+), 222 deletions(-) (limited to 'src/gui.py') diff --git a/src/gui.py b/src/gui.py index e41ec5a9..c69b5901 100644 --- a/src/gui.py +++ b/src/gui.py @@ -22,222 +22,162 @@ import curses from curses import textpad import locale +from datetime import datetime + locale.setlocale(locale.LC_ALL, '') code = locale.getpreferredencoding() import sys from connection import * +from window import Window -class Win(object): - def __init__(self, height, width, y, x, parent_win): - self._resize(height, width, y, x, parent_win) - - def _resize(self, height, width, y, x, parent_win): - self.height, self.width, self.x, self.y = height, width, x, y - try: - self.win = parent_win.subwin(height, width, y, x) - except: - pass - -class UserList(Win): - def __init__(self, height, width, y, x, parent_win): - Win.__init__(self, height, width, y, x, parent_win) - self.win.attron(curses.color_pair(2)) - self.win.vline(0, 0, curses.ACS_VLINE, self.height) - self.win.attroff(curses.color_pair(2)) - self.list = [] - - def add_user(self, name): - """ - add an user to the list - """ - self.list.append(name) - - def refresh(self): - self.win.clear() - self.win.attron(curses.color_pair(2)) - self.win.vline(0, 0, curses.ACS_VLINE, self.height) - self.win.attroff(curses.color_pair(2)) - y = 0 - for name in self.list: - self.win.addstr(y, 1, name) - y += 1 - self.win.refresh() - - def resize(self, height, width, y, x, stdscr): - self._resize(height, width, y, x, stdscr) - self.refresh() - -class Info(Win): - def __init__(self, height, width, y, x, parent_win): - Win.__init__(self, height, width, y, x, parent_win) - self.txt = "" -# self.win.bkgd(ord('p'), curses.COLOR_BLUE) - - def set_info(self, text): - self.txt = text - self.refresh() - - def resize(self, height, width, y, x, stdscr): - self._resize(height, width, y, x, stdscr) - self.refresh() - - def refresh(self): - self.win.clear() - try: - self.win.addstr(0, 0, self.txt + " "*(self.width-len(self.txt)-1) - , curses.color_pair(1)) - except: - pass - -class TextWin(Win): - def __init__(self, height, width, y, x, parent_win): - Win.__init__(self, height, width, y, x, parent_win) - self.lines = [] - - def add_line(self, time, nick, text): - self.lines.append((time, nick, text)) - self.refresh() - - def refresh(self): - self.win.clear() - y = 0 - for line in self.lines[-self.height:]: - self.win.addstr(y, 0, line[0] + " : " + line[1] + ": " + line[2]) - y += 1 - self.win.refresh() - - def resize(self, height, width, y, x, stdscr): - self._resize(height, width, y, x, stdscr) - self.refresh() - -class Input(Win): +class User(object): """ + keep trace of an user in a Room """ - def __init__(self, height, width, y, x, stdscr): - Win.__init__(self, height, width, y, x, stdscr) - self.input = curses.textpad.Textbox(self.win) - self.input.stripspaces = False - self.input.insert_mode = True - self.txt = '' - - def resize(self, height, width, y, x, stdscr): - self._resize(height, width, y, x, stdscr) - self.input = curses.textpad.Textbox(self.win) - self.input.insert_mode = True - self.input.stripspaces = False - self.win.clear() - self.win.addstr(self.txt) - - def do_command(self, key): - self.input.do_command(key) -# self.win.refresh() -# self.text = self.input.gather() + def __init__(self, nick, affiliation, show, status, role): + self.update(affiliation, show, status, role) + self.change_nick(nick) - # def insert_char(self, key): - # if self.insert: - # self.text = self.text[:self.pos]+key+self.text[self.pos:] - # else: - # self.text = self.text[:self.pos]+key+self.text[self.pos+1:] - # self.pos += 1 - # pass + def update(self, affiliation, show, status, role): + self.affiliation = None + self.show = None + self.status = status + self.role = role - def get_text(self): - return self.input.gather() + def change_nick(self, nick): + self.nick = nick - def save_text(self): - self.txt = self.input.gather() -# self.win.clear() -# self.win.addstr(self.txt) - - def refresh(self): -# self.win.clear() -# self.win.addstr(self.text) -# self.win.move(0, len(self.text)-1) - self.win.refresh() - - def clear_text(self): - self.win.clear() - self.txt = '' - self.pos = 0 - self.refresh() - -class Tab(object): +class Room(object): """ - The whole "screen" that can be seen at once in the terminal. - It contains an userlist, an input zone and a chat zone, all - related to one single chat room. """ - def __init__(self, stdscr, name='info'): - """ - name is the name of the Tab, and it's also - the JID of the chatroom. - A particular tab is the "Info" tab which has no - name (None). This info tab should be unique. - The stdscr should be passed to know the size of the - terminal - """ + def __init__(self, name, nick): self.name = name - self.size = (self.height, self.width) = stdscr.getmaxyx() + self.own_nick = nick + self.joined = False # false until self presence is received + self.users = [] + self.lines = [] # (time, nick, msg) or (time, info) + self.topic = '' - self.user_win = UserList(self.height-3, self.width/7, 1, 6*(self.width/7), stdscr) - self.topic_win = Info(1, self.width, 0, 0, stdscr) - self.info_win = Info(1, self.width, self.height-2, 0, stdscr) - self.text_win = TextWin(self.height-3, (self.width/7)*6, 1, 0, stdscr) - self.input = Input(1, self.width, self.height-1, 0, stdscr) + def add_message(self, nick, msg): + self.lines.append((datetime.now(), nick, msg.encode('utf-8'))) - self.info_win.set_info(name) - # debug - self.refresh() + def add_info(self, info): + """ info, like join/quit/status messages""" + self.lines.append((datetime.now(), info.encode('utf-8'))) - def resize(self, stdscr): + def on_presence(self, stanza, nick): """ - Resize the whole tabe. i.e. all its sub-windows """ - self.size = (self.height, self.width) = stdscr.getmaxyx() - self.user_win.resize(self.height-3, self.width/7, 1, 6*(self.width/7), stdscr) - self.topic_win.resize(1, self.width, 0, 0, stdscr) - self.info_win.resize(1, self.width, self.height-2, 0, stdscr) - self.text_win.resize(self.height-3, (self.width/7)*6, 1, 0, stdscr) - self.input.resize(1, self.width, self.height-1, 0, stdscr) - self.refresh() - - def refresh(self): - self.text_win.add_line("fion", "fion", "refresh") - self.text_win.refresh() - self.user_win.refresh() - self.topic_win.refresh() - self.info_win.refresh() - self.input.refresh() - - def do_command(self, key): - self.input.do_command(key) -# self.input.save_text() - self.input.refresh() + affiliation = stanza.getAffiliation() + show = stanza.getShow() + status = stanza.getStatus() + role = stanza.getRole() + if not self.joined: + self.users.append(User(nick, affiliation, show, status, role)) + if nick == self.own_nick: + self.joined = True + self.add_info("%s is in the room" % (nick)) + return + change_nick = stanza.getStatusCode() == '303' + for user in self.users: + if user.nick == nick: + if change_nick: + user.change_nick(stanza.getNick()) + self.add_info('%s is now known as %s' % (nick, stanza.getNick())) + return + if status == 'offline': + self.users.remove(user) + self.add_info('%s has left the room' % (nick)) + return + user.update(affiliation, show, status, role) + self.add_info('%s, status : %s, %s, %s, %s' % (nick, affiliation, role, show, status)) + return + self.users.append(User(nick, affiliation, show, status, role)) + self.add_info('%s joined the room %s' % (nick, self.name)) class Gui(object): """ Graphical user interface using ncurses """ - def __init__(self, stdscr): - self.handler = Handler() + def __init__(self, stdscr=None, muc=None): + + self.init_curses(stdscr) + self.stdscr = stdscr + self.stdscr.leaveok(True) + self.rooms = [Room('Info', '')] # current_room is self.rooms[0] + self.window = Window(stdscr) + self.window.refresh(self.rooms[0]) + + self.muc = muc self.commands = { 'join': self.command_join, 'quit': self.command_quit, + 'next': self.rotate_rooms_left, + 'prev': self.rotate_rooms_right, } - self.handler.connect('on-muc-message-received', self.on_message) - self.handler.connect('gui-join-room', self.on_join_room) - self.handler.connect('on-muc-presence-changed', self.on_presence) - self.init_curses(stdscr) - self.stdscr = stdscr + self.handler = Handler() + self.handler.connect('on-connected', self.on_connected) + self.handler.connect('join-room', self.join_room) + self.handler.connect('room-presence', self.room_presence) + self.handler.connect('room-message', self.room_message) + + def init_curses(self, stdscr): + curses.start_color() + curses.noecho() + curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE) + curses.init_pair(2, curses.COLOR_BLUE, curses.COLOR_BLACK) + + def on_connected(self): + pass + + def join_room(self, room, nick): + self.rooms.insert(0, Room(room, nick)) + self.window.refresh(self.rooms[0]) + + def rotate_rooms_left(self, args): + self.rooms.append(self.rooms.pop(0)) + self.window.refresh(self.rooms[0]) + + def rotate_rooms_right(self, args): + self.rooms.insert(0, self.rooms.pop()) + self.window.refresh(self.rooms[0]) + + def room_message(self, stanza): + if stanza.getType() != 'groupchat': + return # ignore all messages not comming from a MUC + room_from = stanza.getFrom().getStripped() + nick_from = stanza.getFrom().getResource() + for room in self.rooms: + if room_from == room.name: + room.add_message(nick_from, stanza.getBody()) + if room == self.rooms[0]: + # self.window.text_win.refresh(room.lines) + # self.window.user_win.refresh(room.users) + # self.window.input.refresh() + self.window.refresh(self.rooms[0]) + break + + def room_presence(self, stanza): + from_nick = stanza.getFrom().getResource() + from_room = stanza.getFrom().getStripped() + for room in self.rooms: + if from_room == room.name: + room.on_presence(stanza, from_nick) + if room == self.rooms[0]: + self.window.text_win.refresh(room.lines) + self.window.user_win.refresh(room.users) + break def execute(self): - line = self.current_tab.input.get_text() - self.current_tab.input.clear_text() + line = self.window.input.get_text() + self.window.input.clear_text() + if line == "": + return if line.strip().startswith('/'): command = line.strip()[:].split()[0][1:] args = line.strip()[:].split()[1:] @@ -245,58 +185,25 @@ class Gui(object): func = self.commands[command] func(args) return - self.current_tab.text_win.add_line("NOW", "louiz'", line) - # TODO, send message to jabber + if self.rooms[0].name != 'Info': + self.muc.send_message(self.rooms[0].name, line) def command_join(self, args): room = args[0] - self.on_join_room(room, "poezio") + self.muc.join_room(room, "poezio") + self.join_room(room, 'poezio') def command_quit(self, args): sys.exit() - def init_curses(self, stdscr): - stdscr.leaveok(True) - curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE) - curses.init_pair(2, curses.COLOR_BLUE, curses.COLOR_BLACK) - self.current_tab = Tab(stdscr) - self.tabs = [self.current_tab] - def main_loop(self, stdscr): while 1: stdscr.refresh() + # self.window.input.refresh() key = stdscr.getch() if key == curses.KEY_RESIZE: - self.current_tab.resize(stdscr) + self.window.resize(stdscr) elif key == 10: self.execute() else: - self.current_tab.do_command(key) - - def on_message(self, jid, msg, subject, typ, stanza): - print "on_message", jid, msg, subject, typ - - def on_join_room(self, room, nick): - sys.stderr.write(room) - self.current_tab = Tab(self.stdscr, room) - self.tabs.append(self.current_tab) -# self.current_tab.resize() - self.current_tab.refresh() - print "on_join_room", room, nick - - def on_presence(self, jid, priority, show, status, stanza): - print "on presence", jid, priority, show, status - -def main(stdscr): - gui = Gui(stdscr) - gui.main_loop(stdscr) - -if __name__ == '__main__': - resource = config.get('resource') - server = config.get('server') - connection = Connection(server, resource) - connection.start() - curses.wrapper(main) - # rooms = config.get('rooms').split(':') - # for room in rooms: - # connection.send_join_room(room.split('/')[0], room.split('/')[1]) + self.window.do_command(key) -- cgit v1.2.3