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

@ -88,12 +88,32 @@ class Site:
self.font_size = node.getAttribute("font_size")
self.use_frames = node.getAttribute("use_frames")
self.enabled = fix_tf(node.getAttribute("enabled"), default = True)
self.xpad = node.getAttribute("xpad")
self.ypad = node.getAttribute("ypad")
self.layout = {}
for layout_node in node.getElementsByTagName('layout'):
lo = Layout(layout_node)
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):
temp = "Site = " + self.site_name + "\n"
for key in dir(self):
@ -119,9 +139,16 @@ class Stat:
class Game:
def __init__(self, node):
self.game_name = node.getAttribute("game_name")
self.db = node.getAttribute("db")
self.rows = int( node.getAttribute("rows") )
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_list = aux_text.split(',')
@ -146,9 +173,10 @@ class Game:
def __str__(self):
temp = "Game = " + self.game_name + "\n"
temp = temp + " db = %s\n" % self.db
temp = temp + " rows = %d\n" % self.rows
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
for stat in self.stats.keys():
@ -631,6 +659,8 @@ class Config:
parms["font"] = self.supported_sites[site].font
parms["font_size"] = self.supported_sites[site].font_size
parms["enabled"] = self.supported_sites[site].enabled
parms["xpad"] = self.supported_sites[site].xpad
parms["ypad"] = self.supported_sites[site].ypad
return parms
def set_site_parameters(self, site_name, converter = None, decoder = None,
@ -681,9 +711,10 @@ class Config:
param = {}
if self.supported_games.has_key(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['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
return param

View File

@ -39,7 +39,8 @@ import SQL
import Card
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.do_connect(c)
self.connection = self.fdb.db
@ -48,7 +49,12 @@ class Database:
self.import_options = c.get_import_parameters()
self.type = db_params['db-type']
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()
# To add to config:
@ -81,6 +87,8 @@ class Database:
#row = cur.fetchone()
self.saveActions = False if self.import_options['saveActions'] == False else True
def do_connect(self, c):
self.fdb.do_connect(c)
def commit(self):
self.fdb.db.commit()
@ -88,6 +96,19 @@ class Database:
def close_connection(self):
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):
c = self.connection.cursor()
c.execute(self.sql.query['get_table_name'], (hand_id, ))
@ -138,12 +159,8 @@ class Database:
cards = {}
c = self.connection.cursor()
c.execute(self.sql.query['get_common_cards'], [hand])
colnames = [desc[0] for desc in c.description]
for row in c.fetchall():
s_dict = {}
for name, val in zip(colnames, row):
s_dict[name] = val
cards['common'] = (self.convert_cards(s_dict))
# row = c.fetchone()
cards['common'] = c.fetchone()
return cards
def convert_cards(self, d):
@ -326,7 +343,6 @@ class Database:
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)
t5 = time()
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
t6 = time()
if self.saveActions:
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':
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:
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos)
return hands_id

View File

@ -30,12 +30,11 @@ import fpdb_db
import FpdbSQLQueries
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
#print "start of GraphViewer constructor"
self.db=db
self.cursor=db.cursor
self.settings=settings
self.sql=qdict
self.conf = config
self.display = display
@ -235,7 +234,7 @@ class Filters(threading.Thread):
def __set_hero_name(self, w, site):
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):
cb = gtk.CheckButton(site)
@ -556,23 +555,12 @@ def main(argv=None):
config = Configuration.Config()
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.connect(settings['db-backend'],
settings['db-host'],
settings['db-databaseName'],
settings['db-user'],
settings['db-password'])
db.do_connect(config)
qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name())
i = Filters(db, settings, config, qdict)
i = Filters(db, config, qdict)
main_window = gtk.Window()
main_window.connect('destroy', destroy)
main_window.add(i.get_vbox())

View File

@ -248,43 +248,6 @@ class FpdbSQLQueries:
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
################################
@ -1550,136 +1513,6 @@ class FpdbSQLQueries:
elif(self.dbname == 'SQLite'):
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'):
self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""

