Merge branch 'master' of git://git.assembla.com/fpdb

Conflicts:
	pyfpdb/FulltiltToFpdb.py
This commit is contained in:
Eratosthenes 2010-07-21 22:45:14 -04:00
commit 902a4ad722
28 changed files with 1697 additions and 1223 deletions

View File

@ -0,0 +1,59 @@
# Copyright 1999-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# created by Steffen Schaumburg, steffen@schaumburger.info
EAPI="2"
NEED_PYTHON=2.5
DESCRIPTION="Fpdb is a free/open source tracker/HUD for use with online poker"
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${PV}/${P}.tar.gz"
LICENSE="AGPL-3"
SLOT="0"
KEYWORDS="~amd64 ~x86"
#note: this should work on other architectures too, please send me your experiences
IUSE="graphing mysql postgres sqlite"
RDEPEND="
mysql? ( virtual/mysql
dev-python/mysql-python )
postgres? ( dev-db/postgresql-server
dev-python/psycopg )
sqlite? ( dev-lang/python[sqlite]
dev-python/numpy )
>=x11-libs/gtk+-2.10
dev-python/pygtk
graphing? ( dev-python/numpy
dev-python/matplotlib[gtk] )
dev-python/python-xlib"
DEPEND="${RDEPEND}"
src_install() {
dodir /usr/share/games/fpdb
exeinto /usr/share/games/fpdb
doexe run_fpdb.py
dosym /usr/share/games/fpdb/run_fpdb.py /usr/bin/fpdb
insinto /usr/share/games/fpdb
doins readme.txt
insinto /usr/share/games/fpdb/files
doins files/*
insinto /usr/share/games/fpdb/gfx
doins gfx/*
insinto /usr/share/games/fpdb/pyfpdb
doins pyfpdb/*
# pyfpdb/regression-test-files dir is missing for now; cp -r ??
}
pkg_postinst() {
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
elog "You can find the instructions on the project's website."
}

View File

@ -0,0 +1,61 @@
# Copyright 1999-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# created by Steffen Schaumburg, steffen@schaumburger.info
inherit eutils
inherit games
EAPI="2"
NEED_PYTHON=2.5
DESCRIPTION="A free/open source tracker/HUD for use with online poker"
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${PV}/${P}.tar.gz"
LICENSE="AGPL-3"
SLOT="0"
KEYWORDS="~amd64 ~x86"
#note: this should work on other architectures too, please send me your experiences
IUSE="graph mysql postgres sqlite"
RDEPEND="
mysql? ( virtual/mysql
dev-python/mysql-python )
postgres? ( dev-db/postgresql-server
dev-python/psycopg )
sqlite? ( dev-lang/python[sqlite]
dev-python/numpy )
>=x11-libs/gtk+-2.10
dev-python/pygtk
graph? ( dev-python/numpy
dev-python/matplotlib[gtk] )
dev-python/python-xlib"
DEPEND="${RDEPEND}"
src_install() {
insinto "${GAMES_DATADIR}"/${PN}
doins -r gfx
doins -r pyfpdb
doins readme.txt
exeinto "${GAMES_DATADIR}"/${PN}
doexe run_fpdb.py
dodir "${GAMES_BINDIR}"
dosym "${GAMES_DATADIR}"/${PN}/run_fpdb.py "${GAMES_BINDIR}"/${PN}
newicon gfx/fpdb-icon.png ${PN}.png
make_desktop_entry ${PN}
prepgamesdirs
fperms +x "${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
}
pkg_postinst() {
games_pkg_postinst
echo
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
elog "You can find the instructions on the project's website."
echo
}

View File

@ -442,6 +442,8 @@ class Email:
self.password = node.getAttribute("password") self.password = node.getAttribute("password")
self.useSsl = node.getAttribute("useSsl") self.useSsl = node.getAttribute("useSsl")
self.folder = node.getAttribute("folder") self.folder = node.getAttribute("folder")
self.siteName = node.getAttribute("siteName")
self.fetchType = node.getAttribute("fetchType")
def __str__(self): def __str__(self):
return " host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \ return " host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \
@ -655,6 +657,14 @@ class Config:
if site_node.getAttribute("site_name") == site: if site_node.getAttribute("site_name") == site:
return site_node return site_node
def getGameNode(self,gameName):
"""returns DOM game node for a given game"""
for gameNode in self.doc.getElementsByTagName("game"):
#print "getGameNode gameNode:",gameNode
if gameNode.getAttribute("game_name") == gameName:
return gameNode
#end def getGameNode
def get_aux_node(self, aux): def get_aux_node(self, aux):
for aux_node in self.doc.getElementsByTagName("aw"): for aux_node in self.doc.getElementsByTagName("aw"):
if aux_node.getAttribute("name") == aux: if aux_node.getAttribute("name") == aux:
@ -734,6 +744,49 @@ class Config:
location_node.setAttribute("y", str( locations[i-1][1] )) location_node.setAttribute("y", str( locations[i-1][1] ))
self.supported_sites[site_name].layout[max].location[i] = ( locations[i-1][0], locations[i-1][1] ) self.supported_sites[site_name].layout[max].location[i] = ( locations[i-1][0], locations[i-1][1] )
def editStats(self, gameName, statArray):
"""replaces stat selection for the given gameName with the given statArray"""
gameNode = self.getGameNode(gameName)
statNodes = gameNode.getElementsByTagName("stat")
for node in statNodes:
gameNode.removeChild(node)
gameNode.setAttribute("rows", str(len(statArray)))
gameNode.setAttribute("cols", str(len(statArray[0])))
for rowNumber in range(len(statArray)):
for columnNumber in range(len(statArray[rowNumber])):
newStat=self.doc.createElement("stat")
newAttrStatName=self.doc.createAttribute("stat_name")
newStat.setAttributeNode(newAttrStatName)
newStat.setAttribute("stat_name", statArray[rowNumber][columnNumber])
newAttrStatName=self.doc.createAttribute("row")
newStat.setAttributeNode(newAttrStatName)
newStat.setAttribute("row", str(rowNumber))
newAttrStatName=self.doc.createAttribute("col")
newStat.setAttributeNode(newAttrStatName)
newStat.setAttribute("col", str(columnNumber))
newAttrStatName=self.doc.createAttribute("click")
newStat.setAttributeNode(newAttrStatName)
newStat.setAttribute("click", "tog_decorate")
newAttrStatName=self.doc.createAttribute("popup")
newStat.setAttributeNode(newAttrStatName)
newStat.setAttribute("popup", "default")
newAttrStatName=self.doc.createAttribute("tip")
newStat.setAttributeNode(newAttrStatName)
newStat.setAttribute("tip", "tip1")
gameNode.appendChild(newStat)
statNodes = gameNode.getElementsByTagName("stat")
#end def editStats
def edit_aux_layout(self, aux_name, max, width = None, height = None, locations = None): def edit_aux_layout(self, aux_name, max, width = None, height = None, locations = None):
aux_node = self.get_aux_node(aux_name) aux_node = self.get_aux_node(aux_name)
layout_node = self.get_layout_node(aux_node, max) layout_node = self.get_layout_node(aux_node, max)
@ -1069,8 +1122,8 @@ class Config:
def get_supported_games(self): def get_supported_games(self):
"""Get the list of supported games.""" """Get the list of supported games."""
sg = [] sg = []
for game in c.supported_games.keys(): for game in self.supported_games.keys():
sg.append(c.supported_games[game].game_name) sg.append(self.supported_games[game].game_name)
return sg return sg
def execution_path(self, filename): def execution_path(self, filename):

View File

@ -74,7 +74,7 @@ except ImportError:
use_numpy = False use_numpy = False
DB_VERSION = 131 DB_VERSION = 136
# Variance created as sqlite has a bunch of undefined aggregate functions. # Variance created as sqlite has a bunch of undefined aggregate functions.
@ -294,19 +294,16 @@ class Database:
self.connection.rollback() # make sure any locks taken so far are released self.connection.rollback() # make sure any locks taken so far are released
#end def __init__ #end def __init__
def dumpDatabase(self, filename): def dumpDatabase(self):
dumpFile = open(filename, 'w') result="fpdb database dump\nDB version=" + str(DB_VERSION)+"\n\n"
result="Database dump version " + str(DB_VERSION)+"\n\n"
tables=self.cursor.execute(self.sql.query['list_tables']) tables=self.cursor.execute(self.sql.query['list_tables'])
tables=self.cursor.fetchall() tables=self.cursor.fetchall()
dumpFile.write(result)
for table in tables: for table in tables:
table=table[0] table=table[0]
print "table:", table print "table:", table
result="###################\nTable "+table+"\n###################\n" result+="###################\nTable "+table+"\n###################\n"
rows=self.cursor.execute(self.sql.query['get'+table]) rows=self.cursor.execute(self.sql.query['get'+table])
rows=self.cursor.fetchall() rows=self.cursor.fetchall()
columnNames=self.cursor.description columnNames=self.cursor.description
@ -318,8 +315,7 @@ class Database:
result+=(" "+columnNames[columnNumber][0]+"="+str(row[columnNumber])+"\n") result+=(" "+columnNames[columnNumber][0]+"="+str(row[columnNumber])+"\n")
result+="\n" result+="\n"
result+="\n" result+="\n"
dumpFile.write(result) return result
dumpFile.close()
#end def dumpDatabase #end def dumpDatabase
# could be used by hud to change hud style # could be used by hud to change hud style
@ -521,6 +517,7 @@ class Database:
self.connection.commit() self.connection.commit()
self.cursor.close() self.cursor.close()
self.connection.close() self.connection.close()
self.__connected = False
def reconnect(self, due_to_error=False): def reconnect(self, due_to_error=False):
"""Reconnects the DB""" """Reconnects the DB"""
@ -855,7 +852,7 @@ class Database:
def get_player_id(self, config, siteName, playerName): def get_player_id(self, config, siteName, playerName):
c = self.connection.cursor() c = self.connection.cursor()
siteNameUtf = Charset.to_utf8(siteName) siteNameUtf = Charset.to_utf8(siteName)
playerNameUtf = Charset.to_utf8(playerName) playerNameUtf = unicode(playerName)
#print "db.get_player_id siteName",siteName,"playerName",playerName #print "db.get_player_id siteName",siteName,"playerName",playerName
c.execute(self.sql.query['get_player_id'], (playerNameUtf, siteNameUtf)) c.execute(self.sql.query['get_player_id'], (playerNameUtf, siteNameUtf))
row = c.fetchone() row = c.fetchone()
@ -1113,6 +1110,7 @@ class Database:
"""(Re-)creates the tables of the current DB""" """(Re-)creates the tables of the current DB"""
self.drop_tables() self.drop_tables()
self.resetPlayerIDs()
self.create_tables() self.create_tables()
self.createAllIndexes() self.createAllIndexes()
self.commit() self.commit()
@ -1407,18 +1405,6 @@ class Database:
c.execute("INSERT INTO Sites (name,code) VALUES ('Partouche', 'PA')") c.execute("INSERT INTO Sites (name,code) VALUES ('Partouche', 'PA')")
c.execute("INSERT INTO Sites (name,code) VALUES ('Carbon', 'CA')") c.execute("INSERT INTO Sites (name,code) VALUES ('Carbon', 'CA')")
c.execute("INSERT INTO Sites (name,code) VALUES ('PKR', 'PK')") c.execute("INSERT INTO Sites (name,code) VALUES ('PKR', 'PK')")
if self.backend == self.SQLITE:
c.execute("""INSERT INTO TourneyTypes (id, siteId, currency, buyin, fee, category, limitType,
buyInChips, maxSeats, knockout, rebuy, addOn, speed, shootout, matrix)
VALUES (NULL, 1, 'USD', 0, 0, "NA", "NA", 0, 0, 0, 0, 0, NULL, 0, 0);""")
elif self.backend == self.PGSQL:
c.execute("""insert into TourneyTypes(siteId, currency, buyin, fee, category, limitType,
buyInChips, maxSeats, knockout, rebuy, addOn, speed, shootout, matrix)
values (1, 'USD', 0, 0, "NA", "NA", 0, 0, False, False, False, null, False, False);""")
elif self.backend == self.MYSQL_INNODB:
c.execute("""insert into TourneyTypes(id, siteId, currency, buyin, fee, category, limitType,
buyInChips, maxSeats, knockout, rebuy, addOn, speed, shootout, matrix)
values (DEFAULT, 1, 'USD', 0, 0, "NA", "NA", 0, 0, False, False, False, null, False, False);""")
#end def fillDefaultData #end def fillDefaultData
def rebuild_indexes(self, start=None): def rebuild_indexes(self, start=None):
@ -1573,9 +1559,9 @@ class Database:
p['tableName'], p['tableName'],
p['gameTypeId'], p['gameTypeId'],
p['siteHandNo'], p['siteHandNo'],
0, # tourneyId: 0 means not a tourney hand p['tourneyId'],
p['startTime'], p['startTime'],
datetime.today(), #importtime datetime.utcnow(), #importtime
p['seats'], p['seats'],
p['maxSeats'], p['maxSeats'],
p['texture'], p['texture'],
@ -1656,6 +1642,7 @@ class Database:
pdata[p]['street4Bets'], pdata[p]['street4Bets'],
pdata[p]['position'], pdata[p]['position'],
pdata[p]['tourneyTypeId'], pdata[p]['tourneyTypeId'],
pdata[p]['tourneysPlayersIds'],
pdata[p]['startCards'], pdata[p]['startCards'],
pdata[p]['street0_3BChance'], pdata[p]['street0_3BChance'],
pdata[p]['street0_3BDone'], pdata[p]['street0_3BDone'],
@ -1852,6 +1839,9 @@ class Database:
#FIXME: recognise currency #FIXME: recognise currency
return tmp[0] return tmp[0]
def resetPlayerIDs(self):
self.pcache = None
def getSqlPlayerIDs(self, pnames, siteid): def getSqlPlayerIDs(self, pnames, siteid):
result = {} result = {}
if(self.pcache == None): if(self.pcache == None):
@ -1984,7 +1974,7 @@ class Database:
print "***Error sending finish: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) print "***Error sending finish: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
# end def send_finish_msg(): # end def send_finish_msg():
def createOrUpdateTourneyType(self, hand):#note: this method is used on Hand and TourneySummary objects def createTourneyType(self, hand):#note: this method is used on Hand and TourneySummary objects
tourneyTypeId = 1 tourneyTypeId = 1
# Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype # Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype
@ -1994,27 +1984,13 @@ class Database:
) )
result=cursor.fetchone() result=cursor.fetchone()
expectedValues = { 1 : "buyin", 2 : "fee", 4 : "isKO", 5 : "isRebuy", 6 : "speed", if result:
7 : "isShootout", 8 : "isMatrix" }
tourneyTypeIdMatch = True
try:
tourneyTypeId = result[0] tourneyTypeId = result[0]
log.debug("Tourney found in db with Tourney_Type_ID = %d" % tourneyTypeId) else:
for ev in expectedValues :
if ( getattr( hand, expectedValues.get(ev) ) <> result[ev] ):
log.debug("TypeId mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( hand, expectedValues.get(ev)), result[ev]) )
tourneyTypeIdMatch = False
#break
except:
# Tourney not found : a TourneyTypeId has to be found or created for that specific tourney
tourneyTypeIdMatch = False
if tourneyTypeIdMatch == False :
# Check for an existing TTypeId that matches tourney info, if not found create it # Check for an existing TTypeId that matches tourney info, if not found create it
cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']),
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.isKO, (hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.isKO,
hand.isRebuy, hand.isRebuy, hand.speed, hand.isShootout, hand.isMatrix) hand.isRebuy, hand.isRebuy, hand.speed, hand.isShootout, hand.isMatrix, hand.added, hand.addedCurrency)
) )
result=cursor.fetchone() result=cursor.fetchone()
@ -2024,20 +2000,39 @@ class Database:
cursor.execute (self.sql.query['insertTourneyType'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['insertTourneyType'].replace('%s', self.sql.query['placeholder']),
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.buyInChips, (hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.buyInChips,
hand.isKO, hand.isRebuy, hand.isKO, hand.isRebuy,
hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix) hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix, hand.added, hand.addedCurrency)
) )
tourneyTypeId = self.get_last_insert_id(cursor) tourneyTypeId = self.get_last_insert_id(cursor)
return tourneyTypeId return tourneyTypeId
#end def createOrUpdateTourneyType #end def createTourneyType
def createOrUpdateTourney(self, hand, source):#note: this method is used on Hand and TourneySummary objects def createOrUpdateTourney(self, hand, source):#note: this method is used on Hand and TourneySummary objects
cursor = self.get_cursor() cursor = self.get_cursor()
cursor.execute (self.sql.query['getTourneyIdByTourneyNo'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['getTourneyByTourneyNo'].replace('%s', self.sql.query['placeholder']),
(hand.siteId, hand.tourNo)) (hand.siteId, hand.tourNo))
columnNames=[desc[0] for desc in cursor.description]
result=cursor.fetchone() result=cursor.fetchone()
if result != None and len(result)==1: if result != None:
tourneyId = result[0] expectedValues = ('comment', 'tourneyName', 'matrixIdProcessed', 'totalRebuyCount', 'totalAddOnCount',
'prizepool', 'startTime', 'entries', 'commentTs', 'endTime')
updateDb=False
resultDict = dict(zip(columnNames, result))
tourneyId = resultDict["id"]
if source=="TS":
for ev in expectedValues :
if getattr(hand, ev)==None and resultDict[ev]!=None:#DB has this value but object doesnt, so update object
setattr(hand, ev, resultDict[ev])
elif getattr(hand, ev)!=None and resultDict[ev]==None:#object has this value but DB doesnt, so update DB
updateDb=True
#elif ev=="startTime":
# if (resultDict[ev] < hand.startTime):
# hand.startTime=resultDict[ev]
if updateDb:
cursor.execute (self.sql.query['updateTourney'].replace('%s', self.sql.query['placeholder']),
(hand.entries, hand.prizepool, hand.startTime, hand.endTime, hand.tourneyName,
hand.matrixIdProcessed, hand.totalRebuyCount, hand.totalAddOnCount, hand.comment, hand.commentTs, tourneyId))
else: else:
if source=="HHC": if source=="HHC":
cursor.execute (self.sql.query['insertTourney'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['insertTourney'].replace('%s', self.sql.query['placeholder']),
@ -2045,8 +2040,8 @@ class Database:
hand.startTime, None, None, None, None, None)) hand.startTime, None, None, None, None, None))
elif source=="TS": elif source=="TS":
cursor.execute (self.sql.query['insertTourney'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['insertTourney'].replace('%s', self.sql.query['placeholder']),
(hand.tourneyTypeId, hand.tourNo, hand.entries, hand.prizepool, (hand.tourneyTypeId, hand.tourNo, hand.entries, hand.prizepool, hand.startTime,
hand.startTime, hand.endTime, hand.tourneyName, hand.matrixIdProcessed, hand.totalRebuyCount, hand.totalAddOnCount)) hand.endTime, hand.tourneyName, hand.matrixIdProcessed, hand.totalRebuyCount, hand.totalAddOnCount))
else: else:
raise FpdbParseError("invalid source in Database.createOrUpdateTourney") raise FpdbParseError("invalid source in Database.createOrUpdateTourney")
tourneyId = self.get_last_insert_id(cursor) tourneyId = self.get_last_insert_id(cursor)
@ -2054,7 +2049,7 @@ class Database:
#end def createOrUpdateTourney #end def createOrUpdateTourney
def createOrUpdateTourneysPlayers(self, hand, source):#note: this method is used on Hand and TourneySummary objects def createOrUpdateTourneysPlayers(self, hand, source):#note: this method is used on Hand and TourneySummary objects
tourneysPlayersIds=[] tourneysPlayersIds={}
for player in hand.players: for player in hand.players:
if source=="TS": #TODO remove this horrible hack if source=="TS": #TODO remove this horrible hack
playerId = hand.dbid_pids[player] playerId = hand.dbid_pids[player]
@ -2064,12 +2059,31 @@ class Database:
raise FpdbParseError("invalid source in Database.createOrUpdateTourneysPlayers") raise FpdbParseError("invalid source in Database.createOrUpdateTourneysPlayers")
cursor = self.get_cursor() cursor = self.get_cursor()
cursor.execute (self.sql.query['getTourneysPlayersId'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['getTourneysPlayersByIds'].replace('%s', self.sql.query['placeholder']),
(hand.tourneyId, playerId)) (hand.tourneyId, playerId))
columnNames=[desc[0] for desc in cursor.description]
result=cursor.fetchone() result=cursor.fetchone()
if result != None and len(result)==1: if result != None:
tourneysPlayersIds.append(result[0]) expectedValues = ('rank', 'winnings', 'winningsCurrency', 'rebuyCount', 'addOnCount', 'koCount')
updateDb=False
resultDict = dict(zip(columnNames, result))
tourneysPlayersIds[player[1]]=result[0]
if source=="TS":
for ev in expectedValues :
handAttribute=ev
if ev!="winnings" and ev!="winningsCurrency":
handAttribute+="s"
if getattr(hand, handAttribute)[player]==None and resultDict[ev]!=None:#DB has this value but object doesnt, so update object
setattr(hand, handAttribute, resultDict[ev][player])
elif getattr(hand, handAttribute)[player]!=None and resultDict[ev]==None:#object has this value but DB doesnt, so update DB
updateDb=True
if updateDb:
cursor.execute (self.sql.query['updateTourneysPlayer'].replace('%s', self.sql.query['placeholder']),
(hand.ranks[player], hand.winnings[player], hand.winningsCurrency[player],
hand.rebuyCounts[player], hand.addOnCounts[player], hand.koCounts[player], tourneysPlayersIds[player[1]]))
else: else:
if source=="HHC": if source=="HHC":
cursor.execute (self.sql.query['insertTourneysPlayer'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['insertTourneysPlayer'].replace('%s', self.sql.query['placeholder']),
@ -2084,7 +2098,7 @@ class Database:
cursor.execute (self.sql.query['insertTourneysPlayer'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['insertTourneysPlayer'].replace('%s', self.sql.query['placeholder']),
(hand.tourneyId, playerId, None, None, None, (hand.tourneyId, playerId, None, None, None,
hand.rebuyCounts[player], hand.addOnCounts[player], hand.koCounts[player])) hand.rebuyCounts[player], hand.addOnCounts[player], hand.koCounts[player]))
tourneysPlayersIds.append(self.get_last_insert_id(cursor)) tourneysPlayersIds[player[1]]=self.get_last_insert_id(cursor)
return tourneysPlayersIds return tourneysPlayersIds
#end def createOrUpdateTourneysPlayers #end def createOrUpdateTourneysPlayers

View File

@ -59,6 +59,8 @@ class DerivedStats():
self.handsplayers[player[1]]['foldSbToStealChance'] = False self.handsplayers[player[1]]['foldSbToStealChance'] = False
self.handsplayers[player[1]]['foldedSbToSteal'] = False self.handsplayers[player[1]]['foldedSbToSteal'] = False
self.handsplayers[player[1]]['foldedBbToSteal'] = False self.handsplayers[player[1]]['foldedBbToSteal'] = False
self.handsplayers[player[1]]['tourneyTypeId'] = None
for i in range(5): for i in range(5):
self.handsplayers[player[1]]['street%dCalls' % i] = 0 self.handsplayers[player[1]]['street%dCalls' % i] = 0
self.handsplayers[player[1]]['street%dBets' % i] = 0 self.handsplayers[player[1]]['street%dBets' % i] = 0
@ -72,7 +74,6 @@ class DerivedStats():
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
#FIXME - Everything below this point is incomplete. #FIXME - Everything below this point is incomplete.
self.handsplayers[player[1]]['tourneyTypeId'] = 1
for i in range(1,5): for i in range(1,5):
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
@ -102,6 +103,7 @@ class DerivedStats():
self.hands['seats'] = self.countPlayers(hand) self.hands['seats'] = self.countPlayers(hand)
self.hands['maxSeats'] = hand.maxseats self.hands['maxSeats'] = hand.maxseats
self.hands['texture'] = None # No calculation done for this yet. self.hands['texture'] = None # No calculation done for this yet.
self.hands['tourneyId'] = hand.tourneyId
# This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and
# those values remain default in stud. # those values remain default in stud.
@ -140,6 +142,11 @@ class DerivedStats():
self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2])) self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2]))
self.handsplayers[player[1]]['sitout'] = False #TODO: implement actual sitout detection self.handsplayers[player[1]]['sitout'] = False #TODO: implement actual sitout detection
if hand.gametype["type"]=="tour":
self.handsplayers[player[1]]['tourneyTypeId']=hand.tourneyTypeId
self.handsplayers[player[1]]['tourneysPlayersIds'] = hand.tourneysPlayersIds[player[1]]
else:
self.handsplayers[player[1]]['tourneysPlayersIds'] = None
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start' # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
#for i, street in enumerate(hand.actionStreets[2:], start=1): #for i, street in enumerate(hand.actionStreets[2:], start=1):

View File

@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#Copyright 2010 Steffen Schaumburg #Copyright 2008-2010 Steffen Schaumburg
#This program is free software: you can redistribute it and/or modify #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 #it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License. #the Free Software Foundation, version 3 of the License.
@ -16,7 +16,940 @@
#In the "official" distribution you can find the license in agpl-3.0.txt. #In the "official" distribution you can find the license in agpl-3.0.txt.
import threading import threading
import pygtk
pygtk.require('2.0')
import gtk
import os
import sys
from optparse import OptionParser
from time import gmtime, mktime, strftime, strptime
import gobject
#import pokereval
import logging
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
log = logging.getLogger("filter")
import Configuration
import Database
import SQL
import Charset
import Filters
class Filters(threading.Thread): class Filters(threading.Thread):
pass def __init__(self, db, config, qdict, display = {}, debug=True):
#end class Filters # config and qdict are now redundant
self.debug = debug
self.db = db
self.cursor = db.cursor
self.sql = db.sql
self.conf = db.config
self.display = display
# text used on screen stored here so that it can be configured
self.filterText = {'limitsall':'All', 'limitsnone':'None', 'limitsshow':'Show _Limits'
,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players'
,'playerstitle':'Hero:', 'sitestitle':'Sites:', 'gamestitle':'Games:'
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
,'datestitle':'Date:'
,'groupsall':'All Players'
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
}
gen = self.conf.get_general_params()
self.day_start = 0
if 'day_start' in gen:
self.day_start = float(gen['day_start'])
# Outer Packing box
self.mainVBox = gtk.VBox(False, 0)
self.found = {'nl':False, 'fl':False, 'pl':False, 'ring':False, 'tour':False}
self.label = {}
self.callback = {}
self.make_filter()
def make_filter(self):
self.sites = {}
self.games = {}
self.limits = {}
self.seats = {}
self.groups = {}
self.siteid = {}
self.heroes = {}
self.boxes = {}
for site in self.conf.get_supported_sites():
#Get db site id for filtering later
self.cursor.execute(self.sql.query['getSiteId'], (site,))
result = self.db.cursor.fetchall()
if len(result) == 1:
self.siteid[site] = result[0][0]
else:
print "Either 0 or more than one site matched (%s) - EEK" % site
# For use in date ranges.
self.start_date = gtk.Entry(max=12)
self.end_date = gtk.Entry(max=12)
self.start_date.set_property('editable', False)
self.end_date.set_property('editable', False)
# For use in groups etc
self.sbGroups = {}
self.numHands = 0
playerFrame = gtk.Frame()
playerFrame.set_label_align(0.0, 0.0)
vbox = gtk.VBox(False, 0)
self.fillPlayerFrame(vbox, self.display)
playerFrame.add(vbox)
sitesFrame = gtk.Frame()
sitesFrame.set_label_align(0.0, 0.0)
vbox = gtk.VBox(False, 0)
self.fillSitesFrame(vbox)
sitesFrame.add(vbox)
# Game types
gamesFrame = gtk.Frame()
gamesFrame.set_label_align(0.0, 0.0)
gamesFrame.show()
vbox = gtk.VBox(False, 0)
self.fillGamesFrame(vbox)
gamesFrame.add(vbox)
# Limits
limitsFrame = gtk.Frame()
limitsFrame.show()
vbox = gtk.VBox(False, 0)
self.cbLimits = {}
self.cbNoLimits = None
self.cbAllLimits = None
self.cbFL = None
self.cbNL = None
self.cbPL = None
self.rb = {} # radio buttons for ring/tour
self.type = None # ring/tour
self.types = {} # list of all ring/tour values
self.fillLimitsFrame(vbox, self.display)
limitsFrame.add(vbox)
# Seats
seatsFrame = gtk.Frame()
seatsFrame.show()
vbox = gtk.VBox(False, 0)
self.sbSeats = {}
self.fillSeatsFrame(vbox, self.display)
seatsFrame.add(vbox)
# Groups
groupsFrame = gtk.Frame()
groupsFrame.show()
vbox = gtk.VBox(False, 0)
self.fillGroupsFrame(vbox, self.display)
groupsFrame.add(vbox)
# Date
dateFrame = gtk.Frame()
dateFrame.set_label_align(0.0, 0.0)
dateFrame.show()
vbox = gtk.VBox(False, 0)
self.fillDateFrame(vbox)
dateFrame.add(vbox)
# Buttons
self.Button1=gtk.Button("Unnamed 1")
self.Button1.set_sensitive(False)
self.Button2=gtk.Button("Unnamed 2")
self.Button2.set_sensitive(False)
self.mainVBox.add(playerFrame)
self.mainVBox.add(sitesFrame)
self.mainVBox.add(gamesFrame)
self.mainVBox.add(limitsFrame)
self.mainVBox.add(seatsFrame)
self.mainVBox.add(groupsFrame)
self.mainVBox.add(dateFrame)
self.mainVBox.add(self.Button1)
self.mainVBox.add(self.Button2)
self.mainVBox.show_all()
# Should do this cleaner
if "Heroes" not in self.display or self.display["Heroes"] == False:
playerFrame.hide()
if "Sites" not in self.display or self.display["Sites"] == False:
sitesFrame.hide()
if "Games" not in self.display or self.display["Games"] == False:
gamesFrame.hide()
if "Limits" not in self.display or self.display["Limits"] == False:
limitsFrame.hide()
if "Seats" not in self.display or self.display["Seats"] == False:
seatsFrame.hide()
if "Groups" not in self.display or self.display["Groups"] == False:
groupsFrame.hide()
if "Dates" not in self.display or self.display["Dates"] == False:
dateFrame.hide()
if "Button1" not in self.display or self.display["Button1"] == False:
self.Button1.hide()
if "Button2" not in self.display or self.display["Button2"] == False:
self.Button2.hide()
if 'button1' in self.label and self.label['button1']:
self.Button1.set_label( self.label['button1'] )
if 'button2' in self.label and self.label['button2']:
self.Button2.set_label( self.label['button2'] )
if 'button1' in self.callback and self.callback['button1']:
self.Button1.connect("clicked", self.callback['button1'], "clicked")
self.Button1.set_sensitive(True)
if 'button2' in self.callback and self.callback['button2']:
self.Button2.connect("clicked", self.callback['button2'], "clicked")
self.Button2.set_sensitive(True)
# make sure any locks on db are released:
self.db.rollback()
def get_vbox(self):
"""returns the vbox of this thread"""
return self.mainVBox
#end def get_vbox
def getNumHands(self):
return self.numHands
#end def getNumHands
def getSites(self):
return self.sites
#end def getSites
def getGames(self):
return self.games
def getSiteIds(self):
return self.siteid
#end def getSiteIds
def getHeroes(self):
return self.heroes
#end def getHeroes
def getLimits(self):
ltuple = []
for l in self.limits:
if self.limits[l] == True:
ltuple.append(l)
return ltuple
def getType(self):
return(self.type)
def getSeats(self):
if 'from' in self.sbSeats:
self.seats['from'] = self.sbSeats['from'].get_value_as_int()
if 'to' in self.sbSeats:
self.seats['to'] = self.sbSeats['to'].get_value_as_int()
return self.seats
#end def getSeats
def getGroups(self):
return self.groups
def getDates(self):
return self.__get_dates()
#end def getDates
def registerButton1Name(self, title):
self.Button1.set_label(title)
self.label['button1'] = title
def registerButton1Callback(self, callback):
self.Button1.connect("clicked", callback, "clicked")
self.Button1.set_sensitive(True)
self.callback['button1'] = callback
def registerButton2Name(self, title):
self.Button2.set_label(title)
self.label['button2'] = title
#end def registerButton2Name
def registerButton2Callback(self, callback):
self.Button2.connect("clicked", callback, "clicked")
self.Button2.set_sensitive(True)
self.callback['button2'] = callback
#end def registerButton2Callback
def cardCallback(self, widget, data=None):
log.debug( "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) )
def createPlayerLine(self, hbox, site, player):
log.debug('add:"%s"' % player)
label = gtk.Label(site +" id:")
hbox.pack_start(label, False, False, 3)
pname = gtk.Entry()
pname.set_text(player)
pname.set_width_chars(20)
hbox.pack_start(pname, False, True, 0)
pname.connect("changed", self.__set_hero_name, site)
# Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices)
completion = gtk.EntryCompletion()
pname.set_completion(completion)
liststore = gtk.ListStore(gobject.TYPE_STRING)
completion.set_model(liststore)
completion.set_text_column(0)
names = self.db.get_player_names(self.conf, self.siteid[site]) # (config=self.conf, site_id=None, like_player_name="%")
for n in names: # list of single-element "tuples"
_n = Charset.to_gui(n[0])
_nt = (_n, )
liststore.append(_nt)
self.__set_hero_name(pname, site)
def __set_hero_name(self, w, site):
_name = w.get_text()
# get_text() returns a str but we want internal variables to be unicode:
_guiname = unicode(_name)
self.heroes[site] = _guiname
#log.debug("setting heroes[%s]: %s"%(site, self.heroes[site]))
#end def __set_hero_name
def __set_num_hands(self, w, val):
try:
self.numHands = int(w.get_text())
except:
self.numHands = 0
#log.debug("setting numHands:", self.numHands)
#end def __set_num_hands
def createSiteLine(self, hbox, site):
cb = gtk.CheckButton(site)
cb.connect('clicked', self.__set_site_select, site)
cb.set_active(True)
hbox.pack_start(cb, False, False, 0)
def createGameLine(self, hbox, game):
cb = gtk.CheckButton(game)
cb.connect('clicked', self.__set_game_select, game)
hbox.pack_start(cb, False, False, 0)
cb.set_active(True)
def createLimitLine(self, hbox, limit, ltext):
cb = gtk.CheckButton(str(ltext))
cb.connect('clicked', self.__set_limit_select, limit)
hbox.pack_start(cb, False, False, 0)
if limit != "none":
cb.set_active(True)
return(cb)
def __set_site_select(self, w, site):
#print w.get_active()
self.sites[site] = w.get_active()
log.debug("self.sites[%s] set to %s" %(site, self.sites[site]))
def __set_game_select(self, w, game):
#print w.get_active()
self.games[game] = w.get_active()
log.debug("self.games[%s] set to %s" %(game, self.games[game]))
#end def __set_game_select
def __set_limit_select(self, w, limit):
#print "__set_limit_select: limit =", limit, w.get_active()
self.limits[limit] = w.get_active()
log.debug("self.limit[%s] set to %s" %(limit, self.limits[limit]))
if limit.isdigit() or (len(limit) > 2 and (limit[-2:] == 'nl' or limit[-2:] == 'fl' or limit[-2:] == 'pl')):
if self.limits[limit]:
if self.cbNoLimits is not None:
self.cbNoLimits.set_active(False)
else:
if self.cbAllLimits is not None:
self.cbAllLimits.set_active(False)
if not self.limits[limit]:
if limit.isdigit():
if self.cbFL is not None:
self.cbFL.set_active(False)
elif (len(limit) > 2 and (limit[-2:] == 'nl')):
if self.cbNL is not None:
self.cbNL.set_active(False)
else:
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "all":
if self.limits[limit]:
#for cb in self.cbLimits.values():
# cb.set_active(True)
if self.cbFL is not None:
self.cbFL.set_active(True)
if self.cbNL is not None:
self.cbNL.set_active(True)
if self.cbPL is not None:
self.cbPL.set_active(True)
elif limit == "none":
if self.limits[limit]:
for cb in self.cbLimits.values():
cb.set_active(False)
if self.cbNL is not None:
self.cbNL.set_active(False)
if self.cbFL is not None:
self.cbFL.set_active(False)
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "fl":
if not self.limits[limit]:
# only toggle all fl limits off if they are all currently on
# this stops turning one off from cascading into 'fl' box off
# and then all fl limits being turned off
all_fl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if t.isdigit():
if not cb.get_active():
all_fl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
t = cb.get_children()[0].get_text()
if t.isdigit():
if self.limits[limit] or all_fl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
if 'tour' in self.rb:
self.rb['tour'].set_active(True)
elif self.type == 'tour':
if 'ring' in self.rb:
self.rb['ring'].set_active(True)
elif limit == "nl":
if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off
all_nl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "nl" in t and len(t) > 2:
if not cb.get_active():
all_nl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "nl" in t and len(t) > 2:
if self.limits[limit] or all_nl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
if 'tour' in self.rb:
self.rb['tour'].set_active(True)
elif self.type == 'tour':
if 'ring' in self.rb:
self.rb['ring'].set_active(True)
elif limit == "pl":
if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off
all_nl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if not cb.get_active():
all_nl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if self.limits[limit] or all_nl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
if 'tour' in self.rb:
self.rb['tour'].set_active(True)
elif self.type == 'tour':
if 'ring' in self.rb:
self.rb['ring'].set_active(True)
elif limit == "ring":
log.debug("set", limit, "to", self.limits[limit])
if self.limits[limit]:
self.type = "ring"
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
if self.types[cb.get_children()[0].get_text()] == 'tour':
cb.set_active(False)
elif limit == "tour":
log.debug( "set", limit, "to", self.limits[limit] )
if self.limits[limit]:
self.type = "tour"
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
if self.types[cb.get_children()[0].get_text()] == 'ring':
cb.set_active(False)
def __set_seat_select(self, w, seat):
#print "__set_seat_select: seat =", seat, "active =", w.get_active()
self.seats[seat] = w.get_active()
log.debug( "self.seats[%s] set to %s" %(seat, self.seats[seat]) )
def __set_group_select(self, w, group):
#print "__set_seat_select: seat =", seat, "active =", w.get_active()
self.groups[group] = w.get_active()
log.debug( "self.groups[%s] set to %s" %(group, self.groups[group]) )
def fillPlayerFrame(self, vbox, display):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['playerstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="refresh", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__refresh, 'players')
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['players'] = vbox1
for site in self.conf.get_supported_sites():
hBox = gtk.HBox(False, 0)
vbox1.pack_start(hBox, False, True, 0)
player = self.conf.supported_sites[site].screen_name
_pname = Charset.to_gui(player)
self.createPlayerLine(hBox, site, _pname)
if "GroupsAll" in display and display["GroupsAll"] == True:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, False, 0)
cb = gtk.CheckButton(self.filterText['groupsall'])
cb.connect('clicked', self.__set_group_select, 'allplayers')
hbox.pack_start(cb, False, False, 0)
self.sbGroups['allplayers'] = cb
self.groups['allplayers'] = False
lbl = gtk.Label('Min # Hands:')
lbl.set_alignment(xalign=1.0, yalign=0.5)
hbox.pack_start(lbl, expand=True, padding=3)
phands = gtk.Entry()
phands.set_text('0')
phands.set_width_chars(8)
hbox.pack_start(phands, False, False, 0)
phands.connect("changed", self.__set_num_hands, site)
top_hbox.pack_start(showb, expand=False, padding=1)
def fillSitesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
top_hbox.show()
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['sitestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'sites')
showb.show()
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
self.boxes['sites'] = vbox1
vbox.pack_start(vbox1, False, False, 0)
for site in self.conf.get_supported_sites():
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
self.createSiteLine(hbox, site)
#Get db site id for filtering later
#self.cursor.execute(self.sql.query['getSiteId'], (site,))
#result = self.db.cursor.fetchall()
#if len(result) == 1:
# self.siteid[site] = result[0][0]
#else:
# print "Either 0 or more than one site matched - EEK"
def fillGamesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['gamestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'games')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['games'] = vbox1
self.cursor.execute(self.sql.query['getGames'])
result = self.db.cursor.fetchall()
if len(result) >= 1:
for line in result:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
self.createGameLine(hbox, line[0])
else:
print "INFO: No games returned from database"
log.info("No games returned from database")
#end def fillGamesFrame
def fillLimitsFrame(self, vbox, display):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['limitstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'limits')
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['limits'] = vbox1
self.cursor.execute(self.sql.query['getCashLimits'])
# selects limitType, bigBlind
result = self.db.cursor.fetchall()
self.found = {'nl':False, 'fl':False, 'pl':False, 'ring':False, 'tour':False}
if len(result) >= 1:
hbox = gtk.HBox(True, 0)
vbox1.pack_start(hbox, False, False, 0)
vbox2 = gtk.VBox(False, 0)
hbox.pack_start(vbox2, False, False, 0)
vbox3 = gtk.VBox(False, 0)
hbox.pack_start(vbox3, False, False, 0)
for i, line in enumerate(result):
if "UseType" in self.display:
if line[0] != self.display["UseType"]:
continue
hbox = gtk.HBox(False, 0)
if i <= len(result)/2:
vbox2.pack_start(hbox, False, False, 0)
else:
vbox3.pack_start(hbox, False, False, 0)
if True: #line[0] == 'ring':
if line[1] == 'fl':
name = str(line[2])
self.found['fl'] = True
elif line[1] == 'pl':
name = str(line[2])+line[1]
self.found['pl'] = True
else:
name = str(line[2])+line[1]
self.found['nl'] = True
self.cbLimits[name] = self.createLimitLine(hbox, name, name)
self.types[name] = line[0]
self.found[line[0]] = True # type is ring/tour
self.type = line[0] # if only one type, set it now
if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2:
hbox = gtk.HBox(True, 0)
vbox1.pack_start(hbox, False, False, 0)
vbox2 = gtk.VBox(False, 0)
hbox.pack_start(vbox2, False, False, 0)
vbox3 = gtk.VBox(False, 0)
hbox.pack_start(vbox3, False, False, 0)
hbox = gtk.HBox(False, 0)
vbox2.pack_start(hbox, False, False, 0)
self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall'])
hbox = gtk.HBox(False, 0)
vbox2.pack_start(hbox, False, False, 0)
self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone'])
dest = vbox3 # for ring/tour buttons
if "LimitType" in display and display["LimitType"] == True:
num_limit_types = 0
if self.found['fl']: num_limit_types = num_limit_types + 1
if self.found['pl']: num_limit_types = num_limit_types + 1
if self.found['nl']: num_limit_types = num_limit_types + 1
if num_limit_types > 1:
if self.found['fl']:
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbFL = self.createLimitLine(hbox, 'fl', self.filterText['limitsFL'])
if self.found['nl']:
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL'])
if self.found['pl']:
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbPL = self.createLimitLine(hbox, 'pl', self.filterText['limitsPL'])
dest = vbox2 # for ring/tour buttons
else:
print "INFO: No games returned from database"
log.info("No games returned from database")
if "Type" in display and display["Type"] == True and self.found['ring'] and self.found['tour']:
rb1 = gtk.RadioButton(None, self.filterText['ring'])
rb1.connect('clicked', self.__set_limit_select, 'ring')
rb2 = gtk.RadioButton(rb1, self.filterText['tour'])
rb2.connect('clicked', self.__set_limit_select, 'tour')
top_hbox.pack_start(rb1, False, False, 0) # (child, expand, fill, padding)
top_hbox.pack_start(rb2, True, True, 0) # child uses expand space if fill is true
self.rb['ring'] = rb1
self.rb['tour'] = rb2
#print "about to set ring to true"
rb1.set_active(True)
# set_active doesn't seem to call this for some reason so call manually:
self.__set_limit_select(rb1, 'ring')
self.type = 'ring'
top_hbox.pack_start(showb, expand=False, padding=1)
def fillSeatsFrame(self, vbox, display):
hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['seatstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'seats')
hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['seats'] = vbox1
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
lbl_from = gtk.Label(self.filterText['seatsbetween'])
lbl_to = gtk.Label(self.filterText['seatsand'])
adj1 = gtk.Adjustment(value=2, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0)
adj2 = gtk.Adjustment(value=10, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0)
hbox.pack_start(lbl_from, expand=False, padding=3)
hbox.pack_start(sb1, False, False, 0)
hbox.pack_start(lbl_to, expand=False, padding=3)
hbox.pack_start(sb2, False, False, 0)
self.sbSeats['from'] = sb1
self.sbSeats['to'] = sb2
#end def fillSeatsFrame
def fillGroupsFrame(self, vbox, display):
hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['groupstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'groups')
hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['groups'] = vbox1
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, False, 0)
cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow'])
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
cb = gtk.CheckButton(self.filterText['posnshow'])
cb.connect('clicked', self.__set_group_select, 'posn')
hbox.pack_start(cb, False, False, 0)
self.sbGroups['posn'] = cb
self.groups['posn'] = False
if "SeatSep" in display and display["SeatSep"] == True:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
cb = gtk.CheckButton(self.filterText['seatsshow'])
cb.connect('clicked', self.__set_seat_select, 'show')
hbox.pack_start(cb, False, False, 0)
self.sbSeats['show'] = cb
self.seats['show'] = False
def fillCardsFrame(self, vbox):
hbox1 = gtk.HBox(True,0)
hbox1.show()
vbox.pack_start(hbox1, True, True, 0)
cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ]
for j in range(0, len(cards)):
hbox1 = gtk.HBox(True,0)
hbox1.show()
vbox.pack_start(hbox1, True, True, 0)
for i in range(0, len(cards)):
if i < (j + 1):
suit = "o"
else:
suit = "s"
button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit))
button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit))
hbox1.pack_start(button, True, True, 0)
button.show()
def fillDateFrame(self, vbox):
# Hat tip to Mika Bostrom - calendar code comes from PokerStats
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['datestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'dates')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['dates'] = vbox1
hbox = gtk.HBox()
vbox1.pack_start(hbox, False, True, 0)
lbl_start = gtk.Label('From:')
btn_start = gtk.Button()
btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn_start.connect('clicked', self.__calendar_dialog, self.start_date)
hbox.pack_start(lbl_start, expand=False, padding=3)
hbox.pack_start(btn_start, expand=False, padding=3)
hbox.pack_start(self.start_date, expand=False, padding=2)
#New row for end date
hbox = gtk.HBox()
vbox1.pack_start(hbox, False, True, 0)
lbl_end = gtk.Label(' To:')
btn_end = gtk.Button()
btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn_end.connect('clicked', self.__calendar_dialog, self.end_date)
btn_clear = gtk.Button(label=' Clear Dates ')
btn_clear.connect('clicked', self.__clear_dates)
hbox.pack_start(lbl_end, expand=False, padding=3)
hbox.pack_start(btn_end, expand=False, padding=3)
hbox.pack_start(self.end_date, expand=False, padding=2)
hbox.pack_start(btn_clear, expand=False, padding=15)
#end def fillDateFrame
def __refresh(self, widget, entry):
for w in self.mainVBox.get_children():
w.destroy()
self.make_filter()
def __toggle_box(self, widget, entry):
if self.boxes[entry].props.visible:
self.boxes[entry].hide()
widget.set_label("show")
else:
self.boxes[entry].show()
widget.set_label("hide")
#end def __toggle_box
def __calendar_dialog(self, widget, entry):
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
d.set_title('Pick a date')
vb = gtk.VBox()
cal = gtk.Calendar()
vb.pack_start(cal, expand=False, padding=0)
btn = gtk.Button('Done')
btn.connect('clicked', self.__get_date, cal, entry, d)
vb.pack_start(btn, expand=False, padding=4)
d.add(vb)
d.set_position(gtk.WIN_POS_MOUSE)
d.show_all()
#end def __calendar_dialog
def __clear_dates(self, w):
self.start_date.set_text('')
self.end_date.set_text('')
#end def __clear_dates
def __get_dates(self):
# self.day_start gives user's start of day in hours
offset = int(self.day_start * 3600) # calc day_start in seconds
t1 = self.start_date.get_text()
t2 = self.end_date.get_text()
if t1 == '':
t1 = '1970-01-02'
if t2 == '':
t2 = '2020-12-12'
s1 = strptime(t1, "%Y-%m-%d") # make time_struct
s2 = strptime(t2, "%Y-%m-%d")
e1 = mktime(s1) + offset # s1 is localtime, but returned time since epoch is UTC, then add the
e2 = mktime(s2) + offset # s2 is localtime, but returned time since epoch is UTC
e2 = e2 + 24 * 3600 - 1 # date test is inclusive, so add 23h 59m 59s to e2
adj_t1 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e1)) # make adjusted string including time
adj_t2 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e2))
log.info("t1="+t1+" adj_t1="+adj_t1+'.')
return (adj_t1, adj_t2)
#end def __get_dates
def __get_date(self, widget, calendar, entry, win):
# year and day are correct, month is 0..11
(year, month, day) = calendar.get_date()
month += 1
ds = '%04d-%02d-%02d' % (year, month, day)
entry.set_text(ds)
win.destroy()
def main(argv=None):
"""main can also be called in the python interpreter, by supplying the command line as the argument."""
if argv is None:
argv = sys.argv[1:]
def destroy(*args): # call back for terminating the main eventloop
gtk.main_quit()
parser = OptionParser()
(options, argv) = parser.parse_args(args = argv)
config = Configuration.Config()
db = None
db = Database.Database()
db.do_connect(config)
qdict = SQL.SQL(db.get_backend_name())
i = Filters(db, config, qdict)
main_window = gtk.Window()
main_window.connect('destroy', destroy)
main_window.add(i.get_vbox())
main_window.show()
gtk.main()
if __name__ == '__main__':
sys.exit(main())

View File

@ -201,11 +201,14 @@ class Fulltilt(HandHistoryConverter):
return None return None
hand.handid = m.group('HID') hand.handid = m.group('HID')
hand.tablename = m.group('TABLE') hand.tablename = m.group('TABLE')
try: try:
hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d") hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d")
except: except:
hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M ET - %a, %B %d, %Y") hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M ET - %a, %B %d, %Y")
hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, "ET", "UTC")
if m.group("CANCELLED") or m.group("PARTIAL"): if m.group("CANCELLED") or m.group("PARTIAL"):
raise FpdbParseError(hid=m.group('HID')) raise FpdbParseError(hid=m.group('HID'))

View File

@ -101,7 +101,7 @@ class GuiAutoImport (threading.Thread):
hbox.pack_start(lbl1, expand=True, fill=False) hbox.pack_start(lbl1, expand=True, fill=False)
self.doAutoImportBool = False self.doAutoImportBool = False
self.startButton = gtk.ToggleButton(" _Start Autoimport ") self.startButton = gtk.ToggleButton(" Start _Autoimport ")
self.startButton.connect("clicked", self.startClicked, "start clicked") self.startButton.connect("clicked", self.startClicked, "start clicked")
hbox.pack_start(self.startButton, expand=False, fill=False) hbox.pack_start(self.startButton, expand=False, fill=False)
@ -156,7 +156,7 @@ class GuiAutoImport (threading.Thread):
def do_import(self): def do_import(self):
"""Callback for timer to do an import iteration.""" """Callback for timer to do an import iteration."""
if self.doAutoImportBool: if self.doAutoImportBool:
self.startButton.set_label(u' I M P O R T I N G ') self.startButton.set_label(u' _Auto Import Running ')
self.importer.runUpdated() self.importer.runUpdated()
self.addText(".") self.addText(".")
#sys.stdout.write(".") #sys.stdout.write(".")
@ -167,9 +167,9 @@ class GuiAutoImport (threading.Thread):
def reset_startbutton(self): def reset_startbutton(self):
if self.pipe_to_hud is not None: if self.pipe_to_hud is not None:
self.startButton.set_label(u' _Stop Autoimport ') self.startButton.set_label(u' Stop _Autoimport ')
else: else:
self.startButton.set_label(u' _Start Autoimport ') self.startButton.set_label(u' Start _Autoimport ')
return False return False
@ -246,7 +246,7 @@ class GuiAutoImport (threading.Thread):
#print >>self.pipe_to_hud.stdin, "\n" #print >>self.pipe_to_hud.stdin, "\n"
self.pipe_to_hud.communicate('\n') # waits for process to terminate self.pipe_to_hud.communicate('\n') # waits for process to terminate
self.pipe_to_hud = None self.pipe_to_hud = None
self.startButton.set_label(u' _Start Autoimport ') self.startButton.set_label(u' Start _Autoimport ')
#end def GuiAutoImport.startClicked #end def GuiAutoImport.startClicked

View File

@ -44,7 +44,7 @@ except ImportError, inst:
import fpdb_import import fpdb_import
import Database import Database
import RingFilters import Filters
import Charset import Charset
class GuiGraphViewer (threading.Thread): class GuiGraphViewer (threading.Thread):
@ -75,7 +75,7 @@ class GuiGraphViewer (threading.Thread):
"Button2" : True "Button2" : True
} }
self.filters = RingFilters.RingFilters(self.db, self.conf, self.sql, display = filters_display) self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
self.filters.registerButton1Name("Refresh _Graph") self.filters.registerButton1Name("Refresh _Graph")
self.filters.registerButton1Callback(self.generateGraph) self.filters.registerButton1Callback(self.generateGraph)
self.filters.registerButton2Name("_Export to File") self.filters.registerButton2Name("_Export to File")

View File

@ -24,6 +24,8 @@ import gtk
import gobject import gobject
import pango import pango
import os
import traceback
import logging import logging
# logging has been set up in fpdb.py or HUD_main.py, use their settings: # logging has been set up in fpdb.py or HUD_main.py, use their settings:
log = logging.getLogger("logview") log = logging.getLogger("logview")
@ -135,7 +137,7 @@ class GuiLogView:
def loadLog(self): def loadLog(self):
self.liststore.clear() self.liststore.clear()
self.listcols = [] # self.listcols = [] blanking listcols causes sortcols() to fail with index out of range
# guesstimate number of lines in file # guesstimate number of lines in file
if os.path.exists(self.logfile): if os.path.exists(self.logfile):
@ -155,6 +157,15 @@ class GuiLogView:
# 2009-12-02 15:23:21,716 - config DEBUG config logger initialised # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
l = l + 1 l = l + 1
if l > startline: if l > startline:
# NOTE selecting a sort column and then switching to a log file
# with several thousand rows will send cpu 100% for a prolonged period.
# reason is that the append() method seems to sort every record as it goes, rather than
# pulling in the whole file and sorting at the end.
# one fix is to check if a column sort has been selected, reset to date/time asc
# append all the rows and then reselect the required sort order.
# Note: there is no easy method available to revert the list to an "unsorted" state.
# always defaulting to date/time asc doesn't work, because some rows do not have date/time info
# and would end up sorted out of context.
if len(line) > 49 and line[23:26] == ' - ' and line[34:39] == ' ': if len(line) > 49 and line[23:26] == ' - ' and line[34:39] == ' ':
iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) )
else: else:

View File

@ -24,7 +24,7 @@ from time import time, strftime
import fpdb_import import fpdb_import
import Database import Database
import RingFilters import Filters
class GuiPositionalStats (threading.Thread): class GuiPositionalStats (threading.Thread):
def __init__(self, config, querylist, debug=True): def __init__(self, config, querylist, debug=True):
@ -57,7 +57,7 @@ class GuiPositionalStats (threading.Thread):
"Button2" : False "Button2" : False
} }
self.filters = RingFilters.RingFilters(self.db, self.conf, self.sql, display = filters_display) self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
self.filters.registerButton1Name("Refresh") self.filters.registerButton1Name("Refresh")
self.filters.registerButton1Callback(self.refreshStats) self.filters.registerButton1Callback(self.refreshStats)

View File

@ -27,7 +27,7 @@ from time import time, strftime
import Card import Card
import fpdb_import import fpdb_import
import Database import Database
import RingFilters import Filters
import Charset import Charset
import GuiPlayerStats import GuiPlayerStats
@ -79,7 +79,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
"Button2" : True "Button2" : True
} }
self.filters = RingFilters.RingFilters(self.db, self.conf, self.sql, display = filters_display) self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
self.filters.registerButton1Name("_Filters") self.filters.registerButton1Name("_Filters")
self.filters.registerButton1Callback(self.showDetailFilter) self.filters.registerButton1Callback(self.showDetailFilter)
self.filters.registerButton2Name("_Refresh Stats") self.filters.registerButton2Name("_Refresh Stats")

View File

@ -45,7 +45,7 @@ except ImportError, inst:
import Card import Card
import fpdb_import import fpdb_import
import Database import Database
import RingFilters import Filters
import Charset import Charset
class GuiSessionViewer (threading.Thread): class GuiSessionViewer (threading.Thread):
@ -95,7 +95,7 @@ class GuiSessionViewer (threading.Thread):
"Button2" : False "Button2" : False
} }
self.filters = RingFilters.RingFilters(self.db, self.conf, self.sql, display = filters_display) self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
self.filters.registerButton1Name("_Refresh") self.filters.registerButton1Name("_Refresh")
self.filters.registerButton1Callback(self.refreshStats) self.filters.registerButton1Callback(self.refreshStats)

View File

@ -78,6 +78,8 @@ class GuiTourneyPlayerStats (GuiPlayerStats.GuiPlayerStats):
# is column displayed, column heading, xalignment, formatting, celltype # is column displayed, column heading, xalignment, formatting, celltype
self.columns = [ ["siteName", True, "Site", 0.0, "%s", "str"] self.columns = [ ["siteName", True, "Site", 0.0, "%s", "str"]
#,["tourney", False, "Tourney", 0.0, "%s", "str"] # true not allowed for this line #,["tourney", False, "Tourney", 0.0, "%s", "str"] # true not allowed for this line
, ["category", True, "Cat.", 0.0, "%s", "str"]
, ["limitType", True, "Limit", 0.0, "%s", "str"]
, ["currency", True, "Curr.", 0.0, "%s", "str"] , ["currency", True, "Curr.", 0.0, "%s", "str"]
, ["buyIn", True, "BuyIn", 1.0, "%3.2f", "str"] , ["buyIn", True, "BuyIn", 1.0, "%3.2f", "str"]
, ["fee", True, "Fee", 1.0, "%3.2f", "str"] , ["fee", True, "Fee", 1.0, "%3.2f", "str"]

View File

@ -645,7 +645,7 @@ Left-Drag to Move"
</supported_databases> </supported_databases>
<email> <email>
<email host="YOUR_EMAIL_SERVER" username="YOUR_EMAIL_USERNAME" password="YOUR_EMAIL_PASSWORD" useSsl="True" folder="INBOX"/> <email siteName="PokerStars" fetchType="request-summary" host="YOUR_EMAIL_SERVER" username="YOUR_EMAIL_USERNAME" password="YOUR_EMAIL_PASSWORD" useSsl="True" folder="INBOX"/>
</email> </email>
</FreePokerToolsConfig> </FreePokerToolsConfig>
<!-- IMPORTANT: Please note that fpdb stores your email password in clear text. <!-- IMPORTANT: Please note that fpdb stores your email password in clear text.

View File

@ -85,6 +85,8 @@ class Hand(object):
self.isKO = False self.isKO = False
self.isMatrix = False self.isMatrix = False
self.isShootout = False self.isShootout = False
self.added = None
self.addedCurrency = None
self.tourneyComment = None self.tourneyComment = None
self.seating = [] self.seating = []
@ -227,7 +229,7 @@ dealt whether they were seen in a 'dealt to' line
self.dbid_gt = db.getGameTypeId(self.siteId, self.gametype) self.dbid_gt = db.getGameTypeId(self.siteId, self.gametype)
if self.tourNo!=None: if self.tourNo!=None:
self.tourneyTypeId = db.createOrUpdateTourneyType(self) self.tourneyTypeId = db.createTourneyType(self)
db.commit() db.commit()
self.tourneyId = db.createOrUpdateTourney(self, "HHC") self.tourneyId = db.createOrUpdateTourney(self, "HHC")
db.commit() db.commit()

View File

@ -495,6 +495,23 @@ or None if we fail to get the info """
def getTourney(self): def getTourney(self):
return self.tourney return self.tourney
@staticmethod
def changeTimezone(time, givenTimezone, wantedTimezone):
if givenTimezone=="ET" and wantedTimezone=="UTC":
# approximate rules for ET daylight savings time:
if ( time.month == 12 # all of Dec
or (time.month == 11 and time.day > 4) # and most of November
or time.month < 3 # and all of Jan/Feb
or (time.month == 3 and time.day < 11) ): # and 1st 10 days of March
offset = datetime.timedelta(hours=5) # are EST: assume 5 hour offset (ET without daylight saving)
else:
offset = datetime.timedelta(hours=4) # rest is EDT: assume 4 hour offset (ET with daylight saving)
# adjust time into UTC:
time = time + offset
#print " tz = %s start = %s" % (tz, str(hand.starttime))
return time
#end @staticmethod def changeTimezone
@staticmethod @staticmethod
def getTableTitleRe(type, table_name=None, tournament = None, table_number=None): def getTableTitleRe(type, table_name=None, tournament = None, table_number=None):
"Returns string to search in windows titles" "Returns string to search in windows titles"

View File

@ -1,61 +0,0 @@
import imaplib
import Configuration
import os
import pprint
pp = pprint.PrettyPrinter(indent=4)
def open_imap_connection(verbose=False):
# Read the config file
# FIXME
hostname = 'imap.gmail.com'
port = 993
username = 'slartibartfast'
password = '42'
# Connect
if verbose: print "Connecting to %s" % hostname
connection = imaplib.IMAP4_SSL(hostname)
# Login to our account
if verbose: print "Logging in as %s" % username
connection.login(username, password)
return connection
if __name__ == '__main__':
# Read the config file
# FIXME
folder = "INBOX"
c = open_imap_connection(verbose=True)
try:
typ, data = c.list(directory=folder)
print typ, data
c.select('INBOX', readonly=True)
typ, msg_ids = c.search(None, '(SUBJECT "Results for PokerStars Tournament *")')
print typ, msg_ids
msgidlist = msg_ids[0].split(' ')
print msgidlist
for msg in msgidlist:
print 'HEADER:'
typ, msg_data = c.fetch(msg, '(BODY.PEEK[HEADER])')
for response_part in msg_data:
if isinstance(response_part, tuple):
print response_part[1]
print 'BODY TEXT:'
typ, msg_data = c.fetch(msg, '(BODY.PEEK[TEXT])')
for response_part in msg_data:
if isinstance(response_part, tuple):
print response_part[1]
finally:
try:
c.close()
except:
pass
c.logout()

View File

@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#Copyright 2008-2010 Steffen Schaumburg #Copyright 2010 Steffen Schaumburg
#This program is free software: you can redistribute it and/or modify #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 #it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License. #the Free Software Foundation, version 3 of the License.
@ -74,8 +74,8 @@ def run(config, db):
print "completed running Imap import, closing server connection" print "completed running Imap import, closing server connection"
#finally: #finally:
# try: # try:
# server.close() server.close()
# finally: # finally:
# pass # pass
#server.logout() server.logout()

View File

@ -21,26 +21,46 @@ from decimal import Decimal
import datetime import datetime
from Exceptions import FpdbParseError from Exceptions import FpdbParseError
from HandHistoryConverter import *
import PokerStarsToFpdb import PokerStarsToFpdb
from TourneySummary import * from TourneySummary import *
class PokerStarsSummary(TourneySummary): class PokerStarsSummary(TourneySummary):
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl' }
games = { # base, category
"Hold'em" : ('hold','holdem'),
'Omaha' : ('hold','omahahi'),
'Omaha Hi/Lo' : ('hold','omahahilo'),
'Razz' : ('stud','razz'),
'RAZZ' : ('stud','razz'),
'7 Card Stud' : ('stud','studhi'),
'7 Card Stud Hi/Lo' : ('stud','studhilo'),
'Badugi' : ('draw','badugi'),
'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
'5 Card Draw' : ('draw','fivedraw')
}
re_TourNo = re.compile("\#[0-9]+,") re_TourNo = re.compile("\#[0-9]+,")
re_Entries = re.compile("[0-9]+") re_Entries = re.compile("[0-9]+")
re_Prizepool = re.compile("\$[0-9]+\.[0-9]+") re_Prizepool = re.compile("\$[0-9]+\.[0-9]+")
re_Player = re.compile("""(?P<RANK>[0-9]+):\s(?P<NAME>.*)\s\(.*\),(\s)?(\$(?P<WINNINGS>[0-9]+\.[0-9]+))?(?P<STILLPLAYING>still\splaying)?""") re_Player = re.compile(u"""(?P<RANK>[0-9]+):\s(?P<NAME>.*)\s\(.*\),(\s)?(\$(?P<WINNINGS>[0-9]+\.[0-9]+))?(?P<STILLPLAYING>still\splaying)?""")
re_BuyInFee = re.compile("(?P<BUYIN>[0-9]+\.[0-9]+).*(?P<FEE>[0-9]+\.[0-9]+)") re_BuyInFee = re.compile("(?P<BUYIN>[0-9]+\.[0-9]+).*(?P<FEE>[0-9]+\.[0-9]+)")
re_FPP = re.compile("(?P<FPP>[0-9]+)\sFPP") re_FPP = re.compile("(?P<FPP>[0-9]+)\sFPP")
#note: the dollar and cent in the below line are currency-agnostic #note: the dollar and cent in the below line are currency-agnostic
re_Added = re.compile("(?P<DOLLAR>[0-9]+)\.(?P<CENT>[0-9]+)\s(?P<CURRENCY>[A-Z]+)(\sadded\sto\sthe\sprize\spool\sby\sPokerStars)") re_Added = re.compile("(?P<DOLLAR>[0-9]+)\.(?P<CENT>[0-9]+)\s(?P<CURRENCY>[A-Z]+)(\sadded\sto\sthe\sprize\spool\sby\sPokerStars)")
re_DateTime = re.compile("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)") re_DateTime = re.compile("\[(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)")
# = re.compile("") re_DateTimeET = re.compile("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)")
re_GameInfo = re.compile(u""".+(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\s(?P<GAME>Hold\'em|Razz|RAZZ|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball|5\sCard\sDraw)""")
def parseSummary(self): def parseSummary(self):
lines=self.summaryText.splitlines() lines=self.summaryText.splitlines()
self.tourNo = self.re_TourNo.findall(lines[0])[0][1:-1] #ignore game and limit type as thats not recorded self.tourNo = self.re_TourNo.findall(lines[0])[0][1:-1] #ignore game and limit type as thats not recorded
#print "tourNo:",self.tourNo
result=self.re_GameInfo.search(lines[0])
result=result.groupdict()
self.gametype['limitType']=self.limits[result['LIMIT']]
self.gametype['category']=self.games[result['GAME']][1]
if lines[1].find("$")!=-1: #TODO: move this into a method and call that from PokerStarsToFpdb.py:269 if hand.buyinCurrency=="USD" etc. if lines[1].find("$")!=-1: #TODO: move this into a method and call that from PokerStarsToFpdb.py:269 if hand.buyinCurrency=="USD" etc.
self.currency="USD" self.currency="USD"
@ -73,8 +93,10 @@ class PokerStarsSummary(TourneySummary):
result=result.groupdict() result=result.groupdict()
self.added=100*int(Decimal(result['DOLLAR']))+int(Decimal(result['CENT'])) self.added=100*int(Decimal(result['DOLLAR']))+int(Decimal(result['CENT']))
self.addedCurrency=result['CURRENCY'] self.addedCurrency=result['CURRENCY']
#print "TODO: implement added:",self.added,self.addedCurrency
currentLine+=1 currentLine+=1
else:
self.added=0
self.addedCurrency="NA"
#print "after added/entries lines[currentLine]", lines[currentLine] #print "after added/entries lines[currentLine]", lines[currentLine]
result=self.re_Prizepool.findall(lines[currentLine]) result=self.re_Prizepool.findall(lines[currentLine])
@ -84,19 +106,28 @@ class PokerStarsSummary(TourneySummary):
currentLine+=1 currentLine+=1
#print "after prizepool lines[currentLine]", lines[currentLine] #print "after prizepool lines[currentLine]", lines[currentLine]
useET=False
result=self.re_DateTime.search(lines[currentLine]) result=self.re_DateTime.search(lines[currentLine])
if not result:
print "in not result starttime"
useET=True
result=self.re_DateTimeET.search(lines[currentLine])
result=result.groupdict() result=result.groupdict()
datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],result['D'],result['H'],result['MIN'],result['S']) datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],result['D'],result['H'],result['MIN'],result['S'])
self.startTime= datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET" self.startTime= datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
self.startTime = PokerStarsToFpdb.removeET(self.startTime) self.startTime = HandHistoryConverter.changeTimezone(self.startTime, "ET", "UTC")
currentLine+=1 currentLine+=1
result=self.re_DateTime.search(lines[currentLine]) if useET:
result=self.re_DateTimeET.search(lines[currentLine])
else:
result=self.re_DateTime.search(lines[currentLine])
if result: if result:
result=result.groupdict() result=result.groupdict()
datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],result['D'],result['H'],result['MIN'],result['S']) datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],result['D'],result['H'],result['MIN'],result['S'])
self.endTime= datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET" self.endTime= datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
currentLine+=1 self.endTime = HandHistoryConverter.changeTimezone(self.endTime, "ET", "UTC")
currentLine+=1
if lines[currentLine].find("Tournament is still in progress")!=-1: if lines[currentLine].find("Tournament is still in progress")!=-1:
currentLine+=1 currentLine+=1

View File

@ -26,21 +26,6 @@ from decimal import Decimal
# PokerStars HH Format # PokerStars HH Format
def removeET(time):
# approximate rules for ET daylight savings time:
if ( time.month == 12 # all of Dec
or (time.month == 11 and time.day > 4) # and most of November
or time.month < 3 # and all of Jan/Feb
or (time.month == 3 and time.day < 11) ): # and 1st 10 days of March
offset = datetime.timedelta(hours=5) # are EST: assume 5 hour offset (ET without daylight saving)
else:
offset = datetime.timedelta(hours=4) # rest is EDT: assume 4 hour offset (ET with daylight saving)
# adjust time into UTC:
time = time + offset
#print " tz = %s start = %s" % (tz, str(hand.starttime))
return time
#end def removeET
class PokerStars(HandHistoryConverter): class PokerStars(HandHistoryConverter):
# Class Variables # Class Variables
@ -244,7 +229,7 @@ class PokerStars(HandHistoryConverter):
#tz = a.group('TZ') # just assume ET?? #tz = a.group('TZ') # just assume ET??
#print " tz = ", tz, " datetime =", datetimestr #print " tz = ", tz, " datetime =", datetimestr
hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET" hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
hand.startTime = removeET(hand.startTime) hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, "ET", "UTC")
if key == 'HID': if key == 'HID':
hand.handid = info[key] hand.handid = info[key]
if key == 'TOURNO': if key == 'TOURNO':

View File

@ -1,948 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2008-2010 Steffen Schaumburg
#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, version 3 of the License.
#
#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 Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in agpl-3.0.txt.
import threading
import pygtk
pygtk.require('2.0')
import gtk
import os
import sys
from optparse import OptionParser
from time import gmtime, mktime, strftime, strptime
import gobject
#import pokereval
import logging
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
log = logging.getLogger("filter")
import Configuration
import Database
import SQL
import Charset
import Filters
class RingFilters(Filters.Filters):
def __init__(self, db, config, qdict, display = {}, debug=True):
# config and qdict are now redundant
self.debug = debug
self.db = db
self.cursor = db.cursor
self.sql = db.sql
self.conf = db.config
self.display = display
# text used on screen stored here so that it can be configured
self.filterText = {'limitsall':'All', 'limitsnone':'None', 'limitsshow':'Show _Limits'
,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players'
,'playerstitle':'Hero:', 'sitestitle':'Sites:', 'gamestitle':'Games:'
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
,'datestitle':'Date:'
,'groupsall':'All Players'
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
}
gen = self.conf.get_general_params()
self.day_start = 0
if 'day_start' in gen:
self.day_start = float(gen['day_start'])
# Outer Packing box
self.mainVBox = gtk.VBox(False, 0)
self.label = {}
self.callback = {}
self.make_filter()
def make_filter(self):
self.sites = {}
self.games = {}
self.limits = {}
self.seats = {}
self.groups = {}
self.siteid = {}
self.heroes = {}
self.boxes = {}
for site in self.conf.get_supported_sites():
#Get db site id for filtering later
self.cursor.execute(self.sql.query['getSiteId'], (site,))
result = self.db.cursor.fetchall()
if len(result) == 1:
self.siteid[site] = result[0][0]
else:
print "Either 0 or more than one site matched (%s) - EEK" % site
# For use in date ranges.
self.start_date = gtk.Entry(max=12)
self.end_date = gtk.Entry(max=12)
self.start_date.set_property('editable', False)
self.end_date.set_property('editable', False)
# For use in groups etc
self.sbGroups = {}
self.numHands = 0
playerFrame = gtk.Frame()
playerFrame.set_label_align(0.0, 0.0)
vbox = gtk.VBox(False, 0)
self.fillPlayerFrame(vbox, self.display)
playerFrame.add(vbox)
sitesFrame = gtk.Frame()
sitesFrame.set_label_align(0.0, 0.0)
vbox = gtk.VBox(False, 0)
self.fillSitesFrame(vbox)
sitesFrame.add(vbox)
# Game types
gamesFrame = gtk.Frame()
gamesFrame.set_label_align(0.0, 0.0)
gamesFrame.show()
vbox = gtk.VBox(False, 0)
self.fillGamesFrame(vbox)
gamesFrame.add(vbox)
# Limits
limitsFrame = gtk.Frame()
limitsFrame.show()
vbox = gtk.VBox(False, 0)
self.cbLimits = {}
self.cbNoLimits = None
self.cbAllLimits = None
self.cbFL = None
self.cbNL = None
self.cbPL = None
self.rb = {} # radio buttons for ring/tour
self.type = None # ring/tour
self.types = {} # list of all ring/tour values
self.fillLimitsFrame(vbox, self.display)
limitsFrame.add(vbox)
# Seats
seatsFrame = gtk.Frame()
seatsFrame.show()
vbox = gtk.VBox(False, 0)
self.sbSeats = {}
self.fillSeatsFrame(vbox, self.display)
seatsFrame.add(vbox)
# Groups
groupsFrame = gtk.Frame()
groupsFrame.show()
vbox = gtk.VBox(False, 0)
self.fillGroupsFrame(vbox, self.display)
groupsFrame.add(vbox)
# Date
dateFrame = gtk.Frame()
dateFrame.set_label_align(0.0, 0.0)
dateFrame.show()
vbox = gtk.VBox(False, 0)
self.fillDateFrame(vbox)
dateFrame.add(vbox)
# Buttons
self.Button1=gtk.Button("Unnamed 1")
self.Button1.set_sensitive(False)
self.Button2=gtk.Button("Unnamed 2")
self.Button2.set_sensitive(False)
self.mainVBox.add(playerFrame)
self.mainVBox.add(sitesFrame)
self.mainVBox.add(gamesFrame)
self.mainVBox.add(limitsFrame)
self.mainVBox.add(seatsFrame)
self.mainVBox.add(groupsFrame)
self.mainVBox.add(dateFrame)
self.mainVBox.add(self.Button1)
self.mainVBox.add(self.Button2)
self.mainVBox.show_all()
# Should do this cleaner
if "Heroes" not in self.display or self.display["Heroes"] == False:
playerFrame.hide()
if "Sites" not in self.display or self.display["Sites"] == False:
sitesFrame.hide()
if "Games" not in self.display or self.display["Games"] == False:
gamesFrame.hide()
if "Limits" not in self.display or self.display["Limits"] == False:
limitsFrame.hide()
if "Seats" not in self.display or self.display["Seats"] == False:
seatsFrame.hide()
if "Groups" not in self.display or self.display["Groups"] == False:
groupsFrame.hide()
if "Dates" not in self.display or self.display["Dates"] == False:
dateFrame.hide()
if "Button1" not in self.display or self.display["Button1"] == False:
self.Button1.hide()
if "Button2" not in self.display or self.display["Button2"] == False:
self.Button2.hide()
if 'button1' in self.label and self.label['button1']:
self.Button1.set_label( self.label['button1'] )
if 'button2' in self.label and self.label['button2']:
self.Button2.set_label( self.label['button2'] )
if 'button1' in self.callback and self.callback['button1']:
self.Button1.connect("clicked", self.callback['button1'], "clicked")
self.Button1.set_sensitive(True)
if 'button2' in self.callback and self.callback['button2']:
self.Button2.connect("clicked", self.callback['button2'], "clicked")
self.Button2.set_sensitive(True)
# make sure any locks on db are released:
self.db.rollback()
def get_vbox(self):
"""returns the vbox of this thread"""
return self.mainVBox
#end def get_vbox
def getNumHands(self):
return self.numHands
#end def getNumHands
def getSites(self):
return self.sites
#end def getSites
def getGames(self):
return self.games
def getSiteIds(self):
return self.siteid
#end def getSiteIds
def getHeroes(self):
return self.heroes
#end def getHeroes
def getLimits(self):
ltuple = []
for l in self.limits:
if self.limits[l] == True:
ltuple.append(l)
return ltuple
def getType(self):
return(self.type)
def getSeats(self):
if 'from' in self.sbSeats:
self.seats['from'] = self.sbSeats['from'].get_value_as_int()
if 'to' in self.sbSeats:
self.seats['to'] = self.sbSeats['to'].get_value_as_int()
return self.seats
#end def getSeats
def getGroups(self):
return self.groups
def getDates(self):
return self.__get_dates()
#end def getDates
def registerButton1Name(self, title):
self.Button1.set_label(title)
self.label['button1'] = title
def registerButton1Callback(self, callback):
self.Button1.connect("clicked", callback, "clicked")
self.Button1.set_sensitive(True)
self.callback['button1'] = callback
def registerButton2Name(self, title):
self.Button2.set_label(title)
self.label['button2'] = title
#end def registerButton2Name
def registerButton2Callback(self, callback):
self.Button2.connect("clicked", callback, "clicked")
self.Button2.set_sensitive(True)
self.callback['button2'] = callback
#end def registerButton2Callback
def cardCallback(self, widget, data=None):
log.debug( "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) )
def createPlayerLine(self, hbox, site, player):
log.debug('add:"%s"' % player)
label = gtk.Label(site +" id:")
hbox.pack_start(label, False, False, 3)
pname = gtk.Entry()
pname.set_text(player)
pname.set_width_chars(20)
hbox.pack_start(pname, False, True, 0)
pname.connect("changed", self.__set_hero_name, site)
# Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices)
completion = gtk.EntryCompletion()
pname.set_completion(completion)
liststore = gtk.ListStore(gobject.TYPE_STRING)
completion.set_model(liststore)
completion.set_text_column(0)
names = self.db.get_player_names(self.conf, self.siteid[site]) # (config=self.conf, site_id=None, like_player_name="%")
for n in names: # list of single-element "tuples"
_n = Charset.to_gui(n[0])
_nt = (_n, )
liststore.append(_nt)
self.__set_hero_name(pname, site)
def __set_hero_name(self, w, site):
_name = w.get_text()
# get_text() returns a str but we want internal variables to be unicode:
_guiname = unicode(_name)
self.heroes[site] = _guiname
#log.debug("setting heroes[%s]: %s"%(site, self.heroes[site]))
#end def __set_hero_name
def __set_num_hands(self, w, val):
try:
self.numHands = int(w.get_text())
except:
self.numHands = 0
#log.debug("setting numHands:", self.numHands)
#end def __set_num_hands
def createSiteLine(self, hbox, site):
cb = gtk.CheckButton(site)
cb.connect('clicked', self.__set_site_select, site)
cb.set_active(True)
hbox.pack_start(cb, False, False, 0)
def createGameLine(self, hbox, game):
cb = gtk.CheckButton(game)
cb.connect('clicked', self.__set_game_select, game)
hbox.pack_start(cb, False, False, 0)
cb.set_active(True)
def createLimitLine(self, hbox, limit, ltext):
cb = gtk.CheckButton(str(ltext))
cb.connect('clicked', self.__set_limit_select, limit)
hbox.pack_start(cb, False, False, 0)
if limit != "none":
cb.set_active(True)
return(cb)
def __set_site_select(self, w, site):
#print w.get_active()
self.sites[site] = w.get_active()
log.debug("self.sites[%s] set to %s" %(site, self.sites[site]))
def __set_game_select(self, w, game):
#print w.get_active()
self.games[game] = w.get_active()
log.debug("self.games[%s] set to %s" %(game, self.games[game]))
#end def __set_game_select
def __set_limit_select(self, w, limit):
#print w.get_active()
self.limits[limit] = w.get_active()
log.debug("self.limit[%s] set to %s" %(limit, self.limits[limit]))
if limit.isdigit() or (len(limit) > 2 and (limit[-2:] == 'nl' or limit[-2:] == 'fl' or limit[-2:] == 'pl')):
if self.limits[limit]:
if self.cbNoLimits is not None:
self.cbNoLimits.set_active(False)
else:
if self.cbAllLimits is not None:
self.cbAllLimits.set_active(False)
if not self.limits[limit]:
if limit.isdigit():
if self.cbFL is not None:
self.cbFL.set_active(False)
elif (len(limit) > 2 and (limit[-2:] == 'nl')):
if self.cbNL is not None:
self.cbNL.set_active(False)
else:
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "all":
if self.limits[limit]:
#for cb in self.cbLimits.values():
# cb.set_active(True)
if self.cbFL is not None:
self.cbFL.set_active(True)
if self.cbNL is not None:
self.cbNL.set_active(True)
if self.cbPL is not None:
self.cbPL.set_active(True)
elif limit == "none":
if self.limits[limit]:
for cb in self.cbLimits.values():
cb.set_active(False)
if self.cbNL is not None:
self.cbNL.set_active(False)
if self.cbFL is not None:
self.cbFL.set_active(False)
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "fl":
if not self.limits[limit]:
# only toggle all fl limits off if they are all currently on
# this stops turning one off from cascading into 'fl' box off
# and then all fl limits being turned off
all_fl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if t.isdigit():
if not cb.get_active():
all_fl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
t = cb.get_children()[0].get_text()
if t.isdigit():
if self.limits[limit] or all_fl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
if 'tour' in self.rb:
self.rb['tour'].set_active(True)
elif self.type == 'tour':
if 'ring' in self.rb:
self.rb['ring'].set_active(True)
elif limit == "nl":
if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off
all_nl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "nl" in t and len(t) > 2:
if not cb.get_active():
all_nl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "nl" in t and len(t) > 2:
if self.limits[limit] or all_nl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
if 'tour' in self.rb:
self.rb['tour'].set_active(True)
elif self.type == 'tour':
if 'ring' in self.rb:
self.rb['ring'].set_active(True)
elif limit == "pl":
if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off
all_nl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if not cb.get_active():
all_nl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if self.limits[limit] or all_nl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
if 'tour' in self.rb:
self.rb['tour'].set_active(True)
elif self.type == 'tour':
if 'ring' in self.rb:
self.rb['ring'].set_active(True)
elif limit == "ring":
log.debug("set", limit, "to", self.limits[limit])
if self.limits[limit]:
self.type = "ring"
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
if self.types[cb.get_children()[0].get_text()] == 'tour':
cb.set_active(False)
elif limit == "tour":
log.debug( "set", limit, "to", self.limits[limit] )
if self.limits[limit]:
self.type = "tour"
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
if self.types[cb.get_children()[0].get_text()] == 'ring':
cb.set_active(False)
def __set_seat_select(self, w, seat):
#print "__set_seat_select: seat =", seat, "active =", w.get_active()
self.seats[seat] = w.get_active()
log.debug( "self.seats[%s] set to %s" %(seat, self.seats[seat]) )
def __set_group_select(self, w, group):
#print "__set_seat_select: seat =", seat, "active =", w.get_active()
self.groups[group] = w.get_active()
log.debug( "self.groups[%s] set to %s" %(group, self.groups[group]) )
def fillPlayerFrame(self, vbox, display):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['playerstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="refresh", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__refresh, 'players')
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['players'] = vbox1
for site in self.conf.get_supported_sites():
hBox = gtk.HBox(False, 0)
vbox1.pack_start(hBox, False, True, 0)
player = self.conf.supported_sites[site].screen_name
_pname = Charset.to_gui(player)
self.createPlayerLine(hBox, site, _pname)
if "GroupsAll" in display and display["GroupsAll"] == True:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, False, 0)
cb = gtk.CheckButton(self.filterText['groupsall'])
cb.connect('clicked', self.__set_group_select, 'allplayers')
hbox.pack_start(cb, False, False, 0)
self.sbGroups['allplayers'] = cb
self.groups['allplayers'] = False
lbl = gtk.Label('Min # Hands:')
lbl.set_alignment(xalign=1.0, yalign=0.5)
hbox.pack_start(lbl, expand=True, padding=3)
phands = gtk.Entry()
phands.set_text('0')
phands.set_width_chars(8)
hbox.pack_start(phands, False, False, 0)
phands.connect("changed", self.__set_num_hands, site)
top_hbox.pack_start(showb, expand=False, padding=1)
def fillSitesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
top_hbox.show()
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['sitestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'sites')
showb.show()
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
self.boxes['sites'] = vbox1
vbox.pack_start(vbox1, False, False, 0)
for site in self.conf.get_supported_sites():
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
self.createSiteLine(hbox, site)
#Get db site id for filtering later
#self.cursor.execute(self.sql.query['getSiteId'], (site,))
#result = self.db.cursor.fetchall()
#if len(result) == 1:
# self.siteid[site] = result[0][0]
#else:
# print "Either 0 or more than one site matched - EEK"
def fillGamesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['gamestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'games')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['games'] = vbox1
self.cursor.execute(self.sql.query['getGames'])
result = self.db.cursor.fetchall()
if len(result) >= 1:
for line in result:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
self.createGameLine(hbox, line[0])
else:
print "INFO: No games returned from database"
log.info("No games returned from database")
#end def fillGamesFrame
def fillLimitsFrame(self, vbox, display):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['limitstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'limits')
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['limits'] = vbox1
self.cursor.execute(self.sql.query['getCashLimits'])
# selects limitType, bigBlind
result = self.db.cursor.fetchall()
found = {'nl':False, 'fl':False, 'pl':False, 'ring':False, 'tour':False}
if len(result) >= 1:
hbox = gtk.HBox(True, 0)
vbox1.pack_start(hbox, False, False, 0)
vbox2 = gtk.VBox(False, 0)
hbox.pack_start(vbox2, False, False, 0)
vbox3 = gtk.VBox(False, 0)
hbox.pack_start(vbox3, False, False, 0)
for i, line in enumerate(result):
if "UseType" in self.display:
if line[0] != self.display["UseType"]:
continue
hbox = gtk.HBox(False, 0)
if i <= len(result)/2:
vbox2.pack_start(hbox, False, False, 0)
else:
vbox3.pack_start(hbox, False, False, 0)
if True: #line[0] == 'ring':
if line[1] == 'fl':
name = str(line[2])
found['fl'] = True
elif line[1] == 'pl':
name = str(line[2])+line[1]
found['pl'] = True
else:
name = str(line[2])+line[1]
found['nl'] = True
self.cbLimits[name] = self.createLimitLine(hbox, name, name)
self.types[name] = line[0]
found[line[0]] = True # type is ring/tour
self.type = line[0] # if only one type, set it now
if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2:
hbox = gtk.HBox(True, 0)
vbox1.pack_start(hbox, False, False, 0)
vbox2 = gtk.VBox(False, 0)
hbox.pack_start(vbox2, False, False, 0)
vbox3 = gtk.VBox(False, 0)
hbox.pack_start(vbox3, False, False, 0)
hbox = gtk.HBox(False, 0)
vbox2.pack_start(hbox, False, False, 0)
self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall'])
hbox = gtk.HBox(False, 0)
vbox2.pack_start(hbox, False, False, 0)
self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone'])
dest = vbox3 # for ring/tour buttons
if "LimitType" in display and display["LimitType"] == True and found['nl'] and found['fl']:
#if found['fl']:
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbFL = self.createLimitLine(hbox, 'fl', self.filterText['limitsFL'])
#if found['nl']:
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL'])
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbPL = self.createLimitLine(hbox, 'pl', self.filterText['limitsPL'])
dest = vbox2 # for ring/tour buttons
else:
print "INFO: No games returned from database"
log.info("No games returned from database")
if "Type" in display and display["Type"] == True and found['ring'] and found['tour']:
rb1 = gtk.RadioButton(None, self.filterText['ring'])
rb1.connect('clicked', self.__set_limit_select, 'ring')
rb2 = gtk.RadioButton(rb1, self.filterText['tour'])
rb2.connect('clicked', self.__set_limit_select, 'tour')
top_hbox.pack_start(rb1, False, False, 0) # (child, expand, fill, padding)
top_hbox.pack_start(rb2, True, True, 0) # child uses expand space if fill is true
self.rb['ring'] = rb1
self.rb['tour'] = rb2
#print "about to set ring to true"
rb1.set_active(True)
# set_active doesn't seem to call this for some reason so call manually:
self.__set_limit_select(rb1, 'ring')
self.type = 'ring'
top_hbox.pack_start(showb, expand=False, padding=1)
def fillSeatsFrame(self, vbox, display):
hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['seatstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'seats')
hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['seats'] = vbox1
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
lbl_from = gtk.Label(self.filterText['seatsbetween'])
lbl_to = gtk.Label(self.filterText['seatsand'])
adj1 = gtk.Adjustment(value=2, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0)
adj2 = gtk.Adjustment(value=10, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0)
hbox.pack_start(lbl_from, expand=False, padding=3)
hbox.pack_start(sb1, False, False, 0)
hbox.pack_start(lbl_to, expand=False, padding=3)
hbox.pack_start(sb2, False, False, 0)
self.sbSeats['from'] = sb1
self.sbSeats['to'] = sb2
#end def fillSeatsFrame
def fillGroupsFrame(self, vbox, display):
hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['groupstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'groups')
hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['groups'] = vbox1
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, False, 0)
cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow'])
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
cb = gtk.CheckButton(self.filterText['posnshow'])
cb.connect('clicked', self.__set_group_select, 'posn')
hbox.pack_start(cb, False, False, 0)
self.sbGroups['posn'] = cb
self.groups['posn'] = False
if "SeatSep" in display and display["SeatSep"] == True:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
cb = gtk.CheckButton(self.filterText['seatsshow'])
cb.connect('clicked', self.__set_seat_select, 'show')
hbox.pack_start(cb, False, False, 0)
self.sbSeats['show'] = cb
self.seats['show'] = False
def fillCardsFrame(self, vbox):
hbox1 = gtk.HBox(True,0)
hbox1.show()
vbox.pack_start(hbox1, True, True, 0)
cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ]
for j in range(0, len(cards)):
hbox1 = gtk.HBox(True,0)
hbox1.show()
vbox.pack_start(hbox1, True, True, 0)
for i in range(0, len(cards)):
if i < (j + 1):
suit = "o"
else:
suit = "s"
button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit))
button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit))
hbox1.pack_start(button, True, True, 0)
button.show()
def fillDateFrame(self, vbox):
# Hat tip to Mika Bostrom - calendar code comes from PokerStats
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['datestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'dates')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['dates'] = vbox1
hbox = gtk.HBox()
vbox1.pack_start(hbox, False, True, 0)
lbl_start = gtk.Label('From:')
btn_start = gtk.Button()
btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn_start.connect('clicked', self.__calendar_dialog, self.start_date)
hbox.pack_start(lbl_start, expand=False, padding=3)
hbox.pack_start(btn_start, expand=False, padding=3)
hbox.pack_start(self.start_date, expand=False, padding=2)
#New row for end date
hbox = gtk.HBox()
vbox1.pack_start(hbox, False, True, 0)
lbl_end = gtk.Label(' To:')
btn_end = gtk.Button()
btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn_end.connect('clicked', self.__calendar_dialog, self.end_date)
btn_clear = gtk.Button(label=' Clear Dates ')
btn_clear.connect('clicked', self.__clear_dates)
hbox.pack_start(lbl_end, expand=False, padding=3)
hbox.pack_start(btn_end, expand=False, padding=3)
hbox.pack_start(self.end_date, expand=False, padding=2)
hbox.pack_start(btn_clear, expand=False, padding=15)
#end def fillDateFrame
def __refresh(self, widget, entry):
for w in self.mainVBox.get_children():
w.destroy()
self.make_filter()
def __toggle_box(self, widget, entry):
if self.boxes[entry].props.visible:
self.boxes[entry].hide()
widget.set_label("show")
else:
self.boxes[entry].show()
widget.set_label("hide")
#end def __toggle_box
def __calendar_dialog(self, widget, entry):
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
d.set_title('Pick a date')
vb = gtk.VBox()
cal = gtk.Calendar()
vb.pack_start(cal, expand=False, padding=0)
btn = gtk.Button('Done')
btn.connect('clicked', self.__get_date, cal, entry, d)
vb.pack_start(btn, expand=False, padding=4)
d.add(vb)
d.set_position(gtk.WIN_POS_MOUSE)
d.show_all()
#end def __calendar_dialog
def __clear_dates(self, w):
self.start_date.set_text('')
self.end_date.set_text('')
#end def __clear_dates
def __get_dates(self):
# self.day_start gives user's start of day in hours
offset = int(self.day_start * 3600) # calc day_start in seconds
t1 = self.start_date.get_text()
t2 = self.end_date.get_text()
if t1 == '':
t1 = '1970-01-02'
if t2 == '':
t2 = '2020-12-12'
s1 = strptime(t1, "%Y-%m-%d") # make time_struct
s2 = strptime(t2, "%Y-%m-%d")
e1 = mktime(s1) + offset # s1 is localtime, but returned time since epoch is UTC, then add the
e2 = mktime(s2) + offset # s2 is localtime, but returned time since epoch is UTC
e2 = e2 + 24 * 3600 - 1 # date test is inclusive, so add 23h 59m 59s to e2
adj_t1 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e1)) # make adjusted string including time
adj_t2 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e2))
log.info("t1="+t1+" adj_t1="+adj_t1+'.')
return (adj_t1, adj_t2)
#end def __get_dates
def __get_date(self, widget, calendar, entry, win):
# year and day are correct, month is 0..11
(year, month, day) = calendar.get_date()
month += 1
ds = '%04d-%02d-%02d' % (year, month, day)
entry.set_text(ds)
win.destroy()
def main(argv=None):
"""main can also be called in the python interpreter, by supplying the command line as the argument."""
if argv is None:
argv = sys.argv[1:]
def destroy(*args): # call back for terminating the main eventloop
gtk.main_quit()
parser = OptionParser()
(options, argv) = parser.parse_args(args = argv)
config = Configuration.Config()
db = None
db = Database.Database()
db.do_connect(config)
qdict = SQL.SQL(db.get_backend_name())
i = Filters(db, config, qdict)
main_window = gtk.Window()
main_window.connect('destroy', destroy)
main_window.add(i.get_vbox())
main_window.show()
gtk.main()
if __name__ == '__main__':
sys.exit(main())

View File

@ -190,7 +190,7 @@ class Sql:
smallBet int, smallBet int,
bigBet int)""" bigBet int)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['createGametypesTable'] = """CREATE TABLE GameTypes ( self.query['createGametypesTable'] = """CREATE TABLE Gametypes (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
siteId INTEGER, siteId INTEGER,
currency TEXT, currency TEXT,
@ -278,7 +278,7 @@ class Sql:
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
tableName VARCHAR(22) NOT NULL, tableName VARCHAR(22) NOT NULL,
siteHandNo BIGINT NOT NULL, siteHandNo BIGINT NOT NULL,
tourneyId INT UNSIGNED NOT NULL, tourneyId INT UNSIGNED,
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
startTime DATETIME NOT NULL, startTime DATETIME NOT NULL,
importTime DATETIME NOT NULL, importTime DATETIME NOT NULL,
@ -315,7 +315,7 @@ class Sql:
id BIGSERIAL, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
tableName VARCHAR(22) NOT NULL, tableName VARCHAR(22) NOT NULL,
siteHandNo BIGINT NOT NULL, siteHandNo BIGINT NOT NULL,
tourneyId INT NOT NULL, tourneyId INT,
gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
startTime timestamp without time zone NOT NULL, startTime timestamp without time zone NOT NULL,
importTime timestamp without time zone NOT NULL, importTime timestamp without time zone NOT NULL,
@ -351,7 +351,7 @@ class Sql:
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
tableName TEXT(22) NOT NULL, tableName TEXT(22) NOT NULL,
siteHandNo INT NOT NULL, siteHandNo INT NOT NULL,
tourneyId INT NOT NULL, tourneyId INT,
gametypeId INT NOT NULL, gametypeId INT NOT NULL,
startTime REAL NOT NULL, startTime REAL NOT NULL,
importTime REAL NOT NULL, importTime REAL NOT NULL,
@ -401,9 +401,11 @@ class Sql:
maxSeats INT, maxSeats INT,
rebuy BOOLEAN, rebuy BOOLEAN,
rebuyCost INT, rebuyCost INT,
rebuyFee INT,
rebuyChips INT, rebuyChips INT,
addOn BOOLEAN, addOn BOOLEAN,
addOnCost INT, addOnCost INT,
addOnFee INT,
addOnChips INT, addOnChips INT,
knockout BOOLEAN, knockout BOOLEAN,
koBounty INT, koBounty INT,
@ -413,7 +415,9 @@ class Sql:
sng BOOLEAN, sng BOOLEAN,
satellite BOOLEAN, satellite BOOLEAN,
doubleOrNothing BOOLEAN, doubleOrNothing BOOLEAN,
guarantee INT) guarantee INT,
added INT,
addedCurrency VARCHAR(4))
ENGINE=INNODB""" ENGINE=INNODB"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
@ -428,9 +432,11 @@ class Sql:
maxSeats INT, maxSeats INT,
rebuy BOOLEAN, rebuy BOOLEAN,
rebuyCost INT, rebuyCost INT,
rebuyFee INT,
rebuyChips INT, rebuyChips INT,
addOn BOOLEAN, addOn BOOLEAN,
addOnCost INT, addOnCost INT,
addOnFee INT,
addOnChips INT, addOnChips INT,
knockout BOOLEAN, knockout BOOLEAN,
koBounty INT, koBounty INT,
@ -440,7 +446,9 @@ class Sql:
sng BOOLEAN, sng BOOLEAN,
satellite BOOLEAN, satellite BOOLEAN,
doubleOrNothing BOOLEAN, doubleOrNothing BOOLEAN,
guarantee INT)""" guarantee INT,
added INT,
addedCurrency VARCHAR(4))"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
@ -454,9 +462,11 @@ class Sql:
maxSeats INT, maxSeats INT,
rebuy BOOLEAN, rebuy BOOLEAN,
rebuyCost INT, rebuyCost INT,
rebuyFee INT,
rebuyChips INT, rebuyChips INT,
addOn BOOLEAN, addOn BOOLEAN,
addOnCost INT, addOnCost INT,
addOnFee INT,
addOnChips INT, addOnChips INT,
knockout BOOLEAN, knockout BOOLEAN,
koBounty INT, koBounty INT,
@ -466,7 +476,9 @@ class Sql:
sng BOOLEAN, sng BOOLEAN,
satellite BOOLEAN, satellite BOOLEAN,
doubleOrNothing BOOLEAN, doubleOrNothing BOOLEAN,
guarantee INT)""" guarantee INT,
added INT,
addedCurrency VARCHAR(4))"""
################################ ################################
# Create Tourneys # Create Tourneys
@ -548,7 +560,7 @@ class Sql:
comment text, comment text,
commentTs DATETIME, commentTs DATETIME,
tourneysPlayersId BIGINT UNSIGNED, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id), tourneysPlayersId BIGINT UNSIGNED, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
tourneyTypeId SMALLINT UNSIGNED NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId SMALLINT UNSIGNED, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet2 FLOAT,
@ -665,7 +677,7 @@ class Sql:
comment text, comment text,
commentTs timestamp without time zone, commentTs timestamp without time zone,
tourneysPlayersId BIGINT, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id), tourneysPlayersId BIGINT, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
tourneyTypeId INT NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet2 FLOAT,
@ -781,7 +793,7 @@ class Sql:
comment TEXT, comment TEXT,
commentTs REAL, commentTs REAL,
tourneysPlayersId INT, tourneysPlayersId INT,
tourneyTypeId INT NOT NULL DEFAULT 1, tourneyTypeId INT,
wonWhenSeenStreet1 REAL, wonWhenSeenStreet1 REAL,
wonWhenSeenStreet2 REAL, wonWhenSeenStreet2 REAL,
@ -975,7 +987,7 @@ class Sql:
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
activeSeats SMALLINT NOT NULL, activeSeats SMALLINT NOT NULL,
position CHAR(1), position CHAR(1),
tourneyTypeId SMALLINT UNSIGNED NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId SMALLINT UNSIGNED, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT NOT NULL, HDs INT NOT NULL,
@ -1076,7 +1088,7 @@ class Sql:
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
activeSeats SMALLINT, activeSeats SMALLINT,
position CHAR(1), position CHAR(1),
tourneyTypeId INT DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT, HDs INT,
@ -1175,7 +1187,7 @@ class Sql:
playerId INT, playerId INT,
activeSeats INT, activeSeats INT,
position TEXT, position TEXT,
tourneyTypeId INT DEFAULT 1, tourneyTypeId INT,
styleKey TEXT NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey TEXT NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT, HDs INT,
@ -1992,7 +2004,7 @@ class Sql:
- end as bb_or_buyin - end as bb_or_buyin
from Gametypes gt from Gametypes gt
cross join TourneyTypes tt cross join TourneyTypes tt
order by type, limitType DESC, bb_or_buyin DESC""" order by type, gt.limitType DESC, bb_or_buyin DESC"""
self.query['getCashLimits'] = """select DISTINCT type self.query['getCashLimits'] = """select DISTINCT type
, limitType , limitType
, bigBlind as bb_or_buyin , bigBlind as bb_or_buyin
@ -2300,6 +2312,8 @@ class Sql:
,tt.currency AS currency ,tt.currency AS currency
,(CASE WHEN tt.currency = "USD" THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn ,(CASE WHEN tt.currency = "USD" THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
,tt.fee/100.0 AS fee ,tt.fee/100.0 AS fee
,tt.category AS category
,tt.limitType AS limitType
,p.name AS playerName ,p.name AS playerName
,COUNT(1) AS tourneyCount ,COUNT(1) AS tourneyCount
,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank ,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank
@ -2826,7 +2840,7 @@ class Sql:
AND h.startTime < '<enddate_test>' AND h.startTime < '<enddate_test>'
<limit_test> <limit_test>
<game_test> <game_test>
AND gt.type is 'ring' AND gt.type = 'ring'
GROUP BY h.startTime, hp.handId, hp.sawShowdown, hp.totalProfit GROUP BY h.startTime, hp.handId, hp.sawShowdown, hp.totalProfit
ORDER BY h.startTime""" ORDER BY h.startTime"""
@ -3684,15 +3698,17 @@ class Sql:
AND speed=%s AND speed=%s
AND shootout=%s AND shootout=%s
AND matrix=%s AND matrix=%s
AND added=%s
AND addedCurrency=%s
""" """
self.query['insertTourneyType'] = """INSERT INTO TourneyTypes self.query['insertTourneyType'] = """INSERT INTO TourneyTypes
(siteId, currency, buyin, fee, category, limitType, buyInChips, knockout, rebuy, (siteId, currency, buyin, fee, category, limitType, buyInChips, knockout, rebuy,
addOn ,speed, shootout, matrix) addOn ,speed, shootout, matrix, added, addedCurrency)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
""" """
self.query['getTourneyIdByTourneyNo'] = """SELECT t.id self.query['getTourneyByTourneyNo'] = """SELECT t.*
FROM Tourneys t FROM Tourneys t
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id) INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
WHERE tt.siteId=%s AND t.siteTourneyNo=%s WHERE tt.siteId=%s AND t.siteTourneyNo=%s
@ -3706,8 +3722,7 @@ class Sql:
""" """
self.query['updateTourney'] = """UPDATE Tourneys self.query['updateTourney'] = """UPDATE Tourneys
SET tourneyTypeId = %s, SET entries = %s,
entries = %s,
prizepool = %s, prizepool = %s,
startTime = %s, startTime = %s,
endTime = %s, endTime = %s,
@ -3720,20 +3735,18 @@ class Sql:
WHERE id=%s WHERE id=%s
""" """
self.query['getTourneysPlayersId'] = """SELECT id self.query['getTourneysPlayersByIds'] = """SELECT *
FROM TourneysPlayers FROM TourneysPlayers
WHERE tourneyId=%s AND playerId+0=%s WHERE tourneyId=%s AND playerId+0=%s
""" """
self.query['updateTourneysPlayers'] = """UPDATE TourneysPlayers self.query['updateTourneysPlayer'] = """UPDATE TourneysPlayers
SET rank = %s, SET rank = %s,
winnings = %s, winnings = %s,
winningsCurrency = %s, winningsCurrency = %s,
rebuyCount = %s, rebuyCount = %s,
addOnCount = %s, addOnCount = %s,
koCount = %s, koCount = %s
comment = %s,
commentTs = %s
WHERE id=%s WHERE id=%s
""" """
@ -3848,6 +3861,7 @@ class Sql:
street4Bets, street4Bets,
position, position,
tourneyTypeId, tourneyTypeId,
tourneysPlayersId,
startCards, startCards,
street0_3BChance, street0_3BChance,
street0_3BDone, street0_3BDone,
@ -3905,7 +3919,7 @@ class Sql:
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s %s, %s
)""" )"""
################################ ################################

View File

@ -760,38 +760,39 @@ def ffreq4(stat_dict, player):
if __name__== "__main__": if __name__== "__main__":
c = Configuration.Config() c = Configuration.Config()
db_connection = Database.Database(c) #TODO: restore the below code. somehow it creates a version 119 DB but commenting this out makes it print a stat list
h = db_connection.get_last_hand() #db_connection = Database.Database(c)
stat_dict = db_connection.get_stats_from_hand(h, "ring") #h = db_connection.get_last_hand()
#stat_dict = db_connection.get_stats_from_hand(h, "ring")
for player in stat_dict.keys(): #for player in stat_dict.keys():
print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wtsd') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'wtsd')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'profit100') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'profit100')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'saw_f') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'saw_f')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'n') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'n')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'fold_f') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'fold_f')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsd') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsd')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'steal') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'steal')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_SB_steal') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_SB_steal')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_BB_steal') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_BB_steal')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_B') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_B')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'WMsF') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'WMsF')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq1') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq1')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq2') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq2')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq3') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq3')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq4') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq4')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb1') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb1')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb2') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb2')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb3') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb3')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb4') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb4')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq1') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq1')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq2') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq2')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq3') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq3')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq4') #print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq4')
print "\n" #print "\n"
print "\n\nLegal stats:" print "\n\nLegal stats:"
print "(add _0 to name to display with 0 decimal places, _1 to display with 1, etc)\n" print "(add _0 to name to display with 0 decimal places, _1 to display with 1, etc)\n"
@ -804,5 +805,5 @@ if __name__== "__main__":
# print " <pu_stat pu_stat_name = \"%s\"> </pu_stat>" % (attr) # print " <pu_stat pu_stat_name = \"%s\"> </pu_stat>" % (attr)
print print
db_connection.close_connection #db_connection.close_connection

View File

@ -79,19 +79,24 @@ class TourneySummary(object):
self.matrixIdProcessed = None self.matrixIdProcessed = None
self.subTourneyBuyin = None self.subTourneyBuyin = None
self.subTourneyFee = None self.subTourneyFee = None
self.rebuyChips = 0 self.rebuyChips = None
self.addOnChips = 0 self.addOnChips = None
self.rebuyCost = 0 self.rebuyCost = None
self.addOnCost = 0 self.addOnCost = None
self.totalRebuyCount = 0 self.totalRebuyCount = None
self.totalAddOnCount = 0 self.totalAddOnCount = None
self.koBounty = 0 self.koBounty = None
self.tourneyComment = None self.tourneyComment = None
self.players = [] self.players = []
self.isSng = False self.isSng = False
self.isSatellite = False self.isSatellite = False
self.isDoubleOrNothing = False self.isDoubleOrNothing = False
self.guarantee = 0 self.guarantee = None
self.added = None
self.addedCurrency = None
self.gametype = {'category':None, 'limitType':None}
self.comment = None
self.commentTs = None
# Collections indexed by player names # Collections indexed by player names
self.playerIds = {} self.playerIds = {}
@ -150,7 +155,11 @@ class TourneySummary(object):
("SNG", self.isSng), ("SNG", self.isSng),
("SATELLITE", self.isSatellite), ("SATELLITE", self.isSatellite),
("DOUBLE OR NOTHING", self.isDoubleOrNothing), ("DOUBLE OR NOTHING", self.isDoubleOrNothing),
("GUARANTEE", self.guarantee) ("GUARANTEE", self.guarantee),
("ADDED", self.added),
("ADDED CURRENCY", self.addedCurrency),
("COMMENT", self.comment),
("COMMENT TIMESTAMP", self.commentTs)
) )
structs = ( ("PLAYER IDS", self.playerIds), structs = ( ("PLAYER IDS", self.playerIds),
@ -192,7 +201,7 @@ class TourneySummary(object):
for player in self.players: for player in self.players:
id=self.db.get_player_id(self.config, self.siteName, player) id=self.db.get_player_id(self.config, self.siteName, player)
if not id: if not id:
id=self.db.insertPlayer(player, self.siteId) id=self.db.insertPlayer(unicode(player), self.siteId)
self.playerIds.update({player:id}) self.playerIds.update({player:id})
#print "TS.insert players",self.players,"playerIds",self.playerIds #print "TS.insert players",self.players,"playerIds",self.playerIds
@ -201,7 +210,7 @@ class TourneySummary(object):
self.dbid_pids=self.playerIds #TODO:rename this field in Hand so this silly renaming can be removed self.dbid_pids=self.playerIds #TODO:rename this field in Hand so this silly renaming can be removed
#print "TS.self before starting insert",self #print "TS.self before starting insert",self
self.tourneyTypeId = self.db.createOrUpdateTourneyType(self) self.tourneyTypeId = self.db.createTourneyType(self)
self.db.commit() self.db.commit()
self.tourneyId = self.db.createOrUpdateTourney(self, "TS") self.tourneyId = self.db.createOrUpdateTourney(self, "TS")
self.db.commit() self.db.commit()

View File

@ -36,9 +36,9 @@ if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sy
print "Python " + sys.version[0:3] + ' - press return to continue\n' print "Python " + sys.version[0:3] + ' - press return to continue\n'
sys.stdin.readline() sys.stdin.readline()
if os.name=='nt': if os.name=='nt':
os.execvpe('pythonw.exe', ('pythonw.exe', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run) os.execvpe('pythonw.exe', ('pythonw.exe', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run)
else: else:
os.execvpe('python', ('python', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run) os.execvpe('python', ('python', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run)
else: else:
print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n" print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n"
raw_input("Press ENTER to continue.") raw_input("Press ENTER to continue.")
@ -66,6 +66,7 @@ cl_options = string.join(sys.argv[1:])
(options, argv) = Options.fpdb_options() (options, argv) = Options.fpdb_options()
import logging, logging.config import logging, logging.config
log = logging.getLogger("fpdb")
try: try:
import pygtk import pygtk
@ -102,7 +103,7 @@ import GuiPrefs
import GuiLogView import GuiLogView
#import GuiDatabase #import GuiDatabase
import GuiBulkImport import GuiBulkImport
import ImapSummaries import ImapFetcher
import GuiRingPlayerStats import GuiRingPlayerStats
import GuiTourneyPlayerStats import GuiTourneyPlayerStats
import GuiPositionalStats import GuiPositionalStats
@ -114,8 +115,9 @@ import SQL
import Database import Database
import Configuration import Configuration
import Exceptions import Exceptions
import Stats
VERSION = "0.20 plus git" VERSION = "0.20.1 plus git"
class fpdb: class fpdb:
@ -336,29 +338,166 @@ class fpdb:
diatitle="Database Statistics") diatitle="Database Statistics")
#end def dia_database_stats #end def dia_database_stats
def diaHudConfigurator(self, widget, data=None):
"""Opens dialog to set parameters (game category, row count, column count for HUD stat configurator"""
self.hudConfiguratorRows=None
self.hudConfiguratorColumns=None
self.hudConfiguratorGame=None
diaSelections = gtk.Dialog("HUD Configurator - choose category",
self.window,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
label=gtk.Label("Please select the game category for which you want to configure HUD stats:")
diaSelections.vbox.add(label)
label.show()
comboGame = gtk.combo_box_new_text()
comboGame.connect("changed", self.hudConfiguratorComboSelection)
diaSelections.vbox.add(comboGame)
games=self.config.get_supported_games()
for game in games:
comboGame.append_text(game)
comboGame.set_active(0)
comboGame.show()
comboRows = gtk.combo_box_new_text()
comboRows.connect("changed", self.hudConfiguratorComboSelection)
diaSelections.vbox.add(comboRows)
for i in range(1,8):
comboRows.append_text(str(i)+" rows")
comboRows.set_active(0)
comboRows.show()
comboColumns = gtk.combo_box_new_text()
comboColumns.connect("changed", self.hudConfiguratorComboSelection)
diaSelections.vbox.add(comboColumns)
for i in range(1,8):
comboColumns.append_text(str(i)+" columns")
comboColumns.set_active(0)
comboColumns.show()
response=diaSelections.run()
diaSelections.destroy()
if response == gtk.RESPONSE_ACCEPT and self.hudConfiguratorRows!=None and self.hudConfiguratorColumns!=None and self.hudConfiguratorGame!=None:
#print "clicked ok and selected:", self.hudConfiguratorGame,"with", str(self.hudConfiguratorRows), "rows and", str(self.hudConfiguratorColumns), "columns"
self.diaHudConfiguratorTable()
#end def diaHudConfigurator
def hudConfiguratorComboSelection(self, widget):
#TODO: remove this and handle it directly in diaHudConfigurator
result=widget.get_active_text()
if result.endswith(" rows"):
self.hudConfiguratorRows=int(result[0])
elif result.endswith(" columns"):
self.hudConfiguratorColumns=int(result[0])
else:
self.hudConfiguratorGame=result
#end def hudConfiguratorComboSelection
def diaHudConfiguratorTable(self):
"""shows dialogue with Table of ComboBoxes to allow choosing of HUD stats"""
#TODO: add notices to hud configurator: no duplicates, no empties, display options
#TODO: show explanation of what each stat means
diaHudTable = gtk.Dialog("HUD Configurator - please choose your stats",
self.window,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT,
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
label=gtk.Label("Please choose the stats you wish to use in the below table.")
diaHudTable.vbox.add(label)
label.show()
label=gtk.Label("Note that you may not select any stat more than once or it will crash.")
diaHudTable.vbox.add(label)
label.show()
label=gtk.Label("It is not currently possible to select \"empty\" or anything else to that end.")
diaHudTable.vbox.add(label)
label.show()
label=gtk.Label("To configure things like colouring you will still have to manually edit your HUD_config.xml.")
diaHudTable.vbox.add(label)
label.show()
self.hudConfiguratorTableContents=[]
table= gtk.Table(rows=self.hudConfiguratorRows+1, columns=self.hudConfiguratorColumns+1, homogeneous=True)
statDir=dir(Stats)
statDict={}
for attr in statDir:
if attr.startswith('__'): continue
if attr in ("Charset", "Configuration", "Database", "GInitiallyUnowned", "gtk", "pygtk",
"player", "c", "db_connection", "do_stat", "do_tip", "stat_dict",
"h", "re", "re_Percent", "re_Places", ): continue
statDict[attr]=eval("Stats.%s.__doc__" % (attr))
for rowNumber in range(self.hudConfiguratorRows+1):
newRow=[]
for columnNumber in range(self.hudConfiguratorColumns+1):
if rowNumber==0:
if columnNumber==0:
pass
else:
label=gtk.Label("column "+str(columnNumber))
table.attach(child=label, left_attach=columnNumber, right_attach=columnNumber+1, top_attach=rowNumber, bottom_attach=rowNumber+1)
label.show()
elif columnNumber==0:
label=gtk.Label("row "+str(rowNumber))
table.attach(child=label, left_attach=columnNumber, right_attach=columnNumber+1, top_attach=rowNumber, bottom_attach=rowNumber+1)
label.show()
else:
comboBox = gtk.combo_box_new_text()
for stat in statDict.keys():
comboBox.append_text(stat)
comboBox.set_active(0)
newRow.append(comboBox)
table.attach(child=comboBox, left_attach=columnNumber, right_attach=columnNumber+1, top_attach=rowNumber, bottom_attach=rowNumber+1)
comboBox.show()
if rowNumber!=0:
self.hudConfiguratorTableContents.append(newRow)
diaHudTable.vbox.add(table)
table.show()
response=diaHudTable.run()
diaHudTable.destroy()
if response == gtk.RESPONSE_ACCEPT:
self.storeNewHudStatConfig()
#end def diaHudConfiguratorTable
def storeNewHudStatConfig(self):
"""stores selections made in diaHudConfiguratorTable"""
self.obtain_global_lock("diaHudConfiguratorTable")
statTable=[]
for row in self.hudConfiguratorTableContents:
newRow=[]
for column in row:
newField = column.get_active_text()
newRow.append(newField)
statTable.append(newRow)
self.config.editStats(self.hudConfiguratorGame,statTable)
self.config.save() #TODO: make it not store in horrible formatting
self.release_global_lock()
#end def storeNewHudStatConfig
def dia_dump_db(self, widget, data=None): def dia_dump_db(self, widget, data=None):
self.db.dumpDatabase("database-dump.sql") filename = "database-dump.sql"
result = self.db.dumpDatabase()
dumpFile = open(filename, 'w')
dumpFile.write(result)
dumpFile.close()
#end def dia_database_stats #end def dia_database_stats
# def dia_get_db_root_credentials(self):
# """obtains db root credentials from user"""
# user, pw=None, None
#
# dialog=gtk.Dialog(title="DB Credentials needed", parent=None, flags=0,
# buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,"Connect and recreate",gtk.RESPONSE_OK))
#
# label_warning1=gtk.Label("Please enter credentials for a database user for "+self.host+" that has permissions to create a database.")
#
#
# label_user=gtk.Label("Username")
# dialog.vbox.add(label_user)
# label_user.show()
#
# response=dialog.run()
# dialog.destroy()
# return (user, pw, response)
def dia_licensing(self, widget, data=None): def dia_licensing(self, widget, data=None):
self.warning_box("Unimplemented: Licensing") self.warning_box("Unimplemented: Licensing")
@ -393,7 +532,7 @@ class fpdb:
dia_confirm = gtk.MessageDialog(parent=self.window, flags=gtk.DIALOG_DESTROY_WITH_PARENT, type=gtk.MESSAGE_WARNING, dia_confirm = gtk.MessageDialog(parent=self.window, flags=gtk.DIALOG_DESTROY_WITH_PARENT, type=gtk.MESSAGE_WARNING,
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \ diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \
+self.db.database+" on "+self.db.host+" they will be deleted." +self.db.database+" on "+self.db.host+" they will be deleted.\nThis may take a while."
dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted
# disable windowclose, do not want the the underlying processing interrupted mid-process # disable windowclose, do not want the the underlying processing interrupted mid-process
dia_confirm.set_deletable(False) dia_confirm.set_deletable(False)
@ -408,6 +547,10 @@ class fpdb:
# self.release_global_lock() # self.release_global_lock()
# lock_released = True # lock_released = True
self.db.recreate_tables() self.db.recreate_tables()
# find any guibulkimport windows and clear player cache:
for t in self.threads:
if isinstance(t, GuiBulkImport.GuiBulkImport):
t.importer.database.resetPlayerIDs()
self.release_global_lock() self.release_global_lock()
#else: #else:
# for other dbs use same connection as holds global lock # for other dbs use same connection as holds global lock
@ -422,7 +565,7 @@ class fpdb:
dia_restart.destroy() dia_restart.destroy()
self.quit(None, None) self.quit(None, None)
elif response == gtk.RESPONSE_NO: elif response == gtk.RESPONSE_NO:
self.release_global_lock() self.release_global_lock()
print 'User cancelled recreating tables' print 'User cancelled recreating tables'
#if not lock_released: #if not lock_released:
#end def dia_recreate_tables #end def dia_recreate_tables
@ -639,6 +782,7 @@ class fpdb:
<menu action="main"> <menu action="main">
<menuitem action="LoadProf"/> <menuitem action="LoadProf"/>
<menuitem action="SaveProf"/> <menuitem action="SaveProf"/>
<menuitem action="hudConfigurator"/>
<menuitem action="Preferences"/> <menuitem action="Preferences"/>
<separator/> <separator/>
<menuitem action="Quit"/> <menuitem action="Quit"/>
@ -651,6 +795,7 @@ class fpdb:
</menu> </menu>
<menu action="viewers"> <menu action="viewers">
<menuitem action="autoimp"/> <menuitem action="autoimp"/>
<menuitem action="hudConfigurator"/>
<menuitem action="graphs"/> <menuitem action="graphs"/>
<menuitem action="ringplayerstats"/> <menuitem action="ringplayerstats"/>
<menuitem action="tourneyplayerstats"/> <menuitem action="tourneyplayerstats"/>
@ -691,6 +836,7 @@ class fpdb:
('imapsummaries', None, '_Import Tourney Summaries through eMail/IMAP', '<control>I', 'Auto Import and HUD', self.import_imap_summaries), ('imapsummaries', None, '_Import Tourney Summaries through eMail/IMAP', '<control>I', 'Auto Import and HUD', self.import_imap_summaries),
('viewers', None, '_Viewers'), ('viewers', None, '_Viewers'),
('autoimp', None, '_Auto Import and HUD', '<control>A', 'Auto Import and HUD', self.tab_auto_import), ('autoimp', None, '_Auto Import and HUD', '<control>A', 'Auto Import and HUD', self.tab_auto_import),
('hudConfigurator', None, '_HUD Configurator', '<control>H', 'HUD Configurator', self.diaHudConfigurator),
('graphs', None, '_Graphs', '<control>G', 'Graphs', self.tabGraphViewer), ('graphs', None, '_Graphs', '<control>G', 'Graphs', self.tabGraphViewer),
('ringplayerstats', None, 'Ring _Player Stats (tabulated view)', '<control>P', 'Ring Player Stats (tabulated view)', self.tab_ring_player_stats), ('ringplayerstats', None, 'Ring _Player Stats (tabulated view)', '<control>P', 'Ring Player Stats (tabulated view)', self.tab_ring_player_stats),
('tourneyplayerstats', None, '_Tourney Player Stats (tabulated view)', '<control>T', 'Tourney Player Stats (tabulated view)', self.tab_tourney_player_stats), ('tourneyplayerstats', None, '_Tourney Player Stats (tabulated view)', '<control>T', 'Tourney Player Stats (tabulated view)', self.tab_tourney_player_stats),
@ -703,7 +849,7 @@ class fpdb:
('rebuildhudcache', None, 'Rebuild HUD Cache', None, 'Rebuild HUD Cache', self.dia_recreate_hudcache), ('rebuildhudcache', None, 'Rebuild HUD Cache', None, 'Rebuild HUD Cache', self.dia_recreate_hudcache),
('rebuildindexes', None, 'Rebuild DB Indexes', None, 'Rebuild DB Indexes', self.dia_rebuild_indexes), ('rebuildindexes', None, 'Rebuild DB Indexes', None, 'Rebuild DB Indexes', self.dia_rebuild_indexes),
('databasestats', None, '_Statistics', None, 'View Database Statistics', self.dia_database_stats), ('databasestats', None, '_Statistics', None, 'View Database Statistics', self.dia_database_stats),
('dumptofile', None, 'Dump Database to Textfile', None, 'Dump Database to Textfile (takes much time, RAM, HD)', self.dia_dump_db), ('dumptofile', None, 'Dump Database to Textfile (takes ALOT of time)', None, 'Dump Database to Textfile (takes ALOT of time)', self.dia_dump_db),
('help', None, '_Help'), ('help', None, '_Help'),
('Logs', None, '_Log Messages', None, 'Log and Debug Messages', self.dia_logs), ('Logs', None, '_Log Messages', None, 'Log and Debug Messages', self.dia_logs),
('About', None, 'A_bout', None, 'About the program', self.dia_about), ('About', None, 'A_bout', None, 'About the program', self.dia_about),
@ -721,7 +867,7 @@ class fpdb:
#end def get_menu #end def get_menu
def import_imap_summaries(self, widget, data=None): def import_imap_summaries(self, widget, data=None):
result=ImapSummaries.run(self.config, self.db) result=ImapFetcher.run(self.config, self.db)
#print "import imap summaries result:", result #print "import imap summaries result:", result
#end def import_imap_summaries #end def import_imap_summaries
@ -842,12 +988,23 @@ class fpdb:
def quit(self, widget, data=None): def quit(self, widget, data=None):
# TODO: can we get some / all of the stuff done in this function to execute on any kind of abort? # TODO: can we get some / all of the stuff done in this function to execute on any kind of abort?
#FIXME get two "quitting normally" messages, following the addition of the self.window.destroy() call #FIXME get two "quitting normally" messages, following the addition of the self.window.destroy() call
print "Quitting normally" # ... because self.window.destroy() leads to self.destroy() which calls this!
if not self.quitting:
print "Quitting normally"
self.quitting = True
# TODO: check if current settings differ from profile, if so offer to save or abort # TODO: check if current settings differ from profile, if so offer to save or abort
try:
if self.db is not None and self.db.connected: if self.db!=None:
self.db.disconnect() if self.db.backend==self.db.MYSQL_INNODB:
except _mysql_exceptions.OperationalError: # oh, damn, we're already disconnected try:
if self.db is not None and self.db.connected():
self.db.disconnect()
except _mysql_exceptions.OperationalError: # oh, damn, we're already disconnected
pass
else:
if self.db is not None and self.db.connected():
self.db.disconnect()
else:
pass pass
self.statusIcon.set_visible(False) self.statusIcon.set_visible(False)
@ -900,6 +1057,9 @@ class fpdb:
def tab_main_help(self, widget, data=None): def tab_main_help(self, widget, data=None):
"""Displays a tab with the main fpdb help screen""" """Displays a tab with the main fpdb help screen"""
mh_tab=gtk.Label("""Welcome to Fpdb! mh_tab=gtk.Label("""Welcome to Fpdb!
To be notified of new snapshots and releases go to https://lists.sourceforge.net/lists/listinfo/fpdb-announce and subscribe.
If you want to follow development more closely go to https://lists.sourceforge.net/lists/listinfo/fpdb-main and subscribe.
This program is currently in an alpha-state, so our database format is still sometimes changed. This program is currently in an alpha-state, so our database format is still sometimes changed.
You should therefore always keep your hand history files so that you can re-import after an update, if necessary. You should therefore always keep your hand history files so that you can re-import after an update, if necessary.
@ -930,6 +1090,7 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt and gpl-3.0.txt
self.lock = interlocks.InterProcessLock(name="fpdb_global_lock") self.lock = interlocks.InterProcessLock(name="fpdb_global_lock")
self.db = None self.db = None
self.status_bar = None self.status_bar = None
self.quitting = False
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event) self.window.connect("delete_event", self.delete_event)

View File

@ -152,6 +152,8 @@ class Importer:
#Add an individual file to filelist #Add an individual file to filelist
def addImportFile(self, filename, site = "default", filter = "passthrough"): def addImportFile(self, filename, site = "default", filter = "passthrough"):
#TODO: test it is a valid file -> put that in config!! #TODO: test it is a valid file -> put that in config!!
#print "addimportfile: filename is a", filename.__class__
# filename now comes in as unicode
if filename in self.filelist or not os.path.exists(filename): if filename in self.filelist or not os.path.exists(filename):
return return
self.filelist[filename] = [site] + [filter] self.filelist[filename] = [site] + [filter]
@ -177,10 +179,11 @@ class Importer:
if os.path.isdir(inputPath): if os.path.isdir(inputPath):
for subdir in os.walk(inputPath): for subdir in os.walk(inputPath):
for file in subdir[2]: for file in subdir[2]:
self.addImportFile(os.path.join(subdir[0], file), site=site, self.addImportFile(unicode(os.path.join(subdir[0], file),'utf-8'),
filter=filter) site=site, filter=filter)
else: else:
self.addImportFile(inputPath, site=site, filter=filter)
self.addImportFile(unicode(inputPath,'utf-8'), site=site, filter=filter)
#Add a directory of files to filelist #Add a directory of files to filelist
#Only one import directory per site supported. #Only one import directory per site supported.
#dirlist is a hash of lists: #dirlist is a hash of lists:
@ -406,7 +409,8 @@ class Importer:
conv = None conv = None
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, time()) (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, time())
file = file.decode(Configuration.LOCALE_ENCODING) # sc: is there any need to decode this? maybe easier to skip it than guess at the encoding?
#file = file.decode("utf-8") #(Configuration.LOCALE_ENCODING)
# Load filter, process file, pass returned filename to import_fpdb_file # Load filter, process file, pass returned filename to import_fpdb_file
if self.settings['threads'] > 0 and self.writeq is not None: if self.settings['threads'] > 0 and self.writeq is not None:

View File

@ -0,0 +1,116 @@
fpdb database dump
DB version=136
###################
Table Autorates
###################
empty table
###################
Table Backings
###################
empty table
###################
Table Gametypes
###################
empty table
###################
Table Hands
###################
empty table
###################
Table HandsActions
###################
empty table
###################
Table HandsPlayers
###################
empty table
###################
Table HudCache
###################
empty table
###################
Table Players
###################
empty table
###################
Table Settings
###################
version=136
###################
Table Sites
###################
id=1
name=Full Tilt Poker
code=FT
id=2
name=PokerStars
code=PS
id=3
name=Everleaf
code=EV
id=4
name=Win2day
code=W2
id=5
name=OnGame
code=OG
id=6
name=UltimateBet
code=UB
id=7
name=Betfair
code=BF
id=8
name=Absolute
code=AB
id=9
name=PartyPoker
code=PP
id=10
name=Partouche
code=PA
id=11
name=Carbon
code=CA
id=12
name=PKR
code=PK
###################
Table TourneyTypes
###################
empty table
###################
Table Tourneys
###################
empty table
###################
Table TourneysPlayers
###################
empty table