Coverage for Configuration.py: 49%

1282 statements  

« 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 

20 

21######################################################################## 

22 

23#TODO fix / rethink edit stats - it is broken badly just now 

24 

25# Standard Library modules 

26from __future__ import with_statement 

27from __future__ import print_function 

28 

29 

30#import L10n 

31#_ = L10n.get_translation() 

32 

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 

43 

44import platform 

45 

46 

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 

58 

59import logging, logging.config 

60 

61 

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 

67 

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) 

82 

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" 

94 

95if INSTALL_METHOD == "exe" : 

96 FPDB_ROOT_PATH = os.path.dirname(sys.executable) 

97 

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() 

111 

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 

124 

125#GRAPHICS_PATH = os.path.join(FPDB_ROOT_PATH, "gfx") 

126#PYFPDB_PATH = os.path.join(FPDB_ROOT_PATH, "pyfpdb") 

127 

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 

158 

159if os.name == 'posix': 

160 POSIX = True 

161else: 

162 POSIX = False 

163 

164PYTHON_VERSION = sys.version[:3] 

165 

166# logging has been set up in fpdb.py or HUD_main.py, use their settings: 

167log = logging.getLogger("config") 

168 

169LOGLEVEL = {'DEBUG' : logging.DEBUG, 

170 'INFO' : logging.INFO, 

171 'WARNING' : logging.WARNING, 

172 'ERROR' : logging.ERROR, 

173 'CRITICAL': logging.CRITICAL} 

174 

175 

176 

177def get_config(file_name, fallback = True): 

178 """Looks in cwd and in self.default_config_path for a config file.""" 

179 

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  

183 

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) 

217 

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 

244 

245# OK, fall back to the .example file, should be in the start dir 

246 

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") ) 

257 

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() 

267 

268 

269 return (config_path,example_copy,example_path) 

270 

271def set_logfile(file_name): 

272 (conf_file,copied,example_file) = get_config("logging.conf", fallback = False) 

273 

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}") 

288 

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 

304 

305def normalizePath(path): 

306 "Normalized existing pathes" 

307 if os.path.exists(path): 

308 return os.path.abspath(path) 

309 return path 

310 

311######################################################################## 

312# application wide consts 

313 

314APPLICATION_NAME_SHORT = 'fpdb' 

315APPLICATION_VERSION = 'xx.xx.xx' 

316 

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 ) 

325 

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."))) 

331 

332# needs LOCALE_ENCODING (above), imported for sqlite setup in Config class below 

333 

334import Charset 

335 

336 

337 

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 

350 

351class Layout(object): 

352 def __init__(self, node): 

353 

354 self.max = int( node.getAttribute('max') ) 

355 self.width = int( node.getAttribute('width') ) 

356 self.height = int( node.getAttribute('height') ) 

357 

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 

366 

367 for location_node in node.getElementsByTagName('location'): 

368 hud_seat = location_node.getAttribute('seat') 

369 if hud_seat != "": 

370 

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'))) 

381 

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" 

394 

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") 

404 

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) 

408 

409 

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 = '' 

427 

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 

433 

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 

439 

440 self.emails = {} 

441 for email_node in node.getElementsByTagName('email'): 

442 email = Email(email_node) 

443 self.emails[email.fetchType] = email 

444 

445 

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" 

456 

457 for fetchtype in self.emails: 

458 temp = temp + str(self.emails[fetchtype]) + "\n" 

459 

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]) 

462 

463 for max in self.fav_seat: 

464 temp = temp + " max = %s, fav_seat = %s\n" % (max, self.fav_seat[max]) 

465 

466 return temp 

467 

468 

469class Stat(object): 

470 

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") 

488 

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" 

498 

499 return temp 

500 

