Added auto(dis)connect params + misc

- parameters,xmlui: "bool" type is now managed
- parameters,xmlui: categories now use label in addition of name
- QuickFrontend: auto(dis)connection management
- plugin XEP-0045: an error dialog is now show in frontend if room cannot be joined
- Wix: fixed unproper close event management
This commit is contained in:
Goffi 2010-08-18 15:57:26 +08:00
commit 007f12d2ae
11 changed files with 125 additions and 59 deletions

View file

@ -436,6 +436,7 @@ class PrimitivusApp(QuickApp):
self.addWindow(params)
def onExitRequest(self, menu):
QuickApp.onExit(self)
raise urwid.ExitMainLoop()
def onJoinRoomRequest(self, menu):

View file

@ -90,6 +90,9 @@ class XMLUI(urwid.WidgetWrap):
elif type=="textbox":
ctrl = custom_widgets.AdvancedEdit(edit_text = value, multiline=True)
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
elif type=="bool":
ctrl = urwid.CheckBox('', state = value=="true")
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
elif type=="list":
style=[] if elem.getAttribute("multi")=='yes' else ['single']
ctrl = custom_widgets.List(options=[option.getAttribute("value") for option in elem.getElementsByTagName("option")], style=style)
@ -102,7 +105,7 @@ class XMLUI(urwid.WidgetWrap):
error(_("FIXME FIXME FIXME: type [%s] is not implemented") % type) #FIXME !
raise NotImplementedError
if self.type == 'param':
if isinstance(ctrl,urwid.Edit):
if isinstance(ctrl,urwid.Edit) or isinstance(ctrl,urwid.CheckBox):
urwid.connect_signal(ctrl,'change',self.onParamChange)
ctrl._param_category = self._current_category
ctrl._param_name = name
@ -133,12 +136,13 @@ class XMLUI(urwid.WidgetWrap):
self.__parseElems(node, current)
elif node.nodeName == "category":
name = node.getAttribute('name')
label = node.getAttribute('label')
if not name or not isinstance(data,custom_widgets.TabsContainer):
raise InvalidXMLUI
if self.type == 'param':
self._current_category = name #XXX: awful hack because params need category and we don't keep parent
tab_cont = data
listbox = tab_cont.addTab(name)
listbox = tab_cont.addTab(label or name)
self.__parseChilds(listbox.body, node, ['layout'])
else:
message=_("Unknown tag")
@ -217,7 +221,7 @@ class XMLUI(urwid.WidgetWrap):
id = self.host.bridge.launchAction("button", data, profile_key = self.host.profile)
self.host.current_action_ids.add(id)
def onParamChange(self, widget, text):
def onParamChange(self, widget, extra=None):
"""Called when type is param and a widget to save is modified"""
assert(self.type == "param")
self.param_changed.add(widget)
@ -228,6 +232,8 @@ class XMLUI(urwid.WidgetWrap):
ctrl = self.ctrl_list[ctrl_name]
if isinstance(ctrl['control'], custom_widgets.List):
data.append((ctrl_name, ctrl['control'].getSelectedValue()))
if isinstance(ctrl['control'], urwid.CheckBox):
data.append((ctrl_name, "true" if ctrl['control'].get_state() else "false"))
else:
data.append((ctrl_name, ctrl['control'].get_edit_text()))
if self.misc.has_key('action_back'): #FIXME FIXME FIXME: WTF ! Must be cleaned
@ -247,5 +253,9 @@ class XMLUI(urwid.WidgetWrap):
def onSaveParams(self, button):
for ctrl in self.param_changed:
self.host.bridge.setParam(ctrl._param_name, ctrl.get_edit_text(), ctrl._param_category, profile_key = self.host.profile)
if isinstance(ctrl, urwid.CheckBox):
value = "true" if ctrl.get_state() else "false"
else:
value = ctrl.get_edit_text()
self.host.bridge.setParam(ctrl._param_name, value, ctrl._param_category, profile_key = self.host.profile)
self.host.removeWindow()

View file

