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,
142 self
.filters
= Filters
.Filters(self
.db
, self
.conf
, self
.sql
, display
= filters_display
)
143 self
.filters
.registerButton1Name(_("_Filters"))
144 self
.filters
.registerButton1Callback(self
.showDetailFilter
)
145 self
.filters
.registerButton2Name(_("_Refresh Stats"))
146 self
.filters
.registerButton2Callback(self
.refreshStats
)
148 # ToDo: store in config
149 # ToDo: create popup to adjust column config
150 # columns to display, keys match column name returned by sql, values in tuple are:
151 # is column displayed(summary then position), column heading, xalignment, formatting, celltype
152 self
.columns
= self
.conf
.get_gui_cash_stat_params()
154 # Detail filters: This holds the data used in the popup window, extra values are
155 # added at the end of these lists during processing
156 # sql test, screen description, min, max
157 self
.handtests
= [ # already in filter class : ['h.seats', 'Number of Players', 2, 10]
158 ['h.maxSeats', 'Size of Table', 2, 10]
159 ,['h.playersVpi', 'Players who VPI', 0, 10]
160 ,['h.playersAtStreet1', 'Players at Flop', 0, 10]
161 ,['h.playersAtStreet2', 'Players at Turn', 0, 10]
162 ,['h.playersAtStreet3', 'Players at River', 0, 10]
163 ,['h.playersAtStreet4', 'Players at Street7', 0, 10]
164 ,['h.playersAtShowdown', 'Players at Showdown', 0, 10]
165 ,['h.street0Raises', 'Bets to See Flop', 0, 5]
166 ,['h.street1Raises', 'Bets to See Turn', 0, 5]
167 ,['h.street2Raises', 'Bets to See River', 0, 5]
168 ,['h.street3Raises', 'Bets to See Street7', 0, 5]
169 ,['h.street4Raises', 'Bets to See Showdown', 0, 5]
173 [Card
.DATABASE_FILTERS
['pair'], _('Pocket pairs')],
174 [Card
.DATABASE_FILTERS
['suited'], _('Suited')],
175 [Card
.DATABASE_FILTERS
['suited_connectors'], _('Suited connectors')],
176 [Card
.DATABASE_FILTERS
['offsuit'], _('Offsuit')],
177 [Card
.DATABASE_FILTERS
['offsuit_connectors'], _('Offsuit connectors')],
179 self
.stats_frame
= None
180 self
.stats_vbox
= None
181 self
.detailFilters
= [] # the data used to enhance the sql select
182 self
.cardsFilters
= []
184 #self.main_hbox = gtk.HBox(False, 0)
185 #self.main_hbox.show()
186 self
.main_hbox
= gtk
.HPaned()
188 self
.stats_frame
= gtk
.Frame()
189 self
.stats_frame
.show()
191 self
.stats_vbox
= gtk
.VPaned()
192 self
.stats_vbox
.show()
193 self
.stats_frame
.add(self
.stats_vbox
)
194 self
.top_pane_height
= 0
195 self
.height_inc
= None
196 # self.fillStatsFrame(self.stats_vbox)
198 #self.main_hbox.pack_start(self.filters.get_vbox())
199 #self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
200 self
.main_hbox
.pack1(self
.filters
.get_vbox())
201 self
.main_hbox
.pack2(self
.stats_frame
)
202 self
.main_hbox
.show()
204 # make sure Hand column is not displayed
205 [x
for x
in self
.columns
if x
[0] == 'hand'][0][colshowsumm
] = False
206 [x
for x
in self
.columns
if x
[0] == 'hand'][0][colshowposn
] = False
207 # if rfi and steal both on for summaries, turn rfi off
208 if ( [x
for x
in self
.columns
if x
[0] == 'rfi'][0][colshowsumm
]
209 and [x
for x
in self
.columns
if x
[0] == 'steals'][0][colshowsumm
]):
210 [x
for x
in self
.columns
if x
[0] == 'rfi'][0][colshowsumm
] = False
211 # if rfi and steal both on for position breakdowns, turn steals off:
212 if ( [x
for x
in self
.columns
if x
[0] == 'rfi'][0][colshowposn
]
213 and [x
for x
in self
.columns
if x
[0] == 'steals'][0][colshowposn
]):
214 [x
for x
in self
.columns
if x
[0] == 'steals'][0][colshowposn
] = False
220 """returns the vbox of this thread"""
221 return self
.main_hbox
224 def refreshStats(self
, widget
, data
):
225 #self.last_pos = self.stats_vbox.get_position()
226 self
.height_inc
= None
229 # old_len = len(self.liststore[0])
230 try: self
.stats_vbox
.destroy()
231 except AttributeError: pass
234 self
.stats_vbox
= gtk
.VPaned()
235 self
.stats_vbox
.show()
236 self
.stats_frame
.add(self
.stats_vbox
)
237 self
.fillStatsFrame(self
.stats_vbox
)
239 # set height of top pane
240 # (tried 2 ways, guesstimate using ratio of old to new number of rows and sum of
244 #new_len = len(self.liststore[0])
245 #print "setting to", self.top_pane_height + self.height_inc
246 self
.stats_vbox
.set_position(self
.top_pane_height
+ self
.height_inc
)
247 #if self.last_pos > 0:
248 # if old_len > 0 and new_len > 0 and new_len <= 10:
249 # self.stats_vbox.set_position(self.last_pos * (new_len+1.9)/(old_len+1.9))
251 # self.stats_vbox.set_position(self.last_pos)
252 #end def refreshStats
254 def fillStatsFrame(self
, vbox
):
255 sites
= self
.filters
.getSites()
256 heroes
= self
.filters
.getHeroes()
257 siteids
= self
.filters
.getSiteIds()
258 limits
= self
.filters
.getLimits()
259 type = self
.filters
.getType()
260 seats
= self
.filters
.getSeats()
261 groups
= self
.filters
.getGroups()
262 dates
= self
.filters
.getDates()
263 games
= self
.filters
.getGames()
267 # Which sites are selected?
269 if sites
[site
] == True:
270 sitenos
.append(siteids
[site
])
271 _hname
= Charset
.to_utf8(heroes
[site
])
272 result
= self
.db
.get_player_id(self
.conf
, site
, _hname
)
273 if result
is not None:
274 playerids
.append(int(result
))
277 #Should probably pop up here.
278 print _("No sites selected - defaulting to PokerStars")
281 print _("No player ids found")
284 print _("No limits found")
287 self
.createStatsTable(vbox
, playerids
, sitenos
, limits
, type, seats
, groups
, dates
, games
)
288 #end def fillStatsFrame
290 def createStatsTable(self
, vbox
, playerids
, sitenos
, limits
, type, seats
, groups
, dates
, games
):
294 # Scrolled window for summary table
295 swin
= gtk
.ScrolledWindow(hadjustment
=None, vadjustment
=None)
296 swin
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
297 vbox
.pack1(swin
) #, resize=True) don't use resize, self.height_inc relies on initial
298 # height of pane being correct for one row
300 # Display summary table at top of page
301 # 3rd parameter passes extra flags, currently includes:
302 # holecards - whether to display card breakdown (True/False)
303 # numhands - min number hands required when displaying all players
304 # gridnum - index for grid data structures
305 flags
= [False, self
.filters
.getNumHands(), 0]
306 self
.addGrid(swin
, 'playerDetailedStats', flags
, playerids
307 ,sitenos
, limits
, type, seats
, groups
, dates
, games
)
310 if 'allplayers' in groups
and groups
['allplayers']:
311 # can't currently do this combination so skip detailed table
316 vbox2
= gtk
.VBox(False, 0)
317 heading
= gtk
.Label(self
.filterText
['handhead'])
319 vbox2
.pack_start(heading
, expand
=False, padding
=3)
321 # Scrolled window for detailed table (display by hand)
322 swin2
= gtk
.ScrolledWindow(hadjustment
=None, vadjustment
=None)
323 swin2
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
325 vbox2
.pack_start(swin2
, expand
=True, padding
=3)
332 self
.addGrid(swin2
, 'playerDetailedStats', flags
, playerids
333 ,sitenos
, limits
, type, seats
, groups
, dates
, games
)
335 if self
.height_inc
is None:
337 # need this to check whether scrollbar is visible:
338 while gtk
.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
339 gtk
.main_iteration(False)
340 hs
= swin
.get_hscrollbar()
342 #print "hs vis", hs.get_property('visible'), hs.get_property('visible').__class__
343 if hs
.get_property('visible'):
344 self
.height_inc
= hs
.size_request()[1] + swin
.style_get_property('scrollbar-spacing')
345 #print "hh set to", self.height_inc
346 self
.stats_vbox
.set_position(self
.top_pane_height
+ self
.height_inc
)
349 print (_("Stats page displayed in %4.2f seconds") % (time() - startTime
))
350 #end def createStatsTable
352 def reset_style_render_func(self
, treeviewcolumn
, cell
, model
, iter):
353 cell
.set_property('foreground', None)
354 #end def reset_style_render_func
356 def ledger_style_render_func(self
, tvcol
, cell
, model
, iter):
357 str = cell
.get_property('text')
359 str = str.replace("-", "")
361 cell
.set_property('text', str)
362 cell
.set_property('foreground', 'red')
364 cell
.set_property('foreground', 'darkgreen')
368 def sortnums(self
, model
, iter1
, iter2
, nums
):
372 a
= self
.liststore
[grid
].get_value(iter1
, n
)
373 b
= self
.liststore
[grid
].get_value(iter2
, n
)
374 if 'f' in self
.cols_to_show
[n
][4]:
379 if n
== 0 and grid
== 1: #make sure it only works on the starting hands
380 a1
,a2
,a3
= ranks
[a
[0]], ranks
[a
[1]], (a
+'o')[2]
381 b1
,b2
,b3
= ranks
[b
[0]], ranks
[b
[1]], (b
+'o')[2]
382 if a1
> b1
or ( a1
== b1
and (a2
> b2
or (a2
== b2
and a3
> b3
) ) ):
393 #print "n =", n, "iter1[n] =", self.liststore[grid].get_value(iter1,n), "iter2[n] =", self.liststore[grid].get_value(iter2,n), "ret =", ret
395 err
= traceback
.extract_tb(sys
.exc_info()[2])
396 print _("***sortnums error: ") + str(sys
.exc_info()[1])
397 print "\n".join( [e
[0]+':'+str(e
[1])+" "+e
[2] for e
in err
] )
401 def sortcols(self
, col
, nums
):
403 #This doesn't actually work yet - clicking heading in top section sorts bottom section :-(
405 if not col
.get_sort_indicator() or col
.get_sort_order() == gtk
.SORT_ASCENDING
:
406 col
.set_sort_order(gtk
.SORT_DESCENDING
)
408 col
.set_sort_order(gtk
.SORT_ASCENDING
)
409 self
.liststore
[grid
].set_sort_column_id(n
, col
.get_sort_order())
410 self
.liststore
[grid
].set_sort_func(n
, self
.sortnums
, (n
,grid
))
411 for i
in xrange(len(self
.listcols
[grid
])):
412 self
.listcols
[grid
][i
].set_sort_indicator(False)
413 self
.listcols
[grid
][n
].set_sort_indicator(True)
414 # use this listcols[col].set_sort_indicator(True)
415 # to turn indicator off for other cols
417 err
= traceback
.extract_tb(sys
.exc_info()[2])
418 print _("***sortcols error: ") + str(sys
.exc_info()[1])
419 print "\n".join( [e
[0]+':'+str(e
[1])+" "+e
[2] for e
in err
] )
423 def addGrid(self
, vbox
, query
, flags
, playerids
, sitenos
, limits
, type, seats
, groups
, dates
, games
):
427 if not flags
: holecards
,grid
= False,0
428 else: holecards
,grid
= flags
[0],flags
[2]
430 tmp
= self
.sql
.query
[query
]
431 tmp
= self
.refineQuery(tmp
, flags
, playerids
, sitenos
, limits
, type, seats
, groups
, dates
, games
)
432 #print "DEBUG: query: %s" % tmp
433 self
.cursor
.execute(tmp
)
434 result
= self
.cursor
.fetchall()
435 colnames
= [desc
[0].lower() for desc
in self
.cursor
.description
]
437 # pre-fetch some constant values:
438 colshow
= colshowsumm
439 if groups
['posn']: colshow
= colshowposn
440 self
.cols_to_show
= [x
for x
in self
.columns
if x
[colshow
]]
441 hgametypeid_idx
= colnames
.index('hgametypeid')
443 assert len(self
.liststore
) == grid
, "len(self.liststore)="+str(len(self
.liststore
))+" grid-1="+str(grid
)
444 self
.liststore
.append( gtk
.ListStore(*([str] * len(self
.cols_to_show
))) )
445 view
= gtk
.TreeView(model
=self
.liststore
[grid
])
446 view
.set_grid_lines(gtk
.TREE_VIEW_GRID_LINES_BOTH
)
447 #vbox.pack_start(view, expand=False, padding=3)
449 textcell
= gtk
.CellRendererText()
450 textcell50
= gtk
.CellRendererText()
451 textcell50
.set_property('xalign', 0.5)
452 numcell
= gtk
.CellRendererText()
453 numcell
.set_property('xalign', 1.0)
454 assert len(self
.listcols
) == grid
455 self
.listcols
.append( [] )
457 # Create header row eg column: ("game", True, "Game", 0.0, "%s")
458 for col
, column
in enumerate(self
.cols_to_show
):
459 if column
[colalias
] == 'game' and holecards
:
460 s
= [x
for x
in self
.columns
if x
[colalias
] == 'hand'][0][colheading
]
462 s
= column
[colheading
]
463 self
.listcols
[grid
].append(gtk
.TreeViewColumn(s
))
464 view
.append_column(self
.listcols
[grid
][col
])
465 if column
[colformat
] == '%s':
466 if column
[colxalign
] == 0.0:
467 self
.listcols
[grid
][col
].pack_start(textcell
, expand
=True)
468 self
.listcols
[grid
][col
].add_attribute(textcell
, 'text', col
)
471 self
.listcols
[grid
][col
].pack_start(textcell50
, expand
=True)
472 self
.listcols
[grid
][col
].add_attribute(textcell50
, 'text', col
)
473 cellrend
= textcell50
474 self
.listcols
[grid
][col
].set_expand(True)
476 self
.listcols
[grid
][col
].pack_start(numcell
, expand
=True)
477 self
.listcols
[grid
][col
].add_attribute(numcell
, 'text', col
)
478 self
.listcols
[grid
][col
].set_expand(True)
480 #self.listcols[grid][col].set_alignment(column[colxalign]) # no effect?
481 self
.listcols
[grid
][col
].set_clickable(True)
482 self
.listcols
[grid
][col
].connect("clicked", self
.sortcols
, (col
,grid
))
484 self
.listcols
[grid
][col
].set_sort_order(gtk
.SORT_DESCENDING
)
485 self
.listcols
[grid
][col
].set_sort_indicator(True)
486 if column
[coltype
] == 'cash':
487 self
.listcols
[grid
][col
].set_cell_data_func(numcell
, self
.ledger_style_render_func
)
489 self
.listcols
[grid
][col
].set_cell_data_func(cellrend
, self
.reset_style_render_func
)
491 rows
= len(result
) # +1 for title row
495 for col
,column
in enumerate(self
.cols_to_show
):
496 if column
[colalias
] in colnames
:
497 value
= result
[sqlrow
][colnames
.index(column
[colalias
])]
498 if column
[colalias
] == 'plposition':
506 if column
[colalias
] == 'game':
508 value
= Card
.decodeStartHandValue(result
[sqlrow
][colnames
.index('category')], result
[sqlrow
][hgametypeid_idx
] )
510 minbb
= result
[sqlrow
][colnames
.index('minbigblind')]
511 maxbb
= result
[sqlrow
][colnames
.index('maxbigblind')]
512 value
= result
[sqlrow
][colnames
.index('limittype')] + ' ' \
513 + result
[sqlrow
][colnames
.index('category')].title() + ' ' \
514 + result
[sqlrow
][colnames
.index('name')] + ' $'
515 if 100 * int(minbb
/100.0) != minbb
:
516 value
+= '%.2f' % (minbb
/100.0)
518 value
+= '%.0f' % (minbb
/100.0)
520 if 100 * int(maxbb
/100.0) != maxbb
:
521 value
+= ' - $' + '%.2f' % (maxbb
/100.0)
523 value
+= ' - $' + '%.0f' % (maxbb
/100.0)
526 if value
!= None and value
!= -999:
527 treerow
.append(column
[colformat
] % value
)
530 iter = self
.liststore
[grid
].append(treerow
)
534 tips
= DemoTips(column
[colformat
])
539 if len(self
.liststore
) == 1:
540 #print "view hieght is ", view.get_allocation().height, view.size_request(), view.get_visible_rect().height, view.get_vadjustment().get_value()
541 self
.top_pane_height
= view
.size_request()[1]
542 #print "saved ", self.top_pane_height
545 def refineQuery(self
, query
, flags
, playerids
, sitenos
, limits
, type, seats
, groups
, dates
, games
):
553 colshow
= colshowsumm
554 if groups
['posn']: colshow
= colshowposn
556 if 'allplayers' in groups
and groups
['allplayers']:
557 nametest
= "(hp.playerId)"
558 if holecards
or groups
['posn']:
559 pname
= "'all players'"
560 # set flag in self.columns to not show player name column
561 [x
for x
in self
.columns
if x
[0] == 'pname'][0][colshow
] = False
562 # can't do this yet (re-write doing more maths in python instead of sql?)
567 # set flag in self.columns to show player name column
568 [x
for x
in self
.columns
if x
[0] == 'pname'][0][colshow
] = True
570 having
= ' and count(1) > %d ' % (numhands
,)
573 nametest
= str(tuple(playerids
))
574 nametest
= nametest
.replace("L", "")
575 nametest
= nametest
.replace(",)",")")
579 # set flag in self.columns to not show player name column
580 [x
for x
in self
.columns
if x
[0] == 'pname'][0][colshow
] = False
581 query
= query
.replace("<player_test>", nametest
)
582 query
= query
.replace("<playerName>", pname
)
583 query
= query
.replace("<havingclause>", having
)
587 for m
in self
.filters
.display
.items():
588 if m
[0] == 'Games' and m
[1]:
593 gametest
= str(tuple(q
))
594 gametest
= gametest
.replace("L", "")
595 gametest
= gametest
.replace(",)",")")
596 gametest
= gametest
.replace("u'","'")
597 gametest
= "and gt.category in %s" % gametest
599 gametest
= "and gt.category IS NULL"
600 query
= query
.replace("<game_test>", gametest
)
604 for m
in self
.filters
.display
.items():
605 if m
[0] == 'Sites' and m
[1]:
609 sitetest
= str(tuple(q
))
610 sitetest
= sitetest
.replace("L", "")
611 sitetest
= sitetest
.replace(",)",")")
612 sitetest
= sitetest
.replace("u'","'")
613 sitetest
= "and gt.siteId in %s" % sitetest
615 sitetest
= "and gt.siteId IS NULL"
616 query
= query
.replace("<site_test>", sitetest
)
619 query
= query
.replace('<seats_test>', 'between ' + str(seats
['from']) + ' and ' + str(seats
['to']))
620 if 'show' in seats
and seats
['show']:
621 query
= query
.replace('<groupbyseats>', ',h.seats')
622 query
= query
.replace('<orderbyseats>', ',h.seats')
624 query
= query
.replace('<groupbyseats>', '')
625 query
= query
.replace('<orderbyseats>', '')
627 query
= query
.replace('<seats_test>', 'between 0 and 100')
628 query
= query
.replace('<groupbyseats>', '')
629 query
= query
.replace('<orderbyseats>', '')
631 lims
= [int(x
) for x
in limits
if x
.isdigit()]
632 potlims
= [int(x
[0:-2]) for x
in limits
if len(x
) > 2 and x
[-2:] == 'pl']
633 nolims
= [int(x
[0:-2]) for x
in limits
if len(x
) > 2 and x
[-2:] == 'nl']
634 capnolims
= [int(x
[0:-2]) for x
in limits
if len(x
) > 2 and x
[-2:] == 'cn']
635 bbtest
= "and ( (gt.limitType = 'fl' and gt.bigBlind in "
636 # and ( (limit and bb in()) or (nolimit and bb in ()) )
638 blindtest
= str(tuple(lims
))
639 blindtest
= blindtest
.replace("L", "")
640 blindtest
= blindtest
.replace(",)",")")
641 bbtest
= bbtest
+ blindtest
+ ' ) '
643 bbtest
= bbtest
+ '(-1) ) '
644 bbtest
= bbtest
+ " or (gt.limitType = 'pl' and gt.bigBlind in "
646 blindtest
= str(tuple(potlims
))
647 blindtest
= blindtest
.replace("L", "")
648 blindtest
= blindtest
.replace(",)",")")
649 bbtest
= bbtest
+ blindtest
+ ' ) '
651 bbtest
= bbtest
+ '(-1) ) '
652 bbtest
= bbtest
+ " or (gt.limitType = 'nl' and gt.bigBlind in "
654 blindtest
= str(tuple(nolims
))
655 blindtest
= blindtest
.replace("L", "")
656 blindtest
= blindtest
.replace(",)",")")
657 bbtest
= bbtest
+ blindtest
+ ' ) '
659 bbtest
= bbtest
+ '(-1) ) '
660 bbtest
= bbtest
+ " or (gt.limitType = 'cn' and gt.bigBlind in "
662 blindtest
= str(tuple(capnolims
))
663 blindtest
= blindtest
.replace("L", "")
664 blindtest
= blindtest
.replace(",)",")")
665 bbtest
= bbtest
+ blindtest
+ ' ) )'
667 bbtest
= bbtest
+ '(-1) ) )'
669 bbtest
= bbtest
+ " and gt.type = 'ring' "
671 bbtest
= " and gt.type = 'tour' "
672 query
= query
.replace("<gtbigBlind_test>", bbtest
)
674 if holecards
: # re-use level variables for hole card query
675 query
= query
.replace("<hgametypeId>", "hp.startcards")
676 query
= query
.replace("<orderbyhgametypeId>"
677 , ",case when floor((hp.startcards-1)/13) >= mod((hp.startcards-1),13) then hp.startcards + 0.1 "
678 + " else 13*mod((hp.startcards-1),13) + floor((hp.startcards-1)/13) + 1 "
681 query
= query
.replace("<orderbyhgametypeId>", "")
682 groupLevels
= "show" not in str(limits
)
684 query
= query
.replace("<hgametypeId>", "p.name") # need to use p.name for sqlite posn stats to work
686 query
= query
.replace("<hgametypeId>", "h.gametypeId")
688 # process self.detailFilters (a list of tuples)
690 #self.detailFilters = [('h.seats', 5, 6)] # for debug
691 if self
.detailFilters
:
692 for f
in self
.detailFilters
:
695 flagtest
+= ' and %s between %s and %s ' % (f
[0], str(f
[1]), str(f
[2]))
696 query
= query
.replace("<flagtest>", flagtest
)
697 if self
.cardsFilters
:
700 for filter in self
.cardsFilters
:
701 cardstests
.append(filter)
702 cardstests
= ''.join(('and (', ' or '.join(cardstests
), ')'))
705 query
= query
.replace("<cardstest>", cardstests
)
706 # allow for differences in sql cast() function:
707 if self
.db
.backend
== self
.MYSQL_INNODB
:
708 query
= query
.replace("<signed>", 'signed ')
710 query
= query
.replace("<signed>", '')
713 query
= query
.replace("<datestest>", " between '" + dates
[0] + "' and '" + dates
[1] + "'")
717 #query = query.replace("<position>", "case hp.position when '0' then 'Btn' else hp.position end")
718 query
= query
.replace("<position>", "hp.position")
719 # set flag in self.columns to show posn column
720 [x
for x
in self
.columns
if x
[0] == 'plposition'][0][colshow
] = True
722 query
= query
.replace("<position>", "gt.base")
723 # unset flag in self.columns to hide posn column
724 [x
for x
in self
.columns
if x
[0] == 'plposition'][0][colshow
] = False
726 #print "query =\n", query
730 def showDetailFilter(self
, widget
, data
):
731 detailDialog
= gtk
.Dialog(title
=_("Detailed Filters"), parent
=self
.main_window
732 ,flags
=gtk
.DIALOG_MODAL | gtk
.DIALOG_DESTROY_WITH_PARENT
733 ,buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_REJECT
,
734 gtk
.STOCK_OK
, gtk
.RESPONSE_ACCEPT
))
736 handbox
= gtk
.VBox(True, 0)
737 detailDialog
.vbox
.pack_start(handbox
, False, False, 0)
740 label
= gtk
.Label(_("Hand Filters:"))
746 hbox
= gtk
.HBox(False, 0)
747 handbox
.pack_start(hbox
, False, False, 0)
751 for htest
in self
.handtests
:
753 cb
= gtk
.CheckButton()
754 lbl_from
= gtk
.Label(htest
[1])
755 lbl_from
.set_alignment(xalign
=0.0, yalign
=0.5)
756 lbl_tween
= gtk
.Label(_('between'))
757 lbl_to
= gtk
.Label(_('and'))
758 adj1
= gtk
.Adjustment(value
=htest
[2], lower
=0, upper
=10, step_incr
=1, page_incr
=1, page_size
=0)
759 sb1
= gtk
.SpinButton(adjustment
=adj1
, climb_rate
=0.0, digits
=0)
760 adj2
= gtk
.Adjustment(value
=htest
[3], lower
=2, upper
=10, step_incr
=1, page_incr
=1, page_size
=0)
761 sb2
= gtk
.SpinButton(adjustment
=adj2
, climb_rate
=0.0, digits
=0)
763 for df
in [x
for x
in self
.detailFilters
if x
[0] == htest
[0]]:
766 hbox
.pack_start(cb
, expand
=False, padding
=3)
767 hbox
.pack_start(lbl_from
, expand
=True, padding
=3)
768 hbox
.pack_start(lbl_tween
, expand
=False, padding
=3)
769 hbox
.pack_start(sb1
, False, False, 0)
770 hbox
.pack_start(lbl_to
, expand
=False, padding
=3)
771 hbox
.pack_start(sb2
, False, False, 0)
780 htest
[4:7] = [cb
,sb1
,sb2
]
782 label
= gtk
.Label(_('Restrict to hand types:'))
785 for ctest
in self
.cardstests
:
787 cb
= gtk
.CheckButton()
788 if ctest
[0] in self
.cardsFilters
:
790 label
= gtk
.Label(ctest
[1])
791 hbox
.pack_start(cb
, expand
=False, padding
=3)
792 hbox
.pack_start(label
, expand
=True, padding
=3)
796 response
= detailDialog
.run()
798 if response
== gtk
.RESPONSE_ACCEPT
:
799 self
.detailFilters
= []
800 for ht
in self
.handtests
:
801 if ht
[4].get_active():
802 self
.detailFilters
.append( (ht
[0], ht
[5].get_value_as_int(), ht
[6].get_value_as_int()) )
803 ht
[2],ht
[3] = ht
[5].get_value_as_int(), ht
[6].get_value_as_int()
804 print "detailFilters =", self
.detailFilters
805 self
.cardsFilters
= []
806 for ct
in self
.cardstests
:
807 if ct
[2].get_active():
808 self
.cardsFilters
.append(ct
[0])
809 print "cardsFilters =", self
.cardsFilters
810 self
.refreshStats(None, None)
812 detailDialog
.destroy()