fpdb/pyfpdb/TableWindow.py

274 lines
12 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Base class for interacting with poker client windows.
There are currently subclasses for X and Windows.
The class queries the poker client window for data of interest, such as
size and location. It also controls the signals to alert the HUD when the
client has been resized, destroyed, etc.
"""
# Copyright 2008 - 2010, Ray E. Barker
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
import re
# pyGTK modules
import gtk
import gobject
# FreePokerTools modules
from HandHistoryConverter import getTableTitleRe
from HandHistoryConverter import getTableNoRe
# Global used for figuring out the current game being played from the title.
# The dict key is a tuple of (limit type, category) for the game.
# The list is the names for those games used by the supported poker sites
# This is currently only used for mixed games, so it only needs to support those
# games on PokerStars and Full Tilt.
nlpl_game_names = { #fpdb name Stars Name FTP Name (if different)
("nl", "holdem" ) : ("No Limit Hold\'em" , ),
("pl", "holdem" ) : ("Pot Limit Hold\'em" , ),
("pl", "omahahi" ) : ("Pot Limit Omaha" ,"Pot Limit Omaha Hi" ),
}
limit_game_names = { #fpdb name Stars Name FTP Name
("fl", "holdem" ) : ("Limit Hold\'em" , ),
("fl", "omahahilo" ) : ("Limit Omaha H/L" , ),
("fl", "studhilo" ) : ("Limit Stud H/L" , ),
("fl", "razz" ) : ("Limit Razz" , ),
("fl", "studhi" ) : ("Limit Stud" , "Stud Hi"),
("fl", "27_3draw" ) : ("Limit Triple Draw 2-7 Lowball", )
}
# A window title might have our table name + one of these words/
# phrases. If it has this word in the title, it is not a table.
bad_words = ('History for table:', 'HUD:', 'Chat:', 'FPDBHUD', 'Instant Replay')
# Here are the custom signals we define for allowing the 'client watcher'
# thread to communicate with the gui thread. Any time a poker client is
# is moved, resized, or closed on of these signals is emitted to the
# HUD main window.
gobject.signal_new("client_moved", gtk.Window,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,))
gobject.signal_new("client_resized", gtk.Window,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,))
gobject.signal_new("client_destroyed", gtk.Window,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,))
gobject.signal_new("game_changed", gtk.Window,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,))
gobject.signal_new("table_changed", gtk.Window,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,))
# Each TableWindow object must have the following attributes correctly populated:
# tw.name = the table name from the title bar, which must to match the table name
# from the corresponding hand record in the db.
# tw.number = This is the system id number for the client table window in the
# format that the system presents it. This is Xid in Xwindows and
# hwnd in Microsoft Windows.
# tw.title = The full title from the window title bar.
# tw.width, tw.height = The width and height of the window in pixels. This is
# the internal width and height, not including the title bar and
# window borders.
# tw.x, tw.y = The x, y (horizontal, vertical) location of the window relative
# to the top left of the display screen. This also does not include the
# title bar and window borders. To put it another way, this is the
# screen location of (0, 0) in the working window.
# tournament = Tournament number for a tournament or None for a cash game.
# tw.table = tournament: Table number for the tournament.
# cash: full Table name as given by the poker site
# tw.gdkhandle = gdk handle for the poker client window - used to nail the hud to the window
# tw.window = is this still used?
# tw.parent = window object of the parent of the client window, only used in Linux
# tw.game = the poker game being played at the table, only used in mixed games
# tw.search_string = regular expression used to find the table, supplied by XToFpdb.py
# tw.key = a string formulated to be a unique id for this table window, used in the hud main window
class Table_Window(object):
def __init__(self, config, site, table_name = None, tournament = None, table_number = None):
self.config = config
self.site = site
self.hud = None # fill in later
if tournament is not None and table_number is not None:
self.tournament = int(tournament)
self.table = int(table_number)
self.name = "%s - %s" % (self.tournament, self.table)
self.type = "tour"
table_kwargs = dict(tournament = self.tournament, table_number = self.table)
self.tableno_re = getTableNoRe(self.config, self.site, tournament = self.tournament)
self.key = "%s Table %s" % (tournament, str(self.table))
elif table_name is not None:
self.name = table_name
self.type = "cash"
self.tournament = None
table_kwargs = dict(table_name = table_name)
self.key = table_name # used as key for the hud_dict in HUD_main
else:
return None
self.search_string = getTableTitleRe(self.config, self.site, self.type, **table_kwargs)
self.find_table_parameters()
# self.gdkhandle = gtk.gdk.window_foreign_new(self.number)
geo = self.get_geometry()
if geo is None: return None
self.width = geo['width']
self.height = geo['height']
self.x = geo['x']
self.y = geo['y']
self.oldx = self.x # attn ray: remove these two lines and update Hud.py::update_table_position()
self.oldy = self.y
self.game = self.get_game()
def __str__(self):
# __str__ method for testing
likely_attrs = ("number", "title", "site", "width", "height", "x", "y",
"tournament", "table", "gdkhandle", "window", "parent",
"key", "hud", "game", "search_string", "tableno_re")
temp = 'TableWindow object\n'
for a in likely_attrs:
if getattr(self, a, 0):
temp += " %s = %s\n" % (a, getattr(self, a))
return temp
####################################################################
# "get" methods. These query the table and return the info to get.
# They don't change the data in the table and are generally used
# by the "check" methods. Most of the get methods are in the
# subclass because they are specific to X, Windows, etc.
def get_game(self):
# title = self.get_window_title()
# if title is None:
# return False
title = self.title
# check for nl and pl games first, to avoid bad matches
for game, names in nlpl_game_names.iteritems():
for name in names:
if name in title:
return game
for game, names in limit_game_names.iteritems():
for name in names:
if name in title:
return game
return False
def get_table_no(self):
new_title = self.get_window_title()
if new_title is None:
return False
try:
mo = re.search(self.tableno_re, new_title)
except AttributeError: #'Table' object has no attribute 'tableno_re'
return False
if mo is not None:
#print "get_table_no: mo=",mo.groups()
return int(mo.group(1))
return False
####################################################################
# check_table() is meant to be called by the hud periodically to
# determine if the client has been moved or resized. check_table()
# also checks and signals if the client has been closed.
def check_table(self, hud):
result = self.check_size()
if result != False:
hud.parent.main_window.emit(result, hud)
if result == "client_destroyed":
return True
result = self.check_loc()
if result != False:
hud.parent.main_window.emit(result, hud)
if result == "client_destroyed":
return True
return True
####################################################################
# "check" methods. They use the corresponding get method, update the
# table object and return the name of the signal to be emitted or
# False if unchanged. These do not signal for destroyed
# clients to prevent a race condition.
# These might be called by a Window.timeout, so they must not
# return False, or the timeout will be cancelled.
def check_game(self, hud):
new_game = self.get_game()
if new_game is not None and self.game != new_game:
self.game = new_game
hud.main_window.emit("game_changed", hud)
return "game_changed"
return True
def check_size(self):
new_geo = self.get_geometry()
if new_geo is None: # window destroyed
return "client_destroyed"
elif self.width != new_geo['width'] or self.height != new_geo['height']: # window resized
self.oldwidth = self.width
self.width = new_geo['width']
self.oldheight = self.height
self.height = new_geo['height']
return "client_resized"
return False # no change
def check_loc(self):
new_geo = self.get_geometry()
if new_geo is None: # window destroyed
return "client_destroyed"
if self.x != new_geo['x'] or self.y != new_geo['y']: # window moved
# print self.x, self.y, new_geo['x'], new_geo['y']
self.x = new_geo['x']
self.y = new_geo['y']
return "client_moved"
return False # no change
def check_table_no(self, hud):
result = self.get_table_no()
if result != False and result != self.table:
self.table = result
if hud is not None:
hud.parent.main_window.emit("table_changed", hud)
return True
def check_bad_words(self, title):
for word in bad_words:
if word in title: return True
return False