Coverage for Configuration.py: 49%
1282 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 18:50 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 18:50 +0000
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Configuration####
4#Handles fpdb/fpdb-hud configuration files.
5# Copyright 2008-2012, Ray E. Barker
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21########################################################################
23#TODO fix / rethink edit stats - it is broken badly just now
25# Standard Library modules
26from __future__ import with_statement
27from __future__ import print_function
30#import L10n
31#_ = L10n.get_translation()
33import codecs
34import os
35import sys
36import inspect
37import string
38import shutil
39import locale
40import re
41import xml.dom.minidom
42from xml.dom.minidom import Node
44import platform
47if platform.system() == 'Windows':
48 #import winpaths
49 #winpaths_appdata = winpaths.get_appdata()
50 import os
51 winpaths_appdata = os.getenv('APPDATA')
52 #winpaths_appdata = os.getcwd()
53 winpaths_appdata = winpaths_appdata.replace("\\", "/")
54 print ('winpaths_appdata:') #debug
55 print (winpaths_appdata) #debug
56else:
57 winpaths_appdata = False
59import logging, logging.config
62# config version is used to flag a warning at runtime if the users config is
63# out of date.
64# The CONFIG_VERSION should be incremented __ONLY__ if the add_missing_elements()
65# method cannot update existing standard configurations
66CONFIG_VERSION = 83
68#
69# Setup constants
70# code is centralised here to ensure uniform handling of path names
71# especially important when user directory includes non-ascii chars
72#
73# INSTALL_METHOD ("source" or "exe")
74# FPDB_ROOT_PATH (path to the root fpdb installation dir root (normally ...../fpdb)
75# APPDATA_PATH (root path for appdata eg /~ or appdata)
76# CONFIG_PATH (path to the directory holding logs, sqlite db's and config)
77# GRAPHICS_PATH (path to graphics assets (normally .gfx)
78# PYFPDB_PATH (path to py's)
79# OS_FAMILY (OS Family for installed system (Linux, Mac, XP, Win7)
80# POSIX (True=Linux or Mac platform, False=Windows platform)
81# PYTHON_VERSION (n.n)
83if hasattr(sys, "frozen"):
84 if platform.system() == 'Windows':
85 INSTALL_METHOD = "exe"
86 elif platform.system() == 'Darwin':
87 INSTALL_METHOD = "app"
88 elif 'APPDIR' in os.environ:
89 INSTALL_METHOD = "appimage"
90 else:
91 INSTALL_METHOD = "unknown"
92else:
93 INSTALL_METHOD = "source"
95if INSTALL_METHOD == "exe" :
96 FPDB_ROOT_PATH = os.path.dirname(sys.executable)
98 FPDB_ROOT_PATH = FPDB_ROOT_PATH.replace("\\", "/")
99 # should be exe path to \fpdbroot\pyfpdb
100elif INSTALL_METHOD == "app":
101 FPDB_ROOT_PATH = os.path.dirname(sys.executable)
102elif INSTALL_METHOD == "appimage":
103 FPDB_ROOT_PATH = os.environ['APPDIR']
104elif sys.path[0] == "": # we are probably running directly (>>>import Configuration)
105 temp = os.getcwd() # should be ./pyfpdb
106 print(temp)
107 FPDB_ROOT_PATH = os.path.join(temp, os.pardir) # go up one level (to fpdbroot)
108else: # all other cases
109 #FPDB_ROOT_PATH = os.path.dirname(sys.path[0]) # should be source path to /fpdbroot
110 FPDB_ROOT_PATH = os.getcwd()
112sysPlatform = platform.system() #Linux, Windows, Darwin
113if sysPlatform[0:5] == 'Linux':
114 OS_FAMILY = 'Linux'
115elif sysPlatform == 'Darwin':
116 OS_FAMILY = 'Mac'
117elif sysPlatform == 'Windows':
118 if platform.release() != 'XP':
119 OS_FAMILY = 'Win7' #Vista and win7
120 else:
121 OS_FAMILY = 'XP'
122else:
123 OS_FAMILY = False
125#GRAPHICS_PATH = os.path.join(FPDB_ROOT_PATH, "gfx")
126#PYFPDB_PATH = os.path.join(FPDB_ROOT_PATH, "pyfpdb")
128if OS_FAMILY in ['XP', 'Win7']:
129 APPDATA_PATH = winpaths_appdata
130 CONFIG_PATH = os.path.join(APPDATA_PATH, "fpdb")
131 CONFIG_PATH = CONFIG_PATH.replace("\\", "/")
132 FPDB_ROOT_PATH = os.path.dirname(sys.executable)
133 FPDB_ROOT_PATH = FPDB_ROOT_PATH.replace("\\", "/")
134 if INSTALL_METHOD == "source":
135 script = os.path.realpath(__file__)
136 print("SCript path:", script)
137 script = script.replace("\\", "/")
138 script = script.rsplit('/',1)[0]
139 GRAPHICS_PATH = script+'/gfx'
140 else:
141 GRAPHICS_PATH = os.path.join(FPDB_ROOT_PATH, "gfx")
142 GRAPHICS_PATH = GRAPHICS_PATH.replace("\\", "/")
143 PYFPDB_PATH = os.path.join(FPDB_ROOT_PATH, "pyfpdb")
144 PYFPDB_PATH = PYFPDB_PATH.replace("\\", "/")
145elif OS_FAMILY == 'Mac':
146 APPDATA_PATH = os.getenv("HOME")
147 CONFIG_PATH = os.path.join(APPDATA_PATH, ".fpdb")
148 GRAPHICS_PATH = os.path.join(FPDB_ROOT_PATH, "gfx")
149 PYFPDB_PATH = os.path.join(FPDB_ROOT_PATH, "pyfpdb")
150elif OS_FAMILY == 'Linux':
151 APPDATA_PATH = os.path.expanduser(u"~")
152 CONFIG_PATH = os.path.join(APPDATA_PATH, ".fpdb")
153 GRAPHICS_PATH = os.path.join(FPDB_ROOT_PATH,"gfx")
154 PYFPDB_PATH = os.path.join(FPDB_ROOT_PATH)
155else:
156 APPDATA_PATH = False
157 CONFIG_PATH = False
159if os.name == 'posix':
160 POSIX = True
161else:
162 POSIX = False
164PYTHON_VERSION = sys.version[:3]
166# logging has been set up in fpdb.py or HUD_main.py, use their settings:
167log = logging.getLogger("config")
169LOGLEVEL = {'DEBUG' : logging.DEBUG,
170 'INFO' : logging.INFO,
171 'WARNING' : logging.WARNING,
172 'ERROR' : logging.ERROR,
173 'CRITICAL': logging.CRITICAL}
177def get_config(file_name, fallback = True):
178 """Looks in cwd and in self.default_config_path for a config file."""
180 #FIXME
181 # This function has become difficult to understand, plus it no-longer
182 # just looks for a config file, it actually does file copying
184 # look for example file even if not used here, path is returned to caller
185 config_found,example_found,example_copy = False,False,False
186 config_path, example_path = None,None
187 if sysPlatform == 'Windows':
188 print('windows TRUE1')
189 if platform.release() != 'XP':
190 OS_FAMILY = 'Win7' #Vista and win7
191 print('windows TRUE2')
192 else:
193 OS_FAMILY = 'XP'
194 print('windows TRUE3')
195 if OS_FAMILY == 'XP' or 'Win7':
196 print('windows TRUE4')
197 config_path = os.path.join(CONFIG_PATH, file_name)
198 config_path = config_path.replace("\\", "/")
199 else:
200 config_path = os.path.join(CONFIG_PATH, file_name)
201 print ("config_path raw=", config_path)
202 if os.path.exists(config_path): # there is a file in the cwd
203 print(os.path.exists(config_path))
204 config_found = True
205 print (config_found)
206 fallback = False
207 print(fallback) # so we use it
208 else: # no file in the cwd, look where it should be in the first place
209 config_path = os.path.join(CONFIG_PATH, file_name)
210 config_path = config_path.replace("\\", "/")
211 print ("config path 2=", config_path)
212 if os.path.exists(config_path):
213 config_found = True
214 print (config_found)
215 fallback = False
216 print(fallback)
218 if POSIX:
219 # If we're on linux, try to copy example from the place
220 # debian package puts it; get_default_config_path() creates
221 # the config directory for us so there's no need to check it
222 # again
223 example_path = '/usr/share/python-fpdb/' + file_name + '.example'
224 if not os.path.exists(example_path):
225 if os.path.exists(file_name + '.example'):
226 example_path = file_name + '.example'
227 else:
228 example_path = os.path.join(PYFPDB_PATH, file_name + '.example')
229 if not config_found and fallback:
230 try:
231 shutil.copyfile(example_path, config_path)
232 example_copy = True
233 msg = ("Config file has been created at %s.") % (config_path)
234 log.info(msg)
235 except IOError:
236 try:
237 example_path = file_name + '.example'
238 shutil.copyfile(example_path, config_path)
239 example_copy = True
240 msg = ("Config file has been created at %s.") % (config_path)
241 log.info(msg)
242 except IOError:
243 pass
245# OK, fall back to the .example file, should be in the start dir
247 elif os.path.exists(os.path.join(CONFIG_PATH, file_name + '.example').replace("\\", "/")):
248 try:
249 print("exemple path ok")
250 example_path = os.path.join(CONFIG_PATH, file_name + '.example').replace("\\", "/")
251 print ('exemple_path:', example_path)
252 if not config_found and fallback:
253 shutil.copyfile(example_path, config_path)
254 example_copy = True
255 log.info (("No %r found in \"%r\" or \"%r\".") % (file_name, FPDB_ROOT_PATH, CONFIG_PATH) \
256 + " " + ("Config file has been created at %r.") % (config_path+"\n") )
258 except:
259 print((("Error copying .example config file, cannot fall back. Exiting."), "\n"))
260 sys.stderr.write(("Error copying .example config file, cannot fall back. Exiting.")+"\n")
261 sys.stderr.write( str(sys.exc_info()) )
262 sys.exit()
263 elif fallback:
264 print(fallback)
265 sys.stderr.write((("No %s found, cannot fall back. Exiting.") % file_name) + "\n")
266 sys.exit()
269 return (config_path,example_copy,example_path)
271def set_logfile(file_name):
272 (conf_file,copied,example_file) = get_config("logging.conf", fallback = False)
274 log_dir = os.path.join(CONFIG_PATH, 'log').replace('\\', '/')
275 check_dir(log_dir)
276 log_file = os.path.join(log_dir, file_name).replace('\\', '/')
277 if os.path.isfile(conf_file):
278 print('logging.conf file already exists')
279 else:
280 # create a file
281 print('copying logging.conf file in appdata rooming folder')
282 if conf_file:
283 try:
284 log_file = log_file.replace('\\', '/') # replace each \ with \\
285 logging.config.fileConfig(conf_file, {"logFile":log_file})
286 except Exception:
287 sys.stderr.write(f"Could not setup log file {file_name}")
289def check_dir(path, create = True):
290 """Check if a dir exists, optionally creates if not."""
291 if os.path.exists(path):
292 if os.path.isdir(path):
293 return path
294 else:
295 return False
296 if create:
297 path = path.replace('\\', '/')
298 msg = ("Creating directory: '%s'") % (path)
299 print(msg)
300 log.info(msg)
301 os.makedirs(path)#, "utf-8"))
302 else:
303 return False
305def normalizePath(path):
306 "Normalized existing pathes"
307 if os.path.exists(path):
308 return os.path.abspath(path)
309 return path
311########################################################################
312# application wide consts
314APPLICATION_NAME_SHORT = 'fpdb'
315APPLICATION_VERSION = 'xx.xx.xx'
317DATABASE_TYPE_POSTGRESQL = 'postgresql'
318DATABASE_TYPE_SQLITE = 'sqlite'
319DATABASE_TYPE_MYSQL = 'mysql'
320DATABASE_TYPES = (
321 DATABASE_TYPE_POSTGRESQL,
322 DATABASE_TYPE_SQLITE,
323 DATABASE_TYPE_MYSQL,
324 )
326LOCALE_ENCODING = locale.getpreferredencoding()
327if LOCALE_ENCODING in ("US-ASCII", "", None):
328 LOCALE_ENCODING = "cp1252"
329 if (os.uname()[0]!="Darwin"):
330 print((("Default encoding set to US-ASCII, defaulting to CP1252 instead."), ("Please report this problem.")))
332# needs LOCALE_ENCODING (above), imported for sqlite setup in Config class below
334import Charset
338########################################################################
339def string_to_bool(string, default=True):
340 """converts a string representation of a boolean value to boolean True or False
341 @param string: (str) the string to convert
342 @param default: value to return if the string can not be converted to a boolean value
343 """
344 string = string.lower()
345 if string in ('1', 'true', 't'):
346 return True
347 elif string in ('0', 'false', 'f'):
348 return False
349 return default
351class Layout(object):
352 def __init__(self, node):
354 self.max = int( node.getAttribute('max') )
355 self.width = int( node.getAttribute('width') )
356 self.height = int( node.getAttribute('height') )
358 self.location = []
359 self.hh_seats = []
360 self.location = [None for x in range(self.max+1)] # fill array with max seats+1 empty entries
361 # hh_seats is used to map the seat numbers specified in hand history files (and stored in db) onto
362 # the contiguous integerss, 1 to self.max, used to index hud stat_windows (and aw seat_windows) for display
363 # For most sites these numbers are the same, but some sites (e.g. iPoker) omit seat numbers in hand histories
364 # for tables smaller than 10-max.
365 self.hh_seats= [None for x in range(self.max+1)] # fill array with max seats+1 empty entries
367 for location_node in node.getElementsByTagName('location'):
368 hud_seat = location_node.getAttribute('seat')
369 if hud_seat != "":
371 # if hist_seat for this seat number is specified in the layout, then store it in the hh_seats list
372 hist_seat = location_node.getAttribute('hist_seat') #XXX
373 if hist_seat:
374 self.hh_seats[int( hud_seat )] = int( hist_seat )
375 else:
376 # .. otherwise just store the original seat number in the hh_seats list
377 self.hh_seats[int( hud_seat )] = int( hud_seat )
378 self.location[int( hud_seat )] = (int( location_node.getAttribute('x') ), int( location_node.getAttribute('y')))
379 elif location_node.getAttribute('common') != "":
380 self.common = (int( location_node.getAttribute('x') ), int( location_node.getAttribute('y')))
382 def __str__(self):
383 if hasattr(self, 'name'):
384 name = str(self.name)
385 temp = " Layout = %d max, width= %d, height = %d" % (self.max, self.width, self.height)
386 if hasattr(self, 'fav_seat'): temp = temp + ", fav_seat = %d\n" % self.fav_seat
387 else: temp = temp + "\n"
388 if hasattr(self, "common"):
389 temp = temp + " Common = (%d, %d)\n" % (self.common[0], self.common[1])
390 temp = temp + " Locations = "
391 for i in range(1, len(self.location)):
392 temp = temp + "%s:(%d,%d) " % (self.hh_seats[i],self.location[i][0],self.location[i][1])
393 return temp + "\n"
395class Email(object):
396 def __init__(self, node):
397 self.node = node
398 self.host= node.getAttribute("host")
399 self.username = node.getAttribute("username")
400 self.password = node.getAttribute("password")
401 self.useSsl = node.getAttribute("useSsl")
402 self.folder = node.getAttribute("folder")
403 self.fetchType = node.getAttribute("fetchType")
405 def __str__(self):
406 return " email\n fetchType = %s host = %s\n username = %s password = %s\n useSsl = %s folder = %s" \
407 % (self.fetchType, self.host, self.username, self.password, self.useSsl, self.folder)
410class Site(object):
411 def __init__(self, node):
412 self.site_name = node.getAttribute("site_name")
413 self.screen_name = node.getAttribute("screen_name")
414 self.site_path = normalizePath(node.getAttribute("site_path"))
415 self.HH_path = normalizePath(node.getAttribute("HH_path"))
416 self.TS_path = normalizePath(node.getAttribute("TS_path"))
417 self.enabled = string_to_bool(node.getAttribute("enabled"), default=True)
418 self.aux_enabled = string_to_bool(node.getAttribute("aux_enabled"), default=True)
419 self.hud_menu_xshift = node.getAttribute("hud_menu_xshift")
420 self.hud_menu_xshift = 1 if self.hud_menu_xshift == "" else int(self.hud_menu_xshift)
421 self.hud_menu_yshift = node.getAttribute("hud_menu_yshift")
422 self.hud_menu_yshift = 1 if self.hud_menu_yshift == "" else int(self.hud_menu_yshift)
423 if node.hasAttribute("TS_path"):
424 self.TS_path = normalizePath(node.getAttribute("TS_path"))
425 else:
426 self.TS_path = ''
428 self.fav_seat = {}
429 for fav_node in node.getElementsByTagName('fav'):
430 max = int(fav_node.getAttribute("max"))
431 fav = int(fav_node.getAttribute("fav_seat"))
432 self.fav_seat[max] = fav
434 self.layout_set = {}
435 for site_layout_node in node.getElementsByTagName('layout_set'):
436 gt = site_layout_node.getAttribute("game_type")
437 ls = site_layout_node.getAttribute("ls")
438 self.layout_set[gt]=ls
440 self.emails = {}
441 for email_node in node.getElementsByTagName('email'):
442 email = Email(email_node)
443 self.emails[email.fetchType] = email
446 def __str__(self):
447 temp = "Site = " + self.site_name + "\n"
448 for key in dir(self):
449 if key.startswith('__'): continue
450 if key == 'layout_set': continue
451 if key == 'fav_seat': continue
452 if key == 'emails': continue
453 value = getattr(self, key)
454 if callable(value): continue
455 temp = temp + ' ' + key + " = " + str(value) + "\n"
457 for fetchtype in self.emails:
458 temp = temp + str(self.emails[fetchtype]) + "\n"
460 for game_type in self.layout_set:
461 temp = temp + " game_type = %s, layout_set = %s\n" % (game_type, self.layout_set[game_type])
463 for max in self.fav_seat:
464 temp = temp + " max = %s, fav_seat = %s\n" % (max, self.fav_seat[max])
466 return temp
469class Stat(object):
471 def __init__(self, node):
472 rowcol = node.getAttribute("_rowcol") # human string "(r,c)" values >0)
473 self.rows = node.getAttribute("rows")
474 self.cols = node.getAttribute("cols")
475 self.rowcol = tuple(int(s)-1 for s in rowcol[1:-1].split(',')) # tuple (r-1,c-1)
476 self.stat_name = node.getAttribute("_stat_name")
477 self.tip = node.getAttribute("tip")
478 self.click = node.getAttribute("click")
479 self.popup = node.getAttribute("popup")
480 self.hudprefix = node.getAttribute("hudprefix")
481 self.hudsuffix = node.getAttribute("hudsuffix")
482 self.hudcolor = node.getAttribute("hudcolor")
483 self.stat_loth = node.getAttribute("stat_loth")
484 self.stat_hith = node.getAttribute("stat_hith")
485 self.stat_locolor = node.getAttribute("stat_locolor")
486 self.stat_hicolor = node.getAttribute("stat_hicolor")
487 self.stat_midcolor = node.getAttribute("stat_midcolor")
489 def __str__(self):
490 temp = " _rowcol = %s, _stat_name = %s, \n" % (self.rowcol, self.stat_name)
491 for key in dir(self):
492 if key.startswith('__'): continue
493 if key == '_stat_name': continue
494 if key == '_rowcol': continue
495 value = getattr(self, key)
496 if callable(value): continue
497 temp = temp + ' ' + key + " = " + str(value) + "\n"
499 return temp
502class Stat_sets(object):
503 """Representation of a HUD display configuration
504 - stats: Dict of Tuples (position in HUD) -> Configuration.Stat
505 Exemple: {
506 (0,0): Stat(stat_name = 'vpip', stat_hicolor ='#F44336', ...),
507 (0,1): Stat(stat_name = 'pfr', stat_hicolor ='#F44336', ...),
508 ...
509 }
510 - rows, cols: siez of the HUD
511 """
513 def __init__(self, node):
514 self.name = node.getAttribute("name")
515 self.rows = int( node.getAttribute("rows") )
516 self.cols = int( node.getAttribute("cols") )
517 self.xpad = node.getAttribute("xpad")
518 self.xpad = 0 if self.xpad == "" else int(self.xpad)
519 self.ypad = node.getAttribute("ypad")
520 self.ypad = 0 if self.ypad == "" else int(self.ypad)
521 self.stats = None #
523 self.stats = {}
524 for stat_node in node.getElementsByTagName('stat'):
525 stat = Stat(stat_node)
526 self.stats[stat.rowcol] = stat # this is the key!
528 def __str__(self):
529 temp = "Name = " + self.name + "\n"
530 temp = temp + " rows = %d" % self.rows
531 temp = temp + " cols = %d" % self.cols
532 temp = temp + " xpad = %d" % self.xpad
533 temp = temp + " ypad = %d\n" % self.ypad
535 for stat in list(self.stats.keys()):
536 temp = temp + "%s" % self.stats[stat]
538 return temp
541class Database(object):
542 def __init__(self, node):
543 self.db_name = node.getAttribute("db_name")
544 self.db_desc = node.getAttribute("db_desc")
545 self.db_server = node.getAttribute("db_server").lower()
546 self.db_ip = node.getAttribute("db_ip")
547 self.db_port = node.getAttribute("db_port")
548 self.db_user = node.getAttribute("db_user")
549 self.db_pass = node.getAttribute("db_pass")
550 self.db_path = node.getAttribute("db_path")
551 self.db_selected = string_to_bool(node.getAttribute("default"), default=False)
552 log.debug("Database db_name:'%(name)s' db_server:'%(server)s' db_ip:'%(ip)s' db_port:'%(port)s' db_user:'%(user)s' db_pass (not logged) selected:'%(sel)s'" \
553 % { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'port':self.db_port,'user':self.db_user, 'sel':self.db_selected} )
555 def __str__(self):
556 temp = 'Database = ' + self.db_name + '\n'
557 for key in dir(self):
558 if key.startswith('__'): continue
559 value = getattr(self, key)
560 if callable(value): continue
561 temp = temp + ' ' + key + " = " + repr(value) + "\n"
562 return temp
565class Aux_window(object):
566 def __init__(self, node):
567 for (name, value) in list(node.attributes.items()):
568 setattr(self, name, value)
570 def __str__(self):
571 temp = 'Aux = ' + self.name + "\n"
572 for key in dir(self):
573 if key.startswith('__'): continue
574 value = getattr(self, key)
575 if callable(value): continue
576 temp = temp + ' ' + key + " = " + value + "\n"
578 return temp
581class Supported_games(object):
582 def __init__(self, node):
583 for (name, value) in list(node.attributes.items()):
584 setattr(self, name, value)
586 self.game_stat_set = {}
587 for game_stat_set_node in node.getElementsByTagName('game_stat_set'):
588 gss = Game_stat_set(game_stat_set_node)
589 self.game_stat_set[gss.game_type] = gss
591 def __str__(self):
592 temp = 'Supported_games = ' + self.game_name + "\n"
593 for key in dir(self):
594 if key.startswith('__'): continue
595 if key == 'game_stat_set': continue
596 if key == 'game_name': continue
597 value = getattr(self, key)
598 if callable(value): continue
599 temp = temp + ' ' + key + " = " + value + "\n"
601 for gs in self.game_stat_set:
602 temp = temp + "%s" % str(self.game_stat_set[gs])
603 return temp
606class Layout_set(object):
607 def __init__(self, node):
608 for (name, value) in list(node.attributes.items()):
609 setattr(self, name, value)
611 self.layout = {}
612 for layout_node in node.getElementsByTagName('layout'):
613 lo = Layout(layout_node)
614 self.layout[lo.max] = lo
616 def __str__(self):
617 temp = 'Layout set = ' + self.name + "\n"
618 for key in dir(self):
619 if key.startswith('__'): continue
620 if key == 'layout': continue
621 if key == 'name': continue
622 value = getattr(self, key)
623 if callable(value): continue
624 temp = temp + ' ' + key + " = " + value + "\n"
626 for layout in self.layout:
627 temp = temp + "%s" % self.layout[layout]
628 return temp
631class Game_stat_set(object):
632 def __init__(self, node):
633 self.game_type = node.getAttribute("game_type")
634 self.stat_set = node.getAttribute("stat_set")
636 def __str__(self):
637 return " Game Type: '%s' Stat Set: '%s'\n" % (self.game_type, self.stat_set)
640class HHC(object):
641 def __init__(self, node):
642 self.site = node.getAttribute("site")
643 self.converter = node.getAttribute("converter")
644 self.summaryImporter = node.getAttribute("summaryImporter")
646 def __str__(self):
647 return "%s:\tconverter: '%s' summaryImporter: '%s'" % (self.site, self.converter, self.summaryImporter)
650class Popup(object):
651 def __init__(self, node):
652 self.name = node.getAttribute("pu_name")
653 self.pu_class = node.getAttribute("pu_class")
654 self.pu_stats = []
655 self.pu_stats_submenu = []
657 for stat_node in node.getElementsByTagName('pu_stat'):
658 self.pu_stats.append(stat_node.getAttribute("pu_stat_name"))
659 #if stat_node.getAttribute("pu_stat_submenu"):
660 self.pu_stats_submenu.append(
661 tuple(
662 (stat_node.getAttribute("pu_stat_name"),
663 stat_node.getAttribute("pu_stat_submenu"))))
666 def __str__(self):
667 temp = "Popup = " + self.name + " Class = " + self.pu_class + "\n"
668 for stat in self.pu_stats:
669 temp = temp + " " + stat
670 return temp + "\n"
672class Import(object):
673 def __init__(self, node):
674 self.node = node
675 self.interval = node.getAttribute("interval")
676 self.sessionTimeout = string_to_bool(node.getAttribute("sessionTimeout") , default=30)
677 self.ResultsDirectory = node.getAttribute("ResultsDirectory")
678 self.hhBulkPath = node.getAttribute("hhBulkPath")
679 self.saveActions = string_to_bool(node.getAttribute("saveActions") , default=False)
680 self.cacheSessions = string_to_bool(node.getAttribute("cacheSessions") , default=False)
681 self.publicDB = string_to_bool(node.getAttribute("publicDB") , default=False)
682 self.callFpdbHud = string_to_bool(node.getAttribute("callFpdbHud") , default=False)
683 self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False)
684 self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH") , default=False)
685 if node.getAttribute("importFilters"):
686 self.importFilters = node.getAttribute("importFilters").split(",")
687 else:
688 self.importFilters = []
689 if node.getAttribute("timezone"):
690 self.timezone = node.getAttribute("timezone")
691 else:
692 self.timezone = "America/New_York"
694 def __str__(self):
695 return " interval = %s\n callFpdbHud = %s\n saveActions = %s\n cacheSessions = %s\n publicDB = %s\n sessionTimeout = %s\n fastStoreHudCache = %s\n ResultsDirectory = %s" \
696 % (self.interval, self.callFpdbHud, self.saveActions, self.cacheSessions, self.publicDB, self.sessionTimeout, self.fastStoreHudCache, self.ResultsDirectory)
698class HudUI(object):
699 def __init__(self, node):
700 self.node = node
701 self.label = node.getAttribute('label')
702 if node.hasAttribute('card_ht'): self.card_ht = node.getAttribute('card_ht')
703 if node.hasAttribute('card_wd'): self.card_wd = node.getAttribute('card_wd')
704 if node.hasAttribute('deck_type'): self.deck_type = node.getAttribute('deck_type')
705 if node.hasAttribute('card_back'): self.card_back = node.getAttribute('card_back')
706 #
707 if node.hasAttribute('stat_range'): self.stat_range = node.getAttribute('stat_range')
708 if node.hasAttribute('stat_days'): self.hud_days = node.getAttribute('stat_days')
709 if node.hasAttribute('aggregation_level_multiplier'): self.agg_bb_mult = node.getAttribute('aggregation_level_multiplier')
710 if node.hasAttribute('seats_style'): self.seats_style = node.getAttribute('seats_style')
711 if node.hasAttribute('seats_cust_nums_low'): self.seats_cust_nums_low = node.getAttribute('seats_cust_nums_low')
712 if node.hasAttribute('seats_cust_nums_high'): self.seats_cust_nums_high = node.getAttribute('seats_cust_nums_high')
713 #
714 if node.hasAttribute('hero_stat_range'): self.h_stat_range = node.getAttribute('hero_stat_range')
715 if node.hasAttribute('hero_stat_days'): self.h_hud_days = node.getAttribute('hero_stat_days')
716 if node.hasAttribute('hero_aggregation_level_multiplier'): self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier')
717 if node.hasAttribute('hero_seats_style'): self.h_seats_style = node.getAttribute('hero_seats_style')
718 if node.hasAttribute('hero_seats_cust_nums_low'): self.h_seats_cust_nums_low = node.getAttribute('hero_seats_cust_nums_low')
719 if node.hasAttribute('hero_seats_cust_nums_high'): self.h_seats_cust_nums_high = node.getAttribute('hero_seats_cust_nums_high')
722 def __str__(self):
723 return " label = %s\n" % self.label
726class General(dict):
727 def __init__(self):
728 super(General, self).__init__()
730 def add_elements(self, node):
731 # day_start - number n where 0.0 <= n < 24.0 representing start of day for user
732 # e.g. user could set to 4.0 for day to start at 4am local time
733 # [ HH_bulk_path was here - now moved to import section ]
734 for (name, value) in list(node.attributes.items()):
735 log.debug("config.general: adding %s = %s" % (name,value))
736 self[name] = value
738 try:
739 self["version"]=int(self["version"])
740 except KeyError:
741 self["version"]=0
742 self["ui_language"]="system"
743 self["config_difficulty"]="expert"
745 def get_defaults(self):
746 self["version"]=0
747 self["ui_language"]="system"
748 self["config_difficulty"]="expert"
749 self["config_wrap_len"]="-1"
750 self["day_start"]="5"
752 def __str__(self):
753 s = ""
754 for k in self:
755 s = s + " %s = %s\n" % (k, self[k])
756 return(s)
758class GUICashStats(list):
759 """<gui_cash_stats>
760 <col col_name="game" col_title="Game" disp_all="True" disp_posn="True" field_format="%s" field_type="str" xalignment="0.0" />
761 ...
762 </gui_cash_stats>
763 """
764 def __init__(self):
765 super(GUICashStats, self).__init__()
769 def add_elements(self, node):
770 # is this needed?
771 for child in node.childNodes:
772 if child.nodeType == child.ELEMENT_NODE:
773 col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment=None, None, True, True, "%s", "str", 0.0
775 if child.hasAttribute('col_name'): col_name = child.getAttribute('col_name')
776 if child.hasAttribute('col_title'): col_title = child.getAttribute('col_title')
777 if child.hasAttribute('disp_all'): disp_all = string_to_bool(child.getAttribute('disp_all'))
778 if child.hasAttribute('disp_posn'): disp_posn = string_to_bool(child.getAttribute('disp_posn'))
779 if child.hasAttribute('field_format'): field_format = child.getAttribute('field_format')
780 if child.hasAttribute('field_type'): field_type = child.getAttribute('field_type')
781 try:
782 if child.hasAttribute('xalignment'): xalignment = float(child.getAttribute('xalignment'))
783 except ValueError:
784 print(("bad number in xalignment was ignored"))
785 log.info(("bad number in xalignment was ignored"))
787 self.append( [col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment] )
789 def get_defaults(self):
790 """A list of defaults to be called, should there be no entry in config"""
791 # SQL column name, display title, display all, display positional, format, type, alignment
792 defaults = [ ['game', 'Game', True, True, '%s', 'str', 0.0],
793 ['hand', 'Hand', False, False, '%s', 'str', 0.0],
794 ['plposition', 'Posn', False, False, '%s', 'str', 1.0],
795 ['pname', 'Name', False, False, '%s', 'str', 0.0],
796 ['n', 'Hds', True, True, '%1.0f', 'str', 1.0],
797 ['avgseats', 'Seats', False, False, '%3.1f', 'str', 1.0],
798 ['vpip', 'VPIP', True, True, '%3.1f', 'str', 1.0],
799 ['pfr', 'PFR', True, True, '%3.1f', 'str', 1.0],
800 ['pf3', 'PF3', True, True, '%3.1f', 'str', 1.0],
801 ['aggfac', 'AggFac', True, True, '%2.2f', 'str', 1.0],
802 ['aggfrq', 'AggFreq', True, True, '%3.1f', 'str', 1.0],
803 ['conbet', 'ContBet', True, True, '%3.1f', 'str', 1.0],
804 ['rfi', 'RFI', True, True, '%3.1f', 'str', 1.0],
805 ['steals', 'Steals', True, True, '%3.1f', 'str', 1.0],
806 ['saw_f', 'Saw_F', True, True, '%3.1f', 'str', 1.0],
807 ['sawsd', 'SawSD', True, True, '%3.1f', 'str', 1.0],
808 ['wtsdwsf', 'WtSDwsF', True, True, '%3.1f', 'str', 1.0],
809 ['wmsd', 'W$SD', True, True, '%3.1f', 'str', 1.0],
810 ['flafq', 'FlAFq', True, True, '%3.1f', 'str', 1.0],
811 ['tuafq', 'TuAFq', True, True, '%3.1f', 'str', 1.0],
812 ['rvafq', 'RvAFq', True, True, '%3.1f', 'str', 1.0],
813 ['pofafq', 'PoFAFq', False, False, '%3.1f', 'str', 1.0],
814 ['net', 'Net($)', True, True, '%6.2f', 'cash', 1.0],
815 ['bbper100', 'bb/100', True, True, '%4.2f', 'str', 1.0],
816 ['rake', 'Rake($)', True, True, '%6.2f', 'cash', 1.0],
817 ['bb100xr', 'bbxr/100', True, True, '%4.2f', 'str', 1.0],
818 ['stddev', 'Standard Deviation', True, True, '%5.2f', 'str', 1.0]
819 ]
820 for col in defaults:
821 self.append (col)
823# def __str__(self):
824# s = ""
825# for l in self:
826# s = s + " %s = %s\n" % (k, self[k])
827# return(s)
828class GUITourStats(list):
829 """<gui_tour_stats>
830 <col col_name="game" col_title="Game" disp_all="True" disp_posn="True" field_format="%s" field_type="str" xalignment="0.0" />
831 ...
832 </gui_tour_stats>
833 """
834 def __init__(self):
835 super(GUITourStats, self).__init__()
837 def add_elements(self, node):
838 # is this needed?
839 for child in node.childNodes:
840 if child.nodeType == child.ELEMENT_NODE:
841 col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment=None, None, True, True, "%s", "str", 0.0
843 if child.hasAttribute('col_name'): col_name = child.getAttribute('col_name')
844 if child.hasAttribute('col_title'): col_title = child.getAttribute('col_title')
845 if child.hasAttribute('disp_all'): disp_all = string_to_bool(child.getAttribute('disp_all'))
846 if child.hasAttribute('disp_posn'): disp_posn = string_to_bool(child.getAttribute('disp_posn'))
847 if child.hasAttribute('field_format'): field_format = child.getAttribute('field_format')
848 if child.hasAttribute('field_type'): field_type = child.getAttribute('field_type')
849 try:
850 if child.hasAttribute('xalignment'): xalignment = float(child.getAttribute('xalignment'))
851 except ValueError:
852 print(("bad number in xalignment was ignored"))
853 log.info(("bad number in xalignment was ignored"))
855 self.append( [col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment] )
859 def get_defaults(self):
860 """A list of defaults to be called, should there be no entry in config"""
861 # SQL column name, display title, display all, display positional, format, type, alignment
862 defaults = [ ['game', 'Game', True, True, '%s', 'str', 0.0],
863 ['hand', 'Hand', False, False, '%s', 'str', 0.0],
864 ]
865 for col in defaults:
866 self.append (col)
870class RawHands(object):
871 def __init__(self, node=None):
872 if node==None:
873 self.save="error"
874 self.compression="none"
875 #print ("missing config section raw_hands")
876 else:
877 save=node.getAttribute("save")
878 if save in ("none", "error", "all"):
879 self.save=save
880 else:
881 print (("Invalid config value for %s, defaulting to %s") % (raw_hands.save, "\"error\""))
882 self.save="error"
884 compression=node.getAttribute("compression")
885 if save in ("none", "gzip", "bzip2"):
886 self.compression=compression
887 else:
888 print (("Invalid config value for %s, defaulting to %s") % (raw_hands.compression, "\"none\""))
889 self.compression="none"
890 #end def __init__
892 def __str__(self):
893 return " save= %s, compression= %s\n" % (self.save, self.compression)
894#end class RawHands
896class RawTourneys(object):
897 def __init__(self, node=None):
898 if node==None:
899 self.save="error"
900 self.compression="none"
901 #print ("missing config section raw_tourneys")
902 else:
903 save=node.getAttribute("save")
904 if save in ("none", "error", "all"):
905 self.save=save
906 else:
907 print (("Invalid config value for %s, defaulting to %s") % (raw_tourneys.save, "\"error\""))
908 self.save="error"
910 compression=node.getAttribute("compression")
911 if save in ("none", "gzip", "bzip2"):
912 self.compression=compression
913 else:
914 print (("Invalid config value for %s, defaulting to %s") % (raw_tourneys.compression, "\"none\""))
915 self.compression="none"
916 #end def __init__
918 def __str__(self):
919 return " save= %s, compression= %s\n" % (self.save, self.compression)
920#end class RawTourneys
922class Config(object):
923 def __init__(self, file = None, dbname = '', custom_log_dir='', lvl='INFO'):
925 self.install_method = INSTALL_METHOD
926 self.fpdb_root_path = FPDB_ROOT_PATH
927 self.appdata_path = APPDATA_PATH
928 self.config_path = CONFIG_PATH
929 self.pyfpdb_path = PYFPDB_PATH
930 self.graphics_path = GRAPHICS_PATH
931 self.os_family = OS_FAMILY
932 self.posix = POSIX
933 self.python_version = PYTHON_VERSION
935 if not os.path.exists(CONFIG_PATH):
936 os.makedirs(CONFIG_PATH)
938 if custom_log_dir and os.path.exists(custom_log_dir):
939 self.dir_log = str(custom_log_dir, "utf8")
940 else:
941 if OS_FAMILY == 'XP' or 'Win7':
942 print('windows TRUE5')
943 self.dir_log = os.path.join(CONFIG_PATH, 'log')
944 self.dir_log = self.dir_log.replace("\\", "/")
945 else:
946 self.dir_log = os.path.join(CONFIG_PATH, 'log')
947 self.log_file = os.path.join(self.dir_log, 'fpdb-log.txt')
948 log = logging.getLogger("config")
950# "file" is a path to an xml file with the fpdb/HUD configuration
951# we check the existence of "file" and try to recover if it doesn't exist
953# self.default_config_path = self.get_default_config_path()
954 self.example_copy = False
955 if file is not None: # config file path passed in
956 file = os.path.expanduser(file)
957 if not os.path.exists(file):
958 print(("Configuration file %s not found. Using defaults.") % (file))
959 sys.stderr.write(("Configuration file %s not found. Using defaults.") % (file))
960 file = None
962 self.example_copy,example_file = True,None
963 if file is None: (file,self.example_copy,example_file) = get_config("HUD_config.xml", True)
965 self.file = file
967 self.supported_sites = {}
968 self.supported_games = {}
969 self.supported_databases = {} # databaseName --> Database instance
970 self.aux_windows = {}
971 self.layout_sets = {}
972 self.stat_sets = {}
973 self.hhcs = {}
974 self.popup_windows = {}
975 self.db_selected = None # database the user would like to use
976 self.general = General()
977 self.emails = {}
978 self.gui_cash_stats = GUICashStats()
979 self.gui_tour_stats = GUITourStats()
980 self.site_ids = {} # site ID list from the database
981 self.doc = None # Root of XML tree
984 added,n = 1,0 # use n to prevent infinite loop if add_missing_elements() fails somehow
985 while added > 0 and n < 2:
986 n = n + 1
987 log.info("Reading configuration file %s" % file)
988 print (("\n"+("Reading configuration file %s")+"\n") % file)
989 try:
990 doc = xml.dom.minidom.parse(file)
991 self.doc = doc # Root of XML tree
992 self.file_error = None
993 except:
994 import traceback
995 log.error((("Error parsing %s.") % (file)) + ("See error log file."))
996 traceback.print_exc(file=sys.stderr)
997 self.file_error = sys.exc_info()[1]
998 # we could add a parameter to decide whether to return or read a line and exit?
999 return
1000 #print "press enter to continue"
1001 #sys.stdin.readline()
1002 #sys.exit()
1004 if (not self.example_copy) and (example_file is not None):
1005 # reads example file and adds missing elements into current config
1006 added = self.add_missing_elements(doc, example_file)
1008 if doc.getElementsByTagName("general") == []:
1009 self.general.get_defaults()
1010 for gen_node in doc.getElementsByTagName("general"):
1011 self.general.add_elements(node=gen_node) # add/overwrite elements in self.general
1013 if int(self.general["version"]) == CONFIG_VERSION:
1014 self.wrongConfigVersion = False
1015 else:
1016 self.wrongConfigVersion = True
1018 if doc.getElementsByTagName("gui_cash_stats") == []:
1019 self.gui_cash_stats.get_defaults()
1020 for gcs_node in doc.getElementsByTagName("gui_cash_stats"):
1021 self.gui_cash_stats.add_elements(node=gcs_node) # add/overwrite elements in self.gui_cash_stats
1024 if doc.getElementsByTagName("gui_tour_stats") == []:
1025 self.gui_tour_stats.get_defaults()
1026 for gcs_node in doc.getElementsByTagName("gui_tour_stats"):
1027 self.gui_tour_stats.add_elements(node=gcs_node) # add/overwrite elements in self.gui_cash_stats
1030# s_sites = doc.getElementsByTagName("supported_sites")
1031 for site_node in doc.getElementsByTagName("site"):
1032 site = Site(node = site_node)
1033 self.supported_sites[site.site_name] = site
1035# s_games = doc.getElementsByTagName("supported_games")
1036 for supported_game_node in doc.getElementsByTagName("game"):
1037 supported_game = Supported_games(supported_game_node)
1038 self.supported_games[supported_game.game_name] = supported_game
1040 # parse databases defined by user in the <supported_databases> section
1041 # the user may select the actual database to use via commandline or by setting the selected="bool"
1042 # attribute of the tag. if no database is explicitely selected, we use the first one we come across
1043# s_dbs = doc.getElementsByTagName("supported_databases")
1044 #TODO: do we want to take all <database> tags or all <database> tags contained in <supported_databases>
1045 # ..this may break stuff for some users. so leave it unchanged for now untill there is a decission
1046 for db_node in doc.getElementsByTagName("database"):
1047 db = Database(node=db_node)
1048 if db.db_name in self.supported_databases:
1049 raise ValueError("Database names must be unique")
1050 if self.db_selected is None or db.db_selected:
1051 self.db_selected = db.db_name
1052 db_node.setAttribute("default", "True")
1053 self.supported_databases[db.db_name] = db
1054 #TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored
1055 # ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not
1056 if dbname and dbname in self.supported_databases:
1057 self.db_selected = dbname
1058 #NOTE: fpdb can not handle the case when no database is defined in xml, so we throw an exception for now
1059 if self.db_selected is None:
1060 raise ValueError('There must be at least one database defined')
1062# s_dbs = doc.getElementsByTagName("mucked_windows")
1063 for aw_node in doc.getElementsByTagName("aw"):
1064 aw = Aux_window(node = aw_node)
1065 self.aux_windows[aw.name] = aw
1067 for ls_node in doc.getElementsByTagName("ls"):
1068 ls = Layout_set(node = ls_node)
1069 self.layout_sets[ls.name] = ls
1071 for ss_node in doc.getElementsByTagName("ss"):
1072 ss = Stat_sets(node = ss_node)
1073 self.stat_sets[ss.name] = ss
1075# s_dbs = doc.getElementsByTagName("mucked_windows")
1076 for hhc_node in doc.getElementsByTagName("hhc"):
1077 hhc = HHC(node = hhc_node)
1078 self.hhcs[hhc.site] = hhc
1080# s_dbs = doc.getElementsByTagName("popup_windows")
1081 for pu_node in doc.getElementsByTagName("pu"):
1082 pu = Popup(node = pu_node)
1083 self.popup_windows[pu.name] = pu
1085 for imp_node in doc.getElementsByTagName("import"):
1086 imp = Import(node = imp_node)
1087 self.imp = imp
1089 for hui_node in doc.getElementsByTagName('hud_ui'):
1090 hui = HudUI(node = hui_node)
1091 self.ui = hui
1093 db = self.get_db_parameters()
1094 # Set the db path if it's defined in HUD_config.xml (sqlite only), otherwise place in config path.
1095 self.dir_database = db['db-path'] if db['db-path'] else os.path.join(CONFIG_PATH, u'database')
1096 if db['db-password'] == 'YOUR MYSQL PASSWORD':
1097 df_file = self.find_default_conf()
1098 if df_file is None: # this is bad
1099 pass
1100 else:
1101 df_parms = self.read_default_conf(df_file)
1102 self.set_db_parameters(db_name = 'fpdb', db_ip = df_parms['db-host'],
1103 db_user = df_parms['db-user'],
1104 db_pass = df_parms['db-password'])
1105 self.save(file=os.path.join(CONFIG_PATH, "HUD_config.xml"))
1107 if doc.getElementsByTagName("raw_hands") == []:
1108 self.raw_hands = RawHands()
1109 for raw_hands_node in doc.getElementsByTagName('raw_hands'):
1110 self.raw_hands = RawHands(raw_hands_node)
1112 if doc.getElementsByTagName("raw_tourneys") == []:
1113 self.raw_tourneys = RawTourneys()
1114 for raw_tourneys_node in doc.getElementsByTagName('raw_tourneys'):
1115 self.raw_tourneys = RawTourneys(raw_tourneys_node)
1117 #print ""
1118 #end def __init__
1120 def add_missing_elements(self, doc, example_file):
1121 """ Look through example config file and add any elements that are not in the config
1122 May need to add some 'enabled' attributes to turn things off - can't just delete a
1123 config section now because this will add it back in"""
1125 nodes_added = 0
1127 try:
1128 example_doc = xml.dom.minidom.parse(example_file)
1129 except:
1130 log.error((("Error parsing example configuration file %s.") % (example_file)) + ("See error log file."))
1131 return nodes_added
1133 for cnode in doc.getElementsByTagName("FreePokerToolsConfig"):
1134 for example_cnode in example_doc.childNodes:
1135 if example_cnode.localName == "FreePokerToolsConfig":
1136 for e in example_cnode.childNodes:
1137 #print "nodetype", e.nodeType, "name", e.localName, "found", len(doc.getElementsByTagName(e.localName))
1138 if e.nodeType == e.ELEMENT_NODE and doc.getElementsByTagName(e.localName) == []:
1139 new = doc.importNode(e, True) # True means do deep copy
1140 t_node = self.doc.createTextNode(" ")
1141 cnode.appendChild(t_node)
1142 cnode.appendChild(new)
1143 t_node = self.doc.createTextNode("\r\n\r\n")
1144 cnode.appendChild(t_node)
1145 print("... adding missing config section: " + e.localName)
1146 nodes_added = nodes_added + 1
1148 if nodes_added > 0:
1149 print(("Added %d missing config sections" % nodes_added)+"\n")
1150 self.save()
1152 return nodes_added
1154 def find_default_conf(self):
1155 if CONFIG_PATH:
1156 config_file = os.path.join(CONFIG_PATH, 'default.conf')
1157 else: config_file = False
1159 if config_file and os.path.exists(config_file):
1160 file = config_file
1161 else:
1162 file = None
1163 return file
1165 def get_doc(self):
1166 return self.doc
1168 def get_site_node(self, site):
1169 for site_node in self.doc.getElementsByTagName("site"):
1170 if site_node.getAttribute("site_name") == site:
1171 return site_node
1173 def getEmailNode(self, siteName, fetchType):
1174 siteNode = self.get_site_node(siteName)
1175 for emailNode in siteNode.getElementsByTagName("email"):
1176 if emailNode.getAttribute("fetchType") == fetchType:
1177 return emailNode
1178 break
1179 #end def getEmailNode
1181 def getStatSetNode(self,statsetName):
1182 """returns DOM game node for a given game"""
1183 for statsetNode in self.doc.getElementsByTagName("ss"):
1184 #print "getStatSetNode statsetNode:",statsetNode
1185 if statsetNode.getAttribute("name") == statsetName:
1186 return statsetNode
1189 def getGameNode(self,gameName):
1190 """returns DOM game node for a given game"""
1191 for gameNode in self.doc.getElementsByTagName("game"):
1192 #print "getGameNode gameNode:",gameNode
1193 if gameNode.getAttribute("game_name") == gameName:
1194 return gameNode
1195 #end def getGameNode
1198 def get_aux_node(self, aux):
1199 for aux_node in self.doc.getElementsByTagName("aw"):
1200 if aux_node.getAttribute("name") == aux:
1201 return aux_node
1203 def get_layout_set_node(self, ls):
1204 for layout_set_node in self.doc.getElementsByTagName("ls"):
1205 if layout_set_node.getAttribute("name") == ls:
1206 return layout_set_node
1208 def get_layout_node(self, ls, max):
1209 for layout_node in ls.getElementsByTagName("layout"):
1210 if layout_node.getAttribute("max") == str(max):
1211 return layout_node
1213 def get_stat_set_node(self, ss):
1214 for stat_set_node in self.doc.getElementsByTagName("ss"):
1215 if os.ST_NODEV.getAttribute("name") == ss:
1216 return stat_set_node
1218 def get_db_node(self, db_name):
1219 for db_node in self.doc.getElementsByTagName("database"):
1220 if db_node.getAttribute("db_name") == db_name:
1221 return db_node
1222 return None
1224# def get_layout_node(self, site_node, layout):
1225# for layout_node in site_node.getElementsByTagName("layout"):
1226# if layout_node.getAttribute("max") is None:
1227# return None
1228# if int( layout_node.getAttribute("max") ) == int( layout ):
1229# return layout_node
1231 def get_location_node(self, layout_node, seat):
1232 if seat == "common":
1233 for location_node in layout_node.getElementsByTagName("location"):
1234 if location_node.hasAttribute("common"):
1235 return location_node
1236 else:
1237 for location_node in layout_node.getElementsByTagName("location"):
1238 if int( location_node.getAttribute("seat") ) == int( seat ):
1239 return location_node
1241 def save(self, file = None):
1242 if file is None:
1243 file = self.file
1244 try:
1245 shutil.move(file, file+".backup")
1246 except:
1247 pass
1249 with codecs.open(file, 'w', 'utf-8') as f:
1250 #self.doc.writexml(f)
1251 f.write( self.wrap_long_lines( self.doc.toxml() ) )
1253 def wrap_long_lines(self, s):
1254 lines = [ self.wrap_long_line(l) for l in s.splitlines() ]
1255 return('\n'.join(lines) + '\n')
1257 def wrap_long_line(self, l):
1258 if 'config_wrap_len' in self.general:
1259 wrap_len = int(self.general['config_wrap_len'])
1260 else:
1261 wrap_len = -1 # < 0 means no wrap
1263 if wrap_len >= 0 and len(l) > wrap_len:
1264 m = re.compile('\s+\S+\s+')
1265 mo = m.match(l)
1266 if mo:
1267 indent_len = mo.end()
1268 #print "indent = %s (%s)" % (indent_len, l[0:indent_len])
1269 indent = '\n' + ' ' * indent_len
1270 m = re.compile('(\S+="[^"]+"\s+)')
1271 parts = [x for x in m.split(l[indent_len:]) if x]
1272 if len(parts) > 1:
1273 #print "parts =", parts
1274 l = l[0:indent_len] + indent.join(parts)
1275 return(l)
1276 else:
1277 return(l)
1279 def editEmail(self, siteName, fetchType, newEmail):
1280 emailNode = self.getEmailNode(siteName, fetchType)
1281 emailNode.setAttribute("host", newEmail.host)
1282 emailNode.setAttribute("username", newEmail.username)
1283 emailNode.setAttribute("password", newEmail.password)
1284 emailNode.setAttribute("folder", newEmail.folder)
1285 emailNode.setAttribute("useSsl", newEmail.useSsl)
1286 #end def editEmail
1288 def edit_fav_seat(self, site_name, enabled, seat2_dict, seat3_dict, seat4_dict, seat5_dict, seat6_dict, seat7_dict, seat8_dict, seat9_dict, seat10_dict):
1289 site_node = self.get_site_node(site_name)
1290 site_node.setAttribute("enabled", enabled)
1292 for fav_seat in site_node.getElementsByTagName("fav"):
1293 if fav_seat.getAttribute("max") == "2":
1294 fav_seat.setAttribute("fav_seat", seat2_dict)
1295 elif fav_seat.getAttribute("max") == "3":
1296 fav_seat.setAttribute("fav_seat", seat3_dict)
1297 elif fav_seat.getAttribute("max") == "4":
1298 fav_seat.setAttribute("fav_seat", seat4_dict)
1299 elif fav_seat.getAttribute("max") == "5":
1300 fav_seat.setAttribute("fav_seat", seat5_dict)
1301 elif fav_seat.getAttribute("max") == "6":
1302 fav_seat.setAttribute("fav_seat", seat6_dict)
1303 elif fav_seat.getAttribute("max") == "7":
1304 fav_seat.setAttribute("fav_seat", seat7_dict)
1305 elif fav_seat.getAttribute("max") == "8":
1306 fav_seat.setAttribute("fav_seat", seat8_dict)
1307 elif fav_seat.getAttribute("max") == "9":
1308 fav_seat.setAttribute("fav_seat", seat9_dict)
1309 elif fav_seat.getAttribute("max") == "10":
1310 fav_seat.setAttribute("fav_seat", seat10_dict)
1311 #end def
1313 def increment_position(self, position: str) -> str:
1314 # Adapt defined logic for hus stats form config file
1315 # TODO: Probably adapt hud logic instead
1316 """
1317 >>> self.increment_position('(0,0)')
1318 "(1,1)"
1319 >>> self.increment_position('(0, 0)')
1320 "(1,1)"
1321 >>> self.increment_position('(2,3)')
1322 "(3,4)"
1323 """
1324 assert position.startswith("(") and position.endswith(")"), position.__repr__()
1325 # Remove parentheses and split by comma
1326 row, col = map(int, position[1:-1].split(","))
1327 # Check that row and collar are not negative
1328 assert row >= 0 and col >= 0, f"Negative values detected: row={row}, col={col}"
1329 # Increment both row and column by 1
1330 return f"({row + 1},{col + 1})"
1332 def edit_hud(self, hud_name, position, stat_name, click, hudcolor, hudprefix, hudsuffix, popup, stat_hicolor, stat_hith, stat_locolor, stat_loth, tip):
1333 """ Replace given values onto self.doc (XML root node)
1334 """
1335 for statsetNode in self.doc.getElementsByTagName("ss"):
1336 if statsetNode.getAttribute("name") == hud_name:
1337 for fav_stat in statsetNode.getElementsByTagName("stat"):
1338 if fav_stat.getAttribute("_rowcol") == self.increment_position(position):
1339 fav_stat.setAttribute("_stat_name", stat_name)
1340 fav_stat.setAttribute("click", click)
1341 fav_stat.setAttribute("hudcolor", hudcolor)
1342 fav_stat.setAttribute("hudprefix", hudprefix)
1343 fav_stat.setAttribute("hudsuffix", hudsuffix)
1344 fav_stat.setAttribute("popup", popup)
1345 fav_stat.setAttribute("stat_hicolor", stat_hicolor)
1346 fav_stat.setAttribute("stat_hith", stat_hith)
1347 fav_stat.setAttribute("stat_locolor", stat_locolor)
1348 fav_stat.setAttribute("stat_loth", stat_loth)
1349 fav_stat.setAttribute("tip", tip)
1350 # fav_stat.setAttribute("stat_midcolor", stat_midcolor) # not returned by UI
1352 #end def
1354 def edit_site(self, site_name, enabled, screen_name, history_path, summary_path):
1355 site_node = self.get_site_node(site_name)
1356 site_node.setAttribute("enabled", enabled)
1357 site_node.setAttribute("screen_name", screen_name)
1358 site_node.setAttribute("HH_path", history_path)
1359 if summary_path:
1360 site_node.setAttribute("TS_path", summary_path)
1362 def editStats(self, statsetName, statArray):
1363 """replaces stat selection for the given gameName with the given statArray"""
1364 statsetNode = self.getStatSetNode(statsetName)
1365 statNodes = statsetNode.getElementsByTagName("stat")
1367 for node in statNodes:
1368 statsetNode.removeChild(node)
1370 statsetNode.setAttribute("rows", str(len(statArray)))
1371 statsetNode.setAttribute("cols", str(len(statArray[0])))
1373 for rowNumber in range(len(statArray)):
1374 for columnNumber in range(len(statArray[rowNumber])):
1375 newStat = self.doc.createElement("stat")
1377 attributes = {
1378 "_stat_name": statArray[rowNumber][columnNumber],
1379 "_rowcol": f"({rowNumber+1},{columnNumber+1})",
1380 "click": "",
1381 "popup": "default",
1382 "tip": "",
1383 "stat_locolor": "",
1384 "stat_loth": "",
1385 "stat_midcolor": "", # Add stat_midcolor
1386 "stat_hicolor": "",
1387 "stat_hith": ""
1388 }
1390 for attr_name, attr_value in attributes.items():
1391 newAttr = self.doc.createAttribute(attr_name)
1392 newStat.setAttributeNode(newAttr)
1393 newStat.setAttribute(attr_name, attr_value)
1395 statsetNode.appendChild(newStat)
1397 statNodes = statsetNode.getElementsByTagName("stat") #TODO remove this line?
1398 #end def editStats
1399 def editImportFilters(self, games):
1400 self.imp.importFilters = games
1401 imp_node = self.doc.getElementsByTagName("import")[-1]
1402 imp_node.setAttribute("importFilters", games)
1404 def save_layout_set(self, ls, max, locations, width=None, height=None):
1405 #wid/height normally not specified when saving common from the mucked display
1407 print("saving layout =", ls.name, " ", str(max), "Max ", str(locations), "size:", str(width), "x", str(height))
1408 ls_node = self.get_layout_set_node(ls.name)
1409 layout_node = self.get_layout_node(ls_node, max)
1410 if width: layout_node.setAttribute("width", str(width))
1411 if height: layout_node.setAttribute("height", str(height))
1413 for (i, pos) in list(locations.items()):
1414 location_node = self.get_location_node(layout_node, i)
1415 location_node.setAttribute("x", str( locations[i][0] ))
1416 location_node.setAttribute("y", str( locations[i][1] ))
1417 #now refresh the live instance of the layout set with the new locations
1418 # this is needed because any future windows created after a save layout
1419 # MUST pickup the new layout
1420 #fixme - this is horrid
1421 if i == "common":
1422 self.layout_sets[ls.name].layout[max].common = ( locations[i][0], locations[i][1] )
1423 else:
1424 self.layout_sets[ls.name].layout[max].location[i] = ( locations[i][0], locations[i][1] )
1425 # more horridness below, fixme
1426 if height: self.layout_sets[ls.name].layout[max].height = height
1427 if width: self.layout_sets[ls.name].layout[max].width = width
1430 #NOTE: we got a nice Database class, so why map it again here?
1431 # user input validation should be done when initializing the Database class. this allows to give appropriate feddback when something goes wrong
1432 # try ..except is evil here. it swallows all kinds of errors. dont do this
1433 # 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_*)
1434 # 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
1435 # thus we can drop self.db_selected (holding database name) entirely and replace it with self._active_database = Database, avoiding to define the same
1436 # thing multiple times
1437 def get_db_parameters(self):
1438 db = {}
1439 name = self.db_selected
1440 # TODO: What's up with all the exception handling here?!
1441 try: db['db-databaseName'] = name
1442 except: pass
1444 try: db['db-desc'] = self.supported_databases[name].db_desc
1445 except: pass
1447 try: db['db-host'] = self.supported_databases[name].db_ip
1448 except: pass
1450 try: db['db-port'] = self.supported_databases[name].db_port
1451 except: pass
1453 try: db['db-user'] = self.supported_databases[name].db_user
1454 except: pass
1456 try: db['db-password'] = self.supported_databases[name].db_pass
1457 except: pass
1459 try: db['db-server'] = self.supported_databases[name].db_server
1460 except: pass
1462 try: db['db-path'] = self.supported_databases[name].db_path
1463 except: pass
1465 db['db-backend'] = self.get_backend(self.supported_databases[name].db_server)
1467 return db
1469 def set_db_parameters(self, db_name = 'fpdb', db_ip = None, db_port = None, db_user = None,
1470 db_pass = None, db_desc = None, db_server = None,
1471 default = "False"):
1472 db_node = self.get_db_node(db_name)
1473 default = default.lower()
1474 defaultb = string_to_bool(default, False)
1475 if db_node != None:
1476 if db_desc is not None: db_node.setAttribute("db_desc", db_desc)
1477 if db_ip is not None: db_node.setAttribute("db_ip", db_ip)
1478 if db_port is not None: db_node.setAttribute("db_port", db_port)
1479 if db_user is not None: db_node.setAttribute("db_user", db_user)
1480 if db_pass is not None: db_node.setAttribute("db_pass", db_pass)
1481 if db_server is not None: db_node.setAttribute("db_server", db_server)
1482 if defaultb or self.db_selected == db_name:
1483 db_node.setAttribute("default", "True")
1484 for dbn in self.doc.getElementsByTagName("database"):
1485 if dbn.getAttribute('db_name') != db_name and dbn.hasAttribute("default"):
1486 dbn.removeAttribute("default")
1487 elif db_node.hasAttribute("default"):
1488 db_node.removeAttribute("default")
1489 if db_name in self.supported_databases:
1490 if db_desc is not None: self.supported_databases[db_name].dp_desc = db_desc
1491 if db_ip is not None: self.supported_databases[db_name].dp_ip = db_ip
1492 if db_port is not None: self.supported_databases[db_name].dp_port = db_port
1493 if db_user is not None: self.supported_databases[db_name].dp_user = db_user
1494 if db_pass is not None: self.supported_databases[db_name].dp_pass = db_pass
1495 if db_server is not None: self.supported_databases[db_name].dp_server = db_server
1496 self.supported_databases[db_name].db_selected = defaultb
1497 if defaultb:
1498 self.db_selected = db_name
1499 return
1501 def add_db_parameters(self, db_name = 'fpdb', db_ip = None, db_port = None, db_user = None,
1502 db_pass = None, db_desc = None, db_server = None,
1503 default = "False"):
1504 default = default.lower()
1505 defaultb = string_to_bool(default, False)
1506 if db_name in self.supported_databases:
1507 raise ValueError("Database names must be unique")
1509 db_node = self.get_db_node(db_name)
1510 if db_node is None:
1511 for db_node in self.doc.getElementsByTagName("supported_databases"):
1512 # should only be one supported_databases element, use last one if there are several
1513 suppdb_node = db_node
1514 t_node = self.doc.createTextNode(" ")
1515 suppdb_node.appendChild(t_node)
1516 db_node = self.doc.createElement("database")
1517 suppdb_node.appendChild(db_node)
1518 t_node = self.doc.createTextNode("\r\n ")
1519 suppdb_node.appendChild(t_node)
1520 db_node.setAttribute("db_name", db_name)
1521 if db_desc is not None: db_node.setAttribute("db_desc", db_desc)
1522 if db_ip is not None: db_node.setAttribute("db_ip", db_ip)
1523 if db_port is not None: db_node.setAttribute("db_port", db_port)
1524 if db_user is not None: db_node.setAttribute("db_user", db_user)
1525 if db_pass is not None: db_node.setAttribute("db_pass", db_pass)
1526 if db_server is not None: db_node.setAttribute("db_server", db_server)
1527 if defaultb:
1528 db_node.setAttribute("default", "True")
1529 for dbn in self.doc.getElementsByTagName("database"):
1530 if dbn.getAttribute('db_name') != db_name and dbn.hasAttribute("default"):
1531 dbn.removeAttribute("default")
1532 elif db_node.hasAttribute("default"):
1533 db_node.removeAttribute("default")
1534 else:
1535 if db_desc is not None: db_node.setAttribute("db_desc", db_desc)
1536 if db_ip is not None: db_node.setAttribute("db_ip", db_ip)
1537 if db_port is not None: db_node.setAttribute("db_port", db_port)
1538 if db_user is not None: db_node.setAttribute("db_user", db_user)
1539 if db_pass is not None: db_node.setAttribute("db_pass", db_pass)
1540 if db_server is not None: db_node.setAttribute("db_server", db_server)
1541 if defaultb or self.db_selected == db_name:
1542 db_node.setAttribute("default", "True")
1543 elif db_node.hasAttribute("default"):
1544 db_node.removeAttribute("default")
1546 if db_name in self.supported_databases:
1547 if db_desc is not None: self.supported_databases[db_name].dp_desc = db_desc
1548 if db_ip is not None: self.supported_databases[db_name].dp_ip = db_ip
1549 if db_port is not None: self.supported_databases[db_name].dp_port = db_port
1550 if db_user is not None: self.supported_databases[db_name].dp_user = db_user
1551 if db_pass is not None: self.supported_databases[db_name].dp_pass = db_pass
1552 if db_server is not None: self.supported_databases[db_name].dp_server = db_server
1553 self.supported_databases[db_name].db_selected = defaultb
1554 else:
1555 db = Database(node=db_node)
1556 self.supported_databases[db.db_name] = db
1558 if defaultb:
1559 self.db_selected = db_name
1560 return
1562 def get_backend(self, name):
1563 """Returns the number of the currently used backend"""
1564 if name == DATABASE_TYPE_MYSQL:
1565 ret = 2
1566 elif name == DATABASE_TYPE_POSTGRESQL:
1567 ret = 3
1568 elif name == DATABASE_TYPE_SQLITE:
1569 ret = 4
1570 # sqlcoder: this assignment fixes unicode problems for me with sqlite (windows, cp1252)
1571 # feel free to remove or improve this if you understand the problems
1572 # better than me (not hard!)
1573 Charset.not_needed1, Charset.not_needed2, Charset.not_needed3 = True, True, True
1574 else:
1575 raise ValueError('Unsupported database backend: %s' % self.supported_databases[name].db_server)
1577 return ret
1579 def getDefaultSite(self):
1580 "Returns first enabled site or None"
1581 for site_name,site in list(self.supported_sites.items()):
1582 if site.enabled:
1583 return site_name
1584 return None
1586 # Allow to change the menu appearance
1587 def get_hud_ui_parameters(self):
1588 hui = {}
1590 default_text = 'FPDB Menu - Right click\nLeft-Drag to Move'
1591 try:
1592 hui['label'] = self.ui.label
1593 if self.ui.label == '': # Empty menu label is a big no-no
1594 hui['label'] = default_text
1595 except:
1596 hui['label'] = default_text
1598 try: hui['card_ht'] = int(self.ui.card_ht)
1599 except: hui['card_ht'] = 42
1601 try: hui['card_wd'] = int(self.ui.card_wd)
1602 except: hui['card_wd'] = 30
1604 try: hui['deck_type'] = str(self.ui.deck_type)
1605 except: hui['deck_type'] = 'colour'
1607 try: hui['card_back'] = str(self.ui.card_back)
1608 except: hui['card_back'] = 'back04'
1610 try: hui['stat_range'] = self.ui.stat_range
1611 except: hui['stat_range'] = 'A' # default is show stats for All-time, also S(session) and T(ime)
1613 try: hui['hud_days'] = int(self.ui.hud_days)
1614 except: hui['hud_days'] = 90
1616 try: hui['agg_bb_mult'] = int(self.ui.agg_bb_mult)
1617 except: hui['agg_bb_mult'] = 1
1619 try: hui['seats_style'] = self.ui.seats_style
1620 except: hui['seats_style'] = 'A' # A / C / E, use A(ll) / C(ustom) / E(xact) seat numbers
1622 try: hui['seats_cust_nums_low'] = int(self.ui.seats_cust_nums_low)
1623 except: hui['seats_cust_nums_low'] = 1
1624 try: hui['seats_cust_nums_high'] = int(self.ui.seats_cust_nums_high)
1625 except: hui['seats_cust_nums_high'] = 10
1627 # Hero specific
1629 try: hui['h_stat_range'] = self.ui.h_stat_range
1630 except: hui['h_stat_range'] = 'S'
1632 try: hui['h_hud_days'] = int(self.ui.h_hud_days)
1633 except: hui['h_hud_days'] = 30
1635 try: hui['h_agg_bb_mult'] = int(self.ui.h_agg_bb_mult)
1636 except: hui['h_agg_bb_mult'] = 1
1638 try: hui['h_seats_style'] = self.ui.h_seats_style
1639 except: hui['h_seats_style'] = 'A' # A / C / E, use A(ll) / C(ustom) / E(xact) seat numbers
1641 try: hui['h_seats_cust_nums_low'] = int(self.ui.h_seats_cust_nums_low)
1642 except: hui['h_seats_cust_nums_low'] = 1
1643 try: hui['h_seats_cust_nums_high'] = int(self.ui.h_seats_cust_nums_high)
1644 except: hui['h_seats_cust_nums_high'] = 10
1645 return hui
1648 def get_import_parameters(self):
1649 imp = {}
1650 try: imp['callFpdbHud'] = self.imp.callFpdbHud
1651 except: imp['callFpdbHud'] = True
1653 try: imp['interval'] = self.imp.interval
1654 except: imp['interval'] = 10
1656 # ResultsDirectory is the local cache for downloaded results
1657 # NOTE: try: except: doesn'tseem to be triggering
1658 # using if instead
1659 if self.imp.ResultsDirectory != '':
1660 imp['ResultsDirectory'] = self.imp.ResultsDirectory
1661 else:
1662 imp['ResultsDirectory'] = "~/.fpdb/Results/"
1664 # hhBulkPath is the default location for bulk imports (if set)
1665 try: imp['hhBulkPath'] = self.imp.hhBulkPath
1666 except: imp['hhBulkPath'] = ""
1668 try: imp['saveActions'] = self.imp.saveActions
1669 except: imp['saveActions'] = False
1671 try: imp['cacheSessions'] = self.imp.cacheSessions
1672 except: imp['cacheSessions'] = False
1674 try: imp['publicDB'] = self.imp.publicDB
1675 except: imp['publicDB'] = False
1677 try: imp['sessionTimeout'] = self.imp.sessionTimeout
1678 except: imp['sessionTimeout'] = 30
1680 try: imp['saveStarsHH'] = self.imp.saveStarsHH
1681 except: imp['saveStarsHH'] = False
1683 try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache
1684 except: imp['fastStoreHudCache'] = False
1686 try: imp['importFilters'] = self.imp.importFilters
1687 except: imp['importFilters'] = []
1689 try: imp['timezone'] = self.imp.timezone
1690 except: imp['timezone'] = "America/New_York"
1692 return imp
1694 def set_timezone(self, timezone):
1695 self.imp.timezone = timezone
1697 def get_default_paths(self, site = None):
1698 if site is None: site = self.getDefaultSite()
1699 paths = {}
1700 try:
1701 path = os.path.expanduser(self.supported_sites[site].HH_path)
1702 assert(os.path.isdir(path) or os.path.isfile(path)) # maybe it should try another site?
1703 paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = path
1704 if self.imp.hhBulkPath:
1705 paths['bulkImport-defaultPath'] = self.imp.hhBulkPath
1706 if self.supported_sites[site].TS_path != '':
1707 tspath = os.path.expanduser(self.supported_sites[site].TS_path)
1708 paths['hud-defaultTSPath'] = tspath
1709 except AssertionError:
1710 paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **"
1711 return paths
1713# def get_frames(self, site = "PokerStars"):
1714# if site not in self.supported_sites: return False
1715# return self.supported_sites[site].use_frames == True
1717# def get_default_colors(self, site = "PokerStars"):
1718# colors = {}
1719# if site not in self.supported_sites or self.supported_sites[site].hudopacity == "":
1720# colors['hudopacity'] = 0.90
1721# else:
1722# colors['hudopacity'] = float(self.supported_sites[site].hudopacity)
1723# if site not in self.supported_sites or self.supported_sites[site].hudbgcolor == "":
1724# colors['hudbgcolor'] = "#FFFFFF"
1725# else:
1726# colors['hudbgcolor'] = self.supported_sites[site].hudbgcolor
1727# if site not in self.supported_sites or self.supported_sites[site].hudfgcolor == "":
1728# colors['hudfgcolor'] = "#000000"
1729# else:
1730# colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor
1731# return colors
1733# def get_default_font(self, site='PokerStars'):
1734# font = "Sans"
1735# font_size = "8"
1736# site = self.supported_sites.get(site, None)
1737# if site is not None:
1738# if site.font:
1739# font = site.font
1740# if site.font_size:
1741# font_size = site.font_size
1742# return font, font_size
1744 def get_layout_set_locations(self, set = "mucked", max = "9"):
1746 try:
1747 locations = self.layout_sets[set].layout[max].location
1748 except:
1749 locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346),
1750 (586, 393), (421, 440), (267, 440), ( 0, 361),
1751 ( 0, 280), (121, 280), ( 46, 30) )
1752 return locations
1754 def get_supported_sites(self, all=False):
1755 """Returns the list of supported sites."""
1756 if all:
1757 return list(self.supported_sites.keys())
1758 else:
1759 return [site_name for (site_name, site) in list(self.supported_sites.items()) if site.enabled]
1761 def get_site_parameters(self, site):
1762 """Returns a dict of the site parameters for the specified site"""
1763 parms = {}
1764 parms["converter"] = self.hhcs[site].converter
1765 parms["summaryImporter"] = self.hhcs[site].summaryImporter
1766 parms["screen_name"] = self.supported_sites[site].screen_name
1767 parms["site_path"] = self.supported_sites[site].site_path
1768 parms["HH_path"] = self.supported_sites[site].HH_path
1769 parms["TS_path"] = self.supported_sites[site].TS_path
1770 parms["site_name"] = self.supported_sites[site].site_name
1771 parms["enabled"] = self.supported_sites[site].enabled
1772 parms["aux_enabled"] = self.supported_sites[site].aux_enabled
1773 parms["hud_menu_xshift"] = self.supported_sites[site].hud_menu_xshift
1774 parms["hud_menu_yshift"] = self.supported_sites[site].hud_menu_yshift
1775 parms["layout_set"] = self.supported_sites[site].layout_set
1776 parms["emails"] = self.supported_sites[site].emails
1777 parms["fav_seat"] = self.supported_sites[site].fav_seat
1779 return parms
1781 def get_layout(self, site, game_type):
1783 # find layouts used at site
1784 # locate the one used for this game_type
1785 # return that Layout-set() instance
1787 site_layouts = self.get_site_parameters(site)["layout_set"]
1789 if game_type in site_layouts:
1790 return self.layout_sets[site_layouts[game_type]]
1791 elif "all" in site_layouts:
1792 return self.layout_sets[site_layouts["all"]]
1793 else:
1794 return None
1796# def set_site_parameters(self, site_name, converter = None, decoder = None,
1797# hudbgcolor = None, hudfgcolor = None,
1798# hudopacity = None, screen_name = None,
1799# site_path = None, table_finder = None,
1800# HH_path = None, enabled = None,
1801# font = None, font_size = None):
1802# """Sets the specified site parameters for the specified site."""
1803# site_node = self.get_site_node(site_name)
1804# if db_node is not None:
1805# if converter is not None: site_node.setAttribute("converter", converter)
1806# if decoder is not None: site_node.setAttribute("decoder", decoder)
1807# if hudbgcolor is not None: site_node.setAttribute("hudbgcolor", hudbgcolor)
1808# if hudfgcolor is not None: site_node.setAttribute("hudfgcolor", hudfgcolor)
1809# if hudopacity is not None: site_node.setAttribute("hudopacity", hudopacity)
1810# if screen_name is not None: site_node.setAttribute("screen_name", screen_name)
1811# if site_path is not None: site_node.setAttribute("site_path", site_path)
1812# if table_finder is not None: site_node.setAttribute("table_finder", table_finder)
1813# if HH_path is not None: site_node.setAttribute("HH_path", HH_path)
1814# if enabled is not None: site_node.setAttribute("enabled", enabled)
1815# if font is not None: site_node.setAttribute("font", font)
1816# if font_size is not None: site_node.setAttribute("font_size", font_size)
1817# return
1819 def set_general(self,lang=None):
1821 for general_node in self.doc.getElementsByTagName('general'):
1822 if lang: general_node.setAttribute("ui_language", lang)
1824 def set_site_ids(self, sites):
1825 self.site_ids = dict(sites)
1827 def get_site_id(self, site):
1828 return( self.site_ids[site] )
1830 def get_aux_windows(self):
1831 """Gets the list of mucked window formats in the configuration."""
1832 return list(self.aux_windows.keys())
1834 def get_aux_parameters(self, name):
1835 """Gets a dict of mucked window parameters from the named mw."""
1836 param = {}
1837 if name in self.aux_windows:
1838 for key in dir(self.aux_windows[name]):
1839 if key.startswith('__'): continue
1840 value = getattr(self.aux_windows[name], key)
1841 if callable(value): continue
1842 param[key] = value
1844 return param
1845 return None
1847 def get_stat_sets(self):
1848 """Gets the list of stat block contents in the configuration."""
1849 return list(self.stat_sets.keys())
1853 def get_layout_sets(self):
1854 """Gets the list of block layouts in the configuration."""
1855 return list(self.layout_sets.keys())
1857 def get_layout_set_parameters(self, name):
1858 """Gets a dict of parameters from the named ls."""
1859 param = {}
1860 if name in self.layout_sets:
1861 for key in dir(self.layout_sets[name]):
1862 if key.startswith('__'): continue
1863 value = getattr(self.layout_sets[name], key)
1864 if callable(value): continue
1865 param[key] = value
1867 return param
1868 return None
1870 def get_supported_games(self):
1871 """Get the list of supported games."""
1872 sg = []
1873 for game in list(self.supported_games.keys()):
1874 sg.append(self.supported_games[game].game_name)
1875 return sg
1877 def get_supported_games_parameters(self, name, game_type):
1878 """Gets a dict of parameters from the named gametype."""
1879 param = {}
1880 if name in self.supported_games:
1881 for key in dir(self.supported_games[name]):
1882 if key.startswith('__'): continue
1883 if key == ('game_stat_set'): continue
1884 value = getattr(self.supported_games[name], key)
1885 if callable(value): continue
1886 param[key] = value
1888 #some gymnastics now to load the correct Stats_sets instance
1889 # into the game_stat_set key
1891 game_stat_set = getattr(self.supported_games[name], 'game_stat_set')
1893 if game_type in game_stat_set:
1894 param['game_stat_set'] = self.stat_sets[game_stat_set[game_type].stat_set]
1895 elif "all" in game_stat_set:
1896 param['game_stat_set'] = self.stat_sets[game_stat_set["all"].stat_set]
1897 else:
1898 return None
1900 return param
1902 return None
1904 def execution_path(self, filename):
1905 """Join the fpdb path to filename."""
1906 return os.path.join(os.path.dirname(inspect.getfile(sys._getframe(0))), filename)
1908 def get_general_params(self):
1909 return( self.general )
1911 def get_gui_cash_stat_params(self):
1912 #print(type(self.gui_cash_stats))
1913 return( self.gui_cash_stats )
1915 def get_gui_tour_stat_params(self):
1916 #print(type(self.gui_tour_stats))
1917 return( self.gui_tour_stats )
1919if __name__== "__main__":
1920 set_logfile("fpdb-log.txt")
1921 c = Config()
1923 print("\n----------- GENERAL -----------")
1924 print(c.general)
1926 print("\n----------- SUPPORTED SITES -----------")
1927 for s in list(c.supported_sites.keys()):
1928 print(c.supported_sites[s])
1930 print("\n----------- SUPPORTED GAMES -----------")
1931 for game in list(c.supported_games.keys()):
1932 print(c.supported_games[game])
1934 print("\n----------- SUPPORTED DATABASES -----------")
1935 for db in list(c.supported_databases.keys()):
1936 print(c.supported_databases[db])
1938 print("\n----------- AUX WINDOW FORMATS -----------")
1939 for w in list(c.aux_windows.keys()):
1940 print(c.aux_windows[w])
1942 print("\n----------- LAYOUT SETS FORMATS -----------")
1943 for w in list(c.layout_sets.keys()):
1944 print(c.layout_sets[w])
1946 print("\n----------- STAT SETS FORMATS -----------")
1947 for w in list(c.stat_sets.keys()):
1948 print(c.stat_sets[w])
1950 print("\n----------- HAND HISTORY CONVERTERS -----------")
1951 for w in list(c.hhcs.keys()):
1952 print(c.hhcs[w])
1954 print("\n----------- POPUP WINDOW FORMATS -----------")
1955 for w in list(c.popup_windows.keys()):
1956 print(c.popup_windows[w])
1958 print("\n----------- DATABASE PARAMS -----------")
1959 print("db = ", c.get_db_parameters())
1961 print("\n----------- HUD PARAMS -----------")
1962 print("hud params =")
1963 for hud_param, value in list(c.get_hud_ui_parameters().items()):
1964 print(" %s = %s" % (hud_param, value))
1966 print("\n----------- STARTUP PATH -----------")
1967 print("start up path = ", c.execution_path(""))
1969 print("\n----------- GUI CASH STATS -----------")
1970 print("gui_cash_stats =", c.gui_cash_stats)
1972 print("\n----------- Heroes -----------")
1973 for s in list(c.supported_sites.keys()):
1974 print(c.supported_sites[s].screen_name)
1976 print("\n----------- ENVIRONMENT CONSTANTS -----------")
1977 print("Configuration.install_method {source,exe,app} =", INSTALL_METHOD)
1978 print("Configuration.fpdb_root_path =", FPDB_ROOT_PATH, type(FPDB_ROOT_PATH))
1979 print("Configuration.graphics_path =", GRAPHICS_PATH, type(GRAPHICS_PATH))
1980 print("Configuration.appdata_path =", APPDATA_PATH, type(APPDATA_PATH))
1981 print("Configuration.config_path =", CONFIG_PATH, type(CONFIG_PATH))
1982 print("Configuration.pyfpdb_path =", PYFPDB_PATH, type(PYFPDB_PATH))
1983 print("Configuration.os_family {Linux,Mac,XP,Win7} =", OS_FAMILY)
1984 print("Configuration.posix {True/False} =", POSIX)
1985 print("Configuration.python_version =", PYTHON_VERSION)
1986 print("\n\n----------- END OF CONFIG REPORT -----------")
1988 print("press enter to end")
1989 sys.stdin.readline()