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