changeset 1289:653f2e2eea31 frontends_multi_profiles

Wix removal: Wix is now officially abandonned (a futur desktop frontend will replace it)
author Goffi <goffi@goffi.org>
date Sat, 24 Jan 2015 00:15:01 +0100
parents 7cf32aeeebdb
children faa1129559b8
files frontends/src/wix/__init__.py frontends/src/wix/card_game.py frontends/src/wix/chat.py frontends/src/wix/constants.py frontends/src/wix/contact_list.py frontends/src/wix/main_window.py frontends/src/wix/profile.py frontends/src/wix/profile_manager.py frontends/src/wix/quiz_game.py frontends/src/wix/wix frontends/src/wix/xmlui.py
diffstat 10 files changed, 0 insertions(+), 2327 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/wix/card_game.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-from sat.core.i18n import _
-import wx
-import os.path, glob
-from sat.core.log import getLogger
-log = getLogger(__name__)
-from sat_frontends.tools.games import TarotCard
-from sat_frontends.quick_frontend.quick_card_game import QuickCardGame
-from sat_frontends.wix import xmlui
-
-CARD_WIDTH = 74
-CARD_HEIGHT = 136
-MIN_WIDTH = 950 #Minimum size of the panel
-MIN_HEIGHT = 500
-
-
-class WxCard(TarotCard):
-    """This class is used to represent a card, graphically and logically"""
-
-    def __init__(self, file):
-        """@param file: path of the PNG file"""
-        self.bitmap = wx.Image(file).ConvertToBitmap()
-        root_name = os.path.splitext(os.path.basename(file))[0]
-        suit,value = root_name.split('_')
-        TarotCard.__init__(self, (suit, value))
-        log.debug("Card: %s %s" % (suit, value)) #, self.bout
-
-    def draw(self, dc, x, y):
-        """Draw the card on the device context
-        @param dc: device context
-        @param x: abscissa
-        @param y: ordinate"""
-        dc.DrawBitmap(self.bitmap, x, y, True)
-
-
-class CardPanel(QuickCardGame, wx.Panel):
-    """This class is used to display the cards"""
-
-    def __init__(self, parent, referee, players, player_nick):
-        QuickCardGame.__init__(self, parent, referee, players, player_nick)
-        wx.Panel.__init__(self, parent)
-        self.SetMinSize(wx.Size(MIN_WIDTH, MIN_HEIGHT))
-        self.loadCards(os.path.join(self.parent.host.media_dir, 'games/cards/tarot'))
-        self.mouse_over_card = None #contain the card to highlight
-        self.visible_size = CARD_WIDTH/2 #number of pixels visible for cards
-        self.hand = []
-        self.to_show = []
-        self.state = None
-        self.SetBackgroundColour(wx.GREEN)
-        self.Bind(wx.EVT_SIZE, self.onResize)
-        self.Bind(wx.EVT_PAINT, self.onPaint)
-        self.Bind(wx.EVT_MOTION, self.onMouseMove)
-        self.Bind(wx.EVT_LEFT_UP, self.onMouseClick)
-
-        self.parent.host.bridge.tarotGameReady(player_nick, referee, self.parent.host.profile)
-
-    def loadCards(self, dir):
-        """Load all the cards in memory
-        @param dir: directory where the PNG files are"""
-        QuickCardGame.loadCards(self)
-        for file in glob.glob(dir+'/*_*.png'):
-            card = WxCard(file)
-            self.cards[card.suit, card.value]=card
-            self.deck.append(card)
-
-    def newGame(self, hand):
-        """Start a new game, with given hand"""
-        if hand is []:  # reset the display after the scores have been showed
-            self.resetRound()
-            self.Refresh()
-            self.parent.host.bridge.tarotGameReady(self.player_nick, self.referee, self.parent.host.profile)
-            return
-        QuickCardGame.newGame(self, hand)
-        self._recalc_ori()
-        self.Refresh()
-
-    def contratSelected(self, data):
-        """Called when the contrat has been choosed
-        @param data: form result"""
-        log.debug (_("Contrat choosed"))
-        contrat = data[0][1]
-        QuickCardGame.contratSelected(self, contrat)
-
-    def chooseContrat(self, xml_data):
-        """Called when the player has to select his contrat
-        @param xml_data: SàT xml representation of the form"""
-        xmlui.create(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL'])
-
-    def showScores(self, xml_data, winners, loosers):
-        """Called when the round is over, display the scores
-        @param xml_data: SàT xml representation of the form"""
-        if not winners and not loosers:
-            title = _("Draw game")
-        else:
-            title = _('You win \o/') if self.player_nick in winners else _('You loose :(')
-        xmlui.create(self.parent.host, xml_data, title=title, flags=['NO_CANCEL'])
-
-    def cardsPlayed(self, player, cards):
-        """A card has been played by player"""
-        QuickCardGame.cardsPlayed(self, player, cards)
-        self.Refresh()
-
-    def invalidCards(self, phase, played_cards, invalid_cards):
-        """Invalid cards have been played
-        @param phase: phase of the game
-        @param played_cards: all the cards played
-        @param invalid_cards: cards which are invalid"""
-        QuickCardGame.invalidCards(self, phase, played_cards, invalid_cards)
-
-        self._recalc_ori()
-        self.Refresh()
-        if self._autoplay==None: #No dialog if there is autoplay
-            wx.MessageDialog(self, _("Cards played are invalid !"), _("Error"), wx.OK | wx.ICON_ERROR).ShowModal()
-
-    def _is_on_hand(self, pos_x, pos_y):
-        """Return True if the coordinate are on the hand cards"""
-        if pos_x > self.orig_x and pos_y > self.orig_y \
-           and pos_x < self.orig_x + (len(self.hand)+1) * self.visible_size \
-           and pos_y < self.end_y:
-           return True
-        return False
-
-    def onResize(self, event):
-        self._recalc_ori()
-
-    def _recalc_ori(self):
-        """Recalculate origins of hand, must be call when hand size change"""
-        self.orig_x = (self.GetSizeTuple()[0]-(len(self.hand)+1)*self.visible_size)/2 #where we start to draw cards
-        self.orig_y = self.GetSizeTuple()[1] - CARD_HEIGHT - 20
-        self.end_y = self.orig_y + CARD_HEIGHT
-
-    def onPaint(self, event):
-        dc = wx.PaintDC(self)
-
-        #We print the names to know who play where TODO: print avatars when available
-        max_x, max_y = self.GetSize()
-        border = 10 #border between nick and end of panel
-        right_y = left_y = 200
-        right_width, right_height = dc.GetTextExtent(self.right_nick)
-        right_x = max_x - right_width - border
-        left_x = border
-        top_width, top_height = dc.GetTextExtent(self.top_nick)
-        top_x = (max_x - top_width) / 2
-        top_y = border
-        dc.DrawText(self.right_nick, right_x, right_y)
-        dc.DrawText(self.top_nick, top_x, top_y)
-        dc.DrawText(self.left_nick, left_x, left_y)
-
-        #We draw the played cards:
-        center_y = 200 #ordinate used as center point
-        left_x = (max_x - CARD_WIDTH)/2 - CARD_WIDTH - 5
-        right_x = (max_x/2) + (CARD_WIDTH/2) + 5
-        left_y = right_y = center_y - CARD_HEIGHT/2
-        top_x = bottom_x = (max_x - CARD_WIDTH)/2
-        top_y = center_y - CARD_HEIGHT - 5
-        bottom_y = center_y + 5
-        for side in ['left', 'top', 'right', 'bottom']:
-            card = self.played[getattr(self, side+'_nick')]
-            if card != None:
-                card.draw(dc,locals()[side+'_x'], locals()[side+'_y'])
-
-        x=self.orig_x
-        for card in self.hand:
-            if (self.state == "play" or self.state == "ecart") and card == self.mouse_over_card \
-                or self.state == "ecart" and card in self.selected:
-                y = self.orig_y - 30
-            else:
-                y = self.orig_y
-
-            card.draw(dc,x,y)
-            x+=self.visible_size
-
-        if self.to_show:
-            """There are cards to display in the middle"""
-            size = len(self.to_show)*(CARD_WIDTH+10)-10
-            x = (max_x - size)/2
-            for card in self.to_show:
-                card.draw(dc, x, 150)
-                x+=CARD_WIDTH+10
-
-    def onMouseMove(self, event):
-        pos_x,pos_y = event.GetPosition()
-        if self._is_on_hand(pos_x, pos_y):
-           try:
-               self.mouse_over_card = self.hand[(pos_x-self.orig_x)/self.visible_size]
-           except IndexError:
-               self.mouse_over_card = self.hand[-1]
-           self.Refresh()
-        else:
-            self.mouse_over_card = None
-            self.Refresh()
-
-    def onMouseClick(self, event):
-        log.debug("mouse click: %s" % event.GetPosition())
-        pos_x,pos_y = event.GetPosition()
-
-        if self.state == "chien":
-            self.to_show = []
-            self.state = "wait"
-            return
-        elif self.state == "wait_for_ecart":
-            self.state = "ecart"
-            self.hand.extend(self.to_show)
-            self.hand.sort()
-            self.to_show = []
-            self._recalc_ori()
-            self.Refresh()
-            return
-
-        if self._is_on_hand(pos_x, pos_y):
-           idx = (pos_x-self.orig_x)/self.visible_size
-           if idx == len(self.hand):
-               idx-=1
-           if self.hand[idx] == self.mouse_over_card:
-               if self.state == "ecart":
-                   if self.hand[idx] in self.selected:
-                       self.selected.remove(self.hand[idx])
-                   else:
-                       self.selected.append(self.hand[idx])
-                       if len(self.selected) == 6: #TODO: use variable here, as chien len can change with variants
-                           dlg = wx.MessageDialog(self, _("Do you put these cards in chien ?"), _(u"Écart"), wx.YES_NO | wx.ICON_QUESTION)
-                           answer = dlg.ShowModal()
-                           if answer == wx.ID_YES:
-                               ecart = []
-                               for card in self.selected:
-                                   ecart.append((card.suit, card.value))
-                                   self.hand.remove(card)
-                               del self.selected[:]
-                               self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, ecart, self.parent.host.profile)
-                               self.state = "wait"
-
-                   self._recalc_ori()
-                   self.Refresh()
-               if self.state == "play":
-                   card = self.hand[idx]
-                   self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], self.parent.host.profile)
-                   del self.hand[idx]
-                   self.state = "wait"
-                   self._recalc_ori()
-                   self.Refresh()
-
-
--- a/frontends/src/wix/chat.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-from sat.core.i18n import _
-from sat_frontends.wix.constants import Const as C
-import wx
-import os.path
-import time
-from sat.core.log import getLogger
-log = getLogger(__name__)
-from sat_frontends.tools.jid  import JID
-from sat_frontends.quick_frontend.quick_chat import QuickChat
-from sat_frontends.wix.contact_list import ContactList
-from sat_frontends.wix.card_game import CardPanel
-from sat_frontends.wix.quiz_game import QuizPanel
-
-idSEND           = 1
-idTAROT          = 2
-
-
-class Chat(wx.Frame, QuickChat):
-    """The chat Window for one to one conversations"""
-
-    def __init__(self, target, host, type_='one2one'):
-        wx.Frame.__init__(self, None, title=target, pos=(0,0), size=(400,200))
-        QuickChat.__init__(self, target, host, type_)
-
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self.sizer)
-
-        self.splitter = wx.SplitterWindow(self, -1)
-        self.sizer.Add(self.splitter, 1, flag = wx.EXPAND)
-
-        self.conv_panel = wx.Panel(self.splitter)
-        self.conv_panel.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.subjectBox = wx.TextCtrl(self.conv_panel, -1, style = wx.TE_READONLY)
-        self.chatWindow = wx.TextCtrl(self.conv_panel, -1, style = wx.TE_MULTILINE | wx.TE_RICH | wx.TE_READONLY)
-        self.textBox = wx.TextCtrl(self.conv_panel, -1, style = wx.TE_PROCESS_ENTER)
-        self.conv_panel.sizer.Add(self.subjectBox, flag=wx.EXPAND)
-        self.conv_panel.sizer.Add(self.chatWindow, 1, flag=wx.EXPAND)
-        self.conv_panel.sizer.Add(self.textBox, 0, flag=wx.EXPAND)
-        self.conv_panel.SetSizer(self.conv_panel.sizer)
-        self.splitter.Initialize(self.conv_panel)
-        self.SetMenuBar(wx.MenuBar())
-
-        #events
-        self.Bind(wx.EVT_CLOSE, self.onClose, self)
-        self.Bind(wx.EVT_TEXT_ENTER, self.onEnterPressed, self.textBox)
-
-        #fonts
-        self.font={}
-        self.font["points"] = self.chatWindow.GetFont().GetPointSize()
-        self.font["family"] = self.chatWindow.GetFont().GetFamily()
-
-
-        #misc
-        self.day_change = time.strptime(time.strftime("%a %b %d 00:00:00  %Y")) #struct_time of day changing time
-        self.setType(self.type)
-        self.textBox.SetFocus()
-        self.Hide() #We hide because of the show toggle
-
-    def __createPresents(self):
-        """Create a list of present people in a group chat"""
-        self.present_panel = wx.Panel(self.splitter)
-        self.present_panel.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.present_panel.presents = ContactList(self.present_panel, self.host, type_='nicks')
-        self.present_panel.presents.SetMinSize(wx.Size(80,20))
-        self.present_panel.sizer.Add(self.present_panel.presents, 1, wx.EXPAND)
-        self.present_panel.SetSizer(self.present_panel.sizer)
-        self.splitter.SplitVertically(self.present_panel, self.conv_panel, 80)
-
-    def setType(self, type_):
-        QuickChat.setType(self, type_)
-        if type_ is 'group' and not self.splitter.IsSplit():
-            self.__createPresents()
-            self.subjectBox.Show()
-            self.__eraseMenus()
-            self.__createMenus_group()
-            self.sizer.Layout()
-        elif type_ is 'one2one' and self.splitter.IsSplit():
-            self.splitter.Unsplit(self.present_panel)
-            del self.present_panel
-            self.GetMenuBar().Show()
-            self.subjectBox.Hide()
-            self.__eraseMenus()
-            self.__createMenus_O2O()
-            self.nick = None
-        else:
-            self.subjectBox.Hide()
-            self.__eraseMenus()
-            self.__createMenus_O2O()
-            self.historyPrint(profile=self.host.profile)
-
-    def startGame(self, game_type, referee, players):
-        """Configure the chat window to start a game"""
-        if game_type=="Tarot":
-            log.debug (_("configure chat window for Tarot game"))
-            self.tarot_panel = CardPanel(self, referee, players, self.nick)
-            self.sizer.Prepend(self.tarot_panel, 0, flag=wx.EXPAND)
-            self.sizer.Layout()
-            self.Fit()
-            self.splitter.UpdateSize()
-        elif game_type=="Quiz":
-            log.debug (_("configure chat window for Quiz game"))
-            self.quiz_panel = QuizPanel(self, referee, players, self.nick)
-            self.sizer.Prepend(self.quiz_panel, 0, flag=wx.EXPAND)
-            self.sizer.Layout()
-            self.Fit()
-            self.splitter.UpdateSize()
-
-    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_panel
-        elif game_type=="Quiz":
-            return self.quiz_panel
-
-    def setPresents(self, nicks):
-        """Set the users presents in the contact list for a group chat
-        @param nicks: list of nicknames
-        """
-        QuickChat.setPresents(self, nicks)
-        for nick in nicks:
-            self.present_panel.presents.replace(nick)
-
-    def replaceUser(self, nick, show_info=True):
-        """Add user if it is not in the group list"""
-        log.debug (_("Replacing user %s") % nick)
-        if self.type != "group":
-            log.error (_("[INTERNAL] trying to replace user for a non group chat window"))
-            return
-        QuickChat.replaceUser(self, nick, show_info)
-        self.present_panel.presents.replace(nick)
-
-    def removeUser(self, nick, show_info=True):
-        """Remove a user from the group list"""
-        QuickChat.removeUser(self, nick, show_info)
-        self.present_panel.presents.remove(nick)
-
-    def setSubject(self, subject):
-        """Set title for a group chat"""
-        QuickChat.setSubject(self, subject)
-        self.subjectBox.SetValue(subject)
-
-    def __eraseMenus(self):
-        """erase all menus"""
-        menuBar = self.GetMenuBar()
-        for i in range(menuBar.GetMenuCount()):
-            menuBar.Remove(i)
-
-    def __createMenus_O2O(self):
-        """create menu bar for one 2 one chat"""
-        log.info("Creating menus")
-        self.__eraseMenus()
-        menuBar = self.GetMenuBar()
-        actionMenu = wx.Menu()
-        actionMenu.Append(idSEND, _("&SendFile	CTRL-s"),_(" Send a file to contact"))
-        menuBar.Append(actionMenu,_("&Action"))
-        self.host.addMenus(menuBar, C.MENU_SINGLE, {'jid': self.target})
-
-        #events
-        wx.EVT_MENU(self, idSEND, self.onSendFile)
-
-    def __createMenus_group(self):
-        """create menu bar for group chat"""
-        log.info("Creating menus")
-        self.__eraseMenus()
-        menuBar = self.GetMenuBar()
-        actionMenu = wx.Menu()
-        actionMenu.Append(idTAROT, _("Start &Tarot game	CTRL-t"),_(" Start a Tarot card game")) #tmp
-        menuBar.Append(actionMenu,_("&Games"))
-        self.host.addMenus(menuBar, C.MENU_ROOM, {'room_jid': self.target.bare})
-
-        #events
-        wx.EVT_MENU(self, idTAROT, self.onStartTarot)
-
-    def __del__(self):
-        wx.Frame.__del__(self)
-
-    def onClose(self, event):
-        """Close event: we only hide the frame."""
-        event.Veto()
-        self.Hide()
-
-    def onEnterPressed(self, event):
-        """Behaviour when enter pressed in send line."""
-        self.host.sendMessage(self.target.bare if self.type == 'group' else self.target,
-                              event.GetString(),
-                              mess_type="groupchat" if self.type == 'group' else "chat",
-                              profile_key=self.host.profile)
-        self.textBox.Clear()
-
-    def __blink(self):
-        """Do wizzz and buzzz to show window to user or
-        at least inform him of something new"""
-        #TODO: use notification system
-        if not self.IsActive():
-            self.RequestUserAttention()
-        if not self.IsShown():
-            self.Show()
-
-    def printMessage(self, from_jid, msg, profile, timestamp=None):
-        """Print the message with differents colors depending on where it comes from."""
-        try:
-            jid,nick,mymess = QuickChat.printMessage(self, from_jid, msg, profile, timestamp)
-        except TypeError:
-            return
-        log.debug("printMessage, jid = %s type = %s" % (jid, self.type))
-        _font_bold = wx.Font(self.font["points"], self.font["family"], wx.NORMAL, wx.BOLD)
-        _font_normal = wx.Font(self.font["points"], self.font["family"], wx.NORMAL, wx.NORMAL)
-        _font_italic = wx.Font(self.font["points"], self.font["family"], wx.ITALIC if mymess else wx.NORMAL, wx.NORMAL)
-        self.chatWindow.SetDefaultStyle(wx.TextAttr("GREY", font=_font_normal))
-        msg_time = time.localtime(timestamp or None)
-        time_format = "%c" if msg_time < self.day_change else "%H:%M" #if the message was sent before today, we print the full date
-        self.chatWindow.AppendText("[%s]" % time.strftime(time_format, msg_time ))
-        self.chatWindow.SetDefaultStyle(wx.TextAttr( "BLACK" if mymess else "BLUE", font=_font_bold))
-        self.chatWindow.AppendText("[%s] " % nick)
-        self.chatWindow.SetDefaultStyle(wx.TextAttr("BLACK", font=_font_italic))
-        self.chatWindow.AppendText("%s\n" % msg)
-        if not mymess:
-            self.__blink()
-
-    def printInfo(self, msg, type_='normal', timestamp=None):
-        """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"
-        @param timestamp (float): number of seconds since epoch
-        """
-        _font_bold = wx.Font(self.font["points"], self.font["family"], wx.NORMAL, wx.BOLD)
-        _font_normal = wx.Font(self.font["points"], self.font["family"], wx.NORMAL, wx.NORMAL)
-        self.chatWindow.SetDefaultStyle(wx.TextAttr("BLACK", font=_font_bold if type_ == 'normal' else _font_normal))
-        self.chatWindow.AppendText("%s\n" % msg)
-        if type_=="me":
-            self.__blink()
-
-    ### events ###
-
-    def onSendFile(self, e):
-        log.debug(_("Send File"))
-        filename = wx.FileSelector(_("Choose a file to send"), flags = wx.FD_FILE_MUST_EXIST)
-        if filename:
-            log.debug(_("filename: %s"),filename)
-            #FIXME: check last_resource: what if self.target.resource exists ?
-            last_resource = self.host.bridge.getLastResource(unicode(self.target.bare), self.host.profile)
-            if last_resource:
-                full_jid = JID("%s/%s" % (self.target.bare, last_resource))
-            else:
-                full_jid = self.target
-            id = self.host.bridge.sendFile(full_jid, filename, {}, self.host.profile)
-            self.host.waitProgress(id, _("File Transfer"), _("Copying %s") % os.path.basename(filename), self.host.profile)
-
-    def onStartTarot(self, e):
-        log.debug(_("Starting Tarot game"))
-        log.warning(_("FIXME: temporary menu, must be changed"))
-        if len(self.occupants) != 4:
-            err_dlg = wx.MessageDialog(self, _("You need to be exactly 4 peoples in the room to start a Tarot game"), _("Can't start game"), style = wx.OK | wx.ICON_ERROR) #FIXME: gof: temporary only, need to choose the people with who the game has to be started
-            err_dlg.ShowModal()
-        else:
-            self.host.bridge.tarotGameCreate(self.id, list(self.occupants), self.host.profile)
-
-    def updateChatState(self, state, nick=None):
-        """Set the chat state (XEP-0085) of the contact. Leave nick to None
-        to set the state for a one2one conversation, or give a nickname or
-        Const.ALL_OCCUPANTS to set the state of a participant within a MUC.
-        @param state: the new chat state
-        @param nick: None for one2one, the MUC user nick or Const.ALL_OCCUPANTS
-        """
-        #TODO: chat states not implemented yet
-        pass
--- a/frontends/src/wix/constants.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Primitivus: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from sat.core.i18n import _
-import os.path
-import sat_frontends.wix
-from sat_frontends.quick_frontend import constants
-
-
-wix_root = os.path.dirname(sat_frontends.wix.__file__)
-
-
-class Const(constants.Const):
-
-    APP_NAME = "Wix"
-    LICENCE_PATH = os.path.join(wix_root, "COPYING")
-    msgOFFLINE = _("offline")
-    msgONLINE = _("online")
-    DEFAULT_GROUP = "Unclassed"
-    PRESENCE = [("", _("Online"), None),
-                ("chat", _("Free for chat"), "green"),
-                ("away", _("AFK"), "brown"),
-                ("dnd", _("DND"), "red"),
-                ("xa", _("Away"), "red")
-                ]
-    LOG_OPT_SECTION = APP_NAME.lower()
--- a/frontends/src/wix/contact_list.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,251 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from sat.core.i18n import _
-import wx
-from sat_frontends.quick_frontend.quick_contact_list import QuickContactList
-from sat_frontends.wix.constants import Const
-from sat.core.log import getLogger
-log = getLogger(__name__)
-from cgi import escape
-from sat_frontends.tools.jid  import JID
-from os.path import join
-
-
-class Group(unicode):
-    """Class used to recognize groups"""
-
-class Contact(unicode):
-    """Class used to recognize groups"""
-
-class ContactList(wx.SimpleHtmlListBox, QuickContactList):
-    """Customized control to manage contacts."""
-
-    def __init__(self, parent, host, type_="JID"):
-        """init the contact list
-        @param parent: WxWidgets parent of the widget
-        @param host: wix main app class
-        @param type_: type of contact list: "JID" for the usual big jid contact list
-                                           "CUSTOM" for a customized contact list (self._presentItem must then be overrided)
-        """
-        wx.SimpleHtmlListBox.__init__(self, parent, -1)
-        QuickContactList.__init__(self)
-        self.host = host
-        self.type = type_
-        self.__typeSwitch()
-        self.groups = {}  #list contacts in each groups, key = group
-        self.empty_avatar = join(host.media_dir, 'misc/empty_avatar')
-        self.Bind(wx.EVT_LISTBOX, self.onSelected)
-        self.Bind(wx.EVT_LISTBOX_DCLICK, self.onActivated)
-
-    def __contains__(self, jid):
-        return bool(self.__find_idx(jid))
-
-    def __typeSwitch(self):
-        if self.type == "JID":
-            self._presentItem = self._presentItemJID
-        elif self.type != "CUSTOM":
-            self._presentItem = self._presentItemDefault
-
-    def __find_idx(self, entity):
-        """Find indexes of given contact (or groups) in contact list, manage jid
-        @return: list of indexes"""
-        result=[]
-        for i in range(self.GetCount()):
-            if (type(entity) == JID and type(self.GetClientData(i)) == JID and self.GetClientData(i).bare == entity.bare) or\
-                self.GetClientData(i) == entity:
-                result.append(i)
-        return result
-
-    def update_jid(self, jid):
-        self.replace(jid)
-
-    def replace(self, contact, groups=None, attributes=None):
-        """Add a contact to the list if doesn't exist, else update it.
-
-        This method can be called with groups=None for the purpose of updating
-        the contact's attributes (e.g. nickname). In that case, the groups
-        attribute must not be set to the default group but ignored. If not,
-        you may move your contact from its actual group(s) to the default one.
-
-        None value for 'groups' has a different meaning than [None] which is for the default group.
-
-        @param jid (JID)
-        @param groups (list): list of groups or None to ignore the groups membership.
-        @param attributes (dict)
-        """
-        log.debug(_("update %s") % contact)
-        if not self.__find_idx(contact):
-            self.add(contact, groups)
-        else:
-            for i in self.__find_idx(contact):
-                _present = self._presentItem(contact)
-                if _present != None:
-                    self.SetString(i, _present)
-
-    def __eraseGroup(self, group):
-        """Erase all contacts in group
-        @param group: group to erase
-        @return: True if something as been erased"""
-        erased = False
-        indexes = self.__find_idx(group)
-        for idx in indexes:
-            while idx<self.GetCount()-1 and type(self.GetClientData(idx+1)) != Group:
-                erased = True
-                self.Delete(idx+1)
-        return erased
-
-
-    def _presentGroup(self, group):
-        """Make a nice presentation for the contact groups"""
-        html = u"""-- [%s] --""" % group
-
-        return html
-
-    def _presentItemDefault(self, contact):
-        """Make a basic presentation of string contacts in the list."""
-        return contact
-
-    def _presentItemJID(self, jid):
-        """Make a nice presentation of the contact in the list for JID contacts."""
-        name = self.getCache(jid,'name')
-        nick = self.getCache(jid,'nick')
-        _show = self.getCache(jid,'show')
-        if _show == None or _show == 'unavailable':
-            return None
-        show = [x for x in Const.PRESENCE if x[0] == _show][0]
-
-        #show[0]==shortcut
-        #show[1]==human readable
-        #show[2]==color (or None)
-        show_html = "<font color='%s'>[%s]</font>" % (show[2], show[1]) if show[2] else ""
-        status = self.getCache(jid,'status') or ''
-        avatar = self.getCache(jid,'avatar') or self.empty_avatar #XXX: there is a weird bug here: if the image has an extension (i.e. empty_avatar.png),
-        #WxPython segfault, and it doesn't without nothing. I couldn't reproduce the case with a basic test script, so it need further investigation before reporting it
-        #to WxPython dev. Anyway, the program crash with a segfault, not a python exception, so there is definitely something wrong with WxPython.
-        #The case seems to happen when SimpleHtmlListBox parse the HTML with the <img> tag
-
-        html = """
-        <table border='0'>
-        <td>
-            <img  height='64' width='64' src='%s' />
-        </td>
-        <td>
-            <b>%s</b> %s<br />
-            <i>%s</i>
-        </td>
-        </table>
-        """ % (avatar,
-               escape(nick or name or jid.node or jid.bare),
-               show_html,
-               escape(status))
-
-        return html
-
-    def clearContacts(self):
-        """Clear all the contact list"""
-        self.Clear()
-
-    def add(self, contact, groups = None):
-        """add a contact to the list"""
-        log.debug (_("adding %s"),contact)
-        if not groups:
-            _present =  self._presentItem(contact)
-            if _present:
-                idx = self.Insert(_present, 0, contact)
-        else:
-            for group in groups:
-                indexes = self.__find_idx(group)
-                gp_idx = 0
-                if not indexes:  #this is a new group, we have to create it
-                    gp_idx = self.Append(self._presentGroup(group), Group(group))
-                else:
-                    gp_idx = indexes[0]
-
-                _present = self._presentItem(contact)
-                if _present:
-                    self.Insert(_present, gp_idx+1, contact)
-
-    def setSpecial(self, special_jid, special_type, show=False):
-        """Set entity as a special
-        @param jid: jid of the entity
-        @param _type: special type (e.g.: "MUC")
-        @param show: True to display the dialog to chat with this entity
-        """
-        QuickContactList.setSpecial(self, special_jid, special_type, show)
-        if show:
-            self._showDialog(special_jid)
-
-    def _showDialog(self, jid):
-        """Show the dialog associated to the given jid."""
-        indexes = self.__find_idx(jid)
-        if not indexes:
-            return
-        self.DeselectAll()
-        self.SetSelection(indexes[0])
-        self.onActivated(wx.MouseEvent())
-
-    def remove(self, contact):
-        """remove a contact from the list"""
-        log.debug (_("removing %s"), contact)
-        list_idx = self.__find_idx(contact)
-        list_idx.reverse()  #as we make some deletions, we have to reverse the order
-        for i in list_idx:
-            self.Delete(i)
-
-    def onSelected(self, event):
-        """Called when a contact is selected."""
-        data = self.getSelection()
-        if data == None: #we have a group
-            first_visible = self.GetVisibleBegin()
-            group = self.GetClientData(self.GetSelection())
-            erased = self.__eraseGroup(group)
-            if not erased: #the group was already erased, we can add again the contacts
-                contacts = [JID(contact) for contact in self.host.bridge.getContactsFromGroup(group, self.host.profile)]
-                contacts.sort()
-                id_insert = self.GetSelection()+1
-                for contact in contacts:
-                    _present =  self._presentItem(contact)
-                    if _present:
-                        self.Insert(_present, id_insert, contact)
-            self.SetSelection(wx.NOT_FOUND)
-            self.ScrollToLine(first_visible)
-            event.Skip(False)
-        else:
-            event.Skip()
-
-    def onActivated(self, event):
-        """Called when a contact is clicked or activated with keyboard."""
-        data = self.getSelection()
-        self.onActivatedCB(data)
-        event.Skip()
-
-    def getSelection(self):
-        """Return the selected contact, or an empty string if there is not"""
-        if self.GetSelection() == wx.NOT_FOUND:
-            return None
-        data = self.GetClientData(self.GetSelection())
-        if type(data) == Group:
-            return None
-        return data
-
-    def registerActivatedCB(self, cb):
-        """Register a callback with manage contact activation."""
-        self.onActivatedCB=cb
-
--- a/frontends/src/wix/main_window.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,498 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-from sat.core.i18n import _
-from sat_frontends.wix.constants import Const as C
-from sat_frontends.quick_frontend.quick_chat_list import QuickChatList
-from sat_frontends.quick_frontend.quick_app import QuickApp
-import wx
-from sat_frontends.wix.contact_list import ContactList
-from sat_frontends.wix.chat import Chat
-from sat_frontends.wix import xmlui
-from sat_frontends.wix.profile import Profile
-from sat_frontends.wix.profile_manager import ProfileManager
-import os.path
-from sat_frontends.tools.jid  import JID
-from sat.core.log import getLogger
-log = getLogger(__name__)
-from sat_frontends.wix.constants import Const
-
-idCONNECT,\
-idDISCONNECT,\
-idEXIT,\
-idABOUT,\
-idPARAM,\
-idSHOW_PROFILE,\
-idJOIN_ROOM,\
- = range(7)
-
-class ChatList(QuickChatList):
-    """This class manage the list of chat windows"""
-
-    def createChat(self, target):
-        return Chat(target, self.host)
-
-class MainWindow(wx.Frame, QuickApp):
-    """main app window"""
-
-    def __init__(self):
-        QuickApp.__init__(self)
-        wx.Frame.__init__(self,None, title="SàT Wix", size=(350,500))
-
-        #sizer
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self.sizer)
-
-        #Frame elements
-        self.contact_list = ContactList(self, self)
-        self.contact_list.registerActivatedCB(self.onContactActivated)
-        self.contact_list.Hide()
-        self.sizer.Add(self.contact_list, 1, flag=wx.EXPAND)
-
-        self.chat_wins=ChatList(self)
-        self.CreateStatusBar()
-
-        #ToolBar
-        self.tools=self.CreateToolBar()
-        self.statusBox = wx.ComboBox(self.tools, -1, "Online", choices=[status[1] for status in Const.PRESENCE],
-                                      style=wx.CB_DROPDOWN | wx.CB_READONLY)
-        self.tools.AddControl(self.statusBox)
-        self.tools.AddSeparator()
-        self.statusTxt = wx.TextCtrl(self.tools, -1, style=wx.TE_PROCESS_ENTER)
-        self.tools.AddControl(self.statusTxt)
-        self.Bind(wx.EVT_COMBOBOX, self.onStatusChange, self.statusBox)
-        self.Bind(wx.EVT_TEXT_ENTER, self.onStatusChange, self.statusTxt)
-        self.tools.Disable()
-
-        #tray icon
-        ticon = wx.Icon(os.path.join(self.media_dir, 'icons/crystal/32/tray_icon.xpm'), wx.BITMAP_TYPE_XPM)
-        self.tray_icon = wx.TaskBarIcon()
-        if ticon.IsOk():
-            self.tray_icon.SetIcon(ticon, _("Wix jabber client"))
-        wx.EVT_TASKBAR_LEFT_UP(self.tray_icon, self.onTrayClick)
-
-
-        #events
-        self.Bind(wx.EVT_CLOSE, self.onClose, self)
-
-
-        #profile panel
-        self.profile_pan = ProfileManager(self)
-        self.sizer.Add(self.profile_pan, 1, flag=wx.EXPAND)
-
-        self.postInit()
-
-        self.Show()
-
-    def plug_profile_1(self, profile_key='@DEFAULT@'):
-        """Hide profile panel then plug profile"""
-        log.debug (_('plugin profile %s' % profile_key))
-        self.profile_pan.Hide()
-        self.contact_list.Show()
-        self.sizer.Layout()
-        super(MainWindow, self).plug_profile_1(profile_key)
-        #menus
-        self.createMenus()
-
-    def addMenus(self, menubar, type_, menu_data=None):
-        """Add cached menus to instance
-        @param menu: wx.MenuBar instance
-        @param type_: menu type like is sat.core.sat_main.importMenu
-        @param menu_data: data to send with these menus
-
-        """
-        menus = self.profiles[self.profile]['menus'].get(type_,[])
-        for id_, path, path_i18n  in menus:
-            if len(path) != 2:
-                raise NotImplementedError("Menu with a path != 2 are not implemented yet")
-            category = path_i18n[0] # TODO: manage path with more than 2 levels
-            name = path_i18n[1]
-            menu_idx = menubar.FindMenu(category)
-            current_menu = None
-            if menu_idx == wx.NOT_FOUND:
-                #the menu is new, we create it
-                current_menu = wx.Menu()
-                menubar.Append(current_menu, category)
-            else:
-                current_menu = menubar.GetMenu(menu_idx)
-            assert(current_menu != None)
-            item_id = wx.NewId()
-            help_string = self.bridge.getMenuHelp(id_, '')
-            current_menu.Append(item_id, name, help=help_string)
-            #now we register the event
-            def event_answer(e, id_=id_):
-                self.launchAction(id_, menu_data, profile_key = self.profile)
-
-            wx.EVT_MENU(menubar.Parent, item_id, event_answer)
-
-    def createMenus(self):
-        log.info(_("Creating menus"))
-        connectMenu = wx.Menu()
-        connectMenu.Append(idCONNECT, _("&Connect	CTRL-c"),_(" Connect to the server"))
-        connectMenu.Append(idDISCONNECT, _("&Disconnect	CTRL-d"),_(" Disconnect from the server"))
-        connectMenu.Append(idPARAM,_("&Parameters"),_(" Configure the program"))
-        connectMenu.AppendSeparator()
-        connectMenu.Append(idABOUT, _("A&bout"), _(" About %s") % Const.APP_NAME)
-        connectMenu.Append(idEXIT,_("E&xit"),_(" Terminate the program"))
-        contactMenu = wx.Menu()
-        communicationMenu = wx.Menu()
-        communicationMenu.Append(idJOIN_ROOM, _("&Join Room"),_(" Join a Multi-User Chat room"))
-        self.menuBar = wx.MenuBar()
-        self.menuBar.Append(connectMenu,_("&General"))
-        self.menuBar.Append(contactMenu,_("&Contacts"))
-        self.menuBar.Append(communicationMenu,_("&Communication"))
-        self.SetMenuBar(self.menuBar)
-
-        #additionals menus
-        #FIXME: do this in a more generic way (in quickapp)
-        self.addMenus(self.menuBar, C.MENU_GLOBAL)
-
-        # menu items that should be displayed after the automatically added ones
-        contactMenu.AppendSeparator()
-        contactMenu.Append(idSHOW_PROFILE, _("&Show profile"), _(" Show contact's profile"))
-
-        #events
-        wx.EVT_MENU(self, idCONNECT, self.onConnectRequest)
-        wx.EVT_MENU(self, idDISCONNECT, self.onDisconnectRequest)
-        wx.EVT_MENU(self, idPARAM, self.onParam)
-        wx.EVT_MENU(self, idABOUT, self.onAbout)
-        wx.EVT_MENU(self, idEXIT, self.onExit)
-        wx.EVT_MENU(self, idSHOW_PROFILE, self.onShowProfile)
-        wx.EVT_MENU(self, idJOIN_ROOM, self.onJoinRoom)
-
-    def newMessageHandler(self, from_jid, to_jid, msg, _type, extra, profile):
-        QuickApp.newMessageHandler(self, from_jid, to_jid, msg, _type, extra, profile)
-
-    def showAlert(self, message):
-        # TODO: place this in a separate class
-        popup=wx.PopupWindow(self)
-        ### following code come from wxpython demo
-        popup.SetBackgroundColour("CADET BLUE")
-        st = wx.StaticText(popup, -1, message, pos=(10,10))
-        sz = st.GetBestSize()
-        popup.SetSize( (sz.width+20, sz.height+20) )
-        x=(wx.DisplaySize()[0]-popup.GetSize()[0])/2
-        popup.SetPosition((x,0))
-        popup.Show()
-        wx.CallLater(5000,popup.Destroy)
-
-    def showDialog(self, message, title="", type_="info", answer_cb = None, answer_data = None):
-        if type_ == 'info':
-            flags = wx.OK | wx.ICON_INFORMATION
-        elif type_ == 'error':
-            flags = wx.OK | wx.ICON_ERROR
-        elif type_ == 'yes/no':
-            flags = wx.YES_NO | wx.ICON_QUESTION
-        else:
-            flags = wx.OK | wx.ICON_INFORMATION
-            log.error(_('unmanaged dialog type: %s'), type_)
-        dlg = wx.MessageDialog(self, message, title, flags)
-        answer = dlg.ShowModal()
-        dlg.Destroy()
-        if answer_cb:
-            data = [answer_data] if answer_data else []
-            answer_cb(True if (answer == wx.ID_YES or answer == wx.ID_OK) else False, *data)
-
-    def setStatusOnline(self, online=True, show="", statuses={}):
-        """enable/disable controls, must be called when local user online status change"""
-        if online:
-            self.SetStatusText(Const.msgONLINE)
-            self.tools.Enable()
-            try:
-                presence = [x for x in Const.PRESENCE if x[0] == show][0][1]
-                self.statusBox.SetValue(presence)
-            except (TypeError, IndexError):
-                pass
-            try:
-                self.statusTxt.SetValue(statuses['default'])
-            except (TypeError, KeyError):
-                pass
-        else:
-            self.SetStatusText(Const.msgOFFLINE)
-            self.tools.Disable()
-        return
-
-    def launchAction(self, callback_id, data=None, profile_key="@NONE@"):
-        """ Launch a dynamic action
-        @param callback_id: id of the action to launch
-        @param data: data needed only for certain actions
-        @param profile_key: %(doc_profile_key)s
-
-        """
-        if data is None:
-            data = dict()
-        def action_cb(data):
-            if not data:
-                # action was a one shot, nothing to do
-                pass
-            elif "xmlui" in data:
-                log.debug (_("XML user interface received"))
-                ui = xmlui.create(self, xml_data = data['xmlui'])
-                ui.show()
-            elif "authenticated_profile" in data:
-                assert("caller" in data)
-                if data["caller"] == "profile_manager":
-                    assert(self.profile_pan.IsShown())
-                    self.profile_pan.getXMPPParams(data['authenticated_profile'])
-                elif data["caller"] == "plug_profile":
-                    self.plug_profile_1(data['authenticated_profile'])
-                else:
-                    raise NotImplementedError
-            else:
-                dlg = wx.MessageDialog(self, _(u"Unmanaged action result"),
-                                       _('Error'),
-                                       wx.OK | wx.ICON_ERROR
-                                      )
-                dlg.ShowModal()
-                dlg.Destroy()
-        def action_eb(failure):
-            dlg = wx.MessageDialog(self, failure.message,
-                                   failure.fullname,
-                                   wx.OK | wx.ICON_ERROR
-                                  )
-            dlg.ShowModal()
-            dlg.Destroy()
-
-        self.bridge.launchAction(callback_id, data, profile_key, callback=action_cb, errback=action_eb)
-
-    def askConfirmationHandler(self, confirmation_id, confirmation_type, data, profile):
-        #TODO: refactor this in QuickApp
-        if not self.check_profile(profile):
-            return
-        log.debug (_("Confirmation asked"))
-        answer_data={}
-        if confirmation_type == "FILE_TRANSFER":
-            log.debug (_("File transfer confirmation asked"))
-            dlg = wx.MessageDialog(self, _("The contact %(jid)s wants to send you the file %(filename)s\nDo you accept ?") % {'jid':data["from"], 'filename':data["filename"]},
-                                   _('File Request'),
-                                   wx.YES_NO | wx.ICON_QUESTION
-                                  )
-            answer=dlg.ShowModal()
-            if answer==wx.ID_YES:
-                filename = wx.FileSelector(_("Where do you want to save the file ?"), flags = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
-                if filename:
-                    answer_data["dest_path"] = filename
-                    self.bridge.confirmationAnswer(confirmation_id, True, answer_data, profile)
-                    self.waitProgress(confirmation_id, _("File Transfer"), _("Copying %s") % os.path.basename(filename), profile)
-                else:
-                    answer = wx.ID_NO
-            if answer==wx.ID_NO:
-                    self.bridge.confirmationAnswer(confirmation_id, False, answer_data, profile)
-
-            dlg.Destroy()
-
-        elif confirmation_type == "YES/NO":
-            log.debug (_("Yes/No confirmation asked"))
-            dlg = wx.MessageDialog(self, data["message"],
-                                   _('Confirmation'),
-                                   wx.YES_NO | wx.ICON_QUESTION
-                                  )
-            answer=dlg.ShowModal()
-            if answer==wx.ID_YES:
-                self.bridge.confirmationAnswer(confirmation_id, True, {}, profile)
-            if answer==wx.ID_NO:
-                self.bridge.confirmationAnswer(confirmation_id, False, {}, profile)
-
-            dlg.Destroy()
-
-    def actionResultHandler(self, type_, id_, data, profile):
-        if not self.check_profile(profile):
-            return
-        log.debug (_("actionResult: type_ = [%(type_)s] id_ = [%(id_)s] data = [%(data)s]") % {'type_':type_, 'id_':id_, 'data':data})
-        if not id_ in self.current_action_ids:
-            log.debug (_('unknown id_, ignoring'))
-            return
-        if type_ == "SUPPRESS":
-            self.current_action_ids.remove(id_)
-        elif type_ == "SUCCESS":
-            self.current_action_ids.remove(id_)
-            dlg = wx.MessageDialog(self, data["message"],
-                                   _('Success'),
-                                   wx.OK | wx.ICON_INFORMATION
-                                  )
-            dlg.ShowModal()
-            dlg.Destroy()
-        elif type_ == "ERROR":
-            self.current_action_ids.remove(id_)
-            dlg = wx.MessageDialog(self, data["message"],
-                                   _('Error'),
-                                   wx.OK | wx.ICON_ERROR
-                                  )
-            dlg.ShowModal()
-            dlg.Destroy()
-        elif type_ == "XMLUI":
-            self.current_action_ids.remove(id_)
-            log.debug (_("XML user interface received"))
-            misc = {}
-            #FIXME FIXME FIXME: must clean all this crap !
-            title = _('Form')
-            if data['type_'] == _('registration'):
-                title = _('Registration')
-                misc['target'] = data['target']
-                misc['action_back'] = self.bridge.gatewayRegister
-            xmlui.create(self, title=title, xml_data = data['xml'], misc = misc)
-        elif type_ == "RESULT":
-            self.current_action_ids.remove(id_)
-            if self.current_action_ids_cb.has_key(id_):
-                callback = self.current_action_ids_cb[id_]
-                del self.current_action_ids_cb[id_]
-                callback(data)
-        elif type_ == "DICT_DICT":
-            self.current_action_ids.remove(id_)
-            if self.current_action_ids_cb.has_key(id_):
-                callback = self.current_action_ids_cb[id_]
-                del self.current_action_ids_cb[id_]
-                callback(data)
-        else:
-            log.error (_("FIXME FIXME FIXME: type_ [%s] not implemented") % type_)
-            raise NotImplementedError
-
-
-
-    def progressCB(self, progress_id, title, message, profile):
-        data = self.bridge.getProgress(progress_id, profile)
-        if data:
-            if not self.pbar:
-                #first answer, we must construct the bar
-                self.pbar = wx.ProgressDialog(title, message, float(data['size']), None,
-                    wx.PD_SMOOTH | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME)
-                self.pbar.finish_value = float(data['size'])
-
-            self.pbar.Update(int(data['position']))
-        elif self.pbar:
-            self.pbar.Update(self.pbar.finish_value)
-            return
-
-        wx.CallLater(10, self.progressCB, progress_id, title, message, profile)
-
-    def waitProgress (self, progress_id, title, message, profile):
-        self.pbar = None
-        wx.CallLater(10, self.progressCB, progress_id, title, message, profile)
-
-
-
-    ### events ###
-
-    def onContactActivated(self, jid):
-        log.debug (_("onContactActivated: %s"), jid)
-        if self.chat_wins[jid.bare].IsShown():
-            self.chat_wins[jid.bare].Hide()
-        else:
-            self.chat_wins[jid.bare].Show()
-
-    def onConnectRequest(self, e):
-        QuickApp.asyncConnect(self, self.profile)
-
-    def onDisconnectRequest(self, e):
-        self.bridge.disconnect(self.profile)
-
-    def __updateStatus(self):
-        show = [x for x in Const.PRESENCE if x[1] == self.statusBox.GetValue()][0][0]
-        status = self.statusTxt.GetValue()
-        self.bridge.setPresence(show=show, statuses={'default': status}, profile_key=self.profile)  #FIXME: manage multilingual statuses
-
-    def onStatusChange(self, e):
-        log.debug(_("Status change request"))
-        self.__updateStatus()
-
-    def onParam(self, e):
-        log.debug(_("Param request"))
-        def success(params):
-            xmlui.create(self, xml_data=params, title=_("Configuration"))
-
-        def failure(error):
-            dlg = wx.MessageDialog(self, error.message,
-                                   error.fullname,
-                                   wx.OK | wx.ICON_ERROR
-                                  )
-            dlg.ShowModal()
-            dlg.Destroy()
-        self.bridge.getParamsUI(app=Const.APP_NAME, profile_key=self.profile, callback=success, errback=failure)
-
-    def onAbout(self, e):
-        about = wx.AboutDialogInfo()
-        about.SetName(Const.APP_NAME)
-        about.SetVersion (unicode(self.bridge.getVersion()))
-        about.SetCopyright(u"(C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson aka Goffi")
-        about.SetDescription( _(u"%(name)s is a SàT (Salut à Toi) frontend\n"+
-        u"%(name)s is based on WxPython, and is the standard graphic interface of SàT") % {'name': Const.APP_NAME})
-        about.SetWebSite(("http://www.goffi.org", "Goffi's non-hebdo (french)"))
-        about.SetDevelopers([ "Goffi (Jérôme Poisson)"])
-        try:
-            with open(Const.LICENCE_PATH, "r") as licence:
-                about.SetLicence(''.join(licence.readlines()))
-        except:
-            pass
-
-        wx.AboutBox(about)
-
-    def onExit(self, e):
-        self.Close()
-
-    def onShowProfile(self, e):
-        log.debug(_("Show contact's profile request"))
-        target = self.contact_list.getSelection()
-        if not target:
-            dlg = wx.MessageDialog(self, _("You haven't selected any contact !"),
-                                   _('Error'),
-                                   wx.OK | wx.ICON_ERROR
-                                  )
-            dlg.ShowModal()
-            dlg.Destroy()
-            return
-        _id = self.bridge.getCard(target.bare, self.profile)
-        self.current_action_ids.add(_id)
-        self.current_action_ids_cb[_id] = self.onProfileReceived
-
-    def onProfileReceived(self, data):
-        """Called when a profile is received"""
-        log.debug (_('Profile received: [%s]') % data)
-        Profile(self, data)
-
-    def onJoinRoom(self, e):
-        log.warning('FIXME: temporary menu, must be improved')
-        #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'), 'room@muc_service.server.tld')
-        if dlg.ShowModal() == wx.ID_OK:
-            room_jid=JID(dlg.GetValue())
-            if room_jid.is_valid():
-                self.bridge.joinMUC(room_jid, self.profiles[self.profile]['whoami'].node, {}, self.profile)
-            else:
-                log.error (_("'%s' is an invalid JID !"), room_jid)
-
-    def onClose(self, e):
-        QuickApp.onExit(self)
-        log.info(_("Exiting..."))
-        for win in self.chat_wins:
-            self.chat_wins[win].Destroy()
-        self.tray_icon.Destroy()
-        e.Skip()
-
-    def onTrayClick(self, e):
-        log.debug(_("Tray Click"))
-        if self.IsShown():
-            self.Hide()
-        else:
-            self.Show()
-            self.Raise()
-        e.Skip()
--- a/frontends/src/wix/profile.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from sat.core.i18n import _
-import wx
-import pdb
-from sat.core.log import getLogger
-log = getLogger(__name__)
-from sat_frontends.tools.jid  import JID
-
-
-class Profile(wx.Frame):
-    """This class is used to show/modify profile given by SàT"""
-
-    def __init__(self, host, data, title="Profile"):
-        super(Profile, self).__init__(None, title=title)
-        self.host = host
-
-        self.name_dict = { 'fullname': _('Full Name'),
-                           'nick' : _('Nickname'),
-                           'birthday' : _('Birthday'),
-                           'phone' : _('Phone #'),
-                           'website' : _('Website'),
-                           'email' : _('E-mail'),
-                           'avatar' : _('Avatar')
-                         }
-        self.ctl_list = {}  # usefull to access ctrl, key = (name)
-
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.notebook=wx.Notebook(self, -1)
-        self.sizer.Add(self.notebook, 1, flag=wx.EXPAND)
-        self.SetSizer(self.sizer)
-        self.SetAutoLayout(True)
-
-        #events
-        self.Bind(wx.EVT_CLOSE, self.onClose, self)
-
-        self.MakeModal()
-        self.showData(data)
-        self.Show()
-
-    def showData(self, data):
-        flags = wx.TE_READONLY
-
-        #General tab
-        generaltab = wx.Panel(self.notebook)
-        sizer = wx.FlexGridSizer(cols=2)
-        sizer.AddGrowableCol(1)
-        generaltab.SetSizer(sizer)
-        generaltab.SetAutoLayout(True)
-        for field in ['fullname','nick', 'birthday', 'phone', 'website', 'email']:
-            value = data[field] if data.has_key(field) else ''
-            label=wx.StaticText(generaltab, -1, self.name_dict[field]+": ")
-            sizer.Add(label)
-            self.ctl_list[field] = wx.TextCtrl(generaltab, -1, value, style = flags)
-            sizer.Add(self.ctl_list[field], 1, flag = wx.EXPAND)
-        #Avatar
-        if data.has_key('avatar'):
-            filename = self.host.bridge.getAvatarFile(data['avatar'])
-            label=wx.StaticText(generaltab, -1, self.name_dict['avatar']+": ")
-            sizer.Add(label)
-            img = wx.Image(filename).ConvertToBitmap()
-            self.ctl_list['avatar'] = wx.StaticBitmap(generaltab, -1, img)
-            sizer.Add(self.ctl_list['avatar'], 0)
-
-
-
-        self.notebook.AddPage(generaltab, _("General"))
-
-
-    def onClose(self, event):
-        """Close event"""
-        log.debug(_("close"))
-        self.MakeModal(False)
-        event.Skip()
-
--- a/frontends/src/wix/profile_manager.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-
-from sat.core.i18n import _
-from sat_frontends.primitivus.constants import Const as C
-import wx
-from sat.core.log import getLogger
-log = getLogger(__name__)
-
-
-NO_SELECTION_ENTRY = ' '
-
-
-class ProfileManager(wx.Panel):
-    def __init__(self, host):
-        super(ProfileManager, self).__init__(host)
-        self.host = host
-
-        #self.sizer = wx.FlexGridSizer(cols=2)
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self.sizer)
-
-        self.selected_profile = NO_SELECTION_ENTRY  # allow to reselect the previous selection until the profile is authenticated
-        self.profile_name = wx.ComboBox(self, -1, style=wx.CB_READONLY|wx.CB_SORT)
-        self.__refillProfiles()
-        self.Bind(wx.EVT_COMBOBOX, self.onProfileChange)
-        self.panel_id = wx
-
-        self.sizer.Add(wx.Window(self, -1), 1)
-        self.sizer.Add(wx.StaticText(self, -1, _("Profile:")), 0, flag=wx.ALIGN_CENTER)
-        self.sizer.Add(self.profile_name, 0, flag=wx.ALIGN_CENTER)
-        button_panel = wx.Panel(self)
-        button_panel.sizer = wx.BoxSizer(wx.HORIZONTAL)
-        button_panel.SetSizer(button_panel.sizer)
-        button_new = wx.Button(button_panel, -1, _("New"))
-        button_del = wx.Button(button_panel, -1, _("Delete"))
-        button_panel.sizer.Add(button_new)
-        button_panel.sizer.Add(button_del)
-        self.sizer.Add(button_panel, flag=wx.CENTER)
-        self.Bind(wx.EVT_BUTTON, self.onNewProfile, button_new)
-        self.Bind(wx.EVT_BUTTON, self.onDeleteProfile, button_del)
-
-        login_box = wx.StaticBox(self, -1, _("Login"))
-        self.login_sizer = wx.StaticBoxSizer(login_box, wx.VERTICAL)
-        self.sizer.Add(self.login_sizer, 1, wx.EXPAND | wx.ALL)
-        self.login_jid = wx.TextCtrl(self, -1)
-        self.login_sizer.Add(wx.StaticText(self, -1, "JID:"), 0, flag=wx.ALIGN_CENTER)
-        self.login_sizer.Add(self.login_jid, flag=wx.EXPAND)
-        self.login_pass = wx.TextCtrl(self, -1, style = wx.TE_PASSWORD)
-        self.login_sizer.Add(wx.StaticText(self, -1, _("Password:")), 0, flag=wx.ALIGN_CENTER)
-        self.login_sizer.Add(self.login_pass, flag=wx.EXPAND)
-
-        loggin_button = wx.Button(self, -1, _("Connect"))
-        self.Bind(wx.EVT_BUTTON, self.onConnectButton, loggin_button)
-        self.login_sizer.Add(loggin_button, flag=wx.ALIGN_CENTER)
-
-        self.sizer.Add(wx.Window(self, -1), 1)
-
-        #Now we can set the default value
-        self.__setDefault()
-
-    def __setDefault(self):
-        profile_default = NO_SELECTION_ENTRY if self.host.options.profile else self.host.bridge.getProfileName("@DEFAULT@")
-        if profile_default:
-            self.profile_name.SetValue(profile_default)
-            self.onProfileChange(None)
-
-    def __refillProfiles(self):
-        """Update profiles with current names. Must be called after a profile change"""
-        self.profile_name.Clear()
-        profiles = self.host.bridge.getProfilesList()
-        profiles.sort()
-        self.profile_name.Append(NO_SELECTION_ENTRY)
-        for profile in profiles:
-            self.profile_name.Append(profile)
-
-    def onNewProfile(self, event):
-        dlg = wx.TextEntryDialog(self, _("Please enter the new profile name"), _("New profile"), style = wx.OK | wx.CANCEL)
-        if dlg.ShowModal() == wx.ID_OK:
-            name = dlg.GetValue()
-            if name:
-                if name[0]=='@':
-                    wx.MessageDialog(self, _("A profile name can't start with a @"), _("Bad profile name"), wx.ICON_ERROR).ShowModal()
-                else:
-                    def cb():
-                        self.__refillProfiles()
-                        self.profile_name.SetValue(name)
-                        self.selected_profile = name
-                        self.getXMPPParams(name)
-                    self.host.bridge.asyncCreateProfile(name, callback=cb)
-        dlg.Destroy()
-
-    def onDeleteProfile(self, event):
-        name = self.profile_name.GetValue()
-        if not name:
-            return
-        dlg = wx.MessageDialog(self, _("Are you sure to delete the profile [%s]") % name, _("Confirmation"), wx.ICON_QUESTION | wx.YES_NO)
-        if dlg.ShowModal() == wx.ID_YES:
-            def cb():
-                self.__refillProfiles()
-                self.__setDefault()
-            self.host.bridge.asyncDeleteProfile(name, callback=cb)
-        dlg.Destroy()
-
-    def getXMPPParams(self, profile):
-        """This is called from MainWindow.launchAction when the profile has been authenticated.
-
-        @param profile: %(doc_profile)s
-        """
-        def setJID(jabberID):
-            self.login_jid.SetValue(jabberID)
-
-        def setPassword(password):
-            self.login_pass.SetValue(password)
-
-        self.profile_name.SetValue(profile)
-        self.selected_profile = profile
-        self.host.bridge.asyncGetParamA("JabberID", "Connection", profile_key=profile, callback=setJID, errback=self.getParamError)
-        self.host.bridge.asyncGetParamA("Password", "Connection", profile_key=profile, callback=setPassword, errback=self.getParamError)
-
-    def onProfileChange(self, event):
-        """Called when a profile is choosen in the combo box"""
-        profile_name = self.profile_name.GetValue()
-        if not profile_name or profile_name == self.selected_profile:
-            return  # avoid infinite loop
-        if profile_name == NO_SELECTION_ENTRY:
-            self.selected_profile = NO_SELECTION_ENTRY
-            return
-        if self.selected_profile:
-            self.profile_name.SetValue(self.selected_profile)
-        self.host.profile = profile_name  # FIXME: EXTREMELY DIRTY, needed for sat_frontends.tools.xmlui.XMLUI.submit
-        self.host.launchAction(C.AUTHENTICATE_PROFILE_ID, {'caller': 'profile_manager'}, profile_key=profile_name)
-
-    def onConnectButton(self, event):
-        """Called when the Connect button is pressed"""
-        name = self.profile_name.GetValue()
-        assert(name == self.selected_profile)  # if not, there's a bug somewhere...
-        if not name or name == NO_SELECTION_ENTRY:
-            wx.MessageDialog(self, _("You must select a profile or create a new one before connecting"), _("No profile selected"), wx.ICON_ERROR).ShowModal()
-            return
-        if name[0]=='@':
-            wx.MessageDialog(self, _("A profile name can't start with a @"), _("Bad profile name"), wx.ICON_ERROR).ShowModal()
-            return
-        profile = self.host.bridge.getProfileName(name)
-        assert(profile)
-
-        self.host.bridge.asyncGetParamA("JabberID", "Connection", profile_key=profile, callback=lambda old_jid: self.__old_jidReceived(old_jid, profile), errback=self.getParamError)
-
-    def __old_jidReceived(self, old_jid, profile):
-        self.host.bridge.asyncGetParamA("Password", "Connection", profile_key=profile, callback=lambda old_pass: self.__old_passReceived(old_jid, old_pass, profile), errback=self.getParamError)
-
-    def __old_passReceived(self, old_jid, old_pass, profile):
-        new_jid = self.login_jid.GetValue()
-        new_pass = self.login_pass.GetValue()
-        if old_jid != new_jid:
-            log.debug(_('Saving new JID and server'))
-            self.host.bridge.setParam("JabberID", new_jid, "Connection", profile_key=profile)
-        if old_pass != new_pass:
-            log.debug(_('Saving new password'))
-            self.host.bridge.setParam("Password", new_pass, "Connection", profile_key=profile)
-        self.host.plug_profile(profile)
-
-
-    def getParamError(self, ignore):
-        wx.MessageDialog(self, _("Can't get profile parameter"), _("Profile error"), wx.ICON_ERROR).ShowModal()
--- a/frontends/src/wix/quiz_game.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,243 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-
-from sat.core.i18n import _
-import wx
-import os.path, glob
-import pdb
-from sat.core.log import getLogger
-log = getLogger(__name__)
-from sat_frontends.tools.jid  import JID
-from time import time
-from math import sin, cos, pi
-
-CARD_WIDTH = 74
-CARD_HEIGHT = 136
-WIDTH = 800
-HEIGHT = 600
-
-class GraphicElement(object):
-    """This class is used to represent a card, graphically and logically"""
-
-    def __init__(self, file, x=0, y=0, zindex=10, transparent=True):
-        """ Image used to build the game visual
-        @param file: path of the PNG file
-        @param zindex: layer of the element (0=background; the bigger, the more in the foreground)"""
-        self.bitmap = wx.Image(file).ConvertToBitmap()
-        self.x = x
-        self.y = y
-        self.zindex = zindex
-        self.transparent = transparent
-
-    def __cmp__(self, other):
-        return self.zindex.__cmp__(other.zindex)
-
-    def draw(self, dc, x=None, y=None):
-        """Draw the card on the device context
-        @param dc: device context
-        @param x: abscissa
-        @param y: ordinate"""
-        dc.DrawBitmap(self.bitmap, x or self.x, y or self.y, self.transparent)
-
-class BaseWindow(wx.Window):
-    """This is the panel where the game is drawed, under the other widgets"""
-
-    def __init__(self, parent):
-        wx.Window.__init__(self, parent, pos=(0,0), size=(WIDTH, HEIGHT))
-        self.parent = parent
-        self.SetMinSize(wx.Size(WIDTH, HEIGHT))
-        self.Bind(wx.EVT_PAINT, self.onPaint)
-        self.graphic_elts = {}
-        self.loadImages(os.path.join(parent.parent.host.media_dir, 'games/quiz/'))
-
-    def loadImages(self, dir):
-        """Load all the images needed for the game
-        @param dir: directory where the PNG files are"""
-        x_player = 24
-        for name, sub_dir, filename, x, y, zindex, transparent in [("background", "background", "blue_background.png", 0, 0, 0, False),
-                                                             ("joueur0", "characters", "zombie.png", x_player+0*184, 170, 5, True),
-                                                             ("joueur1", "characters", "nerd.png", x_player+1*184, 170, 5, True),
-                                                             ("joueur2", "characters", "zombie.png", x_player+2*184, 170, 5, True),
-                                                             ("joueur3", "characters", "zombie.png", x_player+3*184, 170, 5, True),
-                                                             ("foreground", "foreground", "foreground.png", 0, 0, 10, True)]:
-            self.graphic_elts[name] = GraphicElement(os.path.join(dir, sub_dir, filename), x = x, y = y, zindex=zindex, transparent=transparent)
-
-        self.right_image = wx.Image(os.path.join(dir, "foreground", "right.png")).ConvertToBitmap()
-        self.wrong_image = wx.Image(os.path.join(dir, "foreground", "wrong.png")).ConvertToBitmap()
-
-    def fullPaint(self, device_context):
-        """Paint all the game on the given dc
-        @param device_context: wx.DC"""
-        elements = self.graphic_elts.values()
-        elements.sort()
-        for elem in elements:
-            elem.draw(device_context)
-
-        _font = wx.Font(65, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
-        device_context.SetFont(_font)
-        device_context.SetTextForeground(wx.BLACK)
-
-        for i in range(4):
-            answer = self.parent.players_data[i]["answer"]
-            score = self.parent.players_data[i]["score"]
-            if answer == None:
-                device_context.DrawText("%d" % score, 100 + i*184, 355)
-            else:
-                device_context.DrawBitmap(self.right_image if answer else self.wrong_image, 39+i*184, 348, True)
-
-
-        if self.parent.time_origin:
-            device_context.SetPen(wx.BLACK_PEN)
-            radius = 20
-            center_x = 760
-            center_y = 147
-            origin = self.parent.time_origin
-            current = self.parent.time_pause or time()
-            limit = self.parent.time_limit
-            total = limit - origin
-            left = self.parent.time_left = max(0,limit - current)
-            device_context.SetBrush(wx.RED_BRUSH if left/total < 1/4.0 else wx.WHITE_BRUSH)
-            if left:
-                #we now draw the timer
-                angle = ((-2*pi)*((total-left)/total) + (pi/2))
-                x = center_x + radius * cos(angle)
-                y = center_y - radius * sin(angle)
-                device_context.DrawArc(center_x, center_y-radius, x, y, center_x, center_y)
-
-    def onPaint(self, event):
-        dc = wx.PaintDC(self)
-        self.fullPaint(dc)
-
-
-
-class QuizPanel(wx.Panel):
-    """This class is used to display the quiz game"""
-
-    def __init__(self, parent, referee, players, player_nick):
-        wx.Panel.__init__(self, parent)
-        self.referee = referee
-        self.player_nick = player_nick
-        self.players = players
-        self.time_origin = None #set to unix time when the timer start
-        self.time_limit = None
-        self.time_left = None
-        self.time_pause = None
-        self.last_answer = None
-        self.parent = parent
-        self.SetMinSize(wx.Size(WIDTH, HEIGHT))
-        self.SetSize(wx.Size(WIDTH, HEIGHT))
-        self.base = BaseWindow(self)
-        self.question = wx.TextCtrl(self, -1, pos=(168,17), size=(613, 94), style=wx.TE_MULTILINE | wx.TE_READONLY)
-        self.answer = wx.TextCtrl(self, -1, pos=(410,569), size=(342, 21), style=wx.TE_PROCESS_ENTER)
-        self.players_data = [{}, {}, {}, {}]
-        for i in range(4):
-            self.players_data[i]['bubble'] = wx.TextCtrl(self, -1, pos=(39+i*184, 120), size=(180, 56), style=wx.TE_MULTILINE | wx.TE_READONLY)
-            self.players_data[i]['bubble'].Hide()
-            self.players_data[i]['answer'] = None #True if the player gave a good answer
-            self.players_data[i]['score'] = 0
-        self.answer.Bind(wx.EVT_TEXT_ENTER, self.answered)
-        self.parent.host.bridge.quizGameReady(player_nick, referee, self.parent.host.profile)
-        self.state = None
-
-    def answered(self, event):
-        """Called when the player gave an answer in the box"""
-        self.last_answer = self.answer.GetValue()
-        self.answer.Clear()
-        if self.last_answer:
-            self.parent.host.bridge.quizGameAnswer(self.player_nick, self.referee, self.last_answer, self.parent.host.profile)
-
-    def quizGameTimerExpired(self):
-        """Called when nobody answered the question in time"""
-        self.question.SetValue(_(u"Quel dommage, personne n'a trouvé la réponse\n\nAttention, la prochaine question arrive..."))
-
-    def quizGameTimerRestarted(self, time_left):
-        """Called when nobody answered the question in time"""
-        timer_orig = self.time_limit - self.time_origin
-        self.time_left = time_left
-        self.time_limit = time() + time_left
-        self.time_origin = self.time_limit - timer_orig
-        self.time_pause = None
-        self.__timer_refresh()
-
-    def startTimer(self, timer=60):
-        """Start the timer to answer the question"""
-        self.time_left = timer
-        self.time_origin = time()
-        self.time_limit = self.time_origin + timer
-        self.time_pause = None
-        self.__timer_refresh()
-
-    def __timer_refresh(self):
-        self.Refresh()
-        if self.time_left:
-            wx.CallLater(1000, self.__timer_refresh)
-
-    def quizGameNew(self, data):
-        """Start a new game, with given hand"""
-        if data.has_key('instructions'):
-            self.question.ChangeValue(data['instructions'])
-        self.Refresh()
-
-    def quizGameQuestion(self, question_id, question, timer):
-        """Called when a new question is available
-        @param question: question to ask"""
-        self.question.ChangeValue(question)
-        self.startTimer(timer)
-        self.last_answer = None
-        self.answer.Clear()
-
-    def quizGamePlayerBuzzed(self, player, pause):
-        """Called when the player pushed the buzzer
-        @param player: player who pushed the buzzer
-        @param pause: should we stop the timer ?"""
-        if pause:
-            self.time_pause = time()
-
-    def quizGamePlayerSays(self, player, text, delay):
-        """Called when the player says something
-        @param player: who is talking
-        @param text: what the player says"""
-        if player != self.player_nick and self.last_answer:
-            #if we are not the player talking, and we have an answer, that mean that our answer has not been validated
-            #we can put it again in the answering box
-            self.answer.SetValue(self.last_answer)
-        idx = self.players.index(player)
-        bubble = self.players_data[idx]['bubble']
-        bubble.SetValue(text)
-        bubble.Show()
-        self.Refresh()
-        wx.CallLater(delay * 1000, bubble.Hide)
-
-    def quizGameAnswerResult(self, player, good_answer, score):
-        """Result of the just given answer
-        @param player: who gave the answer
-        @good_answer: True if the answer is right
-        @score: dict of score"""
-        player_idx = self.players.index(player)
-        self.players_data[player_idx]['answer'] = good_answer
-        for _player in score:
-            _idx = self.players.index(_player)
-            self.players_data[_idx]['score'] = score[_player]
-        def removeAnswer():
-            self.players_data[player_idx]['answer'] = None
-            self.Refresh()
-        wx.CallLater(2000, removeAnswer)
-        self.Refresh()
--- a/frontends/src/wix/wix	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013Jé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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-from sat_frontends.wix.constants import Const as C
-from sat.core import log_config
-log_config.satConfigure(C.LOG_BACKEND_STANDARD, C)
-import wx
-from sat_frontends.wix.main_window import MainWindow
-
-
-class SATApp(wx.App):
-    def __init__(self,  redirect=False, filename=None, useBestVisual=False, clearSigInt=True):
-        super(SATApp,self).__init__(redirect, filename, useBestVisual, clearSigInt)
-
-    def OnInit(self):
-        self.main = MainWindow()
-        self.main.Show(True)
-        self.SetTopWindow(self.main)
-        return True
-
-
-sat = SATApp()
-sat.MainLoop()
--- a/frontends/src/wix/xmlui.py	Sat Jan 24 00:14:58 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,428 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# wix: a SAT frontend
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 Affero 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-
-from sat.core.i18n import _
-import wx
-from sat.core.log import getLogger
-log = getLogger(__name__)
-from sat_frontends.tools import xmlui
-from sat_frontends.constants import Const as C
-
-
-class EventWidget(object):
-    """ Used to manage change event of  widgets """
-
-    def _xmluiOnChange(self, callback):
-        """ Call callback with widget as only argument """
-        def change_cb(event):
-            callback(self)
-        self.Bind(self._xmlui_change_event, change_cb)
-
-
-class WixWidget(object):
-    _xmlui_proportion = 0
-
-
-class ValueWidget(WixWidget):
-
-    def _xmluiSetValue(self, value):
-        self.SetValue(value)
-
-    def _xmluiGetValue(self):
-        return self.GetValue()
-
-
-class EmptyWidget(WixWidget, xmlui.EmptyWidget, wx.Window):
-
-    def __init__(self, _xmlui_parent):
-        wx.Window.__init__(self, _xmlui_parent, -1)
-
-
-class TextWidget(WixWidget, xmlui.TextWidget, wx.StaticText):
-
-    def __init__(self, _xmlui_parent, value):
-        wx.StaticText.__init__(self, _xmlui_parent, -1, value)
-
-
-class LabelWidget(xmlui.LabelWidget, TextWidget):
-
-    def __init__(self, _xmlui_parent, value):
-        super(LabelWidget, self).__init__(_xmlui_parent, value+": ")
-
-
-class JidWidget(xmlui.JidWidget, TextWidget):
-    pass
-
-
-class DividerWidget(WixWidget, xmlui.DividerWidget, wx.StaticLine):
-
-    def __init__(self, _xmlui_parent, style='line'):
-        wx.StaticLine.__init__(self, _xmlui_parent, -1)
-
-
-class StringWidget(EventWidget, ValueWidget, xmlui.StringWidget, wx.TextCtrl):
-    _xmlui_change_event = wx.EVT_TEXT
-
-    def __init__(self, _xmlui_parent, value, read_only=False):
-        style = wx.TE_READONLY if read_only else 0
-        wx.TextCtrl.__init__(self, _xmlui_parent, -1, value, style=style)
-        self._xmlui_proportion = 1
-
-
-class PasswordWidget(EventWidget, ValueWidget, xmlui.PasswordWidget, wx.TextCtrl):
-    _xmlui_change_event = wx.EVT_TEXT
-
-    def __init__(self, _xmlui_parent, value, read_only=False):
-        style = wx.TE_PASSWORD
-        if read_only:
-            style |= wx.TE_READONLY
-        wx.TextCtrl.__init__(self, _xmlui_parent, -1, value, style=style)
-        self._xmlui_proportion = 1
-
-
-class TextBoxWidget(EventWidget, ValueWidget, xmlui.TextBoxWidget, wx.TextCtrl):
-    _xmlui_change_event = wx.EVT_TEXT
-
-    def __init__(self, _xmlui_parent, value, read_only=False):
-        style = wx.TE_MULTILINE
-        if read_only:
-            style |= wx.TE_READONLY
-        wx.TextCtrl.__init__(self, _xmlui_parent, -1, value, style=style)
-        self._xmlui_proportion = 1
-
-
-class BoolWidget(EventWidget, ValueWidget, xmlui.BoolWidget, wx.CheckBox):
-    _xmlui_change_event = wx.EVT_CHECKBOX
-
-    def __init__(self, _xmlui_parent, state, read_only=False):
-        style = wx.CHK_2STATE
-        if read_only:
-            style |= wx.TE_READONLY
-        wx.CheckBox.__init__(self, _xmlui_parent, -1, "", style=wx.CHK_2STATE)
-        self.SetValue(state)
-        self._xmlui_proportion = 1
-
-    def _xmluiSetValue(self, value):
-        self.SetValue(value == 'true')
-
-    def _xmluiGetValue(self):
-        return "true" if self.GetValue() else "false"
-
-
-# TODO: use wx.SpinCtrl instead of wx.TextCtrl
-class IntWidget(EventWidget, ValueWidget, xmlui.IntWidget, wx.TextCtrl):
-    _xmlui_change_event = wx.EVT_TEXT
-
-    def __init__(self, _xmlui_parent, value, read_only=False):
-        style = wx.TE_READONLY if read_only else 0
-        wx.TextCtrl.__init__(self, _xmlui_parent, -1, value, style=style)
-        self._xmlui_proportion = 1
-
-
-class ButtonWidget(EventWidget, WixWidget, xmlui.ButtonWidget, wx.Button):
-    _xmlui_change_event = wx.EVT_BUTTON
-
-    def __init__(self, _xmlui_parent, value, click_callback):
-        wx.Button.__init__(self, _xmlui_parent, -1, value)
-        self._xmlui_click_callback = click_callback
-        _xmlui_parent.Bind(wx.EVT_BUTTON, lambda evt: click_callback(evt.GetEventObject()), self)
-        self._xmlui_parent = _xmlui_parent
-
-    def _xmluiOnClick(self, callback):
-        self._xmlui_parent.Bind(wx.EVT_BUTTON, lambda evt: callback(evt.GetEventObject()), self)
-
-
-class ListWidget(EventWidget, WixWidget, xmlui.ListWidget, wx.ListBox):
-    _xmlui_change_event = wx.EVT_LISTBOX
-
-    def __init__(self, _xmlui_parent, options, selected, flags):
-        styles = wx.LB_MULTIPLE if not 'single' in flags else wx.LB_SINGLE
-        wx.ListBox.__init__(self, _xmlui_parent, -1, choices=[option[1] for option in options], style=styles)
-        self._xmlui_attr_map = {label: value for value, label in options}
-        self._xmlui_proportion = 1
-        self._xmluiSelectValues(selected)
-
-    def _xmluiSelectValue(self, value):
-        try:
-            label = [label for label, _value in self._xmlui_attr_map.items() if _value == value][0]
-        except IndexError:
-            log.warning(_("Can't find value [%s] to select" % value))
-            return
-        for idx in xrange(self.GetCount()):
-            self.SetSelection(idx, self.GetString(idx) == label)
-
-    def _xmluiSelectValues(self, values):
-        labels = [label for label, _value in self._xmlui_attr_map.items() if _value in values]
-        for idx in xrange(self.GetCount()):
-            self.SetSelection(idx, self.GetString(idx) in labels)
-
-    def _xmluiGetSelectedValues(self):
-        ret = []
-        labels = [self.GetString(idx) for idx in self.GetSelections()]
-        for label in labels:
-            ret.append(self._xmlui_attr_map[label])
-        return ret
-
-    def _xmluiAddValues(self, values, select=True):
-        selected = self._xmluiGetSelectedValues()
-        for value in values:
-            if value not in self._xmlui_attr_map.values():
-                wx.ListBox.Append(self, value)
-                self._xmlui_attr_map[value] = value
-            if value not in selected:
-                selected.append(value)
-        self._xmluiSelectValues(selected)
-
-
-class WixContainer(object):
-    _xmlui_proportion = 1
-
-    def _xmluiAppend(self, widget):
-        self.sizer.Add(widget, self._xmlui_proportion, flag=wx.EXPAND)
-
-
-class AdvancedListContainer(WixContainer, xmlui.AdvancedListContainer, wx.ScrolledWindow):
-
-    def __init__(self, _xmlui_parent, columns, selectable='no'):
-        wx.ScrolledWindow.__init__(self, _xmlui_parent)
-        self._xmlui_selectable = selectable != 'no'
-        if selectable:
-            columns += 1
-        self.sizer = wx.FlexGridSizer(cols=columns)
-        self.SetSizer(self.sizer)
-        self._xmlui_select_cb = None
-        self._xmlui_select_idx = None
-        self._xmlui_select_widgets = []
-
-    def _xmluiAddRow(self, idx):
-        # XXX: select_button is a Q&D way to implement row selection
-        # FIXME: must be done properly
-        if not self._xmlui_selectable:
-            return
-        select_button = wx.Button(self, wx.ID_OK, label=_("select"))
-        self.sizer.Add(select_button)
-        def click_cb(event, idx=idx):
-            cb = self._xmlui_select_cb
-            self._xmlui_select_idx = idx
-            # TODO: fill self._xmlui_select_widgets
-            if cb is not None:
-                cb(self)
-            event.Skip()
-        self.Bind(wx.EVT_BUTTON, click_cb)
-
-    def _xmluiGetSelectedWidgets(self):
-        return self._xmlui_select_widgets
-
-    def _xmluiGetSelectedIndex(self):
-        return self._xmlui_select_idx
-
-    def _xmluiOnSelect(self, callback):
-        self._xmlui_select_cb = callback
-
-class PairsContainer(WixContainer, xmlui.PairsContainer, wx.Panel):
-
-    def __init__(self, _xmlui_parent):
-        wx.Panel.__init__(self, _xmlui_parent)
-        self.sizer = wx.FlexGridSizer(cols=2)
-        self.sizer.AddGrowableCol(1) #The growable column need most of time to be the right one in pairs
-        self.SetSizer(self.sizer)
-
-
-class TabsContainer(WixContainer, xmlui.TabsContainer, wx.Notebook):
-
-    def __init__(self, _xmlui_parent):
-        wx.Notebook.__init__(self, _xmlui_parent, -1, style=wx.NB_LEFT if self._xmlui_main.type=='param' else 0)
-
-    def _xmluiAddTab(self, label):
-        tab_panel = wx.Panel(self, -1)
-        tab_panel.sizer = wx.BoxSizer(wx.VERTICAL)
-        tab_panel.SetSizer(tab_panel.sizer)
-        self.AddPage(tab_panel, label)
-        VerticalContainer._xmluiAdapt(tab_panel)
-        return tab_panel
-
-
-class VerticalContainer(WixContainer, xmlui.VerticalContainer, wx.Panel):
-
-    def __init__(self, _xmlui_parent):
-        wx.Panel.__init__(self, _xmlui_parent)
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self.sizer)
-
-
-## Dialogs ##
-
-
-class WixDialog(object):
-
-    def __init__(self, _xmlui_parent, level):
-        self.host = _xmlui_parent.host
-        self.ok_cb = None
-        self.cancel_cb = None
-        if level == C.XMLUI_DATA_LVL_INFO:
-            self.flags = wx.ICON_INFORMATION
-        elif level == C.XMLUI_DATA_LVL_ERROR:
-            self.flags = wx.ICON_ERROR
-        else:
-            self.flags = wx.ICON_INFORMATION
-            log.warning(_("Unmanaged dialog level: %s") % level)
-
-    def _xmluiShow(self):
-        answer = self.ShowModal()
-        if answer == wx.ID_YES or answer == wx.ID_OK:
-            self._xmluiValidated()
-        else:
-            self._xmluiCancelled()
-
-    def _xmluiClose(self):
-        self.Destroy()
-
-
-class MessageDialog(WixDialog, xmlui.MessageDialog, wx.MessageDialog):
-
-    def __init__(self, _xmlui_parent, title, message, level):
-        WixDialog.__init__(self, _xmlui_parent, level)
-        xmlui.MessageDialog.__init__(self, _xmlui_parent)
-        self.flags |= wx.OK
-        wx.MessageDialog.__init__(self, _xmlui_parent.host, message, title, style = self.flags)
-
-
-class NoteDialog(xmlui.NoteDialog, MessageDialog):
-    # TODO: separate NoteDialog
-    pass
-
-
-class ConfirmDialog(WixDialog, xmlui.ConfirmDialog, wx.MessageDialog):
-
-    def __init__(self, _xmlui_parent, title, message, level, buttons_set):
-        WixDialog.__init__(self, _xmlui_parent, level)
-        xmlui.ConfirmDialog.__init__(self, _xmlui_parent)
-        if buttons_set == C.XMLUI_DATA_BTNS_SET_YESNO:
-            self.flags |= wx.YES_NO
-        else:
-            self.flags |= wx.OK | wx.CANCEL
-        wx.MessageDialog.__init__(self, _xmlui_parent.host, message, title, style = self.flags)
-
-
-class FileDialog(WixDialog, xmlui.FileDialog, wx.FileDialog):
-
-    def __init__(self, _xmlui_parent, title, message, level, filetype):
-        # TODO: message and filetype are not managed yet
-        WixDialog.__init__(self, _xmlui_parent, level)
-        self.flags = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT # FIXME: use the legacy flags, but must manage cases like dir or open
-        xmlui.FileDialog.__init__(self, _xmlui_parent)
-        wx.FileDialog.__init__(self, _xmlui_parent.host, title, style = self.flags)
-
-    def _xmluiShow(self):
-        answer = self.ShowModal()
-        if answer == wx.ID_OK:
-            self._xmluiValidated({'path': self.GetPath()})
-        else:
-            self._xmluiCancelled()
-
-
-class GenericFactory(object):
-
-    def __getattr__(self, attr):
-        if attr.startswith("create"):
-            cls = globals()[attr[6:]]
-            return cls
-
-
-class WidgetFactory(GenericFactory):
-
-    def __getattr__(self, attr):
-        if attr.startswith("create"):
-            cls = GenericFactory.__getattr__(self, attr)
-            cls._xmlui_main = self._xmlui_main
-            return cls
-
-
-class XMLUIPanel(xmlui.XMLUIPanel, wx.Frame):
-    """Create an user interface from a SàT XML"""
-    widget_factory = WidgetFactory()
-
-    def __init__(self, host, parsed_xml, title=None, flags = None,):
-        self.widget_factory._xmlui_main = self
-        xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags)
-
-    def constructUI(self, parsed_dom):
-        style = wx.DEFAULT_FRAME_STYLE & ~wx.CLOSE_BOX if 'NO_CANCEL' in self.flags else wx.DEFAULT_FRAME_STYLE
-        wx.Frame.__init__(self, None, style=style)
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self.sizer)
-
-        def postTreat():
-            if self.title:
-                self.SetTitle(self.title)
-
-            if self.type == 'form':
-                dialogButtons = wx.StdDialogButtonSizer()
-                submitButton = wx.Button(self.main_cont,wx.ID_OK, label=_("Submit"))
-                dialogButtons.AddButton(submitButton)
-                self.main_cont.Bind(wx.EVT_BUTTON, self.onFormSubmitted, submitButton)
-                if not 'NO_CANCEL' in self.flags:
-                    cancelButton = wx.Button(self.main_cont,wx.ID_CANCEL)
-                    dialogButtons.AddButton(cancelButton)
-                    self.main_cont.Bind(wx.EVT_BUTTON, self.onFormCancelled, cancelButton)
-                dialogButtons.Realize()
-                self.main_cont.sizer.Add(dialogButtons, flag=wx.ALIGN_CENTER_HORIZONTAL)
-
-            self.sizer.Add(self.main_cont, 1, flag=wx.EXPAND)
-            self.sizer.Fit(self)
-            self.Show()
-
-        super(XMLUIPanel, self).constructUI(parsed_dom, postTreat)
-        if not 'NO_CANCEL' in self.flags:
-            self.Bind(wx.EVT_CLOSE, self.onClose, self)
-        self.MakeModal()
-
-    def _xmluiClose(self):
-        self.MakeModal(False)
-        self.Destroy()
-
-    ###events
-
-    def onParamChange(self, ctrl):
-        super(XMLUIPanel, self).onParamChange(ctrl)
-
-    def onFormSubmitted(self, event):
-        """Called when submit button is clicked"""
-        button = event.GetEventObject()
-        super(XMLUIPanel, self).onFormSubmitted(button)
-
-    def onClose(self, event):
-        """Close event: we have to send the form."""
-        log.debug(_("close"))
-        if self.type == 'param':
-            self.onSaveParams()
-        else:
-            self._xmluiClose()
-        event.Skip()
-
-
-class XMLUIDialog(xmlui.XMLUIDialog):
-    dialog_factory = WidgetFactory()
-
-
-xmlui.registerClass(xmlui.CLASS_PANEL, XMLUIPanel)
-xmlui.registerClass(xmlui.CLASS_DIALOG, XMLUIDialog)
-create = xmlui.create