Merge branch 'master' of git://git.assembla.com/fpdboz

This commit is contained in:
Mika Bostrom 2009-11-24 19:42:39 +02:00
commit 48930e1679
16 changed files with 537 additions and 415 deletions

View File

@ -26,7 +26,7 @@ except:
diaSQLLibMissing = gtk.Dialog(title="Fatal Error - SQL interface library missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK)) diaSQLLibMissing = gtk.Dialog(title="Fatal Error - SQL interface library missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK))
print "Please note that the CLI importer only works with MySQL, if you use PostgreSQL this error is expected." print "Please note that the CLI importer only works with MySQL, if you use PostgreSQL this error is expected."
import fpdb_import import fpdb_import
import fpdb_db import fpdb_db
@ -36,9 +36,9 @@ if __name__ == "__main__":
parser.add_option("-c", "--handCount", default="0", type="int", parser.add_option("-c", "--handCount", default="0", type="int",
help="Number of hands to import (default 0 means unlimited)") help="Number of hands to import (default 0 means unlimited)")
parser.add_option("-d", "--database", default="fpdb", help="The MySQL database to use (default fpdb)") parser.add_option("-d", "--database", default="fpdb", help="The MySQL database to use (default fpdb)")
parser.add_option("-e", "--errorFile", default="failed.txt", parser.add_option("-e", "--errorFile", default="failed.txt",
help="File to store failed hands into. (default: failed.txt) Not implemented.") help="File to store failed hands into. (default: failed.txt) Not implemented.")
parser.add_option("-f", "--inputFile", "--file", "--inputfile", default="stdin", parser.add_option("-f", "--inputFile", "--file", "--inputfile", default="stdin",
help="The file you want to import (remember to use quotes if necessary)") help="The file you want to import (remember to use quotes if necessary)")
parser.add_option("-m", "--minPrint", "--status", default="50", type="int", parser.add_option("-m", "--minPrint", "--status", default="50", type="int",
help="How often to print a one-line status report (0 means never, default is 50)") help="How often to print a one-line status report (0 means never, default is 50)")
@ -51,8 +51,8 @@ if __name__ == "__main__":
parser.add_option("-x", "--failOnError", action="store_true", parser.add_option("-x", "--failOnError", action="store_true",
help="If this option is passed it quits when it encounters any error") help="If this option is passed it quits when it encounters any error")
(options, sys.argv) = parser.parse_args() (options, argv) = parser.parse_args()
settings={'callFpdbHud':False, 'db-backend':2} settings={'callFpdbHud':False, 'db-backend':2}
settings['db-host']=options.server settings['db-host']=options.server
settings['db-user']=options.user settings['db-user']=options.user

View File

@ -6,17 +6,17 @@ Handles HUD configuration files.
""" """
# Copyright 2008, 2009, Ray E. Barker # Copyright 2008, 2009, Ray E. Barker
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -54,16 +54,19 @@ def get_exec_path():
"""Returns the path to the fpdb.(py|exe) file we are executing""" """Returns the path to the fpdb.(py|exe) file we are executing"""
if hasattr(sys, "frozen"): # compiled by py2exe if hasattr(sys, "frozen"): # compiled by py2exe
return os.path.dirname(sys.executable) return os.path.dirname(sys.executable)
else: else:
return os.path.dirname(sys.path[0]) pathname = os.path.dirname(sys.argv[0])
return os.path.abspath(pathname)
def get_config(file_name, fallback = True): def get_config(file_name, fallback = True):
"""Looks in cwd and in self.default_config_path for a config file.""" """Looks in cwd and in self.default_config_path for a config file."""
config_path = os.path.join(get_exec_path(), file_name) config_path = os.path.join(get_exec_path(), file_name)
# print "config_path=", config_path
if os.path.exists(config_path): # there is a file in the cwd if os.path.exists(config_path): # there is a file in the cwd
return config_path # so we use it return config_path # so we use it
else: # no file in the cwd, look where it should be in the first place else: # no file in the cwd, look where it should be in the first place
config_path = os.path.join(get_default_config_path(), file_name) config_path = os.path.join(get_default_config_path(), file_name)
# print "config path 2=", config_path
if os.path.exists(config_path): if os.path.exists(config_path):
return config_path return config_path
@ -142,7 +145,7 @@ class Layout:
if node.hasAttribute('fav_seat'): self.fav_seat = int( node.getAttribute('fav_seat') ) if node.hasAttribute('fav_seat'): self.fav_seat = int( node.getAttribute('fav_seat') )
self.width = int( node.getAttribute('width') ) self.width = int( node.getAttribute('width') )
self.height = int( node.getAttribute('height') ) self.height = int( node.getAttribute('height') )
self.location = [] self.location = []
self.location = map(lambda x: None, range(self.max+1)) # fill array with max seats+1 empty entries self.location = map(lambda x: None, range(self.max+1)) # fill array with max seats+1 empty entries
@ -161,7 +164,7 @@ class Layout:
temp = temp + " Locations = " temp = temp + " Locations = "
for i in range(1, len(self.location)): for i in range(1, len(self.location)):
temp = temp + "(%d,%d)" % self.location[i] temp = temp + "(%d,%d)" % self.location[i]
return temp + "\n" return temp + "\n"
class Site: class Site:
@ -171,7 +174,7 @@ class Site:
if os.path.exists(path): if os.path.exists(path):
return os.path.abspath(path) return os.path.abspath(path)
return path return path
self.site_name = node.getAttribute("site_name") self.site_name = node.getAttribute("site_name")
self.table_finder = node.getAttribute("table_finder") self.table_finder = node.getAttribute("table_finder")
self.screen_name = node.getAttribute("screen_name") self.screen_name = node.getAttribute("screen_name")
@ -191,7 +194,7 @@ class Site:
self.ypad = node.getAttribute("ypad") self.ypad = node.getAttribute("ypad")
self.layout = {} self.layout = {}
print "Loading site", self.site_name print "Loading site", self.site_name
for layout_node in node.getElementsByTagName('layout'): for layout_node in node.getElementsByTagName('layout'):
lo = Layout(layout_node) lo = Layout(layout_node)
@ -204,7 +207,7 @@ class Site:
self.hudopacity = 1.0 if self.hudopacity == "" else float(self.hudopacity) self.hudopacity = 1.0 if self.hudopacity == "" else float(self.hudopacity)
if self.use_frames == "": self.use_frames = False if self.use_frames == "": self.use_frames = False
if self.font == "": self.font = "Sans" if self.font == "": self.font = "Sans"
if self.hudbgcolor == "": self.hudbgcolor = "#000000" if self.hudbgcolor == "": self.hudbgcolor = "#000000"
if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF" if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF"
@ -216,20 +219,20 @@ class Site:
value = getattr(self, key) value = getattr(self, key)
if callable(value): continue if callable(value): continue
temp = temp + ' ' + key + " = " + str(value) + "\n" temp = temp + ' ' + key + " = " + str(value) + "\n"
for layout in self.layout: for layout in self.layout:
temp = temp + "%s" % self.layout[layout] temp = temp + "%s" % self.layout[layout]
return temp return temp
class Stat: class Stat:
def __init__(self): def __init__(self):
pass pass
def __str__(self): def __str__(self):
temp = " stat_name = %s, row = %d, col = %d, tip = %s, click = %s, popup = %s\n" % (self.stat_name, self.row, self.col, self.tip, self.click, self.popup) temp = " stat_name = %s, row = %d, col = %d, tip = %s, click = %s, popup = %s\n" % (self.stat_name, self.row, self.col, self.tip, self.click, self.popup)
return temp return temp
class Game: class Game:
def __init__(self, node): def __init__(self, node):
self.game_name = node.getAttribute("game_name") self.game_name = node.getAttribute("game_name")
@ -262,9 +265,9 @@ class Game:
stat.hudprefix = stat_node.getAttribute("hudprefix") stat.hudprefix = stat_node.getAttribute("hudprefix")
stat.hudsuffix = stat_node.getAttribute("hudsuffix") stat.hudsuffix = stat_node.getAttribute("hudsuffix")
stat.hudcolor = stat_node.getAttribute("hudcolor") stat.hudcolor = stat_node.getAttribute("hudcolor")
self.stats[stat.stat_name] = stat self.stats[stat.stat_name] = stat
def __str__(self): def __str__(self):
temp = "Game = " + self.game_name + "\n" temp = "Game = " + self.game_name + "\n"
temp = temp + " rows = %d\n" % self.rows temp = temp + " rows = %d\n" % self.rows
@ -272,12 +275,12 @@ class Game:
temp = temp + " xpad = %d\n" % self.xpad temp = temp + " xpad = %d\n" % self.xpad
temp = temp + " ypad = %d\n" % self.ypad temp = temp + " ypad = %d\n" % self.ypad
temp = temp + " aux = %s\n" % self.aux temp = temp + " aux = %s\n" % self.aux
for stat in self.stats.keys(): for stat in self.stats.keys():
temp = temp + "%s" % self.stats[stat] temp = temp + "%s" % self.stats[stat]
return temp return temp
class Database: class Database:
def __init__(self, node): def __init__(self, node):
self.db_name = node.getAttribute("db_name") self.db_name = node.getAttribute("db_name")
@ -288,7 +291,7 @@ class Database:
self.db_selected = string_to_bool(node.getAttribute("default"), default=False) self.db_selected = string_to_bool(node.getAttribute("default"), default=False)
log.debug("Database db_name:'%(name)s' db_server:'%(server)s' db_ip:'%(ip)s' db_user:'%(user)s' db_pass (not logged) selected:'%(sel)s'" \ log.debug("Database db_name:'%(name)s' db_server:'%(server)s' db_ip:'%(ip)s' db_user:'%(user)s' db_pass (not logged) selected:'%(sel)s'" \
% { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'user':self.db_user, 'sel':self.db_selected} ) % { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'user':self.db_user, 'sel':self.db_selected} )
def __str__(self): def __str__(self):
temp = 'Database = ' + self.db_name + '\n' temp = 'Database = ' + self.db_name + '\n'
for key in dir(self): for key in dir(self):
@ -336,7 +339,7 @@ class Popup:
self.pu_stats = [] self.pu_stats = []
for stat_node in node.getElementsByTagName('pu_stat'): for stat_node in node.getElementsByTagName('pu_stat'):
self.pu_stats.append(stat_node.getAttribute("pu_stat_name")) self.pu_stats.append(stat_node.getAttribute("pu_stat_name"))
def __str__(self): def __str__(self):
temp = "Popup = " + self.name + "\n" temp = "Popup = " + self.name + "\n"
for stat in self.pu_stats: for stat in self.pu_stats:
@ -385,7 +388,7 @@ class Tv:
self.combinedPostflop = string_to_bool(node.getAttribute("combinedPostflop"), default=True) self.combinedPostflop = string_to_bool(node.getAttribute("combinedPostflop"), default=True)
def __str__(self): def __str__(self):
return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" % return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" %
(self.combinedStealFold, self.combined2B3B, self.combinedPostflop) ) (self.combinedStealFold, self.combined2B3B, self.combinedPostflop) )
class Config: class Config:
@ -410,7 +413,7 @@ class Config:
print "\nReading configuration file %s\n" % file print "\nReading configuration file %s\n" % file
try: try:
doc = xml.dom.minidom.parse(file) doc = xml.dom.minidom.parse(file)
except: except:
log.error("Error parsing %s. See error log file." % (file)) log.error("Error parsing %s. See error log file." % (file))
traceback.print_exc(file=sys.stderr) traceback.print_exc(file=sys.stderr)
print "press enter to continue" print "press enter to continue"
@ -438,9 +441,9 @@ class Config:
for game_node in doc.getElementsByTagName("game"): for game_node in doc.getElementsByTagName("game"):
game = Game(node = game_node) game = Game(node = game_node)
self.supported_games[game.game_name] = game self.supported_games[game.game_name] = game
# parse databases defined by user in the <supported_databases> section # parse databases defined by user in the <supported_databases> section
# the user may select the actual database to use via commandline or by setting the selected="bool" # the user may select the actual database to use via commandline or by setting the selected="bool"
# attribute of the tag. if no database is explicitely selected, we use the first one we come across # attribute of the tag. if no database is explicitely selected, we use the first one we come across
# s_dbs = doc.getElementsByTagName("supported_databases") # s_dbs = doc.getElementsByTagName("supported_databases")
#TODO: do we want to take all <database> tags or all <database> tags contained in <supported_databases> #TODO: do we want to take all <database> tags or all <database> tags contained in <supported_databases>
@ -452,7 +455,7 @@ class Config:
if self.db_selected is None or db.db_selected: if self.db_selected is None or db.db_selected:
self.db_selected = db.db_name self.db_selected = db.db_name
self.supported_databases[db.db_name] = db self.supported_databases[db.db_name] = db
#TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored #TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored
# ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not # ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not
if dbname and dbname in self.supported_databases: if dbname and dbname in self.supported_databases:
self.db_selected = dbname self.db_selected = dbname
@ -502,7 +505,7 @@ class Config:
def set_hhArchiveBase(self, path): def set_hhArchiveBase(self, path):
self.imp.node.setAttribute("hhArchiveBase", path) self.imp.node.setAttribute("hhArchiveBase", path)
def find_default_conf(self): def find_default_conf(self):
if os.name == 'posix': if os.name == 'posix':
config_path = os.path.join(os.path.expanduser("~"), '.fpdb', 'default.conf') config_path = os.path.join(os.path.expanduser("~"), '.fpdb', 'default.conf')
@ -534,7 +537,7 @@ class Config:
def get_layout_node(self, site_node, layout): def get_layout_node(self, site_node, layout):
for layout_node in site_node.getElementsByTagName("layout"): for layout_node in site_node.getElementsByTagName("layout"):
if layout_node.getAttribute("max") is None: if layout_node.getAttribute("max") is None:
return None return None
if int( layout_node.getAttribute("max") ) == int( layout ): if int( layout_node.getAttribute("max") ) == int( layout ):
return layout_node return layout_node
@ -618,7 +621,7 @@ class Config:
elif self.supported_databases[name].db_server== DATABASE_TYPE_POSTGRESQL: elif self.supported_databases[name].db_server== DATABASE_TYPE_POSTGRESQL:
db['db-backend'] = 3 db['db-backend'] = 3
elif self.supported_databases[name].db_server== DATABASE_TYPE_SQLITE: elif self.supported_databases[name].db_server== DATABASE_TYPE_SQLITE:
db['db-backend'] = 4 db['db-backend'] = 4
else: else:
raise ValueError('Unsupported database backend: %s' % self.supported_databases[name].db_server) raise ValueError('Unsupported database backend: %s' % self.supported_databases[name].db_server)
return db return db
@ -639,7 +642,7 @@ class Config:
if db_server is not None: self.supported_databases[db_name].dp_server = db_server if db_server is not None: self.supported_databases[db_name].dp_server = db_server
if db_type is not None: self.supported_databases[db_name].dp_type = db_type if db_type is not None: self.supported_databases[db_name].dp_type = db_type
return return
def getDefaultSite(self): def getDefaultSite(self):
"Returns first enabled site or None" "Returns first enabled site or None"
for site_name,site in self.supported_sites.iteritems(): for site_name,site in self.supported_sites.iteritems():
@ -702,7 +705,7 @@ class Config:
return hui return hui
def get_import_parameters(self): def get_import_parameters(self):
imp = {} imp = {}
try: imp['callFpdbHud'] = self.imp.callFpdbHud try: imp['callFpdbHud'] = self.imp.callFpdbHud
@ -728,10 +731,10 @@ class Config:
path = os.path.expanduser(self.supported_sites[site].HH_path) path = os.path.expanduser(self.supported_sites[site].HH_path)
assert(os.path.isdir(path) or os.path.isfile(path)) # maybe it should try another site? assert(os.path.isdir(path) or os.path.isfile(path)) # maybe it should try another site?
paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = path paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = path
except AssertionError: except AssertionError:
paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **" paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **"
return paths return paths
def get_frames(self, site = "PokerStars"): def get_frames(self, site = "PokerStars"):
if site not in self.supported_sites: return False if site not in self.supported_sites: return False
return self.supported_sites[site].use_frames == True return self.supported_sites[site].use_frames == True
@ -751,7 +754,7 @@ class Config:
else: else:
colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor
return colors return colors
def get_default_font(self, site='PokerStars'): def get_default_font(self, site='PokerStars'):
font = "Sans" font = "Sans"
font_size = "8" font_size = "8"
@ -770,17 +773,17 @@ class Config:
if location is not None: if location is not None:
return location.location return location.location
return ( return (
( 0, 0), (684, 61), (689, 239), (692, 346), ( 0, 0), (684, 61), (689, 239), (692, 346),
(586, 393), (421, 440), (267, 440), ( 0, 361), (586, 393), (421, 440), (267, 440), ( 0, 361),
( 0, 280), (121, 280), ( 46, 30) ( 0, 280), (121, 280), ( 46, 30)
) )
def get_aux_locations(self, aux = "mucked", max = "9"): def get_aux_locations(self, aux = "mucked", max = "9"):
try: try:
locations = self.aux_windows[aux].layout[max].location locations = self.aux_windows[aux].layout[max].location
except: except:
locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346), locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346),
(586, 393), (421, 440), (267, 440), ( 0, 361), (586, 393), (421, 440), (267, 440), ( 0, 361),
( 0, 280), (121, 280), ( 46, 30) ) ( 0, 280), (121, 280), ( 46, 30) )
return locations return locations
@ -791,7 +794,7 @@ class Config:
return self.supported_sites.keys() return self.supported_sites.keys()
else: else:
return [site_name for (site_name, site) in self.supported_sites.items() if site.enabled] return [site_name for (site_name, site) in self.supported_sites.items() if site.enabled]
def get_site_parameters(self, site): def get_site_parameters(self, site):
"""Returns a dict of the site parameters for the specified site""" """Returns a dict of the site parameters for the specified site"""
parms = {} parms = {}
@ -814,7 +817,7 @@ class Config:
return parms return parms
def set_site_parameters(self, site_name, converter = None, decoder = None, def set_site_parameters(self, site_name, converter = None, decoder = None,
hudbgcolor = None, hudfgcolor = None, hudbgcolor = None, hudfgcolor = None,
hudopacity = None, screen_name = None, hudopacity = None, screen_name = None,
site_path = None, table_finder = None, site_path = None, table_finder = None,
HH_path = None, enabled = None, HH_path = None, enabled = None,
@ -852,7 +855,7 @@ class Config:
return param return param
return None return None
def get_game_parameters(self, name): def get_game_parameters(self, name):
"""Get the configuration parameters for the named game.""" """Get the configuration parameters for the named game."""
param = {} param = {}
@ -878,7 +881,7 @@ class Config:
if __name__== "__main__": if __name__== "__main__":
c = Config() c = Config()
print "\n----------- SUPPORTED SITES -----------" print "\n----------- SUPPORTED SITES -----------"
for s in c.supported_sites.keys(): for s in c.supported_sites.keys():
print c.supported_sites[s] print c.supported_sites[s]
@ -905,7 +908,7 @@ if __name__== "__main__":
for w in c.hhcs.keys(): for w in c.hhcs.keys():
print c.hhcs[w] print c.hhcs[w]
print "----------- END HAND HISTORY CONVERTERS -----------" print "----------- END HAND HISTORY CONVERTERS -----------"
print "\n----------- POPUP WINDOW FORMATS -----------" print "\n----------- POPUP WINDOW FORMATS -----------"
for w in c.popup_windows.keys(): for w in c.popup_windows.keys():
print c.popup_windows[w] print c.popup_windows[w]
@ -921,7 +924,7 @@ if __name__== "__main__":
c.edit_layout("PokerStars", 6, locations=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) )) c.edit_layout("PokerStars", 6, locations=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) ))
c.save(file="testout.xml") c.save(file="testout.xml")
print "db = ", c.get_db_parameters() print "db = ", c.get_db_parameters()
# print "tv = ", c.get_tv_parameters() # print "tv = ", c.get_tv_parameters()
# print "imp = ", c.get_import_parameters() # print "imp = ", c.get_import_parameters()
@ -932,7 +935,7 @@ if __name__== "__main__":
print c.get_aux_parameters(mw) print c.get_aux_parameters(mw)
print "mucked locations =", c.get_aux_locations('mucked', 9) print "mucked locations =", c.get_aux_locations('mucked', 9)
# c.edit_aux_layout('mucked', 9, locations = [(487, 113), (555, 469), (572, 276), (522, 345), # c.edit_aux_layout('mucked', 9, locations = [(487, 113), (555, 469), (572, 276), (522, 345),
# (333, 354), (217, 341), (150, 273), (150, 169), (230, 115)]) # (333, 354), (217, 341), (150, 273), (150, 169), (230, 115)])
# print "mucked locations =", c.get_aux_locations('mucked', 9) # print "mucked locations =", c.get_aux_locations('mucked', 9)