@ -119,42 +119,47 @@ class QuickApp():
###now we get the essential params###
self.profiles[profile]['whoami']=JID(self.bridge.getParamA("JabberID","Connection", profile))
autoconnect = self.bridge.getParamA("autoconnect","Connection", profile) == "true"
self.profiles[profile]['watched']=self.bridge.getParamA("Watched", "Misc", profile).split() #TODO: put this in a plugin
## misc ##
self.profiles[profile]['onlineContact'] = set() #FIXME: temporary
#TODO: gof: managed multi-profiles here
if self.bridge.isConnected(profile):
self.setStatusOnline(True)
else:
#TODO: gof: manage multi-profiles here
if not self.bridge.isConnected(profile):
self.setStatusOnline(False)
return
else:
self.setStatusOnline(True)
### now we fill the contact list ###
for contact in self.bridge.getContacts(profile):
self.newContact(contact[0], contact[1], contact[2], profile)
### now we fill the contact list ###
for contact in self.bridge.getContacts(profile):
self.newContact(contact[0], contact[1], contact[2], profile)
presences = self.bridge.getPresenceStatus(profile)
for contact in presences:
for res in presences[contact]:
jabber_id = contact+('/'+res if res else '')
show = presences[contact][res][0]
priority = presences[contact][res][1]
statuses = presences[contact][res][2]
self.presenceUpdate(jabber_id, show, priority, statuses, profile)
presences = self.bridge.getPresenceStatus(profile)
for contact in presences:
for res in presences[contact]:
jabber_id = contact+('/'+res if res else '')
show = presences[contact][res][0]
priority = presences[contact][res][1]
statuses = presences[contact][res][2]
self.presenceUpdate(jabber_id, show, priority, statuses, profile)
#The waiting subscription requests
waitingSub = self.bridge.getWaitingSub(profile)
for sub in waitingSub:
self.subscribe(waitingSub[sub], sub, profile)
#The waiting subscription requests
waitingSub = self.bridge.getWaitingSub(profile)
for sub in waitingSub:
self.subscribe(waitingSub[sub], sub, profile)
#Now we open the MUC window where we already are:
for room_args in self.bridge.getRoomJoined(profile):
self.roomJoined(*room_args, profile=profile)
#Now we open the MUC window where we already are:
for room_args in self.bridge.getRoomJoined(profile):
self.roomJoined(*room_args, profile=profile)
for subject_args in self.bridge.getRoomSubjects(profile):
self.roomNewSubject(*subject_args, profile=profile)
for subject_args in self.bridge.getRoomSubjects(profile):
self.roomNewSubject(*subject_args, profile=profile)
if autoconnect and not self.bridge.isConnected(profile_key):
#Does the user want autoconnection ?
self.bridge.connect(profile_key)
def unplug_profile(self, profile):
"""Tell the application to not follow anymore the profile"""
@ -420,3 +425,11 @@ class QuickApp():
def actionResult(self, type, id, data):
raise NotImplementedError
def onExit(self):
"""Must be called when the frontend is terminating"""
#TODO: mange multi-profile here
autodisconnect = self.bridge.getParamA("autodisconnect","Connection", self.profile) == "true"
if autodisconnect and self.bridge.isConnected(self.profile):
#Does the user want autodisconnection ?
self.bridge.disconnect(self.profile)

View file

@ -188,9 +188,6 @@ class Chat(wx.Frame, QuickChat):
def onClose(self, event):
"""Close event: we only hide the frame."""
event.Veto()
self.Show() ## this is a workaround to a wxpython bug:
## with Raise on hidden frame, Hide doesn't work anymore
## TODO: check this and repport bug to wxpython devs
self.Hide()
def onEnterPressed(self, event):
@ -222,9 +219,10 @@ class Chat(wx.Frame, QuickChat):
self.chatWindow.AppendText("%s\n" % msg)
if not mymess:
#TODO: use notification system
self.RequestUserAttention() #FIXME: do this only if in background.
self.Show() #gof: FIXME: to check
#self.Raise() #FIXME: too intrusive
if not self.IsActive():
self.RequestUserAttention()
if not self.IsShown():
self.Show()
### events ###

View file

@ -119,7 +119,6 @@ class ContactList(wx.SimpleHtmlListBox, QuickContactList):
def add(self, contact, groups = None):
"""add a contact to the list"""
debug (_("adding %s"),contact)
#gof: groups = param_groups or self.CM.getAttr(jid, 'groups')
if not groups:
idx = self.Insert(self.__presentItem(contact), 0, contact)
else:

View file

@ -125,8 +125,6 @@ class MainWindow(wx.Frame, QuickApp):
for i in range(self.menuBar.GetMenuCount()):
self.menuBar.EnableTop(i, True)
super(MainWindow, self).plug_profile(profile_key)
if not self.bridge.isConnected(profile_key):
self.bridge.connect(profile_key)
def createMenus(self):
info(_("Creating menus"))
@ -464,7 +462,10 @@ class MainWindow(wx.Frame, QuickApp):
gatewayManager = GatewaysManager(self, data, server=target)
def onClose(self, e):
QuickApp.onExit(self)
info(_("Exiting..."))
for win in self.chat_wins:
self.chat_wins[win].Destroy()
e.Skip()
def onTrayClick(self, e):

