diff frontends/src/primitivus/chat.py @ 223:86d249b6d9b7

Files reorganisation
author Goffi <goffi@goffi.org>
date Wed, 29 Dec 2010 01:06:29 +0100
parents frontends/primitivus/chat.py@3198bfd66daa
children fd9b7834d98a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frontends/src/primitivus/chat.py	Wed Dec 29 01:06:29 2010 +0100
@@ -0,0 +1,279 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+Primitivus: a SAT frontend
+Copyright (C) 2009, 2010  Jérôme Poisson (goffi@goffi.org)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import urwid
+from quick_frontend.quick_contact_list import QuickContactList
+from quick_frontend.quick_chat import QuickChat
+from urwid_satext import sat_widgets
+import time
+from tools.jid  import JID
+from card_game import CardGame
+from urwid_satext.files_management import FileDialog
+
+
+class ChatText(urwid.FlowWidget):
+    """Manage the printing of chat message"""
+    
+    def __init__(self, parent, timestamp, nick, my_mess, message, align='left'):
+        self.parent = parent
+        self.timestamp = time.localtime(timestamp)
+        self.nick = nick
+        self.my_mess = my_mess
+        self.message = unicode(message)
+        self.align = align
+
+    def selectable(self):
+        return True
+
+    def keypress(self, size, key):
+        return key
+
+    def rows(self,size,focus=False):
+        return self.display_widget(size, focus).rows(size, focus)
+
+    def render(self, size, focus=False):
+        canvas = urwid.CompositeCanvas(self.display_widget(size, focus).render(size, focus))
+        if focus:
+            canvas.set_cursor(self.get_cursor_coords(size))
+        return canvas
+
+    def get_cursor_coords(self, size):
+        #(maxcol,) = size
+        return 0, 0
+
+    def display_widget(self, size, focus):
+        render_txt = []
+        if self.parent.show_timestamp:
+            time_format = "%c" if self.timestamp < self.parent.day_change else "%H:%M" #if the message was sent before today, we print the full date
+            render_txt.append(('date',"[%s]" % time.strftime(time_format, self.timestamp).decode('utf-8')))
+        if self.parent.show_short_nick:
+            render_txt.append(('my_nick' if self.my_mess else 'other_nick',"**" if self.my_mess else "*"))
+        else:
+            render_txt.append(('my_nick' if self.my_mess else 'other_nick',"[%s] " % self.nick))
+        render_txt.append(self.message)
+        return urwid.Text(render_txt, align=self.align)
+
+class Chat(urwid.WidgetWrap, QuickChat):
+
+    def __init__(self, target, host, type='one2one'):
+        self.target = target
+        QuickChat.__init__(self, target, host, type)
+        self.content = urwid.SimpleListWalker([])
+        self.text_list = urwid.ListBox(self.content)
+        self.chat_widget = urwid.Frame(self.text_list)
+        self.chat_colums = urwid.Columns([('weight', 8, self.chat_widget)])
+        self.chat_colums = urwid.Columns([('weight', 8, self.chat_widget)])
+        self.pile = urwid.Pile([self.chat_colums])
+        urwid.WidgetWrap.__init__(self, self.__getDecoration(self.pile))
+        self.setType(type)
+        self.day_change = time.strptime(time.strftime("%a %b %d 00:00:00  %Y")) #struct_time of day changing time
+        self.show_timestamp = True
+        self.show_short_nick = False
+        self.show_title = 1 #0: clip title; 1: full title; 2: no title
+        self.subject = None
+
+    def keypress(self, size, key):
+        if key == "meta p": #user wants to (un)hide the presents panel
+            if self.type == 'group':
+                widgets = self.chat_colums.widget_list
+                if self.present_panel in widgets:
+                    self.__removePresentPanel()
+                else:
+                    self.__appendPresentPanel()
+        elif key == "meta t": #user wants to (un)hide timestamp
+            self.show_timestamp = not self.show_timestamp
+            for wid in self.content:
+                wid._invalidate()
+        elif key == "meta n": #user wants to (not) use short nick
+            self.show_short_nick = not self.show_short_nick
+            for wid in self.content:
+                wid._invalidate()
+        elif key == "meta l": #user wants to (un)hide widget decoration
+            show = not isinstance(self._w, sat_widgets.LabelLine)
+            self.showDecoration(show)
+            self._invalidate()
+        elif key == "meta s": #user wants to (un)hide group's subject or change its apperance
+            if self.subject:
+                self.show_title = (self.show_title + 1) % 3
+                if self.show_title == 0:
+                    self.setSubject(self.subject,'clip')
+                elif self.show_title == 1:
+                    self.setSubject(self.subject,'space')
+                elif self.show_title == 2:
+                    self.chat_widget.header = None
+                self._invalidate()
+
+
+        return super(Chat, self).keypress(size, key) 
+    
+    def getMenu(self):
+        """Return Menu bar"""
+        menu = sat_widgets.Menu(self.host.loop)
+        if self.type == 'group':
+            game = _("Game")
+            menu.addMenu(game, "Tarot", self.onTarotRequest)
+        elif self.type == 'one2one':
+            menu.addMenu(_("Action"), _("Send file"), self.onSendFileRequest)
+        return menu
+
+    def setType(self, type):
+        QuickChat.setType(self, type)
+        if type == 'one2one':
+            self.historyPrint(profile=self.host.profile)
+        elif type == 'group':
+            if len(self.chat_colums.widget_list) == 1:
+                present_widget = self.__buildPresentList()
+                self.present_panel = sat_widgets.VerticalSeparator(present_widget)
+                self.__appendPresentPanel()
+          
+    def __getDecoration(self, widget):
+        return sat_widgets.LabelLine(widget, sat_widgets.SurroundedText(unicode(self.target)))
+
+    def showDecoration(self, show=True):
+        """Show/Hide the decoration around the chat window"""
+        if show:
+            main_widget = self.__getDecoration(self.pile)
+        else:
+            main_widget = self.pile
+        self._w = main_widget
+
+
+    def __buildPresentList(self):
+        self.present_wid = sat_widgets.GenericList([],option_type = sat_widgets.ClickableText)
+        return self.present_wid
+   
+    def __appendPresentPanel(self):
+        self.chat_colums.widget_list.append(self.present_panel) 
+        self.chat_colums.column_types.append(('weight', 2))
+
+    def __removePresentPanel(self):
+        self.chat_colums.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.chat_colums
+        self.chat_colums.widget_list.remove(self.present_panel)
+        del self.chat_colums.column_types[-1]
+    
+    def __appendGamePanel(self, widget):
+        assert (len(self.pile.widget_list) == 1)
+        self.pile.widget_list.insert(0,widget)
+        self.pile.item_types.insert(0,('weight', 1))
+        self.pile.widget_list.insert(1,urwid.Filler(urwid.Divider('-')))
+        self.pile.item_types.insert(1,('fixed', 1))
+        self.host.redraw()
+
+    def __removeGamePanel(self):
+        assert (len(self.pile.widget_list) == 3)
+        self.pile.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.chat_colums
+        del self.pile.widget_list[0]
+        del self.pile.item_types[0]
+        self.host.redraw()
+
+    def setSubject(self, subject, wrap='space'):
+        """Set title for a group chat"""
+        QuickChat.setSubject(self, subject)
+        self.subject = subject
+        self.subj_wid = urwid.Text(unicode(subject.replace('\n','|') if wrap == 'clip' else subject ),
+                                  align='left' if wrap=='clip' else 'center',wrap=wrap)
+        self.chat_widget.header = urwid.AttrMap(self.subj_wid,'title')
+        self.host.redraw()
+
+    def setPresents(self, param_nicks):
+        """Set the users presents in the contact list for a group chat
+        @param nicks: list of nicknames
+        """
+        nicks = [unicode(nick) for nick in param_nicks] #FIXME: should be done in DBus bridge
+        nicks.sort()
+        QuickChat.setPresents(self, nicks)
+        self.present_wid.changeValues(nicks)
+        self.host.redraw()
+
+    def replaceUser(self, param_nick):
+        """Add user if it is not in the group list"""
+        nick = unicode(param_nick) #FIXME: should be done in DBus bridge
+        if "facebook" in nick:
+            self.host.debug()
+        QuickChat.replaceUser(self, nick)
+        presents = self.present_wid.getAllValues()
+        if nick not in presents:
+            presents.append(nick)
+            presents.sort()
+            self.present_wid.changeValues(presents)
+        self.host.redraw()
+
+    def removeUser(self, param_nick):
+        """Remove a user from the group list"""
+        nick = unicode(param_nick) #FIXME: should be done in DBus bridge
+        QuickChat.removeUser(self, nick)
+        self.present_wid.deleteValue(nick)
+        self.host.redraw()
+
+    def printMessage(self, from_jid, msg, profile, timestamp=""):
+        assert isinstance(from_jid, JID)
+        try:
+            jid,nick,mymess = QuickChat.printMessage(self, from_jid, msg, profile, timestamp)
+        except TypeError:
+            return
+        my_jid = self.host.profiles[profile]['whoami']
+        self.content.append(ChatText(self, timestamp or None, nick, mymess, msg))
+        self.text_list.set_focus(len(self.content)-1)
+        self.host.redraw()
+    
+    def printInfo(self, msg, type='normal'):
+        """Print general info
+        @param msg: message to print
+        @type: one of:
+            normal: general info like "toto has joined the room"
+            me: "/me" information like "/me clenches his fist" ==> "toto clenches his fist"
+        """
+        self.content.append(sat_widgets.ClickableText(msg))
+        self.text_list.set_focus(len(self.content)-1)
+        self.host.redraw()
+    
+    def startGame(self, game_type, referee, players):
+        """Configure the chat window to start a game"""
+        if game_type=="Tarot":
+            try:
+                self.tarot_wid = CardGame(self, referee, players, self.nick)
+                self.__appendGamePanel(self.tarot_wid)
+            except e:
+                self.host.debug()
+    
+    def getGame(self, game_type):
+        """Return class managing the game type"""
+        #TODO: check that the game is launched, and manage errors
+        if game_type=="Tarot":
+            return self.tarot_wid 
+
+    #MENU EVENTS#
+    def onTarotRequest(self, menu):
+        if len(self.occupants) != 4:
+            self.host.showPopUp(sat_widgets.Alert(_("Can't start game"), _("You need to be exactly 4 peoples in the room to start a Tarot game"), ok_cb=self.host.removePopUp)) 
+        else:
+            self.host.bridge.tarotGameCreate(self.id, list(self.occupants), self.host.profile)
+    
+    def onSendFileRequest(self, menu):
+        dialog = FileDialog(ok_cb=self.onFileSelected, cancel_cb=self.host.removePopUp)
+        self.host.showPopUp(dialog, 80, 80)
+
+    #MISC EVENTS#
+    def onFileSelected(self, filepath):
+        self.host.removePopUp()
+        full_jid = self.host.CM.get_full(self.target)
+        id = self.host.bridge.sendFile(full_jid, filepath)
+        self.host.addProgress(id,filepath)