View File

@ -1343,7 +1343,9 @@ class Database:
q = q.replace('%s', self.sql.query['placeholder']) q = q.replace('%s', self.sql.query['placeholder'])
self.cursor.execute(q, ( c = self.connection.cursor()
c.execute(q, (
p['tableName'], p['tableName'],
p['gameTypeId'], p['gameTypeId'],
p['siteHandNo'], p['siteHandNo'],
@ -1374,7 +1376,7 @@ class Database:
p['street4Pot'], p['street4Pot'],
p['showdownPot'] p['showdownPot']
)) ))
return self.get_last_insert_id(self.cursor) return self.get_last_insert_id(c)
# def storeHand # def storeHand
def storeHandsPlayers(self, hid, pids, pdata): def storeHandsPlayers(self, hid, pids, pdata):
@ -1385,17 +1387,39 @@ class Database:
pids[p], pids[p],
pdata[p]['startCash'], pdata[p]['startCash'],
pdata[p]['seatNo'], pdata[p]['seatNo'],
pdata[p]['card1'],
pdata[p]['card2'],
pdata[p]['card3'],
pdata[p]['card4'],
pdata[p]['card5'],
pdata[p]['card6'],
pdata[p]['card7'],
pdata[p]['winnings'], pdata[p]['winnings'],
pdata[p]['rake'],
pdata[p]['totalProfit'],
pdata[p]['street0VPI'], pdata[p]['street0VPI'],
pdata[p]['street1Seen'], pdata[p]['street1Seen'],
pdata[p]['street2Seen'], pdata[p]['street2Seen'],
pdata[p]['street3Seen'], pdata[p]['street3Seen'],
pdata[p]['street4Seen'], pdata[p]['street4Seen'],
pdata[p]['sawShowdown'],
pdata[p]['wonAtSD'],
pdata[p]['street0Aggr'], pdata[p]['street0Aggr'],
pdata[p]['street1Aggr'], pdata[p]['street1Aggr'],
pdata[p]['street2Aggr'], pdata[p]['street2Aggr'],
pdata[p]['street3Aggr'], pdata[p]['street3Aggr'],
pdata[p]['street4Aggr'] pdata[p]['street4Aggr'],
pdata[p]['wonWhenSeenStreet1'],
pdata[p]['street0Calls'],
pdata[p]['street1Calls'],
pdata[p]['street2Calls'],
pdata[p]['street3Calls'],
pdata[p]['street4Calls'],
pdata[p]['street0Bets'],
pdata[p]['street1Bets'],
pdata[p]['street2Bets'],
pdata[p]['street3Bets'],
pdata[p]['street4Bets'],
) ) ) )
q = """INSERT INTO HandsPlayers ( q = """INSERT INTO HandsPlayers (
@ -1403,19 +1427,46 @@ class Database:
playerId, playerId,
startCash, startCash,
seatNo, seatNo,
card1,
card2,
card3,
card4,
card5,
card6,
card7,
winnings, winnings,
rake,
totalProfit,
street0VPI, street0VPI,
street1Seen, street1Seen,
street2Seen, street2Seen,
street3Seen, street3Seen,
street4Seen, street4Seen,
sawShowdown,
wonAtSD,
street0Aggr, street0Aggr,
street1Aggr, street1Aggr,
street2Aggr, street2Aggr,
street3Aggr, street3Aggr,
street4Aggr street4Aggr,
wonWhenSeenStreet1,
street0Calls,
street1Calls,
street2Calls,
street3Calls,
street4Calls,
street0Bets,
street1Bets,
street2Bets,
street3Bets,
street4Bets
) )
VALUES ( VALUES (
%s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s %s, %s, %s, %s, %s
@ -1423,16 +1474,9 @@ class Database:
# position, # position,
# tourneyTypeId, # tourneyTypeId,
# card1,
# card2,
# card3,
# card4,
# startCards, # startCards,
# rake,
# totalProfit,
# street0_3BChance, # street0_3BChance,
# street0_3BDone, # street0_3BDone,
# sawShowdown,
# otherRaisedStreet1, # otherRaisedStreet1,
# otherRaisedStreet2, # otherRaisedStreet2,
# otherRaisedStreet3, # otherRaisedStreet3,
@ -1441,8 +1485,6 @@ class Database:
# foldToOtherRaisedStreet2, # foldToOtherRaisedStreet2,
# foldToOtherRaisedStreet3, # foldToOtherRaisedStreet3,
# foldToOtherRaisedStreet4, # foldToOtherRaisedStreet4,
# wonWhenSeenStreet1,
# wonAtSD,
# stealAttemptChance, # stealAttemptChance,
# stealAttempted, # stealAttempted,
# foldBbToStealChance, # foldBbToStealChance,
@ -1473,21 +1515,13 @@ class Database:
# street3CheckCallRaiseDone, # street3CheckCallRaiseDone,
# street4CheckCallRaiseChance, # street4CheckCallRaiseChance,
# street4CheckCallRaiseDone, # street4CheckCallRaiseDone,
# street0Calls,
# street1Calls,
# street2Calls,
# street3Calls,
# street4Calls,
# street0Bets,
# street1Bets,
# street2Bets,
# street3Bets,
# street4Bets
q = q.replace('%s', self.sql.query['placeholder']) q = q.replace('%s', self.sql.query['placeholder'])
#print "DEBUG: inserts: %s" %inserts #print "DEBUG: inserts: %s" %inserts
self.cursor.executemany(q, inserts) #print "DEBUG: q: %s" % q
c = self.connection.cursor()
c.executemany(q, inserts)
def storeHudCacheNew(self, gid, pid, hc): def storeHudCacheNew(self, gid, pid, hc):
q = """INSERT INTO HudCache ( q = """INSERT INTO HudCache (

View File

@ -1,6 +1,6 @@
"""Database manager """Database manager
@todo: (gtk) how to validate user input in gtk.Dialog? as soon as the user clicks ok the dialog is dead. we use a while loop as workaround. not nice @todo: (gtk) how to validate user input in gtk.Dialog? as soon as the user clicks ok the dialog is dead. we use a while loop as workaround. not nice
@todo: (fpdb) we need the application name 'fpdb' from somewhere to put it in dialog titles @todo: (fpdb) we need the application name 'fpdb' from somewhere to put it in dialog titles
@todo: (fpdb) config object should be initialized globally and accessible from all modules via Configuration.py @todo: (fpdb) config object should be initialized globally and accessible from all modules via Configuration.py
@ -24,10 +24,10 @@ import gobject
#******************************************************************************************************* #*******************************************************************************************************
class DatabaseManager(gobject.GObject): class DatabaseManager(gobject.GObject):
DatabaseTypes = {} DatabaseTypes = {}
@classmethod @classmethod
def from_fpdb(klass, data, defaultDatabaseType=None): def from_fpdb(klass, data, defaultDatabaseType=None):
#NOTE: if no databases are present in config fpdb fails with #NOTE: if no databases are present in config fpdb fails with
# Traceback (most recent call last): # Traceback (most recent call last):
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/DatabaseManager.py", line 783, in <module> # File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/DatabaseManager.py", line 783, in <module>
@ -38,12 +38,12 @@ class DatabaseManager(gobject.GObject):
# db = self.get_db_parameters() # db = self.get_db_parameters()
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/Configuration.py", line 583, in get_db_parameters # File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/Configuration.py", line 583, in get_db_parameters
# name = self.db_selected # name = self.db_selected
# AttributeError: Config instance has no attribute 'db_selected' # AttributeError: Config instance has no attribute 'db_selected'
import sys import sys
import Options import Options
import Configuration import Configuration
#NOTE: fpdb should perform this globally #NOTE: fpdb should perform this globally
(options, sys.argv) = Options.fpdb_options() (options, argv) = Options.fpdb_options()
config = Configuration.Config(file=options.config, dbname=options.dbname) config = Configuration.Config(file=options.config, dbname=options.dbname)
#TODO: handle no database present #TODO: handle no database present
defaultDatabaseName = config.get_db_parameters().get('db-databaseName', None) defaultDatabaseName = config.get_db_parameters().get('db-databaseName', None)
@ -54,7 +54,7 @@ class DatabaseManager(gobject.GObject):
#NOTE: Config does not seem to validate user input, so anything may end up here #NOTE: Config does not seem to validate user input, so anything may end up here
if databaseKlass is None: if databaseKlass is None:
raise ValueError('Unknown databasetype: %s' % fpdbDatabase.db_server) raise ValueError('Unknown databasetype: %s' % fpdbDatabase.db_server)
database = databaseKlass() database = databaseKlass()
if database.Type == 'sqlite': if database.Type == 'sqlite':
database.name = fpdbDatabase.db_name database.name = fpdbDatabase.db_name
@ -66,17 +66,17 @@ class DatabaseManager(gobject.GObject):
database.port = int(fpdbDatabase.db_ip) database.port = int(fpdbDatabase.db_ip)
database.user = fpdbDatabase.db_user database.user = fpdbDatabase.db_user
database.password = fpdbDatabase.db_pass database.password = fpdbDatabase.db_pass
databases.append(database) databases.append(database)
return klass(databases=databases, defaultDatabaseType=defaultDatabaseType) return klass(databases=databases, defaultDatabaseType=defaultDatabaseType)
def to_fpdb(self): def to_fpdb(self):
pass pass
def __init__(self, databases=None, defaultDatabaseType=None): def __init__(self, databases=None, defaultDatabaseType=None):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._defaultDatabaseType = defaultDatabaseType self._defaultDatabaseType = defaultDatabaseType
self._databases = [] if databases is None else list(databases) self._databases = [] if databases is None else list(databases)
self._activeDatabase = None self._activeDatabase = None
@ -98,21 +98,21 @@ class DatabaseManager(gobject.GObject):
self._databases.append(database) self._databases.append(database)
def remove_database(self, database): def remove_database(self, database):
self._databases.remove(database) self._databases.remove(database)
def activate_database(self, database): def activate_database(self, database):
if self._activeDatabase is not None: if self._activeDatabase is not None:
self._activeDatabase.status = self._activeDatabase.StatusInactive self._activeDatabase.status = self._activeDatabase.StatusInactive
#TODO: finalize database #TODO: finalize database
self.emit('database-deactivated', self.database_id(self._activeDatabase) ) self.emit('database-deactivated', self.database_id(self._activeDatabase) )
database.status = database.StatusActive database.status = database.StatusActive
#TODO: activate database #TODO: activate database
self._activeDatabase = database self._activeDatabase = database
self.emit('database-activated', self.database_id(database) ) self.emit('database-activated', self.database_id(database) )
def active_database(self): def active_database(self):
return self._activeDatabase return self._activeDatabase
# register DatabaseManager signals # register DatabaseManager signals
gobject.type_register(DatabaseManager) gobject.type_register(DatabaseManager)
gobject.signal_new('database-activated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, )) gobject.signal_new('database-activated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
@ -134,20 +134,20 @@ class DatabaseTypeBase(object):
StatusActive = 'active' StatusActive = 'active'
StatusInactive = 'inactive' StatusInactive = 'inactive'
StatusError = 'error' #TODO: not implemented StatusError = 'error' #TODO: not implemented
#TODO: not happy with returning error string. just being too lazy to impl dozens of error codes for later translation #TODO: not happy with returning error string. just being too lazy to impl dozens of error codes for later translation
def init_new_database(self): def init_new_database(self):
"""initializes a new empty database """initializes a new empty database
@return: (str) error if something goes wrong, None otherwise @return: (str) error if something goes wrong, None otherwise
""" """
raise NotImplementedError() raise NotImplementedError()
def validate_database(self): def validate_database(self):
"""checks if the database is valid """checks if the database is valid
@return: (str) error if something goes wrong, None otherwise @return: (str) error if something goes wrong, None otherwise
""" """
raise NotImplementedError() raise NotImplementedError()
class DatabaseTypePostgres(DatabaseTypeBase): class DatabaseTypePostgres(DatabaseTypeBase):
Type = 'postgresql' Type = 'postgresql'
@classmethod @classmethod
@ -161,15 +161,15 @@ class DatabaseTypePostgres(DatabaseTypeBase):
self.password = password self.password = password
self.database = database self.database = database
self.status = self.StatusInactive self.status = self.StatusInactive
#TODO: implement #TODO: implement
def init_new_database(self): def init_new_database(self):
pass pass
#TODO: implement #TODO: implement
def validate_database(self): def validate_database(self):
pass pass
class DatabaseTypeMysql(DatabaseTypeBase): class DatabaseTypeMysql(DatabaseTypeBase):
Type = 'mysql' Type = 'mysql'
@classmethod @classmethod
@ -183,11 +183,11 @@ class DatabaseTypeMysql(DatabaseTypeBase):
self.password = password self.password = password
self.database = database self.database = database
self.status = self.StatusInactive self.status = self.StatusInactive
#TODO: implement #TODO: implement
def init_new_database(self): def init_new_database(self):
pass pass
#TODO: implement #TODO: implement
def validate_database(self): def validate_database(self):
pass pass
@ -202,7 +202,7 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
self.name = name self.name = name
self.file = file self.file = file
self.status = self.StatusInactive self.status = self.StatusInactive
def init_new_database(self): def init_new_database(self):
# make shure all attrs are specified # make shure all attrs are specified
if not self.file: if not self.file:
@ -212,15 +212,15 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
open(self.file, 'w').close() open(self.file, 'w').close()
except IOError: except IOError:
return 'can not write file' return 'can not write file'
#TODO: init tables (...) #TODO: init tables (...)
def validate_database(self): def validate_database(self):
pass pass
#TODO: check if tables (...) exist #TODO: check if tables (...) exist
#TODO: how do we want to handle unsupported database types? #TODO: how do we want to handle unsupported database types?
# ..uncomment to remove unsupported database types # ..uncomment to remove unsupported database types
@ -235,7 +235,7 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
#TODO: there is no title (on linux), wtf? #TODO: there is no title (on linux), wtf?
def DialogError(parent=None, msg=''): def DialogError(parent=None, msg=''):
dlg = gtk.MessageDialog( dlg = gtk.MessageDialog(
parent=parent, parent=parent,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
type=gtk.MESSAGE_ERROR, type=gtk.MESSAGE_ERROR,
buttons=gtk.BUTTONS_OK, buttons=gtk.BUTTONS_OK,
@ -248,33 +248,33 @@ def DialogError(parent=None, msg=''):
#TODO: derrive from gtk.VBox? #TODO: derrive from gtk.VBox?
class WidgetDatabaseProperties(gtk.VBox): class WidgetDatabaseProperties(gtk.VBox):
ModeNew = 0 ModeNew = 0
ModeEdit = 1 ModeEdit = 1
ModeAdd = 2 ModeAdd = 2
class SqLiteFileChooserButton(gtk.HBox): class SqLiteFileChooserButton(gtk.HBox):
#NOTE: for some weird reason it is impossible to let the user choose a non exiting filename with gtk.FileChooserButton, so impl our own on the fly #NOTE: for some weird reason it is impossible to let the user choose a non exiting filename with gtk.FileChooserButton, so impl our own on the fly
def __init__(self, widgetDatabaseProperties, parentWidget): def __init__(self, widgetDatabaseProperties, parentWidget):
gtk.HBox.__init__(self) gtk.HBox.__init__(self)
self.set_homogeneous(False) self.set_homogeneous(False)
self.parentWidget = parentWidget self.parentWidget = parentWidget
self.widgetDatabaseProperties = widgetDatabaseProperties self.widgetDatabaseProperties = widgetDatabaseProperties
self.entry = gtk.Entry() self.entry = gtk.Entry()
self.button = gtk.Button('...') self.button = gtk.Button('...')
self.button.connect('clicked', self.on_button_clicked) self.button.connect('clicked', self.on_button_clicked)
# layout widgets # layout widgets
self.pack_start(self.entry, True, True) self.pack_start(self.entry, True, True)
self.pack_start(self.button, False, False) self.pack_start(self.button, False, False)
def get_filename(self): def get_filename(self):
return self.entry.get_text() return self.entry.get_text()
def set_filename(self, name): def set_filename(self, name):
self.entry.set_text(name) self.entry.set_text(name)
def on_button_clicked(self, button): def on_button_clicked(self, button):
if self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeAdd: if self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeAdd:
action = gtk.FILE_CHOOSER_ACTION_OPEN action = gtk.FILE_CHOOSER_ACTION_OPEN
@ -283,13 +283,13 @@ class WidgetDatabaseProperties(gtk.VBox):
else: else:
raise ValueError('unsupported dialog mode') raise ValueError('unsupported dialog mode')
dlg = gtk.FileChooserDialog( dlg = gtk.FileChooserDialog(
title='Choose an exiting database file or type in name of a new one', title='Choose an exiting database file or type in name of a new one',
parent=self.parentWidget, parent=self.parentWidget,
action=action, action=action,
buttons=( buttons=(
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_OK, gtk.RESPONSE_OK,
), ),
backend=None backend=None
) )
dlg.set_default_response(gtk.RESPONSE_OK) dlg.set_default_response(gtk.RESPONSE_OK)
@ -298,8 +298,8 @@ class WidgetDatabaseProperties(gtk.VBox):
fileName = dlg.get_filename() fileName = dlg.get_filename()
self.set_filename(fileName) self.set_filename(fileName)
dlg.destroy() dlg.destroy()
#TODO: bit ugly this thingy. try to find a better way to map database attrs to gtk widgets #TODO: bit ugly this thingy. try to find a better way to map database attrs to gtk widgets
class FieldWidget(object): class FieldWidget(object):
def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''): def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''):
@ -310,15 +310,15 @@ class WidgetDatabaseProperties(gtk.VBox):
self._attrDatabase = attrDatabase self._attrDatabase = attrDatabase
self._widget = widget self._widget = widget
self._defaultValue = defaultValue self._defaultValue = defaultValue
self._attrGetter=None, self._attrGetter=None,
self._attrGet = attrGet self._attrGet = attrGet
self._attrSet = attrSet self._attrSet = attrSet
self._canEdit = canEdit self._canEdit = canEdit
self._label.set_tooltip_text(tooltip) self._label.set_tooltip_text(tooltip)
self._widget.set_tooltip_text(tooltip) self._widget.set_tooltip_text(tooltip)
def widget(self): def widget(self):
return self._widget return self._widget
def label(self): def label(self):
return self._label return self._label
@ -335,10 +335,10 @@ class WidgetDatabaseProperties(gtk.VBox):
setattr(database, self._attrDatabase, getattr(self._widget, self._attrGet)() ) setattr(database, self._attrDatabase, getattr(self._widget, self._attrGet)() )
def reset_value(self): def reset_value(self):
getattr(self._widget, self._attrSet)(self._defaultValue) getattr(self._widget, self._attrSet)(self._defaultValue)
def __init__(self, databaseManager, database, mode=ModeEdit, parentWidget=None): def __init__(self, databaseManager, database, mode=ModeEdit, parentWidget=None):
gtk.VBox.__init__(self) gtk.VBox.__init__(self)
self.databaseManager = databaseManager self.databaseManager = databaseManager
self.database = database self.database = database
self.mode = mode self.mode = mode
@ -346,76 +346,76 @@ class WidgetDatabaseProperties(gtk.VBox):
self.fieldWidgets = ( self.fieldWidgets = (
self.FieldWidget( self.FieldWidget(
text='Name:', text='Name:',
attrDatabase='name', attrDatabase='name',
widget=gtk.Entry(), widget=gtk.Entry(),
defaultValue='', defaultValue='',
attrGet='get_text', attrGet='get_text',
attrSet='set_text', attrSet='set_text',
canEdit=True, canEdit=True,
tooltip='Any name you like to name the database ' tooltip='Any name you like to name the database '
), ),
self.FieldWidget( self.FieldWidget(
text='File:', text='File:',
attrDatabase='file', attrDatabase='file',
widget=self.SqLiteFileChooserButton(self, self.parentWidget), widget=self.SqLiteFileChooserButton(self, self.parentWidget),
defaultValue='', defaultValue='',
attrGet='get_filename', attrGet='get_filename',
attrSet='set_filename', attrSet='set_filename',
canEdit=False, canEdit=False,
tooltip='Fully qualified path of the file to hold the database ' tooltip='Fully qualified path of the file to hold the database '
), ),
self.FieldWidget( self.FieldWidget(
text='Host:', text='Host:',
attrDatabase='host', attrDatabase='host',
widget=gtk.Entry(), widget=gtk.Entry(),
defaultValue='', defaultValue='',
attrGet='get_text', attrGet='get_text',
attrSet='set_text', attrSet='set_text',
canEdit=False, canEdit=False,
tooltip='Host the database is located at' tooltip='Host the database is located at'
), ),
self.FieldWidget( self.FieldWidget(
text='Port:', text='Port:',
attrDatabase='port', attrDatabase='port',
widget=gtk.SpinButton(adjustment=gtk.Adjustment(value=0, lower=0, upper=999999, step_incr=1, page_incr=10) ), widget=gtk.SpinButton(adjustment=gtk.Adjustment(value=0, lower=0, upper=999999, step_incr=1, page_incr=10) ),
defaultValue=0, defaultValue=0,
attrGet='get_value', attrGet='get_value',
attrSet='set_value', attrSet='set_value',
canEdit=False, canEdit=False,
tooltip='Port to use to connect to the host' tooltip='Port to use to connect to the host'
), ),
self.FieldWidget( self.FieldWidget(
text='User:', text='User:',
attrDatabase='user', attrDatabase='user',
widget=gtk.Entry(), widget=gtk.Entry(),
defaultValue='', defaultValue='',
attrGet='get_text', attrGet='get_text',
attrSet='set_text', attrSet='set_text',
canEdit=False, canEdit=False,
tooltip='User name used to login to the host' tooltip='User name used to login to the host'
), ),
self.FieldWidget( self.FieldWidget(
text='Pwd:', text='Pwd:',
attrDatabase='password', attrDatabase='password',
widget=gtk.Entry(), widget=gtk.Entry(),
defaultValue='', defaultValue='',
attrGet='get_text', attrGet='get_text',
attrSet='set_text', attrSet='set_text',
canEdit=False, canEdit=False,
tooltip='Password used to login to the host' tooltip='Password used to login to the host'
), ),
self.FieldWidget( self.FieldWidget(
text='Db:', text='Db:',
attrDatabase='database', attrDatabase='database',
widget=gtk.Entry(), widget=gtk.Entry(),
defaultValue='', defaultValue='',
attrGet='get_text', attrGet='get_text',
attrSet='set_text', attrSet='set_text',
canEdit=False, canEdit=False,
tooltip='Name of the database' tooltip='Name of the database'
), ),
) )
# setup database type combo # setup database type combo
self.comboType = gtk.ComboBox() self.comboType = gtk.ComboBox()
listStore= gtk.ListStore(str, str) listStore= gtk.ListStore(str, str)
@ -424,7 +424,7 @@ class WidgetDatabaseProperties(gtk.VBox):
self.comboType.pack_start(cell, True) self.comboType.pack_start(cell, True)
self.comboType.add_attribute(cell, 'text', 0) self.comboType.add_attribute(cell, 'text', 0)
self.comboType.connect('changed', self.on_combo_type_changed) self.comboType.connect('changed', self.on_combo_type_changed)
# fill database type combo with available database klasses. we store (databaseDisplayName, databaseType) in our model for later lookup # fill database type combo with available database klasses. we store (databaseDisplayName, databaseType) in our model for later lookup
iCurrentDatabase = 0 iCurrentDatabase = 0
databaseTypes = [(klass.display_name(), klass.Type) for klass in databaseManager.DatabaseTypes.values()] databaseTypes = [(klass.display_name(), klass.Type) for klass in databaseManager.DatabaseTypes.values()]
@ -435,7 +435,7 @@ class WidgetDatabaseProperties(gtk.VBox):
iCurrentDatabase = i iCurrentDatabase = i
if self.mode == self.ModeEdit or len(databaseTypes) < 2: if self.mode == self.ModeEdit or len(databaseTypes) < 2:
self.comboType.set_button_sensitivity(gtk.SENSITIVITY_OFF) self.comboType.set_button_sensitivity(gtk.SENSITIVITY_OFF)
# init and layout field widgets # init and layout field widgets
self.pack_start(self.comboType, False, False, 2) self.pack_start(self.comboType, False, False, 2)
table = gtk.Table(rows=len(self.fieldWidgets) +1, columns=2, homogeneous=False) table = gtk.Table(rows=len(self.fieldWidgets) +1, columns=2, homogeneous=False)
@ -443,11 +443,11 @@ class WidgetDatabaseProperties(gtk.VBox):
for i,fieldWidget in enumerate(self.fieldWidgets): for i,fieldWidget in enumerate(self.fieldWidgets):
table.attach(fieldWidget.label(), 0, 1, i, i+1, xoptions=gtk.FILL) table.attach(fieldWidget.label(), 0, 1, i, i+1, xoptions=gtk.FILL)
table.attach(fieldWidget.widget(), 1, 2, i, i+1) table.attach(fieldWidget.widget(), 1, 2, i, i+1)
# init widget # init widget
self.comboType.set_active(iCurrentDatabase) self.comboType.set_active(iCurrentDatabase)
self._adjust_widgets(self.database) self._adjust_widgets(self.database)
def _adjust_widgets(self, database): def _adjust_widgets(self, database):
for fieldWidget in self.fieldWidgets: for fieldWidget in self.fieldWidgets:
isSensitive = fieldWidget.is_sensitive(database) isSensitive = fieldWidget.is_sensitive(database)
@ -458,24 +458,24 @@ class WidgetDatabaseProperties(gtk.VBox):
if self.mode == self.ModeEdit: if self.mode == self.ModeEdit:
isSensitive = isSensitive and fieldWidget.can_edit() isSensitive = isSensitive and fieldWidget.can_edit()
fieldWidget.set_sensitive(isSensitive) fieldWidget.set_sensitive(isSensitive)
def on_combo_type_changed(self, combo): def on_combo_type_changed(self, combo):
i = self.comboType.get_active() i = self.comboType.get_active()
if i < 0: if i < 0:
return return
# check if we need to init a new database # check if we need to init a new database
currentDatabaseType = self.comboType.get_model()[i][1] currentDatabaseType = self.comboType.get_model()[i][1]
if currentDatabaseType == self.database.Type: if currentDatabaseType == self.database.Type:
return return
# create new empty database # create new empty database
#NOTE: we dont register it in DatabaseManager #NOTE: we dont register it in DatabaseManager
self.database = self.databaseManager.DatabaseTypes[currentDatabaseType]() self.database = self.databaseManager.DatabaseTypes[currentDatabaseType]()
self._adjust_widgets(self.database) self._adjust_widgets(self.database)
def get_database(self): def get_database(self):
for fieldWidget in self.fieldWidgets: for fieldWidget in self.fieldWidgets:
if fieldWidget.is_sensitive(self.database): if fieldWidget.is_sensitive(self.database):
@ -486,7 +486,7 @@ class WidgetDatabaseProperties(gtk.VBox):
class DialogDatabaseProperties(gtk.Dialog): class DialogDatabaseProperties(gtk.Dialog):
def __init__(self, databaseManager, database, parent=None, mode=WidgetDatabaseProperties.ModeEdit, title=''): def __init__(self, databaseManager, database, parent=None, mode=WidgetDatabaseProperties.ModeEdit, title=''):
gtk.Dialog.__init__(self, gtk.Dialog.__init__(self,
title=title, title=title,
parent=parent, parent=parent,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
buttons=( buttons=(
@ -495,7 +495,7 @@ class DialogDatabaseProperties(gtk.Dialog):
) )
) )
self.connect('response', self.on_dialog_response) self.connect('response', self.on_dialog_response)
# setup widget # setup widget
self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database, mode=mode, parentWidget=self) self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database, mode=mode, parentWidget=self)
self.vbox.pack_start(self.widgetDatabaseProperties, True, True) self.vbox.pack_start(self.widgetDatabaseProperties, True, True)
@ -503,23 +503,23 @@ class DialogDatabaseProperties(gtk.Dialog):
def get_widget_database_properties(self): def get_widget_database_properties(self):
return self.widgetDatabaseProperties return self.widgetDatabaseProperties
def on_dialog_response(self, dlg, responseId): def on_dialog_response(self, dlg, responseId):
if responseId == gtk.RESPONSE_REJECT: if responseId == gtk.RESPONSE_REJECT:
pass pass
elif responseId == gtk.RESPONSE_ACCEPT: elif responseId == gtk.RESPONSE_ACCEPT:
pass pass
#TODO: derrive from gtk.VBox?
#TODO: derrive from gtk.VBox?
# ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete # ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete
class WidgetDatabaseManager(gtk.VBox): class WidgetDatabaseManager(gtk.VBox):
""" """
""" """
def __init__(self, databaseManager, parentWidget=None): def __init__(self, databaseManager, parentWidget=None):
gtk.VBox.__init__(self) gtk.VBox.__init__(self)
self.parentWidget = parentWidget self.parentWidget = parentWidget
self.databaseManager = databaseManager self.databaseManager = databaseManager
self.databaseManager.connect('database-activated', self.on_database_manager_database_activated) self.databaseManager.connect('database-activated', self.on_database_manager_database_activated)
@ -529,17 +529,17 @@ class WidgetDatabaseManager(gtk.VBox):
DatabaseTypeBase.StatusInactive: 'Inactive', DatabaseTypeBase.StatusInactive: 'Inactive',
DatabaseTypeBase.StatusError: 'Error', DatabaseTypeBase.StatusError: 'Error',
} }
#TODO: dono how to make word wrap work as expected #TODO: dono how to make word wrap work as expected
self.labelInfo = gtk.Label('database management') self.labelInfo = gtk.Label('database management')
self.labelInfo.set_line_wrap(True) self.labelInfo.set_line_wrap(True)
self.labelInfo.set_selectable(True) self.labelInfo.set_selectable(True)
self.labelInfo.set_single_line_mode(False) self.labelInfo.set_single_line_mode(False)
self.labelInfo.set_alignment(0, 0) self.labelInfo.set_alignment(0, 0)
# database management buttons # database management buttons
#TODO: bit messy the distinction New/Add/Edit. we'd have to pass three flags to DialogDatabaseProperties #TODO: bit messy the distinction New/Add/Edit. we'd have to pass three flags to DialogDatabaseProperties
# to handle this. maybe drop Edit (is just a Remove + Add), to keep things simple # to handle this. maybe drop Edit (is just a Remove + Add), to keep things simple
self.buttonDatabaseActivate = gtk.Button("Activate") self.buttonDatabaseActivate = gtk.Button("Activate")
@ -560,13 +560,13 @@ class WidgetDatabaseManager(gtk.VBox):
self.buttonDatabaseRemove.set_tooltip_text('removes the database from the list') self.buttonDatabaseRemove.set_tooltip_text('removes the database from the list')
self.buttonDatabaseRemove.set_sensitive(False) self.buttonDatabaseRemove.set_sensitive(False)
self.buttonDatabaseRemove.connect('clicked', self.on_button_database_remove_clicked) self.buttonDatabaseRemove.connect('clicked', self.on_button_database_remove_clicked)
#TODO: i dont think we should do any real database management here. maybe drop it #TODO: i dont think we should do any real database management here. maybe drop it
#self.buttonDatabaseDelete = gtk.Button("Delete") #self.buttonDatabaseDelete = gtk.Button("Delete")
#self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it') #self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it')
#self.buttonDatabaseDelete.set_sensitive(False) #self.buttonDatabaseDelete.set_sensitive(False)
# init database tree # init database tree
self.treeDatabases = gtk.TreeView() self.treeDatabases = gtk.TreeView()
treeDatabaseColumns = ( # name, displayName, dataType treeDatabaseColumns = ( # name, displayName, dataType
('name', 'Name', str), ('name', 'Name', str),
@ -584,7 +584,7 @@ class WidgetDatabaseManager(gtk.VBox):
col.set_visible(False) col.set_visible(False)
self.treeDatabaseColumns[name] = i self.treeDatabaseColumns[name] = i
self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed) self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed)
# layout widgets # layout widgets
vbox = gtk.VBox(self) vbox = gtk.VBox(self)
vbox.pack_start(self.labelInfo, False, False, 2) vbox.pack_start(self.labelInfo, False, False, 2)
@ -602,12 +602,12 @@ class WidgetDatabaseManager(gtk.VBox):
#vbox.pack_start(self.buttonDatabaseDelete, False, False, 2) #vbox.pack_start(self.buttonDatabaseDelete, False, False, 2)
box = gtk.VBox() box = gtk.VBox()
vbox.pack_start(box, True, True, 0) vbox.pack_start(box, True, True, 0)
hbox.pack_start(gtk.VSeparator(), False, False, 2) hbox.pack_start(gtk.VSeparator(), False, False, 2)
hbox.pack_end(self.treeDatabases, True, True, 2) hbox.pack_end(self.treeDatabases, True, True, 2)
self.show_all() self.show_all()
# init widget # init widget
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
for database in self.databaseManager: for database in self.databaseManager:
@ -616,8 +616,8 @@ class WidgetDatabaseManager(gtk.VBox):
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] ) model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() ) model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database)) model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
def on_database_manager_database_activated(self, databaseManager, idDatabase): def on_database_manager_database_activated(self, databaseManager, idDatabase):
database = self.databaseManager.database_from_id(idDatabase) database = self.databaseManager.database_from_id(idDatabase)
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
@ -627,8 +627,8 @@ class WidgetDatabaseManager(gtk.VBox):
break break
else: else:
raise ValueError('database not found') raise ValueError('database not found')
def on_database_manager_database_deactivated(self, databaseManager, idDatabase): def on_database_manager_database_deactivated(self, databaseManager, idDatabase):
database = self.databaseManager.database_from_id(idDatabase) database = self.databaseManager.database_from_id(idDatabase)
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
@ -638,31 +638,31 @@ class WidgetDatabaseManager(gtk.VBox):
break break
else: else:
raise ValueError('database not found') raise ValueError('database not found')
def on_button_database_activate_clicked(self, button): def on_button_database_activate_clicked(self, button):
selection = self.treeDatabases.get_selection() selection = self.treeDatabases.get_selection()
if selection is None: if selection is None:
return return
model, it = selection.get_selected() model, it = selection.get_selected()
idDatabase = model.get_value(it, self.treeDatabaseColumns['_id']) idDatabase = model.get_value(it, self.treeDatabaseColumns['_id'])
database = self.databaseManager.database_from_id(idDatabase) database = self.databaseManager.database_from_id(idDatabase)
self.databaseManager.activate_database(database) self.databaseManager.activate_database(database)
#TODO: for some reason i have to click OK/Cancel twice to close the dialog #TODO: for some reason i have to click OK/Cancel twice to close the dialog
def on_button_database_new_clicked(self, button): def on_button_database_new_clicked(self, button):
databaseKlass = self.databaseManager.get_default_database_type() databaseKlass = self.databaseManager.get_default_database_type()
if databaseKlass is None: if databaseKlass is None:
raise ValueError('no default database type set') raise ValueError('no default database type set')
database = databaseKlass() database = databaseKlass()
while True: while True:
dlg = DialogDatabaseProperties( dlg = DialogDatabaseProperties(
self.databaseManager, self.databaseManager,
database, database,
parent=self.parentWidget, parent=self.parentWidget,
mode=WidgetDatabaseProperties.ModeNew, mode=WidgetDatabaseProperties.ModeNew,
title='New database' title='New database'
) )
@ -679,11 +679,11 @@ class WidgetDatabaseManager(gtk.VBox):
database = None database = None
dlg.destroy() dlg.destroy()
break break
if database is None: if database is None:
return return
self.databaseManager.add_database(database) self.databaseManager.add_database(database)
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
it = model.append() it = model.append()
@ -691,19 +691,19 @@ class WidgetDatabaseManager(gtk.VBox):
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] ) model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() ) model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database)) model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
def on_button_database_add_clicked(self, button): def on_button_database_add_clicked(self, button):
databaseKlass = self.databaseManager.get_default_database_type() databaseKlass = self.databaseManager.get_default_database_type()
if databaseKlass is None: if databaseKlass is None:
raise ValueError('no defult database type set') raise ValueError('no defult database type set')
database = databaseKlass() database = databaseKlass()
while True: while True:
dlg = DialogDatabaseProperties( dlg = DialogDatabaseProperties(
self.databaseManager, self.databaseManager,
database, database,
parent=self.parentWidget, parent=self.parentWidget,
mode=WidgetDatabaseProperties.ModeAdd, mode=WidgetDatabaseProperties.ModeAdd,
title='Add database' title='Add database'
) )
@ -719,11 +719,11 @@ class WidgetDatabaseManager(gtk.VBox):
else: else:
database = None database = None
dlg.destroy() dlg.destroy()
break break
if database is None: if database is None:
return return
self.databaseManager.add_database(database) self.databaseManager.add_database(database)
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
it = model.append() it = model.append()
@ -732,20 +732,20 @@ class WidgetDatabaseManager(gtk.VBox):
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() ) model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database)) model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
dlg.destroy() dlg.destroy()
def on_button_database_edit_clicked(self, button): def on_button_database_edit_clicked(self, button):
selection = self.treeDatabases.get_selection() selection = self.treeDatabases.get_selection()
if selection is None: if selection is None:
return return
model, it = selection.get_selected() model, it = selection.get_selected()
idDatabase = model.get_value(it, self.treeDatabaseColumns['_id']) idDatabase = model.get_value(it, self.treeDatabaseColumns['_id'])
database = self.databaseManager.database_from_id(idDatabase) database = self.databaseManager.database_from_id(idDatabase)
dlg = DialogDatabaseProperties( dlg = DialogDatabaseProperties(
self.databaseManager, self.databaseManager,
database, database,
parent=self.parentWidget, parent=self.parentWidget,
mode=WidgetDatabaseProperties.ModeEdit, mode=WidgetDatabaseProperties.ModeEdit,
title='Edit database' title='Edit database'
) )
response = dlg.run() response = dlg.run()
@ -759,31 +759,31 @@ class WidgetDatabaseManager(gtk.VBox):
model.set_value(it, self.treeDatabaseColumns['name'], database.name) model.set_value(it, self.treeDatabaseColumns['name'], database.name)
dlg.destroy() dlg.destroy()
def on_button_database_remove_clicked(self, button): def on_button_database_remove_clicked(self, button):
selection = self.treeDatabases.get_selection() selection = self.treeDatabases.get_selection()
if selection is None: if selection is None:
return return
model, it = selection.get_selected() model, it = selection.get_selected()
#TODO: finalize database #TODO: finalize database
model.remove(it) model.remove(it)
def on_tree_databases_selection_changed(self, treeSelection): def on_tree_databases_selection_changed(self, treeSelection):
hasSelection = bool(treeSelection.count_selected_rows()) hasSelection = bool(treeSelection.count_selected_rows())
# enable/disable selection dependend widgets # enable/disable selection dependend widgets
self.buttonDatabaseActivate.set_sensitive(hasSelection) self.buttonDatabaseActivate.set_sensitive(hasSelection)
self.buttonDatabaseEdit.set_sensitive(hasSelection) self.buttonDatabaseEdit.set_sensitive(hasSelection)
self.buttonDatabaseRemove.set_sensitive(hasSelection) self.buttonDatabaseRemove.set_sensitive(hasSelection)
#self.buttonDatabaseDelete.set_sensitive(hasSelection) #self.buttonDatabaseDelete.set_sensitive(hasSelection)
class DialogDatabaseManager(gtk.Dialog): class DialogDatabaseManager(gtk.Dialog):
def __init__(self, databaseManager, parent=None): def __init__(self, databaseManager, parent=None):
gtk.Dialog.__init__(self, gtk.Dialog.__init__(self,
title="Databases", title="Databases",
parent=parent, parent=parent,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
buttons=( buttons=(
@ -794,11 +794,11 @@ class DialogDatabaseManager(gtk.Dialog):
self.widgetDatabaseManager = WidgetDatabaseManager(databaseManager, parentWidget=self) self.widgetDatabaseManager = WidgetDatabaseManager(databaseManager, parentWidget=self)
self.vbox.pack_start(self.widgetDatabaseManager, True, True) self.vbox.pack_start(self.widgetDatabaseManager, True, True)
self.show_all() self.show_all()
#************************************************************************************************** #**************************************************************************************************
if __name__ == '__main__': if __name__ == '__main__':
databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite) databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite)
#d = DialogDatabaseProperties( #d = DialogDatabaseProperties(
# DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite), # DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite),
#database=DatabaseTypePostgres(), #database=DatabaseTypePostgres(),
@ -808,5 +808,3 @@ if __name__ == '__main__':
d.connect("destroy", gtk.main_quit) d.connect("destroy", gtk.main_quit)
d.run() d.run()
#gtk.main() #gtk.main()

View File

@ -18,7 +18,7 @@
#fpdb modules #fpdb modules
import Card import Card
DEBUG = True DEBUG = False
if DEBUG: if DEBUG:
import pprint import pprint
@ -39,8 +39,16 @@ class DerivedStats():
#Init vars that may not be used, but still need to be inserted. #Init vars that may not be used, but still need to be inserted.
# All stud street4 need this when importing holdem # All stud street4 need this when importing holdem
self.handsplayers[player[1]]['winnings'] = 0 self.handsplayers[player[1]]['winnings'] = 0
self.handsplayers[player[1]]['rake'] = 0
self.handsplayers[player[1]]['totalProfit'] = 0
self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Seen'] = False
self.handsplayers[player[1]]['street4Aggr'] = False self.handsplayers[player[1]]['street4Aggr'] = False
self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False
self.handsplayers[player[1]]['sawShowdown'] = False
self.handsplayers[player[1]]['wonAtSD'] = False
for i in range(5):
self.handsplayers[player[1]]['street%dCalls' % i] = 0
self.handsplayers[player[1]]['street%dBets' % i] = 0
self.assembleHands(self.hand) self.assembleHands(self.hand)
self.assembleHandsPlayers(self.hand) self.assembleHandsPlayers(self.hand)
@ -81,12 +89,13 @@ class DerivedStats():
self.hands['boardcard5'] = cards[4] self.hands['boardcard5'] = cards[4]
#print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals() #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals()
#FIXME: Pot size still in decimal, needs to be converted to cents totals = hand.getStreetTotals()
(self.hands['street1Pot'], totals = [int(100*i) for i in totals]
self.hands['street2Pot'], self.hands['street1Pot'] = totals[0]
self.hands['street3Pot'], self.hands['street2Pot'] = totals[1]
self.hands['street4Pot'], self.hands['street3Pot'] = totals[2]
self.hands['showdownPot']) = hand.getStreetTotals() self.hands['street4Pot'] = totals[3]
self.hands['showdownPot'] = totals[4]
self.vpip(hand) # Gives playersVpi (num of players vpip) self.vpip(hand) # Gives playersVpi (num of players vpip)
#print "DEBUG: vpip: %s" %(self.hands['playersVpi']) #print "DEBUG: vpip: %s" %(self.hands['playersVpi'])
@ -94,27 +103,62 @@ class DerivedStats():
#print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4']) #print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4'])
self.streetXRaises(hand) # Empty function currently self.streetXRaises(hand) # Empty function currently
# comment TEXT,
# commentTs DATETIME
def assembleHandsPlayers(self, hand): def assembleHandsPlayers(self, hand):
#street0VPI/vpip already called in Hand #street0VPI/vpip already called in Hand
# sawShowdown is calculated in playersAtStreetX, as that calculation gives us a convenient list of names
#hand.players = [[seat, name, chips],[seat, name, chips]] #hand.players = [[seat, name, chips],[seat, name, chips]]
for player in hand.players: for player in hand.players:
self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = player[2] self.handsplayers[player[1]]['startCash'] = player[2]
# Winnings is a non-negative value of money collected from the pot, which already includes the
# rake taken out. hand.collectees is Decimal, database requires cents
for player in hand.collectees:
self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player])
for i, street in enumerate(hand.actionStreets[2:]): for i, street in enumerate(hand.actionStreets[2:]):
self.seen(self.hand, i+1) self.seen(self.hand, i+1)
for i, street in enumerate(hand.actionStreets[1:]): for i, street in enumerate(hand.actionStreets[1:]):
self.aggr(self.hand, i) self.aggr(self.hand, i)
self.calls(self.hand, i)
self.bets(self.hand, i)
# Winnings is a non-negative value of money collected from the pot, which already includes the
# rake taken out. hand.collectees is Decimal, database requires cents
for player in hand.collectees:
self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player])
#FIXME: This is pretty dodgy, rake = hand.rake/#collectees
# You can really only pay rake when you collect money, but
# different sites calculate rake differently.
# Should be fine for split-pots, but won't be accurate for multi-way pots
self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees)
if self.handsplayers[player]['street1Seen'] == True:
self.handsplayers[player]['wonWhenSeenStreet1'] = True
if self.handsplayers[player]['sawShowdown'] == True:
self.handsplayers[player]['wonAtSD'] = True
for player in hand.pot.committed:
self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player]))
#default_holecards = ["Xx", "Xx", "Xx", "Xx"]
#if hand.gametype['base'] == "hold":
# pass
#elif hand.gametype['base'] == "stud":
# pass
#else:
# # Flop hopefully...
# pass
for street in hand.holeStreets:
for player in hand.players:
for i in range(1,8): self.handsplayers[player[1]]['card%d' % i] = 0
#print "DEBUG: hand.holecards[%s]: %s" % (street, hand.holecards[street])
if player[1] in hand.holecards[street].keys() and hand.gametype['base'] == "hold":
self.handsplayers[player[1]]['card1'] = Card.encodeCard(hand.holecards[street][player[1]][1][0])
self.handsplayers[player[1]]['card2'] = Card.encodeCard(hand.holecards[street][player[1]][1][1])
try:
self.handsplayers[player[1]]['card3'] = Card.encodeCard(hand.holecards[street][player[1]][1][2])
self.handsplayers[player[1]]['card4'] = Card.encodeCard(hand.holecards[street][player[1]][1][3])
except IndexError:
# Just means no player cards for that street/game - continue
pass
def assembleHudCache(self, hand): def assembleHudCache(self, hand):
pass pass
@ -147,14 +191,23 @@ class DerivedStats():
self.hands['playersAtStreet4'] = 0 self.hands['playersAtStreet4'] = 0
self.hands['playersAtShowdown'] = 0 self.hands['playersAtShowdown'] = 0
alliners = set()
for (i, street) in enumerate(hand.actionStreets[2:]): for (i, street) in enumerate(hand.actionStreets[2:]):
actors = {} actors = set()
for act in hand.actions[street]: for action in hand.actions[street]:
actors[act[0]] = 1 if len(action) > 2 and action[-1]: # allin
self.hands['playersAtStreet%s' % str(i+1)] = len(actors.keys()) alliners.add(action[0])
actors.add(action[0])
if len(actors)==0 and len(alliners)<2:
alliners = set()
self.hands['playersAtStreet%d' % (i+1)] = len(set.union(alliners, actors))
#Need playersAtShowdown actions = hand.actions[hand.actionStreets[-1]]
pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)
self.hands['playersAtShowdown'] = len(pas)
for player in pas:
self.handsplayers[player]['sawShowdown'] = True
def streetXRaises(self, hand): def streetXRaises(self, hand):
# self.actions[street] is a list of all actions in a tuple, contining the action as the second element # self.actions[street] is a list of all actions in a tuple, contining the action as the second element
@ -162,11 +215,11 @@ class DerivedStats():
# No idea what this value is actually supposed to be # No idea what this value is actually supposed to be
# In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl
# Leaving empty for the moment, # Leaving empty for the moment,
self.hands['street0Raises'] = 0 # /* num small bets paid to see flop/street4, including blind */
self.hands['street1Raises'] = 0 # /* num small bets paid to see turn/street5 */ for i in range(5): self.hands['street%dRaises' % i] = 0
self.hands['street2Raises'] = 0 # /* num big bets paid to see river/street6 */
self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */ for (i, street) in enumerate(hand.actionStreets[1:]):
self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */ self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street]))
def seen(self, hand, i): def seen(self, hand, i):
pas = set() pas = set()
@ -191,5 +244,32 @@ class DerivedStats():
else: else:
self.handsplayers[player[1]]['street%sAggr' % i] = False self.handsplayers[player[1]]['street%sAggr' % i] = False
def calls(self, hand, i):
callers = []
for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('calls'):
self.handsplayers[act[0]]['street%sCalls' % i] = 1 + self.handsplayers[act[0]]['street%sCalls' % i]
# CG - I'm sure this stat is wrong
# Best guess is that raise = 2 bets
def bets(self, hand, i):
betters = []
for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('bets'):
self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i]
def countPlayers(self, hand): def countPlayers(self, hand):
pass pass
def pfba(self, actions, f=None, l=None):
"""Helper method. Returns set of PlayersFilteredByActions
f - forbidden actions
l - limited to actions
"""
players = set()
for action in actions:
if l is not None and action[1] not in l: continue
if f is not None and action[1] in f: continue
players.add(action[0])
return players