501 

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 """ 

512 

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 # 

522 

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! 

527 

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 

534 

535 for stat in list(self.stats.keys()): 

536 temp = temp + "%s" % self.stats[stat] 

537 

538 return temp 

539 

540 

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} ) 

554 

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 

563 

564 

565class Aux_window(object): 

566 def __init__(self, node): 

567 for (name, value) in list(node.attributes.items()): 

568 setattr(self, name, value) 

569 

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" 

577 

578 return temp 

579 

580 

581class Supported_games(object): 

582 def __init__(self, node): 

583 for (name, value) in list(node.attributes.items()): 

584 setattr(self, name, value) 

585 

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 

590 

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" 

600 

601 for gs in self.game_stat_set: 

602 temp = temp + "%s" % str(self.game_stat_set[gs]) 

603 return temp 

604 

605 

606class Layout_set(object): 

607 def __init__(self, node): 

608 for (name, value) in list(node.attributes.items()): 

609 setattr(self, name, value) 

610 

611 self.layout = {} 

612 for layout_node in node.getElementsByTagName('layout'): 

613 lo = Layout(layout_node) 

614 self.layout[lo.max] = lo 

615 

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" 

625 

626 for layout in self.layout: 

627 temp = temp + "%s" % self.layout[layout] 

628 return temp 

629 

630 

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") 

635 

636 def __str__(self): 

637 return " Game Type: '%s' Stat Set: '%s'\n" % (self.game_type, self.stat_set) 

638 

639 

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") 

645 

646 def __str__(self): 

647 return "%s:\tconverter: '%s' summaryImporter: '%s'" % (self.site, self.converter, self.summaryImporter) 

648 

649 

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 = [] 

656 

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")))) 

664 

665 

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" 

671 

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" 

693 

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) 

697 

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') 

720 

721 

722 def __str__(self): 

723 return " label = %s\n" % self.label 

724 

725 

726class General(dict): 

727 def __init__(self): 

728 super(General, self).__init__() 

729 

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 

737 

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" 

744 

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" 

751 

752 def __str__(self): 

753 s = "" 

754 for k in self: 

755 s = s + " %s = %s\n" % (k, self[k]) 

756 return(s) 

757 

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__() 

766 

767 

768 

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 

774 

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")) 

786 

787 self.append( [col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment] ) 

788 

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) 

822 

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__() 

836 

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 

842 

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")) 

854 

855 self.append( [col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment] ) 

856 

857 

858 

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) 

867 

868 

869 

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" 

883 

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__ 

891 

892 def __str__(self): 

893 return " save= %s, compression= %s\n" % (self.save, self.compression) 

894#end class RawHands 

895 

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" 

909 

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__ 

917 

918 def __str__(self): 

919 return " save= %s, compression= %s\n" % (self.save, self.compression) 

920#end class RawTourneys 

921 

922class Config(object): 

923 def __init__(self, file = None, dbname = '', custom_log_dir='', lvl='INFO'): 

924 

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 

934 

935 if not os.path.exists(CONFIG_PATH): 

936 os.makedirs(CONFIG_PATH) 

937 

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") 

949 

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 

952 

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 

961 

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) 

964 

965 self.file = file 

966 

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 

982 

983 

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() 

1003 

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) 

1007 

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 

1012 

1013 if int(self.general["version"]) == CONFIG_VERSION: 

1014 self.wrongConfigVersion = False 

1015 else: 

1016 self.wrongConfigVersion = True 

1017 

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 

1022 

1023 

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 

1028 

1029 

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 

1034 

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 

1039 

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') 

1061 

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 

1066 

1067 for ls_node in doc.getElementsByTagName("ls"): 

1068 ls = Layout_set(node = ls_node) 

1069 self.layout_sets[ls.name] = ls 

1070 

1071 for ss_node in doc.getElementsByTagName("ss"): 

1072 ss = Stat_sets(node = ss_node) 

1073 self.stat_sets[ss.name] = ss 

1074 

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 

1079 

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 

1084 

1085 for imp_node in doc.getElementsByTagName("import"): 

1086 imp = Import(node = imp_node) 

1087 self.imp = imp 

1088 

1089 for hui_node in doc.getElementsByTagName('hud_ui'): 

1090 hui = HudUI(node = hui_node) 

1091 self.ui = hui 

1092 

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")) 

1106 

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) 

1111 

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) 

1116 

1117 #print "" 

1118 #end def __init__ 

1119 

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""" 

1124 

1125 nodes_added = 0 

1126 

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 

1132 

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 

1147 

1148 if nodes_added > 0: 

1149 print(("Added %d missing config sections" % nodes_added)+"\n") 

1150 self.save() 

1151 

1152 return nodes_added 

1153 

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 

1158 

1159 if config_file and os.path.exists(config_file): 

1160 file = config_file 

1161 else: 

1162 file = None 

1163 return file 

1164 

1165 def get_doc(self): 

1166 return self.doc 

1167 

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 

1172 

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 

1180 

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 

1187 

1188 

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 

1196 

1197 

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 

1202 

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 

1207 

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 

1212 

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 

1217 

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 

1223 

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 

1230 

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 

1240 

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 

1248 

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() ) ) 

1252 

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') 

1256 

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 

1262 

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) 

1278 

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 

1287 

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) 

1291 

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 

1312 

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})" 

1331 

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 

1351 

1352 #end def 

1353 

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) 

1361 

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") 

1366 

1367 for node in statNodes: 

1368 statsetNode.removeChild(node) 

1369 

1370 statsetNode.setAttribute("rows", str(len(statArray))) 

1371 statsetNode.setAttribute("cols", str(len(statArray[0]))) 

1372 

