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

Conflicts:
	pyfpdb/Hand.py
This commit is contained in:
Worros 2009-07-01 09:21:21 +08:00
commit 7351749b7a
19 changed files with 500 additions and 558 deletions

View File

@ -86,14 +86,34 @@ class Site:
self.aux_window = node.getAttribute("aux_window") self.aux_window = node.getAttribute("aux_window")
self.font = node.getAttribute("font") self.font = node.getAttribute("font")
self.font_size = node.getAttribute("font_size") self.font_size = node.getAttribute("font_size")
self.use_frames = node.getAttribute("use_frames") self.use_frames = node.getAttribute("use_frames")
self.enabled = fix_tf(node.getAttribute("enabled"), default = True) self.enabled = fix_tf(node.getAttribute("enabled"), default = True)
self.xpad = node.getAttribute("xpad")
self.ypad = node.getAttribute("ypad")
self.layout = {} self.layout = {}
for layout_node in node.getElementsByTagName('layout'): for layout_node in node.getElementsByTagName('layout'):
lo = Layout(layout_node) lo = Layout(layout_node)
self.layout[lo.max] = lo self.layout[lo.max] = lo
# Site defaults
if self.xpad == "": self.xpad = 1
else: self.xpad = int(self.xpad)
if self.ypad == "": self.ypad = 0
else: self.ypad = int(self.ypad)
if self.font_size == "": self.font_size = 7
else: self.font_size = int(self.font_size)
if self.hudopacity == "": self.hudopacity = 1.0
else: self.hudopacity = float(self.hudopacity)
if self.use_frames == "": self.use_frames = False
if self.font == "": self.font = "Sans"
if self.hudbgcolor == "": self.hudbgcolor = "000000"
if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF"
def __str__(self): def __str__(self):
temp = "Site = " + self.site_name + "\n" temp = "Site = " + self.site_name + "\n"
for key in dir(self): for key in dir(self):
@ -119,9 +139,16 @@ class Stat:
class Game: class Game:
def __init__(self, node): def __init__(self, node):
self.game_name = node.getAttribute("game_name") self.game_name = node.getAttribute("game_name")
self.db = node.getAttribute("db")
self.rows = int( node.getAttribute("rows") ) self.rows = int( node.getAttribute("rows") )
self.cols = int( node.getAttribute("cols") ) self.cols = int( node.getAttribute("cols") )
self.xpad = node.getAttribute("xpad")
self.ypad = node.getAttribute("ypad")
# Defaults
if self.xpad == "": self.xpad = 1
else: self.xpad = int(self.xpad)
if self.ypad == "": self.ypad = 0
else: self.ypad = int(self.ypad)
aux_text = node.getAttribute("aux") aux_text = node.getAttribute("aux")
aux_list = aux_text.split(',') aux_list = aux_text.split(',')
@ -146,9 +173,10 @@ class Game:
def __str__(self): def __str__(self):
temp = "Game = " + self.game_name + "\n" temp = "Game = " + self.game_name + "\n"
temp = temp + " db = %s\n" % self.db
temp = temp + " rows = %d\n" % self.rows temp = temp + " rows = %d\n" % self.rows
temp = temp + " cols = %d\n" % self.cols temp = temp + " cols = %d\n" % self.cols
temp = temp + " xpad = %d\n" % self.xpad
temp = temp + " ypad = %d\n" % self.ypad
temp = temp + " aux = %s\n" % self.aux temp = temp + " aux = %s\n" % self.aux
for stat in self.stats.keys(): for stat in self.stats.keys():
@ -631,6 +659,8 @@ class Config:
parms["font"] = self.supported_sites[site].font parms["font"] = self.supported_sites[site].font
parms["font_size"] = self.supported_sites[site].font_size parms["font_size"] = self.supported_sites[site].font_size
parms["enabled"] = self.supported_sites[site].enabled parms["enabled"] = self.supported_sites[site].enabled
parms["xpad"] = self.supported_sites[site].xpad
parms["ypad"] = self.supported_sites[site].ypad
return parms return parms
def set_site_parameters(self, site_name, converter = None, decoder = None, def set_site_parameters(self, site_name, converter = None, decoder = None,
@ -681,9 +711,10 @@ class Config:
param = {} param = {}
if self.supported_games.has_key(name): if self.supported_games.has_key(name):
param['game_name'] = self.supported_games[name].game_name param['game_name'] = self.supported_games[name].game_name
param['db'] = self.supported_games[name].db
param['rows'] = self.supported_games[name].rows param['rows'] = self.supported_games[name].rows
param['cols'] = self.supported_games[name].cols param['cols'] = self.supported_games[name].cols
param['xpad'] = self.supported_games[name].xpad
param['ypad'] = self.supported_games[name].ypad
param['aux'] = self.supported_games[name].aux param['aux'] = self.supported_games[name].aux
return param return param

View File

@ -39,7 +39,8 @@ import SQL
import Card import Card
class Database: class Database:
def __init__(self, c, db_name, game): def __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more
print "\ncreating Database instance, sql =", sql
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.fdb.do_connect(c) self.fdb.do_connect(c)
self.connection = self.fdb.db self.connection = self.fdb.db
@ -48,7 +49,12 @@ class Database:
self.import_options = c.get_import_parameters() self.import_options = c.get_import_parameters()
self.type = db_params['db-type'] self.type = db_params['db-type']
self.backend = db_params['db-backend'] self.backend = db_params['db-backend']
self.sql = SQL.Sql(game = game, type = self.type, db_server = db_params['db-server']) self.db_server = db_params['db-server']
# where possible avoid creating new SQL instance by using the global one passed in
if sql == None:
self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server'])
else:
self.sql = sql
self.connection.rollback() self.connection.rollback()
# To add to config: # To add to config:
@ -81,6 +87,8 @@ class Database:
#row = cur.fetchone() #row = cur.fetchone()
self.saveActions = False if self.import_options['saveActions'] == False else True self.saveActions = False if self.import_options['saveActions'] == False else True
def do_connect(self, c):
self.fdb.do_connect(c)
def commit(self): def commit(self):
self.fdb.db.commit() self.fdb.db.commit()
@ -88,6 +96,19 @@ class Database:
def close_connection(self): def close_connection(self):
self.connection.close() self.connection.close()
def disconnect(self, due_to_error=False):
"""Disconnects the DB (rolls back if param is true, otherwise commits"""
self.fdb.disconnect(due_to_error)
def reconnect(self, due_to_error=False):
"""Reconnects the DB"""
self.fdb.reconnect(due_to_error=False)
def get_backend_name(self):
"""Reconnects the DB"""
return self.fdb.get_backend_name()
def get_table_name(self, hand_id): def get_table_name(self, hand_id):
c = self.connection.cursor() c = self.connection.cursor()
c.execute(self.sql.query['get_table_name'], (hand_id, )) c.execute(self.sql.query['get_table_name'], (hand_id, ))
@ -138,12 +159,8 @@ class Database:
cards = {} cards = {}
c = self.connection.cursor() c = self.connection.cursor()
c.execute(self.sql.query['get_common_cards'], [hand]) c.execute(self.sql.query['get_common_cards'], [hand])
colnames = [desc[0] for desc in c.description] # row = c.fetchone()
for row in c.fetchall(): cards['common'] = c.fetchone()
s_dict = {}
for name, val in zip(colnames, row):
s_dict[name] = val
cards['common'] = (self.convert_cards(s_dict))
return cards return cards
def convert_cards(self, d): def convert_cards(self, d):
@ -326,7 +343,6 @@ class Database:
if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop':
fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
t5 = time() t5 = time()
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
t6 = time() t6 = time()
if self.saveActions: if self.saveActions:
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos)
@ -361,8 +377,6 @@ class Database:
if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop':
fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
if self.saveActions: if self.saveActions:
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos)
return hands_id return hands_id

View File