View File

@ -4,7 +4,7 @@ class FpdbError(Exception):
def __str__(self): def __str__(self):
return repr(self.value) return repr(self.value)
class FpdbParseError(FpdbError): class FpdbParseError(FpdbError):
def __init__(self,value='',hid=''): def __init__(self,value='',hid=''):
self.value = value self.value = value
self.hid = hid self.hid = hid
@ -17,8 +17,15 @@ class FpdbParseError(FpdbError):
class FpdbDatabaseError(FpdbError): class FpdbDatabaseError(FpdbError):
pass pass
class FpdbMySQLFailedError(FpdbDatabaseError): class FpdbMySQLError(FpdbDatabaseError):
pass pass
class FpdbMySQLAccessDenied(FpdbDatabaseError):
def __init__(self, value='', errmsg=''):
self.value = value
self.errmsg = errmsg
def __str__(self):
return repr(self.value +" " + self.errmsg)
class DuplicateError(FpdbError): class DuplicateError(FpdbError):
pass pass

View File

@ -69,7 +69,7 @@ class Filters(threading.Thread):
self.sbGroups = {} self.sbGroups = {}
self.numHands = 0 self.numHands = 0
# Outer Packing box # Outer Packing box
self.mainVBox = gtk.VBox(False, 0) self.mainVBox = gtk.VBox(False, 0)
playerFrame = gtk.Frame("Hero:") playerFrame = gtk.Frame("Hero:")
@ -334,7 +334,7 @@ class Filters(threading.Thread):
elif limit == "fl": elif limit == "fl":
if not self.limits[limit]: if not self.limits[limit]:
# only toggle all fl limits off if they are all currently on # only toggle all fl limits off if they are all currently on
# this stops turning one off from cascading into 'fl' box off # this stops turning one off from cascading into 'fl' box off
# and then all fl limits being turned off # and then all fl limits being turned off
all_fl_on = True all_fl_on = True
for cb in self.cbLimits.values(): for cb in self.cbLimits.values():
@ -361,7 +361,7 @@ class Filters(threading.Thread):
elif limit == "nl": elif limit == "nl":
if not self.limits[limit]: if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on # only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off # this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off # and then all nl limits being turned off
all_nl_on = True all_nl_on = True
for cb in self.cbLimits.values(): for cb in self.cbLimits.values():
@ -733,11 +733,11 @@ def main(argv=None):
gtk.main_quit() gtk.main_quit()
parser = OptionParser() parser = OptionParser()
(options, sys.argv) = parser.parse_args(args = argv) (options, argv) = parser.parse_args(args = argv)
config = Configuration.Config() config = Configuration.Config()
db = None db = None
db = fpdb_db.fpdb_db() db = fpdb_db.fpdb_db()
db.do_connect(config) db.do_connect(config)
@ -752,5 +752,3 @@ def main(argv=None):
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@ -53,7 +53,7 @@ class GuiAutoImport (threading.Thread):
self.importer.setFailOnError(False) self.importer.setFailOnError(False)
self.importer.setHandCount(0) self.importer.setHandCount(0)
# self.importer.setWatchTime() # self.importer.setWatchTime()
self.server = settings['db-host'] self.server = settings['db-host']
self.user = settings['db-user'] self.user = settings['db-user']
self.password = settings['db-password'] self.password = settings['db-password']
@ -63,7 +63,7 @@ class GuiAutoImport (threading.Thread):
hbox = gtk.HBox(True, 0) # contains 2 equal vboxes hbox = gtk.HBox(True, 0) # contains 2 equal vboxes
self.mainVBox.pack_start(hbox, False, False, 0) self.mainVBox.pack_start(hbox, False, False, 0)
vbox1 = gtk.VBox(True, 0) vbox1 = gtk.VBox(True, 0)
hbox.pack_start(vbox1, True, True, 0) hbox.pack_start(vbox1, True, True, 0)
vbox2 = gtk.VBox(True, 0) vbox2 = gtk.VBox(True, 0)
@ -144,13 +144,13 @@ class GuiAutoImport (threading.Thread):
gobject.timeout_add(1000, self.reset_startbutton) gobject.timeout_add(1000, self.reset_startbutton)
return True return True
return False return False
def reset_startbutton(self): def reset_startbutton(self):
if self.pipe_to_hud is not None: if self.pipe_to_hud is not None:
self.startButton.set_label(u' _Stop Autoimport ') self.startButton.set_label(u' _Stop Autoimport ')
else: else:
self.startButton.set_label(u' _Start Autoimport ') self.startButton.set_label(u' _Start Autoimport ')
return False return False
@ -169,7 +169,7 @@ class GuiAutoImport (threading.Thread):
if widget.get_active(): # toggled on if widget.get_active(): # toggled on
# - Does the lock acquisition need to be more sophisticated for multiple dirs? # - Does the lock acquisition need to be more sophisticated for multiple dirs?
# (see comment above about what to do if pipe already open) # (see comment above about what to do if pipe already open)
# - Ideally we want to release the lock if the auto-import is killed by some # - Ideally we want to release the lock if the auto-import is killed by some
# kind of exception - is this possible? # kind of exception - is this possible?
if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired
print "\nGlobal lock taken ..." print "\nGlobal lock taken ..."
@ -183,7 +183,7 @@ class GuiAutoImport (threading.Thread):
command = os.path.join(sys.path[0], 'HUD_main.py') command = os.path.join(sys.path[0], 'HUD_main.py')
command = [command, ] + string.split(self.settings['cl_options']) command = [command, ] + string.split(self.settings['cl_options'])
bs = 1 bs = 1
try: try:
self.pipe_to_hud = subprocess.Popen(command, bufsize=bs, self.pipe_to_hud = subprocess.Popen(command, bufsize=bs,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
@ -191,17 +191,17 @@ class GuiAutoImport (threading.Thread):
except: except:
err = traceback.extract_tb(sys.exc_info()[2])[-1] err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "*** GuiAutoImport Error opening pipe: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) print "*** GuiAutoImport Error opening pipe: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
else: else:
for site in self.input_settings: for site in self.input_settings:
self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1]) self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1])
print " * Add", site, " import directory", str(self.input_settings[site][0]) print " * Add", site, " import directory", str(self.input_settings[site][0])
print "+Import directory - Site: " + site + " dir: " + str(self.input_settings[site][0]) print "+Import directory - Site: " + site + " dir: " + str(self.input_settings[site][0])
self.do_import() self.do_import()
interval = int(self.intervalEntry.get_text()) interval = int(self.intervalEntry.get_text())
if self.importtimer != 0: if self.importtimer != 0:
gobject.source_remove(self.importtimer) gobject.source_remove(self.importtimer)
self.importtimer = gobject.timeout_add(interval * 1000, self.do_import) self.importtimer = gobject.timeout_add(interval * 1000, self.do_import)
else: else:
print "auto-import aborted - global lock not available" print "auto-import aborted - global lock not available"
else: # toggled off else: # toggled off
@ -258,7 +258,7 @@ class GuiAutoImport (threading.Thread):
vbox1.pack_start(pathHBox1, False, True, 0) vbox1.pack_start(pathHBox1, False, True, 0)
pathHBox2 = gtk.HBox(False, 0) pathHBox2 = gtk.HBox(False, 0)
vbox2.pack_start(pathHBox2, False, True, 0) vbox2.pack_start(pathHBox2, False, True, 0)
params = self.config.get_site_parameters(site) params = self.config.get_site_parameters(site)
paths = self.config.get_default_paths(site) paths = self.config.get_default_paths(site)
self.createSiteLine(pathHBox1, pathHBox2, site, False, paths['hud-defaultPath'], params['converter'], params['enabled']) self.createSiteLine(pathHBox1, pathHBox2, site, False, paths['hud-defaultPath'], params['converter'], params['enabled'])
@ -281,7 +281,7 @@ if __name__== "__main__":
parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, help="don't start gui") parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, help="don't start gui")
parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int", parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int",
help="How often to print a one-line status report (0 (default) means never)") help="How often to print a one-line status report (0 (default) means never)")
(options, sys.argv) = parser.parse_args() (options, argv) = parser.parse_args()
config = Configuration.Config() config = Configuration.Config()
# db = fpdb_db.fpdb_db() # db = fpdb_db.fpdb_db()
@ -305,4 +305,3 @@ if __name__== "__main__":
gtk.main() gtk.main()
else: else:
pass pass