View file

@ -61,30 +61,37 @@ class Param(wx.Frame):
for param in cat_dom.documentElement.getElementsByTagName("param"):
name = param.getAttribute("name")
label = param.getAttribute("label")
type = param.getAttribute("type")
value = param.getAttribute("value")
sizer = wx.BoxSizer(wx.HORIZONTAL)
if type=="string":
label=wx.StaticText(panel, -1, name+" ")
label=wx.StaticText(panel, -1, (label or name)+" ")
ctrl = wx.TextCtrl(panel, -1, value)
sizer.Add(label)
elif type=="password":
label=wx.StaticText(panel, -1, name+" ")
label=wx.StaticText(panel, -1, (label or name)+" ")
ctrl = wx.TextCtrl(panel, -1, value, style=wx.TE_PASSWORD)
sizer.Add(label)
elif type=="bool":
ctrl = wx.CheckBox(panel, -1, label or name, style = wx.CHK_2STATE)
ctrl.SetValue(value=="true")
elif type=="button":
ctrl = wx.Button(panel, -1, value)
ctrl.callback_id = param.getAttribute("callback_id")
else:
error(_("FIXME FIXME FIXME")) #FIXME !
raise NotImplementedError
ctrl.param_id=(name, category)
if name:
ctrl.param_id=(name, category)
self.ctl_list[(name, category)] = ctrl
sizer.Add(ctrl, 1, flag=wx.EXPAND)
self.ctl_list[(name, category)] = ctrl
panel.sizer.Add(sizer, flag=wx.EXPAND)
if type=="string" or type=="password":
panel.Bind(wx.EVT_TEXT, self.onTextChanged, ctrl)
elif type=="bool":
panel.Bind(wx.EVT_CHECKBOX, self.onCheckBoxClicked, ctrl)
elif type=="button":
panel.Bind(wx.EVT_BUTTON, self.onButtonClicked, ctrl)
@ -94,7 +101,7 @@ class Param(wx.Frame):
cat_dom.unlink()
def onTextChanged(self, event):
"""Called when a paramated is modified"""
"""Called when a string paramater is modified"""
self.modified[event.GetEventObject().param_id]=event.GetString()
### FIXME # Some hacks for better presentation, should be generic # FIXME ###
@ -105,8 +112,13 @@ class Param(wx.Frame):
event.Skip()
def onCheckBoxClicked(self, event):
"""Called when a bool paramater is modified"""
self.modified[event.GetEventObject().param_id]="true" if event.GetEventObject().GetValue() else "false"
event.Skip()
def onButtonClicked(self, event):
"""Called when a paramated is modified"""
"""Called when a button paramater is modified"""
self.__save_parameters()
name, category = event.GetEventObject().param_id
callback_id = event.GetEventObject().callback_id

View file

@ -88,6 +88,11 @@ class XMLUI(wx.Frame):
ctrl = wx.TextCtrl(parent, -1, value, style=wx.TE_MULTILINE)
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
_proportion = 1
elif type=="bool":
ctrl = wx.CheckBox(panel, -1, "", style = wx.CHK_2STATE)
ctrl.SetValue(value=="true")
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
_proportion = 1
elif type=="list":
style=wx.LB_MULTIPLE if elem.getAttribute("multi")=='yes' else wx.LB_SINGLE
ctrl = wx.ListBox(parent, -1, choices=[option.getAttribute("value") for option in elem.getElementsByTagName("option")], style=style)
@ -138,13 +143,14 @@ class XMLUI(wx.Frame):
parent.sizer.Add(current, _proportion, flag=wx.EXPAND)
elif node.nodeName == "category":
name = node.getAttribute('name')
label = node.getAttribute('label')
if not node.nodeName in wanted or not name or not isinstance(parent,wx.Notebook):
raise Exception("Invalid XMLUI") #TODO: make a custom exception
notebook = parent
tab_panel = wx.Panel(notebook, -1)
tab_panel.sizer = wx.BoxSizer(wx.VERTICAL)
tab_panel.SetSizer(tab_panel.sizer)
notebook.AddPage(tab_panel, name)
notebook.AddPage(tab_panel, label or name)
self.__parseChilds(tab_panel, None, node, ['layout'])
else:
@ -211,6 +217,8 @@ class XMLUI(wx.Frame):
ctrl = self.ctrl_list[ctrl_name]
if isinstance(ctrl['control'], wx.ListBox):
data.append((ctrl_name, ctrl['control'].GetStringSelection()))
elif isinstance(ctrl['control'], wx.CheckBox):
data.append((ctrl_name, "true" if ctrl['control'].GetValue() else "false"))
else:
data.append((ctrl_name, ctrl['control'].GetValue()))
if self.misc.has_key('action_back'): #FIXME FIXME FIXME: WTF ! Must be cleaned

