Files reorganisation
This commit is contained in:
parent
c8b5f1db90
commit
e4452c4b03
8 changed files with 10 additions and 8 deletions
0
frontends/src/quick_frontend/__init__.py
Normal file
0
frontends/src/quick_frontend/__init__.py
Normal file
437
frontends/src/quick_frontend/quick_app.py
Normal file
437
frontends/src/quick_frontend/quick_app.py
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from logging import debug, info, error
|
||||
from tools.jid import JID
|
||||
from sat_bridge_frontend.DBus import DBusBridgeFrontend,BridgeExceptionNoService
|
||||
from optparse import OptionParser
|
||||
import pdb
|
||||
|
||||
import gettext
|
||||
gettext.install('sat_frontend', "../i18n", unicode=True)
|
||||
|
||||
class QuickApp():
|
||||
"""This class contain the main methods needed for the frontend"""
|
||||
|
||||
def __init__(self, single_profile=True):
|
||||
self.rosterList = {}
|
||||
self.profiles = {}
|
||||
self.single_profile = single_profile
|
||||
self.check_options()
|
||||
|
||||
## bridge ##
|
||||
try:
|
||||
self.bridge=DBusBridgeFrontend()
|
||||
except BridgeExceptionNoService:
|
||||
print(_(u"Can't connect to SàT backend, are you sure it's launched ?"))
|
||||
import sys
|
||||
sys.exit(1)
|
||||
self.bridge.register("connected", self.connected)
|
||||
self.bridge.register("disconnected", self.disconnected)
|
||||
self.bridge.register("newContact", self.newContact)
|
||||
self.bridge.register("newMessage", self.newMessage)
|
||||
self.bridge.register("newAlert", self.newAlert)
|
||||
self.bridge.register("presenceUpdate", self.presenceUpdate)
|
||||
self.bridge.register("roomJoined", self.roomJoined)
|
||||
self.bridge.register("roomUserJoined", self.roomUserJoined)
|
||||
self.bridge.register("roomUserLeft", self.roomUserLeft)
|
||||
self.bridge.register("roomNewSubject", self.roomNewSubject)
|
||||
self.bridge.register("tarotGameStarted", self.tarotGameStarted)
|
||||
self.bridge.register("tarotGameNew", self.tarotGameNew)
|
||||
self.bridge.register("tarotGameChooseContrat", self.tarotChooseContrat)
|
||||
self.bridge.register("tarotGameShowCards", self.tarotShowCards)
|
||||
self.bridge.register("tarotGameYourTurn", self.tarotMyTurn)
|
||||
self.bridge.register("tarotGameScore", self.tarotScore)
|
||||
self.bridge.register("tarotGameCardsPlayed", self.tarotCardsPlayed)
|
||||
self.bridge.register("tarotGameInvalidCards", self.tarotInvalidCards)
|
||||
self.bridge.register("subscribe", self.subscribe)
|
||||
self.bridge.register("paramUpdate", self.paramUpdate)
|
||||
self.bridge.register("contactDeleted", self.contactDeleted)
|
||||
self.bridge.register("updatedValue", self.updatedValue, "request")
|
||||
self.bridge.register("askConfirmation", self.askConfirmation, "request")
|
||||
self.bridge.register("actionResult", self.actionResult, "request")
|
||||
self.bridge.register("actionResultExt", self.actionResult, "request")
|
||||
|
||||
self.current_action_ids = set()
|
||||
self.current_action_ids_cb = {}
|
||||
|
||||
def check_profile(self, profile):
|
||||
"""Tell if the profile is currently followed by the application"""
|
||||
return profile in self.profiles.keys()
|
||||
|
||||
def postInit(self):
|
||||
"""Must be called after initialization is done, do all automatic task (auto plug profile)"""
|
||||
if self.options.profile:
|
||||
if not self.bridge.getProfileName(self.options.profile):
|
||||
error(_("Trying to plug an unknown profile (%s)" % self.options.profile))
|
||||
else:
|
||||
self.plug_profile(self.options.profile)
|
||||
|
||||
def check_options(self):
|
||||
"""Check command line options"""
|
||||
usage=_("""
|
||||
%prog [options]
|
||||
|
||||
%prog --help for options list
|
||||
""")
|
||||
parser = OptionParser(usage=usage)
|
||||
|
||||
parser.add_option("-p", "--profile", help=_("Select the profile to use"))
|
||||
|
||||
(self.options, args) = parser.parse_args()
|
||||
if self.options.profile:
|
||||
self.options.profile = self.options.profile.decode('utf-8')
|
||||
return args
|
||||
|
||||
def plug_profile(self, profile_key='@DEFAULT@'):
|
||||
"""Tell application which profile must be used"""
|
||||
if self.single_profile and self.profiles:
|
||||
error(_('There is already one profile plugged (we are in single profile mode) !'))
|
||||
return
|
||||
profile = self.bridge.getProfileName(profile_key)
|
||||
if not profile:
|
||||
error(_("The profile asked doesn't exist"))
|
||||
return
|
||||
if self.profiles.has_key(profile):
|
||||
warning(_("The profile is already plugged"))
|
||||
return
|
||||
self.profiles[profile]={}
|
||||
if self.single_profile:
|
||||
self.profile = profile
|
||||
|
||||
###now we get the essential params###
|
||||
self.profiles[profile]['whoami']=JID(self.bridge.getParamA("JabberID","Connection", profile))
|
||||
autoconnect = self.bridge.getParamA("autoconnect","Connection", profile) == "true"
|
||||
self.profiles[profile]['watched']=self.bridge.getParamA("Watched", "Misc", profile).split() #TODO: put this in a plugin
|
||||
|
||||
## misc ##
|
||||
self.profiles[profile]['onlineContact'] = set() #FIXME: temporary
|
||||
|
||||
#TODO: gof: manage multi-profiles here
|
||||
if not self.bridge.isConnected(profile):
|
||||
self.setStatusOnline(False)
|
||||
else:
|
||||
self.setStatusOnline(True)
|
||||
|
||||
### now we fill the contact list ###
|
||||
for contact in self.bridge.getContacts(profile):
|
||||
self.newContact(contact[0], contact[1], contact[2], profile)
|
||||
|
||||
presences = self.bridge.getPresenceStatus(profile)
|
||||
for contact in presences:
|
||||
for res in presences[contact]:
|
||||
jabber_id = contact+('/'+res if res else '')
|
||||
show = presences[contact][res][0]
|
||||
priority = presences[contact][res][1]
|
||||
statuses = presences[contact][res][2]
|
||||
self.presenceUpdate(jabber_id, show, priority, statuses, profile)
|
||||
|
||||
#The waiting subscription requests
|
||||
waitingSub = self.bridge.getWaitingSub(profile)
|
||||
for sub in waitingSub:
|
||||
self.subscribe(waitingSub[sub], sub, profile)
|
||||
|
||||
#Now we open the MUC window where we already are:
|
||||
for room_args in self.bridge.getRoomJoined(profile):
|
||||
self.roomJoined(*room_args, profile=profile)
|
||||
|
||||
for subject_args in self.bridge.getRoomSubjects(profile):
|
||||
self.roomNewSubject(*subject_args, profile=profile)
|
||||
|
||||
if autoconnect and not self.bridge.isConnected(profile_key):
|
||||
#Does the user want autoconnection ?
|
||||
self.bridge.connect(profile_key)
|
||||
|
||||
|
||||
def unplug_profile(self, profile):
|
||||
"""Tell the application to not follow anymore the profile"""
|
||||
if not profile in self.profiles:
|
||||
warning (_("This profile is not plugged"))
|
||||
return
|
||||
self.profiles.remove(profile)
|
||||
|
||||
def clear_profile(self):
|
||||
self.profiles.clear()
|
||||
|
||||
def connected(self, profile):
|
||||
"""called when the connection is made"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug(_("Connected"))
|
||||
self.setStatusOnline(True)
|
||||
|
||||
|
||||
def disconnected(self, profile):
|
||||
"""called when the connection is closed"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug(_("Disconnected"))
|
||||
self.CM.clear()
|
||||
self.contactList.clear_contacts()
|
||||
self.setStatusOnline(False)
|
||||
|
||||
def newContact(self, JabberId, attributes, groups, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
entity=JID(JabberId)
|
||||
self.rosterList[entity.short]=(dict(attributes), list(groups))
|
||||
|
||||
def newMessage(self, from_jid, msg, type, to_jid, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
sender=JID(from_jid)
|
||||
addr=JID(to_jid)
|
||||
win = addr if sender.short == self.profiles[profile]['whoami'].short else sender
|
||||
self.current_action_ids = set()
|
||||
self.current_action_ids_cb = {}
|
||||
self.chat_wins[win.short].printMessage(sender, msg, profile)
|
||||
|
||||
def newAlert(self, msg, title, alert_type, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
assert alert_type in ['INFO','ERROR']
|
||||
self.showDialog(unicode(msg),unicode(title),alert_type.lower())
|
||||
|
||||
|
||||
def setStatusOnline(self, online=True):
|
||||
pass
|
||||
|
||||
def presenceUpdate(self, jabber_id, show, priority, statuses, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("presence update for %(jid)s (show=%(show)s, priority=%(priority)s, statuses=%(statuses)s) [profile:%(profile)s]") % {'jid':jabber_id, 'show':show, 'priority':priority, 'statuses':statuses, 'profile':profile});
|
||||
from_jid=JID(jabber_id)
|
||||
debug ("from_jid.short=%(from_jid)s whoami.short=%(whoami)s" % {'from_jid':from_jid.short, 'whoami':self.profiles[profile]['whoami'].short})
|
||||
|
||||
if from_jid.short==self.profiles[profile]['whoami'].short:
|
||||
if not type:
|
||||
self.setStatusOnline(True)
|
||||
elif type=="unavailable":
|
||||
self.setStatusOnline(False)
|
||||
return
|
||||
|
||||
if show != 'unavailable':
|
||||
name=""
|
||||
groups = []
|
||||
if self.rosterList.has_key(from_jid.short):
|
||||
if self.rosterList[from_jid.short][0].has_key("name"):
|
||||
name=self.rosterList[from_jid.short][0]["name"]
|
||||
groups=self.rosterList[from_jid.short][1]
|
||||
|
||||
#FIXME: must be moved in a plugin
|
||||
if from_jid.short in self.profiles[profile]['watched'] and not from_jid.short in self.profiles[profile]['onlineContact']:
|
||||
self.showAlert(_("Watched jid [%s] is connected !") % from_jid.short)
|
||||
|
||||
self.profiles[profile]['onlineContact'].add(from_jid) #FIXME onlineContact is useless with CM, must be removed
|
||||
self.CM.add(from_jid)
|
||||
self.CM.update(from_jid, 'name', name)
|
||||
self.CM.update(from_jid, 'show', show)
|
||||
self.CM.update(from_jid, 'statuses', statuses)
|
||||
self.CM.update(from_jid, 'groups', groups)
|
||||
cache = self.bridge.getCardCache(from_jid)
|
||||
if cache.has_key('nick'):
|
||||
self.CM.update(from_jid, 'nick', cache['nick'])
|
||||
if cache.has_key('avatar'):
|
||||
self.CM.update(from_jid, 'avatar', self.bridge.getAvatarFile(cache['avatar']))
|
||||
self.contactList.replace(from_jid, self.CM.getAttr(from_jid, 'groups'))
|
||||
|
||||
if show=="unavailable" and from_jid in self.profiles[profile]['onlineContact']:
|
||||
self.profiles[profile]['onlineContact'].remove(from_jid)
|
||||
self.CM.remove(from_jid)
|
||||
if not self.CM.isConnected(from_jid):
|
||||
self.contactList.disconnect(from_jid)
|
||||
|
||||
def roomJoined(self, room_id, room_service, room_nicks, user_nick, profile):
|
||||
"""Called when a MUC room is joined"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Room [%(room_name)s] joined by %(profile)s, users presents:%(users)s") % {'room_name':room_id+'@'+room_service, 'profile': profile, 'users':room_nicks})
|
||||
room_jid=room_id+'@'+room_service
|
||||
self.chat_wins[room_jid].setUserNick(user_nick)
|
||||
self.chat_wins[room_jid].setType("group")
|
||||
self.chat_wins[room_jid].id = room_jid
|
||||
self.chat_wins[room_jid].setPresents(list(set([user_nick]+room_nicks)))
|
||||
|
||||
|
||||
def roomUserJoined(self, room_id, room_service, user_nick, user_data, profile):
|
||||
"""Called when an user joined a MUC room"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
room_jid=room_id+'@'+room_service
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].replaceUser(user_nick)
|
||||
debug (_("user [%(user_nick)s] joined room [%(room_jid)s]") % {'user_nick':user_nick, 'room_jid':room_jid})
|
||||
|
||||
def roomUserLeft(self, room_id, room_service, user_nick, user_data, profile):
|
||||
"""Called when an user joined a MUC room"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
room_jid=room_id+'@'+room_service
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].removeUser(user_nick)
|
||||
debug (_("user [%(user_nick)s] left room [%(room_jid)s]") % {'user_nick':user_nick, 'room_jid':room_jid})
|
||||
|
||||
def roomNewSubject(self, room_id, room_service, subject, profile):
|
||||
"""Called when subject of MUC room change"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
room_jid=room_id+'@'+room_service
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].setSubject(subject)
|
||||
debug (_("new subject for room [%(room_jid)s]: %(subject)s") % {'room_jid':room_jid, "subject":subject})
|
||||
|
||||
def tarotGameStarted(self, room_jid, referee, players, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Tarot Game Started \o/"))
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].startGame("Tarot", referee, players)
|
||||
debug (_("new Tarot game started by [%(referee)s] in room [%(room_jid)s] with %(players)s") % {'referee':referee, 'room_jid':room_jid, 'players':[str(player) for player in players]})
|
||||
|
||||
def tarotGameNew(self, room_jid, hand, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("New Tarot Game"))
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].getGame("Tarot").newGame(hand)
|
||||
|
||||
def tarotChooseContrat(self, room_jid, xml_data, profile):
|
||||
"""Called when the player has to select his contrat"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Tarot: need to select a contrat"))
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].getGame("Tarot").chooseContrat(xml_data)
|
||||
|
||||
def tarotShowCards(self, room_jid, game_stage, cards, data, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Show cards"))
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].getGame("Tarot").showCards(game_stage, cards, data)
|
||||
|
||||
def tarotMyTurn(self, room_jid, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("My turn to play"))
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].getGame("Tarot").myTurn()
|
||||
|
||||
def tarotScore(self, room_jid, xml_data, winners, loosers, profile):
|
||||
"""Called when the game is finished and the score are updated"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Tarot: score received"))
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].getGame("Tarot").showScores(xml_data, winners, loosers)
|
||||
|
||||
def tarotCardsPlayed(self, room_jid, player, cards, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Card(s) played (%(player)s): %(cards)s") % {"player":player, "cards":cards})
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].getGame("Tarot").cardsPlayed(player, cards)
|
||||
|
||||
def tarotInvalidCards(self, room_jid, phase, played_cards, invalid_cards, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Cards played are not valid: %s") % invalid_cards)
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].getGame("Tarot").invalidCards(phase, played_cards, invalid_cards)
|
||||
|
||||
def _subscribe_cb(self, answer, data):
|
||||
entity, profile = data
|
||||
if answer:
|
||||
self.bridge.subscription("subscribed", entity.short, profile_key = profile)
|
||||
else:
|
||||
self.bridge.subscription("unsubscribed", entity.short, profile_key = profile)
|
||||
|
||||
def subscribe(self, type, raw_jid, profile):
|
||||
"""Called when a subsciption management signal is received"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
entity = JID(raw_jid)
|
||||
if type=="subscribed":
|
||||
# this is a subscription confirmation, we just have to inform user
|
||||
self.showDialog(_("The contact %s has accepted your subscription") % entity.short, _('Subscription confirmation'))
|
||||
elif type=="unsubscribed":
|
||||
# this is a subscription refusal, we just have to inform user
|
||||
self.showDialog(_("The contact %s has refused your subscription") % entity.short, _('Subscription refusal'), 'error')
|
||||
elif type=="subscribe":
|
||||
# this is a subscriptionn request, we have to ask for user confirmation
|
||||
answer = self.showDialog(_("The contact %s wants to subscribe to your presence.\nDo you accept ?") % entity.short, _('Subscription confirmation'), 'yes/no', answer_cb = self._subscribe_cb, answer_data=(entity, profile))
|
||||
|
||||
def showDialog(self, message, title, type="info", answer_cb = None):
|
||||
raise NotImplementedError
|
||||
|
||||
def showAlert(self, message):
|
||||
pass #FIXME
|
||||
|
||||
def paramUpdate(self, name, value, namespace, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug(_("param update: [%(namespace)s] %(name)s = %(value)s") % {'namespace':namespace, 'name':name, 'value':value})
|
||||
if (namespace,name) == ("Connection", "JabberID"):
|
||||
debug (_("Changing JID to %s"), value)
|
||||
self.profiles[profile]['whoami']=JID(value)
|
||||
elif (namespace,name) == ("Misc", "Watched"):
|
||||
self.profiles[profile]['watched']=value.split()
|
||||
|
||||
def contactDeleted(self, jid, profile):
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
target = JID(jid)
|
||||
self.CM.remove(target)
|
||||
self.contactList.remove(self.CM.get_full(target))
|
||||
try:
|
||||
self.profiles[profile]['onlineContact'].remove(target.short)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def updatedValue(self, name, data):
|
||||
if name == "card_nick":
|
||||
target = JID(data['jid'])
|
||||
if target in self.contactList:
|
||||
self.CM.update(target, 'nick', data['nick'])
|
||||
self.contactList.replace(target)
|
||||
elif name == "card_avatar":
|
||||
target = JID(data['jid'])
|
||||
if target in self.contactList:
|
||||
filename = self.bridge.getAvatarFile(data['avatar'])
|
||||
self.CM.update(target, 'avatar', filename)
|
||||
self.contactList.replace(target)
|
||||
|
||||
def askConfirmation(self, type, id, data):
|
||||
raise NotImplementedError
|
||||
|
||||
def actionResult(self, type, id, data):
|
||||
raise NotImplementedError
|
||||
|
||||
def onExit(self):
|
||||
"""Must be called when the frontend is terminating"""
|
||||
#TODO: mange multi-profile here
|
||||
try:
|
||||
autodisconnect = self.bridge.getParamA("autodisconnect","Connection", self.profile) == "true"
|
||||
if autodisconnect and self.bridge.isConnected(self.profile):
|
||||
#Does the user want autodisconnection ?
|
||||
self.bridge.disconnect(self.profile)
|
||||
except:
|
||||
pass
|
||||
156
frontends/src/quick_frontend/quick_card_game.py
Normal file
156
frontends/src/quick_frontend/quick_card_game.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from logging import debug, info, error
|
||||
from tools.jid import JID
|
||||
|
||||
|
||||
|
||||
class QuickCardGame():
|
||||
|
||||
def __init__(self, parent, referee, players, player_nick):
|
||||
self._autoplay = None #XXX: use 0 to activate fake play, None else
|
||||
self.parent = parent
|
||||
self.referee = referee
|
||||
self.players = players
|
||||
self.played = {}
|
||||
for player in players:
|
||||
self.played[player] = None
|
||||
self.player_nick = player_nick
|
||||
self.bottom_nick = unicode(self.player_nick)
|
||||
idx = self.players.index(self.player_nick)
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.right_nick = unicode(self.players[idx])
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.top_nick = unicode(self.players[idx])
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.left_nick = unicode(self.players[idx])
|
||||
self.bottom_nick = unicode(player_nick)
|
||||
self.selected = [] #Card choosed by the player (e.g. during ecart)
|
||||
self.hand_size = 13 #number of cards in a hand
|
||||
self.hand = []
|
||||
self.to_show = []
|
||||
self.state = None
|
||||
|
||||
def getPlayerLocation(self, nick):
|
||||
"""return player location (top,bottom,left or right)"""
|
||||
for location in ['top','left','bottom','right']:
|
||||
if getattr(self,'%s_nick' % location) == nick:
|
||||
return location
|
||||
assert(False)
|
||||
|
||||
def loadCards(self):
|
||||
"""Load all the cards in memory
|
||||
@param dir: directory where the PNG files are"""
|
||||
self.cards={}
|
||||
self.deck=[]
|
||||
self.cards["atout"]={} #As Tarot is a french game, it's more handy & logical to keep french names
|
||||
self.cards["pique"]={} #spade
|
||||
self.cards["coeur"]={} #heart
|
||||
self.cards["carreau"]={} #diamond
|
||||
self.cards["trefle"]={} #club
|
||||
|
||||
def newGame(self, hand):
|
||||
"""Start a new game, with given hand"""
|
||||
assert (len(self.hand) == 0)
|
||||
for suit, value in hand:
|
||||
self.hand.append(self.cards[suit, value])
|
||||
self.hand.sort()
|
||||
self.state = "init"
|
||||
|
||||
def contratSelected(self, contrat):
|
||||
"""Called when the contrat has been choosed
|
||||
@param data: form result"""
|
||||
self.parent.host.bridge.tarotGameContratChoosed(self.player_nick, self.referee, contrat or 'Passe', self.parent.host.profile)
|
||||
|
||||
def chooseContrat(self, xml_data):
|
||||
"""Called when the player as to select his contrat
|
||||
@param xml_data: SàT xml representation of the form"""
|
||||
raise NotImplementedError
|
||||
|
||||
def showCards(self, game_stage, cards, data):
|
||||
"""Display cards in the middle of the game (to show for e.g. chien ou poignée)"""
|
||||
self.to_show = []
|
||||
for suit, value in cards:
|
||||
self.to_show.append(self.cards[suit, value])
|
||||
if game_stage == "chien" and data['attaquant'] == self.player_nick:
|
||||
self.state = "wait_for_ecart"
|
||||
else:
|
||||
self.state = "chien"
|
||||
|
||||
def myTurn(self):
|
||||
"""Called when we have to play :)"""
|
||||
if self.state == "chien":
|
||||
self.to_show = []
|
||||
self.state = "play"
|
||||
self.__fakePlay()
|
||||
|
||||
def __fakePlay(self):
|
||||
"""Convenience method for stupid autoplay
|
||||
/!\ don't forgot to comment any interactive dialog for invalid card"""
|
||||
if self._autoplay == None:
|
||||
return
|
||||
if self._autoplay >= len(self.hand):
|
||||
self._autoplay = 0
|
||||
card = self.hand[self._autoplay]
|
||||
self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], profile_key = self.parent.host.profile)
|
||||
del self.hand[self._autoplay]
|
||||
self.state = "wait"
|
||||
self._autoplay+=1
|
||||
|
||||
def showScores(self, xml_data, winners, loosers):
|
||||
"""Called at the end of a game
|
||||
@param xml_data: SàT xml representation of the scores
|
||||
@param winners: list of winners' nicks
|
||||
@param loosers: list of loosers' nicks"""
|
||||
raise NotImplementedError
|
||||
|
||||
def cardsPlayed(self, player, cards):
|
||||
"""A card has been played by player"""
|
||||
if self.to_show:
|
||||
self.to_show = []
|
||||
pl_cards = []
|
||||
if self.played[player] != None: #FIXME
|
||||
for pl in self.played:
|
||||
self.played[pl] = None
|
||||
for suit, value in cards:
|
||||
pl_cards.append(self.cards[suit, value])
|
||||
self.played[player] = pl_cards[0]
|
||||
|
||||
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"""
|
||||
|
||||
if phase == "play":
|
||||
self.state = "play"
|
||||
elif phase == "ecart":
|
||||
self.state = "ecart"
|
||||
else:
|
||||
error ('INTERNAL ERROR: unmanaged game phase')
|
||||
|
||||
for suit, value in played_cards:
|
||||
self.hand.append(self.cards[suit, value])
|
||||
|
||||
self.hand.sort()
|
||||
self.__fakePlay()
|
||||
|
||||
127
frontends/src/quick_frontend/quick_chat.py
Normal file
127
frontends/src/quick_frontend/quick_chat.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from logging import debug, info, warning, error
|
||||
from tools.jid import JID
|
||||
|
||||
|
||||
|
||||
class QuickChat():
|
||||
|
||||
def __init__(self, target, host, type='one2one'):
|
||||
self.target = target
|
||||
self.host = host
|
||||
self.type = type
|
||||
self.id = ""
|
||||
self.nick = None
|
||||
self.occupants = set()
|
||||
|
||||
def setType(self, type):
|
||||
"""Set the type of the chat
|
||||
@param type: can be 'one2one' for single conversation or 'group' for chat à la IRC
|
||||
"""
|
||||
self.type = type
|
||||
|
||||
def setPresents(self, nicks):
|
||||
"""Set the users presents in the contact list for a group chat
|
||||
@param nicks: list of nicknames
|
||||
"""
|
||||
debug (_("Adding users %s to room") % nicks)
|
||||
if self.type != "group":
|
||||
error (_("[INTERNAL] trying to set presents nicks for a non group chat window"))
|
||||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
self.occupants.update(nicks)
|
||||
|
||||
def replaceUser(self, nick):
|
||||
"""Add user if it is not in the group list"""
|
||||
debug (_("Replacing user %s") % nick)
|
||||
if self.type != "group":
|
||||
error (_("[INTERNAL] trying to replace user for a non group chat window"))
|
||||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
len_before = len(self.occupants)
|
||||
self.occupants.add(nick)
|
||||
if len_before != len(self.occupants):
|
||||
self.printInfo("=> %s has joined the room" % nick)
|
||||
|
||||
def setUserNick(self, nick):
|
||||
"""Set the nick of the user, usefull for e.g. change the color of the user"""
|
||||
self.nick = nick
|
||||
|
||||
def removeUser(self, nick):
|
||||
"""Remove a user from the group list"""
|
||||
debug(_("Removing user %s") % nick)
|
||||
if self.type != "group":
|
||||
error (_("[INTERNAL] trying to remove user for a non group chat window"))
|
||||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
self.occupants.remove(nick)
|
||||
self.printInfo("<= %s has left the room" % nick)
|
||||
|
||||
def setSubject(self, subject):
|
||||
"""Set title for a group chat"""
|
||||
debug(_("Setting subject to %s") % subject)
|
||||
if self.type != "group":
|
||||
error (_("[INTERNAL] trying to set subject for a non group chat window"))
|
||||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
|
||||
def historyPrint(self, size=20, keep_last=False, profile='@NONE@'):
|
||||
"""Print the initial history"""
|
||||
debug (_("now we print history"))
|
||||
history=self.host.bridge.getHistory(self.host.profiles[profile]['whoami'].short, self.target, 20)
|
||||
stamps=history.keys()
|
||||
stamps.sort()
|
||||
for stamp in stamps:
|
||||
self.printMessage(JID(history[stamp][0]), history[stamp][1], profile, stamp)
|
||||
if keep_last: ##FIXME hack for sortilege
|
||||
self.last_history = stamps[-1] if stamps else None
|
||||
|
||||
def _get_nick(self, jid):
|
||||
"""Return nick of this jid when possible"""
|
||||
return jid.resource if self.type == "group" else (self.host.CM.getAttr(jid,'nick') or self.host.CM.getAttr(jid,'name') or jid.node)
|
||||
|
||||
def printMessage(self, from_jid, msg, profile, timestamp):
|
||||
"""Print message in chat window. Must be implemented by child class"""
|
||||
jid=JID(from_jid)
|
||||
nick = self._get_nick(jid)
|
||||
mymess = (jid.resource == self.nick) if self.type == "group" else (jid.short == self.host.profiles[profile]['whoami'].short) #mymess = True if message comes from local user
|
||||
if msg.startswith('/me '):
|
||||
self.printInfo('* %s %s' % (nick, msg[4:]),type='me')
|
||||
return
|
||||
return jid, nick, mymess
|
||||
|
||||
def printInfo(self, msg, type='normal'):
|
||||
"""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"
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def startGame(self, game_type, referee, players):
|
||||
"""Configure the chat window to start a game"""
|
||||
#No need to raise an error as game are not mandatory
|
||||
warning(_('startGame is not implemented in this frontend'))
|
||||
|
||||
def getGame(self, game_type):
|
||||
"""Return class managing the game type"""
|
||||
#No need to raise an error as game are not mandatory
|
||||
warning(_('getGame is not implemented in this frontend'))
|
||||
41
frontends/src/quick_frontend/quick_chat_list.py
Normal file
41
frontends/src/quick_frontend/quick_chat_list.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from tools.jid import JID
|
||||
|
||||
|
||||
class QuickChatList(dict):
|
||||
"""This class is used to manage the list of chat windows.
|
||||
It act as a dict, but create a chat window when the name is found for the first time."""
|
||||
|
||||
def __init__(self, host):
|
||||
dict.__init__(self)
|
||||
self.host = host
|
||||
|
||||
def __getitem__(self,to_jid):
|
||||
target=JID(to_jid)
|
||||
if not self.has_key(target.short):
|
||||
#we have to create the chat win
|
||||
self[target.short] = self.createChat(target)
|
||||
return dict.__getitem__(self,target.short)
|
||||
|
||||
def createChat(self, target):
|
||||
raise NotImplementedError
|
||||
57
frontends/src/quick_frontend/quick_contact_list.py
Normal file
57
frontends/src/quick_frontend/quick_contact_list.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from logging import debug, info, error
|
||||
from tools.jid import JID
|
||||
|
||||
|
||||
class QuickContactList():
|
||||
"""This class manage the visual representation of contacts"""
|
||||
|
||||
def __init__(self, CM):
|
||||
"""
|
||||
@param CM: instance of QuickContactManagement
|
||||
"""
|
||||
debug(_("Contact List init"))
|
||||
self.CM = CM
|
||||
|
||||
def __contains__(self, jid):
|
||||
raise NotImplementedError
|
||||
|
||||
def clear_contacts(self, jid):
|
||||
"""Clear all the contact list"""
|
||||
raise NotImplementedError
|
||||
|
||||
def replace(self, jid, groups=None):
|
||||
"""add a contact to the list if doesn't exist, else update it"""
|
||||
raise NotImplementedError
|
||||
|
||||
def disconnect(self, jid):
|
||||
"""mark a contact disconnected"""
|
||||
raise NotImplementedError
|
||||
|
||||
def remove(self, jid):
|
||||
"""remove a contact from the list"""
|
||||
raise NotImplementedError
|
||||
|
||||
def add(self, jid, param_groups=None):
|
||||
"""add a contact to the list"""
|
||||
raise NotImplementedError
|
||||
99
frontends/src/quick_frontend/quick_contact_management.py
Normal file
99
frontends/src/quick_frontend/quick_contact_management.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from logging import debug, info, warning, error
|
||||
from tools.jid import JID
|
||||
import pdb
|
||||
|
||||
|
||||
class QuickContactManagement():
|
||||
"""This helper class manage the contacts and ease the use of nicknames and shortcuts"""
|
||||
### FIXME: is SàT a better place for all this stuff ??? ###
|
||||
|
||||
def __init__(self):
|
||||
self.__contactlist = {}
|
||||
|
||||
def clear(self):
|
||||
"""Clear all the contact list"""
|
||||
self.__contactlist.clear()
|
||||
|
||||
def add(self, entity):
|
||||
"""Add contact to the list, update resources"""
|
||||
if not self.__contactlist.has_key(entity.short):
|
||||
self.__contactlist[entity.short] = {'resources':[]}
|
||||
if entity.resource in self.__contactlist[entity.short]['resources']:
|
||||
self.__contactlist[entity.short]['resources'].remove(entity.resource)
|
||||
self.__contactlist[entity.short]['resources'].append(entity.resource)
|
||||
|
||||
def getContFromGroup(self, group):
|
||||
"""Return all contacts which are in given group"""
|
||||
result = []
|
||||
for contact in self.__contactlist:
|
||||
if self.__contactlist[contact].has_key('groups'):
|
||||
if group in self.__contactlist[contact]['groups']:
|
||||
result.append(JID(contact))
|
||||
return result
|
||||
|
||||
def getAttr(self, entity, name):
|
||||
"""Return a specific attribute of contact, or all attributes
|
||||
@param entity: jid of the contact
|
||||
@param name: name of the attribute
|
||||
@return: asked attribute"""
|
||||
if self.__contactlist.has_key(entity.short):
|
||||
if name == 'status': #FIXME: for the moment, we only use the first status
|
||||
if self.__contactlist[entity.short]['statuses']:
|
||||
return self.__contactlist[entity.short]['statuses'].values()[0]
|
||||
if self.__contactlist[entity.short].has_key(name):
|
||||
return self.__contactlist[entity.short][name]
|
||||
else:
|
||||
debug(_('Trying to get attribute for an unknown contact'))
|
||||
return None
|
||||
|
||||
def isConnected(self, entity):
|
||||
"""Tell if the contact is online"""
|
||||
return self.__contactlist.has_key(entity.short)
|
||||
|
||||
def remove(self, entity):
|
||||
"""remove resource. If no more resource is online or is no resource is specified, contact is deleted"""
|
||||
try:
|
||||
if entity.resource:
|
||||
self.__contactlist[entity.short]['resources'].remove(entity.resource)
|
||||
if not entity.resource or not self.__contactlist[entity.short]['resources']:
|
||||
#no more resource available: the contact seems really disconnected
|
||||
del self.__contactlist[entity.short]
|
||||
except KeyError:
|
||||
error(_('INTERNAL ERROR: Key error'))
|
||||
raise
|
||||
|
||||
def update(self, entity, key, value):
|
||||
"""Update attribute of contact
|
||||
@param entity: jid of the contact
|
||||
@param key: name of the attribute
|
||||
@param value: value of the attribute
|
||||
"""
|
||||
if self.__contactlist.has_key(entity.short):
|
||||
self.__contactlist[entity.short][key] = value
|
||||
else:
|
||||
debug (_('Trying to update an unknown contact: %s'), entity.short)
|
||||
|
||||
def get_full(self, entity):
|
||||
return entity.short+'/'+self.__contactlist[entity.short]['resources'][-1]
|
||||
|
||||
57
frontends/src/quick_frontend/quick_gateways.py
Normal file
57
frontends/src/quick_frontend/quick_gateways.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
class QuickGatewaysManager():
|
||||
|
||||
|
||||
def __init__(self, host, gateways, title=_("Gateways manager"), server=None):
|
||||
self.WARNING_MSG = _(u"""Be careful ! Gateways allow you to use an external IM (legacy IM), so you can see your contact as jabber contacts.
|
||||
But when you do this, all your messages go throught the external legacy IM server, it is a huge privacy issue (i.e.: all your messages throught the gateway can be monitored, recorded, analyzed by the external server, most of time a private company).""")
|
||||
self.host = host
|
||||
|
||||
def getGatewayDesc(self, gat_type):
|
||||
"""Return a human readable description of gateway type
|
||||
@param gat_type: type of gateway, as given by SàT"""
|
||||
desc = _('Unknown IM')
|
||||
|
||||
if gat_type == 'irc':
|
||||
desc = "Internet Relay Chat"
|
||||
elif gat_type == 'xmpp':
|
||||
desc = "XMPP"
|
||||
elif gat_type == 'qq':
|
||||
desc = "Tencent QQ"
|
||||
elif gat_type == 'simple':
|
||||
desc = "SIP/SIMPLE"
|
||||
elif gat_type == 'icq':
|
||||
desc = "ICQ"
|
||||
elif gat_type == 'yahoo':
|
||||
desc = "Yahoo! Messenger"
|
||||
elif gat_type == 'gadu-gadu':
|
||||
desc = "Gadu-Gadu"
|
||||
elif gat_type == 'aim':
|
||||
desc = "AOL Instant Messenger"
|
||||
elif gat_type == 'msn':
|
||||
desc = 'Windows Live Messenger'
|
||||
|
||||
return desc
|
||||
Loading…
Reference in a new issue