View File

@ -43,7 +43,7 @@ class GuiBulkImport():
def dopulse(self): def dopulse(self):
self.progressbar.pulse() self.progressbar.pulse()
return True return True
def load_clicked(self, widget, data=None): def load_clicked(self, widget, data=None):
stored = None stored = None
dups = None dups = None
@ -58,9 +58,9 @@ class GuiBulkImport():
self.progressbar.set_text("Importing...") self.progressbar.set_text("Importing...")
self.progressbar.pulse() self.progressbar.pulse()
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7) while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
gtk.main_iteration(False) gtk.main_iteration(False)
self.timer = gobject.timeout_add(100, self.dopulse) self.timer = gobject.timeout_add(100, self.dopulse)
# get the dir to import from the chooser # get the dir to import from the chooser
selected = self.chooser.get_filenames() selected = self.chooser.get_filenames()
@ -87,7 +87,7 @@ class GuiBulkImport():
else: else:
self.importer.setDropHudCache("auto") self.importer.setDropHudCache("auto")
sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0] sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
for selection in selected: for selection in selected:
self.importer.addBulkImportImportFileOrDir(selection, site = sitename) self.importer.addBulkImportImportFileOrDir(selection, site = sitename)
self.importer.setCallHud(False) self.importer.setCallHud(False)
@ -99,7 +99,7 @@ class GuiBulkImport():
# raise Exceptions.FpdbError # raise Exceptions.FpdbError
# finally: # finally:
gobject.source_remove(self.timer) gobject.source_remove(self.timer)
ttime = time() - starttime ttime = time() - starttime
if ttime == 0: if ttime == 0:
ttime = 1 ttime = 1
@ -324,9 +324,9 @@ def main(argv=None):
help="If this option is passed it quits when it encounters any error") help="If this option is passed it quits when it encounters any error")
parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int", parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int",
help="How often to print a one-line status report (0 (default) means never)") help="How often to print a one-line status report (0 (default) means never)")
parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False, parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False,
help="Print some useful one liners") help="Print some useful one liners")
(options, sys.argv) = parser.parse_args(args = argv) (options, argv) = parser.parse_args(args = argv)
if options.usage == True: if options.usage == True:
#Print usage examples and exit #Print usage examples and exit
@ -339,7 +339,7 @@ def main(argv=None):
sys.exit(0) sys.exit(0)
config = Configuration.Config() config = Configuration.Config()
settings = {} settings = {}
settings['minPrint'] = options.minPrint settings['minPrint'] = options.minPrint
if os.name == 'nt': settings['os'] = 'windows' if os.name == 'nt': settings['os'] = 'windows'
@ -362,7 +362,7 @@ def main(argv=None):
gtk.main() gtk.main()
else: else:
#Do something useful #Do something useful
importer = fpdb_import.Importer(False,settings, config) importer = fpdb_import.Importer(False,settings, config)
# importer.setDropIndexes("auto") # importer.setDropIndexes("auto")
importer.setDropIndexes("don't drop") importer.setDropIndexes("don't drop")
importer.setFailOnError(options.failOnError) importer.setFailOnError(options.failOnError)
@ -377,4 +377,3 @@ def main(argv=None):
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@ -5,17 +5,17 @@
Main for FreePokerTools HUD. Main for FreePokerTools HUD.
""" """
# Copyright 2008, 2009, Ray E. Barker # Copyright 2008, 2009, Ray E. Barker
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -33,7 +33,7 @@ import os
import Options import Options
import traceback import traceback
(options, sys.argv) = Options.fpdb_options() (options, argv) = Options.fpdb_options()
if not options.errorsToConsole: if not options.errorsToConsole:
print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_."
@ -101,20 +101,20 @@ class HUD_main(object):
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, type, stat_dict, cards): def create_HUD(self, new_hand_id, table, table_name, max, poker_game, type, stat_dict, cards):
"""type is "ring" or "tour" used to set hud_params""" """type is "ring" or "tour" used to set hud_params"""
def idle_func(): def idle_func():
gtk.gdk.threads_enter() gtk.gdk.threads_enter()
try: # TODO: seriously need to decrease the scope of this block.. what are we expecting to error? try: # TODO: seriously need to decrease the scope of this block.. what are we expecting to error?
# TODO: The purpose of this try/finally block is to make darn sure that threads_leave() # TODO: The purpose of this try/finally block is to make darn sure that threads_leave()
# TODO: gets called. If there is an exception and threads_leave() doesn't get called we # TODO: gets called. If there is an exception and threads_leave() doesn't get called we
# TODO: lock up. REB # TODO: lock up. REB
table.gdkhandle = gtk.gdk.window_foreign_new(table.number) table.gdkhandle = gtk.gdk.window_foreign_new(table.number)
newlabel = gtk.Label("%s - %s" % (table.site, table_name)) newlabel = gtk.Label("%s - %s" % (table.site, table_name))
self.vb.add(newlabel) self.vb.add(newlabel)
newlabel.show() newlabel.show()
self.main_window.resize_children() self.main_window.resize_children()
self.hud_dict[table_name].tablehudlabel = newlabel self.hud_dict[table_name].tablehudlabel = newlabel
self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict, cards) self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict, cards)
for m in self.hud_dict[table_name].aux_windows: for m in self.hud_dict[table_name].aux_windows:
@ -151,23 +151,23 @@ class HUD_main(object):
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows] [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows]
gobject.idle_add(idle_func) gobject.idle_add(idle_func)
def update_HUD(self, new_hand_id, table_name, config): def update_HUD(self, new_hand_id, table_name, config):
"""Update a HUD gui from inside the non-gui read_stdin thread.""" """Update a HUD gui from inside the non-gui read_stdin thread."""
# This is written so that only 1 thread can touch the gui--mainly # This is written so that only 1 thread can touch the gui--mainly
# for compatibility with Windows. This method dispatches the # for compatibility with Windows. This method dispatches the
# function idle_func() to be run by the gui thread, at its leisure. # function idle_func() to be run by the gui thread, at its leisure.
def idle_func(): def idle_func():
gtk.gdk.threads_enter() gtk.gdk.threads_enter()
# try: # try:
self.hud_dict[table_name].update(new_hand_id, config) self.hud_dict[table_name].update(new_hand_id, config)
[aw.update_gui(new_hand_id) for aw in self.hud_dict[table_name].aux_windows] [aw.update_gui(new_hand_id) for aw in self.hud_dict[table_name].aux_windows]
# finally: # finally:
gtk.gdk.threads_leave() gtk.gdk.threads_leave()
return False return False
gobject.idle_add(idle_func) gobject.idle_add(idle_func)
def read_stdin(self): # This is the thread function def read_stdin(self): # This is the thread function
"""Do all the non-gui heavy lifting for the HUD program.""" """Do all the non-gui heavy lifting for the HUD program."""
@ -176,7 +176,7 @@ class HUD_main(object):
# need their own access to the database, but should open their own # need their own access to the database, but should open their own
# if it is required. # if it is required.
self.db_connection = Database.Database(self.config) self.db_connection = Database.Database(self.config)
# get hero's screen names and player ids # get hero's screen names and player ids
self.hero, self.hero_ids = {}, {} self.hero, self.hero_ids = {}, {}
for site in self.config.get_supported_sites(): for site in self.config.get_supported_sites():
@ -185,7 +185,7 @@ class HUD_main(object):
site_id = result[0][0] site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name self.hero[site_id] = self.config.supported_sites[site].screen_name
self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id]) self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id])
while 1: # wait for a new hand number on stdin while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline() new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id) new_hand_id = string.rstrip(new_hand_id)
@ -199,7 +199,7 @@ class HUD_main(object):
(table_name, max, poker_game, type, site_id, site_name, tour_number, tab_number) = \ (table_name, max, poker_game, type, site_id, site_name, tour_number, tab_number) = \
self.db_connection.get_table_info(new_hand_id) self.db_connection.get_table_info(new_hand_id)
except Exception, err: except Exception, err:
print "db error: skipping %s" % new_hand_id print "db error: skipping %s" % new_hand_id
sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id) sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id)
continue continue
@ -210,7 +210,7 @@ class HUD_main(object):
# Update an existing HUD # Update an existing HUD
if temp_key in self.hud_dict: if temp_key in self.hud_dict:
# get stats using hud's specific params and get cards # get stats using hud's specific params and get cards
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days']) , self.hud_dict[temp_key].hud_params['h_hud_days'])
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id]) stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
@ -222,7 +222,7 @@ class HUD_main(object):
self.hud_dict[temp_key].cards = cards self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config) self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD # Or create a new HUD
else: else:
# get stats using default params--also get cards # get stats using default params--also get cards