1373 for rowNumber in range(len(statArray)): 

1374 for columnNumber in range(len(statArray[rowNumber])): 

1375 newStat = self.doc.createElement("stat") 

1376 

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 } 

1389 

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) 

1394 

1395 statsetNode.appendChild(newStat) 

1396 

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) 

1403 

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 

1406 

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)) 

1412 

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 

1428 

1429 

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 

1443 

1444 try: db['db-desc'] = self.supported_databases[name].db_desc 

1445 except: pass 

1446 

1447 try: db['db-host'] = self.supported_databases[name].db_ip 

1448 except: pass 

1449 

1450 try: db['db-port'] = self.supported_databases[name].db_port 

1451 except: pass 

1452 

1453 try: db['db-user'] = self.supported_databases[name].db_user 

1454 except: pass 

1455 

1456 try: db['db-password'] = self.supported_databases[name].db_pass 

1457 except: pass 

1458 

1459 try: db['db-server'] = self.supported_databases[name].db_server 

1460 except: pass 

1461 

1462 try: db['db-path'] = self.supported_databases[name].db_path 

1463 except: pass 

1464 

1465 db['db-backend'] = self.get_backend(self.supported_databases[name].db_server) 

1466 

1467 return db 

1468 

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 

1500 

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") 

1508 

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") 

1545 

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 

1557 

1558 if defaultb: 

1559 self.db_selected = db_name 

1560 return 

1561 

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) 

1576 

1577 return ret 

1578 

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 

1585 

1586 # Allow to change the menu appearance 

1587 def get_hud_ui_parameters(self): 

1588 hui = {} 

1589 

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 

1597 

1598 try: hui['card_ht'] = int(self.ui.card_ht) 

1599 except: hui['card_ht'] = 42 

1600 

1601 try: hui['card_wd'] = int(self.ui.card_wd) 

1602 except: hui['card_wd'] = 30 

1603 

1604 try: hui['deck_type'] = str(self.ui.deck_type) 

1605 except: hui['deck_type'] = 'colour' 

1606 

1607 try: hui['card_back'] = str(self.ui.card_back) 

1608 except: hui['card_back'] = 'back04' 

1609 

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) 

1612 

1613 try: hui['hud_days'] = int(self.ui.hud_days) 

1614 except: hui['hud_days'] = 90 

1615 

1616 try: hui['agg_bb_mult'] = int(self.ui.agg_bb_mult) 

1617 except: hui['agg_bb_mult'] = 1 

1618 

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 

1621 

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 

1626 

1627 # Hero specific 

1628 

1629 try: hui['h_stat_range'] = self.ui.h_stat_range 

1630 except: hui['h_stat_range'] = 'S' 

1631 

1632 try: hui['h_hud_days'] = int(self.ui.h_hud_days) 

1633 except: hui['h_hud_days'] = 30 

1634 

1635 try: hui['h_agg_bb_mult'] = int(self.ui.h_agg_bb_mult) 

1636 except: hui['h_agg_bb_mult'] = 1 

1637 

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 

1640 

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 

1646 

1647 

1648 def get_import_parameters(self): 

1649 imp = {} 

1650 try: imp['callFpdbHud'] = self.imp.callFpdbHud 

1651 except: imp['callFpdbHud'] = True 

1652 

1653 try: imp['interval'] = self.imp.interval 

1654 except: imp['interval'] = 10 

1655 

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/" 

1663 

1664 # hhBulkPath is the default location for bulk imports (if set) 

1665 try: imp['hhBulkPath'] = self.imp.hhBulkPath 

1666 except: imp['hhBulkPath'] = "" 

1667 

1668 try: imp['saveActions'] = self.imp.saveActions 

1669 except: imp['saveActions'] = False 

1670 

1671 try: imp['cacheSessions'] = self.imp.cacheSessions 

1672 except: imp['cacheSessions'] = False 

1673 

1674 try: imp['publicDB'] = self.imp.publicDB 

1675 except: imp['publicDB'] = False 

1676 

1677 try: imp['sessionTimeout'] = self.imp.sessionTimeout 

1678 except: imp['sessionTimeout'] = 30 

1679 

1680 try: imp['saveStarsHH'] = self.imp.saveStarsHH 

1681 except: imp['saveStarsHH'] = False 

1682 

1683 try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache 

1684 except: imp['fastStoreHudCache'] = False 

1685 

1686 try: imp['importFilters'] = self.imp.importFilters 

1687 except: imp['importFilters'] = [] 

1688 

1689 try: imp['timezone'] = self.imp.timezone 

1690 except: imp['timezone'] = "America/New_York" 

1691 

1692 return imp 

1693 

1694 def set_timezone(self, timezone): 

1695 self.imp.timezone = timezone 

