7dd8b9de16
Go through and change all references to gameTypeId to gametypeId to make it consistent. The database field is named with the lowercase version, and MySQL is case sensitive. This may have been causing minor issues in multiple areas when attempting to join on gametype.
768 lines
33 KiB
Python
768 lines
33 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#Copyright 2008-2010 Steffen Schaumburg
|
|
#This program is free software: you can redistribute it and/or modify
|
|
#it under the terms of the GNU Affero General Public License as published by
|
|
#the Free Software Foundation, version 3 of the License.
|
|
#
|
|
#This program is distributed in the hope that it will be useful,
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
#GNU General Public License for more details.
|
|
#
|
|
#You should have received a copy of the GNU Affero General Public License
|
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
|
|
|
import 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'),
|
|
'AggFac':_('Aggression Factor\n'),
|
|
'AggFreq':_('Aggression Frequency\nBet or Raise vs Fold'),
|
|
'ContBet':_('Continuation Bet on the 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':_('Amount Won when Show Down seen'),
|
|
'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', 'black')
|
|
#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']
|
|
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) ) )'
|
|
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()
|
|
|
|
|
|
|
|
|
|
|