diff --git a/frontends/src/wix/__init__.py b/frontends/src/wix/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/frontends/src/wix/card_game.py b/frontends/src/wix/card_game.py
deleted file mode 100644
index 45b74a50..00000000
--- a/frontends/src/wix/card_game.py
+++ /dev/null
@@ -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 .
-
-
-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()
-
-
diff --git a/frontends/src/wix/chat.py b/frontends/src/wix/chat.py
deleted file mode 100644
index fd51c73d..00000000
--- a/frontends/src/wix/chat.py
+++ /dev/null
@@ -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 .
-
-
-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
diff --git a/frontends/src/wix/constants.py b/frontends/src/wix/constants.py
deleted file mode 100644
index 546458d4..00000000
--- a/frontends/src/wix/constants.py
+++ /dev/null
@@ -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 .
-
-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()
diff --git a/frontends/src/wix/contact_list.py b/frontends/src/wix/contact_list.py
deleted file mode 100644
index dcab9596..00000000
--- a/frontends/src/wix/contact_list.py
+++ /dev/null
@@ -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 .
-
-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 tag
-
- html = """
-
-
-
- |
-
- %s %s
- %s
- |
-
- """ % (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
-
diff --git a/frontends/src/wix/main_window.py b/frontends/src/wix/main_window.py
deleted file mode 100644
index fd3d4ad3..00000000
--- a/frontends/src/wix/main_window.py
+++ /dev/null
@@ -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 .
-
-
-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()
diff --git a/frontends/src/wix/profile.py b/frontends/src/wix/profile.py
deleted file mode 100644
index 702f796a..00000000
--- a/frontends/src/wix/profile.py
+++ /dev/null
@@ -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 .
-
-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()
-
diff --git a/frontends/src/wix/profile_manager.py b/frontends/src/wix/profile_manager.py
deleted file mode 100644
index f574fca3..00000000
--- a/frontends/src/wix/profile_manager.py
+++ /dev/null
@@ -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 .
-
-
-
-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()
diff --git a/frontends/src/wix/quiz_game.py b/frontends/src/wix/quiz_game.py
deleted file mode 100644
index cba903c8..00000000
--- a/frontends/src/wix/quiz_game.py
+++ /dev/null
@@ -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 .
-
-
-
-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()
diff --git a/frontends/src/wix/wix b/frontends/src/wix/wix
deleted file mode 100755
index c1d83a51..00000000
--- a/frontends/src/wix/wix
+++ /dev/null
@@ -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 .
-
-
-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()
diff --git a/frontends/src/wix/xmlui.py b/frontends/src/wix/xmlui.py
deleted file mode 100644
index 921ffd90..00000000
--- a/frontends/src/wix/xmlui.py
+++ /dev/null
@@ -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 .
-
-
-
-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