Coverage for GuiTourneyPlayerStats.py: 0%
197 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-28 16:41 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-28 16:41 +0000
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
4#Copyright 2010-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.
8#
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.
13#
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.
18from __future__ import print_function
21#import L10n
22#_ = L10n.get_translation()
24from time import time, strftime
26from PyQt5.QtCore import Qt
27from PyQt5.QtGui import (QStandardItem, QStandardItemModel)
28from PyQt5.QtWidgets import (QFrame, QScrollArea, QSplitter,
29 QTableView, QVBoxLayout)
31import Charset
32import Filters
34colalias,colshow,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5
36class GuiTourneyPlayerStats(QSplitter):
37 def __init__(self, config, db, sql, mainwin, debug=True):
38 QSplitter.__init__(self, mainwin)
39 self.conf = config
40 self.db = db
41 self.cursor = self.db.cursor
42 self.sql = sql
43 self.main_window = mainwin
44 self.debug = debug
46 self.liststore = [] # QStandardItemModel[] stores the contents of the grids
47 self.listcols = []
49 filters_display = { "Heroes" : True,
50 "Sites" : True,
51 #"Games" : True,
52 #"Limits" : True,
53 #"LimitSep" : True,
54 #"LimitType" : True,
55 #"Type" : True,
56 "Seats" : True,
57 #"SeatSep" : True,
58 "Dates" : True,
59 #"Groups" : True,
60 #"GroupsAll" : True,
61 #"Button1" : True,
62 "Button2" : True}
64 self.stats_frame = None
65 self.stats_vbox = None
66 self.detailFilters = [] # the data used to enhance the sql select
68 self.filters = Filters.Filters(self.db, display = filters_display)
69 #self.filters.registerButton1Name(("_Filters"))
70 #self.filters.registerButton1Callback(self.showDetailFilter)
71 self.filters.registerButton2Name(("_Refresh Stats"))
72 self.filters.registerButton2Callback(self.refreshStats)
74 scroll = QScrollArea()
75 scroll.setWidget(self.filters)
77 # ToDo: store in config
78 # ToDo: create popup to adjust column config
79 # columns to display, keys match column name returned by sql, values in tuple are:
80 # is column displayed, column heading, xalignment, formatting, celltype
81 self.columns = [ ["siteName", True, ("Site"), 0.0, "%s", "str"]
82 , ["category", True, ("Cat."), 0.0, "%s", "str"]
83 , ["limitType", True, ("Limit"), 0.0, "%s", "str"]
84 , ["currency", True, ("Curr."), 0.0, "%s", "str"]
85 , ["buyIn", True, ("BuyIn"), 1.0, "%3.2f", "str"]
86 , ["fee", True, ("Fee"), 1.0, "%3.2f", "str"]
87 , ["maxSeats", True, ("Seats"), 0.0, "%s", "str"]
88 , ["knockout", True, ("KO") ,0.0, "%s", "str"]
89 , ["reEntry", True, ("ReEntry"), 0.0, "%s", "str"]
90 , ["playerName", False, ("Name"), 0.0, "%s", "str"] # true not allowed for this line (set in code)
91 , ["tourneyCount", True, ("#"), 1.0, "%1.0f", "str"]
92 , ["itm", True, ("ITM%"), 1.0, "%3.2f", "str"]
93 , ["_1st", False, ("1st"), 1.0, "%1.0f", "str"]
94 , ["_2nd", True, ("2nd"), 1.0, "%1.0f", "str"]
95 , ["_3rd", True, ("3rd"), 1.0, "%1.0f", "str"]
96 , ["unknownRank", True, ("Rank?"), 1.0, "%1.0f", "str"]
97 , ["spent", True, ("Spent"), 1.0, "%3.2f", "str"]
98 , ["won", True, ("Won"), 1.0, "%3.2f", "str"]
99 , ["net", True, ("Net"), 1.0, "%3.2f", "str"]
100 , ["roi", True, ("ROI%"), 1.0, "%3.2f", "str"]
101 , ["profitPerTourney", True,("$/Tour"), 1.0, "%3.2f", "str"]]
103 self.stats_frame = QFrame()
104 self.stats_frame.setLayout(QVBoxLayout())
106 self.stats_vbox = QSplitter(Qt.Vertical)
107 self.stats_frame.layout().addWidget(self.stats_vbox)
108 # self.fillStatsFrame(self.stats_vbox)
110 #self.main_hbox.pack_start(self.filters.get_vbox())
111 #self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
112 self.addWidget(scroll)
113 self.addWidget(self.stats_frame)
114 self.setStretchFactor(0, 0)
115 self.setStretchFactor(1, 1)
117 def addGrid(self, vbox, query, numTourneys, tourneyTypes, playerids, sitenos, seats):
118 sqlrow = 0
119 grid=numTourneys #TODO: should this be numTourneyTypes?
121 query = self.sql.query[query]
122 query = self.refineQuery(query, numTourneys, tourneyTypes, playerids, sitenos, seats)
123 self.cursor.execute(query)
124 result = self.cursor.fetchall()
125 colnames = [desc[0] for desc in self.cursor.description]
127 # pre-fetch some constant values:
128 #self.cols_to_show = [x for x in self.columns if x[colshow]]
129 #htourneytypeid_idx = colnames.index('tourneyTypeId')
131 assert len(self.liststore) == grid, "len(self.liststore)="+str(len(self.liststore))+" grid-1="+str(grid)
132 view = QTableView()
133 self.liststore.append(QStandardItemModel(0, len(self.columns), view))
134 view.setModel(self.liststore[grid])
135 view.verticalHeader().hide()
136 vbox.addWidget(view)
137 assert len(self.listcols) == grid
138 self.listcols.append( [] )
140 # Create header row eg column: ("game", True, "Game", 0.0, "%s")
141 for col, column in enumerate(self.columns):
142 if column[colalias] == 'game' and holecards:
143 s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading]
144 else:
145 s = column[colheading]
146 self.listcols[grid].append(s)
147 self.liststore[grid].setHorizontalHeaderLabels(self.listcols[grid])
149 rows = len(result) # +1 for title row
151 while sqlrow < rows:
152 treerow = []
153 for col,column in enumerate(self.columns):
154 if column[colalias] in colnames:
155 value = result[sqlrow][colnames.index(column[colalias])]
156 else:
157 value = 111
158 if column[colalias] == 'siteName':
159 if result[sqlrow][colnames.index('speed')] != 'Normal':
160 if (result[sqlrow][colnames.index('speed')] == 'Hyper'
161 and result[sqlrow][colnames.index('siteName')] ==
162 'Full Tilt Poker'):
163 value = value + ' ' + 'Super Turbo'
164 else:
165 value = value + ' ' + result[sqlrow][colnames.index('speed')]
166 if column[colalias] == 'knockout' or column[colalias] == 'reEntry':
167 if result[sqlrow][colnames.index(column[colalias])] == 1:
168 value = 'Yes'
169 else:
170 value = 'No'
171 item = QStandardItem('')
172 if value != None and value != -999:
173 item = QStandardItem(column[colformat] % value)
174 item.setEditable(False)
175 item.setTextAlignment(Qt.AlignRight)
176 treerow.append(item)
177 self.liststore[grid].appendRow(treerow)
178 sqlrow += 1
180 view.resizeColumnsToContents()
181 view.setSortingEnabled(True)
183 def createStatsTable(self, vbox, tourneyTypes, playerids, sitenos, seats):
184 startTime = time()
186 numTourneys = self.filters.getNumTourneys()
187 self.addGrid(vbox, 'tourneyPlayerDetailedStats', numTourneys, tourneyTypes, playerids, sitenos, seats)
189 print(("Stats page displayed in %4.2f seconds") % (time() - startTime))
191 def fillStatsFrame(self, vbox):
192 tourneyTypes = self.filters.getTourneyTypes()
193 #tourneys = self.tourneys.getTourneys()
194 sites = self.filters.getSites()
195 heroes = self.filters.getHeroes()
196 siteids = self.filters.getSiteIds()
197 seats = self.filters.getSeats()
198 dates = self.filters.getDates()
199 sitenos = []
200 playerids = []
202 # Which sites are selected?
203 for site in sites:
204 sitenos.append(siteids[site])
205 _hname = Charset.to_utf8(heroes[site])
206 result = self.db.get_player_id(self.conf, site, _hname)
207 if result is not None:
208 playerids.append(int(result))
210 if not sitenos:
211 #Should probably pop up here.
212 print(("No sites selected - defaulting to PokerStars"))
213 sitenos = [2]
214 if not playerids:
215 print(("No player ids found"))
216 return
218 self.createStatsTable(vbox, tourneyTypes, playerids, sitenos, seats)
220 def refineQuery(self, query, numTourneys, tourneyTypes, playerids, sitenos, seats):
221 having = ''
223 #print "start of refinequery, playerids:",playerids
224 if playerids:
225 nametest = str(tuple(playerids))
226 nametest = nametest.replace("L", "")
227 nametest = nametest.replace(",)",")")
228 else:
229 nametest = "1 = 2"
230 #print "refinequery, nametest after initial creation:",nametest
231 pname = "p.name"
232 # set flag in self.columns to not show player name column
233 #[x for x in self.columns if x[0] == 'pname'][0][1] = False #TODO: fix and reactivate
235 query = query.replace("<nametest>", nametest)
236 query = query.replace("<playerName>", pname)
237 query = query.replace("<havingclause>", having)
239 sitetest = ""
240 q = []
241 for m in list(self.filters.display.items()):
242 if m[0] == 'Sites' and m[1]:
243 for n in sitenos:
244 q.append(n)
245 if len(q) > 0:
246 sitetest = str(tuple(q))
247 sitetest = sitetest.replace("L", "")
248 sitetest = sitetest.replace(",)",")")
249 sitetest = sitetest.replace("u'","'")
250 sitetest = "and tt.siteId in %s" % sitetest#[1:-1]
251 else:
252 sitetest = "and tt.siteId IS NULL"
253 #print "refinequery, sitetest before its use for replacement:",sitetest
254 query = query.replace("<sitetest>", sitetest)
256 if seats:
257 query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
258 if False: #'show' in seats and seats['show']: should be 'show' in groups but we don't even display the groups filter
259 query = query.replace('<groupbyseats>', ',h.seats')
260 query = query.replace('<orderbyseats>', ',h.seats')
261 else:
262 query = query.replace('<groupbyseats>', '')
263 query = query.replace('<orderbyseats>', '')
264 else:
265 query = query.replace('<seats_test>', 'between 0 and 100')
266 query = query.replace('<groupbyseats>', '')
267 query = query.replace('<orderbyseats>', '')
269 #bbtest = self.filters.get_limits_where_clause(limits)
271 #query = query.replace("<gtbigBlind_test>", bbtest)
273 #query = query.replace("<orderbyhgametypeId>", "")
275 # process self.detailFilters (a list of tuples)
276 flagtest = ''
277 #self.detailFilters = [('h.seats', 5, 6)] # for debug
278 if self.detailFilters:
279 for f in self.detailFilters:
280 if len(f) == 3:
281 # X between Y and Z
282 flagtest += ' and %s between %s and %s ' % (f[0], str(f[1]), str(f[2]))
283 query = query.replace("<flagtest>", flagtest)
285 # allow for differences in sql cast() function:
286 if self.db.backend == self.db.MYSQL_INNODB:
287 query = query.replace("<signed>", 'signed ')
288 else:
289 query = query.replace("<signed>", '')
291 # Filter on dates
292 start_date, end_date = self.filters.getDates()
293 query = query.replace("<startdate_test>", start_date)
294 query = query.replace("<enddate_test>", end_date)
296 return(query)
298 def refreshStats(self, widget):
299# self.last_pos = self.stats_vbox.get_position()
300 self.stats_frame.layout().removeWidget(self.stats_vbox)
301 self.stats_vbox.setParent(None)
302 self.liststore = []
303 self.listcols = []
304 #self.stats_vbox = gtk.VBox(False, 0)
305 self.stats_vbox = QSplitter(Qt.Vertical)
306 self.stats_frame.layout().addWidget(self.stats_vbox)
307 self.fillStatsFrame(self.stats_vbox)
308# if self.last_pos > 0:
309# self.stats_vbox.set_position(self.last_pos)
311 def reset_style_render_func(self, treeviewcolumn, cell, model, iter):
312 cell.set_property('foreground', None)
314 def sortCols(self, col, nums):
315 #This doesn't actually work yet - clicking heading in top section sorts bottom section :-(
316 (n, grid) = nums
317 if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
318 col.set_sort_order(gtk.SORT_DESCENDING)
319 else:
320 col.set_sort_order(gtk.SORT_ASCENDING)
321 self.liststore[grid].set_sort_column_id(n, col.get_sort_order())
322 self.liststore[grid].set_sort_func(n, self.sortnums, (n,grid))
323 for i in range(len(self.listcols[grid])):
324 self.listcols[grid][i].set_sort_indicator(False)
325 self.listcols[grid][n].set_sort_indicator(True)
326 # use this listcols[col].set_sort_indicator(True)
327 # to turn indicator off for other cols
329if __name__ == "__main__":
330 import Configuration
331 config = Configuration.Config()
333 settings = {}
335 settings.update(config.get_db_parameters())
336 settings.update(config.get_import_parameters())
337 settings.update(config.get_default_paths())
339 from PyQt5.QtWidgets import QApplication, QMainWindow
340 app = QApplication([])
341 import SQL
342 sql = SQL.Sql(db_server=settings['db-server'])
343 import Database
344 db= Database.Database(config, sql)
345 main_window = QMainWindow()
346 i = GuiTourneyPlayerStats(config, db, sql, main_window)
347 main_window.setCentralWidget(i)
348 main_window.show()
349 main_window.resize(1400, 800)
350 app.exec_()