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.
19 _
= L10n
.get_translation()
28 from time
import time
, strftime
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'),
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
])
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):
103 self
.main_window
= mainwin
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
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
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,
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]
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
221 """returns the vbox of this thread"""
222 return self
.main_hbox
225 def refreshStats(self
, widget
, data
):
226 #self.last_pos = self.stats_vbox.get_position()
227 self
.height_inc
= None
230 # old_len = len(self.liststore[0])
231 try: self
.stats_vbox
.destroy()
232 except AttributeError: pass
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
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))
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()
269 # Which sites are selected?
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
))
279 #Should probably pop up here.
280 print _("No sites selected - defaulting to PokerStars")
283 print _("No player ids found")
286 print _("No limits found")
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
):
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
)
312 if 'allplayers' in groups
and groups
['allplayers']:
313 # can't currently do this combination so skip detailed table
318 vbox2
= gtk
.VBox(False, 0)
319 heading
= gtk
.Label(self
.filterText
['handhead'])
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
)
327 vbox2
.pack_start(swin2
, expand
=True, padding
=3)
334 self
.addGrid(swin2
, 'playerDetailedStats', flags
, playerids
335 ,sitenos
, limits
, type, seats
, groups
, dates
, games
, currencies
)
337 if self
.height_inc
is None:
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()
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
)
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')
361 str = str.replace("-", "")
363 cell
.set_property('text', str)
364 cell
.set_property('foreground', 'red')
366 cell
.set_property('foreground', 'darkgreen')
370 def sortnums(self
, model
, iter1
, iter2
, 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]:
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
) ) ):
395 #print "n =", n, "iter1[n] =", self.liststore[grid].get_value(iter1,n), "iter2[n] =", self.liststore[grid].get_value(iter2,n), "ret =", ret
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
] )
403 def sortcols(self
, col
, nums
):
405 #This doesn't actually work yet - clicking heading in top section sorts bottom section :-(
407 if not col
.get_sort_indicator() or col
.get_sort_order() == gtk
.SORT_ASCENDING
:
408 col
.set_sort_order(gtk
.SORT_DESCENDING
)
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
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
] )
425 def addGrid(self
, vbox
, query
, flags
, playerids
, sitenos
, limits
, type, seats
, groups
, dates
, games
, currencies
):
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)
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
]
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
)
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)
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)
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
))
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
)
491 self
.listcols
[grid
][col
].set_cell_data_func(cellrend
, self
.reset_style_render_func
)
493 rows
= len(result
) # +1 for title row
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':
508 if column
[colalias
] == 'game':
510 value
= Card
.decodeStartHandValue(result
[sqlrow
][colnames
.index('category')], result
[sqlrow
][hgametypeid_idx
] )
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)
520 value
+= '%.0f' % (minbb
/100.0)
522 if 100 * int(maxbb
/100.0) != maxbb
:
523 value
+= ' - $' + '%.2f' % (maxbb
/100.0)
525 value
+= ' - $' + '%.0f' % (maxbb
/100.0)
528 if value
!= None and value
!= -999:
529 treerow
.append(column
[colformat
] % value
)
532 iter = self
.liststore
[grid
].append(treerow
)
536 tips
= DemoTips(column
[colformat
])
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
547 def refineQuery(self
, query
, flags
, playerids
, sitenos
, limits
, type, seats
, groups
, dates
, games
, currencies
):
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?)
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
572 having
= ' and count(1) > %d ' % (numhands
,)
575 nametest
= str(tuple(playerids
))
576 nametest
= nametest
.replace("L", "")
577 nametest
= nametest
.replace(",)",")")
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
)
589 for m
in self
.filters
.display
.items():
590 if m
[0] == 'Games' and m
[1]:
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
601 gametest
= "and gt.category IS NULL"
602 query
= query
.replace("<game_test>", gametest
)
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
)
616 for m
in self
.filters
.display
.items():
617 if m
[0] == 'Sites' and m
[1]:
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
627 sitetest
= "and gt.siteId IS NULL"
628 query
= query
.replace("<site_test>", sitetest
)
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')
636 query
= query
.replace('<groupbyseats>', '')
637 query
= query
.replace('<orderbyseats>', '')
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 ()) )
650 blindtest
= str(tuple(lims
))
651 blindtest
= blindtest
.replace("L", "")
652 blindtest
= blindtest
.replace(",)",")")
653 bbtest
= bbtest
+ blindtest
+ ' ) '
655 bbtest
= bbtest
+ '(-1) ) '
656 bbtest
= bbtest
+ " or (gt.limitType = 'pl' and gt.bigBlind in "
658 blindtest
= str(tuple(potlims
))
659 blindtest
= blindtest
.replace("L", "")
660 blindtest
= blindtest
.replace(",)",")")
661 bbtest
= bbtest
+ blindtest
+ ' ) '
663 bbtest
= bbtest
+ '(-1) ) '
664 bbtest
= bbtest
+ " or (gt.limitType = 'nl' and gt.bigBlind in "
666 blindtest
= str(tuple(nolims
))
667 blindtest
= blindtest
.replace("L", "")
668 blindtest
= blindtest
.replace(",)",")")
669 bbtest
= bbtest
+ blindtest
+ ' ) '
671 bbtest
= bbtest
+ '(-1) ) '
672 bbtest
= bbtest
+ " or (gt.limitType = 'cn' and gt.bigBlind in "
674 blindtest
= str(tuple(capnolims
))
675 blindtest
= blindtest
.replace("L", "")
676 blindtest
= blindtest
.replace(",)",")")
677 bbtest
= bbtest
+ blindtest
+ ' ) )'
679 bbtest
= bbtest
+ '(-1) ) )'
681 bbtest
= bbtest
+ " and gt.type = 'ring' "
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 "
693 query
= query
.replace("<orderbyhgametypeId>", "")
694 groupLevels
= "show" not in str(limits
)
696 query
= query
.replace("<hgametypeId>", "p.name") # need to use p.name for sqlite posn stats to work
698 query
= query
.replace("<hgametypeId>", "h.gametypeId")
700 # process self.detailFilters (a list of tuples)
702 #self.detailFilters = [('h.seats', 5, 6)] # for debug
703 if self
.detailFilters
:
704 for f
in self
.detailFilters
:
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
:
712 for filter in self
.cardsFilters
:
713 cardstests
.append(filter)
714 cardstests
= ''.join(('and (', ' or '.join(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 ')
722 query
= query
.replace("<signed>", '')
725 query
= query
.replace("<datestest>", " between '" + dates
[0] + "' and '" + dates
[1] + "'")
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
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
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)
752 label
= gtk
.Label(_("Hand Filters:"))
758 hbox
= gtk
.HBox(False, 0)
759 handbox
.pack_start(hbox
, False, False, 0)
763 for htest
in self
.handtests
:
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]]:
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)
792 htest
[4:7] = [cb
,sb1
,sb2
]
794 label
= gtk
.Label(_('Restrict to hand types:'))
797 for ctest
in self
.cardstests
:
799 cb
= gtk
.CheckButton()
800 if ctest
[0] in self
.cardsFilters
:
802 label
= gtk
.Label(ctest
[1])
803 hbox
.pack_start(cb
, expand
=False, padding
=3)
804 hbox
.pack_start(label
, expand
=True, padding
=3)
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()