primitivus group chat & misc

primitivus: new widget: SurroundedText (text with a character repeated around it)
primitivus: new decorator LabelLine (like lineBox, but with a label on the top line)
wix & primitivus & quick_app: group chat method move to quick_chat

wix: when new message, window is not raised anymore, but RequestUserAttention is called instead
This commit is contained in:
Goffi 2010-07-08 14:12:18 +08:00
commit dbb3520a4f
7 changed files with 113 additions and 31 deletions

View file

@ -22,7 +22,7 @@ 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 custom_widgets import Password,List,InputDialog,ConfirmDialog,Alert,SelectableText
from custom_widgets import Password,List,InputDialog,ConfirmDialog,Alert,SelectableText,LabelLine,SurroundedText
class Chat(urwid.WidgetWrap, QuickChat):
@ -31,8 +31,8 @@ class Chat(urwid.WidgetWrap, QuickChat):
QuickChat.__init__(self, target, host, type)
self.content = urwid.SimpleListWalker([])
self.text_list = urwid.ListBox(self.content)
main_widget = urwid.LineBox(
urwid.Frame(self.text_list, urwid.AttrMap(urwid.Text(str(target),'center'),'title'))
main_widget = LabelLine(
urwid.Frame(self.text_list), SurroundedText(str(target))
)
urwid.WidgetWrap.__init__(self, main_widget)
self.setType(type)
@ -41,6 +41,12 @@ class Chat(urwid.WidgetWrap, QuickChat):
QuickChat.setType(self, type)
if type == 'one2one':
self.historyPrint(profile=self.host.profile)
def setSubject(self, subject):
"""Set title for a group chat"""
QuickChat.setSubject(self, subject)
self._w.base_widget.header = urwid.AttrMap(urwid.Text(unicode(subject),align='center'),'title')
def printMessage(self, from_jid, msg, profile, timestamp=""):
self.content.append(SelectableText("[%s] " % from_jid + msg))

View file

@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import urwid
from quick_frontend.quick_contact_list import QuickContactList
from custom_widgets import Password,List,InputDialog,ConfirmDialog,Alert
from custom_widgets import Password,List,InputDialog,ConfirmDialog,Alert,LabelLine,SurroundedText
class ContactList(urwid.WidgetWrap, QuickContactList):
@ -35,8 +35,8 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
#we now build the widget
body_content = urwid.SimpleListWalker([self.list_wid])
frame_body = urwid.ListBox(body_content)
frame = urwid.Frame(frame_body,urwid.AttrMap(urwid.Text(_("Contacts"),align='center'),'title'))
self.main_widget = urwid.LineBox(frame)
frame = urwid.Frame(frame_body) #,urwid.AttrMap(urwid.Text(_("Contacts"),align='center'),'title'))
self.main_widget = LabelLine(frame,SurroundedText(_("Contacts")))
urwid.WidgetWrap.__init__(self, self.main_widget)
if on_click:
urwid.connect_signal(self, 'click', on_click, user_data)

View file

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import urwid
from urwid.escape import utf8decode
class Password(urwid.Edit):
@ -59,7 +60,28 @@ class AdvancedEdit(urwid.Edit):
return super(AdvancedEdit, self).keypress(size, key)
class SurroundedText(urwid.FlowWidget):
def __init__(self,text,car=utf8decode('─')):
self.text=text
self.car=car
def rows(self,size,focus=False):
return self.display_widget(size, focus).rows(size, focus)
def render(self, size, focus=False):
return self.display_widget(size, focus).render(size, focus)
def display_widget(self, size, focus):
(maxcol,) = size
middle = (maxcol-len(self.text))/2
render_text = middle * self.car + self.text + (maxcol - len(self.text) - middle) * self.car
return urwid.Text(render_text)
class SelectableText(urwid.FlowWidget):
"""Text which can be selected with space"""
signals = ['change']
def __init__(self, text, align='left'):
@ -255,9 +277,11 @@ class List(urwid.FlowWidget):
def displayWidget(self, size, focus):
list_size = sum([wid.rows(size, focus) for wid in self.genericList.content])
height = min(list_size,self.max_height)
height = min(list_size,self.max_height) or 1
return urwid.BoxAdapter(self.genericList, height)
## DIALOGS ##
class GenericDialog(urwid.WidgetWrap):
def __init__(self, widgets_lst, title, style=[], **kwargs):
@ -286,9 +310,9 @@ class GenericDialog(urwid.WidgetWrap):
class InputDialog(GenericDialog):
def __init__(self, title, instrucions, style=['OK/CANCEL'], **kwargs):
def __init__(self, title, instrucions, style=['OK/CANCEL'], default_txt = '', **kwargs):
instr_wid = urwid.Text(instrucions+':')
edit_box = urwid.Edit()
edit_box = urwid.Edit(edit_text=default_txt)
GenericDialog.__init__(self, [instr_wid,edit_box], title, style, ok_value=edit_box, **kwargs)
class ConfirmDialog(GenericDialog):
@ -301,6 +325,8 @@ class Alert(GenericDialog):
def __init__(self, title, message, style=['OK'], **kwargs):
GenericDialog.__init__(self, [urwid.Text(message, 'center')], title, style, ok_value=None, **kwargs)
## CONTAINERS ##
class FocusFrame(urwid.Frame):
"""Frame which manage "tab" key"""
@ -316,3 +342,12 @@ class FocusFrame(urwid.Frame):
self.set_focus(focus_name)
return urwid.Frame.keypress(self, size, key)
## DECORATORS ##
class LabelLine(urwid.LineBox):
def __init__(self, original_widget, label_widget):
urwid.LineBox.__init__(self, original_widget)
top_columns = self._w.widget_list[0]
top_columns.widget_list[1] = label_widget

View file

@ -28,7 +28,7 @@ import urwid
from profile_manager import ProfileManager
from contact_list import ContactList
from chat import Chat
from custom_widgets import AdvancedEdit,FocusFrame
from custom_widgets import AdvancedEdit,FocusFrame,InputDialog,Alert
import pdb
"""from window import Window
from editbox import EditBox
@ -39,6 +39,7 @@ import logging
from logging import debug, info, error
#import locale
import sys, os
from tools.jid import JID
#from curses import ascii
#import locale
#from signal import signal, SIGWINCH
@ -104,6 +105,9 @@ class PrimitivusApp(QuickApp):
raise urwid.ExitMainLoop()
elif input == 'ctrl d' and 'D' in self.bridge.getVersion(): #Debug only for dev versions
self.debug()
elif input == 'meta j': #user wants to join a room
pop_up_widget = InputDialog(_("Entering a MUC room"), _("Please enter MUC's JID"), default_txt = 'test@conference.necton2.int', cancel_cb=self.removePopUp, ok_cb=self.onJoinRoom)
self.showPopUp(pop_up_widget)
def __buildMainWidget(self):
self.contactList = ContactList(self, self.CM, on_click = self.contactSelected, on_change=lambda w: self.redraw())
@ -118,7 +122,7 @@ class PrimitivusApp(QuickApp):
self.loop.widget = self.__buildMainWidget()
QuickApp.plug_profile(self, profile_key)
def removePopUp(self):
def removePopUp(self, widget=None):
self.loop.widget = self.main_widget
def showPopUp(self, pop_up_widget):
@ -134,11 +138,26 @@ class PrimitivusApp(QuickApp):
self.center_part.widget_list[1] = self.chat_wins[contact]
def onTextEntered(self, editBar):
contact = self.contactList.get_contact()
"""Called when text is entered in the main edit bar"""
contact = self.contactList.get_contact() ###Based on the fact that there is currently only one contact selectableat once
if contact:
self.bridge.sendMessage(contact, editBar.get_edit_text(), profile_key=self.profile)
chat = self.chat_wins[contact]
self.bridge.sendMessage(contact,
editBar.get_edit_text(),
type = "groupchat" if chat.type == 'group' else "chat",
profile_key=self.profile)
editBar.set_edit_text('')
def onJoinRoom(self, button, edit):
self.removePopUp()
room_jid = JID(edit.get_edit_text())
if room_jid.is_valid():
self.bridge.joinMUC(room_jid.domain, room_jid.node, self.profiles[self.profile]['whoami'].node, self.profile)
else:
message = _("'%s' is an invalid JID !") % room_jid
error (message)
Alert(_("Error"), message, ok_cb=self.removePopUp)
sat = PrimitivusApp()
sat.start()

View file

@ -40,10 +40,40 @@ class QuickChat():
"""
self.type = type
def setPresents(self, nicks):
"""Set the users presents in the contact list for a group chat
@param nicks: list of nicknames
"""
debug (_("Adding users %s to room") % nicks)
if self.type != "group":
error (_("[INTERNAL] trying to set presents nicks for a non group chat window"))
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
def replaceUser(self, nick):
"""Add user if it is not in the group list"""
debug (_("Replacing user %s") % nick)
if self.type != "group":
error (_("[INTERNAL] trying to replace user for a non group chat window"))
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
def setUserNick(self, nick):
"""Set the nick of the user, usefull for e.g. change the color of the user"""
self.nick = nick
def removeUser(self, nick):
"""Remove a user from the group list"""
debug(_("Removing user %s") % nick)
if self.type != "group":
error (_("[INTERNAL] trying to remove user for a non group chat window"))
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
def setSubject(self, subject):
"""Set title for a group chat"""
debug(_("Setting subject to %s") % subject)
if self.type != "group":
error (_("[INTERNAL] trying to set subject for a non group chat window"))
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
def historyPrint(self, size=20, keep_last=False, profile='@NONE@'):
"""Print the initial history"""
debug (_("now we print history"))

View file

@ -128,10 +128,7 @@ class Chat(wx.Frame, QuickChat):
"""Set the users presents in the contact list for a group chat
@param nicks: list of nicknames
"""
debug (_("Adding users %s to room") % nicks)
if self.type != "group":
error (_("[INTERNAL] trying to set presents nicks for a non group chat window"))
return
QuickChat.setPresents(self, nicks)
for nick in nicks:
self.present_panel.presents.replace(nick)
self.occupants.add(nick)
@ -143,27 +140,19 @@ class Chat(wx.Frame, QuickChat):
if self.type != "group":
error (_("[INTERNAL] trying to replace user for a non group chat window"))
return
self.present_panel.presents.replace(nick)
self.occupants.add(nick)
QuickChat.replaceUser(self, nick)
def removeUser(self, nick):
"""Remove a user from the group list"""
debug(_("Removing user %s") % nick)
if self.type != "group":
error (_("[INTERNAL] trying to remove user for a non group chat window"))
return
QuickChat.removeUser(self, nick)
self.present_panel.presents.remove(nick)
self.occupants.remove(nick)
def setSubject(self, subject):
"""Set title for a group chat"""
debug(_("Setting subject to %s") % subject)
if self.type != "group":
error (_("[INTERNAL] trying to set subject for a non group chat window"))
return
QuickChat.setSubject(self, subject)
self.subjectBox.SetValue(subject)
def __eraseMenus(self):
"""erase all menus"""
menuBar = self.GetMenuBar()
@ -228,7 +217,10 @@ class Chat(wx.Frame, QuickChat):
self.chatWindow.SetDefaultStyle(wx.TextAttr("BLACK", font=_font))
self.chatWindow.AppendText("%s\n" % msg)
if not mymess:
self.Raise() #FIXME: too intrusive
#TODO: use notification system
self.RequestUserAttention() #FIXME: do this only if in background.
self.Show() #gof: FIXME: to check
#self.Raise() #FIXME: too intrusive
### events ###

View file

@ -442,7 +442,7 @@ class MainWindow(wx.Frame, QuickApp):
#TODO: a proper MUC room joining dialog with nickname etc
dlg = wx.TextEntryDialog(
self, _("Please enter MUC's JID"),
_('Entering a MUC room'), _('test@conference.necton2.int'))
_('Entering a MUC room'), 'test@conference.necton2.int')
#_('Entering a MUC room'), _('room@muc_service.server.tld'))
if dlg.ShowModal() == wx.ID_OK:
room_jid=JID(dlg.GetValue())