5fcd167b62
Signed-off-by: tribumarchal
780 lines
34 KiB
Python
780 lines
34 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#Copyright 2008-2010 Steffen Schaumburg
|
|
#This program is free software: you can redistribute it and/or modify
|
|
#it under the terms of the GNU Affero General Public License as published by
|
|
#the Free Software Foundation, version 3 of the License.
|
|
#
|
|
#This program is distributed in the hope that it will be useful,
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
#GNU General Public License for more details.
|
|
#
|
|
#You should have received a copy of the GNU Affero General Public License
|
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
|
|
|
import L10n
|
|
_ = L10n.get_translation()
|
|
|
|
import traceback
|
|
import threading
|
|
import pygtk
|
|
pygtk.require('2.0')
|
|
import gtk
|
|
import os
|
|
import sys
|
|
from time import time, strftime
|
|
|
|
import Card
|
|
import fpdb_import
|
|
import Database
|
|
import Filters
|
|
import Charset
|
|
import GuiPlayerStats
|
|
|
|
from TreeViewTooltips import TreeViewTooltips
|
|
|
|
|
|
#colalias,colshowsumm,colshowposn,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5,6
|
|
#new order in config file:
|
|
colalias,colheading,colshowsumm,colshowposn,colformat,coltype,colxalign = 0,1,2,3,4,5,6
|
|
ranks = {'x':0, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, 'T':10, 'J':11, 'Q':12, 'K':13, 'A':14}
|
|
onlinehelp = {'Game':_('Type of Game'),
|
|
'Hand':_('Hole cards'),
|
|
'Posn':_('Position'),
|
|
'Name':_('Name of the player'),
|
|
'Hds':_('Number of hands played'),
|
|
'Seats':_('Number of Seats'),
|
|
'VPIP':_('Voluntarily Putting In the pot\n(blinds excluded)'),
|
|
'PFR':_('% Pre Flop Raise'),
|
|
'PF3':_('% Pre Flop Re-Raise / 3Bet'),
|
|
'PF4':_('% Pre Flop Re-Raise / 4Bet'),
|
|
'PFF3':_('% Pre Flop Fold To Re-Raise / F3Bet'),
|
|
'PFF4':_('% Pre Flop Fold To Re-Raise / F4Bet'),
|
|
'AggFac':_('Aggression Factor\n'),
|
|
'AggFreq':_('Aggression Frequency\nBet or Raise vs Fold'),
|
|
'ContBet':_('Continuation Bet post-flop'),
|
|
'RFI':_('% Raise First In\% Raise when first to bet'),
|
|
'Steals':_('% First to raise pre-flop\nand steal blinds'),
|
|
'Saw_F':_('% Saw Flop vs hands dealt'),
|
|
'SawSD':_('Saw Show Down / River'),
|
|
'WtSDwsF':_('Went To Show Down When Saw Flop'),
|
|
'W$SD':_('% Won some money at showdown'),
|
|
'FlAFq':_('Flop Aggression\n% Bet or Raise after seeing Flop'),
|
|
'TuAFq':_('Turn Aggression\n% Bet or Raise after seeing Turn'),
|
|
'RvAFq':_('River Aggression\n% Bet or Raise after seeing River'),
|
|
'PoFAFq':_('Coming Soon\nTotal % agression'),
|
|
'Net($)':_('Amount won'),
|
|
'bb/100':_('Number of Big Blinds won\nor lost per 100 hands'),
|
|
'Rake($)':_('Amount of rake paid'),
|
|
'bbxr/100':_('Number of Big Blinds won\nor lost per 100 hands\nwhen excluding rake'),
|
|
'Variance':_('Measure of uncertainty\nThe lower, the more stable the amounts won')
|
|
}
|
|
|
|
|
|
|
|
class DemoTips(TreeViewTooltips):
|
|
|
|
def __init__(self, customer_column):
|
|
# call base class init
|
|
TreeViewTooltips.__init__(self)
|
|
|
|
def get_tooltip(self, view, column, path):
|
|
model = view.get_model()
|
|
cards = model[path][0]
|
|
title=column.get_title()
|
|
if (title == 'Hand' or title == 'Game'): display='' #no tooltips on headers
|
|
else: display='<big>%s for %s</big>\n<i>%s</i>' % (title,cards,onlinehelp[title])
|
|
return (display)
|
|
|
|
def location(self, x, y, w, h):
|
|
# this will place the tooltip above and to the right
|
|
return x + 30, y - (h + 10)
|
|
|
|
|
|
|
|
class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|
|
|
def __init__(self, config, querylist, mainwin, debug=True):
|
|
self.debug = debug
|
|
self.conf = config
|
|
self.main_window = mainwin
|
|
self.sql = querylist
|
|
|
|
self.liststore = [] # gtk.ListStore[] stores the contents of the grids
|
|
self.listcols = [] # gtk.TreeViewColumn[][] stores the columns in the grids
|
|
|
|
self.MYSQL_INNODB = 2
|
|
self.PGSQL = 3
|
|
self.SQLITE = 4
|
|
|
|
# create new db connection to avoid conflicts with other threads
|
|
self.db = Database.Database(self.conf, sql=self.sql)
|
|
self.cursor = self.db.cursor
|
|
|
|
settings = {}
|
|
settings.update(self.conf.get_db_parameters())
|
|
settings.update(self.conf.get_import_parameters())
|
|
settings.update(self.conf.get_default_paths())
|
|
|
|
# text used on screen stored here so that it can be configured
|
|
self.filterText = {'handhead':_('Hand Breakdown for all levels listed above')
|
|
}
|
|
|
|
filters_display = { "Heroes" : True,
|
|
"Sites" : True,
|
|
"Games" : True,
|
|
"Limits" : True,
|
|
"LimitSep" : True,
|
|
"LimitType" : True,
|
|
"Type" : True,
|
|
"Seats" : True,
|
|
"SeatSep" : True,
|
|
"Dates" : True,
|
|
"Groups" : True,
|
|
"GroupsAll" : True,
|
|
"Button1" : True,
|
|
"Button2" : True
|
|
}
|
|
|
|
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
|
|
self.filters.registerButton1Name(_("_Filters"))
|
|
self.filters.registerButton1Callback(self.showDetailFilter)
|
|
self.filters.registerButton2Name(_("_Refresh Stats"))
|
|
self.filters.registerButton2Callback(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(summary then position), column heading, xalignment, formatting, celltype
|
|
self.columns = self.conf.get_gui_cash_stat_params()
|
|
|
|
# Detail filters: This holds the data used in the popup window, extra values are
|
|
# added at the end of these lists during processing
|
|
# sql test, screen description, min, max
|
|
self.handtests = [ # already in filter class : ['h.seats', 'Number of Players', 2, 10]
|
|
['h.maxSeats', 'Size of Table', 2, 10]
|
|
,['h.playersVpi', 'Players who VPI', 0, 10]
|
|
,['h.playersAtStreet1', 'Players at Flop', 0, 10]
|
|
,['h.playersAtStreet2', 'Players at Turn', 0, 10]
|
|
,['h.playersAtStreet3', 'Players at River', 0, 10]
|
|
,['h.playersAtStreet4', 'Players at Street7', 0, 10]
|
|
,['h.playersAtShowdown', 'Players at Showdown', 0, 10]
|
|
,['h.street0Raises', 'Bets to See Flop', 0, 5]
|
|
,['h.street1Raises', 'Bets to See Turn', 0, 5]
|
|
,['h.street2Raises', 'Bets to See River', 0, 5]
|
|
,['h.street3Raises', 'Bets to See Street7', 0, 5]
|
|
,['h.street4Raises', 'Bets to See Showdown', 0, 5]
|
|
]
|
|
|
|
self.stats_frame = None
|
|
self.stats_vbox = None
|
|
self.detailFilters = [] # the data used to enhance the sql select
|
|
|
|
#self.main_hbox = gtk.HBox(False, 0)
|
|
#self.main_hbox.show()
|
|
self.main_hbox = gtk.HPaned()
|
|
|
|
self.stats_frame = gtk.Frame()
|
|
self.stats_frame.show()
|
|
|
|
self.stats_vbox = gtk.VPaned()
|
|
self.stats_vbox.show()
|
|
self.stats_frame.add(self.stats_vbox)
|
|
self.top_pane_height = 0
|
|
self.height_inc = None
|
|
# self.fillStatsFrame(self.stats_vbox)
|
|
|
|
#self.main_hbox.pack_start(self.filters.get_vbox())
|
|
#self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
|
|
self.main_hbox.pack1(self.filters.get_vbox())
|
|
self.main_hbox.pack2(self.stats_frame)
|
|
self.main_hbox.show()
|
|
|
|
# make sure Hand column is not displayed
|
|
[x for x in self.columns if x[0] == 'hand'][0][colshowsumm] = False
|
|
[x for x in self.columns if x[0] == 'hand'][0][colshowposn] = False
|
|
# if rfi and steal both on for summaries, turn rfi off
|
|
if ( [x for x in self.columns if x[0] == 'rfi'][0][colshowsumm]
|
|
and [x for x in self.columns if x[0] == 'steals'][0][colshowsumm]):
|
|
[x for x in self.columns if x[0] == 'rfi'][0][colshowsumm] = False
|
|
# if rfi and steal both on for position breakdowns, turn steals off:
|
|
if ( [x for x in self.columns if x[0] == 'rfi'][0][colshowposn]
|
|
and [x for x in self.columns if x[0] == 'steals'][0][colshowposn]):
|
|
[x for x in self.columns if x[0] == 'steals'][0][colshowposn] = False
|
|
|
|
self.last_pos = -1
|
|
|
|
|
|
def get_vbox(self):
|
|
"""returns the vbox of this thread"""
|
|
return self.main_hbox
|
|
#end def get_vbox
|
|
|
|
def refreshStats(self, widget, data):
|
|
#self.last_pos = self.stats_vbox.get_position()
|
|
self.height_inc = None
|
|
#old_len = 0
|
|
#if self.liststore:
|
|
# old_len = len(self.liststore[0])
|
|
try: self.stats_vbox.destroy()
|
|
except AttributeError: pass
|
|
self.liststore = []
|
|
self.listcols = []
|
|
self.stats_vbox = gtk.VPaned()
|
|
self.stats_vbox.show()
|
|
self.stats_frame.add(self.stats_vbox)
|
|
self.fillStatsFrame(self.stats_vbox)
|
|
|
|
# set height of top pane
|
|
# (tried 2 ways, guesstimate using ratio of old to new number of rows and sum of
|
|
# heights of parts)
|
|
new_len = 0
|
|
if self.liststore:
|
|
#new_len = len(self.liststore[0])
|
|
#print "setting to", self.top_pane_height + self.height_inc
|
|
self.stats_vbox.set_position(self.top_pane_height + self.height_inc)
|
|
#if self.last_pos > 0:
|
|
# if old_len > 0 and new_len > 0 and new_len <= 10:
|
|
# self.stats_vbox.set_position(self.last_pos * (new_len+1.9)/(old_len+1.9))
|
|
# else:
|
|
# self.stats_vbox.set_position(self.last_pos)
|
|
#end def refreshStats
|
|
|
|
def fillStatsFrame(self, vbox):
|
|
sites = self.filters.getSites()
|
|
heroes = self.filters.getHeroes()
|
|
siteids = self.filters.getSiteIds()
|
|
limits = self.filters.getLimits()
|
|
type = self.filters.getType()
|
|
seats = self.filters.getSeats()
|
|
groups = self.filters.getGroups()
|
|
dates = self.filters.getDates()
|
|
games = self.filters.getGames()
|
|
sitenos = []
|
|
playerids = []
|
|
|
|
# Which sites are selected?
|
|
for site in sites:
|
|
if sites[site] == True:
|
|
sitenos.append(siteids[site])
|
|
_hname = Charset.to_utf8(heroes[site])
|
|
result = self.db.get_player_id(self.conf, site, _hname)
|
|
if result is not None:
|
|
playerids.append(int(result))
|
|
|
|
if not sitenos:
|
|
#Should probably pop up here.
|
|
print _("No sites selected - defaulting to PokerStars")
|
|
sitenos = [2]
|
|
if not playerids:
|
|
print _("No player ids found")
|
|
return
|
|
if not limits:
|
|
print _("No limits found")
|
|
return
|
|
|
|
self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates, games)
|
|
#end def fillStatsFrame
|
|
|
|
def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates, games):
|
|
startTime = time()
|
|
show_detail = True
|
|
|
|
# Scrolled window for summary table
|
|
swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
|
|
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
vbox.pack1(swin) #, resize=True) don't use resize, self.height_inc relies on initial
|
|
# height of pane being correct for one row
|
|
|
|
# Display summary table at top of page
|
|
# 3rd parameter passes extra flags, currently includes:
|
|
# holecards - whether to display card breakdown (True/False)
|
|
# numhands - min number hands required when displaying all players
|
|
# gridnum - index for grid data structures
|
|
flags = [False, self.filters.getNumHands(), 0]
|
|
self.addGrid(swin, 'playerDetailedStats', flags, playerids
|
|
,sitenos, limits, type, seats, groups, dates, games)
|
|
swin.show()
|
|
|
|
if 'allplayers' in groups and groups['allplayers']:
|
|
# can't currently do this combination so skip detailed table
|
|
show_detail = False
|
|
|
|
if show_detail:
|
|
# Separator
|
|
vbox2 = gtk.VBox(False, 0)
|
|
heading = gtk.Label(self.filterText['handhead'])
|
|
heading.show()
|
|
vbox2.pack_start(heading, expand=False, padding=3)
|
|
|
|
# Scrolled window for detailed table (display by hand)
|
|
swin2 = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
|
|
swin2.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
swin2.show()
|
|
vbox2.pack_start(swin2, expand=True, padding=3)
|
|
vbox.pack2(vbox2)
|
|
vbox2.show()
|
|
|
|
# Detailed table
|
|
flags[0] = True
|
|
flags[2] = 1
|
|
self.addGrid(swin2, 'playerDetailedStats', flags, playerids
|
|
,sitenos, limits, type, seats, groups, dates, games)
|
|
|
|
if self.height_inc is None:
|
|
self.height_inc = 0
|
|
# need this to check whether scrollbar is visible:
|
|
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
|
|
gtk.main_iteration(False)
|
|
hs = swin.get_hscrollbar()
|
|
if hs is not None:
|
|
#print "hs vis", hs.get_property('visible'), hs.get_property('visible').__class__
|
|
if hs.get_property('visible'):
|
|
self.height_inc = hs.size_request()[1] + swin.style_get_property('scrollbar-spacing')
|
|
#print "hh set to", self.height_inc
|
|
self.stats_vbox.set_position(self.top_pane_height + self.height_inc)
|
|
|
|
self.db.rollback()
|
|
print (_("Stats page displayed in %4.2f seconds") % (time() - startTime))
|
|
#end def createStatsTable
|
|
|
|
def reset_style_render_func(self, treeviewcolumn, cell, model, iter):
|
|
cell.set_property('foreground', None)
|
|
#end def reset_style_render_func
|
|
|
|
def ledger_style_render_func(self, tvcol, cell, model, iter):
|
|
str = cell.get_property('text')
|
|
if '-' in str:
|
|
str = str.replace("-", "")
|
|
str = "(%s)" %(str)
|
|
cell.set_property('text', str)
|
|
cell.set_property('foreground', 'red')
|
|
else:
|
|
cell.set_property('foreground', 'darkgreen')
|
|
|
|
return
|
|
|
|
def sortnums(self, model, iter1, iter2, nums):
|
|
try:
|
|
ret = 0
|
|
(n, grid) = nums
|
|
a = self.liststore[grid].get_value(iter1, n)
|
|
b = self.liststore[grid].get_value(iter2, n)
|
|
if 'f' in self.cols_to_show[n][4]:
|
|
try: a = float(a)
|
|
except: a = 0.0
|
|
try: b = float(b)
|
|
except: b = 0.0
|
|
if n == 0 and grid == 1: #make sure it only works on the starting hands
|
|
a1,a2,a3 = ranks[a[0]], ranks[a[1]], (a+'o')[2]
|
|
b1,b2,b3 = ranks[b[0]], ranks[b[1]], (b+'o')[2]
|
|
if a1 > b1 or ( a1 == b1 and (a2 > b2 or (a2 == b2 and a3 > b3) ) ):
|
|
ret = 1
|
|
else:
|
|
ret = -1
|
|
else:
|
|
if a < b:
|
|
ret = -1
|
|
elif a == b:
|
|
ret = 0
|
|
else:
|
|
ret = 1
|
|
#print "n =", n, "iter1[n] =", self.liststore[grid].get_value(iter1,n), "iter2[n] =", self.liststore[grid].get_value(iter2,n), "ret =", ret
|
|
except:
|
|
err = traceback.extract_tb(sys.exc_info()[2])
|
|
print _("***sortnums error: ") + str(sys.exc_info()[1])
|
|
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
|
|
|
return(ret)
|
|
|
|
def sortcols(self, col, nums):
|
|
try:
|
|
#This doesn't actually work yet - clicking heading in top section sorts bottom section :-(
|
|
(n, grid) = nums
|
|
if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
|
|
col.set_sort_order(gtk.SORT_DESCENDING)
|
|
else:
|
|
col.set_sort_order(gtk.SORT_ASCENDING)
|
|
self.liststore[grid].set_sort_column_id(n, col.get_sort_order())
|
|
self.liststore[grid].set_sort_func(n, self.sortnums, (n,grid))
|
|
for i in xrange(len(self.listcols[grid])):
|
|
self.listcols[grid][i].set_sort_indicator(False)
|
|
self.listcols[grid][n].set_sort_indicator(True)
|
|
# use this listcols[col].set_sort_indicator(True)
|
|
# to turn indicator off for other cols
|
|
except:
|
|
err = traceback.extract_tb(sys.exc_info()[2])
|
|
print _("***sortcols error: ") + str(sys.exc_info()[1])
|
|
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
|
#end def sortcols
|
|
|
|
|
|
def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
|
|
counter = 0
|
|
row = 0
|
|
sqlrow = 0
|
|
if not flags: holecards,grid = False,0
|
|
else: holecards,grid = flags[0],flags[2]
|
|
|
|
tmp = self.sql.query[query]
|
|
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates, games)
|
|
#print "DEBUG: query: %s" % tmp
|
|
self.cursor.execute(tmp)
|
|
result = self.cursor.fetchall()
|
|
colnames = [desc[0].lower() for desc in self.cursor.description]
|
|
|
|
# pre-fetch some constant values:
|
|
colshow = colshowsumm
|
|
if groups['posn']: colshow = colshowposn
|
|
self.cols_to_show = [x for x in self.columns if x[colshow]]
|
|
hgametypeid_idx = colnames.index('hgametypeid')
|
|
|
|
assert len(self.liststore) == grid, "len(self.liststore)="+str(len(self.liststore))+" grid-1="+str(grid)
|
|
self.liststore.append( gtk.ListStore(*([str] * len(self.cols_to_show))) )
|
|
view = gtk.TreeView(model=self.liststore[grid])
|
|
view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
|
|
#vbox.pack_start(view, expand=False, padding=3)
|
|
vbox.add(view)
|
|
textcell = gtk.CellRendererText()
|
|
textcell50 = gtk.CellRendererText()
|
|
textcell50.set_property('xalign', 0.5)
|
|
numcell = gtk.CellRendererText()
|
|
numcell.set_property('xalign', 1.0)
|
|
assert len(self.listcols) == grid
|
|
self.listcols.append( [] )
|
|
|
|
# Create header row eg column: ("game", True, "Game", 0.0, "%s")
|
|
for col, column in enumerate(self.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]
|
|
self.listcols[grid].append(gtk.TreeViewColumn(s))
|
|
view.append_column(self.listcols[grid][col])
|
|
if column[colformat] == '%s':
|
|
if column[colxalign] == 0.0:
|
|
self.listcols[grid][col].pack_start(textcell, expand=True)
|
|
self.listcols[grid][col].add_attribute(textcell, 'text', col)
|
|
cellrend = textcell
|
|
else:
|
|
self.listcols[grid][col].pack_start(textcell50, expand=True)
|
|
self.listcols[grid][col].add_attribute(textcell50, 'text', col)
|
|
cellrend = textcell50
|
|
self.listcols[grid][col].set_expand(True)
|
|
else:
|
|
self.listcols[grid][col].pack_start(numcell, expand=True)
|
|
self.listcols[grid][col].add_attribute(numcell, 'text', col)
|
|
self.listcols[grid][col].set_expand(True)
|
|
cellrend = numcell
|
|
#self.listcols[grid][col].set_alignment(column[colxalign]) # no effect?
|
|
self.listcols[grid][col].set_clickable(True)
|
|
self.listcols[grid][col].connect("clicked", self.sortcols, (col,grid))
|
|
if col == 0:
|
|
self.listcols[grid][col].set_sort_order(gtk.SORT_DESCENDING)
|
|
self.listcols[grid][col].set_sort_indicator(True)
|
|
if column[coltype] == 'cash':
|
|
self.listcols[grid][col].set_cell_data_func(numcell, self.ledger_style_render_func)
|
|
else:
|
|
self.listcols[grid][col].set_cell_data_func(cellrend, self.reset_style_render_func)
|
|
|
|
rows = len(result) # +1 for title row
|
|
|
|
while sqlrow < rows:
|
|
treerow = []
|
|
for col,column in enumerate(self.cols_to_show):
|
|
if column[colalias] in colnames:
|
|
value = result[sqlrow][colnames.index(column[colalias])]
|
|
if column[colalias] == 'plposition':
|
|
if value == 'B':
|
|
value = 'BB'
|
|
elif value == 'S':
|
|
value = 'SB'
|
|
elif value == '0':
|
|
value = 'Btn'
|
|
else:
|
|
if column[colalias] == 'game':
|
|
if holecards:
|
|
value = Card.decodeStartHandValue(result[sqlrow][colnames.index('category')], result[sqlrow][hgametypeid_idx] )
|
|
else:
|
|
minbb = result[sqlrow][colnames.index('minbigblind')]
|
|
maxbb = result[sqlrow][colnames.index('maxbigblind')]
|
|
value = result[sqlrow][colnames.index('limittype')] + ' ' \
|
|
+ result[sqlrow][colnames.index('category')].title() + ' ' \
|
|
+ result[sqlrow][colnames.index('name')] + ' $'
|
|
if 100 * int(minbb/100.0) != minbb:
|
|
value += '%.2f' % (minbb/100.0)
|
|
else:
|
|
value += '%.0f' % (minbb/100.0)
|
|
if minbb != maxbb:
|
|
if 100 * int(maxbb/100.0) != maxbb:
|
|
value += ' - $' + '%.2f' % (maxbb/100.0)
|
|
else:
|
|
value += ' - $' + '%.0f' % (maxbb/100.0)
|
|
else:
|
|
continue
|
|
if value and value != -999:
|
|
treerow.append(column[colformat] % value)
|
|
else:
|
|
treerow.append(' ')
|
|
iter = self.liststore[grid].append(treerow)
|
|
#print treerow
|
|
sqlrow += 1
|
|
row += 1
|
|
tips = DemoTips(column[colformat])
|
|
tips.add_view(view)
|
|
|
|
vbox.show_all()
|
|
view.show()
|
|
if len(self.liststore) == 1:
|
|
#print "view hieght is ", view.get_allocation().height, view.size_request(), view.get_visible_rect().height, view.get_vadjustment().get_value()
|
|
self.top_pane_height = view.size_request()[1]
|
|
#print "saved ", self.top_pane_height
|
|
#end def addGrid
|
|
|
|
def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
|
|
having = ''
|
|
if not flags:
|
|
holecards = False
|
|
numhands = 0
|
|
else:
|
|
holecards = flags[0]
|
|
numhands = flags[1]
|
|
colshow = colshowsumm
|
|
if groups['posn']: colshow = colshowposn
|
|
|
|
if 'allplayers' in groups and groups['allplayers']:
|
|
nametest = "(hp.playerId)"
|
|
if holecards or groups['posn']:
|
|
pname = "'all players'"
|
|
# set flag in self.columns to not show player name column
|
|
[x for x in self.columns if x[0] == 'pname'][0][colshow] = False
|
|
# can't do this yet (re-write doing more maths in python instead of sql?)
|
|
if numhands:
|
|
nametest = "(-1)"
|
|
else:
|
|
pname = "p.name"
|
|
# set flag in self.columns to show player name column
|
|
[x for x in self.columns if x[0] == 'pname'][0][colshow] = True
|
|
if numhands:
|
|
having = ' and count(1) > %d ' % (numhands,)
|
|
else:
|
|
if playerids:
|
|
nametest = str(tuple(playerids))
|
|
nametest = nametest.replace("L", "")
|
|
nametest = nametest.replace(",)",")")
|
|
else:
|
|
nametest = "1 = 2"
|
|
pname = "p.name"
|
|
# set flag in self.columns to not show player name column
|
|
[x for x in self.columns if x[0] == 'pname'][0][colshow] = False
|
|
query = query.replace("<player_test>", nametest)
|
|
query = query.replace("<playerName>", pname)
|
|
query = query.replace("<havingclause>", having)
|
|
|
|
gametest = ""
|
|
q = []
|
|
for m in self.filters.display.items():
|
|
if m[0] == 'Games' and m[1]:
|
|
for n in games:
|
|
if games[n]:
|
|
q.append(n)
|
|
if len(q) > 0:
|
|
gametest = str(tuple(q))
|
|
gametest = gametest.replace("L", "")
|
|
gametest = gametest.replace(",)",")")
|
|
gametest = gametest.replace("u'","'")
|
|
gametest = "and gt.category in %s" % gametest
|
|
else:
|
|
gametest = "and gt.category IS NULL"
|
|
query = query.replace("<game_test>", gametest)
|
|
|
|
sitetest = ""
|
|
q = []
|
|
for m in self.filters.display.items():
|
|
if m[0] == 'Sites' and m[1]:
|
|
for n in sitenos:
|
|
q.append(n)
|
|
if len(q) > 0:
|
|
sitetest = str(tuple(q))
|
|
sitetest = sitetest.replace("L", "")
|
|
sitetest = sitetest.replace(",)",")")
|
|
sitetest = sitetest.replace("u'","'")
|
|
sitetest = "and gt.siteId in %s" % sitetest
|
|
else:
|
|
sitetest = "and gt.siteId IS NULL"
|
|
query = query.replace("<site_test>", sitetest)
|
|
|
|
if seats:
|
|
query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
|
|
if 'show' in seats and seats['show']:
|
|
query = query.replace('<groupbyseats>', ',h.seats')
|
|
query = query.replace('<orderbyseats>', ',h.seats')
|
|
else:
|
|
query = query.replace('<groupbyseats>', '')
|
|
query = query.replace('<orderbyseats>', '')
|
|
else:
|
|
query = query.replace('<seats_test>', 'between 0 and 100')
|
|
query = query.replace('<groupbyseats>', '')
|
|
query = query.replace('<orderbyseats>', '')
|
|
|
|
lims = [int(x) for x in limits if x.isdigit()]
|
|
potlims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'pl']
|
|
nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl']
|
|
capnolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'cn']
|
|
bbtest = "and ( (gt.limitType = 'fl' and gt.bigBlind in "
|
|
# and ( (limit and bb in()) or (nolimit and bb in ()) )
|
|
if lims:
|
|
blindtest = str(tuple(lims))
|
|
blindtest = blindtest.replace("L", "")
|
|
blindtest = blindtest.replace(",)",")")
|
|
bbtest = bbtest + blindtest + ' ) '
|
|
else:
|
|
bbtest = bbtest + '(-1) ) '
|
|
bbtest = bbtest + " or (gt.limitType = 'pl' and gt.bigBlind in "
|
|
if potlims:
|
|
blindtest = str(tuple(potlims))
|
|
blindtest = blindtest.replace("L", "")
|
|
blindtest = blindtest.replace(",)",")")
|
|
bbtest = bbtest + blindtest + ' ) '
|
|
else:
|
|
bbtest = bbtest + '(-1) ) '
|
|
bbtest = bbtest + " or (gt.limitType = 'nl' and gt.bigBlind in "
|
|
if nolims:
|
|
blindtest = str(tuple(nolims))
|
|
blindtest = blindtest.replace("L", "")
|
|
blindtest = blindtest.replace(",)",")")
|
|
bbtest = bbtest + blindtest + ' ) '
|
|
else:
|
|
bbtest = bbtest + '(-1) ) '
|
|
bbtest = bbtest + " or (gt.limitType = 'cn' and gt.bigBlind in "
|
|
if capnolims:
|
|
blindtest = str(tuple(capnolims))
|
|
blindtest = blindtest.replace("L", "")
|
|
blindtest = blindtest.replace(",)",")")
|
|
bbtest = bbtest + blindtest + ' ) )'
|
|
else:
|
|
bbtest = bbtest + '(-1) ) )'
|
|
if type == 'ring':
|
|
bbtest = bbtest + " and gt.type = 'ring' "
|
|
elif type == 'tour':
|
|
bbtest = " and gt.type = 'tour' "
|
|
query = query.replace("<gtbigBlind_test>", bbtest)
|
|
|
|
if holecards: # re-use level variables for hole card query
|
|
query = query.replace("<hgametypeId>", "hp.startcards")
|
|
query = query.replace("<orderbyhgametypeId>"
|
|
, ",case when floor((hp.startcards-1)/13) >= mod((hp.startcards-1),13) then hp.startcards + 0.1 "
|
|
+ " else 13*mod((hp.startcards-1),13) + floor((hp.startcards-1)/13) + 1 "
|
|
+ " end desc ")
|
|
else:
|
|
query = query.replace("<orderbyhgametypeId>", "")
|
|
groupLevels = "show" not in str(limits)
|
|
if groupLevels:
|
|
query = query.replace("<hgametypeId>", "p.name") # need to use p.name for sqlite posn stats to work
|
|
else:
|
|
query = query.replace("<hgametypeId>", "h.gametypeId")
|
|
|
|
# process self.detailFilters (a list of tuples)
|
|
flagtest = ''
|
|
#self.detailFilters = [('h.seats', 5, 6)] # for debug
|
|
if self.detailFilters:
|
|
for f in self.detailFilters:
|
|
if len(f) == 3:
|
|
# X between Y and Z
|
|
flagtest += ' and %s between %s and %s ' % (f[0], str(f[1]), str(f[2]))
|
|
query = query.replace("<flagtest>", flagtest)
|
|
|
|
# allow for differences in sql cast() function:
|
|
if self.db.backend == self.MYSQL_INNODB:
|
|
query = query.replace("<signed>", 'signed ')
|
|
else:
|
|
query = query.replace("<signed>", '')
|
|
|
|
# Filter on dates
|
|
query = query.replace("<datestest>", " between '" + dates[0] + "' and '" + dates[1] + "'")
|
|
|
|
# Group by position?
|
|
if groups['posn']:
|
|
#query = query.replace("<position>", "case hp.position when '0' then 'Btn' else hp.position end")
|
|
query = query.replace("<position>", "hp.position")
|
|
# set flag in self.columns to show posn column
|
|
[x for x in self.columns if x[0] == 'plposition'][0][colshow] = True
|
|
else:
|
|
query = query.replace("<position>", "gt.base")
|
|
# unset flag in self.columns to hide posn column
|
|
[x for x in self.columns if x[0] == 'plposition'][0][colshow] = False
|
|
|
|
#print "query =\n", query
|
|
return(query)
|
|
#end def refineQuery
|
|
|
|
def showDetailFilter(self, widget, data):
|
|
detailDialog = gtk.Dialog(title=_("Detailed Filters"), parent=self.main_window
|
|
,flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
|
|
,buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
|
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
|
|
|
|
handbox = gtk.VBox(True, 0)
|
|
detailDialog.vbox.pack_start(handbox, False, False, 0)
|
|
handbox.show()
|
|
|
|
label = gtk.Label(_("Hand Filters:"))
|
|
handbox.add(label)
|
|
label.show()
|
|
|
|
betweenFilters = []
|
|
for htest in self.handtests:
|
|
hbox = gtk.HBox(False, 0)
|
|
handbox.pack_start(hbox, False, False, 0)
|
|
hbox.show()
|
|
|
|
cb = gtk.CheckButton()
|
|
lbl_from = gtk.Label(htest[1])
|
|
lbl_from.set_alignment(xalign=0.0, yalign=0.5)
|
|
lbl_tween = gtk.Label(_('between'))
|
|
lbl_to = gtk.Label(_('and'))
|
|
adj1 = gtk.Adjustment(value=htest[2], lower=0, upper=10, step_incr=1, page_incr=1, page_size=0)
|
|
sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0)
|
|
adj2 = gtk.Adjustment(value=htest[3], lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
|
|
sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0)
|
|
|
|
for df in [x for x in self.detailFilters if x[0] == htest[0]]:
|
|
cb.set_active(True)
|
|
|
|
hbox.pack_start(cb, expand=False, padding=3)
|
|
hbox.pack_start(lbl_from, expand=True, padding=3)
|
|
hbox.pack_start(lbl_tween, expand=False, padding=3)
|
|
hbox.pack_start(sb1, False, False, 0)
|
|
hbox.pack_start(lbl_to, expand=False, padding=3)
|
|
hbox.pack_start(sb2, False, False, 0)
|
|
|
|
cb.show()
|
|
lbl_from.show()
|
|
lbl_tween.show()
|
|
sb1.show()
|
|
lbl_to.show()
|
|
sb2.show()
|
|
|
|
htest[4:7] = [cb,sb1,sb2]
|
|
|
|
response = detailDialog.run()
|
|
|
|
if response == gtk.RESPONSE_ACCEPT:
|
|
self.detailFilters = []
|
|
for ht in self.handtests:
|
|
if ht[4].get_active():
|
|
self.detailFilters.append( (ht[0], ht[5].get_value_as_int(), ht[6].get_value_as_int()) )
|
|
ht[2],ht[3] = ht[5].get_value_as_int(), ht[6].get_value_as_int()
|
|
print "detailFilters =", self.detailFilters
|
|
self.refreshStats(None, None)
|
|
|
|
detailDialog.destroy()
|
|
|
|
|
|
|
|
|
|
|