Add 'Currencies' filter to the ring player stats viewer.
[fpdb-dooglus.git] / pyfpdb / GuiRingPlayerStats.py
blob85244960b49f3c26840723a9f16e8894e2de9913
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 #Copyright 2008-2011 Steffen Schaumburg
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 #GNU General Public License for more details.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
18 import L10n
19 _ = L10n.get_translation()
21 import traceback
22 import threading
23 import pygtk
24 pygtk.require('2.0')
25 import gtk
26 import os
27 import sys
28 from time import time, strftime
30 import Card
31 import fpdb_import
32 import Database
33 import Filters
34 import Charset
35 import GuiPlayerStats
37 from TreeViewTooltips import TreeViewTooltips
40 #colalias,colshowsumm,colshowposn,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5,6
41 #new order in config file:
42 colalias,colheading,colshowsumm,colshowposn,colformat,coltype,colxalign = 0,1,2,3,4,5,6
43 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}
44 onlinehelp = {'Game':_('Type of Game'),
45 'Hand':_('Hole cards'),
46 'Posn':_('Position'),
47 'Name':_('Player Name'),
48 'Hds':_('Number of hands seen'),
49 'Seats':_('Number of Seats'),
50 'VPIP':_('Voluntarily put in preflop/3rd street %'),
51 'PFR':_('Preflop/3rd street raise %'),
52 'PF3':_('% 3 bet preflop/3rd street'),
53 'PF4':_('% 4 bet preflop/3rd street'),
54 'PFF3':_('% fold to 3 bet preflop/3rd street'),
55 'PFF4':_('% fold to 4 bet preflop/3rd street'),
56 'AggFac':_('Aggression factor')+("\n"),
57 'AggFreq':_('Post-flop aggression frequency'),
58 'ContBet':_('% continuation bet'),
59 'RFI':_('% Raise First In / % Raise when first to bet'),
60 'Steals':_('% steal attempted'),
61 'Saw_F':_('Flop/4th street seen %'),
62 'SawSD':_('Saw Showdown / River'),
63 'WtSDwsF':_('% went to showdown when seen flop/4th street'),
64 'W$SD':_('% won some money at showdown'),
65 'FlAFq':_('Aggression frequency flop/4th street'),
66 'TuAFq':_('Aggression frequency turn/5th street'),
67 'RvAFq':_('Aggression frequency river/6th street'),
68 'PoFAFq':_('Coming Soon\nTotal % agression'),
69 'Net($)':_('Total Profit'),
70 'bb/100':_('Big blinds won per 100 hands'),
71 'Rake($)':_('Amount of rake paid'),
72 'bbxr/100':_('Big blinds won per 100 hands\nwhen excluding rake'),
73 'Variance':_('Measure of uncertainty\nThe lower, the more stable the amounts won')
78 class DemoTips(TreeViewTooltips):
80 def __init__(self, customer_column):
81 # call base class init
82 TreeViewTooltips.__init__(self)
84 def get_tooltip(self, view, column, path):
85 model = view.get_model()
86 cards = model[path][0]
87 title=column.get_title()
88 if (title == 'Hand' or title == 'Game'): display='' #no tooltips on headers
89 else: display='<big>%s for %s</big>\n<i>%s</i>' % (title,cards,onlinehelp[title])
90 return (display)
92 def location(self, x, y, w, h):
93 # this will place the tooltip above and to the right
94 return x + 30, y - (h + 10)
98 class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
100 def __init__(self, config, querylist, mainwin, debug=True):
101 self.debug = debug
102 self.conf = config
103 self.main_window = mainwin
104 self.sql = querylist
106 self.liststore = [] # gtk.ListStore[] stores the contents of the grids
107 self.listcols = [] # gtk.TreeViewColumn[][] stores the columns in the grids
109 self.MYSQL_INNODB = 2
110 self.PGSQL = 3
111 self.SQLITE = 4
113 # create new db connection to avoid conflicts with other threads
114 self.db = Database.Database(self.conf, sql=self.sql)
115 self.cursor = self.db.cursor
117 settings = {}
118 settings.update(self.conf.get_db_parameters())
119 settings.update(self.conf.get_import_parameters())
120 settings.update(self.conf.get_default_paths())
122 # text used on screen stored here so that it can be configured
123 self.filterText = {'handhead':_('Hand Breakdown for all levels listed above')
126 filters_display = { "Heroes" : True,
127 "Sites" : True,
128 "Games" : True,
129 "Currencies": True,
130 "Limits" : True,
131 "LimitSep" : True,
132 "LimitType" : True,
133 "Type" : True,
134 "Seats" : True,
135 "SeatSep" : True,
136 "Dates" : True,
137 "Groups" : True,
138 "GroupsAll" : True,
139 "Button1" : True,
140 "Button2" : True
143 self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
144 self.filters.registerButton1Name(_("_Filters"))
145 self.filters.registerButton1Callback(self.showDetailFilter)
146 self.filters.registerButton2Name(_("_Refresh Stats"))
147 self.filters.registerButton2Callback(self.refreshStats)
149 # ToDo: store in config
150 # ToDo: create popup to adjust column config
151 # columns to display, keys match column name returned by sql, values in tuple are:
152 # is column displayed(summary then position), column heading, xalignment, formatting, celltype
153 self.columns = self.conf.get_gui_cash_stat_params()
155 # Detail filters: This holds the data used in the popup window, extra values are
156 # added at the end of these lists during processing
157 # sql test, screen description, min, max
158 self.handtests = [ # already in filter class : ['h.seats', 'Number of Players', 2, 10]
159 ['h.maxSeats', 'Size of Table', 2, 10]
160 ,['h.playersVpi', 'Players who VPI', 0, 10]
161 ,['h.playersAtStreet1', 'Players at Flop', 0, 10]
162 ,['h.playersAtStreet2', 'Players at Turn', 0, 10]
163 ,['h.playersAtStreet3', 'Players at River', 0, 10]
164 ,['h.playersAtStreet4', 'Players at Street7', 0, 10]
165 ,['h.playersAtShowdown', 'Players at Showdown', 0, 10]
166 ,['h.street0Raises', 'Bets to See Flop', 0, 5]
167 ,['h.street1Raises', 'Bets to See Turn', 0, 5]
168 ,['h.street2Raises', 'Bets to See River', 0, 5]
169 ,['h.street3Raises', 'Bets to See Street7', 0, 5]
170 ,['h.street4Raises', 'Bets to See Showdown', 0, 5]
173 self.cardstests = [
174 [Card.DATABASE_FILTERS['pair'], _('Pocket pairs')],
175 [Card.DATABASE_FILTERS['suited'], _('Suited')],
176 [Card.DATABASE_FILTERS['suited_connectors'], _('Suited connectors')],
177 [Card.DATABASE_FILTERS['offsuit'], _('Offsuit')],
178 [Card.DATABASE_FILTERS['offsuit_connectors'], _('Offsuit connectors')],
180 self.stats_frame = None
181 self.stats_vbox = None
182 self.detailFilters = [] # the data used to enhance the sql select
183 self.cardsFilters = []
185 #self.main_hbox = gtk.HBox(False, 0)
186 #self.main_hbox.show()
187 self.main_hbox = gtk.HPaned()
189 self.stats_frame = gtk.Frame()
190 self.stats_frame.show()
192 self.stats_vbox = gtk.VPaned()
193 self.stats_vbox.show()
194 self.stats_frame.add(self.stats_vbox)
195 self.top_pane_height = 0
196 self.height_inc = None
197 # self.fillStatsFrame(self.stats_vbox)
199 #self.main_hbox.pack_start(self.filters.get_vbox())
200 #self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
201 self.main_hbox.pack1(self.filters.get_vbox())
202 self.main_hbox.pack2(self.stats_frame)
203 self.main_hbox.show()
205 # make sure Hand column is not displayed
206 [x for x in self.columns if x[0] == 'hand'][0][colshowsumm] = False
207 [x for x in self.columns if x[0] == 'hand'][0][colshowposn] = False
208 # if rfi and steal both on for summaries, turn rfi off
209 if ( [x for x in self.columns if x[0] == 'rfi'][0][colshowsumm]
210 and [x for x in self.columns if x[0] == 'steals'][0][colshowsumm]):
211 [x for x in self.columns if x[0] == 'rfi'][0][colshowsumm] = False
212 # if rfi and steal both on for position breakdowns, turn steals off:
213 if ( [x for x in self.columns if x[0] == 'rfi'][0][colshowposn]
214 and [x for x in self.columns if x[0] == 'steals'][0][colshowposn]):
215 [x for x in self.columns if x[0] == 'steals'][0][colshowposn] = False
217 self.last_pos = -1
220 def get_vbox(self):
221 """returns the vbox of this thread"""
222 return self.main_hbox
223 #end def get_vbox
225 def refreshStats(self, widget, data):
226 #self.last_pos = self.stats_vbox.get_position()
227 self.height_inc = None
228 #old_len = 0
229 #if self.liststore:
230 # old_len = len(self.liststore[0])
231 try: self.stats_vbox.destroy()
232 except AttributeError: pass
233 self.liststore = []
234 self.listcols = []
235 self.stats_vbox = gtk.VPaned()
236 self.stats_vbox.show()
237 self.stats_frame.add(self.stats_vbox)
238 self.fillStatsFrame(self.stats_vbox)
240 # set height of top pane
241 # (tried 2 ways, guesstimate using ratio of old to new number of rows and sum of
242 # heights of parts)
243 new_len = 0
244 if self.liststore:
245 #new_len = len(self.liststore[0])
246 #print "setting to", self.top_pane_height + self.height_inc
247 self.stats_vbox.set_position(self.top_pane_height + self.height_inc)
248 #if self.last_pos > 0:
249 # if old_len > 0 and new_len > 0 and new_len <= 10:
250 # self.stats_vbox.set_position(self.last_pos * (new_len+1.9)/(old_len+1.9))
251 # else:
252 # self.stats_vbox.set_position(self.last_pos)
253 #end def refreshStats
255 def fillStatsFrame(self, vbox):
256 sites = self.filters.getSites()
257 heroes = self.filters.getHeroes()
258 siteids = self.filters.getSiteIds()
259 limits = self.filters.getLimits()
260 type = self.filters.getType()
261 seats = self.filters.getSeats()
262 groups = self.filters.getGroups()
263 dates = self.filters.getDates()
264 games = self.filters.getGames()
265 currencies = self.filters.getCurrencies()
266 sitenos = []
267 playerids = []
269 # Which sites are selected?
270 for site in sites:
271 if sites[site] == True:
272 sitenos.append(siteids[site])
273 _hname = Charset.to_utf8(heroes[site])
274 result = self.db.get_player_id(self.conf, site, _hname)
275 if result is not None:
276 playerids.append(int(result))
278 if not sitenos:
279 #Should probably pop up here.
280 print _("No sites selected - defaulting to PokerStars")
281 sitenos = [2]
282 if not playerids:
283 print _("No player ids found")
284 return
285 if not limits:
286 print _("No limits found")
287 return
289 self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates, games, currencies)
290 #end def fillStatsFrame
292 def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates, games, currencies):
293 startTime = time()
294 show_detail = True
296 # Scrolled window for summary table
297 swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
298 swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
299 vbox.pack1(swin) #, resize=True) don't use resize, self.height_inc relies on initial
300 # height of pane being correct for one row
302 # Display summary table at top of page
303 # 3rd parameter passes extra flags, currently includes:
304 # holecards - whether to display card breakdown (True/False)
305 # numhands - min number hands required when displaying all players
306 # gridnum - index for grid data structures
307 flags = [False, self.filters.getNumHands(), 0]
308 self.addGrid(swin, 'playerDetailedStats', flags, playerids
309 ,sitenos, limits, type, seats, groups, dates, games, currencies)
310 swin.show()
312 if 'allplayers' in groups and groups['allplayers']:
313 # can't currently do this combination so skip detailed table
314 show_detail = False
316 if show_detail:
317 # Separator
318 vbox2 = gtk.VBox(False, 0)
319 heading = gtk.Label(self.filterText['handhead'])
320 heading.show()
321 vbox2.pack_start(heading, expand=False, padding=3)
323 # Scrolled window for detailed table (display by hand)
324 swin2 = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
325 swin2.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
326 swin2.show()
327 vbox2.pack_start(swin2, expand=True, padding=3)
328 vbox.pack2(vbox2)
329 vbox2.show()
331 # Detailed table
332 flags[0] = True
333 flags[2] = 1
334 self.addGrid(swin2, 'playerDetailedStats', flags, playerids
335 ,sitenos, limits, type, seats, groups, dates, games, currencies)
337 if self.height_inc is None:
338 self.height_inc = 0
339 # need this to check whether scrollbar is visible:
340 while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
341 gtk.main_iteration(False)
342 hs = swin.get_hscrollbar()
343 if hs is not None:
344 #print "hs vis", hs.get_property('visible'), hs.get_property('visible').__class__
345 if hs.get_property('visible'):
346 self.height_inc = hs.size_request()[1] + swin.style_get_property('scrollbar-spacing')
347 #print "hh set to", self.height_inc
348 self.stats_vbox.set_position(self.top_pane_height + self.height_inc)
350 self.db.rollback()
351 print (_("Stats page displayed in %4.2f seconds") % (time() - startTime))
352 #end def createStatsTable
354 def reset_style_render_func(self, treeviewcolumn, cell, model, iter):
355 cell.set_property('foreground', None)
356 #end def reset_style_render_func
358 def ledger_style_render_func(self, tvcol, cell, model, iter):
359 str = cell.get_property('text')
360 if '-' in str:
361 str = str.replace("-", "")
362 str = "(%s)" %(str)
363 cell.set_property('text', str)
364 cell.set_property('foreground', 'red')
365 else:
366 cell.set_property('foreground', 'darkgreen')
368 return
370 def sortnums(self, model, iter1, iter2, nums):
371 try:
372 ret = 0
373 (n, grid) = nums
374 a = self.liststore[grid].get_value(iter1, n)
375 b = self.liststore[grid].get_value(iter2, n)
376 if 'f' in self.cols_to_show[n][4]:
377 try: a = float(a)
378 except: a = 0.0
379 try: b = float(b)
380 except: b = 0.0
381 if n == 0 and grid == 1: #make sure it only works on the starting hands
382 a1,a2,a3 = ranks[a[0]], ranks[a[1]], (a+'o')[2]
383 b1,b2,b3 = ranks[b[0]], ranks[b[1]], (b+'o')[2]
384 if a1 > b1 or ( a1 == b1 and (a2 > b2 or (a2 == b2 and a3 > b3) ) ):
385 ret = 1
386 else:
387 ret = -1
388 else:
389 if a < b:
390 ret = -1
391 elif a == b:
392 ret = 0
393 else:
394 ret = 1
395 #print "n =", n, "iter1[n] =", self.liststore[grid].get_value(iter1,n), "iter2[n] =", self.liststore[grid].get_value(iter2,n), "ret =", ret
396 except:
397 err = traceback.extract_tb(sys.exc_info()[2])
398 print _("***sortnums error: ") + str(sys.exc_info()[1])
399 print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
401 return(ret)
403 def sortcols(self, col, nums):
404 try:
405 #This doesn't actually work yet - clicking heading in top section sorts bottom section :-(
406 (n, grid) = nums
407 if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
408 col.set_sort_order(gtk.SORT_DESCENDING)
409 else:
410 col.set_sort_order(gtk.SORT_ASCENDING)
411 self.liststore[grid].set_sort_column_id(n, col.get_sort_order())
412 self.liststore[grid].set_sort_func(n, self.sortnums, (n,grid))
413 for i in xrange(len(self.listcols[grid])):
414 self.listcols[grid][i].set_sort_indicator(False)
415 self.listcols[grid][n].set_sort_indicator(True)
416 # use this listcols[col].set_sort_indicator(True)
417 # to turn indicator off for other cols
418 except:
419 err = traceback.extract_tb(sys.exc_info()[2])
420 print _("***sortcols error: ") + str(sys.exc_info()[1])
421 print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
422 #end def sortcols
425 def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games, currencies):
426 counter = 0
427 row = 0
428 sqlrow = 0
429 if not flags: holecards,grid = False,0
430 else: holecards,grid = flags[0],flags[2]
432 tmp = self.sql.query[query]
433 tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates, games, currencies)
434 #print "DEBUG: query: %s" % tmp
435 self.cursor.execute(tmp)
436 result = self.cursor.fetchall()
437 colnames = [desc[0].lower() for desc in self.cursor.description]
439 # pre-fetch some constant values:
440 colshow = colshowsumm
441 if groups['posn']: colshow = colshowposn
442 self.cols_to_show = [x for x in self.columns if x[colshow]]
443 hgametypeid_idx = colnames.index('hgametypeid')
445 assert len(self.liststore) == grid, "len(self.liststore)="+str(len(self.liststore))+" grid-1="+str(grid)
446 self.liststore.append( gtk.ListStore(*([str] * len(self.cols_to_show))) )
447 view = gtk.TreeView(model=self.liststore[grid])
448 view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
449 #vbox.pack_start(view, expand=False, padding=3)
450 vbox.add(view)
451 textcell = gtk.CellRendererText()
452 textcell50 = gtk.CellRendererText()
453 textcell50.set_property('xalign', 0.5)
454 numcell = gtk.CellRendererText()
455 numcell.set_property('xalign', 1.0)
456 assert len(self.listcols) == grid
457 self.listcols.append( [] )
459 # Create header row eg column: ("game", True, "Game", 0.0, "%s")
460 for col, column in enumerate(self.cols_to_show):
461 if column[colalias] == 'game' and holecards:
462 s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading]
463 else:
464 s = column[colheading]
465 self.listcols[grid].append(gtk.TreeViewColumn(s))
466 view.append_column(self.listcols[grid][col])
467 if column[colformat] == '%s':
468 if column[colxalign] == 0.0:
469 self.listcols[grid][col].pack_start(textcell, expand=True)
470 self.listcols[grid][col].add_attribute(textcell, 'text', col)
471 cellrend = textcell
472 else:
473 self.listcols[grid][col].pack_start(textcell50, expand=True)
474 self.listcols[grid][col].add_attribute(textcell50, 'text', col)
475 cellrend = textcell50
476 self.listcols[grid][col].set_expand(True)
477 else:
478 self.listcols[grid][col].pack_start(numcell, expand=True)
479 self.listcols[grid][col].add_attribute(numcell, 'text', col)
480 self.listcols[grid][col].set_expand(True)
481 cellrend = numcell
482 #self.listcols[grid][col].set_alignment(column[colxalign]) # no effect?
483 self.listcols[grid][col].set_clickable(True)
484 self.listcols[grid][col].connect("clicked", self.sortcols, (col,grid))
485 if col == 0:
486 self.listcols[grid][col].set_sort_order(gtk.SORT_DESCENDING)
487 self.listcols[grid][col].set_sort_indicator(True)
488 if column[coltype] == 'cash':
489 self.listcols[grid][col].set_cell_data_func(numcell, self.ledger_style_render_func)
490 else:
491 self.listcols[grid][col].set_cell_data_func(cellrend, self.reset_style_render_func)
493 rows = len(result) # +1 for title row
495 while sqlrow < rows:
496 treerow = []
497 for col,column in enumerate(self.cols_to_show):
498 if column[colalias] in colnames:
499 value = result[sqlrow][colnames.index(column[colalias])]
500 if column[colalias] == 'plposition':
501 if value == 'B':
502 value = 'BB'
503 elif value == 'S':
504 value = 'SB'
505 elif value == '0':
506 value = 'Btn'
507 else:
508 if column[colalias] == 'game':
509 if holecards:
510 value = Card.decodeStartHandValue(result[sqlrow][colnames.index('category')], result[sqlrow][hgametypeid_idx] )
511 else:
512 minbb = result[sqlrow][colnames.index('minbigblind')]
513 maxbb = result[sqlrow][colnames.index('maxbigblind')]
514 value = result[sqlrow][colnames.index('limittype')] + ' ' \
515 + result[sqlrow][colnames.index('category')].title() + ' ' \
516 + result[sqlrow][colnames.index('name')] + ' $'
517 if 100 * int(minbb/100.0) != minbb:
518 value += '%.2f' % (minbb/100.0)
519 else:
520 value += '%.0f' % (minbb/100.0)
521 if minbb != maxbb:
522 if 100 * int(maxbb/100.0) != maxbb:
523 value += ' - $' + '%.2f' % (maxbb/100.0)
524 else:
525 value += ' - $' + '%.0f' % (maxbb/100.0)
526 else:
527 continue
528 if value != None and value != -999:
529 treerow.append(column[colformat] % value)
530 else:
531 treerow.append(' ')
532 iter = self.liststore[grid].append(treerow)
533 #print treerow
534 sqlrow += 1
535 row += 1
536 tips = DemoTips(column[colformat])
537 tips.add_view(view)
539 vbox.show_all()
540 view.show()
541 if len(self.liststore) == 1:
542 #print "view hieght is ", view.get_allocation().height, view.size_request(), view.get_visible_rect().height, view.get_vadjustment().get_value()
543 self.top_pane_height = view.size_request()[1]
544 #print "saved ", self.top_pane_height
545 #end def addGrid
547 def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games, currencies):
548 having = ''
549 if not flags:
550 holecards = False
551 numhands = 0
552 else:
553 holecards = flags[0]
554 numhands = flags[1]
555 colshow = colshowsumm
556 if groups['posn']: colshow = colshowposn
558 if 'allplayers' in groups and groups['allplayers']:
559 nametest = "(hp.playerId)"
560 if holecards or groups['posn']:
561 pname = "'all players'"
562 # set flag in self.columns to not show player name column
563 [x for x in self.columns if x[0] == 'pname'][0][colshow] = False
564 # can't do this yet (re-write doing more maths in python instead of sql?)
565 if numhands:
566 nametest = "(-1)"
567 else:
568 pname = "p.name"
569 # set flag in self.columns to show player name column
570 [x for x in self.columns if x[0] == 'pname'][0][colshow] = True
571 if numhands:
572 having = ' and count(1) > %d ' % (numhands,)
573 else:
574 if playerids:
575 nametest = str(tuple(playerids))
576 nametest = nametest.replace("L", "")
577 nametest = nametest.replace(",)",")")
578 else:
579 nametest = "1 = 2"
580 pname = "p.name"
581 # set flag in self.columns to not show player name column
582 [x for x in self.columns if x[0] == 'pname'][0][colshow] = False
583 query = query.replace("<player_test>", nametest)
584 query = query.replace("<playerName>", pname)
585 query = query.replace("<havingclause>", having)
587 gametest = ""
588 q = []
589 for m in self.filters.display.items():
590 if m[0] == 'Games' and m[1]:
591 for n in games:
592 if games[n]:
593 q.append(n)
594 if len(q) > 0:
595 gametest = str(tuple(q))
596 gametest = gametest.replace("L", "")
597 gametest = gametest.replace(",)",")")
598 gametest = gametest.replace("u'","'")
599 gametest = "and gt.category in %s" % gametest
600 else:
601 gametest = "and gt.category IS NULL"
602 query = query.replace("<game_test>", gametest)
604 q = []
605 for n in currencies:
606 if currencies[n]:
607 q.append(n)
608 currencytest = str(tuple(q))
609 currencytest = currencytest.replace(",)",")")
610 currencytest = currencytest.replace("u'","'")
611 currencytest = "AND gt.currency in %s" % currencytest
612 query = query.replace("<currency_test>", currencytest)
614 sitetest = ""
615 q = []
616 for m in self.filters.display.items():
617 if m[0] == 'Sites' and m[1]:
618 for n in sitenos:
619 q.append(n)
620 if len(q) > 0:
621 sitetest = str(tuple(q))
622 sitetest = sitetest.replace("L", "")
623 sitetest = sitetest.replace(",)",")")
624 sitetest = sitetest.replace("u'","'")
625 sitetest = "and gt.siteId in %s" % sitetest
626 else:
627 sitetest = "and gt.siteId IS NULL"
628 query = query.replace("<site_test>", sitetest)
630 if seats:
631 query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
632 if 'show' in seats and seats['show']:
633 query = query.replace('<groupbyseats>', ',h.seats')
634 query = query.replace('<orderbyseats>', ',h.seats')
635 else:
636 query = query.replace('<groupbyseats>', '')
637 query = query.replace('<orderbyseats>', '')
638 else:
639 query = query.replace('<seats_test>', 'between 0 and 100')
640 query = query.replace('<groupbyseats>', '')
641 query = query.replace('<orderbyseats>', '')
643 lims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'fl']
644 potlims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'pl']
645 nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl']
646 capnolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'cn']
647 bbtest = "and ( (gt.limitType = 'fl' and gt.bigBlind in "
648 # and ( (limit and bb in()) or (nolimit and bb in ()) )
649 if lims:
650 blindtest = str(tuple(lims))
651 blindtest = blindtest.replace("L", "")
652 blindtest = blindtest.replace(",)",")")
653 bbtest = bbtest + blindtest + ' ) '
654 else:
655 bbtest = bbtest + '(-1) ) '
656 bbtest = bbtest + " or (gt.limitType = 'pl' and gt.bigBlind in "
657 if potlims:
658 blindtest = str(tuple(potlims))
659 blindtest = blindtest.replace("L", "")
660 blindtest = blindtest.replace(",)",")")
661 bbtest = bbtest + blindtest + ' ) '
662 else:
663 bbtest = bbtest + '(-1) ) '
664 bbtest = bbtest + " or (gt.limitType = 'nl' and gt.bigBlind in "
665 if nolims:
666 blindtest = str(tuple(nolims))
667 blindtest = blindtest.replace("L", "")
668 blindtest = blindtest.replace(",)",")")
669 bbtest = bbtest + blindtest + ' ) '
670 else:
671 bbtest = bbtest + '(-1) ) '
672 bbtest = bbtest + " or (gt.limitType = 'cn' and gt.bigBlind in "
673 if capnolims:
674 blindtest = str(tuple(capnolims))
675 blindtest = blindtest.replace("L", "")
676 blindtest = blindtest.replace(",)",")")
677 bbtest = bbtest + blindtest + ' ) )'
678 else:
679 bbtest = bbtest + '(-1) ) )'
680 if type == 'ring':
681 bbtest = bbtest + " and gt.type = 'ring' "
682 elif type == 'tour':
683 bbtest = " and gt.type = 'tour' "
684 query = query.replace("<gtbigBlind_test>", bbtest)
686 if holecards: # re-use level variables for hole card query
687 query = query.replace("<hgametypeId>", "hp.startcards")
688 query = query.replace("<orderbyhgametypeId>"
689 , ",case when floor((hp.startcards-1)/13) >= mod((hp.startcards-1),13) then hp.startcards + 0.1 "
690 + " else 13*mod((hp.startcards-1),13) + floor((hp.startcards-1)/13) + 1 "
691 + " end desc ")
692 else:
693 query = query.replace("<orderbyhgametypeId>", "")
694 groupLevels = "show" not in str(limits)
695 if groupLevels:
696 query = query.replace("<hgametypeId>", "p.name") # need to use p.name for sqlite posn stats to work
697 else:
698 query = query.replace("<hgametypeId>", "h.gametypeId")
700 # process self.detailFilters (a list of tuples)
701 flagtest = ''
702 #self.detailFilters = [('h.seats', 5, 6)] # for debug
703 if self.detailFilters:
704 for f in self.detailFilters:
705 if len(f) == 3:
706 # X between Y and Z
707 flagtest += ' and %s between %s and %s ' % (f[0], str(f[1]), str(f[2]))
708 query = query.replace("<flagtest>", flagtest)
709 if self.cardsFilters:
710 cardstests = []
712 for filter in self.cardsFilters:
713 cardstests.append(filter)
714 cardstests = ''.join(('and (', ' or '.join(cardstests), ')'))
715 else:
716 cardstests = ''
717 query = query.replace("<cardstest>", cardstests)
718 # allow for differences in sql cast() function:
719 if self.db.backend == self.MYSQL_INNODB:
720 query = query.replace("<signed>", 'signed ')
721 else:
722 query = query.replace("<signed>", '')
724 # Filter on dates
725 query = query.replace("<datestest>", " between '" + dates[0] + "' and '" + dates[1] + "'")
727 # Group by position?
728 if groups['posn']:
729 #query = query.replace("<position>", "case hp.position when '0' then 'Btn' else hp.position end")
730 query = query.replace("<position>", "hp.position")
731 # set flag in self.columns to show posn column
732 [x for x in self.columns if x[0] == 'plposition'][0][colshow] = True
733 else:
734 query = query.replace("<position>", "gt.base")
735 # unset flag in self.columns to hide posn column
736 [x for x in self.columns if x[0] == 'plposition'][0][colshow] = False
738 #print "query =\n", query
739 return(query)
740 #end def refineQuery
742 def showDetailFilter(self, widget, data):
743 detailDialog = gtk.Dialog(title=_("Detailed Filters"), parent=self.main_window
744 ,flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
745 ,buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
746 gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
748 handbox = gtk.VBox(True, 0)
749 detailDialog.vbox.pack_start(handbox, False, False, 0)
750 handbox.show()
752 label = gtk.Label(_("Hand Filters:"))
753 handbox.add(label)
754 label.show()
756 betweenFilters = []
757 def add_hbox():
758 hbox = gtk.HBox(False, 0)
759 handbox.pack_start(hbox, False, False, 0)
760 hbox.show()
761 return hbox
763 for htest in self.handtests:
764 hbox = add_hbox()
765 cb = gtk.CheckButton()
766 lbl_from = gtk.Label(htest[1])
767 lbl_from.set_alignment(xalign=0.0, yalign=0.5)
768 lbl_tween = gtk.Label(_('between'))
769 lbl_to = gtk.Label(_('and'))
770 adj1 = gtk.Adjustment(value=htest[2], lower=0, upper=10, step_incr=1, page_incr=1, page_size=0)
771 sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0)
772 adj2 = gtk.Adjustment(value=htest[3], lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
773 sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0)
775 for df in [x for x in self.detailFilters if x[0] == htest[0]]:
776 cb.set_active(True)
778 hbox.pack_start(cb, expand=False, padding=3)
779 hbox.pack_start(lbl_from, expand=True, padding=3)
780 hbox.pack_start(lbl_tween, expand=False, padding=3)
781 hbox.pack_start(sb1, False, False, 0)
782 hbox.pack_start(lbl_to, expand=False, padding=3)
783 hbox.pack_start(sb2, False, False, 0)
785 cb.show()
786 lbl_from.show()
787 lbl_tween.show()
788 sb1.show()
789 lbl_to.show()
790 sb2.show()
792 htest[4:7] = [cb,sb1,sb2]
794 label = gtk.Label(_('Restrict to hand types:'))
795 handbox.add(label)
796 label.show()
797 for ctest in self.cardstests:
798 hbox = add_hbox()
799 cb = gtk.CheckButton()
800 if ctest[0] in self.cardsFilters:
801 cb.set_active(True)
802 label = gtk.Label(ctest[1])
803 hbox.pack_start(cb, expand=False, padding=3)
804 hbox.pack_start(label, expand=True, padding=3)
805 cb.show()
806 label.show()
807 ctest[2:3] = [cb]
808 response = detailDialog.run()
810 if response == gtk.RESPONSE_ACCEPT:
811 self.detailFilters = []
812 for ht in self.handtests:
813 if ht[4].get_active():
814 self.detailFilters.append( (ht[0], ht[5].get_value_as_int(), ht[6].get_value_as_int()) )
815 ht[2],ht[3] = ht[5].get_value_as_int(), ht[6].get_value_as_int()
816 print "detailFilters =", self.detailFilters
817 self.cardsFilters = []
818 for ct in self.cardstests:
819 if ct[2].get_active():
820 self.cardsFilters.append(ct[0])
821 print "cardsFilters =", self.cardsFilters
822 self.refreshStats(None, None)
824 detailDialog.destroy()