Coverage for Filters.py: 0%
953 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 18:50 +0000
« 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 -*-
4from __future__ import print_function
5from __future__ import division
6import itertools
7from ast import Pass
9from dataclasses import replace
10from past.utils import old_div
11import pathlib
12import os
13from PyQt5.QtGui import QIcon
14from PyQt5.QtCore import QDate, QDateTime
15from PyQt5.QtWidgets import (QCalendarWidget, QCheckBox, QCompleter,
16 QDateEdit, QDialog, QGridLayout,
17 QGroupBox, QHBoxLayout, QLabel,
18 QLineEdit, QPushButton, QRadioButton,
19 QSpinBox, QVBoxLayout, QWidget, QComboBox)
21from time import gmtime, mktime, strftime, strptime
22from functools import partial
23import logging
25import Configuration
26import Database
27import SQL
28import Charset
29import Card
31if __name__ == "__main__":
32 Configuration.set_logfile("fpdb-log.txt")
33log = logging.getLogger("filter")
35class Filters(QWidget):
36 def __init__(self, db, display={}):
37 super().__init__(None)
38 self.db = db
39 self.cursor = db.cursor
40 self.sql = db.sql
41 self.conf = db.config
42 self.display = display
43 self.heroList = None
44 self.cbSites = {}
45 self.cbGames = {}
46 self.cbLimits = {}
47 self.cbPositions = {}
48 self.cbCurrencies = {}
49 self.cbGraphops = {}
50 self.cbTourney = {}
51 self.cbTourneyCat = {}
52 self.cbTourneyLim = {}
53 self.cbTourneyBuyin = {}
55 self.gameName = {"27_1draw": ("Single Draw 2-7 Lowball"),
56 "27_3draw": ("Triple Draw 2-7 Lowball"),
57 "a5_3draw": ("Triple Draw A-5 Lowball"),
58 "5_studhi": ("5 Card Stud"),
59 "badugi": ("Badugi"),
60 "badacey": ("Badacey"),
61 "badeucey": ("Badeucey"),
62 "drawmaha": ("2-7 Drawmaha"),
63 "a5_1draw": ("A-5 Single Draw"),
64 "27_razz": ("2-7 Razz"),
65 "fivedraw": ("5 Card Draw"),
66 "holdem": ("Hold'em"),
67 "6_holdem": ("Hold'em"),
68 "omahahi": ("Omaha"),
69 "fusion": ("Fusion"),
70 "omahahilo": ("Omaha Hi/Lo"),
71 "razz": ("Razz"),
72 "studhi": ("7 Card Stud"),
73 "studhilo": ("7 Card Stud Hi/Lo"),
74 "5_omahahi": ("5 Card Omaha"),
75 "5_omaha8": ("5 Card Omaha Hi/Lo"),
76 "cour_hi": ("Courchevel"),
77 "cour_hilo": ("Courchevel Hi/Lo"),
78 "2_holdem": ("Double hold'em"),
79 "irish": ("Irish"),
80 "6_omahahi": ("6 Card Omaha")}
82 self.currencyName = {"USD": ("US Dollar"),
83 "EUR": ("Euro"),
84 "T$": ("Tournament Dollar"),
85 "play": ("Play Money")}
87 self.filterText = {'limitsall': ('All'), 'limitsnone': ('None'), 'limitsshow': ('Show Limits'),
88 'gamesall': ('All'), 'gamesnone': ('None'),
89 'positionsall': ('All'), 'positionsnone': ('None'),
90 'currenciesall': ('All'), 'currenciesnone': ('None'),
91 'seatsbetween': ('Between:'), 'seatsand': ('And:'), 'seatsshow': ('Show Number of Players'),
92 'playerstitle': ('Hero:'), 'sitestitle': (('Sites') + ':'), 'gamestitle': (('Games') + ':'), 'tourneytitle': (('Tourney') + ':'), 'tourneycat': (('Category') + ':'),
93 'limitstitle': ('Limits:'), 'positionstitle': ('Positions:'), 'seatstitle': ('Number of Players:'), 'tourneylim': (('Limit Type') + ':'),
94 'groupstitle': ('Grouping:'), 'posnshow': ('Show Position Stats'), 'tourneybuyin': (('Buyin') + ':'),
95 'datestitle': ('Date:'), 'currenciestitle': (('Currencies') + ':'),
96 'groupsall': ('All Players'), 'cardstitle': (('Hole Cards') + ':'),
97 'limitsFL': 'FL', 'limitsNL': 'NL', 'limitsPL': 'PL', 'limitsCN': 'CAP', 'ring': ('Ring'), 'tour': ('Tourney'), 'limitsHP': 'HP'}
99 gen = self.conf.get_general_params()
100 self.day_start = 0
102 if 'day_start' in gen:
103 self.day_start = float(gen['day_start'])
105 self.setLayout(QVBoxLayout())
107 self.callback = {}
109 self.setStyleSheet("QPushButton {padding-left:5;padding-right:5;padding-top:2;padding-bottom:2;}")
110 self.make_filter()
112 def make_filter(self):
113 self.siteid = {}
114 self.cards = {}
115 self.type = None
117 for site in self.conf.get_supported_sites():
118 self.cursor.execute(self.sql.query['getSiteId'], (site,))
119 result = self.db.cursor.fetchall()
120 if len(result) == 1:
121 self.siteid[site] = result[0][0]
122 else:
123 log.debug(("Either 0 or more than one site matched for %s"), site)
125 self.start_date = QDateEdit(QDate(1970, 1, 1))
126 self.end_date = QDateEdit(QDate(2100, 1, 1))
128 self.cbGroups = {}
129 self.phands = None
131 if self.display.get("Heroes", False):
132 self.layout().addWidget(self.create_player_frame())
133 if self.display.get("Sites", False):
134 self.layout().addWidget(self.create_sites_frame())
135 if self.display.get("Games", False):
136 self.layout().addWidget(self.create_games_frame())
137 if self.display.get("Tourney", False):
138 self.layout().addWidget(self.create_tourney_frame())
139 if self.display.get("TourneyCat", False):
140 self.layout().addWidget(self.create_tourney_cat_frame())
141 if self.display.get("TourneyLim", False):
142 self.layout().addWidget(self.create_tourney_lim_frame())
143 if self.display.get("TourneyBuyin", False):
144 self.layout().addWidget(self.create_tourney_buyin_frame())
145 if self.display.get("Currencies", False):
146 self.layout().addWidget(self.create_currencies_frame())
147 if self.display.get("Limits", False):
148 self.layout().addWidget(self.create_limits_frame())
149 if self.display.get("Positions", False):
150 self.layout().addWidget(self.create_positions_frame())
151 if self.display.get("GraphOps", False):
152 self.layout().addWidget(self.create_graph_ops_frame())
153 if self.display.get("Seats", False):
154 self.layout().addWidget(self.create_seats_frame())
155 if self.display.get("Groups", False):
156 self.layout().addWidget(self.create_groups_frame())
157 if self.display.get("Dates", False):
158 self.layout().addWidget(self.create_date_frame())
159 if self.display.get("Cards", False):
160 self.layout().addWidget(self.create_cards_frame())
161 if self.display.get("Button1", False) or self.display.get("Button2", False):
162 self.layout().addWidget(self.create_buttons())
164 self.db.rollback()
165 self.set_default_hero()
167 def set_default_hero(self):
168 if self.heroList and self.heroList.count() > 0:
169 self.heroList.setCurrentIndex(0)
170 self.update_filters_for_hero()
172 def create_player_frame(self):
173 playerFrame = QGroupBox(self.filterText['playerstitle'])
174 self.leHeroes = {}
175 self.fillPlayerFrame(playerFrame, self.display)
176 return playerFrame
178 def create_sites_frame(self):
179 sitesFrame = QGroupBox(self.filterText['sitestitle'])
180 self.cbSites = {}
181 self.fillSitesFrame(sitesFrame)
182 return sitesFrame
184 def create_games_frame(self):
185 gamesFrame = QGroupBox(self.filterText['gamestitle'])
186 self.fillGamesFrame(gamesFrame)
187 return gamesFrame
189 def create_tourney_frame(self):
190 tourneyFrame = QGroupBox(self.filterText['tourneytitle'])
191 self.cbTourney = {}
192 self.fillTourneyTypesFrame(tourneyFrame)
193 return tourneyFrame
195 def create_tourney_cat_frame(self):
196 tourneyCatFrame = QGroupBox(self.filterText['tourneycat'])
197 self.cbTourneyCat = {}
198 self.fillTourneyCatFrame(tourneyCatFrame)
199 return tourneyCatFrame
201 def create_tourney_lim_frame(self):
202 tourneyLimFrame = QGroupBox(self.filterText['tourneylim'])
203 self.cbTourneyLim = {}
204 self.fillTourneyLimFrame(tourneyLimFrame)
205 return tourneyLimFrame
207 def create_tourney_buyin_frame(self):
208 tourneyBuyinFrame = QGroupBox(self.filterText['tourneybuyin'])
209 self.cbTourneyBuyin = {}
210 self.fillTourneyBuyinFrame(tourneyBuyinFrame)
211 return tourneyBuyinFrame
213 def create_currencies_frame(self):
214 currenciesFrame = QGroupBox(self.filterText['currenciestitle'])
215 self.fillCurrenciesFrame(currenciesFrame)
216 return currenciesFrame
218 def create_limits_frame(self):
219 limitsFrame = QGroupBox(self.filterText['limitstitle'])
220 self.fillLimitsFrame(limitsFrame, self.display)
221 return limitsFrame
223 def create_positions_frame(self):
224 positionsFrame = QGroupBox(self.filterText['positionstitle'])
225 self.fillPositionsFrame(positionsFrame, self.display)
226 return positionsFrame
228 def create_graph_ops_frame(self):
229 graphopsFrame = QGroupBox("Graphing Options:")
230 self.cbGraphops = {}
231 self.fillGraphOpsFrame(graphopsFrame)
232 return graphopsFrame
234 def create_seats_frame(self):
235 seatsFrame = QGroupBox(self.filterText['seatstitle'])
236 self.sbSeats = {}
237 self.fillSeatsFrame(seatsFrame)
238 return seatsFrame
240 def create_groups_frame(self):
241 groupsFrame = QGroupBox(self.filterText['groupstitle'])
242 self.fillGroupsFrame(groupsFrame, self.display)
243 return groupsFrame
245 def create_date_frame(self):
246 dateFrame = QGroupBox(self.filterText['datestitle'])
247 self.fillDateFrame(dateFrame)
248 return dateFrame
250 def create_cards_frame(self):
251 cardsFrame = QGroupBox(self.filterText['cardstitle'])
252 self.fillHoleCardsFrame(cardsFrame)
253 return cardsFrame
255 def create_buttons(self):
256 button_frame = QWidget()
257 button_layout = QVBoxLayout(button_frame)
258 if self.display.get("Button1", False):
259 self.Button1 = QPushButton("Unnamed 1")
260 button_layout.addWidget(self.Button1)
261 if self.display.get("Button2", False):
262 self.Button2 = QPushButton("Unnamed 2")
263 button_layout.addWidget(self.Button2)
264 return button_frame
266 def getNumHands(self):
267 return self.phands.value() if self.phands else 0
269 def getNumTourneys(self):
270 return 0
272 def getGraphOps(self):
273 return [g for g in self.cbGraphops if self.cbGraphops[g].isChecked()]
275 def getSites(self):
276 return [s for s in self.cbSites if self.cbSites[s].isChecked() and self.cbSites[s].isEnabled()]
278 def getPositions(self):
279 return [p for p in self.cbPositions if self.cbPositions[p].isChecked() and self.cbPositions[p].isEnabled()]
281 def getTourneyCat(self):
282 return [g for g in self.cbTourneyCat if self.cbTourneyCat[g].isChecked()]
284 def getTourneyLim(self):
285 return [g for g in self.cbTourneyLim if self.cbTourneyLim[g].isChecked()]
287 def getTourneyBuyin(self):
288 return [g for g in self.cbTourneyBuyin if self.cbTourneyBuyin[g].isChecked()]
290 def getTourneyTypes(self):
291 return [g for g in self.cbTourney if self.cbTourney[g].isChecked()]
293 def getGames(self):
294 return [g for g in self.cbGames if self.cbGames[g].isChecked() and self.cbGames[g].isEnabled()]
296 def getCards(self):
297 return self.cards
299 def getCurrencies(self):
300 return [c for c in self.cbCurrencies if self.cbCurrencies[c].isChecked() and self.cbCurrencies[c].isEnabled()]
302 def getSiteIds(self):
303 return self.siteid
305 def getHeroes(self):
306 if selected_text := self.heroList.currentText():
307 hero = selected_text.split(" on ")[0]
308 site = selected_text.split(" on ")[1]
309 return {site: hero}
310 else:
311 return {}
313 def getGraphOps(self):
314 return [g for g in self.cbGraphops if self.cbGraphops[g].isChecked()]
316 def getLimits(self):
317 return [l for l in self.cbLimits if self.cbLimits[l].isChecked() and self.cbLimits[l].isEnabled()]
319 def getType(self):
320 return self.type
322 def getSeats(self):
323 result = {}
324 if 'from' in self.sbSeats:
325 result['from'] = self.sbSeats['from'].value()
326 if 'to' in self.sbSeats:
327 result['to'] = self.sbSeats['to'].value()
328 return result
330 def getGroups(self):
331 return [g for g in self.cbGroups if self.cbGroups[g].isChecked()]
333 def getDates(self):
334 offset = int(self.day_start * 3600)
335 t1 = self.start_date.date()
336 t2 = self.end_date.date()
337 adj_t1 = QDateTime(t1).addSecs(offset)
338 adj_t2 = QDateTime(t2).addSecs(offset + 24 * 3600 - 1)
339 return (adj_t1.toUTC().toString("yyyy-MM-dd HH:mm:ss"), adj_t2.toUTC().toString("yyyy-MM-dd HH:mm:ss"))
341 def fillCardsFrame(self, frame):
342 vbox1 = QVBoxLayout()
343 frame.setLayout(vbox1)
345 grid = QGridLayout()
346 vbox1.addLayout(grid)
347 self.createCardsWidget(grid)
349 hbox = QHBoxLayout()
350 vbox1.addLayout(hbox)
351 self.createCardsControls(hbox)
353 self.cards = {}
354 for i, j in itertools.product(range(2, 15), range(2, 15)):
355 for s in ['s', 'o']:
356 if i >= j:
357 hand = f"{i}{j}{s}"
358 self.cards[hand] = False
360 def registerButton1Name(self, title):
361 self.Button1.setText(title)
363 def registerButton1Callback(self, callback):
364 self.Button1.clicked.connect(callback)
365 self.Button1.setEnabled(True)
366 self.callback['button1'] = callback
368 def registerButton2Name(self, title):
369 self.Button2.setText(title)
371 def registerButton2Callback(self, callback):
372 self.Button2.clicked.connect(callback)
373 self.Button2.setEnabled(True)
374 self.callback['button2'] = callback
376 def registerCardsCallback(self, callback):
377 self.callback['cards'] = callback
379 def __set_tourney_type_select(self, w, tourneyType):
380 self.tourneyTypes[tourneyType] = w.get_active()
381 log.debug("self.tourney_types[%s] set to %s", tourneyType, self.tourneyTypes[tourneyType])
383 def createTourneyTypeLine(self, hbox, tourneyType):
384 cb = QCheckBox(str(tourneyType))
385 cb.clicked.connect(partial(self.__set_tourney_type_select, tourneyType=tourneyType))
386 hbox.addWidget(cb)
387 cb.setChecked(True)
389 def createCardsWidget(self, grid):
390 grid.setSpacing(0)
391 for i in range(0, 13):
392 for j in range(0, 13):
393 abbr = Card.card_map_abbr[j][i]
394 b = QPushButton("")
395 import platform
396 if platform.system() == "Darwin":
397 b.setStyleSheet("QPushButton {border-width:0;margin:6;padding:0;}")
398 else:
399 b.setStyleSheet("QPushButton {border-width:0;margin:0;padding:0;}")
400 b.clicked.connect(partial(self.__toggle_card_select, widget=b, card=abbr))
401 self.cards[abbr] = False
402 self.__toggle_card_select(False, widget=b, card=abbr)
403 grid.addWidget(b, j, i)
405 def createCardsControls(self, hbox):
406 selections = ["All", "Suited", "Off Suit"]
407 for s in selections:
408 cb = QCheckBox(s)
409 cb.clicked.connect(self.__set_cards)
410 hbox.addWidget(cb)
412 def __card_select_bgcolor(self, card, selected):
413 s_on = "red"
414 s_off = "orange"
415 o_on = "white"
416 o_off = "lightgrey"
417 p_on = "blue"
418 p_off = "lightblue"
419 if len(card) == 2:
420 return p_on if selected else p_off
421 if card[2] == 's':
422 return s_on if selected else s_off
423 if card[2] == 'o':
424 return o_on if selected else o_off
426 def __toggle_card_select(self, checkState, widget, card):
427 font = widget.font()
428 font.setPointSize(10)
429 widget.setFont(font)
430 widget.setText(card)
431 self.cards[card] = not self.cards[card]
432 if 'cards' in self.callback:
433 self.callback['cards'](card)
435 def __set_cards(self, checkState):
436 pass
438 def __set_checkboxes(self, checkState, checkBoxes, setState):
439 for checkbox in list(checkBoxes.values()):
440 checkbox.setChecked(setState)
442 def __select_limit(self, checkState, limit):
443 for l, checkbox in list(self.cbLimits.items()):
444 if l.endswith(limit):
445 checkbox.setChecked(True)
447 def fillPlayerFrame(self, frame, display):
448 vbox = QVBoxLayout()
449 frame.setLayout(vbox)
450 self.heroList = QComboBox()
451 self.heroList.setStyleSheet("background-color: #455364")
452 current_directory = str(pathlib.Path(__file__).parent.absolute())
454 for count, site in enumerate(self.conf.get_supported_sites(), start=1):
455 player = self.conf.supported_sites[site].screen_name
456 _pname = player
457 self.leHeroes[site] = QLineEdit(_pname)
459 if os.name == 'nt':
460 icoPath = os.path.dirname(__file__) + "\\icons\\"
461 else:
462 icoPath = ""
464 icon_file = ""
465 if site == "PokerStars":
466 icon_file = 'ps.svg'
467 elif site == "Full Tilt Poker":
468 icon_file = 'ft.svg'
469 elif site == "Everleaf":
470 icon_file = 'everleaf.png'
471 elif site == "Boss":
472 icon_file = 'boss.ico'
473 elif site == "PartyPoker":
474 icon_file = 'party.png'
475 elif site == "Merge":
476 icon_file = 'merge.png'
477 elif site == "PKR":
478 icon_file = 'pkr.png'
479 elif site == "iPoker":
480 icon_file = 'ipoker.png'
481 elif site == "Cake":
482 icon_file = 'cake.png'
483 elif site == "Entraction":
484 icon_file = 'entraction.png'
485 elif site == "BetOnline":
486 icon_file = 'betonline.png'
487 elif site == "Microgaming":
488 icon_file = 'microgaming.png'
489 elif site == "Bovada":
490 icon_file = 'bovada.png'
491 elif site == "Enet":
492 icon_file = 'enet.png'
493 elif site == "SealsWithClubs":
494 icon_file = 'swc.png'
495 elif site == "WinningPoker":
496 icon_file = 'winning.png'
497 elif site == "GGPoker":
498 icon_file = 'gg.png'
499 elif site == "Pacific":
500 icon_file = 'pacific.png'
501 elif site == "KingsClub":
502 icon_file = 'kingsclub.png'
503 elif site == "Unibet":
504 icon_file = 'unibet.png'
505 elif site == "Winamax":
506 icon_file = 'wina.svg'
507 else:
508 icon_file = ''
510 if icon_file:
511 self.heroList.addItem(QIcon(icoPath + icon_file), f"{_pname} on {site}")
512 else:
513 self.heroList.addItem(f"{_pname} on {site}")
515 vbox.addWidget(self.heroList)
516 self.heroList.currentTextChanged.connect(self.update_filters_for_hero)
518 if "GroupsAll" in display and display["GroupsAll"]:
519 hbox = QHBoxLayout()
520 vbox.addLayout(hbox)
521 self.cbGroups['allplayers'] = QCheckBox(self.filterText['groupsall'])
522 hbox.addWidget(self.cbGroups['allplayers'])
524 lbl = QLabel(('Min # Hands:'))
525 hbox.addWidget(lbl)
527 self.phands = QSpinBox()
528 self.phands.setMaximum(int(1e5))
529 hbox.addWidget(self.phands)
531 refresh_button = QPushButton("Refresh Filters")
532 refresh_button.clicked.connect(self.update_filters_for_hero)
533 vbox.addWidget(refresh_button)
535 def fillSitesFrame(self, frame):
536 vbox = QVBoxLayout()
537 frame.setLayout(vbox)
539 for site in self.conf.get_supported_sites():
540 self.cbSites[site] = QCheckBox(site)
541 self.cbSites[site].setChecked(True)
542 vbox.addWidget(self.cbSites[site])
544 def fillTourneyTypesFrame(self, frame):
545 vbox1 = QVBoxLayout()
546 frame.setLayout(vbox1)
548 req = self.cursor.execute("SELECT DISTINCT tourneyName FROM Tourneys")
549 result = req.fetchall()
550 print(result)
551 self.gameList = QComboBox()
552 self.gameList.setStyleSheet("background-color: #455364")
553 for count, game in enumerate(result, start=0):
554 game = str(result[count])
555 if game == "(None,)":
556 game = "(\"None\",)"
557 game = game.replace("(", "")
558 game = game.replace(",", "")
559 game = game.replace(")", "")
560 else:
561 game = game.replace("(", "")
562 game = game.replace(",", "")
563 game = game.replace(")", "")
565 print(game)
566 if game != '"None"':
567 self.gameList.insertItem(count, game)
568 else:
569 self.gameList.insertItem(count, game)
571 if len(result) >= 1:
572 for line in result:
573 if str(line) == "(None,)":
574 self.cbTourney[line[0]] = QCheckBox("None")
575 self.cbTourney[line[0]].setChecked(True)
576 vbox1.addWidget(self.cbTourney[line[0]])
577 else:
578 self.cbTourney[line[0]] = QCheckBox(line[0])
579 self.cbTourney[line[0]].setChecked(True)
580 vbox1.addWidget(self.cbTourney[line[0]])
582 else:
583 print("INFO: No games returned from database")
584 log.info("No games returned from database")
586 def fillTourneyCatFrame(self, frame):
587 vbox1 = QVBoxLayout()
588 frame.setLayout(vbox1)
590 req = self.cursor.execute("SELECT DISTINCT category FROM TourneyTypes")
591 result = req.fetchall()
592 print(result)
593 self.gameList = QComboBox()
594 self.gameList.setStyleSheet("background-color: #455364")
595 for count, game in enumerate(result, start=0):
596 game = str(result[count])
597 if game == "(None,)":
598 game = "(\"None\",)"
599 game = game.replace("(", "")
600 game = game.replace(",", "")
601 game = game.replace(")", "")
602 else:
603 game = game.replace("(", "")
604 game = game.replace(",", "")
605 game = game.replace(")", "")
607 print(game)
608 if game != '"None"':
609 self.gameList.insertItem(count, game)
610 else:
611 self.gameList.insertItem(count, game)
613 if len(result) >= 1:
614 for line in result:
615 if str(line) == "(None,)":
616 self.cbTourneyCat[line[0]] = QCheckBox("None")
617 self.cbTourneyCat[line[0]].setChecked(True)
618 vbox1.addWidget(self.cbTourneyCat[line[0]])
619 else:
620 self.cbTourneyCat[line[0]] = QCheckBox(line[0])
621 self.cbTourneyCat[line[0]].setChecked(True)
622 vbox1.addWidget(self.cbTourneyCat[line[0]])
624 else:
625 print("INFO: No games returned from database")
626 log.info("No games returned from database")
628 def fillTourneyLimFrame(self, frame):
629 vbox1 = QVBoxLayout()
630 frame.setLayout(vbox1)
632 req = self.cursor.execute("SELECT DISTINCT limitType FROM TourneyTypes")
633 result = req.fetchall()
634 print(result)
635 self.gameList = QComboBox()
636 self.gameList.setStyleSheet("background-color: #455364")
637 for count, game in enumerate(result, start=0):
638 game = str(result[count])
639 if game == "(None,)":
640 game = "(\"None\",)"
641 game = game.replace("(", "")
642 game = game.replace(",", "")
643 game = game.replace(")", "")
644 else:
645 game = game.replace("(", "")
646 game = game.replace(",", "")
647 game = game.replace(")", "")
649 print(game)
650 if game != '"None"':
651 self.gameList.insertItem(count, game)
652 else:
653 self.gameList.insertItem(count, game)
655 if len(result) >= 1:
656 for line in result:
657 if str(line) == "(None,)":
658 self.cbTourneyLim[line[0]] = QCheckBox("None")
659 self.cbTourneyLim[line[0]].setChecked(True)
660 vbox1.addWidget(self.cbTourneyLim[line[0]])
661 else:
662 self.cbTourneyLim[line[0]] = QCheckBox(line[0])
663 self.cbTourneyLim[line[0]].setChecked(True)
664 vbox1.addWidget(self.cbTourneyLim[line[0]])
666 else:
667 print("INFO: No games returned from database")
668 log.info("No games returned from database")
670 def fillTourneyBuyinFrame(self, frame):
671 vbox1 = QVBoxLayout()
672 frame.setLayout(vbox1)
674 req = self.cursor.execute("SELECT DISTINCT buyin, fee FROM TourneyTypes")
675 result = req.fetchall()
677 if len(result) >= 1:
678 for count, (buyin, fee) in enumerate(result):
679 if buyin is None and fee is None:
680 display_text = "None"
681 value = "None"
682 else:
683 total = (buyin + fee) / 100 # Convert to dollars
684 display_text = f"${total:.2f}"
685 value = f"{buyin},{fee}"
687 self.cbTourneyBuyin[value] = QCheckBox(display_text)
688 self.cbTourneyBuyin[value].setChecked(True)
689 vbox1.addWidget(self.cbTourneyBuyin[value])
690 else:
691 log.info("No buy-ins returned from database")
695 def fillGamesFrame(self, frame):
696 vbox1 = QVBoxLayout()
697 frame.setLayout(vbox1)
699 self.cursor.execute(self.sql.query['getGames'])
700 result = self.db.cursor.fetchall()
701 print(result)
702 self.gameList = QComboBox()
703 self.gameList.setStyleSheet("background-color: #455364")
704 for count, game in enumerate(result, start=0):
705 game = str(result[count])
706 game = game.replace("(", "")
707 game = game.replace(",", "")
708 game = game.replace(")", "")
709 print(game)
710 self.gameList.insertItem(count, game)
712 if len(result) >= 1:
713 for line in sorted(result, key=lambda game: self.gameName[game[0]]):
714 self.cbGames[line[0]] = QCheckBox(self.gameName[line[0]])
715 self.cbGames[line[0]].setChecked(True)
716 vbox1.addWidget(self.cbGames[line[0]])
718 if len(result) >= 2:
719 hbox = QHBoxLayout()
720 vbox1.addLayout(hbox)
721 hbox.addStretch()
723 btnAll = QPushButton(self.filterText['gamesall'])
724 btnAll.clicked.connect(partial(self.__set_checkboxes,
725 checkBoxes=self.cbGames,
726 setState=True))
727 hbox.addWidget(btnAll)
729 btnNone = QPushButton(self.filterText['gamesnone'])
730 btnNone.clicked.connect(partial(self.__set_checkboxes,
731 checkBoxes=self.cbGames,
732 setState=False))
733 hbox.addWidget(btnNone)
734 hbox.addStretch()
735 else:
736 print("INFO: No games returned from database")
737 log.info("No games returned from database")
739 def fillTourneyFrame(self, frame):
740 vbox1 = QVBoxLayout()
741 frame.setLayout(vbox1)
743 self.cursor.execute(self.sql.query['getTourneyNames'])
744 result = self.db.cursor.fetchall()
745 print(result)
746 self.gameList = QComboBox()
747 self.gameList.setStyleSheet("background-color: #455364")
748 for count, game in enumerate(result, start=0):
749 game = str(result[count])
750 game = game.replace("(", "")
751 game = game.replace(",", "")
752 game = game.replace(")", "")
753 self.gameList.insertItem(count, game)
755 def fillPositionsFrame(self, frame, display):
756 vbox1 = QVBoxLayout()
757 frame.setLayout(vbox1)
759 result = [[0], [1], [2], [3], [4], [5], [6], [7], ['S'], ['B']]
760 res_count = len(result)
762 if res_count > 0:
763 v_count = 0
764 COL_COUNT = 4
765 hbox = None
766 for line in result:
767 if v_count == 0:
768 hbox = QHBoxLayout()
769 vbox1.addLayout(hbox)
771 line_str = str(line[0])
772 self.cbPositions[line_str] = QCheckBox(line_str)
773 self.cbPositions[line_str].setChecked(True)
774 hbox.addWidget(self.cbPositions[line_str])
776 v_count += 1
777 if v_count == COL_COUNT:
778 v_count = 0
780 dif = res_count % COL_COUNT
781 while dif > 0:
782 fillbox = QVBoxLayout()
783 hbox.addLayout(fillbox)
784 dif -= 1
786 if res_count > 1:
787 hbox = QHBoxLayout()
788 vbox1.addLayout(hbox)
789 hbox.addStretch()
791 btnAll = QPushButton(self.filterText['positionsall'])
792 btnAll.clicked.connect(partial(self.__set_checkboxes,
793 checkBoxes=self.cbPositions,
794 setState=True))
795 hbox.addWidget(btnAll)
797 btnNone = QPushButton(self.filterText['positionsnone'])
798 btnNone.clicked.connect(partial(self.__set_checkboxes,
799 checkBoxes=self.cbPositions,
800 setState=False))
801 hbox.addWidget(btnNone)
802 hbox.addStretch()
803 else:
804 print("INFO: No positions returned from database")
805 log.info("No positions returned from database")
807 def fillHoleCardsFrame(self, frame):
808 vbox1 = QVBoxLayout()
809 frame.setLayout(vbox1)
811 grid = QGridLayout()
812 vbox1.addLayout(grid)
813 self.createCardsWidget(grid)
815 hbox = QHBoxLayout()
816 vbox1.addLayout(hbox)
817 self.createCardsControls(hbox)
819 def fillCurrenciesFrame(self, frame):
820 vbox1 = QVBoxLayout()
821 frame.setLayout(vbox1)
823 self.cursor.execute(self.sql.query['getCurrencies'])
824 result = self.db.cursor.fetchall()
825 if len(result) >= 1:
826 for line in result:
827 if line[0] in self.currencyName:
828 cname = self.currencyName[line[0]]
829 else:
830 cname = line[0]
831 self.cbCurrencies[line[0]] = QCheckBox(cname)
832 self.cbCurrencies[line[0]].setChecked(True)
833 vbox1.addWidget(self.cbCurrencies[line[0]])
835 if len(result) >= 2:
836 hbox = QHBoxLayout()
837 vbox1.addLayout(hbox)
838 hbox.addStretch()
840 btnAll = QPushButton(self.filterText['currenciesall'])
841 btnAll.clicked.connect(partial(self.__set_checkboxes,
842 checkBoxes=self.cbCurrencies,
843 setState=True))
844 hbox.addWidget(btnAll)
846 btnNone = QPushButton(self.filterText['currenciesnone'])
847 btnNone.clicked.connect(partial(self.__set_checkboxes,
848 checkBoxes=self.cbCurrencies,
849 setState=False))
850 hbox.addWidget(btnNone)
851 hbox.addStretch()
852 else:
853 self.cbCurrencies[line[0]].setChecked(True)
854 else:
855 log.info("No currencies returned from database")
857 def fillLimitsFrame(self, frame, display):
858 vbox1 = QVBoxLayout()
859 frame.setLayout(vbox1)
861 self.cursor.execute(self.sql.query['getCashLimits'])
862 result = self.db.cursor.fetchall()
863 limits_found = set()
864 types_found = set()
866 if len(result) >= 1:
867 hbox = QHBoxLayout()
868 vbox1.addLayout(hbox)
869 vbox2 = QVBoxLayout()
870 hbox.addLayout(vbox2)
871 vbox3 = QVBoxLayout()
872 hbox.addLayout(vbox3)
873 for i, line in enumerate(result):
874 if "UseType" in self.display:
875 if line[0] != self.display["UseType"]:
876 continue
877 hbox = QHBoxLayout()
878 if i < old_div((len(result) + 1), 2):
879 vbox2.addLayout(hbox)
880 else:
881 vbox3.addLayout(hbox)
882 if True:
883 name = str(line[2]) + line[1]
884 limits_found.add(line[1])
885 self.cbLimits[name] = QCheckBox(name)
886 self.cbLimits[name].setChecked(True)
887 hbox.addWidget(self.cbLimits[name])
888 types_found.add(line[0])
889 self.type = line[0]
890 if "LimitSep" in display and display["LimitSep"] and len(result) >= 2:
891 hbox = QHBoxLayout()
892 vbox1.addLayout(hbox)
893 hbox.addStretch()
895 btnAll = QPushButton(self.filterText['limitsall'])
896 btnAll.clicked.connect(partial(self.__set_checkboxes,
897 checkBoxes=self.cbLimits,
898 setState=True))
899 hbox.addWidget(btnAll)
901 btnNone = QPushButton(self.filterText['limitsnone'])
902 btnNone.clicked.connect(partial(self.__set_checkboxes,
903 checkBoxes=self.cbLimits,
904 setState=False))
905 hbox.addWidget(btnNone)
907 if "LimitType" in display and display["LimitType"] and len(limits_found) > 1:
908 for limit in limits_found:
909 btn = QPushButton(self.filterText['limits' + limit.upper()])
910 btn.clicked.connect(partial(self.__select_limit, limit=limit))
911 hbox.addWidget(btn)
913 hbox.addStretch()
914 else:
915 print("INFO: No games returned from database")
916 log.info("No games returned from database")
918 if "Type" in display and display["Type"] and 'ring' in types_found and 'tour' in types_found:
919 self.type = 'ring'
921 def fillGraphOpsFrame(self, frame):
922 vbox1 = QVBoxLayout()
923 frame.setLayout(vbox1)
925 hbox1 = QHBoxLayout()
926 vbox1.addLayout(hbox1)
928 label = QLabel("Show Graph In:")
929 hbox1.addWidget(label)
931 self.cbGraphops['$'] = QRadioButton("$$", frame)
932 hbox1.addWidget(self.cbGraphops['$'])
933 self.cbGraphops['$'].setChecked(True)
935 self.cbGraphops['BB'] = QRadioButton("BB", frame)
936 hbox1.addWidget(self.cbGraphops['BB'])
938 self.cbGraphops['showdown'] = QCheckBox("Showdown Winnings")
939 vbox1.addWidget(self.cbGraphops['showdown'])
941 self.cbGraphops['nonshowdown'] = QCheckBox("Non-Showdown Winnings")
942 vbox1.addWidget(self.cbGraphops['nonshowdown'])
944 self.cbGraphops['ev'] = QCheckBox("EV")
945 vbox1.addWidget(self.cbGraphops['ev'])
947 def fillSeatsFrame(self, frame):
948 hbox = QHBoxLayout()
949 frame.setLayout(hbox)
951 lbl_from = QLabel(self.filterText['seatsbetween'])
952 lbl_to = QLabel(self.filterText['seatsand'])
954 adj1 = QSpinBox()
955 adj1.setRange(2, 10)
956 adj1.setValue(2)
957 adj1.valueChanged.connect(partial(self.__seats_changed, 'from'))
959 adj2 = QSpinBox()
960 adj2.setRange(2, 10)
961 adj2.setValue(10)
962 adj2.valueChanged.connect(partial(self.__seats_changed, 'to'))
964 hbox.addStretch()
965 hbox.addWidget(lbl_from)
966 hbox.addWidget(adj1)
967 hbox.addWidget(lbl_to)
968 hbox.addWidget(adj2)
969 hbox.addStretch()
971 self.sbSeats['from'] = adj1
972 self.sbSeats['to'] = adj2
974 def fillGroupsFrame(self, frame, display):
975 vbox = QVBoxLayout()
976 frame.setLayout(vbox)
978 self.cbGroups['limits'] = QCheckBox(self.filterText['limitsshow'])
979 vbox.addWidget(self.cbGroups['limits'])
981 self.cbGroups['posn'] = QCheckBox(self.filterText['posnshow'])
982 vbox.addWidget(self.cbGroups['posn'])
984 if "SeatSep" in display and display["SeatSep"]:
985 self.cbGroups['seats'] = QCheckBox(self.filterText['seatsshow'])
986 vbox.addWidget(self.cbGroups['seats'])
988 def fillDateFrame(self, frame):
989 table = QGridLayout()
990 frame.setLayout(table)
992 lbl_start = QLabel(('From:'))
993 btn_start = QPushButton("Cal")
994 btn_start.clicked.connect(partial(self.__calendar_dialog, dateEdit=self.start_date))
995 clr_start = QPushButton("Reset")
996 clr_start.clicked.connect(self.__clear_start_date)
998 lbl_end = QLabel(('To:'))
999 btn_end = QPushButton("Cal")
1000 btn_end.clicked.connect(partial(self.__calendar_dialog, dateEdit=self.end_date))
1001 clr_end = QPushButton("Reset")
1002 clr_end.clicked.connect(self.__clear_end_date)
1004 table.addWidget(lbl_start, 0, 0)
1005 table.addWidget(btn_start, 0, 1)
1006 table.addWidget(self.start_date, 0, 2)
1007 table.addWidget(clr_start, 0, 3)
1009 table.addWidget(lbl_end, 1, 0)
1010 table.addWidget(btn_end, 1, 1)
1011 table.addWidget(self.end_date, 1, 2)
1012 table.addWidget(clr_end, 1, 3)
1014 table.setColumnStretch(0, 1)
1016 def get_limits_where_clause(self, limits):
1017 where = ""
1018 lims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'fl']
1019 potlims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'pl']
1020 nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl']
1021 capnolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'cn']
1022 hpnolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'hp']
1024 where = "AND ( "
1026 if lims:
1027 clause = "(gt.limitType = 'fl' and gt.bigBlind in (%s))" % (','.join(map(str, lims)))
1028 else:
1029 clause = "(gt.limitType = 'fl' and gt.bigBlind in (-1))"
1030 where = where + clause
1031 if potlims:
1032 clause = "or (gt.limitType = 'pl' and gt.bigBlind in (%s))" % (','.join(map(str, potlims)))
1033 else:
1034 clause = "or (gt.limitType = 'pl' and gt.bigBlind in (-1))"
1035 where = where + clause
1036 if nolims:
1037 clause = "or (gt.limitType = 'nl' and gt.bigBlind in (%s))" % (','.join(map(str, nolims)))
1038 else:
1039 clause = "or (gt.limitType = 'nl' and gt.bigBlind in (-1))"
1040 where = where + clause
1041 if hpnolims:
1042 clause = "or (gt.limitType = 'hp' and gt.bigBlind in (%s))" % (','.join(map(str, hpnolims)))
1043 else:
1044 clause = "or (gt.limitType = 'hp' and gt.bigBlind in (-1))"
1045 where = where + clause
1046 if capnolims:
1047 clause = "or (gt.limitType = 'cp' and gt.bigBlind in (%s))" % (','.join(map(str, capnolims)))
1048 else:
1049 clause = "or (gt.limitType = 'cp' and gt.bigBlind in (-1))"
1050 where = where + clause + ' )'
1052 return where
1054 def replace_placeholders_with_filter_values(self, query):
1055 if '<game_test>' in query:
1056 games = self.getGames()
1057 if games:
1058 gametest = f"AND gt.category IN {str(tuple(games)).replace(',)', ')')}"
1059 else:
1060 gametest = ""
1061 query = query.replace('<game_test>', gametest)
1063 if '<limit_test>' in query:
1064 limits = self.getLimits()
1065 if limits:
1066 limittest = self.get_limits_where_clause(limits)
1067 else:
1068 limittest = ""
1069 query = query.replace('<limit_test>', limittest)
1071 if '<player_test>' in query:
1072 heroes = self.getHeroes()
1073 if heroes:
1074 hero_ids = self.get_hero_ids(heroes)
1075 player_test = f"AND hp.playerId IN ({','.join(map(str, hero_ids))})"
1076 else:
1077 player_test = ""
1078 query = query.replace('<player_test>', player_test)
1080 if '<position_test>' in query:
1081 positions = self.getPositions()
1082 if positions:
1083 formatted_positions = [f"'{position}'" for position in positions]
1084 positiontest = f"AND hp.position IN ({','.join(formatted_positions)})"
1085 else:
1086 positiontest = ""
1087 query = query.replace('<position_test>', positiontest)
1089 return query
1091 def get_hero_ids(self, heroes):
1092 hero_ids = []
1093 site_ids = self.getSiteIds()
1094 for site, hero in heroes.items():
1095 site_id = site_ids.get(site)
1096 if site_id is not None:
1097 self.cursor.execute(self.sql.query['getPlayerId'], (site_id, hero))
1098 result = self.cursor.fetchone()
1099 if result:
1100 hero_ids.append(result[0])
1101 return hero_ids
1103 def __calendar_dialog(self, checkState, dateEdit):
1104 d = QDialog()
1105 d.setWindowTitle('Pick a date')
1107 vb = QVBoxLayout()
1108 d.setLayout(vb)
1109 cal = QCalendarWidget()
1110 vb.addWidget(cal)
1112 btn = QPushButton('Done')
1113 btn.clicked.connect(partial(self.__get_date, dlg=d, calendar=cal, dateEdit=dateEdit))
1114 vb.addWidget(btn)
1115 d.exec_()
1117 def __clear_start_date(self, checkState):
1118 self.start_date.setDate(QDate(1970, 1, 1))
1120 def __clear_end_date(self, checkState):
1121 self.end_date.setDate(QDate(2100, 1, 1))
1123 def __get_date(self, checkState, dlg, calendar, dateEdit):
1124 newDate = calendar.selectedDate()
1125 dateEdit.setDate(newDate)
1127 if dateEdit == self.start_date:
1128 end = self.end_date.date()
1129 if newDate > end:
1130 self.end_date.setDate(newDate)
1131 else:
1132 start = self.start_date.date()
1133 if newDate < start:
1134 self.start_date.setDate(newDate)
1135 dlg.accept()
1137 def __seats_changed(self, value, which):
1138 seats_from = self.sbSeats['from'].value()
1139 seats_to = self.sbSeats['to'].value()
1140 if seats_from > seats_to:
1141 if which == 'from':
1142 self.sbSeats['to'].setValue(seats_from)
1143 else:
1144 self.sbSeats['from'].setValue(seats_to)
1146 def setGames(self, games):
1147 self.games = games
1149 def update_filters_for_hero(self):
1150 if self.heroList and self.heroList.count() > 0:
1151 selected_text = self.heroList.currentText()
1152 if " on " in selected_text:
1153 selected_hero, selected_site = selected_text.split(" on ")
1154 self.update_sites_for_hero(selected_hero, selected_site)
1155 self.update_games_for_hero(selected_hero, selected_site)
1156 self.update_limits_for_hero(selected_hero, selected_site)
1157 self.update_positions_for_hero(selected_hero, selected_site)
1158 self.update_currencies_for_hero(selected_hero, selected_site)
1160 def update_sites_for_hero(self, hero, site):
1161 for s, checkbox in self.cbSites.items():
1162 checkbox.setChecked(s == site)
1163 checkbox.setEnabled(s == site)
1165 def update_games_for_hero(self, hero, site):
1166 site_id = self.siteid[site]
1167 usetype = self.display.get("UseType", "")
1168 print(f"Game type for hero {hero} on site {site}: {usetype}")
1170 if usetype == 'tour':
1171 query = """
1172 SELECT DISTINCT tt.category
1173 FROM TourneyTypes tt
1174 JOIN Tourneys t ON tt.id = t.tourneyTypeId
1175 JOIN TourneysPlayers tp ON t.id = tp.tourneyId
1176 JOIN Players p ON tp.playerId = p.id
1177 WHERE tt.siteId = ? AND p.name = ?
1178 """
1179 else: # ring games
1180 query = """
1181 SELECT DISTINCT gt.category
1182 FROM GameTypes gt
1183 JOIN Hands h ON gt.id = h.gametypeId
1184 JOIN HandsPlayers hp ON h.id = hp.handId
1185 JOIN Players p ON hp.playerId = p.id
1186 WHERE gt.siteId = ? AND p.name = ? AND gt.type = 'ring'
1187 """
1189 print("Query:")
1190 print(query)
1192 self.cursor.execute(query, (site_id, hero))
1193 games = [row[0] for row in self.cursor.fetchall()]
1194 print(f"Available games for hero {hero} on site {site}: {games}")
1196 for game, checkbox in self.cbGames.items():
1197 if game in games:
1198 checkbox.setChecked(True)
1199 checkbox.setEnabled(True)
1200 else:
1201 checkbox.setChecked(False)
1202 checkbox.setEnabled(False)
1204 # update
1205 self.games = games
1208 def update_limits_for_hero(self, hero, site):
1209 query = self.sql.query['getCashLimits'].replace("%s", str(self.siteid[site]))
1210 self.cursor.execute(query)
1211 limits = [f"{row[2]}{row[1]}" for row in self.cursor.fetchall()]
1212 for limit, checkbox in self.cbLimits.items():
1213 if limit in limits:
1214 checkbox.setChecked(True)
1215 checkbox.setEnabled(True)
1216 else:
1217 checkbox.setChecked(False)
1218 checkbox.setEnabled(False)
1220 def update_positions_for_hero(self, hero, site):
1221 query = "SELECT DISTINCT hp.position FROM HandsPlayers hp JOIN Hands h ON hp.handId = h.id JOIN Players p ON hp.playerId = p.id WHERE p.name = ? AND h.siteHandNo LIKE ?"
1222 site_id = self.siteid[site]
1223 self.cursor.execute(query, (hero, f"{site_id}%"))
1224 positions = [str(row[0]) for row in self.cursor.fetchall()]
1225 for position, checkbox in self.cbPositions.items():
1226 if position in positions:
1227 checkbox.setChecked(True)
1228 checkbox.setEnabled(True)
1229 else:
1230 checkbox.setChecked(False)
1231 checkbox.setEnabled(False)
1233 def getBuyIn(self):
1234 selected_buyins = []
1235 for value, checkbox in self.cbTourneyBuyin.items():
1236 if checkbox.isChecked() and value != "None":
1237 buyin, fee = map(int, value.split(','))
1238 total = buyin + fee
1239 selected_buyins.append(total)
1240 return selected_buyins
1242 def update_currencies_for_hero(self, hero, site):
1243 query = """
1244 SELECT DISTINCT gt.currency
1245 FROM GameTypes gt
1246 JOIN Hands h ON gt.id = h.gametypeId
1247 JOIN HandsPlayers hp ON h.id = hp.handId
1248 JOIN Players p ON hp.playerId = p.id
1249 WHERE gt.siteId = ? AND p.name = ?
1250 """
1251 site_id = self.siteid[site]
1252 #debug
1253 #print(f"executed request for {hero} on {site} (site_id: {site_id})")
1254 self.cursor.execute(query, (site_id, hero))
1255 currencies = [row[0] for row in self.cursor.fetchall()]
1256 #debug
1257 #print(f"currencies found for {hero} on {site}: {currencies}")
1259 for currency, checkbox in self.cbCurrencies.items():
1260 if currency in currencies:
1261 checkbox.setChecked(True)
1262 checkbox.setEnabled(True)
1263 else:
1264 checkbox.setChecked(False)
1265 checkbox.setEnabled(False)
1267 # manage tour 'T$' on 'ring'
1268 if currency == 'T$' and self.getType() == 'ring':
1269 checkbox.setChecked(False)
1270 checkbox.setEnabled(False)
1271 #debug
1272 #print(f"Devise {currency} - Checked: {checkbox.isChecked()}, Activated: {checkbox.isEnabled()} on {site}")
1274if __name__ == '__main__':
1275 config = Configuration.Config(file="HUD_config.test.xml")
1276 db = Database.Database(config)
1278 qdict = SQL.Sql(db_server='sqlite')
1280 filters_display = {"Heroes": False,
1281 "Sites": False,
1282 "Games": False,
1283 "Cards": True,
1284 "Currencies": False,
1285 "Limits": False,
1286 "LimitSep": False,
1287 "LimitType": False,
1288 "Type": False,
1289 "UseType": 'ring',
1290 "Seats": False,
1291 "SeatSep": False,
1292 "Dates": False,
1293 "GraphOps": False,
1294 "Groups": False,
1295 "Button1": False,
1296 "Button2": False
1297 }
1299 from PyQt5.QtWidgets import QMainWindow, QApplication
1300 app = QApplication([])
1301 i = Filters(db, display=filters_display)
1302 main_window = QMainWindow()
1303 main_window.setCentralWidget(i)
1304 main_window.show()
1305 app.exec_()