Coverage for TableWindow.py: 14%
147 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 -*-
3"""Base class for interacting with poker client windows.
5There are currently subclasses for X, OSX, and Windows.
7The class queries the poker client window for data of interest, such as
8size and location. It also controls the signals to alert the HUD when the
9client has been resized, destroyed, etc.
10"""
11# Copyright 2008 - 2011, Ray E. Barker
13# This program is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License as published by
15# the Free Software Foundation; either version 2 of the License, or
16# (at your option) any later version.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program; if not, write to the Free Software
25# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27########################################################################
30# import L10n
31# _ = L10n.get_translation()
33# Standard Library modules
34import re
35import logging
36from time import sleep
38# FreePokerTools modules
39import Configuration
40from HandHistoryConverter import getTableTitleRe
41from HandHistoryConverter import getTableNoRe
43c = Configuration.Config()
44log = logging.getLogger("hud")
46# Global used for figuring out the current game being played from the title.
47# The dict key is a tuple of (limit type, category) for the game.
48# The list is the names for those games used by the supported poker sites
49# This is currently only used for mixed games, so it only needs to support those
50# games on PokerStars and Full Tilt.
51nlpl_game_names = { # fpdb name Stars Name FTP Name (if different)
52 ("nl", "holdem"): ("No Limit Hold'em",),
53 ("pl", "holdem"): ("Pot Limit Hold'em",),
54 ("pl", "omahahi"): ("Pot Limit Omaha", "Pot Limit Omaha Hi"),
55}
56limit_game_names = { # fpdb name Stars Name FTP Name
57 ("fl", "holdem"): ("Limit Hold'em",),
58 ("fl", "omahahilo"): ("Limit Omaha H/L",),
59 ("fl", "studhilo"): ("Limit Stud H/L",),
60 ("fl", "razz"): ("Limit Razz",),
61 ("fl", "studhi"): ("Limit Stud", "Stud Hi"),
62 ("fl", "27_3draw"): ("Limit Triple Draw 2-7 Lowball",),
63}
65# A window title might have our table name + one of these words/
66# phrases. If it has this word in the title, it is not a table.
67bad_words = ("History for table:", "HUD:", "Chat:", "FPDBHUD", "Lobby")
69# Each TableWindow object must have the following attributes correctly populated:
70# tw.name = the table name from the title bar, which must to match the table name
71# from the corresponding hand record in the db.
72# tw.number = This is the system id number for the client table window in the
73# format that the system presents it. This is Xid in Xwindows and
74# hwnd in Microsoft Windows.
75# tw.title = The full title from the window title bar.
76# tw.width, tw.height = The width and height of the window in pixels. This is
77# the internal width and height, not including the title bar and
78# window borders.
79# tw.x, tw.y = The x, y (horizontal, vertical) location of the window relative
80# to the top left of the display screen. This also does not include the
81# title bar and window borders. To put it another way, this is the
82# screen location of (0, 0) in the working window.
83# tournament = Tournament number for a tournament or None for a cash game.
84# table = Table number for a tournament.
85# gdkhandle =
86# window =
87# parent =
88# game =
89# search_string =
92class Table_Window(object):
93 def __init__(self, config, site, table_name=None, tournament=None, table_number=None):
94 self.config = config
95 self.site = site
96 self.hud = None # fill in later
97 self.gdkhandle = None
98 self.number = None
99 # check if
100 if isinstance(table_name, bytes):
101 log.debug(f"Décodage de table_name en UTF-8 : {table_name}")
102 table_name = table_name.decode('utf-8')
103 if isinstance(tournament, bytes):
104 log.debug(f"Décodage de table_name en UTF-8 : {tournament}")
105 tournament = tournament.decode('utf-8')
106 if isinstance(table_number, bytes):
107 log.debug(f"Décodage de table_name en UTF-8 : {table_number}")
108 table_number = table_number.decode('utf-8')
110 if tournament is not None and table_number is not None:
111 log.debug(tournament)
112 self.tournament = int(tournament)
113 log.debug(" tournement:")
114 log.debug(self.tournament)
115 log.debug("table_number:")
116 log.debug(type(table_number))
117 log.debug(table_number)
118 # temp bug correction for ipoker must investigate
119 # if table_number is not an interger
121 log.debug("table_number error:")
122 log.debug(type(table_number))
123 log.debug(table_number)
124 self.table = int(table_number)
125 log.debug(self.table)
126 self.name = "%s - %s" % (self.tournament, self.table)
127 self.type = "tour"
128 table_kwargs = dict(tournament=self.tournament, table_number=self.table)
129 self.tableno_re = getTableNoRe(self.config, self.site, tournament=self.tournament)
130 elif table_name is not None:
131 log.debug("table_number cash:")
132 log.debug(type(table_name))
133 log.debug((table_name))
134 self.name = table_name
135 self.type = "cash"
136 self.tournament = None
137 table_kwargs = dict(table_name=table_name)
138 log.debug("table_kwarg cash:")
139 log.debug(type(table_kwargs))
140 log.debug((table_kwargs))
141 else:
142 return None
144 self.search_string = getTableTitleRe(self.config, self.site, self.type, **table_kwargs)
145 log.debug(f"search string: {self.search_string}")
146 # make a small delay otherwise Xtables.root.get_windows()
147 # returns empty for unknown reasons
148 sleep(0.1)
150 self.find_table_parameters()
151 if not self.number:
152 log.error(('Can\'t find table "%s" with search string "%s"'), table_name, self.search_string)
154 geo = self.get_geometry()
155 if geo is None:
156 return None
157 self.width = geo["width"]
158 self.height = geo["height"]
159 self.x = geo["x"]
160 log.debug(self.x)
161 self.y = geo["y"]
162 log.debug(self.y)
163 self.oldx = self.x # attn ray: remove these two lines and update Hud.py::update_table_position()
164 log.debug(self.oldx)
165 self.oldy = self.y
166 log.debug(self.oldy)
167 self.game = self.get_game()
169 def __str__(self):
170 likely_attrs = (
171 "number",
172 "title",
173 "site",
174 "width",
175 "height",
176 "x",
177 "y",
178 "tournament",
179 "table",
180 "gdkhandle",
181 "window",
182 "parent",
183 "key",
184 "hud",
185 "game",
186 "search_string",
187 "tableno_re",
188 )
189 temp = "TableWindow object\n"
190 for a in likely_attrs:
191 if getattr(self, a, 0):
192 temp += " %s = %s\n" % (a, getattr(self, a))
193 return temp
195 ####################################################################
196 # "get" methods. These query the table and return the info to get.
197 # They don't change the data in the table and are generally used
198 # by the "check" methods. Most of the get methods are in the
199 # subclass because they are specific to X, Windows, etc.
200 def get_game(self):
201 # title = self.get_window_title()
202 # if title is None:
203 # return False
204 title = self.title
206 # check for nl and pl games first, to avoid bad matches
207 for game, names in list(nlpl_game_names.items()):
208 for name in names:
209 if name in title:
210 return game
211 for game, names in list(limit_game_names.items()):
212 for name in names:
213 if name in title:
214 return game
215 return False
217 def get_table_no(self):
218 new_title = self.get_window_title()
219 log.debug(f"new table title: {new_title}")
220 if new_title is None:
221 return False
223 try:
224 log.debug(f"before searching: {new_title}")
225 mo = re.search(self.tableno_re, new_title)
226 except AttributeError: #'Table' object has no attribute 'tableno_re'
227 log.debug("'Table' object has no attribute 'tableno_re'")
228 return False
230 if mo is not None:
231 return int(mo.group(1))
232 return False
234 ####################################################################
235 # check_table() is meant to be called by the hud periodically to
236 # determine if the client has been moved or resized. check_table()
237 # also checks and signals if the client has been closed.
238 def check_table(self):
239 return self.check_size() or self.check_loc()
241 ####################################################################
242 # "check" methods. They use the corresponding get method, update the
243 # table object and return the name of the signal to be emitted or
244 # False if unchanged. These do not signal for destroyed
245 # clients to prevent a race condition.
247 # These might be called by a Window.timeout, so they must not
248 # return False, or the timeout will be cancelled.
249 def check_size(self):
250 new_geo = self.get_geometry()
251 if new_geo is None: # window destroyed
252 return "client_destroyed"
254 elif self.width != new_geo["width"] or self.height != new_geo["height"]: # window resized
255 self.oldwidth = self.width
256 self.width = new_geo["width"]
257 self.oldheight = self.height
258 self.height = new_geo["height"]
259 return "client_resized"
260 return False # no change
262 def check_loc(self):
263 new_geo = self.get_geometry()
264 if new_geo is None: # window destroyed
265 return "client_destroyed"
267 if self.x != new_geo["x"] or self.y != new_geo["y"]: # window moved
268 self.x = new_geo["x"]
269 self.y = new_geo["y"]
270 return "client_moved"
271 return False # no change
273 def has_table_title_changed(self, hud):
274 log.debug("before get_table_no()")
275 result = self.get_table_no()
276 log.debug(f"tb has change nb {result}")
277 if result is not False and result != self.table:
278 log.debug(f"compare result and self.table {result} {self.table}")
279 self.table = result
280 if hud is not None:
281 log.debug("return True")
282 return True
283 log.debug("return False")
284 return False
286 def check_bad_words(self, title):
287 for word in bad_words:
288 if word in title:
289 return True
290 return False