1696 

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 

1712 

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 

1716 

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 

1732 

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 

1743 

1744 def get_layout_set_locations(self, set = "mucked", max = "9"): 

1745 

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 

1753 

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] 

1760 

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 

1778 

1779 return parms 

1780 

1781 def get_layout(self, site, game_type): 

1782 

1783 # find layouts used at site 

1784 # locate the one used for this game_type 

1785 # return that Layout-set() instance  

1786 

1787 site_layouts = self.get_site_parameters(site)["layout_set"] 

1788 

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 

1795 

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 

1818 

1819 def set_general(self,lang=None): 

1820 

1821 for general_node in self.doc.getElementsByTagName('general'): 

1822 if lang: general_node.setAttribute("ui_language", lang) 

1823 

1824 def set_site_ids(self, sites): 

1825 self.site_ids = dict(sites) 

1826 

1827 def get_site_id(self, site): 

1828 return( self.site_ids[site] ) 

1829 

1830 def get_aux_windows(self): 

1831 """Gets the list of mucked window formats in the configuration.""" 

1832 return list(self.aux_windows.keys()) 

1833 

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 

1843 

1844 return param 

1845 return None 

1846 

1847 def get_stat_sets(self): 

1848 """Gets the list of stat block contents in the configuration.""" 

1849 return list(self.stat_sets.keys()) 

1850 

1851 

1852 

1853 def get_layout_sets(self): 

1854 """Gets the list of block layouts in the configuration.""" 

1855 return list(self.layout_sets.keys()) 

1856 

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 

1866 

1867 return param 

1868 return None 

1869 

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 

1876 

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 

1887 

1888 #some gymnastics now to load the correct Stats_sets instance 

1889 # into the game_stat_set key 

1890 

1891 game_stat_set = getattr(self.supported_games[name], 'game_stat_set') 

1892 

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 

1899 

1900 return param 

1901 

1902 return None 

1903 

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) 

1907 

1908 def get_general_params(self): 

1909 return( self.general ) 

1910 

1911 def get_gui_cash_stat_params(self): 

1912 #print(type(self.gui_cash_stats)) 

1913 return( self.gui_cash_stats ) 

1914 

1915 def get_gui_tour_stat_params(self): 

1916 #print(type(self.gui_tour_stats)) 

1917 return( self.gui_tour_stats ) 

1918 

1919if __name__== "__main__": 

1920 set_logfile("fpdb-log.txt") 

1921 c = Config() 

1922 

1923 print("\n----------- GENERAL -----------") 

1924 print(c.general) 

1925 

1926 print("\n----------- SUPPORTED SITES -----------") 

1927 for s in list(c.supported_sites.keys()): 

1928 print(c.supported_sites[s]) 

1929 

1930 print("\n----------- SUPPORTED GAMES -----------") 

1931 for game in list(c.supported_games.keys()): 

1932 print(c.supported_games[game]) 

1933 

1934 print("\n----------- SUPPORTED DATABASES -----------") 

1935 for db in list(c.supported_databases.keys()): 

1936 print(c.supported_databases[db]) 

1937 

1938 print("\n----------- AUX WINDOW FORMATS -----------") 

1939 for w in list(c.aux_windows.keys()): 

1940 print(c.aux_windows[w]) 

1941 

1942 print("\n----------- LAYOUT SETS FORMATS -----------") 

1943 for w in list(c.layout_sets.keys()): 

1944 print(c.layout_sets[w]) 

1945 

1946 print("\n----------- STAT SETS FORMATS -----------") 

1947 for w in list(c.stat_sets.keys()): 

1948 print(c.stat_sets[w]) 

1949 

1950 print("\n----------- HAND HISTORY CONVERTERS -----------") 

1951 for w in list(c.hhcs.keys()): 

1952 print(c.hhcs[w]) 

1953 

1954 print("\n----------- POPUP WINDOW FORMATS -----------") 

1955 for w in list(c.popup_windows.keys()): 

1956 print(c.popup_windows[w]) 

1957 

1958 print("\n----------- DATABASE PARAMS -----------") 

1959 print("db = ", c.get_db_parameters()) 

1960 

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)) 

1965 

1966 print("\n----------- STARTUP PATH -----------") 

1967 print("start up path = ", c.execution_path("")) 

1968 

1969 print("\n----------- GUI CASH STATS -----------") 

1970 print("gui_cash_stats =", c.gui_cash_stats) 

1971 

1972 print("\n----------- Heroes -----------") 

1973 for s in list(c.supported_sites.keys()): 

1974 print(c.supported_sites[s].screen_name) 

1975 

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 -----------") 

1987 

1988 print("press enter to end") 

1989 sys.stdin.readline() 

1990