2 # -*- coding: utf-8 -*-
5 Handles fpdb/fpdb-hud configuration files.
7 # Copyright 2008-2011, Ray E. Barker
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 ########################################################################
27 # Standard Library modules
28 from __future__
import with_statement
31 _
= L10n
.get_translation()
41 import xml
.dom
.minidom
42 from xml
.dom
.minidom
import Node
45 if platform
.system() == 'Windows':
47 winpaths_appdata
= winpaths
.get_appdata()
49 winpaths_appdata
= False
51 import logging
, logging
.config
56 # code is centralised here to ensure uniform handling of path names
57 # especially important when user directory includes non-ascii chars
59 # INSTALL_METHOD ("source" or "exe")
60 # FPDB_PROGRAM_PATH (path to the root fpdb installation dir root (normally ...../fpdb)
61 # APPDATA_PATH (root path for appdata eg /~ or appdata)
62 # CONFIG_PATH (path to the directory holding logs, sqlite db's and config)
63 # OS_FAMILY (OS Family for installed system (Linux, Mac, XP, Win7)
64 # POSIX (True=Linux or Mac platform, False=Windows platform)
65 # PYTHON_VERSION (n.n)
67 if hasattr(sys
, "frozen"):
68 INSTALL_METHOD
= "exe"
70 INSTALL_METHOD
= "source"
72 if INSTALL_METHOD
== "exe":
73 FPDB_PROGRAM_PATH
= os
.path
.dirname(sys
.executable
) # should be exe path to /fpdb
75 FPDB_PROGRAM_PATH
= os
.path
.dirname(sys
.path
[0]) # should be source path to /fpdb
77 sysPlatform
= platform
.system() #Linux, Windows, Darwin
78 if sysPlatform
[0:5] == 'Linux':
80 elif sysPlatform
== 'Darwin':
82 elif sysPlatform
== 'Windows':
83 if platform
.release() <> 'XP':
84 OS_FAMILY
= 'Win7' #Vista and win7
90 if OS_FAMILY
in ['XP', 'Win7']:
91 APPDATA_PATH
= winpaths_appdata
92 CONFIG_PATH
= os
.path
.join(APPDATA_PATH
, u
"fpdb")
93 elif OS_FAMILY
== 'Mac':
94 APPDATA_PATH
= os
.getenv("HOME")
95 CONFIG_PATH
= os
.path
.join(APPDATA_PATH
, u
".fpdb")
96 elif OS_FAMILY
== 'Linux':
97 APPDATA_PATH
= os
.path
.expanduser("~")
98 CONFIG_PATH
= os
.path
.join(APPDATA_PATH
, u
".fpdb")
103 if os
.name
== 'posix':
108 PYTHON_VERSION
= sys
.version
[:3]
110 # logging has been set up in fpdb.py or HUD_main.py, use their settings:
111 log
= logging
.getLogger("config")
113 def get_config(file_name
, fallback
= True):
114 """Looks in cwd and in self.default_config_path for a config file."""
115 # look for example file even if not used here, path is returned to caller
116 config_found
,example_found
,example_copy
= False,False,False
117 config_path
, example_path
= None,None
119 if file_name
== 'logging.conf' and INSTALL_METHOD
== "source":
120 config_path
= os
.path
.join(FPDB_PROGRAM_PATH
, 'pyfpdb', file_name
)
122 config_path
= os
.path
.join(FPDB_PROGRAM_PATH
, file_name
)
123 #print "config_path=", config_path
124 if os
.path
.exists(config_path
): # there is a file in the cwd
125 config_found
= True # so we use it
126 else: # no file in the cwd, look where it should be in the first place
127 config_path
= os
.path
.join(CONFIG_PATH
, file_name
)
128 #print "config path 2=", config_path
129 if os
.path
.exists(config_path
):
132 #TODO: clean up the example path loading to ensure it behaves the same on all OSs
133 # Example configuration for debian package
135 # If we're on linux, try to copy example from the place
136 # debian package puts it; get_default_config_path() creates
137 # the config directory for us so there's no need to check it
139 example_path
= '/usr/share/python-fpdb/' + file_name
+ '.example'
140 if not os
.path
.exists(example_path
):
141 if os
.path
.exists(file_name
+ '.example'):
142 example_path
= file_name
+ '.example'
144 example_path
= "pyfpdb/" + file_name
+ '.example'
145 if not config_found
and fallback
:
147 shutil
.copyfile(example_path
, config_path
)
149 msg
= _("Config file has been created at %s.") % (config_path
+"\n")
153 example_path
= file_name
+ '.example'
154 shutil
.copyfile(example_path
, config_path
)
156 msg
= _("Config file has been created at %s.") % (config_path
+"\n")
161 # OK, fall back to the .example file, should be in the start dir
162 elif os
.path
.exists(file_name
+ ".example"):
165 example_path
= file_name
+ ".example"
166 check_dir(CONFIG_PATH
)
167 if not config_found
and fallback
:
168 shutil
.copyfile(example_path
, config_path
)
170 msg
= _("No %s found\n in %s\n or %s") % (file_name
, FPDB_PROGRAM_PATH
, CONFIG_PATH
) \
171 + " " + _("Config file has been created at %s.") % (config_path
+"\n")
175 print _("Error copying .example config file, cannot fall back. Exiting."), "\n"
176 sys
.stderr
.write(_("Error copying .example config file, cannot fall back. Exiting.")+"\n")
177 sys
.stderr
.write( str(sys
.exc_info()) )
180 print _("No %s found, cannot fall back. Exiting.") % file_name
, "\n"
181 sys
.stderr
.write((_("No %s found, cannot fall back. Exiting.") % file_name
) + "\n")
184 #print "get_config: returning "+str( (config_path,example_copy,example_path) )
185 return (config_path
,example_copy
,example_path
)
187 def get_logger(file_name
, config
= "config", fallback
= False, log_dir
=None, log_file
=None):
188 (conf_file
,copied
,example_file
) = get_config(file_name
, fallback
= fallback
)
191 log_dir
= os
.path
.join(FPDB_PROGRAM_PATH
, u
'log')
192 #print "\nget_logger: checking log_dir:", log_dir
195 file = os
.path
.join(log_dir
, u
'fpdb-log.txt')
197 file = os
.path
.join(log_dir
, log_file
)
201 file = file.replace('\\', '\\\\') # replace each \ with \\
202 # print " ="+file+" "+ str(type(file))+" len="+str(len(file))+"\n"
203 logging
.config
.fileConfig(conf_file
, {"logFile":file})
204 log
= logging
.getLogger(config
)
205 log
.debug("%s logger initialised" % config
)
210 log
= logging
.basicConfig(filename
=file, level
=logging
.INFO
)
211 log
= logging
.getLogger()
212 # but it looks like default is no output :-( maybe because all the calls name a module?
213 log
.debug(_("Default logger initialised for %s") % file)
214 #print(_("Default logger initialised for %s") % file)
217 def check_dir(path
, create
= True):
218 """Check if a dir exists, optionally creates if not."""
219 if os
.path
.exists(path
):
220 if os
.path
.isdir(path
):
225 msg
= _("Creating directory: '%s'") % (path
)
228 os
.mkdir(path
)#, "utf-8"))
233 ########################################################################
234 # application wide consts
236 APPLICATION_NAME_SHORT
= 'fpdb'
237 APPLICATION_VERSION
= 'xx.xx.xx'
239 DATABASE_TYPE_POSTGRESQL
= 'postgresql'
240 DATABASE_TYPE_SQLITE
= 'sqlite'
241 DATABASE_TYPE_MYSQL
= 'mysql'
243 DATABASE_TYPE_POSTGRESQL
,
244 DATABASE_TYPE_SQLITE
,
248 LOCALE_ENCODING
= locale
.getpreferredencoding()
249 if LOCALE_ENCODING
in ("US-ASCII", "", None):
250 LOCALE_ENCODING
= "cp1252"
251 if (os
.uname()[0]!="Darwin"):
252 print _("Default encoding set to US-ASCII, defaulting to CP1252 instead."), _("Please report this problem.")
254 # needs LOCALE_ENCODING (above), imported for sqlite setup in Config class below
259 ########################################################################
260 def string_to_bool(string
, default
=True):
261 """converts a string representation of a boolean value to boolean True or False
262 @param string: (str) the string to convert
263 @param default: value to return if the string can not be converted to a boolean value
265 string
= string
.lower()
266 if string
in ('1', 'true', 't'):
268 elif string
in ('0', 'false', 'f'):
273 def __init__(self
, node
):
275 self
.max = int( node
.getAttribute('max') )
276 if node
.hasAttribute('fav_seat'): self
.fav_seat
= int( node
.getAttribute('fav_seat') )
277 if node
.hasAttribute('name'): self
.name
= node
.getAttribute('name')
278 else: self
.name
= None
279 self
.width
= int( node
.getAttribute('width') )
280 self
.height
= int( node
.getAttribute('height') )
283 self
.location
= map(lambda x
: None, range(self
.max+1)) # fill array with max seats+1 empty entries
285 for location_node
in node
.getElementsByTagName('location'):
286 if location_node
.getAttribute('seat') != "":
287 self
.location
[int( location_node
.getAttribute('seat') )] = (int( location_node
.getAttribute('x') ), int( location_node
.getAttribute('y')))
288 elif location_node
.getAttribute('common') != "":
289 self
.common
= (int( location_node
.getAttribute('x') ), int( location_node
.getAttribute('y')))
292 if hasattr(self
, 'name'):
293 name
= str(self
.name
) + ", "
296 temp
= " Layout = %s%d max, width= %d, height = %d" % (name
, self
.max, self
.width
, self
.height
)
297 if hasattr(self
, 'fav_seat'): temp
= temp
+ ", fav_seat = %d\n" % self
.fav_seat
298 else: temp
= temp
+ "\n"
299 if hasattr(self
, "common"):
300 temp
= temp
+ " Common = (%d, %d)\n" % (self
.common
[0], self
.common
[1])
301 temp
= temp
+ " Locations = "
302 for i
in range(1, len(self
.location
)):
303 temp
= temp
+ "(%d,%d)" % self
.location
[i
]
308 def __init__(self
, node
):
310 self
.host
= node
.getAttribute("host")
311 self
.username
= node
.getAttribute("username")
312 self
.password
= node
.getAttribute("password")
313 self
.useSsl
= node
.getAttribute("useSsl")
314 self
.folder
= node
.getAttribute("folder")
315 self
.fetchType
= node
.getAttribute("fetchType")
318 return " fetchType=%s\n host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \
319 % (self
.fetchType
, self
.host
, self
.username
, self
.password
, self
.useSsl
, self
.folder
)
322 def __init__(self
, node
):
323 def normalizePath(path
):
324 "Normalized existing pathes"
325 if os
.path
.exists(path
):
326 return os
.path
.abspath(path
)
329 self
.site_name
= node
.getAttribute("site_name")
330 self
.table_finder
= node
.getAttribute("table_finder")
331 self
.screen_name
= node
.getAttribute("screen_name")
332 self
.site_path
= normalizePath(node
.getAttribute("site_path"))
333 self
.HH_path
= normalizePath(node
.getAttribute("HH_path"))
334 self
.decoder
= node
.getAttribute("decoder")
335 self
.hudopacity
= node
.getAttribute("hudopacity")
336 self
.hudbgcolor
= node
.getAttribute("bgcolor")
337 self
.hudfgcolor
= node
.getAttribute("fgcolor")
338 self
.converter
= node
.getAttribute("converter")
339 self
.aux_window
= node
.getAttribute("aux_window")
340 self
.font
= node
.getAttribute("font")
341 self
.font_size
= node
.getAttribute("font_size")
342 self
.use_frames
= node
.getAttribute("use_frames")
343 self
.enabled
= string_to_bool(node
.getAttribute("enabled"), default
=True)
344 self
.xpad
= node
.getAttribute("xpad")
345 self
.ypad
= node
.getAttribute("ypad")
346 self
.xshift
= node
.getAttribute("xshift")
347 self
.yshift
= node
.getAttribute("yshift")
351 for layout_node
in node
.getElementsByTagName('layout'):
352 lo
= Layout(layout_node
)
353 self
.layout
[lo
.max] = lo
355 for email_node
in node
.getElementsByTagName('email'):
356 email
= Email(email_node
)
357 self
.emails
[email
.fetchType
] = email
360 self
.xpad
= 1 if self
.xpad
== "" else int(self
.xpad
)
361 self
.ypad
= 0 if self
.ypad
== "" else int(self
.ypad
)
362 self
.xshift
= 1 if self
.xshift
== "" else int(self
.xshift
)
363 self
.yshift
= 0 if self
.yshift
== "" else int(self
.yshift
)
364 self
.font_size
= 7 if self
.font_size
== "" else int(self
.font_size
)
365 self
.hudopacity
= 1.0 if self
.hudopacity
== "" else float(self
.hudopacity
)
367 if self
.use_frames
== "": self
.use_frames
= False
368 if self
.font
== "": self
.font
= "Sans"
369 if self
.hudbgcolor
== "": self
.hudbgcolor
= "#000000"
370 if self
.hudfgcolor
== "": self
.hudfgcolor
= "#FFFFFF"
373 temp
= "Site = " + self
.site_name
+ "\n"
374 for key
in dir(self
):
375 if key
.startswith('__'): continue
376 if key
== 'layout': continue
377 value
= getattr(self
, key
)
378 if callable(value
): continue
379 temp
= temp
+ ' ' + key
+ " = " + str(value
) + "\n"
381 for layout
in self
.layout
:
382 temp
= temp
+ "%s" % self
.layout
[layout
]
391 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
)
395 def __init__(self
, node
):
396 self
.game_name
= node
.getAttribute("game_name")
397 self
.rows
= int( node
.getAttribute("rows") )
398 self
.cols
= int( node
.getAttribute("cols") )
399 self
.xpad
= node
.getAttribute("xpad")
400 self
.ypad
= node
.getAttribute("ypad")
401 self
.xshift
= node
.getAttribute("xshift")
402 self
.yshift
= node
.getAttribute("yshift")
405 if self
.xpad
== "": self
.xpad
= 1
406 else: self
.xpad
= int(self
.xpad
)
407 if self
.ypad
== "": self
.ypad
= 0
408 else: self
.ypad
= int(self
.ypad
)
409 if self
.xshift
== "": self
.xshift
= 1
410 else: self
.xshift
= int(self
.xshift
)
411 if self
.yshift
== "": self
.yshift
= 0
412 else: self
.yshift
= int(self
.yshift
)
414 aux_text
= node
.getAttribute("aux")
415 aux_list
= aux_text
.split(',')
416 for i
in range(0, len(aux_list
)):
417 aux_list
[i
] = aux_list
[i
].strip()
421 for stat_node
in node
.getElementsByTagName('stat'):
423 stat
.stat_name
= stat_node
.getAttribute("stat_name")
424 stat
.row
= int( stat_node
.getAttribute("row") )
425 stat
.col
= int( stat_node
.getAttribute("col") )
426 stat
.tip
= stat_node
.getAttribute("tip")
427 stat
.click
= stat_node
.getAttribute("click")
428 stat
.popup
= stat_node
.getAttribute("popup")
429 stat
.hudprefix
= stat_node
.getAttribute("hudprefix")
430 stat
.hudsuffix
= stat_node
.getAttribute("hudsuffix")
431 stat
.hudcolor
= stat_node
.getAttribute("hudcolor")
432 stat
.stat_loth
= stat_node
.getAttribute("stat_loth")
433 stat
.stat_hith
= stat_node
.getAttribute("stat_hith")
434 stat
.stat_locolor
= stat_node
.getAttribute("stat_locolor")
435 stat
.stat_hicolor
= stat_node
.getAttribute("stat_hicolor")
437 self
.stats
[stat
.stat_name
] = stat
440 temp
= "Game = " + self
.game_name
+ "\n"
441 temp
= temp
+ " rows = %d\n" % self
.rows
442 temp
= temp
+ " cols = %d\n" % self
.cols
443 temp
= temp
+ " xpad = %d\n" % self
.xpad
444 temp
= temp
+ " ypad = %d\n" % self
.ypad
445 temp
= temp
+ " xshift = %d\n" % self
.xshift
446 temp
= temp
+ " yshift = %d\n" % self
.yshift
447 temp
= temp
+ " aux = %s\n" % self
.aux
449 for stat
in self
.stats
.keys():
450 temp
= temp
+ "%s" % self
.stats
[stat
]
455 def __init__(self
, node
):
456 self
.db_name
= node
.getAttribute("db_name")
457 self
.db_desc
= node
.getAttribute("db_desc")
458 self
.db_server
= node
.getAttribute("db_server").lower()
459 self
.db_ip
= node
.getAttribute("db_ip")
460 self
.db_user
= node
.getAttribute("db_user")
461 self
.db_pass
= node
.getAttribute("db_pass")
462 self
.db_selected
= string_to_bool(node
.getAttribute("default"), default
=False)
463 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'" \
464 % { 'name':self
.db_name
, 'server':self
.db_server
, 'ip':self
.db_ip
, 'user':self
.db_user
, 'sel':self
.db_selected
} )
467 temp
= 'Database = ' + self
.db_name
+ '\n'
468 for key
in dir(self
):
469 if key
.startswith('__'): continue
470 value
= getattr(self
, key
)
471 if callable(value
): continue
472 temp
= temp
+ ' ' + key
+ " = " + repr(value
) + "\n"
476 def __init__(self
, node
):
477 for (name
, value
) in node
.attributes
.items():
478 setattr(self
, name
, value
)
481 for layout_node
in node
.getElementsByTagName('layout'):
482 lo
= Layout(layout_node
)
483 self
.layout
[lo
.max] = lo
486 temp
= 'Aux = ' + self
.name
+ "\n"
487 for key
in dir(self
):
488 if key
.startswith('__'): continue
489 if key
== 'layout': continue
490 value
= getattr(self
, key
)
491 if callable(value
): continue
492 temp
= temp
+ ' ' + key
+ " = " + value
+ "\n"
494 for layout
in self
.layout
:
495 temp
= temp
+ "%s" % self
.layout
[layout
]
499 def __init__(self
, node
):
500 self
.site
= node
.getAttribute("site")
501 self
.converter
= node
.getAttribute("converter")
502 self
.summaryImporter
= node
.getAttribute("summaryImporter")
505 return "%s:\tconverter: '%s' summaryImporter: '%s'" % (self
.site
, self
.converter
, self
.summaryImporter
)
509 def __init__(self
, node
):
510 self
.name
= node
.getAttribute("pu_name")
512 for stat_node
in node
.getElementsByTagName('pu_stat'):
513 self
.pu_stats
.append(stat_node
.getAttribute("pu_stat_name"))
516 temp
= "Popup = " + self
.name
+ "\n"
517 for stat
in self
.pu_stats
:
518 temp
= temp
+ " " + stat
522 def __init__(self
, node
):
524 self
.interval
= node
.getAttribute("interval")
525 self
.sessionTimeout
= string_to_bool(node
.getAttribute("sessionTimeout") , default
=30)
526 self
.ResultsDirectory
= node
.getAttribute("ResultsDirectory")
527 self
.hhBulkPath
= node
.getAttribute("hhBulkPath")
528 self
.saveActions
= string_to_bool(node
.getAttribute("saveActions") , default
=False)
529 self
.cacheSessions
= string_to_bool(node
.getAttribute("cacheSessions") , default
=False)
530 self
.callFpdbHud
= string_to_bool(node
.getAttribute("callFpdbHud") , default
=False)
531 self
.fastStoreHudCache
= string_to_bool(node
.getAttribute("fastStoreHudCache"), default
=False)
532 self
.saveStarsHH
= string_to_bool(node
.getAttribute("saveStarsHH") , default
=False)
535 return " interval = %s\n callFpdbHud = %s\n saveActions = %s\n fastStoreHudCache = %s\nResultsDirectory = %s" \
536 % (self
.interval
, self
.callFpdbHud
, self
.saveActions
, self
.cacheSessions
, self
.sessionTimeout
, self
.fastStoreHudCache
, self
.ResultsDirectory
)
539 def __init__(self
, node
):
541 self
.label
= node
.getAttribute('label')
543 self
.hud_style
= node
.getAttribute('stat_range')
544 self
.hud_days
= node
.getAttribute('stat_days')
545 self
.aggregate_ring
= string_to_bool(node
.getAttribute('aggregate_ring_game_stats'))
546 self
.aggregate_tour
= string_to_bool(node
.getAttribute('aggregate_tourney_stats'))
547 self
.agg_bb_mult
= node
.getAttribute('aggregation_level_multiplier')
549 self
.h_hud_style
= node
.getAttribute('hero_stat_range')
550 self
.h_hud_days
= node
.getAttribute('hero_stat_days')
551 self
.h_aggregate_ring
= string_to_bool(node
.getAttribute('aggregate_hero_ring_game_stats'))
552 self
.h_aggregate_tour
= string_to_bool(node
.getAttribute('aggregate_hero_tourney_stats'))
553 self
.h_agg_bb_mult
= node
.getAttribute('hero_aggregation_level_multiplier')
557 return " label = %s\n" % self
.label
562 super(General
, self
).__init
__()
564 def add_elements(self
, node
):
565 # day_start - number n where 0.0 <= n < 24.0 representing start of day for user
566 # e.g. user could set to 4.0 for day to start at 4am local time
567 # [ HH_bulk_path was here - now moved to import section ]
568 for (name
, value
) in node
.attributes
.items():
569 log
.debug(unicode(_("config.general: adding %s = %s"), "utf8") % (name
,value
))
573 self
["version"]=int(self
["version"])
576 self
["ui_language"]="system"
577 self
["config_difficulty"]="expert"
579 def get_defaults(self
):
581 self
["ui_language"]="system"
582 self
["config_difficulty"]="expert"
583 self
["config_wrap_len"]="-1"
584 self
["day_start"]="5"
589 s
= s
+ " %s = %s\n" % (k
, self
[k
])
592 class GUICashStats(list):
594 <col col_name="game" col_title="Game" disp_all="True" disp_posn="True" field_format="%s" field_type="str" xalignment="0.0" />
599 super(GUICashStats
, self
).__init
__()
601 def add_elements(self
, node
):
603 for child
in node
.childNodes
:
604 if child
.nodeType
== child
.ELEMENT_NODE
:
605 col_name
, col_title
, disp_all
, disp_posn
, field_format
, field_type
, xalignment
=None, None, True, True, "%s", "str", 0.0
607 if child
.hasAttribute('col_name'): col_name
= child
.getAttribute('col_name')
608 if child
.hasAttribute('col_title'): col_title
= child
.getAttribute('col_title')
609 if child
.hasAttribute('disp_all'): disp_all
= string_to_bool(child
.getAttribute('disp_all'))
610 if child
.hasAttribute('disp_posn'): disp_posn
= string_to_bool(child
.getAttribute('disp_posn'))
611 if child
.hasAttribute('field_format'): field_format
= child
.getAttribute('field_format')
612 if child
.hasAttribute('field_type'): field_type
= child
.getAttribute('field_type')
614 if child
.hasAttribute('xalignment'): xalignment
= float(child
.getAttribute('xalignment'))
616 print _("bad number in xalignment was ignored")
617 log
.info(_("bad number in xalignment was ignored"))
619 self
.append( [col_name
, col_title
, disp_all
, disp_posn
, field_format
, field_type
, xalignment
] )
621 def get_defaults(self
):
622 """A list of defaults to be called, should there be no entry in config"""
623 # SQL column name, display title, display all, display positional, format, type, alignment
624 defaults
= [ [u
'game', u
'Game', True, True, u
'%s', u
'str', 0.0],
625 [u
'hand', u
'Hand', False, False, u
'%s', u
'str', 0.0],
626 [u
'plposition', u
'Posn', False, False, u
'%s', u
'str', 1.0],
627 [u
'pname', u
'Name', False, False, u
'%s', u
'str', 0.0],
628 [u
'n', u
'Hds', True, True, u
'%1.0f', u
'str', 1.0],
629 [u
'avgseats', u
'Seats', False, False, u
'%3.1f', u
'str', 1.0],
630 [u
'vpip', u
'VPIP', True, True, u
'%3.1f', u
'str', 1.0],
631 [u
'pfr', u
'PFR', True, True, u
'%3.1f', u
'str', 1.0],
632 [u
'pf3', u
'PF3', True, True, u
'%3.1f', u
'str', 1.0],
633 [u
'aggfac', u
'AggFac', True, True, u
'%2.2f', u
'str', 1.0],
634 [u
'aggfrq', u
'AggFreq', True, True, u
'%3.1f', u
'str', 1.0],
635 [u
'conbet', u
'ContBet', True, True, u
'%3.1f', u
'str', 1.0],
636 [u
'rfi', u
'RFI', True, True, u
'%3.1f', u
'str', 1.0],
637 [u
'steals', u
'Steals', True, True, u
'%3.1f', u
'str', 1.0],
638 [u
'saw_f', u
'Saw_F', True, True, u
'%3.1f', u
'str', 1.0],
639 [u
'sawsd', u
'SawSD', True, True, u
'%3.1f', u
'str', 1.0],
640 [u
'wtsdwsf', u
'WtSDwsF', True, True, u
'%3.1f', u
'str', 1.0],
641 [u
'wmsd', u
'W$SD', True, True, u
'%3.1f', u
'str', 1.0],
642 [u
'flafq', u
'FlAFq', True, True, u
'%3.1f', u
'str', 1.0],
643 [u
'tuafq', u
'TuAFq', True, True, u
'%3.1f', u
'str', 1.0],
644 [u
'rvafq', u
'RvAFq', True, True, u
'%3.1f', u
'str', 1.0],
645 [u
'pofafq', u
'PoFAFq', False, False, u
'%3.1f', u
'str', 1.0],
646 [u
'net', u
'Net($)', True, True, u
'%6.2f', u
'cash', 1.0],
647 [u
'bbper100', u
'bb/100', True, True, u
'%4.2f', u
'str', 1.0],
648 [u
'rake', u
'Rake($)', True, True, u
'%6.2f', u
'cash', 1.0],
649 [u
'bb100xr', u
'bbxr/100', True, True, u
'%4.2f', u
'str', 1.0],
650 [u
'variance', u
'Variance', True, True, u
'%5.2f', u
'str', 1.0]
658 # s = s + " %s = %s\n" % (k, self[k])
662 def __init__(self
, node
=None):
665 self
.compression
="none"
666 #print _("missing config section raw_hands")
668 save
=node
.getAttribute("save")
669 if save
in ("none", "error", "all"):
672 print (_("Invalid config value for %s, defaulting to %s") % (raw_hands
.save
, "\"error\""))
675 compression
=node
.getAttribute("compression")
676 if save
in ("none", "gzip", "bzip2"):
677 self
.compression
=compression
679 print (_("Invalid config value for %s, defaulting to %s") % (raw_hands
.compression
, "\"none\""))
680 self
.compression
="none"
684 return " save= %s, compression= %s\n" % (self
.save
, self
.compression
)
688 def __init__(self
, node
=None):
691 self
.compression
="none"
692 #print _("missing config section raw_tourneys")
694 save
=node
.getAttribute("save")
695 if save
in ("none", "error", "all"):
698 print (_("Invalid config value for %s, defaulting to %s") % (raw_tourneys
.save
, "\"error\""))
701 compression
=node
.getAttribute("compression")
702 if save
in ("none", "gzip", "bzip2"):
703 self
.compression
=compression
705 print (_("Invalid config value for %s, defaulting to %s") % (raw_tourneys
.compression
, "\"none\""))
706 self
.compression
="none"
710 return " save= %s, compression= %s\n" % (self
.save
, self
.compression
)
711 #end class RawTourneys
714 def __init__(self
, file = None, dbname
= ''):
715 # "file" is a path to an xml file with the fpdb/HUD configuration
716 # we check the existence of "file" and try to recover if it doesn't exist
718 # self.default_config_path = self.get_default_config_path()
720 self
.example_copy
= False
721 if file is not None: # config file path passed in
722 file = os
.path
.expanduser(file)
723 if not os
.path
.exists(file):
724 print _("Configuration file %s not found. Using defaults.") % (file)
725 sys
.stderr
.write(_("Configuration file %s not found. Using defaults.") % (file))
728 self
.example_copy
,example_file
= True,None
729 if file is None: (file,self
.example_copy
,example_file
) = get_config("HUD_config.xml", True)
733 self
.install_method
= INSTALL_METHOD
734 self
.fpdb_program_path
= FPDB_PROGRAM_PATH
735 self
.appdata_path
= APPDATA_PATH
736 self
.config_path
= CONFIG_PATH
737 self
.os_family
= OS_FAMILY
739 self
.python_version
= PYTHON_VERSION
741 if not os
.path
.exists(CONFIG_PATH
):
742 os
.mkdir(CONFIG_PATH
)
744 self
.dir_log
= os
.path
.join(CONFIG_PATH
, u
'log')
745 self
.dir_database
= os
.path
.join(CONFIG_PATH
, u
'database')
746 self
.log_file
= os
.path
.join(self
.dir_log
, u
'fpdb-log.txt')
747 log
= get_logger(u
"logging.conf", "config", log_dir
=self
.dir_log
)
749 self
.supported_sites
= {}
750 self
.supported_games
= {}
751 self
.supported_databases
= {} # databaseName --> Database instance
752 self
.aux_windows
= {}
754 self
.popup_windows
= {}
755 self
.db_selected
= None # database the user would like to use
756 self
.general
= General()
758 self
.gui_cash_stats
= GUICashStats()
759 self
.site_ids
= {} # site ID list from the database
762 added
,n
= 1,0 # use n to prevent infinite loop if add_missing_elements() fails somehow
763 while added
> 0 and n
< 2:
765 log
.info(unicode(_("Reading configuration file %s"), "utf8") % file)
766 #print (("\n"+_("Reading configuration file %s")+"\n") % file)
768 doc
= xml
.dom
.minidom
.parse(file)
770 self
.file_error
= None
772 log
.error((_("Error parsing %s.") % (file)) + _("See error log file."))
773 traceback
.print_exc(file=sys
.stderr
)
774 self
.file_error
= sys
.exc_info()[1]
775 # we could add a parameter to decide whether to return or read a line and exit?
777 #print "press enter to continue"
778 #sys.stdin.readline()
780 #ExpatError: not well-formed (invalid token): line 511, column 4
781 #sys.exc_info = (<class 'xml.parsers.expat.ExpatError'>, ExpatError('not well-formed (invalid token): line 511,
782 # column 4',), <traceback object at 0x024503A0>)
784 if (not self
.example_copy
) and (example_file
is not None):
785 # reads example file and adds missing elements into current config
786 added
= self
.add_missing_elements(doc
, example_file
)
788 if doc
.getElementsByTagName("general") == []:
789 self
.general
.get_defaults()
790 for gen_node
in doc
.getElementsByTagName("general"):
791 self
.general
.add_elements(node
=gen_node
) # add/overwrite elements in self.general
793 if doc
.getElementsByTagName("gui_cash_stats") == []:
794 self
.gui_cash_stats
.get_defaults()
795 for gcs_node
in doc
.getElementsByTagName("gui_cash_stats"):
796 self
.gui_cash_stats
.add_elements(node
=gcs_node
) # add/overwrite elements in self.gui_cash_stats
798 # s_sites = doc.getElementsByTagName("supported_sites")
799 for site_node
in doc
.getElementsByTagName("site"):
800 site
= Site(node
= site_node
)
801 self
.supported_sites
[site
.site_name
] = site
803 # s_games = doc.getElementsByTagName("supported_games")
804 for game_node
in doc
.getElementsByTagName("game"):
805 game
= Game(node
= game_node
)
806 self
.supported_games
[game
.game_name
] = game
808 # parse databases defined by user in the <supported_databases> section
809 # the user may select the actual database to use via commandline or by setting the selected="bool"
810 # attribute of the tag. if no database is explicitely selected, we use the first one we come across
811 # s_dbs = doc.getElementsByTagName("supported_databases")
812 #TODO: do we want to take all <database> tags or all <database> tags contained in <supported_databases>
813 # ..this may break stuff for some users. so leave it unchanged for now untill there is a decission
814 for db_node
in doc
.getElementsByTagName("database"):
815 db
= Database(node
=db_node
)
816 if db
.db_name
in self
.supported_databases
:
817 raise ValueError("Database names must be unique")
818 if self
.db_selected
is None or db
.db_selected
:
819 self
.db_selected
= db
.db_name
820 db_node
.setAttribute("default", "True")
821 self
.supported_databases
[db
.db_name
] = db
822 #TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored
823 # ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not
824 if dbname
and dbname
in self
.supported_databases
:
825 self
.db_selected
= dbname
826 #NOTE: fpdb can not handle the case when no database is defined in xml, so we throw an exception for now
827 if self
.db_selected
is None:
828 raise ValueError('There must be at least one database defined')
830 # s_dbs = doc.getElementsByTagName("mucked_windows")
831 for aw_node
in doc
.getElementsByTagName("aw"):
832 aw
= Aux_window(node
= aw_node
)
833 self
.aux_windows
[aw
.name
] = aw
835 # s_dbs = doc.getElementsByTagName("mucked_windows")
836 for hhc_node
in doc
.getElementsByTagName("hhc"):
837 hhc
= HHC(node
= hhc_node
)
838 self
.hhcs
[hhc
.site
] = hhc
840 # s_dbs = doc.getElementsByTagName("popup_windows")
841 for pu_node
in doc
.getElementsByTagName("pu"):
842 pu
= Popup(node
= pu_node
)
843 self
.popup_windows
[pu
.name
] = pu
845 for imp_node
in doc
.getElementsByTagName("import"):
846 imp
= Import(node
= imp_node
)
849 for hui_node
in doc
.getElementsByTagName('hud_ui'):
850 hui
= HudUI(node
= hui_node
)
853 db
= self
.get_db_parameters()
854 if db
['db-password'] == 'YOUR MYSQL PASSWORD':
855 df_file
= self
.find_default_conf()
856 if df_file
is None: # this is bad
859 df_parms
= self
.read_default_conf(df_file
)
860 self
.set_db_parameters(db_name
= 'fpdb', db_ip
= df_parms
['db-host'],
861 db_user
= df_parms
['db-user'],
862 db_pass
= df_parms
['db-password'])
863 self
.save(file=os
.path
.join(CONFIG_PATH
, u
"HUD_config.xml"))
865 if doc
.getElementsByTagName("raw_hands") == []:
866 self
.raw_hands
= RawHands()
867 for raw_hands_node
in doc
.getElementsByTagName('raw_hands'):
868 self
.raw_hands
= RawHands(raw_hands_node
)
870 if doc
.getElementsByTagName("raw_tourneys") == []:
871 self
.raw_tourneys
= RawTourneys()
872 for raw_tourneys_node
in doc
.getElementsByTagName('raw_tourneys'):
873 self
.raw_tourneys
= RawTourneys(raw_tourneys_node
)
878 def add_missing_elements(self
, doc
, example_file
):
879 """ Look through example config file and add any elements that are not in the config
880 May need to add some 'enabled' attributes to turn things off - can't just delete a
881 config section now because this will add it back in"""
886 example_doc
= xml
.dom
.minidom
.parse(example_file
)
888 log
.error((_("Error parsing example configuration file %s.") % (example_file
)) + _("See error log file."))
891 for cnode
in doc
.getElementsByTagName("FreePokerToolsConfig"):
892 for example_cnode
in example_doc
.childNodes
:
893 if example_cnode
.localName
== "FreePokerToolsConfig":
894 for e
in example_cnode
.childNodes
:
895 #print "nodetype", e.nodeType, "name", e.localName, "found", len(doc.getElementsByTagName(e.localName))
896 if e
.nodeType
== e
.ELEMENT_NODE
and doc
.getElementsByTagName(e
.localName
) == []:
897 new
= doc
.importNode(e
, True) # True means do deep copy
898 t_node
= self
.doc
.createTextNode(" ")
899 cnode
.appendChild(t_node
)
900 cnode
.appendChild(new
)
901 t_node
= self
.doc
.createTextNode("\r\n\r\n")
902 cnode
.appendChild(t_node
)
903 print "... adding missing config section: " + e
.localName
904 nodes_added
= nodes_added
+ 1
907 print "Added %d missing config sections\n" % nodes_added
912 def find_default_conf(self
):
914 config_file
= os
.path
.join(CONFIG_PATH
, u
'default.conf')
915 else: config_file
= False
917 if config_file
and os
.path
.exists(config_file
):
926 def get_site_node(self
, site
):
927 for site_node
in self
.doc
.getElementsByTagName("site"):
928 if site_node
.getAttribute("site_name") == site
:
931 def getEmailNode(self
, siteName
, fetchType
):
932 siteNode
= self
.get_site_node(siteName
)
933 for emailNode
in siteNode
.getElementsByTagName("email"):
934 if emailNode
.getAttribute("fetchType") == fetchType
:
935 print "found emailNode"
938 #end def getEmailNode
940 def getGameNode(self
,gameName
):
941 """returns DOM game node for a given game"""
942 for gameNode
in self
.doc
.getElementsByTagName("game"):
943 #print "getGameNode gameNode:",gameNode
944 if gameNode
.getAttribute("game_name") == gameName
:
948 def get_aux_node(self
, aux
):
949 for aux_node
in self
.doc
.getElementsByTagName("aw"):
950 if aux_node
.getAttribute("name") == aux
:
953 def get_db_node(self
, db_name
):
954 for db_node
in self
.doc
.getElementsByTagName("database"):
955 if db_node
.getAttribute("db_name") == db_name
:
959 def get_layout_node(self
, site_node
, layout
):
960 for layout_node
in site_node
.getElementsByTagName("layout"):
961 if layout_node
.getAttribute("max") is None:
963 if int( layout_node
.getAttribute("max") ) == int( layout
):
966 def get_location_node(self
, layout_node
, seat
):
968 for location_node
in layout_node
.getElementsByTagName("location"):
969 if location_node
.hasAttribute("common"):
972 for location_node
in layout_node
.getElementsByTagName("location"):
973 if int( location_node
.getAttribute("seat") ) == int( seat
):
976 def save(self
, file = None):
980 shutil
.move(file, file+".backup")
984 with
open(file, 'w') as f
:
985 #self.doc.writexml(f)
986 f
.write( self
.wrap_long_lines( self
.doc
.toxml() ) )
988 def wrap_long_lines(self
, s
):
989 lines
= [ self
.wrap_long_line(l
) for l
in s
.splitlines() ]
990 return('\n'.join(lines
) + '\n')
992 def wrap_long_line(self
, l
):
993 if 'config_wrap_len' in self
.general
:
994 wrap_len
= int(self
.general
['config_wrap_len'])
996 wrap_len
= -1 # < 0 means no wrap
998 if wrap_len
>= 0 and len(l
) > wrap_len
:
999 m
= re
.compile('\s+\S+\s+')
1002 indent_len
= mo
.end()
1003 #print "indent = %s (%s)" % (indent_len, l[0:indent_len])
1004 indent
= '\n' + ' ' * indent_len
1005 m
= re
.compile('(\S+="[^"]+"\s+)')
1006 parts
= [x
for x
in m
.split(l
[indent_len
:]) if x
]
1008 #print "parts =", parts
1009 l
= l
[0:indent_len
] + indent
.join(parts
)
1014 def editEmail(self
, siteName
, fetchType
, newEmail
):
1015 emailNode
= self
.getEmailNode(siteName
, fetchType
)
1016 emailNode
.setAttribute("host", newEmail
.host
)
1017 emailNode
.setAttribute("username", newEmail
.username
)
1018 emailNode
.setAttribute("password", newEmail
.password
)
1019 emailNode
.setAttribute("folder", newEmail
.folder
)
1020 emailNode
.setAttribute("useSsl", newEmail
.useSsl
)
1023 def edit_layout(self
, site_name
, max, width
= None, height
= None,
1024 fav_seat
= None, locations
= None):
1025 site_node
= self
.get_site_node(site_name
)
1026 layout_node
= self
.get_layout_node(site_node
, max)
1027 # TODO: how do we support inserting new layouts?
1028 if layout_node
is None:
1030 for i
in range(1, max + 1):
1031 location_node
= self
.get_location_node(layout_node
, i
)
1032 location_node
.setAttribute("x", str( locations
[i
-1][0] ))
1033 location_node
.setAttribute("y", str( locations
[i
-1][1] ))
1034 self
.supported_sites
[site_name
].layout
[max].location
[i
] = ( locations
[i
-1][0], locations
[i
-1][1] )
1036 def edit_site(self
, site_name
, enabled
, screen_name
, history_path
):
1037 site_node
= self
.get_site_node(site_name
)
1038 site_node
.setAttribute("enabled", enabled
)
1039 site_node
.setAttribute("screen_name", screen_name
)
1040 site_node
.setAttribute("HH_path", history_path
)
1042 def editStats(self
, gameName
, statArray
):
1043 """replaces stat selection for the given gameName with the given statArray"""
1044 gameNode
= self
.getGameNode(gameName
)
1045 statNodes
= gameNode
.getElementsByTagName("stat")
1047 for node
in statNodes
:
1048 gameNode
.removeChild(node
)
1050 gameNode
.setAttribute("rows", str(len(statArray
)))
1051 gameNode
.setAttribute("cols", str(len(statArray
[0])))
1053 for rowNumber
in range(len(statArray
)):
1054 for columnNumber
in range(len(statArray
[rowNumber
])):
1055 newStat
=self
.doc
.createElement("stat")
1057 newAttrStatName
=self
.doc
.createAttribute("stat_name")
1058 newStat
.setAttributeNode(newAttrStatName
)
1059 newStat
.setAttribute("stat_name", statArray
[rowNumber
][columnNumber
])
1061 newAttrStatName
=self
.doc
.createAttribute("row")
1062 newStat
.setAttributeNode(newAttrStatName
)
1063 newStat
.setAttribute("row", str(rowNumber
))
1065 newAttrStatName
=self
.doc
.createAttribute("col")
1066 newStat
.setAttributeNode(newAttrStatName
)
1067 newStat
.setAttribute("col", str(columnNumber
))
1069 newAttrStatName
=self
.doc
.createAttribute("click")
1070 newStat
.setAttributeNode(newAttrStatName
)
1071 newStat
.setAttribute("click", "tog_decorate")
1073 newAttrStatName
=self
.doc
.createAttribute("popup")
1074 newStat
.setAttributeNode(newAttrStatName
)
1075 newStat
.setAttribute("popup", "default")
1077 newAttrStatName
=self
.doc
.createAttribute("tip")
1078 newStat
.setAttributeNode(newAttrStatName
)
1079 newStat
.setAttribute("tip", "tip1")
1081 gameNode
.appendChild(newStat
)
1082 statNodes
= gameNode
.getElementsByTagName("stat") #TODO remove this line?
1085 def edit_aux_layout(self
, aux_name
, max, width
= None, height
= None, locations
= None):
1086 aux_node
= self
.get_aux_node(aux_name
)
1087 layout_node
= self
.get_layout_node(aux_node
, max)
1088 if layout_node
is None:
1089 print "aux node not found"
1091 print "editing locations =", locations
1092 for (i
, pos
) in locations
.iteritems():
1093 location_node
= self
.get_location_node(layout_node
, i
)
1094 location_node
.setAttribute("x", str( locations
[i
][0] ))
1095 location_node
.setAttribute("y", str( locations
[i
][1] ))
1097 self
.aux_windows
[aux_name
].layout
[max].common
= ( locations
[i
][0], locations
[i
][1] )
1099 self
.aux_windows
[aux_name
].layout
[max].location
[i
] = ( locations
[i
][0], locations
[i
][1] )
1101 #NOTE: we got a nice Database class, so why map it again here?
1102 # user input validation should be done when initializing the Database class. this allows to give appropriate feddback when something goes wrong
1103 # try ..except is evil here. it swallows all kinds of errors. dont do this
1104 # naming database types 2, 3, 4 on the fly is no good idea. i see this all over the code. better use some globally defined consts (see DATABASE_TYPE_*)
1105 # i would like to drop this method entirely and replace it by get_selected_database() or better get_active_database(), returning one of our Database instances
1106 # thus we can drop self.db_selected (holding database name) entirely and replace it with self._active_database = Database, avoiding to define the same
1107 # thing multiple times
1108 def get_db_parameters(self
):
1110 name
= self
.db_selected
1111 # TODO: What's up with all the exception handling here?!
1112 try: db
['db-databaseName'] = name
1115 try: db
['db-desc'] = self
.supported_databases
[name
].db_desc
1118 try: db
['db-host'] = self
.supported_databases
[name
].db_ip
1121 try: db
['db-user'] = self
.supported_databases
[name
].db_user
1124 try: db
['db-password'] = self
.supported_databases
[name
].db_pass
1127 try: db
['db-server'] = self
.supported_databases
[name
].db_server
1130 db
['db-backend'] = self
.get_backend(self
.supported_databases
[name
].db_server
)
1134 def set_db_parameters(self
, db_name
= 'fpdb', db_ip
= None, db_user
= None,
1135 db_pass
= None, db_desc
= None, db_server
= None,
1137 db_node
= self
.get_db_node(db_name
)
1138 default
= default
.lower()
1139 defaultb
= string_to_bool(default
, False)
1141 if db_desc
is not None: db_node
.setAttribute("db_desc", db_desc
)
1142 if db_ip
is not None: db_node
.setAttribute("db_ip", db_ip
)
1143 if db_user
is not None: db_node
.setAttribute("db_user", db_user
)
1144 if db_pass
is not None: db_node
.setAttribute("db_pass", db_pass
)
1145 if db_server
is not None: db_node
.setAttribute("db_server", db_server
)
1146 if defaultb
or self
.db_selected
== db_name
:
1147 db_node
.setAttribute("default", "True")
1148 for dbn
in self
.doc
.getElementsByTagName("database"):
1149 if dbn
.getAttribute('db_name') != db_name
and dbn
.hasAttribute("default"):
1150 dbn
.removeAttribute("default")
1151 elif db_node
.hasAttribute("default"):
1152 db_node
.removeAttribute("default")
1153 if self
.supported_databases
.has_key(db_name
):
1154 if db_desc
is not None: self
.supported_databases
[db_name
].dp_desc
= db_desc
1155 if db_ip
is not None: self
.supported_databases
[db_name
].dp_ip
= db_ip
1156 if db_user
is not None: self
.supported_databases
[db_name
].dp_user
= db_user
1157 if db_pass
is not None: self
.supported_databases
[db_name
].dp_pass
= db_pass
1158 if db_server
is not None: self
.supported_databases
[db_name
].dp_server
= db_server
1159 self
.supported_databases
[db_name
].db_selected
= defaultb
1161 self
.db_selected
= db_name
1164 def add_db_parameters(self
, db_name
= 'fpdb', db_ip
= None, db_user
= None,
1165 db_pass
= None, db_desc
= None, db_server
= None,
1167 default
= default
.lower()
1168 defaultb
= string_to_bool(default
, False)
1169 if db_name
in self
.supported_databases
:
1170 raise ValueError("Database names must be unique")
1172 db_node
= self
.get_db_node(db_name
)
1174 for db_node
in self
.doc
.getElementsByTagName("supported_databases"):
1175 # should only be one supported_databases element, use last one if there are several
1176 suppdb_node
= db_node
1177 t_node
= self
.doc
.createTextNode(" ")
1178 suppdb_node
.appendChild(t_node
)
1179 db_node
= self
.doc
.createElement("database")
1180 suppdb_node
.appendChild(db_node
)
1181 t_node
= self
.doc
.createTextNode("\r\n ")
1182 suppdb_node
.appendChild(t_node
)
1183 db_node
.setAttribute("db_name", db_name
)
1184 if db_desc
is not None: db_node
.setAttribute("db_desc", db_desc
)
1185 if db_ip
is not None: db_node
.setAttribute("db_ip", db_ip
)
1186 if db_user
is not None: db_node
.setAttribute("db_user", db_user
)
1187 if db_pass
is not None: db_node
.setAttribute("db_pass", db_pass
)
1188 if db_server
is not None: db_node
.setAttribute("db_server", db_server
)
1190 db_node
.setAttribute("default", "True")
1191 for dbn
in self
.doc
.getElementsByTagName("database"):
1192 if dbn
.getAttribute('db_name') != db_name
and dbn
.hasAttribute("default"):
1193 dbn
.removeAttribute("default")
1194 elif db_node
.hasAttribute("default"):
1195 db_node
.removeAttribute("default")
1197 if db_desc
is not None: db_node
.setAttribute("db_desc", db_desc
)
1198 if db_ip
is not None: db_node
.setAttribute("db_ip", db_ip
)
1199 if db_user
is not None: db_node
.setAttribute("db_user", db_user
)
1200 if db_pass
is not None: db_node
.setAttribute("db_pass", db_pass
)
1201 if db_server
is not None: db_node
.setAttribute("db_server", db_server
)
1202 if defaultb
or self
.db_selected
== db_name
:
1203 db_node
.setAttribute("default", "True")
1204 elif db_node
.hasAttribute("default"):
1205 db_node
.removeAttribute("default")
1207 if self
.supported_databases
.has_key(db_name
):
1208 if db_desc
is not None: self
.supported_databases
[db_name
].dp_desc
= db_desc
1209 if db_ip
is not None: self
.supported_databases
[db_name
].dp_ip
= db_ip
1210 if db_user
is not None: self
.supported_databases
[db_name
].dp_user
= db_user
1211 if db_pass
is not None: self
.supported_databases
[db_name
].dp_pass
= db_pass
1212 if db_server
is not None: self
.supported_databases
[db_name
].dp_server
= db_server
1213 self
.supported_databases
[db_name
].db_selected
= defaultb
1215 db
= Database(node
=db_node
)
1216 self
.supported_databases
[db
.db_name
] = db
1219 self
.db_selected
= db_name
1222 def get_backend(self
, name
):
1223 """Returns the number of the currently used backend"""
1224 if name
== DATABASE_TYPE_MYSQL
:
1226 elif name
== DATABASE_TYPE_POSTGRESQL
:
1228 elif name
== DATABASE_TYPE_SQLITE
:
1230 # sqlcoder: this assignment fixes unicode problems for me with sqlite (windows, cp1252)
1231 # feel free to remove or improve this if you understand the problems
1232 # better than me (not hard!)
1233 Charset
.not_needed1
, Charset
.not_needed2
, Charset
.not_needed3
= True, True, True
1235 raise ValueError('Unsupported database backend: %s' % self
.supported_databases
[name
].db_server
)
1239 def getDefaultSite(self
):
1240 "Returns first enabled site or None"
1241 for site_name
,site
in self
.supported_sites
.iteritems():
1246 # Allow to change the menu appearance
1247 def get_hud_ui_parameters(self
):
1250 default_text
= 'FPDB Menu - Right click\nLeft-Drag to Move'
1252 hui
['label'] = self
.ui
.label
1253 if self
.ui
.label
== '': # Empty menu label is a big no-no
1254 hui
['label'] = default_text
1256 hui
['label'] = default_text
1258 try: hui
['hud_style'] = self
.ui
.hud_style
1259 except: hui
['hud_style'] = 'A' # default is show stats for All-time, also S(session) and T(ime)
1261 try: hui
['hud_days'] = int(self
.ui
.hud_days
)
1262 except: hui
['hud_days'] = 90
1264 try: hui
['aggregate_ring'] = self
.ui
.aggregate_ring
1265 except: hui
['aggregate_ring'] = False
1267 try: hui
['aggregate_tour'] = self
.ui
.aggregate_tour
1268 except: hui
['aggregate_tour'] = True
1270 try: hui
['agg_bb_mult'] = self
.ui
.agg_bb_mult
1271 except: hui
['agg_bb_mult'] = 1
1273 try: hui
['seats_style'] = self
.ui
.seats_style
1274 except: hui
['seats_style'] = 'A' # A / C / E, use A(ll) / C(ustom) / E(xact) seat numbers
1276 try: hui
['seats_cust_nums'] = self
.ui
.seats_cust_nums
1277 except: hui
['seats_cust_nums'] = ['n/a', 'n/a', (2,2), (3,4), (3,5), (4,6), (5,7), (6,8), (7,9), (8,10), (8,10)]
1281 try: hui
['h_hud_style'] = self
.ui
.h_hud_style
1282 except: hui
['h_hud_style'] = 'S'
1284 try: hui
['h_hud_days'] = int(self
.ui
.h_hud_days
)
1285 except: hui
['h_hud_days'] = 30
1287 try: hui
['h_aggregate_ring'] = self
.ui
.h_aggregate_ring
1288 except: hui
['h_aggregate_ring'] = False
1290 try: hui
['h_aggregate_tour'] = self
.ui
.h_aggregate_tour
1291 except: hui
['h_aggregate_tour'] = True
1293 try: hui
['h_agg_bb_mult'] = self
.ui
.h_agg_bb_mult
1294 except: hui
['h_agg_bb_mult'] = 1
1296 try: hui
['h_seats_style'] = self
.ui
.h_seats_style
1297 except: hui
['h_seats_style'] = 'A' # A / C / E, use A(ll) / C(ustom) / E(xact) seat numbers
1299 try: hui
['h_seats_cust_nums'] = self
.ui
.h_seats_cust_nums
1300 except: hui
['h_seats_cust_nums'] = ['n/a', 'n/a', (2,2), (3,4), (3,5), (4,6), (5,7), (6,8), (7,9), (8,10), (8,10)]
1305 def get_import_parameters(self
):
1307 try: imp
['callFpdbHud'] = self
.imp
.callFpdbHud
1308 except: imp
['callFpdbHud'] = True
1310 try: imp
['interval'] = self
.imp
.interval
1311 except: imp
['interval'] = 10
1313 # ResultsDirectory is the local cache for downloaded results
1314 # NOTE: try: except: doesn'tseem to be triggering
1316 if self
.imp
.ResultsDirectory
!= '':
1317 imp
['ResultsDirectory'] = self
.imp
.ResultsDirectory
1319 imp
['ResultsDirectory'] = "~/.fpdb/Results/"
1321 # hhBulkPath is the default location for bulk imports (if set)
1322 try: imp
['hhBulkPath'] = self
.imp
.hhBulkPath
1323 except: imp
['hhBulkPath'] = ""
1325 try: imp
['saveActions'] = self
.imp
.saveActions
1326 except: imp
['saveActions'] = False
1328 try: imp
['cacheSessions'] = self
.imp
.cacheSessions
1329 except: imp
['cacheSessions'] = False
1331 try: imp
['sessionTimeout'] = self
.imp
.sessionTimeout
1332 except: imp
['sessionTimeout'] = 30
1334 try: imp
['saveStarsHH'] = self
.imp
.saveStarsHH
1335 except: imp
['saveStarsHH'] = False
1337 try: imp
['fastStoreHudCache'] = self
.imp
.fastStoreHudCache
1338 except: imp
['fastStoreHudCache'] = True
1342 def get_default_paths(self
, site
= None):
1343 if site
is None: site
= self
.getDefaultSite()
1346 path
= os
.path
.expanduser(self
.supported_sites
[site
].HH_path
)
1347 assert(os
.path
.isdir(path
) or os
.path
.isfile(path
)) # maybe it should try another site?
1348 paths
['hud-defaultPath'] = paths
['bulkImport-defaultPath'] = path
1349 if self
.imp
.hhBulkPath
:
1350 paths
['bulkImport-defaultPath'] = self
.imp
.hhBulkPath
1351 except AssertionError:
1352 paths
['hud-defaultPath'] = paths
['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **"
1355 def get_frames(self
, site
= "PokerStars"):
1356 if site
not in self
.supported_sites
: return False
1357 return self
.supported_sites
[site
].use_frames
== True
1359 def get_default_colors(self
, site
= "PokerStars"):
1361 if site
not in self
.supported_sites
or self
.supported_sites
[site
].hudopacity
== "":
1362 colors
['hudopacity'] = 0.90
1364 colors
['hudopacity'] = float(self
.supported_sites
[site
].hudopacity
)
1365 if site
not in self
.supported_sites
or self
.supported_sites
[site
].hudbgcolor
== "":
1366 colors
['hudbgcolor'] = "#FFFFFF"
1368 colors
['hudbgcolor'] = self
.supported_sites
[site
].hudbgcolor
1369 if site
not in self
.supported_sites
or self
.supported_sites
[site
].hudfgcolor
== "":
1370 colors
['hudfgcolor'] = "#000000"
1372 colors
['hudfgcolor'] = self
.supported_sites
[site
].hudfgcolor
1375 def get_default_font(self
, site
='PokerStars'):
1378 site
= self
.supported_sites
.get(site
, None)
1379 if site
is not None:
1383 font_size
= site
.font_size
1384 return font
, font_size
1386 def get_locations(self
, site_name
="PokerStars", max=8):
1387 site
= self
.supported_sites
.get(site_name
, None)
1388 if site
is not None:
1389 location
= site
.layout
.get(max, None)
1390 if location
is not None:
1391 return location
.location
1393 ( 0, 0), (684, 61), (689, 239), (692, 346),
1394 (586, 393), (421, 440), (267, 440), ( 0, 361),
1395 ( 0, 280), (121, 280), ( 46, 30)
1398 def get_aux_locations(self
, aux
= "mucked", max = "9"):
1401 locations
= self
.aux_windows
[aux
].layout
[max].location
1403 locations
= ( ( 0, 0), (684, 61), (689, 239), (692, 346),
1404 (586, 393), (421, 440), (267, 440), ( 0, 361),
1405 ( 0, 280), (121, 280), ( 46, 30) )
1408 def get_supported_sites(self
, all
=False):
1409 """Returns the list of supported sites."""
1411 return self
.supported_sites
.keys()
1413 return [site_name
for (site_name
, site
) in self
.supported_sites
.items() if site
.enabled
]
1415 def get_site_parameters(self
, site
):
1416 """Returns a dict of the site parameters for the specified site"""
1418 parms
["converter"] = self
.supported_sites
[site
].converter
1419 parms
["decoder"] = self
.supported_sites
[site
].decoder
1420 parms
["hudbgcolor"] = self
.supported_sites
[site
].hudbgcolor
1421 parms
["hudfgcolor"] = self
.supported_sites
[site
].hudfgcolor
1422 parms
["hudopacity"] = self
.supported_sites
[site
].hudopacity
1423 parms
["screen_name"] = self
.supported_sites
[site
].screen_name
1424 parms
["site_path"] = self
.supported_sites
[site
].site_path
1425 parms
["table_finder"] = self
.supported_sites
[site
].table_finder
1426 parms
["HH_path"] = self
.supported_sites
[site
].HH_path
1427 parms
["site_name"] = self
.supported_sites
[site
].site_name
1428 parms
["aux_window"] = self
.supported_sites
[site
].aux_window
1429 parms
["font"] = self
.supported_sites
[site
].font
1430 parms
["font_size"] = self
.supported_sites
[site
].font_size
1431 parms
["enabled"] = self
.supported_sites
[site
].enabled
1432 parms
["xpad"] = self
.supported_sites
[site
].xpad
1433 parms
["ypad"] = self
.supported_sites
[site
].ypad
1434 parms
["xshift"] = self
.supported_sites
[site
].xshift
1435 parms
["yshift"] = self
.supported_sites
[site
].yshift
1438 def set_site_parameters(self
, site_name
, converter
= None, decoder
= None,
1439 hudbgcolor
= None, hudfgcolor
= None,
1440 hudopacity
= None, screen_name
= None,
1441 site_path
= None, table_finder
= None,
1442 HH_path
= None, enabled
= None,
1443 font
= None, font_size
= None):
1444 """Sets the specified site parameters for the specified site."""
1445 site_node
= self
.get_site_node(site_name
)
1446 if db_node
is not None:
1447 if converter
is not None: site_node
.setAttribute("converter", converter
)
1448 if decoder
is not None: site_node
.setAttribute("decoder", decoder
)
1449 if hudbgcolor
is not None: site_node
.setAttribute("hudbgcolor", hudbgcolor
)
1450 if hudfgcolor
is not None: site_node
.setAttribute("hudfgcolor", hudfgcolor
)
1451 if hudopacity
is not None: site_node
.setAttribute("hudopacity", hudopacity
)
1452 if screen_name
is not None: site_node
.setAttribute("screen_name", screen_name
)
1453 if site_path
is not None: site_node
.setAttribute("site_path", site_path
)
1454 if table_finder
is not None: site_node
.setAttribute("table_finder", table_finder
)
1455 if HH_path
is not None: site_node
.setAttribute("HH_path", HH_path
)
1456 if enabled
is not None: site_node
.setAttribute("enabled", enabled
)
1457 if font
is not None: site_node
.setAttribute("font", font
)
1458 if font_size
is not None: site_node
.setAttribute("font_size", font_size
)
1461 def set_site_ids(self
, sites
):
1462 self
.site_ids
= dict(sites
)
1464 def get_site_id(self
, site
):
1465 return( self
.site_ids
[site
] )
1467 def get_aux_windows(self
):
1468 """Gets the list of mucked window formats in the configuration."""
1469 return self
.aux_windows
.keys()
1471 def get_aux_parameters(self
, name
):
1472 """Gets a dict of mucked window parameters from the named mw."""
1474 if self
.aux_windows
.has_key(name
):
1475 for key
in dir(self
.aux_windows
[name
]):
1476 if key
.startswith('__'): continue
1477 value
= getattr(self
.aux_windows
[name
], key
)
1478 if callable(value
): continue
1484 def get_game_parameters(self
, name
):
1485 """Get the configuration parameters for the named game."""
1487 if self
.supported_games
.has_key(name
):
1488 param
['game_name'] = self
.supported_games
[name
].game_name
1489 param
['rows'] = self
.supported_games
[name
].rows
1490 param
['cols'] = self
.supported_games
[name
].cols
1491 param
['xpad'] = self
.supported_games
[name
].xpad
1492 param
['ypad'] = self
.supported_games
[name
].ypad
1493 param
['xshift'] = self
.supported_games
[name
].xshift
1494 param
['yshift'] = self
.supported_games
[name
].yshift
1495 param
['aux'] = self
.supported_games
[name
].aux
1498 def get_supported_games(self
):
1499 """Get the list of supported games."""
1501 for game
in self
.supported_games
.keys():
1502 sg
.append(self
.supported_games
[game
].game_name
)
1505 def execution_path(self
, filename
):
1506 """Join the fpdb path to filename."""
1507 return os
.path
.join(os
.path
.dirname(inspect
.getfile(sys
._getframe
(0))), filename
)
1509 def get_general_params(self
):
1510 return( self
.general
)
1512 def get_gui_cash_stat_params(self
):
1513 return( self
.gui_cash_stats
)
1515 if __name__
== "__main__":
1518 print "\n----------- SUPPORTED SITES -----------"
1519 for s
in c
.supported_sites
.keys():
1520 print c
.supported_sites
[s
]
1521 print "----------- END SUPPORTED SITES -----------"
1524 print "\n----------- SUPPORTED GAMES -----------"
1525 for game
in c
.supported_games
.keys():
1526 print c
.supported_games
[game
]
1527 print "----------- END SUPPORTED GAMES -----------"
1530 print "\n----------- SUPPORTED DATABASES -----------"
1531 for db
in c
.supported_databases
.keys():
1532 print c
.supported_databases
[db
]
1533 print "----------- END SUPPORTED DATABASES -----------"
1535 print "\n----------- AUX WINDOW FORMATS -----------"
1536 for w
in c
.aux_windows
.keys():
1537 print c
.aux_windows
[w
]
1538 print "----------- END AUX WINDOW FORMATS -----------"
1540 print "\n----------- HAND HISTORY CONVERTERS -----------"
1541 for w
in c
.hhcs
.keys():
1543 print "----------- END HAND HISTORY CONVERTERS -----------"
1545 print "\n----------- POPUP WINDOW FORMATS -----------"
1546 for w
in c
.popup_windows
.keys():
1547 print c
.popup_windows
[w
]
1548 print "----------- END POPUP WINDOW FORMATS -----------"
1550 print "\n----------- IMPORT -----------"
1551 # print c.imp # Need to add an str method for imp to print
1552 print "----------- END IMPORT -----------"
1554 c
.edit_layout("PokerStars", 6, locations
=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) ))
1555 c
.save(file="testout.xml")
1557 print "db = ", c
.get_db_parameters()
1558 # print "imp = ", c.get_import_parameters()
1559 print "paths = ", c
.get_default_paths("PokerStars")
1560 print "colors = ", c
.get_default_colors("PokerStars")
1561 print "locs = ", c
.get_locations("PokerStars", 8)
1562 for mw
in c
.get_aux_windows():
1563 print c
.get_aux_parameters(mw
)
1565 print "mucked locations =", c
.get_aux_locations('mucked', 9)
1566 # c.edit_aux_layout('mucked', 9, locations = [(487, 113), (555, 469), (572, 276), (522, 345),
1567 # (333, 354), (217, 341), (150, 273), (150, 169), (230, 115)])
1568 # print "mucked locations =", c.get_aux_locations('mucked', 9)
1570 for site
in c
.supported_sites
.keys():
1571 print "site = ", site
,
1572 print c
.get_site_parameters(site
)
1573 print c
.get_default_font(site
)
1575 for game
in c
.get_supported_games():
1576 print c
.get_game_parameters(game
)
1578 for hud_param
, value
in c
.get_hud_ui_parameters().iteritems():
1579 print "hud param %s = %s" % (hud_param
, value
)
1581 print "start up path = ", c
.execution_path("")
1583 print "gui_cash_stats =", c
.gui_cash_stats
1586 from xml
.dom
.ext
import PrettyPrint
1587 for site_node
in c
.doc
.getElementsByTagName("site"):
1588 PrettyPrint(site_node
, stream
=sys
.stdout
, encoding
="utf-8")
1590 print "xml.dom.ext needs PyXML to be installed!"
1592 print "\n----------- ENVIRONMENT CONSTANTS -----------"
1593 print "Configuration.install_method {source,exe} =", INSTALL_METHOD
1594 print "Configuration.fpdb_program_path =", FPDB_PROGRAM_PATH
1595 print "Configuration.appdata_path =", APPDATA_PATH
1596 print "Configuration.config_path =", CONFIG_PATH
1597 print "Configuration.os_family {Linux,Mac,XP,Win7} =", OS_FAMILY
1598 print "Configuration.posix {True/False} =", POSIX
1599 print "Configuration.python_version =", PYTHON_VERSION
1600 print "----------- END ENVIRONMENT CONSTANTS -----------"
1602 print "press enter to end"
1603 sys
.stdin
.readline()