View File

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

View File

@ -66,7 +66,7 @@ class GuiPlayerStats (threading.Thread):
"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.registerButton1Callback(self.showDetailFilter)
self.filters.registerButton2Name("_Refresh")
@ -227,11 +227,6 @@ class GuiPlayerStats (threading.Thread):
if not flags: holecards = False
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.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates)
self.cursor.execute(tmp)
@ -279,10 +274,6 @@ class GuiPlayerStats (threading.Thread):
while sqlrow < rows:
treerow = []
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
for col,column in enumerate(cols_to_show):
if column[colalias] in colnames:
value = result[sqlrow][colnames.index(column[colalias])]

View File

@ -20,6 +20,7 @@ import pygtk
pygtk.require('2.0')
import gtk
import os
from time import time, strftime
import fpdb_import
import fpdb_db
@ -58,21 +59,50 @@ class GuiPositionalStats (threading.Thread):
"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.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.stats_frame = None
self.stats_vbox = None
self.main_hbox = gtk.HBox(False, 0)
self.main_hbox.show()
statsFrame = gtk.Frame("Stats:")
statsFrame.set_label_align(0.0, 0.0)
statsFrame.show()
self.stats_frame = gtk.VBox(False, 0)
self.stats_frame = gtk.Frame()
self.stats_frame.set_label_align(0.0, 0.0)
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.
# 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"
)
self.fillStatsFrame(self.stats_frame)
statsFrame.add(self.stats_frame)
self.fillStatsFrame(self.stats_vbox)
self.stats_frame.add(self.stats_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):
@ -107,9 +137,12 @@ class GuiPositionalStats (threading.Thread):
print "DEBUG: activesite set to %s" %(self.activesite)
def refreshStats(self, widget, data):
try: self.stats_table.destroy()
try: self.stats_vbox.destroy()
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):
sites = self.filters.getSites()
@ -144,66 +177,104 @@ class GuiPositionalStats (threading.Thread):
self.createStatsTable(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
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.refineQuery(tmp, playerids, sitenos, limits, seats, dates)
self.cursor.execute(tmp)
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)
colnames = [desc[0].lower() for desc in self.cursor.description]
last_game,last_seats,sqlrow = "","",0
while sqlrow < rows:
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
rowprinted=0
treerow = []
avgcol = colnames.index('avgseats')
for col,colname in enumerate(self.posncols):
if colname in colnames:
sqlcol = colnames.index(colname)
else:
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 sqlrow == 0:
l = gtk.Label(result[sqlrow][sqlcol])
value = result[sqlrow][sqlcol]
rowprinted=1
elif result[sqlrow][0] != last_game:
l = gtk.Label(' ')
value = ' '
elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats:
l = gtk.Label(' ')
value = ' '
else:
l = gtk.Label(result[sqlrow][sqlcol])
value = result[sqlrow][sqlcol]
rowprinted=1
else:
l = gtk.Label(' ')
if col == 0:
l.set_alignment(xalign=0.0, yalign=0.5)
elif col == 1:
l.set_alignment(xalign=0.5, yalign=0.5)
value = ' '
if value and value != -999:
treerow.append(value)
else:
l.set_alignment(xalign=1.0, yalign=0.5)
eb.add(l)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
treerow.append(' ')
iter = liststore.append(treerow)
last_game = result[sqlrow][0]
last_seats = result[sqlrow][avgcol]
if rowprinted:
@ -220,50 +291,36 @@ class GuiPositionalStats (threading.Thread):
# blank row between main stats and totals:
col = 0
if(row%2 == 0):
bgcolor = "white"
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()
treerow = [' ' for x in self.posncols]
iter = liststore.append(treerow)
row = row + 1
for sqlrow in range(rows):
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
treerow = []
for col,colname in enumerate(self.posncols):
if colname in colnames:
sqlcol = colnames.index(colname)
elif colname != "plposition":
continue
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
if colname == 'plposition':
l = gtk.Label('Totals')
value = 'Totals'
elif result[sqlrow][sqlcol]:
l = gtk.Label(result[sqlrow][sqlcol])
value = result[sqlrow][sqlcol]
else:
l = gtk.Label(' ')
if col == 0:
l.set_alignment(xalign=0.0, yalign=0.5)
elif col == 1:
l.set_alignment(xalign=0.5, yalign=0.5)
value = ' '
if value and value != -999:
treerow.append(value)
else:
l.set_alignment(xalign=1.0, yalign=0.5)
eb.add(l)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
treerow.append(' ')
iter = liststore.append(treerow)
row = row + 1
vbox.show_all()
self.db.db.rollback()
print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime)
#end def fillStatsFrame(self, vbox):
def refineQuery(self, query, playerids, sitenos, limits, seats, dates):