@ -30,12 +30,11 @@ import fpdb_db
import FpdbSQLQueries import FpdbSQLQueries
class Filters(threading.Thread): class Filters(threading.Thread):
def __init__(self, db, settings, config, qdict, display = {},debug=True): def __init__(self, db, config, qdict, display = {}, debug=True):
self.debug=debug self.debug=debug
#print "start of GraphViewer constructor" #print "start of GraphViewer constructor"
self.db=db self.db=db
self.cursor=db.cursor self.cursor=db.cursor
self.settings=settings
self.sql=qdict self.sql=qdict
self.conf = config self.conf = config
self.display = display self.display = display
@ -235,7 +234,7 @@ class Filters(threading.Thread):
def __set_hero_name(self, w, site): def __set_hero_name(self, w, site):
self.heroes[site] = w.get_text() self.heroes[site] = w.get_text()
# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) # print "DEBUG: setting heroes[%s]: %s"%(site, self.heroes[site])
def createSiteLine(self, hbox, site): def createSiteLine(self, hbox, site):
cb = gtk.CheckButton(site) cb = gtk.CheckButton(site)
@ -556,23 +555,12 @@ def main(argv=None):
config = Configuration.Config() config = Configuration.Config()
db = None db = None
settings = {}
settings.update(config.get_db_parameters())
settings.update(config.get_tv_parameters())
settings.update(config.get_import_parameters())
settings.update(config.get_default_paths())
db = fpdb_db.fpdb_db() db = fpdb_db.fpdb_db()
db.connect(settings['db-backend'], db.do_connect(config)
settings['db-host'],
settings['db-databaseName'],
settings['db-user'],
settings['db-password'])
qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name()) qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name())
i = Filters(db, settings, config, qdict) i = Filters(db, config, qdict)
main_window = gtk.Window() main_window = gtk.Window()
main_window.connect('destroy', destroy) main_window.connect('destroy', destroy)
main_window.add(i.get_vbox()) main_window.add(i.get_vbox())

View File

