changeset 183:9ee4a1d0d7fb

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
author Goffi <goffi@goffi.org>
date Wed, 18 Aug 2010 15:57:26 +0800
parents 556c2bd7c344
children 8ea1510d474b
files frontends/primitivus/primitivus frontends/primitivus/xmlui.py frontends/quick_frontend/quick_app.py frontends/wix/chat.py frontends/wix/contact_list.py frontends/wix/main_window.py frontends/wix/param.py frontends/wix/xmlui.py plugins/plugin_xep_0045.py tools/memory.py tools/xml_tools.py
diffstat 11 files changed, 121 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/primitivus/primitivus	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/primitivus/primitivus	Wed Aug 18 15:57:26 2010 +0800
@@ -436,6 +436,7 @@
         self.addWindow(params)
 
     def onExitRequest(self, menu):
+        QuickApp.onExit(self)
         raise urwid.ExitMainLoop()
 
     def onJoinRoomRequest(self, menu):
--- a/frontends/primitivus/xmlui.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/primitivus/xmlui.py	Wed Aug 18 15:57:26 2010 +0800
@@ -90,6 +90,9 @@
             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 @@
                 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 @@
                     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 @@
         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 @@
             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 @@
 
     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()
--- a/frontends/quick_frontend/quick_app.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/quick_frontend/quick_app.py	Wed Aug 18 15:57:26 2010 +0800
@@ -119,42 +119,47 @@
         
         ###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 @@
     
     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)
--- a/frontends/wix/chat.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/wix/chat.py	Wed Aug 18 15:57:26 2010 +0800
@@ -188,9 +188,6 @@
     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 @@
         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 ###
 
--- a/frontends/wix/contact_list.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/wix/contact_list.py	Wed Aug 18 15:57:26 2010 +0800
@@ -119,7 +119,6 @@
     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:
--- a/frontends/wix/main_window.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/wix/main_window.py	Wed Aug 18 15:57:26 2010 +0800
@@ -125,8 +125,6 @@
         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 @@
         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):
--- a/frontends/wix/param.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/wix/param.py	Wed Aug 18 15:57:26 2010 +0800
@@ -61,30 +61,37 @@
         
         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 @@
         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 @@
 
         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
--- a/frontends/wix/xmlui.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/frontends/wix/xmlui.py	Wed Aug 18 15:57:26 2010 +0800
@@ -88,6 +88,11 @@
                 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 @@
                     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 @@
             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
--- a/plugins/plugin_xep_0045.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/plugins/plugin_xep_0045.py	Wed Aug 18 15:57:26 2010 +0800
@@ -96,8 +96,9 @@
 
     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"""
--- a/tools/memory.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/tools/memory.py	Wed Aug 18 15:57:26 2010 +0800
@@ -40,24 +40,31 @@
     """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'))
--- a/tools/xml_tools.py	Wed Aug 18 12:45:48 2010 +0800
+++ b/tools/xml_tools.py	Wed Aug 18 15:57:26 2010 +0800
@@ -81,12 +81,14 @@
     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 @@
             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 @@
         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 @@
             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 @@
             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 @@
         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)