View File

@ -34,10 +34,13 @@ import gobject
# FreePokerTools modules
from Mucked import Aux_Window
from Mucked import Seat_Window
from Mucked import Aux_Seats
class Hello(Aux_Window):
"""A 'Hello World' Aux_Window demo."""
def create(self):
print "creating Hello"
# This demo simply creates a label in a window.
self.container = gtk.Window()
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.
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):
"""A 'Hello World' Aux_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()
class Hello_Seats(Aux_Seats):
"""A 'Hello World' Seat_Window demo."""
def print_cards(self, *args):
# callback for the menu item
print "cards =", self.hud.cards
def create_contents(self, container, i):
container.label = gtk.Label("empty")
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)
def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows."""
def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
unique_name = 'unique name for finding this window'
real_name = window.get_title()
window.set_title(unique_name)
tl_windows = []
win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
for w in tl_windows:
if w[1] == unique_name:
# """Set the specified gtk window to stayontop in MS Windows."""
#
# def windowEnumerationHandler(hwnd, resultList):
# '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
# resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
# unique_name = 'unique name for finding this window'
# real_name = window.get_title()
# window.set_title(unique_name)
# tl_windows = []
# win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
#
# for w in tl_windows:
# if w[1] == unique_name:
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)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break
# break
window.set_title(real_name)
# window.set_title(real_name)
class Stat_Window:
@ -445,10 +445,10 @@ class Stat_Window:
Stats.do_tip(e_box[r][c], 'stuff')
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])
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') )
if usegtkframes:
@ -473,6 +473,7 @@ class Popup_window:
def __init__(self, parent, stat_window):
self.sb_click = 0
self.stat_window = stat_window
self.parent = parent
# create the popup window
self.window = gtk.Window()
@ -532,11 +533,15 @@ class Popup_window:
# db_connection.close_connection()
stat_dict = stat_window.parent.stat_dict
pu_text = ""
mo_text = ""
for s in stat_list:
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"
self.lab.set_text(pu_text)
Stats.do_tip(self.lab, mo_text)
self.window.show_all()
self.window.set_transient_for(stat_window.window)
@ -572,25 +577,25 @@ class Popup_window:
def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows."""
def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
# def windowEnumerationHandler(hwnd, resultList):
# '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
# resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
unique_name = 'unique name for finding this window'
real_name = window.get_title()
window.set_title(unique_name)
tl_windows = []
win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
# unique_name = 'unique name for finding this window'
# real_name = window.get_title()
# window.set_title(unique_name)
# tl_windows = []
# win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
for w in tl_windows:
if w[1] == unique_name:
# for w in tl_windows:
# if w[1] == unique_name:
window.set_transient_for(self.parent.main_window)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break
# break
window.set_title(real_name)
# window.set_title(real_name)
if __name__== "__main__":
main_window = gtk.Window()

View File

@ -37,27 +37,18 @@ import Configuration
import Database
import Card
class Aux_Window:
class Aux_Window(object):
def __init__(self, hud, params, config):
self.hud = hud
self.params = params
self.config = config
def update_data(self, *args):
pass
def update_gui(self, *args):
pass
def create(self, *args):
pass
def relocate(self, *args):
pass
def save_layout(self, *args):
pass
# Override these methods as needed
def update_data(self, *args): pass
def update_gui(self, *args): pass
def create(self, *args): pass
def relocate(self, *args): pass
def save_layout(self, *args): pass
def destroy(self):
try:
self.container.destroy()
@ -89,14 +80,19 @@ class Aux_Window:
pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0)
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):
"""Returns the number of cards in the list."""
n = 0
for c in cards:
if c in set('shdc'): return True
return False
if c != None and c > 0: n = n + 1
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):
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.eb[(c, r)].set_tooltip_text('')
class Flop_Mucked(Aux_Window):
"""Aux_Window class for displaying mucked cards for flop games."""
class Seat_Window(gtk.Window):
"""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):
self.hud = hud # hud object that this aux window supports
self.config = config # configuration object for this aux window to use
self.params = params # dict aux params from config
self.positions = {} # dict of window positions
# self.rel_positions = {} # dict of window positions, relative to the table origin
self.displayed_cards = False
self.displayed = False # the seat windows are displayed
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.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):
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))
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']):
if i == 'common':
(x, y) = self.params['layout'][self.hud.max].common
else:
(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_property("skip-taskbar-hint", True)
self.m_windows[i].set_transient_for(self.hud.main_window)
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].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.rel_positions[i] = (int(x), int(y))
self.m_windows[i].move(self.positions[i][0], self.positions[i][1])
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()
if self.uses_timer:
self.m_windows[i].hide()
def update_gui(self, new_hand_id):
"""Prepare and show the mucked cards."""
if self.displayed_cards:
self.hide_mucked_cards()
self.displayed_cards = False
for (i, cards) in self.hud.cards.iteritems():
if self.has_cards(cards):
"""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'])*len(cards)/2,
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[k:k+2] for k in xrange(0, len(cards), 2)]:
for card in cards:
# concatenate each card image to scratch
self.card_images[self.split_cards(card)].copy_area(0, 0,
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'])
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
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'])
for stats in self.hud.stat_dict.itervalues():
self.eb[stats['seat']].set_tooltip_text(stats['screen_name'])
def update_gui(self, new_hand_id):
"""Prepare and show the mucked cards."""
if self.displayed: self.hide()
if self.displayed_cards and float(self.params['timeout']) > 0:
# See how many players showed a hand. Skip if only 1 shows (= hero)
n_sd = 0
for (i, cards) in self.hud.cards.iteritems():
n_cards = self.has_cards(cards)
if n_cards > 0:
n_sd = n_sd + 1
if n_sd < 2:
print "skipping, n_sd =", n_sd
return
super(Flop_Mucked, self).update_gui(new_hand_id)
if self.displayed and float(self.params['timeout']) > 0:
self.timer_on = True
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):
# this is the callback from the timeout
@ -418,15 +478,9 @@ class Flop_Mucked(Aux_Window):
if not self.timer_on:
return False
else:
self.hide_mucked_cards()
self.hide()
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):
"""Handle button clicks in the event boxes."""
@ -444,58 +498,14 @@ class Flop_Mucked(Aux_Window):
self.timer_on = False
else:
self.timer_on = False
self.hide_mucked_cards()
self.hide()
elif event.button == 1: # left button event
window = widget.get_parent()
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):
for (i, cards) in self.hud.cards.iteritems():
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
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()
self.displayed = True

View File

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

View File

@ -231,7 +231,7 @@ def discover_nt_by_name(c, tablename):
titles = {}
win32gui.EnumWindows(win_enum_handler, titles)
for hwnd in titles:
print "Tbales.py: tablename =", tablename, "title =", titles[hwnd]
#print "Tables.py: tablename =", tablename, "title =", titles[hwnd]
try:
# 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
@ -314,6 +314,10 @@ def get_site_from_exe(c, exe):
return params['site_name']
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):
# 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.

View File

@ -92,6 +92,8 @@ if __name__=="__main__":
print "game =", table.get_game()
fake = fake_hud(table)
print "fake =", fake
gobject.timeout_add(100, check_on_table, table, fake)
print "calling 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)
self.x = int(x) + b_width
self.y = int(y) + tb_height
self.height = int(height) - b_width - tb_height
self.width = int(width) - 2*b_width
self.width = width - x
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.title = titles[hwnd]
@ -76,12 +79,13 @@ class Table(Table_Window):
self.gdkhandle = gtk.gdk.window_foreign_new(long(self.window))
def get_geometry(self):
if not win32gui.IsWindow(self.window): # window closed
if not win32gui.IsWindow(self.number): # window closed
return None
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,
'y' : int(y) + tb_height,
'width' : int(height) - b_width - tb_height,
@ -116,27 +120,32 @@ class Table(Table_Window):
def topify(self, hud):
"""Set the specified gtk window to stayontop in MS Windows."""
def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
unique_name = 'unique name for finding this window'
real_name = hud.main_window.get_title()
hud.main_window.set_title(unique_name)
tl_windows = []
win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
for w in tl_windows:
if w[1] == unique_name:
hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
# def windowEnumerationHandler(hwnd, resultList):
# '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
# resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
#
# unique_name = 'unique name for finding this window'
# real_name = hud.main_window.get_title()
# hud.main_window.set_title(unique_name)
# tl_windows = []
# win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
#
# for w in tl_windows:
# if w[1] == unique_name:
# hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
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 |= win32con.WS_CLIPCHILDREN
# 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):
titles[hwnd] = win32gui.GetWindowText(hwnd)

View File

@ -32,7 +32,7 @@ import pygtk
pygtk.require('2.0')
import gtk
import fpdb_db
import fpdb_simple
import GuiBulkImport
import GuiPlayerStats
@ -41,6 +41,8 @@ import GuiTableViewer
import GuiAutoImport
import GuiGraphViewer
import GuiSessionViewer
import SQL
import Database
import FpdbSQLQueries
import Configuration
@ -178,20 +180,21 @@ class fpdb:
def dia_load_profile(self, widget, data=None):
"""Dialogue to select a file to load a profile from"""
if self.obtain_global_lock() == 0: # returns 0 if successful
try:
chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
chooser.set_filename(self.profile)
#try:
# chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
# action=gtk.FILE_CHOOSER_ACTION_OPEN,
# buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
# chooser.set_filename(self.profile)
response = chooser.run()
chooser.destroy()
if response == gtk.RESPONSE_OK:
self.load_profile(chooser.get_filename())
elif response == gtk.RESPONSE_CANCEL:
print 'User cancelled loading profile'
except:
pass
# response = chooser.run()
# chooser.destroy()
# if response == gtk.RESPONSE_OK:
# self.load_profile(chooser.get_filename())
# elif response == gtk.RESPONSE_CANCEL:
# print 'User cancelled loading profile'
#except:
# pass
self.load_profile()
self.release_global_lock()
#end def dia_load_profile
@ -203,22 +206,23 @@ class fpdb:
try:
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
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
response = dia_confirm.run()
dia_confirm.destroy()
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
# than lock all the other tables
# ToDo: lock all other tables so that lock doesn't have to be released
self.release_global_lock()
lock_released = True
self.db.recreate_tables()
self.db.fdb.recreate_tables()
else:
# 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:
print 'User cancelled recreating tables'
except:
@ -346,6 +350,7 @@ class fpdb:
def load_profile(self):
"""Loads profile from the provided path name."""
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.settings = {}
if (os.sep=="/"):
self.settings['os']="linuxmac"
@ -358,17 +363,13 @@ class fpdb:
self.settings.update(self.config.get_import_parameters())
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 = fpdb_db.fpdb_db()
#print "end of fpdb.load_profile, databaseName:",self.settings['db-databaseName']
self.db.connect(self.settings['db-backend'],
self.settings['db-host'],
self.settings['db-databaseName'],
self.settings['db-user'],
self.settings['db-password'])
if self.db.wrongDbVersion:
self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server'])
self.db = Database.Database(self.config, sql = self.sql)
if self.db.fdb.wrongDbVersion:
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.")
@ -386,9 +387,16 @@ class fpdb:
response = diaDbVersionWarning.run()
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
self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name())
self.db.db.rollback()
self.db.connection.rollback()
#end def load_profile
def not_implemented(self, widget, data=None):
@ -397,13 +405,9 @@ class fpdb:
def obtain_global_lock(self):
print "\nTaking global lock ..."
self.fdb_lock = fpdb_db.fpdb_db()
self.fdb_lock.connect(self.settings['db-backend'],
self.settings['db-host'],
self.settings['db-databaseName'],
self.settings['db-user'],
self.settings['db-password'])
return self.fdb_lock.get_global_lock()
self.fdb_lock = Database.Database(self.config, sql = self.sql)
self.fdb_lock.do_connect(self.config)
return self.fdb_lock.fdb.get_global_lock()
#end def obtain_global_lock
def quit(self, widget, data=None):
@ -414,9 +418,9 @@ class fpdb:
#end def quit_cliecked
def release_global_lock(self):
self.fdb_lock.db.rollback()
self.fdb_lock.disconnect()
print "Global lock released."
self.fdb_lock.fdb.db.rollback()
self.fdb_lock.fdb.disconnect()
print "Global lock released.\n"
#end def release_global_lock
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):
"""opens a table viewer tab"""
#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)
tv_tab=new_tv_thread.get_vbox()
self.add_and_display_tab(tv_tab, "Table Viewer")
@ -474,7 +478,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def tabGraphViewer(self, widget, data=None):
"""opens a graph viewer tab"""
#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)
gv_tab=new_gv_thread.get_vbox()
self.add_and_display_tab(gv_tab, "Graphs")
@ -483,8 +487,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def __init__(self):
self.threads = []
self.db = None
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.load_profile()
self.status_bar = None
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
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.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.load_profile()
sys.stderr.write("fpdb starting ...")
#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['createAutoratesTable'])
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['createTourneysTable'])
self.cursor.execute(self.sql.query['createTourneysPlayersTable'])
@ -568,17 +567,18 @@ class fpdb_db:
print "analyze took", atime, "seconds"
#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
# 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):
if self.backend == self.MYSQL_INNODB:
try:
self.cursor.execute( "lock tables Hands write" )
self.cursor.execute( "lock tables Players write" )
except:
# Table 'fpdb.hands' doesn't exist
if str(sys.exc_value).find(".Hands' doesn't exist") >= 0:
# Table 'fpdb.players' doesn't exist
if str(sys.exc_value).find(".Players' doesn't exist") >= 0:
return(2)
print "Error! failed to obtain global lock. Close all programs accessing " \
+ "database (including fpdb) and try again (%s)." \
@ -586,11 +586,11 @@ class fpdb_db:
return(1)
elif self.backend == self.PGSQL:
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
except:
# relation "hands" does not exist
if str(sys.exc_value).find('relation "hands" does not exist') >= 0:
# relation "players" does not exist
if str(sys.exc_value).find('relation "players" does not exist') >= 0:
return(2)
print "Error! failed to obtain global lock. Close all programs accessing " \
+ "database (including fpdb) and try again (%s)." \

View File

@ -31,6 +31,7 @@ import re
import fpdb_simple
import fpdb_db
import Database
import fpdb_parse_logic
import Configuration
@ -57,7 +58,8 @@ class Importer:
self.settings = settings
self.caller = caller
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.filelist = {}
self.dirlist = {}
@ -75,6 +77,7 @@ class Importer:
self.settings.setdefault("minPrint", 30)
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.do_connect(self.config)
self.fdb.db.rollback()
@ -393,7 +396,8 @@ class Importer:
try:
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()
stored += 1

View File

@ -21,10 +21,13 @@ import fpdb_simple
import Database
#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']
#This is redundant - hopefully fdb will be a Database object in an interation soon
db = Database.Database(config, 'fpdb', '')
if db == None:
#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])
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)
#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
,hand_start_time, names, tableName, maxSeats, hudCache,
board_values, board_suits):