Coverage for GuiTourneyPlayerStats.py: 0%

197 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-27 18:50 +0000

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3 

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. 

17 

18from __future__ import print_function 

19 

20 

21#import L10n 

22#_ = L10n.get_translation() 

23 

24from time import time, strftime 

25 

26from PyQt5.QtCore import Qt 

27from PyQt5.QtGui import (QStandardItem, QStandardItemModel) 

28from PyQt5.QtWidgets import (QFrame, QScrollArea, QSplitter, 

29 QTableView, QVBoxLayout) 

30 

31import Charset 

32import Filters 

33 

34colalias,colshow,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5 

35 

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 

45 

46 self.liststore = [] # QStandardItemModel[] stores the contents of the grids 

47 self.listcols = [] 

48 

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} 

63 

64 self.stats_frame = None 

65 self.stats_vbox = None 

66 self.detailFilters = [] # the data used to enhance the sql select 

67 

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) 

73 

74 scroll = QScrollArea() 

75 scroll.setWidget(self.filters) 

76 

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"]] 

102 

103 self.stats_frame = QFrame() 

104 self.stats_frame.setLayout(QVBoxLayout()) 

105 

106 self.stats_vbox = QSplitter(Qt.Vertical) 

107 self.stats_frame.layout().addWidget(self.stats_vbox) 

108 # self.fillStatsFrame(self.stats_vbox) 

109 

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) 

116 

117 def addGrid(self, vbox, query, numTourneys, tourneyTypes, playerids, sitenos, seats): 

118 sqlrow = 0 

119 grid=numTourneys #TODO: should this be numTourneyTypes? 

120 

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] 

126 

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') 

130 

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( [] ) 

139 

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]) 

148 

149 rows = len(result) # +1 for title row 

150 

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 

179 

180 view.resizeColumnsToContents() 

181 view.setSortingEnabled(True) 

182 

183 def createStatsTable(self, vbox, tourneyTypes, playerids, sitenos, seats): 

184 startTime = time() 

185 

186 numTourneys = self.filters.getNumTourneys() 

187 self.addGrid(vbox, 'tourneyPlayerDetailedStats', numTourneys, tourneyTypes, playerids, sitenos, seats) 

188 

189 print(("Stats page displayed in %4.2f seconds") % (time() - startTime)) 

190 

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 = [] 

201 

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)) 

209 

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 

217 

218 self.createStatsTable(vbox, tourneyTypes, playerids, sitenos, seats) 

219 

220 def refineQuery(self, query, numTourneys, tourneyTypes, playerids, sitenos, seats): 

221 having = '' 

222 

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 

234 

235 query = query.replace("<nametest>", nametest) 

236 query = query.replace("<playerName>", pname) 

237 query = query.replace("<havingclause>", having) 

238 

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) 

255 

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>', '') 

268 

269 #bbtest = self.filters.get_limits_where_clause(limits) 

270 

271 #query = query.replace("<gtbigBlind_test>", bbtest) 

272 

273 #query = query.replace("<orderbyhgametypeId>", "") 

274 

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) 

284 

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>", '') 

290 

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) 

295 

296 return(query) 

297 

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) 

310 

311 def reset_style_render_func(self, treeviewcolumn, cell, model, iter): 

312 cell.set_property('foreground', None) 

313 

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 

328 

329if __name__ == "__main__": 

330 import Configuration 

331 config = Configuration.Config() 

332 

333 settings = {} 

334 

335 settings.update(config.get_db_parameters()) 

336 settings.update(config.get_import_parameters()) 

337 settings.update(config.get_default_paths()) 

338 

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_()