View file

@ -96,8 +96,9 @@ class XEP_0045():
def __err_joining_room(self, failure, profile):
"""Called when something is going wrong when joining the room"""
error ("Error when joining the room")
#TODO: gof: send an error message throught the bridge
mess = _("Error when joining the room")
error (mess)
self.host.bridge.newAlert(mess, _("Group chat error"), "ERROR", profile)
def getRoomJoined(self, profile_key='@DEFAULT@'):
"""Return room where user is"""

View file

@ -40,24 +40,31 @@ class Param():
"""This class manage parameters with xml"""
### TODO: add desciption in params
#TODO: mettre Watched dans un plugin
#TODO: move Watched in a plugin
default_xml = u"""
<params>
<general>
</general>
<individual>
<category name='"""+_("Connection")+"""'>
<category name="Connection" label="%(category_connection)s">
<param name="JabberID" value="goffi@necton2.int/TestScript" type="string" />
<param name="Password" value="toto" type="password" />
<param name="Server" value="necton2.int" type="string" />
<param name="NewAccount" value='"""+_("Register new account")+"""' type="button" callback_id="registerNewAccount"/>
<param name="NewAccount" value="%(label_NewAccount)s" type="button" callback_id="registerNewAccount"/>
<param name="autoconnect" label="%(label_autoconnect)s" value="true" type="bool" />
<param name="autodisconnect" label="%(label_autodisconnect)s" value="false" type="bool" />
</category>
<category name='"""+_("Misc")+"""'>
<category name="Misc" label="%(category_misc)s">
<param name="Watched" value="test@Jabber.goffi.int" type="string" />
</category>
</individual>
</params>
"""
""" % {'category_connection': _("Connection"),
'label_NewAccount': _("Register new account"),
'label_autoconnect': _('Connect on frontend startup'),
'label_autodisconnect': _('Disconnect on frontend closure'),
'category_misc': _("Misc")
}
def load_default_params(self):
self.dom = minidom.parseString(Param.default_xml.encode('utf-8'))

View file

@ -81,12 +81,14 @@ def paramsXml2xmlUI(xml):
param_ui = XMLUI("param", "tabs")
for category in top.getElementsByTagName("category"):
name = category.getAttribute('name')
label = category.getAttribute('label')
if not name:
error(_('INTERNAL ERROR: params categories must have a name'))
assert(False)
param_ui.addCategory(name, 'pairs')
param_ui.addCategory(name, 'pairs', label=label)
for param in category.getElementsByTagName("param"):
name = param.getAttribute('name')
label = param.getAttribute('label')
if not name:
error(_('INTERNAL ERROR: params must have a name'))
assert(False)
@ -96,7 +98,7 @@ def paramsXml2xmlUI(xml):
if type == "button":
param_ui.addEmpty()
else:
param_ui.addLabel(name)
param_ui.addLabel(label or name)
param_ui.addElement(name=name, type=type, value=value, callback_id=callback_id)
return param_ui.toXml()
@ -209,6 +211,12 @@ class XMLUI:
if value:
elem.setAttribute('value', value)
def addBool(self, name=None, value="true"):
"""Add a string box"""
assert value in ["true","false"]
elem = self.__createElem('bool', name, self.currentLayout)
elem.setAttribute('value', value)
def addList(self, options, name=None, value=None, style=set()):
"""Add a list of choices"""
styles = set(style)
@ -253,6 +261,10 @@ class XMLUI:
self.addPassword(name, value)
elif type == 'textbox':
self.addTextBox(name, value)
elif type == 'bool':
if not value:
value = "true"
self.addBool(name, value)
elif type == 'list':
self.addList(options, name, value)
elif type == 'button':
@ -267,7 +279,7 @@ class XMLUI:
opt.setAttribute('value', option)
parent.appendChild(opt)
def addCategory(self, name, layout):
def addCategory(self, name, layout, label=None):
"""Add a category to current layout (must be a tabs layout)"""
assert(layout != 'tabs')
if not self.parentTabsLayout:
@ -276,8 +288,12 @@ class XMLUI:
if self.parentTabsLayout.getAttribute('type') != 'tabs':
error(_("parent layout of a category is not tabs"))
assert(False)
if not label:
label = name
self.currentCategory = cat = self.doc.createElement('category')
cat.setAttribute('name', name)
cat.setAttribute('label', label)
self.changeLayout(layout)
self.parentTabsLayout.appendChild(cat)