@ -248,43 +248,6 @@ class FpdbSQLQueries:
self.query['createHandsTable'] = """ """ self.query['createHandsTable'] = """ """
################################
# Create Gametypes
################################
if(self.dbname == 'MySQL InnoDB'):
self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards (
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id),
card1Value smallint NOT NULL,
card1Suit char(1) NOT NULL,
card2Value smallint NOT NULL,
card2Suit char(1) NOT NULL,
card3Value smallint NOT NULL,
card3Suit char(1) NOT NULL,
card4Value smallint NOT NULL,
card4Suit char(1) NOT NULL,
card5Value smallint NOT NULL,
card5Suit char(1) NOT NULL)
ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'):
self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards (
id BIGSERIAL, PRIMARY KEY (id),
handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id),
card1Value smallint,
card1Suit char(1),
card2Value smallint,
card2Suit char(1),
card3Value smallint,
card3Suit char(1),
card4Value smallint,
card4Suit char(1),
card5Value smallint,
card5Suit char(1))"""
elif(self.dbname == 'SQLite'):
self.query['createBoardCardsTable'] = """ """
################################ ################################
# Create TourneyTypes # Create TourneyTypes
################################ ################################
@ -1550,136 +1513,6 @@ class FpdbSQLQueries:
elif(self.dbname == 'SQLite'): elif(self.dbname == 'SQLite'):
self.query['playerStatsByPosition'] = """ """ self.query['playerStatsByPosition'] = """ """
if(self.dbname == 'MySQL InnoDB'):
self.query['playerStatsByPositionAndHoleCards'] = """
SELECT
concat(upper(stats.limitType), ' '
,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' '
,stats.name, ' $'
,cast(trim(leading ' ' from
case when stats.bigBlind < 100 then format(stats.bigBlind/100.0,2)
else format(stats.bigBlind/100.0,0)
end ) as char)
) AS Game
,case when stats.PlPosition = -2 then 'BB'
when stats.PlPosition = -1 then 'SB'
when stats.PlPosition = 0 then 'Btn'
when stats.PlPosition = 1 then 'CO'
when stats.PlPosition = 2 then 'MP'
when stats.PlPosition = 5 then 'EP'
else '??'
end AS PlPosition
/*,stats.n*/,hprof2.n
/*,stats.vpip*/,0
/*,stats.pfr*/,0
/*,stats.saw_f*/,0
/*,stats.sawsd*/,0
/*,stats.wtsdwsf*/,0
/*,stats.wmsd*/,0
/*,stats.FlAFq*/,0
/*,stats.TuAFq*/,0
/*,stats.RvAFq*/,0
/*,stats.PoFAFq*/,0
/* if you have handsactions data the next 3 fields should give same answer as
following 3 commented out fields */
/*,stats.Net
,stats.BBper100
,stats.Profitperhand*/
,format(hprof2.sum_profit/100.0,2) AS Net
/*,format((hprof2.sum_profit/(stats.bigBlind+0.0)) / (stats.n/100.0),2)*/,0
AS BBlPer100
,hprof2.profitperhand AS Profitperhand
,format(hprof2.variance,2) AS Variance
FROM
(select /* stats from hudcache */
gt.base
,gt.category
,upper(gt.limitType) as limitType
,s.name
,gt.bigBlind
,hc.gametypeId
,case when hc.position = 'B' then -2
when hc.position = 'S' then -1
when hc.position = 'D' then 0
when hc.position = 'C' then 1
when hc.position = 'M' then 2
when hc.position = 'E' then 5
else 9
end as PlPosition
,sum(HDs) AS n
,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip
,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr
,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f
,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd
,case when sum(street1Seen) = 0 then '-'
else format(100.0*sum(sawShowdown)/sum(street1Seen),1)
end AS wtsdwsf
,case when sum(sawShowdown) = 0 then '-'
end AS wtsdwsf
,case when sum(sawShowdown) = 0 then '-'
else format(100.0*sum(wonAtSD)/sum(sawShowdown),1)
end AS wmsd
,case when sum(street1Seen) = 0 then '-'
else format(100.0*sum(street1Aggr)/sum(street1Seen),1)
end AS FlAFq
,case when sum(street2Seen) = 0 then '-'
else format(100.0*sum(street2Aggr)/sum(street2Seen),1)
end AS TuAFq
,case when sum(street3Seen) = 0 then '-'
else format(100.0*sum(street3Aggr)/sum(street3Seen),1)
end AS RvAFq
,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-'
else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr))
/(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1)
end AS PoFAFq
,format(sum(totalProfit)/100.0,2) AS Net
,format((sum(totalProfit)/(gt.bigBlind+0.0)) / (sum(HDs)/100.0),2)
AS BBper100
,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand
from Gametypes gt
inner join Sites s on s.Id = gt.siteId
inner join HudCache hc on hc.gameTypeId = gt.Id
where hc.playerId in <player_test>
# use <gametype_test> here ?
group by gt.base
,gt.category
,upper(gt.limitType)
,s.name
,gt.bigBlind
,hc.gametypeId
,PlPosition
) stats
inner join
( select # profit from handsplayers/handsactions
hprof.gameTypeId,
case when hprof.position = 'B' then -2
when hprof.position = 'S' then -1
when hprof.position in ('3','4') then 2
when hprof.position in ('6','7') then 5
else hprof.position
end as PlPosition,
sum(hprof.profit) as sum_profit,
avg(hprof.profit/100.0) as profitperhand,
variance(hprof.profit/100.0) as variance,
count(*) as n
from
(select hp.handId, h.gameTypeId, hp.position, hp.winnings, SUM(ha.amount) as costs
, hp.winnings - SUM(ha.amount) as profit
from HandsPlayers hp
inner join Hands h ON h.id = hp.handId
left join HandsActions ha ON ha.handsPlayerId = hp.id
where hp.playerId in <player_test>
# use <gametype_test> here ?
and hp.tourneysPlayersId IS NULL
and ((hp.card1Value = <first_card> and hp.card2Value = <second_card>) or (hp.card1Value = <second_card> and hp.card2Value = <first_card>))
group by hp.handId, h.gameTypeId, hp.position, hp.winnings
) hprof
group by hprof.gameTypeId, PlPosition
) hprof2
on ( hprof2.gameTypeId = stats.gameTypeId
and hprof2.PlPosition = stats.PlPosition)
order by stats.category, stats.limittype, stats.bigBlind, cast(stats.PlPosition as signed)
"""
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'):
self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""

View File

@ -43,14 +43,14 @@ import Filters
class GuiGraphViewer (threading.Thread): class GuiGraphViewer (threading.Thread):
def __init__(self, db, settings, querylist, config, debug=True): def __init__(self, querylist, config, debug=True):
"""Constructor for GraphViewer""" """Constructor for GraphViewer"""
self.debug=debug self.debug=debug
#print "start of GraphViewer constructor" #print "start of GraphViewer constructor"
self.db=db self.db = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.cursor=db.cursor self.db.do_connect(config)
self.settings=settings
self.sql=querylist self.sql = querylist
self.conf = config self.conf = config
filters_display = { "Heroes" : True, filters_display = { "Heroes" : True,
@ -63,7 +63,7 @@ class GuiGraphViewer (threading.Thread):
"Button2" : True "Button2" : True
} }
self.filters = Filters.Filters(db, settings, config, querylist, display = filters_display) self.filters = Filters.Filters(self.db, config, querylist, 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")
@ -146,7 +146,7 @@ class GuiGraphViewer (threading.Thread):
for site in sites: for site in sites:
if sites[site] == True: if sites[site] == True:
sitenos.append(siteids[site]) sitenos.append(siteids[site])
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append(result[0][0]) playerids.append(result[0][0])
@ -226,7 +226,7 @@ class GuiGraphViewer (threading.Thread):
#print "DEBUG: sql query:" #print "DEBUG: sql query:"
#print tmp #print tmp
self.cursor.execute(tmp) self.db.cursor.execute(tmp)
#returns (HandId,Winnings,Costs,Profit) #returns (HandId,Winnings,Costs,Profit)
winnings = self.db.cursor.fetchall() winnings = self.db.cursor.fetchall()
self.db.db.rollback() self.db.db.rollback()

View File

@ -66,7 +66,7 @@ class GuiPlayerStats (threading.Thread):
"Button2" : True "Button2" : True
} }
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) self.filters = Filters.Filters(self.db, config, querylist, 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") self.filters.registerButton2Name("_Refresh")
@ -227,11 +227,6 @@ class GuiPlayerStats (threading.Thread):
if not flags: holecards = False if not flags: holecards = False
else: holecards = flags[0] else: holecards = flags[0]
self.stats_table = gtk.Table(1, 1, False)
self.stats_table.set_col_spacings(4)
self.stats_table.show()
tmp = self.sql.query[query] tmp = self.sql.query[query]
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates) tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates)
self.cursor.execute(tmp) self.cursor.execute(tmp)
@ -279,10 +274,6 @@ class GuiPlayerStats (threading.Thread):
while sqlrow < rows: while sqlrow < rows:
treerow = [] treerow = []
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
for col,column in enumerate(cols_to_show): for col,column in enumerate(cols_to_show):
if column[colalias] in colnames: if column[colalias] in colnames:
value = result[sqlrow][colnames.index(column[colalias])] value = result[sqlrow][colnames.index(column[colalias])]

View File

@ -20,6 +20,7 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import os import os
from time import time, strftime
import fpdb_import import fpdb_import
import fpdb_db import fpdb_db
@ -58,21 +59,50 @@ class GuiPositionalStats (threading.Thread):
"Button2" : False "Button2" : False
} }
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) self.filters = Filters.Filters(self.db, config, querylist, display = filters_display)
self.filters.registerButton1Name("Refresh") self.filters.registerButton1Name("Refresh")
self.filters.registerButton1Callback(self.refreshStats) self.filters.registerButton1Callback(self.refreshStats)
# ToDo: store in config
# ToDo: create popup to adjust column config
# columns to display, keys match column name returned by sql, values in tuple are:
# is column displayed, column heading, xalignment, formatting
self.columns = [ ["game", True, "Game", 0.0, "%s"]
, ["hand", False, "Hand", 0.0, "%s"] # true not allowed for this line
, ["plposition", False, "Posn", 1.0, "%s"] # true not allowed for this line (set in code)
, ["n", True, "Hds", 1.0, "%d"]
, ["avgseats", True, "Seats", 1.0, "%3.1f"]
, ["vpip", True, "VPIP", 1.0, "%3.1f"]
, ["pfr", True, "PFR", 1.0, "%3.1f"]
, ["pf3", True, "PF3", 1.0, "%3.1f"]
, ["steals", True, "Steals", 1.0, "%3.1f"]
, ["saw_f", True, "Saw_F", 1.0, "%3.1f"]
, ["sawsd", True, "SawSD", 1.0, "%3.1f"]
, ["wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f"]
, ["wmsd", True, "W$SD", 1.0, "%3.1f"]
, ["flafq", True, "FlAFq", 1.0, "%3.1f"]
, ["tuafq", True, "TuAFq", 1.0, "%3.1f"]
, ["rvafq", True, "RvAFq", 1.0, "%3.1f"]
, ["pofafq", False, "PoFAFq", 1.0, "%3.1f"]
, ["net", True, "Net($)", 1.0, "%6.2f"]
, ["bbper100", True, "bb/100", 1.0, "%4.2f"]
, ["rake", True, "Rake($)", 1.0, "%6.2f"]
, ["bb100xr", True, "bbxr/100", 1.0, "%4.2f"]
, ["variance", True, "Variance", 1.0, "%5.2f"]
]
self.stat_table = None self.stat_table = None
self.stats_frame = None self.stats_frame = None
self.stats_vbox = None
self.main_hbox = gtk.HBox(False, 0) self.main_hbox = gtk.HBox(False, 0)
self.main_hbox.show() self.main_hbox.show()
statsFrame = gtk.Frame("Stats:") self.stats_frame = gtk.Frame()
statsFrame.set_label_align(0.0, 0.0) self.stats_frame.set_label_align(0.0, 0.0)
statsFrame.show()
self.stats_frame = gtk.VBox(False, 0)
self.stats_frame.show() self.stats_frame.show()
self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox.show()
# This could be stored in config eventually, or maybe configured in this window somehow. # This could be stored in config eventually, or maybe configured in this window somehow.
# Each posncols element is the name of a column returned by the sql # Each posncols element is the name of a column returned by the sql
@ -90,11 +120,11 @@ class GuiPositionalStats (threading.Thread):
, "PoFAFq", "Net($)", "bb/100", "$/hand", "Variance", "Hds" , "PoFAFq", "Net($)", "bb/100", "$/hand", "Variance", "Hds"
) )
self.fillStatsFrame(self.stats_frame) self.fillStatsFrame(self.stats_vbox)
statsFrame.add(self.stats_frame) self.stats_frame.add(self.stats_vbox)
self.main_hbox.pack_start(self.filters.get_vbox()) self.main_hbox.pack_start(self.filters.get_vbox())
self.main_hbox.pack_start(statsFrame) self.main_hbox.pack_start(self.stats_frame)
def get_vbox(self): def get_vbox(self):
@ -107,9 +137,12 @@ class GuiPositionalStats (threading.Thread):
print "DEBUG: activesite set to %s" %(self.activesite) print "DEBUG: activesite set to %s" %(self.activesite)
def refreshStats(self, widget, data): def refreshStats(self, widget, data):
try: self.stats_table.destroy() try: self.stats_vbox.destroy()
except AttributeError: pass except AttributeError: pass
self.fillStatsFrame(self.stats_frame) self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox.show()
self.stats_frame.add(self.stats_vbox)
self.fillStatsFrame(self.stats_vbox)
def fillStatsFrame(self, vbox): def fillStatsFrame(self, vbox):
sites = self.filters.getSites() sites = self.filters.getSites()
@ -144,66 +177,104 @@ class GuiPositionalStats (threading.Thread):
self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates) self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates)
def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates): def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates):
self.stats_table = gtk.Table(1, 1, False) # gtk table expands as required
self.stats_table.set_col_spacings(4)
self.stats_table.show()
vbox.add(self.stats_table)
starttime = time()
colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4
row = 0 row = 0
col = 0 col = 0
for t in self.posnheads:
l = gtk.Label(self.posnheads[col])
l.show()
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
col +=1
tmp = self.sql.query['playerStatsByPosition'] tmp = self.sql.query['playerStatsByPosition']
tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates) tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates)
self.cursor.execute(tmp) self.cursor.execute(tmp)
result = self.cursor.fetchall() result = self.cursor.fetchall()
colnames = [desc[0].lower() for desc in self.cursor.description]
liststore = gtk.ListStore(*([str] * len(colnames)))
view = gtk.TreeView(model=liststore)
view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
vbox.pack_start(view, expand=False, padding=3)
# left-aligned cells:
textcell = gtk.CellRendererText()
# centred cells:
textcell50 = gtk.CellRendererText()
textcell50.set_property('xalign', 0.5)
# right-aligned cells:
numcell = gtk.CellRendererText()
numcell.set_property('xalign', 1.0)
listcols = []
for t in self.posnheads:
listcols.append(gtk.TreeViewColumn(self.posnheads[col]))
view.append_column(listcols[col])
if col == 0:
listcols[col].pack_start(textcell, expand=True)
listcols[col].add_attribute(textcell, 'text', col)
listcols[col].set_expand(True)
elif col in (1, 2):
listcols[col].pack_start(textcell50, expand=True)
listcols[col].add_attribute(textcell50, 'text', col)
listcols[col].set_expand(True)
else:
listcols[col].pack_start(numcell, expand=True)
listcols[col].add_attribute(numcell, 'text', col)
listcols[col].set_expand(True)
col +=1
# Code below to be used when full column data structures implemented like in player stats:
# Create header row eg column: ("game", True, "Game", 0.0, "%s")
#for col, column in enumerate(cols_to_show):
# if column[colalias] == 'game' and holecards:
# s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading]
# else:
# s = column[colheading]
# listcols.append(gtk.TreeViewColumn(s))
# view.append_column(listcols[col])
# if column[colformat] == '%s':
# if column[colxalign] == 0.0:
# listcols[col].pack_start(textcell, expand=True)
# listcols[col].add_attribute(textcell, 'text', col)
# else:
# listcols[col].pack_start(textcell50, expand=True)
# listcols[col].add_attribute(textcell50, 'text', col)
# listcols[col].set_expand(True)
# else:
# listcols[col].pack_start(numcell, expand=True)
# listcols[col].add_attribute(numcell, 'text', col)
# listcols[col].set_expand(True)
# #listcols[col].set_alignment(column[colxalign]) # no effect?
rows = len(result) rows = len(result)
colnames = [desc[0].lower() for desc in self.cursor.description]
last_game,last_seats,sqlrow = "","",0 last_game,last_seats,sqlrow = "","",0
while sqlrow < rows: while sqlrow < rows:
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
rowprinted=0 rowprinted=0
treerow = []
avgcol = colnames.index('avgseats') avgcol = colnames.index('avgseats')
for col,colname in enumerate(self.posncols): for col,colname in enumerate(self.posncols):
if colname in colnames: if colname in colnames:
sqlcol = colnames.index(colname) sqlcol = colnames.index(colname)
else: else:
continue continue
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
# print blank row between levels:
if result[sqlrow][sqlcol]: if result[sqlrow][sqlcol]:
if sqlrow == 0: if sqlrow == 0:
l = gtk.Label(result[sqlrow][sqlcol]) value = result[sqlrow][sqlcol]
rowprinted=1 rowprinted=1
elif result[sqlrow][0] != last_game: elif result[sqlrow][0] != last_game:
l = gtk.Label(' ') value = ' '
elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats: elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats:
l = gtk.Label(' ') value = ' '
else: else:
l = gtk.Label(result[sqlrow][sqlcol]) value = result[sqlrow][sqlcol]
rowprinted=1 rowprinted=1
else: else:
l = gtk.Label(' ') l = gtk.Label(' ')
if col == 0: value = ' '
l.set_alignment(xalign=0.0, yalign=0.5) if value and value != -999:
elif col == 1: treerow.append(value)
l.set_alignment(xalign=0.5, yalign=0.5)
else: else:
l.set_alignment(xalign=1.0, yalign=0.5) treerow.append(' ')
eb.add(l) iter = liststore.append(treerow)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
last_game = result[sqlrow][0] last_game = result[sqlrow][0]
last_seats = result[sqlrow][avgcol] last_seats = result[sqlrow][avgcol]
if rowprinted: if rowprinted:
@ -220,50 +291,36 @@ class GuiPositionalStats (threading.Thread):
# blank row between main stats and totals: # blank row between main stats and totals:
col = 0 col = 0
if(row%2 == 0): treerow = [' ' for x in self.posncols]
bgcolor = "white" iter = liststore.append(treerow)
else:
bgcolor = "lightgrey"
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
l = gtk.Label(' ')
eb.add(l)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
row = row + 1 row = row + 1
for sqlrow in range(rows): for sqlrow in range(rows):
if(row%2 == 0): treerow = []
bgcolor = "white"
else:
bgcolor = "lightgrey"
for col,colname in enumerate(self.posncols): for col,colname in enumerate(self.posncols):
if colname in colnames: if colname in colnames:
sqlcol = colnames.index(colname) sqlcol = colnames.index(colname)
elif colname != "plposition": elif colname != "plposition":
continue continue
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
if colname == 'plposition': if colname == 'plposition':
l = gtk.Label('Totals') l = gtk.Label('Totals')
value = 'Totals'
elif result[sqlrow][sqlcol]: elif result[sqlrow][sqlcol]:
l = gtk.Label(result[sqlrow][sqlcol]) l = gtk.Label(result[sqlrow][sqlcol])
value = result[sqlrow][sqlcol]
else: else:
l = gtk.Label(' ') l = gtk.Label(' ')
if col == 0: value = ' '
l.set_alignment(xalign=0.0, yalign=0.5) if value and value != -999:
elif col == 1: treerow.append(value)
l.set_alignment(xalign=0.5, yalign=0.5)
else: else:
l.set_alignment(xalign=1.0, yalign=0.5) treerow.append(' ')
eb.add(l) iter = liststore.append(treerow)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
row = row + 1 row = row + 1
vbox.show_all()
self.db.db.rollback() self.db.db.rollback()
print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime)
#end def fillStatsFrame(self, vbox): #end def fillStatsFrame(self, vbox):
def refineQuery(self, query, playerids, sitenos, limits, seats, dates): def refineQuery(self, query, playerids, sitenos, limits, seats, dates):

View File

@ -34,10 +34,13 @@ import gobject
# FreePokerTools modules # FreePokerTools modules
from Mucked import Aux_Window from Mucked import Aux_Window
from Mucked import Seat_Window
from Mucked import Aux_Seats
class Hello(Aux_Window): class Hello(Aux_Window):
"""A 'Hello World' Aux_Window demo.""" """A 'Hello World' Aux_Window demo."""
def create(self): def create(self):
print "creating Hello"
# This demo simply creates a label in a window. # This demo simply creates a label in a window.
self.container = gtk.Window() self.container = gtk.Window()
self.container.add(gtk.Label("Hello World")) self.container.add(gtk.Label("Hello World"))
@ -99,15 +102,18 @@ class Hello_plus(Aux_Window):
# hands played that was updated in the "update_data()" function. # hands played that was updated in the "update_data()" function.
self.label.set_text("Hello %s\nYou have played %d hands\n on %s." % (self.hero, self.hands_played, self.site)) self.label.set_text("Hello %s\nYou have played %d hands\n on %s." % (self.hero, self.hands_played, self.site))
class Hello_Menu(Aux_Window): class Hello_Seats(Aux_Seats):
"""A 'Hello World' Aux_Window demo.""" """A 'Hello World' Seat_Window demo."""
def create(self):
# This demo puts a menu item on the HUD mainwindow.
self.item = gtk.MenuItem('Print cards')
self.hud.menu.append(self.item)
self.item.connect("activate", self.print_cards)
self.item.show()
def print_cards(self, *args): def create_contents(self, container, i):
# callback for the menu item container.label = gtk.Label("empty")
print "cards =", self.hud.cards container.add(container.label)
container.show_all()
def update_contents(self, container, i):
if i == "common": return
id = self.get_id_from_seat(i)
if id == None:
container.label.set_text("empty")
else:
container.label.set_text("player = %s" % self.hud.stat_dict[id]['screen_name'])

View File

@ -339,30 +339,30 @@ class Hud:
Stats.do_tip(window.e_box[r][c], tip) Stats.do_tip(window.e_box[r][c], tip)
def topify_window(self, window): def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows.""" # """Set the specified gtk window to stayontop in MS Windows."""
#
def windowEnumerationHandler(hwnd, resultList): # def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.''' # '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd))) # resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
# unique_name = 'unique name for finding this window'
unique_name = 'unique name for finding this window' # real_name = window.get_title()
real_name = window.get_title() # window.set_title(unique_name)
window.set_title(unique_name) # tl_windows = []
tl_windows = [] # win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
win32gui.EnumWindows(windowEnumerationHandler, tl_windows) #
# for w in tl_windows:
for w in tl_windows: # if w[1] == unique_name:
if w[1] == unique_name:
self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number)) self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number))
self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) # self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
self.main_window.gdkhandle = self.main_window.window
self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break # break
window.set_title(real_name) # window.set_title(real_name)
class Stat_Window: class Stat_Window:
@ -445,10 +445,10 @@ class Stat_Window:
Stats.do_tip(e_box[r][c], 'stuff') Stats.do_tip(e_box[r][c], 'stuff')
if usegtkframes: if usegtkframes:
grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = game.xpad, ypadding = game.ypad)
self.frame[r][c].add(e_box[r][c]) self.frame[r][c].add(e_box[r][c])
else: else:
grid.attach(e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) grid.attach(e_box[r][c], c, c+1, r, r+1, xpadding = game.xpad, ypadding = game.ypad)
label[r].append( gtk.Label('xxx') ) label[r].append( gtk.Label('xxx') )
if usegtkframes: if usegtkframes:
@ -473,6 +473,7 @@ class Popup_window:
def __init__(self, parent, stat_window): def __init__(self, parent, stat_window):
self.sb_click = 0 self.sb_click = 0
self.stat_window = stat_window self.stat_window = stat_window
self.parent = parent
# create the popup window # create the popup window
self.window = gtk.Window() self.window = gtk.Window()
@ -532,11 +533,15 @@ class Popup_window:
# db_connection.close_connection() # db_connection.close_connection()
stat_dict = stat_window.parent.stat_dict stat_dict = stat_window.parent.stat_dict
pu_text = "" pu_text = ""
mo_text = ""
for s in stat_list: for s in stat_list:
number = Stats.do_stat(stat_dict, player = int(stat_window.player_id), stat = s) number = Stats.do_stat(stat_dict, player = int(stat_window.player_id), stat = s)
mo_text += number[5] + " " + number[4] + "\n"
pu_text += number[3] + "\n" pu_text += number[3] + "\n"
self.lab.set_text(pu_text) self.lab.set_text(pu_text)
Stats.do_tip(self.lab, mo_text)
self.window.show_all() self.window.show_all()
self.window.set_transient_for(stat_window.window) self.window.set_transient_for(stat_window.window)
@ -572,25 +577,25 @@ class Popup_window:
def topify_window(self, window): def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows.""" """Set the specified gtk window to stayontop in MS Windows."""
def windowEnumerationHandler(hwnd, resultList): # def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.''' # '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd))) # resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
unique_name = 'unique name for finding this window' # unique_name = 'unique name for finding this window'
real_name = window.get_title() # real_name = window.get_title()
window.set_title(unique_name) # window.set_title(unique_name)
tl_windows = [] # tl_windows = []
win32gui.EnumWindows(windowEnumerationHandler, tl_windows) # win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
for w in tl_windows: # for w in tl_windows:
if w[1] == unique_name: # if w[1] == unique_name:
window.set_transient_for(self.parent.main_window) window.set_transient_for(self.parent.main_window)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break # break
window.set_title(real_name) # window.set_title(real_name)
if __name__== "__main__": if __name__== "__main__":
main_window = gtk.Window() main_window = gtk.Window()

View File

@ -37,27 +37,18 @@ import Configuration
import Database import Database
import Card import Card
class Aux_Window: class Aux_Window(object):
def __init__(self, hud, params, config): def __init__(self, hud, params, config):
self.hud = hud self.hud = hud
self.params = params self.params = params
self.config = config self.config = config
def update_data(self, *args): # Override these methods as needed
pass def update_data(self, *args): pass
def update_gui(self, *args): pass
def update_gui(self, *args): def create(self, *args): pass
pass def relocate(self, *args): pass
def save_layout(self, *args): pass
def create(self, *args):
pass
def relocate(self, *args):
pass
def save_layout(self, *args):
pass
def destroy(self): def destroy(self):
try: try:
self.container.destroy() self.container.destroy()
@ -89,14 +80,19 @@ class Aux_Window:
pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0) pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0)
return temp_pb return temp_pb
def split_cards(self, card):
if card == 'xx': return ('B', 'S')
return (card[0], card[1].upper())
def has_cards(self, cards): def has_cards(self, cards):
"""Returns the number of cards in the list."""
n = 0
for c in cards: for c in cards:
if c in set('shdc'): return True if c != None and c > 0: n = n + 1
return False return n
def get_id_from_seat(self, seat):
"""Determine player id from seat number, given stat_dict."""
for id, dict in self.hud.stat_dict.iteritems():
if seat == dict['seat']:
return id
return None
class Stud_mucked(Aux_Window): class Stud_mucked(Aux_Window):
def __init__(self, hud, config, params): def __init__(self, hud, config, params):
@ -329,87 +325,151 @@ class Stud_cards:
self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[0]) self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[0])
self.eb[(c, r)].set_tooltip_text('') self.eb[(c, r)].set_tooltip_text('')
class Flop_Mucked(Aux_Window): class Seat_Window(gtk.Window):
"""Aux_Window class for displaying mucked cards for flop games.""" """Subclass gtk.Window for the seat windows."""
class Aux_Seats(Aux_Window):
"""A super class to display an aux_window at each seat."""
def __init__(self, hud, config, params): def __init__(self, hud, config, params):
self.hud = hud # hud object that this aux window supports self.hud = hud # hud object that this aux window supports
self.config = config # configuration object for this aux window to use self.config = config # configuration object for this aux window to use
self.params = params # dict aux params from config self.params = params # dict aux params from config
self.positions = {} # dict of window positions self.positions = {} # dict of window positions
# self.rel_positions = {} # dict of window positions, relative to the table origin self.displayed = False # the seat windows are displayed
self.displayed_cards = False self.uses_timer = False # the Aux_seats object uses a timer to control hiding
self.timer_on = False # bool = Ture if the timeout for removing the cards is on self.timer_on = False # bool = Ture if the timeout for removing the cards is on
self.card_images = self.get_card_images()
# placeholders that should be overridden--so we don't throw errors
def create_contents(self): pass
def update_contents(self): pass
def create(self): def create(self):
self.adj = self.hud.adj_seats(0, self.config) self.adj = self.hud.adj_seats(0, self.config) # move adj_seats to aux and get rid of it in Hud.py
loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max)) loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max))
self.m_windows = {} # windows to put the card images in self.m_windows = {} # windows to put the card images in
self.eb = {} # event boxes so we can interact with the mucked cards
self.seen_cards = {} # image objects to stash the cards in
for i in (range(1, self.hud.max + 1) + ['common']): for i in (range(1, self.hud.max + 1) + ['common']):
if i == 'common': if i == 'common':
(x, y) = self.params['layout'][self.hud.max].common (x, y) = self.params['layout'][self.hud.max].common
else: else:
(x, y) = loc[self.adj[i]] (x, y) = loc[self.adj[i]]
self.m_windows[i] = gtk.Window() self.m_windows[i] = Seat_Window()
self.m_windows[i].set_decorated(False) self.m_windows[i].set_decorated(False)
self.m_windows[i].set_property("skip-taskbar-hint", True) self.m_windows[i].set_property("skip-taskbar-hint", True)
self.m_windows[i].set_transient_for(self.hud.main_window) self.m_windows[i].set_transient_for(self.hud.main_window)
self.m_windows[i].set_focus_on_map(False) self.m_windows[i].set_focus_on_map(False)
self.eb[i] = gtk.EventBox()
self.eb[i].connect("button_press_event", self.button_press_cb)
self.m_windows[i].connect("configure_event", self.configure_event_cb, i) self.m_windows[i].connect("configure_event", self.configure_event_cb, i)
self.m_windows[i].add(self.eb[i])
self.seen_cards[i] = gtk.image_new_from_pixbuf(self.card_images[('B', 'H')])
self.eb[i].add(self.seen_cards[i])
self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y) self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y)
# self.rel_positions[i] = (int(x), int(y))
self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) self.m_windows[i].move(self.positions[i][0], self.positions[i][1])
self.m_windows[i].set_opacity(float(self.params['opacity'])) if self.params.has_key('opacity'):
self.m_windows[i].set_opacity(float(self.params['opacity']))
# the create_contents method is supplied by the subclass
self.create_contents(self.m_windows[i], i)
self.m_windows[i].show_all() self.m_windows[i].show_all()
self.m_windows[i].hide() if self.uses_timer:
self.m_windows[i].hide()
def update_gui(self, new_hand_id):
"""Update the gui, LDO."""
for i in self.m_windows.keys():
self.update_contents(self.m_windows[i], i)
# Methods likely to be of use for any Seat_Window implementation
def destroy(self):
"""Destroy all of the seat windows."""
for i in self.m_windows.keys():
self.m_windows[i].destroy()
del(self.m_windows[i])
# Methods likely to be useful for mucked card windows (or similar) only
def hide(self):
"""Hide the seat windows."""
for (i, w) in self.m_windows.iteritems():
w.hide()
self.displayed = False
def save_layout(self, *args):
"""Save new layout back to the aux element in the config file."""
new_locs = {}
# print "adj =", self.adj
for (i, pos) in self.positions.iteritems():
if i != 'common':
new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
else:
new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs)
def configure_event_cb(self, widget, event, i, *args):
self.positions[i] = widget.get_position()
# self.rel_positions[i] = (self.positions[i][0] - self.hud.table.x, self.positions[i][1] - self.hud.table.y)
class Flop_Mucked(Aux_Seats):
"""Aux_Window class for displaying mucked cards for flop games."""
def __init__(self, hud, config, params):
super(Flop_Mucked, self).__init__(hud, config, params)
self.card_images = self.get_card_images()
self.uses_timer = True # this Aux_seats object uses a timer to control hiding
def create_contents(self, container, i):
"""Create the widgets for showing the contents of the Aux_seats window."""
container.eb = gtk.EventBox()
container.eb.connect("button_press_event", self.button_press_cb)
container.add(container.eb)
container.seen_cards = gtk.image_new_from_pixbuf(self.card_images[0])
container.eb.add(container.seen_cards)
def update_contents(self, container, i):
if not self.hud.cards.has_key(i): return
cards = self.hud.cards[i]
n_cards = self.has_cards(cards)
if n_cards > 1:
# scratch is a working pixbuf, used to assemble the image
scratch = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
int(self.params['card_wd'])*n_cards,
int(self.params['card_ht']))
x = 0 # x coord where the next card starts in scratch
for card in cards:
# concatenate each card image to scratch
if card == None or card ==0:
break
self.card_images[card].copy_area(0, 0,
int(self.params['card_wd']), int(self.params['card_ht']),
scratch, x, 0)
x = x + int(self.params['card_wd'])
container.seen_cards.set_from_pixbuf(scratch)
container.resize(1,1)
container.show()
container.move(self.positions[i][0], self.positions[i][1]) # here is where I move back
self.displayed = True
if i != "common":
self.m_windows[i].eb.set_tooltip_text(self.hud.stat_dict[i]['screen_name'])
def update_gui(self, new_hand_id): def update_gui(self, new_hand_id):
"""Prepare and show the mucked cards.""" """Prepare and show the mucked cards."""
if self.displayed_cards: if self.displayed: self.hide()
self.hide_mucked_cards()
self.displayed_cards = False # See how many players showed a hand. Skip if only 1 shows (= hero)
n_sd = 0
for (i, cards) in self.hud.cards.iteritems(): for (i, cards) in self.hud.cards.iteritems():
if self.has_cards(cards): n_cards = self.has_cards(cards)
# scratch is a working pixbuf, used to assemble the image if n_cards > 0:
scratch = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, n_sd = n_sd + 1
int(self.params['card_wd'])*len(cards)/2, if n_sd < 2:
int(self.params['card_ht'])) print "skipping, n_sd =", n_sd
x = 0 # x coord where the next card starts in scratch return
for card in [cards[k:k+2] for k in xrange(0, len(cards), 2)]:
# concatenate each card image to scratch
self.card_images[self.split_cards(card)].copy_area(0, 0,
int(self.params['card_wd']), int(self.params['card_ht']),
scratch, x, 0)
x = x + int(self.params['card_wd'])
self.seen_cards[i].set_from_pixbuf(scratch)
# self.m_windows[i].show_all()
self.m_windows[i].resize(1,1)
self.m_windows[i].show()
self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back
self.displayed_cards = True
for stats in self.hud.stat_dict.itervalues(): super(Flop_Mucked, self).update_gui(new_hand_id)
self.eb[stats['seat']].set_tooltip_text(stats['screen_name'])
if self.displayed_cards and float(self.params['timeout']) > 0: if self.displayed and float(self.params['timeout']) > 0:
self.timer_on = True self.timer_on = True
gobject.timeout_add(int(1000*float(self.params['timeout'])), self.timed_out) gobject.timeout_add(int(1000*float(self.params['timeout'])), self.timed_out)
def destroy(self):
"""Destroy all of the mucked windows."""
for w in self.m_windows.values():
w.destroy()
def timed_out(self): def timed_out(self):
# this is the callback from the timeout # this is the callback from the timeout
@ -418,15 +478,9 @@ class Flop_Mucked(Aux_Window):
if not self.timer_on: if not self.timer_on:
return False return False
else: else:
self.hide_mucked_cards() self.hide()
return False return False
def hide_mucked_cards(self):
"""Hide the mucked card windows."""
for (i, w) in self.m_windows.iteritems():
w.hide()
self.displayed_cards = False
def button_press_cb(self, widget, event, *args): def button_press_cb(self, widget, event, *args):
"""Handle button clicks in the event boxes.""" """Handle button clicks in the event boxes."""
@ -444,58 +498,14 @@ class Flop_Mucked(Aux_Window):
self.timer_on = False self.timer_on = False
else: else:
self.timer_on = False self.timer_on = False
self.hide_mucked_cards() self.hide()
elif event.button == 1: # left button event elif event.button == 1: # left button event
window = widget.get_parent() window = widget.get_parent()
window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time) window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time)
def configure_event_cb(self, widget, event, i, *args):
self.positions[i] = widget.get_position()
# self.rel_positions[i] = (self.positions[i][0] - self.hud.table.x, self.positions[i][1] - self.hud.table.y)
def expose_all(self): def expose_all(self):
for (i, cards) in self.hud.cards.iteritems(): for (i, cards) in self.hud.cards.iteritems():
self.m_windows[i].show() self.m_windows[i].show()
self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back
self.displayed_cards = True self.displayed = True
def save_layout(self, *args):
"""Save new layout back to the aux element in the config file."""
new_locs = {}
# print "adj =", self.adj
for (i, pos) in self.positions.iteritems():
if i != 'common':
new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
else:
new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs)
# This test program doesn't work
#if __name__== "__main__":
#
# def destroy(*args): # call back for terminating the main eventloop
# gtk.main_quit() # used only for testing
#
# def process_new_hand(source, condition, db_connection): #callback from stdin watch -- testing only
## there is a new hand_id to be processed
## just read it and pass it to update
# new_hand_id = sys.stdin.readline()
# new_hand_id = new_hand_id.rstrip() # remove trailing whitespace
# m.update_data(new_hand_id, db_connection)
# m.update_gui(new_hand_id)
# return(True)
#
# config = Configuration.Config()
# db_connection = Database.Database(config, 'fpdbTEST', '')
# main_window = gtk.Window()
# main_window.set_keep_above(True)
# main_window.connect("destroy", destroy)
#
# aux_to_call = "stud_mucked"
# aux_params = config.get_aux_parameters(aux_to_call)
# m = eval("%s(None, config, aux_params)" % aux_params['class'])
#
# s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand, db_connection)
# gtk.main()

View File

@ -542,18 +542,13 @@ class Sql:
self.query['get_common_cards'] = """ self.query['get_common_cards'] = """
select select
card1Value AS card1value, boardcard1,
card1Suit AS card1suit, boardcard2,
card2Value AS card2value, boardcard3,
card2Suit AS card2suit, boardcard4,
card3Value AS card3value, boardcard5
card3Suit AS card3suit, from Hands
card4Value AS card4value, where Id = %s
card4Suit AS card4suit,
card5Value AS card5value,
card5Suit AS card5suit
from BoardCards
where handId = %s
""" """
self.query['get_action_from_hand'] = """ self.query['get_action_from_hand'] = """

View File

@ -231,7 +231,7 @@ def discover_nt_by_name(c, tablename):
titles = {} titles = {}
win32gui.EnumWindows(win_enum_handler, titles) win32gui.EnumWindows(win_enum_handler, titles)
for hwnd in titles: for hwnd in titles:
print "Tbales.py: tablename =", tablename, "title =", titles[hwnd] #print "Tables.py: tablename =", tablename, "title =", titles[hwnd]
try: try:
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
if not tablename in titles[hwnd]: continue if not tablename in titles[hwnd]: continue
@ -314,6 +314,10 @@ def get_site_from_exe(c, exe):
return params['site_name'] return params['site_name']
return None return None
def everleaf_decode_table(tw):
# 2 - Tournament ID: 573256 - NL Hold'em - 150/300 blinds - Good luck <username>! - [Connection is ...]
pass
def pokerstars_decode_table(tw): def pokerstars_decode_table(tw):
# Extract poker information from the window title. This is not needed for # Extract poker information from the window title. This is not needed for
# fpdb, since all that information is available in the db via new_hand_number. # fpdb, since all that information is available in the db via new_hand_number.

View File

@ -92,6 +92,8 @@ if __name__=="__main__":
print "game =", table.get_game() print "game =", table.get_game()
fake = fake_hud(table) fake = fake_hud(table)
print "fake =", fake
gobject.timeout_add(100, check_on_table, table, fake) gobject.timeout_add(100, check_on_table, table, fake)
print "calling main"
gtk.main() gtk.main()

View File

@ -65,8 +65,11 @@ class Table(Table_Window):
print "x = %s y = %s width = %s height = %s" % (x, y, width, height) print "x = %s y = %s width = %s height = %s" % (x, y, width, height)
self.x = int(x) + b_width self.x = int(x) + b_width
self.y = int(y) + tb_height self.y = int(y) + tb_height
self.height = int(height) - b_width - tb_height self.width = width - x
self.width = int(width) - 2*b_width self.height = height - y
print "x = %s y = %s width = %s height = %s" % (self.x, self.y, self.width, self.height)
#self.height = int(height) - b_width - tb_height
#self.width = int(width) - 2*b_width
self.exe = self.get_nt_exe(hwnd) self.exe = self.get_nt_exe(hwnd)
self.title = titles[hwnd] self.title = titles[hwnd]
@ -76,12 +79,13 @@ class Table(Table_Window):
self.gdkhandle = gtk.gdk.window_foreign_new(long(self.window)) self.gdkhandle = gtk.gdk.window_foreign_new(long(self.window))
def get_geometry(self): def get_geometry(self):
if not win32gui.IsWindow(self.number): # window closed
if not win32gui.IsWindow(self.window): # window closed
return None return None
try: try:
(x, y, width, height) = win32gui.GetWindowRect(hwnd) (x, y, width, height) = win32gui.GetWindowRect(self.number)
width = width - x
height = height - y
return {'x' : int(x) + b_width, return {'x' : int(x) + b_width,
'y' : int(y) + tb_height, 'y' : int(y) + tb_height,
'width' : int(height) - b_width - tb_height, 'width' : int(height) - b_width - tb_height,
@ -116,27 +120,32 @@ class Table(Table_Window):
def topify(self, hud): def topify(self, hud):
"""Set the specified gtk window to stayontop in MS Windows.""" """Set the specified gtk window to stayontop in MS Windows."""
def windowEnumerationHandler(hwnd, resultList): # def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.''' # '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd))) # resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
#
unique_name = 'unique name for finding this window' # unique_name = 'unique name for finding this window'
real_name = hud.main_window.get_title() # real_name = hud.main_window.get_title()
hud.main_window.set_title(unique_name) # hud.main_window.set_title(unique_name)
tl_windows = [] # tl_windows = []
win32gui.EnumWindows(windowEnumerationHandler, tl_windows) # win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
#
for w in tl_windows: # for w in tl_windows:
if w[1] == unique_name: # if w[1] == unique_name:
hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) # hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
hud.main_window.gdkhandle.set_transient_for(self.gdkhandle) hud.main_window.gdkhandle = hud.main_window.window
hud.main_window.gdkhandle.set_transient_for(self.gdkhandle)
rect = self.gdkhandle.get_frame_extents()
(innerx, innery) = self.gdkhandle.get_origin()
b_width = rect.x - innerx
tb_height = rect.y - innery
# #
# style = win32gui.GetWindowLong(self.number, win32con.GWL_EXSTYLE) # style = win32gui.GetWindowLong(self.number, win32con.GWL_EXSTYLE)
# style |= win32con.WS_CLIPCHILDREN # style |= win32con.WS_CLIPCHILDREN
# win32gui.SetWindowLong(self.number, win32con.GWL_EXSTYLE, style) # win32gui.SetWindowLong(self.number, win32con.GWL_EXSTYLE, style)
break # break
hud.main_window.set_title(real_name) # hud.main_window.set_title(real_name)
def win_enum_handler(hwnd, titles): def win_enum_handler(hwnd, titles):
titles[hwnd] = win32gui.GetWindowText(hwnd) titles[hwnd] = win32gui.GetWindowText(hwnd)

View File

@ -32,7 +32,7 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import fpdb_db
import fpdb_simple import fpdb_simple
import GuiBulkImport import GuiBulkImport
import GuiPlayerStats import GuiPlayerStats
@ -41,6 +41,8 @@ import GuiTableViewer
import GuiAutoImport import GuiAutoImport
import GuiGraphViewer import GuiGraphViewer
import GuiSessionViewer import GuiSessionViewer
import SQL
import Database
import FpdbSQLQueries import FpdbSQLQueries
import Configuration import Configuration
@ -178,20 +180,21 @@ class fpdb:
def dia_load_profile(self, widget, data=None): def dia_load_profile(self, widget, data=None):
"""Dialogue to select a file to load a profile from""" """Dialogue to select a file to load a profile from"""
if self.obtain_global_lock() == 0: # returns 0 if successful if self.obtain_global_lock() == 0: # returns 0 if successful
try: #try:
chooser = gtk.FileChooserDialog(title="Please select a profile file to load", # chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
action=gtk.FILE_CHOOSER_ACTION_OPEN, # action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) # buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
chooser.set_filename(self.profile) # chooser.set_filename(self.profile)
response = chooser.run() # response = chooser.run()
chooser.destroy() # chooser.destroy()
if response == gtk.RESPONSE_OK: # if response == gtk.RESPONSE_OK:
self.load_profile(chooser.get_filename()) # self.load_profile(chooser.get_filename())
elif response == gtk.RESPONSE_CANCEL: # elif response == gtk.RESPONSE_CANCEL:
print 'User cancelled loading profile' # print 'User cancelled loading profile'
except: #except:
pass # pass
self.load_profile()
self.release_global_lock() self.release_global_lock()
#end def dia_load_profile #end def dia_load_profile
@ -203,22 +206,23 @@ class fpdb:
try: try:
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, dia_confirm = gtk.MessageDialog(parent=None, flags=0, 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 "+self.db.database+" on "+self.db.host+" they will be deleted." diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \
+self.db.fdb.database+" on "+self.db.fdb.host+" they will be deleted."
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
response = dia_confirm.run() response = dia_confirm.run()
dia_confirm.destroy() dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
if self.db.backend == self.fdb_lock.MYSQL_INNODB: if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB:
# mysql requires locks on all tables or none - easier to release this lock # mysql requires locks on all tables or none - easier to release this lock
# than lock all the other tables # than lock all the other tables
# ToDo: lock all other tables so that lock doesn't have to be released # ToDo: lock all other tables so that lock doesn't have to be released
self.release_global_lock() self.release_global_lock()
lock_released = True lock_released = True
self.db.recreate_tables() self.db.fdb.recreate_tables()
else: else:
# for other dbs use same connection as holds global lock # for other dbs use same connection as holds global lock
self.fdb_lock.recreate_tables() self.fdb_lock.fdb.recreate_tables()
elif response == gtk.RESPONSE_NO: elif response == gtk.RESPONSE_NO:
print 'User cancelled recreating tables' print 'User cancelled recreating tables'
except: except:
@ -346,6 +350,7 @@ class fpdb:
def load_profile(self): def load_profile(self):
"""Loads profile from the provided path name.""" """Loads profile from the provided path name."""
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.settings = {} self.settings = {}
if (os.sep=="/"): if (os.sep=="/"):
self.settings['os']="linuxmac" self.settings['os']="linuxmac"
@ -358,17 +363,13 @@ class fpdb:
self.settings.update(self.config.get_import_parameters()) self.settings.update(self.config.get_import_parameters())
self.settings.update(self.config.get_default_paths()) self.settings.update(self.config.get_default_paths())
if self.db!=None: if self.db != None and self.db.fdb != None:
self.db.disconnect() self.db.disconnect()
self.db = fpdb_db.fpdb_db() self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server'])
#print "end of fpdb.load_profile, databaseName:",self.settings['db-databaseName'] self.db = Database.Database(self.config, sql = self.sql)
self.db.connect(self.settings['db-backend'],
self.settings['db-host'], if self.db.fdb.wrongDbVersion:
self.settings['db-databaseName'],
self.settings['db-user'],
self.settings['db-password'])
if self.db.wrongDbVersion:
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
label = gtk.Label("An invalid DB version or missing tables have been detected.") label = gtk.Label("An invalid DB version or missing tables have been detected.")
@ -386,9 +387,16 @@ class fpdb:
response = diaDbVersionWarning.run() response = diaDbVersionWarning.run()
diaDbVersionWarning.destroy() diaDbVersionWarning.destroy()
if self.status_bar == None:
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host))
self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show()
else:
self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host))
# Database connected to successfully, load queries to pass on to other classes # Database connected to successfully, load queries to pass on to other classes
self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name())
self.db.db.rollback() self.db.connection.rollback()
#end def load_profile #end def load_profile
def not_implemented(self, widget, data=None): def not_implemented(self, widget, data=None):
@ -397,13 +405,9 @@ class fpdb:
def obtain_global_lock(self): def obtain_global_lock(self):
print "\nTaking global lock ..." print "\nTaking global lock ..."
self.fdb_lock = fpdb_db.fpdb_db() self.fdb_lock = Database.Database(self.config, sql = self.sql)
self.fdb_lock.connect(self.settings['db-backend'], self.fdb_lock.do_connect(self.config)
self.settings['db-host'], return self.fdb_lock.fdb.get_global_lock()
self.settings['db-databaseName'],
self.settings['db-user'],
self.settings['db-password'])
return self.fdb_lock.get_global_lock()
#end def obtain_global_lock #end def obtain_global_lock
def quit(self, widget, data=None): def quit(self, widget, data=None):
@ -414,9 +418,9 @@ class fpdb:
#end def quit_cliecked #end def quit_cliecked
def release_global_lock(self): def release_global_lock(self):
self.fdb_lock.db.rollback() self.fdb_lock.fdb.db.rollback()
self.fdb_lock.disconnect() self.fdb_lock.fdb.disconnect()
print "Global lock released." print "Global lock released.\n"
#end def release_global_lock #end def release_global_lock
def tab_abbreviations(self, widget, data=None): def tab_abbreviations(self, widget, data=None):
@ -465,7 +469,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def tab_table_viewer(self, widget, data=None): def tab_table_viewer(self, widget, data=None):
"""opens a table viewer tab""" """opens a table viewer tab"""
#print "start of tab_table_viewer" #print "start of tab_table_viewer"
new_tv_thread=GuiTableViewer.GuiTableViewer(self.db, self.settings) new_tv_thread=GuiTableViewer.GuiTableViewer(self.db.fdb, self.settings)
self.threads.append(new_tv_thread) self.threads.append(new_tv_thread)
tv_tab=new_tv_thread.get_vbox() tv_tab=new_tv_thread.get_vbox()
self.add_and_display_tab(tv_tab, "Table Viewer") self.add_and_display_tab(tv_tab, "Table Viewer")
@ -474,17 +478,16 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def tabGraphViewer(self, widget, data=None): def tabGraphViewer(self, widget, data=None):
"""opens a graph viewer tab""" """opens a graph viewer tab"""
#print "start of tabGraphViewer" #print "start of tabGraphViewer"
new_gv_thread=GuiGraphViewer.GuiGraphViewer(self.db, self.settings, self.querydict, self.config) new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.querydict, self.config)
self.threads.append(new_gv_thread) self.threads.append(new_gv_thread)
gv_tab=new_gv_thread.get_vbox() gv_tab=new_gv_thread.get_vbox()
self.add_and_display_tab(gv_tab, "Graphs") self.add_and_display_tab(gv_tab, "Graphs")
#end def tabGraphViewer #end def tabGraphViewer
def __init__(self): def __init__(self):
self.threads=[] self.threads = []
self.db=None self.db = None
self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.status_bar = None
self.load_profile()
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)
@ -519,11 +522,8 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.tab_main_help(None, None) self.tab_main_help(None, None)
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host))
self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show()
self.window.show() self.window.show()
self.load_profile()
sys.stderr.write("fpdb starting ...") sys.stderr.write("fpdb starting ...")
#end def __init__ #end def __init__

View File

@ -243,7 +243,6 @@ class fpdb_db:
self.cursor.execute(self.sql.query['createPlayersTable']) self.cursor.execute(self.sql.query['createPlayersTable'])
self.cursor.execute(self.sql.query['createAutoratesTable']) self.cursor.execute(self.sql.query['createAutoratesTable'])
self.cursor.execute(self.sql.query['createHandsTable']) self.cursor.execute(self.sql.query['createHandsTable'])
self.cursor.execute(self.sql.query['createBoardCardsTable'])
self.cursor.execute(self.sql.query['createTourneyTypesTable']) self.cursor.execute(self.sql.query['createTourneyTypesTable'])
self.cursor.execute(self.sql.query['createTourneysTable']) self.cursor.execute(self.sql.query['createTourneysTable'])
self.cursor.execute(self.sql.query['createTourneysPlayersTable']) self.cursor.execute(self.sql.query['createTourneysPlayersTable'])
@ -568,17 +567,18 @@ class fpdb_db:
print "analyze took", atime, "seconds" print "analyze took", atime, "seconds"
#end def analyzeDB #end def analyzeDB
# Currently uses an exclusive lock on the Hands table as a global lock # Currently uses an exclusive lock on the Players table as a global lock
# ( Changed because Hands is used in Database.init() )
# Return values are Unix style, 0 for success, positive integers for errors # Return values are Unix style, 0 for success, positive integers for errors
# 1 = generic error # 1 = generic error
# 2 = hands table does not exist (error message is suppressed) # 2 = players table does not exist (error message is suppressed)
def get_global_lock(self): def get_global_lock(self):
if self.backend == self.MYSQL_INNODB: if self.backend == self.MYSQL_INNODB:
try: try:
self.cursor.execute( "lock tables Hands write" ) self.cursor.execute( "lock tables Players write" )
except: except:
# Table 'fpdb.hands' doesn't exist # Table 'fpdb.players' doesn't exist
if str(sys.exc_value).find(".Hands' doesn't exist") >= 0: if str(sys.exc_value).find(".Players' doesn't exist") >= 0:
return(2) return(2)
print "Error! failed to obtain global lock. Close all programs accessing " \ print "Error! failed to obtain global lock. Close all programs accessing " \
+ "database (including fpdb) and try again (%s)." \ + "database (including fpdb) and try again (%s)." \
@ -586,11 +586,11 @@ class fpdb_db:
return(1) return(1)
elif self.backend == self.PGSQL: elif self.backend == self.PGSQL:
try: try:
self.cursor.execute( "lock table Hands in exclusive mode nowait" ) self.cursor.execute( "lock table Players in exclusive mode nowait" )
#print "... after lock table, status =", self.cursor.statusmessage #print "... after lock table, status =", self.cursor.statusmessage
except: except:
# relation "hands" does not exist # relation "players" does not exist
if str(sys.exc_value).find('relation "hands" does not exist') >= 0: if str(sys.exc_value).find('relation "players" does not exist') >= 0:
return(2) return(2)
print "Error! failed to obtain global lock. Close all programs accessing " \ print "Error! failed to obtain global lock. Close all programs accessing " \
+ "database (including fpdb) and try again (%s)." \ + "database (including fpdb) and try again (%s)." \

View File

@ -31,6 +31,7 @@ import re
import fpdb_simple import fpdb_simple
import fpdb_db import fpdb_db
import Database
import fpdb_parse_logic import fpdb_parse_logic
import Configuration import Configuration
@ -57,7 +58,8 @@ class Importer:
self.settings = settings self.settings = settings
self.caller = caller self.caller = caller
self.config = config self.config = config
self.fdb = None self.database = None # database will be the main db interface eventually
self.fdb = None # fdb may disappear or just hold the simple db connection
self.cursor = None self.cursor = None
self.filelist = {} self.filelist = {}
self.dirlist = {} self.dirlist = {}
@ -75,6 +77,7 @@ class Importer:
self.settings.setdefault("minPrint", 30) self.settings.setdefault("minPrint", 30)
self.settings.setdefault("handCount", 0) self.settings.setdefault("handCount", 0)
self.database = Database.Database(self.config) # includes .connection and .sql variables
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.fdb.do_connect(self.config) self.fdb.do_connect(self.config)
self.fdb.db.rollback() self.fdb.db.rollback()
@ -392,8 +395,9 @@ class Importer:
self.hand=hand self.hand=hand
try: try:
handsId = fpdb_parse_logic.mainParser(self.settings, self.fdb handsId = fpdb_parse_logic.mainParser( self.settings, self.fdb
, self.siteIds[site], category, hand, self.config) , self.siteIds[site], category, hand
, self.config, self.database )
self.fdb.db.commit() self.fdb.db.commit()
stored += 1 stored += 1

View File

@ -21,10 +21,13 @@ import fpdb_simple
import Database import Database
#parses a holdem hand #parses a holdem hand
def mainParser(settings, fdb, siteID, category, hand, config): def mainParser(settings, fdb, siteID, category, hand, config, db = None):
backend = settings['db-backend'] backend = settings['db-backend']
#This is redundant - hopefully fdb will be a Database object in an interation soon if db == None:
db = Database.Database(config, 'fpdb', '') #This is redundant - hopefully fdb will be a Database object in an iteration soon
db = Database.Database(c = config, sql = None)
else:
db = db
category = fpdb_simple.recogniseCategory(hand[0]) category = fpdb_simple.recogniseCategory(hand[0])
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud" base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"

View File

@ -1136,16 +1136,6 @@ def storeActions(cursor, handsPlayersIds, actionTypes, allIns, actionAmounts, ac
cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts) cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts)
#end def storeActions #end def storeActions
def store_board_cards(cursor, hands_id, board_values, board_suits):
#stores into table board_cards
cursor.execute ("""INSERT INTO BoardCards (handId, card1Value, card1Suit,
card2Value, card2Suit, card3Value, card3Suit, card4Value, card4Suit,
card5Value, card5Suit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
(hands_id, board_values[0], board_suits[0], board_values[1], board_suits[1],
board_values[2], board_suits[2], board_values[3], board_suits[3],
board_values[4], board_suits[4]))
#end def store_board_cards
def storeHands(backend, conn, cursor, site_hand_no, gametype_id def storeHands(backend, conn, cursor, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats, hudCache, ,hand_start_time, names, tableName, maxSeats, hudCache,
board_values, board_suits): board_values, board_suits):