View File

@ -94,7 +94,7 @@ follow : whether to tail -f the input"""
else: else:
log.info("Created directory '%s'" % out_dir) log.info("Created directory '%s'" % out_dir)
try: try:
self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') self.out_fh = codecs.open(self.out_path, 'w', 'utf8')
except: except:
log.error("out_path %s couldn't be opened" % (self.out_path)) log.error("out_path %s couldn't be opened" % (self.out_path))
else: else:

View File

@ -23,26 +23,26 @@ def fpdb_options():
"""Process command line options for fpdb and HUD_main.""" """Process command line options for fpdb and HUD_main."""
parser = OptionParser() parser = OptionParser()
parser.add_option("-x", "--errorsToConsole", parser.add_option("-x", "--errorsToConsole",
action="store_true", action="store_true",
help="If passed error output will go to the console rather than .") help="If passed error output will go to the console rather than .")
parser.add_option("-d", "--databaseName", parser.add_option("-d", "--databaseName",
dest="dbname", default="fpdb", dest="dbname", default="fpdb",
help="Overrides the default database name") help="Overrides the default database name")
parser.add_option("-c", "--configFile", parser.add_option("-c", "--configFile",
dest="config", default=None, dest="config", default=None,
help="Specifies a configuration file.") help="Specifies a configuration file.")
parser.add_option("-r", "--rerunPython", parser.add_option("-r", "--rerunPython",
action="store_true", action="store_true",
help="Indicates program was restarted with a different path (only allowed once).") help="Indicates program was restarted with a different path (only allowed once).")
(options, sys.argv) = parser.parse_args() (options, argv) = parser.parse_args()
return (options, sys.argv) return (options, argv)
if __name__== "__main__": if __name__== "__main__":
(options, sys.argv) = fpdb_options() (options, argv) = fpdb_options()
print "errorsToConsole =", options.errorsToConsole print "errorsToConsole =", options.errorsToConsole
print "database name =", options.dbname print "database name =", options.dbname
print "config file =", options.config print "config file =", options.config
print "press enter to end" print "press enter to end"
sys.stdin.readline() sys.stdin.readline()

View File

@ -31,18 +31,18 @@ class PokerStars(HandHistoryConverter):
sitename = "PokerStars" sitename = "PokerStars"
filetype = "text" filetype = "text"
codepage = "cp1252" codepage = ("utf8", "cp1252")
siteId = 2 # Needs to match id entry in Sites database siteId = 2 # Needs to match id entry in Sites database
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games
sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\x80", "GBP": "\xa3"} # ADD Euro, Sterling, etc HERE sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\xe2\x82\xac", "GBP": "\xa3"} # ADD Euro, Sterling, etc HERE
substitutions = { substitutions = {
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes 'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
'LS' : "\$|\x80|\xa3" # legal currency symbols ADD Euro, Sterling, etc HERE 'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
} }
# Static regexes # Static regexes
re_GameInfo = re.compile(""" re_GameInfo = re.compile(u"""
PokerStars\sGame\s\#(?P<HID>[0-9]+):\s+ PokerStars\sGame\s\#(?P<HID>[0-9]+):\s+
(Tournament\s\# # open paren of tournament info (Tournament\s\# # open paren of tournament info
(?P<TOURNO>\d+),\s (?P<TOURNO>\d+),\s
@ -62,7 +62,7 @@ class PokerStars(HandHistoryConverter):
(?P<DATETIME>.*$)""" % substitutions, (?P<DATETIME>.*$)""" % substitutions,
re.MULTILINE|re.VERBOSE) re.MULTILINE|re.VERBOSE)
re_PlayerInfo = re.compile(""" re_PlayerInfo = re.compile(u"""
^Seat\s(?P<SEAT>[0-9]+):\s ^Seat\s(?P<SEAT>[0-9]+):\s
(?P<PNAME>.*)\s (?P<PNAME>.*)\s
\((%(LS)s)?(?P<CASH>[.0-9]+)\sin\schips\)""" % substitutions, \((%(LS)s)?(?P<CASH>[.0-9]+)\sin\schips\)""" % substitutions,
@ -373,12 +373,9 @@ if __name__ == "__main__":
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt") parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-") parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False) parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
parser.add_option("-q", "--quiet", #parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO) #parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
parser.add_option("-v", "--verbose", #parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
action="store_const", const=logging.INFO, dest="verbosity")
parser.add_option("--vv",
action="store_const", const=logging.DEBUG, dest="verbosity")
(options, args) = parser.parse_args() (options, args) = parser.parse_args()

View File

@ -3,17 +3,17 @@
Based on HUD_main .. who knows if we want to actually use this or not Based on HUD_main .. who knows if we want to actually use this or not
""" """
# Copyright 2008, 2009, Eric Blade # Copyright 2008, 2009, Eric Blade
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -31,7 +31,7 @@ import os
import Options import Options
import traceback import traceback
(options, sys.argv) = Options.fpdb_options() (options, argv) = Options.fpdb_options()
if not options.errorsToConsole: if not options.errorsToConsole:
print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_."
@ -55,7 +55,7 @@ import SummaryEverleaf
class Tournament: class Tournament:
"""Tournament will hold the information about a tournament, I guess ? Remember I'm new to this language, so I don't know the best ways to do things""" """Tournament will hold the information about a tournament, I guess ? Remember I'm new to this language, so I don't know the best ways to do things"""
def __init__(self, parent, site, tid): # site should probably be something in the config object, but i don't know how the config object works right now, so we're going to make it a str .. def __init__(self, parent, site, tid): # site should probably be something in the config object, but i don't know how the config object works right now, so we're going to make it a str ..
print "Tournament init" print "Tournament init"
self.parent = parent self.parent = parent
@ -74,7 +74,7 @@ class Tournament:
self.prizepool = 0 self.prizepool = 0
self.players = {} # eventually i'd guess we'd probably want to fill this with playername:playerid's self.players = {} # eventually i'd guess we'd probably want to fill this with playername:playerid's
self.results = {} # i'd guess we'd want to load this up with playerid's instead of playernames, too, as well, also self.results = {} # i'd guess we'd want to load this up with playerid's instead of playernames, too, as well, also
# if site == "Everleaf": # this should be attached to a button that says "retrieve tournament info" or something for sites that we know how to do it for # if site == "Everleaf": # this should be attached to a button that says "retrieve tournament info" or something for sites that we know how to do it for
summary = SummaryEverleaf.EverleafSummary() summary = SummaryEverleaf.EverleafSummary()
self.site = summary.parser.SiteName self.site = summary.parser.SiteName
@ -87,9 +87,9 @@ class Tournament:
self.rebuys = (summary.parser.TourneyRebuys == "yes") self.rebuys = (summary.parser.TourneyRebuys == "yes")
self.prizepool = summary.parser.TourneyPool self.prizepool = summary.parser.TourneyPool
self.numplayers = summary.parser.TourneyPlayers self.numplayers = summary.parser.TourneyPlayers
self.openwindow() # let's start by getting any info we need.. meh self.openwindow() # let's start by getting any info we need.. meh
def openwindow(self, widget=None): def openwindow(self, widget=None):
if self.window is not None: if self.window is not None:
self.window.show() # isn't there a better way to bring something to the front? not that GTK focus works right anyway, ever self.window.show() # isn't there a better way to bring something to the front? not that GTK focus works right anyway, ever
@ -102,24 +102,24 @@ class Tournament:
self.window.set_border_width(1) self.window.set_border_width(1)
self.window.set_default_size(480,640) self.window.set_default_size(480,640)
self.window.set_resizable(True) self.window.set_resizable(True)
self.main_vbox = gtk.VBox(False, 1) self.main_vbox = gtk.VBox(False, 1)
self.main_vbox.set_border_width(1) self.main_vbox.set_border_width(1)
self.window.add(self.main_vbox) self.window.add(self.main_vbox)
self.window.show() self.window.show()
def addrebuy(self, widget=None): def addrebuy(self, widget=None):
t = self t = self
t.numrebuys += 1 t.numrebuys += 1
t.mylabel.set_label("%s - %s - %s - %s - %s %s - %s - %s - %s - %s - %s" % (t.site, t.id, t.starttime, t.endtime, t.structure, t.game, t.buyin, t.fee, t.numrebuys, t.numplayers, t.prizepool)) t.mylabel.set_label("%s - %s - %s - %s - %s %s - %s - %s - %s - %s - %s" % (t.site, t.id, t.starttime, t.endtime, t.structure, t.game, t.buyin, t.fee, t.numrebuys, t.numplayers, t.prizepool))
def delete_event(self, widget, event, data=None): def delete_event(self, widget, event, data=None):
return False return False
def destroy(self, widget, data=None): def destroy(self, widget, data=None):
return False return False
#end def destroy #end def destroy
class ttracker_main(object): class ttracker_main(object):
"""A main() object to own both the read_stdin thread and the gui.""" """A main() object to own both the read_stdin thread and the gui."""
@ -143,11 +143,11 @@ class ttracker_main(object):
self.addbutton = gtk.Button(label="Enter Tournament") self.addbutton = gtk.Button(label="Enter Tournament")
self.addbutton.connect("clicked", self.addClicked, "add tournament") self.addbutton.connect("clicked", self.addClicked, "add tournament")
self.vb.add(self.addbutton) self.vb.add(self.addbutton)
self.main_window.add(self.vb) self.main_window.add(self.vb)
self.main_window.set_title("FPDB Tournament Tracker") self.main_window.set_title("FPDB Tournament Tracker")
self.main_window.show_all() self.main_window.show_all()
def addClicked(self, widget, data): # what is "data"? i'm guessing anything i pass in after the function name in connect() but unsure because the documentation sucks def addClicked(self, widget, data): # what is "data"? i'm guessing anything i pass in after the function name in connect() but unsure because the documentation sucks
print "addClicked", widget, data print "addClicked", widget, data
t = Tournament(self, None, None) t = Tournament(self, None, None)
@ -162,7 +162,7 @@ class ttracker_main(object):
rebuybutton = gtk.Button(label="Rebuy") rebuybutton = gtk.Button(label="Rebuy")
rebuybutton.connect("clicked", t.addrebuy) rebuybutton.connect("clicked", t.addrebuy)
self.vb.add(rebuybutton) self.vb.add(rebuybutton)
self.vb.add(editbutton) # These should probably be put in.. a.. h-box? i don't know.. self.vb.add(editbutton) # These should probably be put in.. a.. h-box? i don't know..
self.vb.add(mylabel) self.vb.add(mylabel)
self.main_window.resize_children() self.main_window.resize_children()
self.main_window.show() self.main_window.show()
@ -172,29 +172,29 @@ class ttracker_main(object):
t.mylabel = mylabel t.mylabel = mylabel
t.editbutton = editbutton t.editbutton = editbutton
t.rebuybutton = rebuybutton t.rebuybutton = rebuybutton
self.vb.show() self.vb.show()
print self.tourney_list print self.tourney_list
return True return True
else: else:
return False return False
# when we move the start command over to the main program, we can have the main program ask for the tourney id, and pipe it into the stdin here # when we move the start command over to the main program, we can have the main program ask for the tourney id, and pipe it into the stdin here
# at least that was my initial thought on it # at least that was my initial thought on it
def destroy(*args): # call back for terminating the main eventloop def destroy(*args): # call back for terminating the main eventloop
gtk.main_quit() gtk.main_quit()
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, stat_dict, cards): def create_HUD(self, new_hand_id, table, table_name, max, poker_game, stat_dict, cards):
def idle_func(): def idle_func():
gtk.gdk.threads_enter() gtk.gdk.threads_enter()
try: try:
newlabel = gtk.Label("%s - %s" % (table.site, table_name)) newlabel = gtk.Label("%s - %s" % (table.site, table_name))
self.vb.add(newlabel) self.vb.add(newlabel)
newlabel.show() newlabel.show()
self.main_window.resize_children() self.main_window.resize_children()
self.hud_dict[table_name].tablehudlabel = newlabel self.hud_dict[table_name].tablehudlabel = newlabel
self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict, cards) self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict, cards)
for m in self.hud_dict[table_name].aux_windows: for m in self.hud_dict[table_name].aux_windows:
@ -212,11 +212,11 @@ class ttracker_main(object):
self.hud_dict[table_name].cards = cards self.hud_dict[table_name].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows] [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows]
gobject.idle_add(idle_func) gobject.idle_add(idle_func)
def update_HUD(self, new_hand_id, table_name, config): def update_HUD(self, new_hand_id, table_name, config):
"""Update a HUD gui from inside the non-gui read_stdin thread.""" """Update a HUD gui from inside the non-gui read_stdin thread."""
# This is written so that only 1 thread can touch the gui--mainly # This is written so that only 1 thread can touch the gui--mainly
# for compatibility with Windows. This method dispatches the # for compatibility with Windows. This method dispatches the
# function idle_func() to be run by the gui thread, at its leisure. # function idle_func() to be run by the gui thread, at its leisure.
def idle_func(): def idle_func():
gtk.gdk.threads_enter() gtk.gdk.threads_enter()
@ -227,7 +227,7 @@ class ttracker_main(object):
finally: finally:
gtk.gdk.threads_leave() gtk.gdk.threads_leave()
gobject.idle_add(idle_func) gobject.idle_add(idle_func)
def read_stdin(self): # This is the thread function def read_stdin(self): # This is the thread function
"""Do all the non-gui heavy lifting for the HUD program.""" """Do all the non-gui heavy lifting for the HUD program."""
@ -238,7 +238,7 @@ class ttracker_main(object):
self.db_connection = Database.Database(self.config, self.db_name, 'temp') self.db_connection = Database.Database(self.config, self.db_name, 'temp')
# self.db_connection.init_hud_stat_vars(hud_days) # self.db_connection.init_hud_stat_vars(hud_days)
tourny_finder = re.compile('(\d+) (\d+)') tourny_finder = re.compile('(\d+) (\d+)')
while 1: # wait for a new hand number on stdin while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline() new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id) new_hand_id = string.rstrip(new_hand_id)
@ -272,7 +272,7 @@ class ttracker_main(object):
print "could not find tournament: skipping " print "could not find tournament: skipping "
sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
continue continue
else: else:
temp_key = table_name temp_key = table_name
@ -282,7 +282,7 @@ class ttracker_main(object):
self.hud_dict[temp_key].cards = cards self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config) self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD # Or create a new HUD
else: else:
if type == "tour": if type == "tour":

View File

@ -41,7 +41,7 @@ if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sy
else: else:
pass pass
#print "debug - not changing path" #print "debug - not changing path"
if os.name == 'nt': if os.name == 'nt':
import win32api import win32api
import win32con import win32con
@ -53,7 +53,7 @@ import threading
import Options import Options
import string import string
cl_options = string.join(sys.argv[1:]) cl_options = string.join(sys.argv[1:])
(options, sys.argv) = Options.fpdb_options() (options, argv) = Options.fpdb_options()
if not options.errorsToConsole: if not options.errorsToConsole:
print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_."
@ -80,7 +80,7 @@ import SQL
import Database import Database
import FpdbSQLQueries import FpdbSQLQueries
import Configuration import Configuration
from Exceptions import * import Exceptions
VERSION = "0.12" VERSION = "0.12"
@ -178,23 +178,23 @@ class fpdb:
"""obtains db root credentials from user""" """obtains db root credentials from user"""
self.warning_box("Unimplemented: Get Root Database Credentials") self.warning_box("Unimplemented: Get Root Database Credentials")
# user, pw=None, None # user, pw=None, None
# #
# dialog=gtk.Dialog(title="DB Credentials needed", parent=None, flags=0, # dialog=gtk.Dialog(title="DB Credentials needed", parent=None, flags=0,
# buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,"Connect and recreate",gtk.RESPONSE_OK)) # buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,"Connect and recreate",gtk.RESPONSE_OK))
# #
# label_warning1=gtk.Label("Please enter credentials for a database user for "+self.host+" that has permissions to create a database.") # label_warning1=gtk.Label("Please enter credentials for a database user for "+self.host+" that has permissions to create a database.")
# #
# #
# label_user=gtk.Label("Username") # label_user=gtk.Label("Username")
# dialog.vbox.add(label_user) # dialog.vbox.add(label_user)
# label_user.show() # label_user.show()
# #
# response=dialog.run() # response=dialog.run()
# dialog.destroy() # dialog.destroy()
# return (user, pw, response) # return (user, pw, response)
def dia_import_db(self, widget, data=None): def dia_import_db(self, widget, data=None):
self.warning_box("Unimplemented: Import Database") self.warning_box("Unimplemented: Import Database")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
@ -211,7 +211,7 @@ class fpdb:
# chooser.set_filename(self.profile) # chooser.set_filename(self.profile)
# response = chooser.run() # response = chooser.run()
# chooser.destroy() # chooser.destroy()
# if response == gtk.RESPONSE_OK: # if response == gtk.RESPONSE_OK:
# self.load_profile(chooser.get_filename()) # self.load_profile(chooser.get_filename())
# elif response == gtk.RESPONSE_CANCEL: # elif response == gtk.RESPONSE_CANCEL:
@ -239,7 +239,7 @@ class fpdb:
dia_confirm.destroy() dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
#if self.db.backend == self.fdb_lock.fdb.MYSQL_INNODB: #if self.db.backend == self.fdb_lock.fdb.MYSQL_INNODB:
# mysql requires locks on all tables or none - easier to release this lock # mysql requires locks on all tables or none - easier to release this lock
# than lock all the other tables # than lock all the other tables
# ToDo: lock all other tables so that lock doesn't have to be released # ToDo: lock all other tables so that lock doesn't have to be released
# self.release_global_lock() # self.release_global_lock()
@ -252,7 +252,7 @@ class fpdb:
print 'User cancelled recreating tables' print 'User cancelled recreating tables'
#if not lock_released: #if not lock_released:
self.release_global_lock() self.release_global_lock()
def dia_recreate_hudcache(self, widget, data=None): def dia_recreate_hudcache(self, widget, data=None):
if self.obtain_global_lock(): if self.obtain_global_lock():
self.dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache") self.dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache")
@ -314,7 +314,7 @@ class fpdb:
entry.set_text(ds) entry.set_text(ds)
win.destroy() win.destroy()
self.dia_confirm.set_modal(True) self.dia_confirm.set_modal(True)
def dia_regression_test(self, widget, data=None): def dia_regression_test(self, widget, data=None):
self.warning_box("Unimplemented: Regression Test") self.warning_box("Unimplemented: Regression Test")
self.obtain_global_lock() self.obtain_global_lock()
@ -322,7 +322,7 @@ class fpdb:
def dia_save_profile(self, widget, data=None): def dia_save_profile(self, widget, data=None):
self.warning_box("Unimplemented: Save Profile (try saving a HUD layout, that should do it)") self.warning_box("Unimplemented: Save Profile (try saving a HUD layout, that should do it)")
def diaSetupWizard(self, path): def diaSetupWizard(self, path):
diaSetupWizard = gtk.Dialog(title="Fatal Error - Config File Missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK)) diaSetupWizard = gtk.Dialog(title="Fatal Error - Config File Missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK))
@ -453,21 +453,25 @@ class fpdb:
self.sql = SQL.Sql(db_server = self.settings['db-server']) self.sql = SQL.Sql(db_server = self.settings['db-server'])
try: try:
self.db = Database.Database(self.config, sql = self.sql) self.db = Database.Database(self.config, sql = self.sql)
except FpdbMySQLFailedError: except Exceptions.FpdbMySQLAccessDenied:
self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?")
exit() exit()
except FpdbError:
#print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) # except FpdbMySQLFailedError:
self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") # self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR")
err = traceback.extract_tb(sys.exc_info()[2])[-1] # exit()
print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) # except FpdbError:
sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) # #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])
except: # self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR")
#print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) # err = traceback.extract_tb(sys.exc_info()[2])[-1]
self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") # print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
err = traceback.extract_tb(sys.exc_info()[2])[-1] # sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) # except:
sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) # #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])
# self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR")
# err = traceback.extract_tb(sys.exc_info()[2])[-1]
# print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
# sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
if self.db.wrongDbVersion: if self.db.wrongDbVersion:
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
@ -496,7 +500,7 @@ class fpdb:
# Database connected to successfully, load queries to pass on to other classes # Database connected to successfully, load queries to pass on to other classes
self.db.rollback() self.db.rollback()
self.validate_config() self.validate_config()
def not_implemented(self, widget, data=None): def not_implemented(self, widget, data=None):
@ -624,7 +628,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.window.show() self.window.show()
self.load_profile() self.load_profile()
self.statusIcon = gtk.StatusIcon() self.statusIcon = gtk.StatusIcon()
if os.path.exists('../gfx/fpdb-cards.png'): if os.path.exists('../gfx/fpdb-cards.png'):
self.statusIcon.set_from_file('../gfx/fpdb-cards.png') self.statusIcon.set_from_file('../gfx/fpdb-cards.png')
@ -643,19 +647,19 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.statusMenu.append(menuItem) self.statusMenu.append(menuItem)
self.statusIcon.connect('popup-menu', self.statusicon_menu, self.statusMenu) self.statusIcon.connect('popup-menu', self.statusicon_menu, self.statusMenu)
self.statusIcon.set_visible(True) self.statusIcon.set_visible(True)
self.window.connect('window-state-event', self.window_state_event_cb) self.window.connect('window-state-event', self.window_state_event_cb)
sys.stderr.write("fpdb starting ...") sys.stderr.write("fpdb starting ...")
def window_state_event_cb(self, window, event): def window_state_event_cb(self, window, event):
print "window_state_event", event print "window_state_event", event
if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED: if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
# -20 = GWL_EXSTYLE can't find it in the pywin32 libs # -20 = GWL_EXSTYLE can't find it in the pywin32 libs
#bits = win32api.GetWindowLong(self.window.window.handle, -20) #bits = win32api.GetWindowLong(self.window.window.handle, -20)
#bits = bits ^ (win32con.WS_EX_TOOLWINDOW | win32con.WS_EX_APPWINDOW) #bits = bits ^ (win32con.WS_EX_TOOLWINDOW | win32con.WS_EX_APPWINDOW)
#win32api.SetWindowLong(self.window.window.handle, -20, bits) #win32api.SetWindowLong(self.window.window.handle, -20, bits)
if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED: if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
self.window.hide() self.window.hide()
self.window.set_skip_taskbar_hint(True) self.window.set_skip_taskbar_hint(True)
@ -665,7 +669,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.window.set_skip_pager_hint(False) self.window.set_skip_pager_hint(False)
# Tell GTK not to propagate this signal any further # Tell GTK not to propagate this signal any further
return True return True
def statusicon_menu(self, widget, button, time, data = None): def statusicon_menu(self, widget, button, time, data = None):
# we don't need to pass data here, since we do keep track of most all # we don't need to pass data here, since we do keep track of most all
# our variables .. the example code that i looked at for this # our variables .. the example code that i looked at for this
@ -676,7 +680,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
data.show_all() data.show_all()
data.popup(None, None, None, 3, time) data.popup(None, None, None, 3, time)
pass pass
def statusicon_activate(self, widget, data = None): def statusicon_activate(self, widget, data = None):
# Let's allow the tray icon to toggle window visibility, the way # Let's allow the tray icon to toggle window visibility, the way
# most other apps work # most other apps work
@ -686,7 +690,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
else: else:
self.window.show() self.window.show()
self.window.present() self.window.present()
def warning_box(self, str, diatitle="FPDB WARNING"): def warning_box(self, str, diatitle="FPDB WARNING"):
diaWarning = gtk.Dialog(title=diatitle, parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diaWarning = gtk.Dialog(title=diatitle, parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
@ -697,7 +701,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
response = diaWarning.run() response = diaWarning.run()
diaWarning.destroy() diaWarning.destroy()
return response return response
def validate_config(self): def validate_config(self):
hhbase = self.config.get_import_parameters().get("hhArchiveBase") hhbase = self.config.get_import_parameters().get("hhArchiveBase")
hhbase = os.path.expanduser(hhbase) hhbase = os.path.expanduser(hhbase)
@ -716,7 +720,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.") self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.")
elif response == gtk.RESPONSE_NO: elif response == gtk.RESPONSE_NO:
self.select_hhArchiveBase() self.select_hhArchiveBase()
def select_hhArchiveBase(self, widget=None): def select_hhArchiveBase(self, widget=None):
fc = gtk.FileChooserDialog(title="Select HH Output Directory", parent=None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_OPEN,gtk.RESPONSE_OK), backend=None) fc = gtk.FileChooserDialog(title="Select HH Output Directory", parent=None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_OPEN,gtk.RESPONSE_OK), backend=None)
fc.run() fc.run()
@ -726,7 +730,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.config.save() self.config.save()
self.load_profile() # we can't do this at the end of this func because load_profile calls this func self.load_profile() # we can't do this at the end of this func because load_profile calls this func
fc.destroy() # TODO: loop this to make sure we get valid data back from it, because the open directory thing in GTK lets you select files and not select things and other stupid bullshit fc.destroy() # TODO: loop this to make sure we get valid data back from it, because the open directory thing in GTK lets you select files and not select things and other stupid bullshit
def main(self): def main(self):
gtk.main() gtk.main()
return 0 return 0

View File

@ -82,10 +82,10 @@ class fpdb_db:
self.connect(backend=db['db-backend'], self.connect(backend=db['db-backend'],
host=db['db-host'], host=db['db-host'],
database=db['db-databaseName'], database=db['db-databaseName'],
user=db['db-user'], user=db['db-user'],
password=db['db-password']) password=db['db-password'])
#end def do_connect #end def do_connect
def connect(self, backend=None, host=None, database=None, def connect(self, backend=None, host=None, database=None,
user=None, password=None): user=None, password=None):
"""Connects a database with the given parameters""" """Connects a database with the given parameters"""
@ -100,12 +100,15 @@ class fpdb_db:
import MySQLdb import MySQLdb
if use_pool: if use_pool:
MySQLdb = pool.manage(MySQLdb, pool_size=5) MySQLdb = pool.manage(MySQLdb, pool_size=5)
# try: try:
self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True) self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True)
#TODO: Add port option #TODO: Add port option
# except: except MySQLdb.Error, ex:
# raise FpdbMySQLFailedError("MySQL connection failed") if ex.args[0] == 1045:
elif backend==fpdb_db.PGSQL: raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1])
else:
print "*** WARNING UNKNOWN MYSQL ERROR", ex
elif backend == fpdb_db.PGSQL:
import psycopg2 import psycopg2
import psycopg2.extensions import psycopg2.extensions
if use_pool: if use_pool:
@ -131,8 +134,8 @@ class fpdb_db:
if not connected: if not connected:
try: try:
self.db = psycopg2.connect(host = host, self.db = psycopg2.connect(host = host,
user = user, user = user,
password = password, password = password,
database = database) database = database)
except: except:
msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user) msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user)
@ -187,13 +190,13 @@ class fpdb_db:
self.cursor.close() self.cursor.close()
self.db.close() self.db.close()
#end def disconnect #end def disconnect
def reconnect(self, due_to_error=False): def reconnect(self, due_to_error=False):
"""Reconnects the DB""" """Reconnects the DB"""
#print "started fpdb_db.reconnect" #print "started fpdb_db.reconnect"
self.disconnect(due_to_error) self.disconnect(due_to_error)
self.connect(self.backend, self.host, self.database, self.user, self.password) self.connect(self.backend, self.host, self.database, self.user, self.password)
def get_backend_name(self): def get_backend_name(self):
"""Returns the name of the currently used backend""" """Returns the name of the currently used backend"""
if self.backend==2: if self.backend==2:
@ -205,7 +208,7 @@ class fpdb_db:
else: else:
raise FpdbError("invalid backend") raise FpdbError("invalid backend")
#end def get_backend_name #end def get_backend_name
def get_db_info(self): def get_db_info(self):
return (self.host, self.database, self.user, self.password) return (self.host, self.database, self.user, self.password)
#end def get_db_info #end def get_db_info