diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 223ef8b2..e6361fb0 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -266,6 +266,7 @@ class Popup: class Import: def __init__(self, node): + self.node = node self.interval = node.getAttribute("interval") self.callFpdbHud = node.getAttribute("callFpdbHud") self.hhArchiveBase = node.getAttribute("hhArchiveBase") @@ -345,8 +346,10 @@ class Config: self.supported_games[game.game_name] = game # s_dbs = doc.getElementsByTagName("supported_databases") - if dbname and dbname in self.supported_databases: - self.db_selected = dbname + # select database from those defined in config by: + # 1) command line option + # or 2) selected="True" in config element + # or 3) just choose the first we come across for db_node in doc.getElementsByTagName("database"): try: db = Database(node = db_node) @@ -360,6 +363,9 @@ class Config: self.db_selected = db.db_name except: raise + if dbname and dbname in self.supported_databases: + self.db_selected = dbname + # s_dbs = doc.getElementsByTagName("mucked_windows") for aw_node in doc.getElementsByTagName("aw"): @@ -396,7 +402,9 @@ class Config: db_pass = df_parms['db-password']) self.save(file=os.path.join(self.default_config_path, "HUD_config.xml")) - + def set_hhArchiveBase(self, path): + self.imp.node.setAttribute("hhArchiveBase", path) + def find_config(self): """Looks in cwd and in self.default_config_path for a config file.""" if os.path.exists('HUD_config.xml'): # there is a HUD_config in the cwd diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 04719d7a..f4de8169 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -209,6 +209,7 @@ class Database: if self.backend == self.SQLITE and db_params['db-databaseName'] == ':memory:' and self.fdb.wrongDbVersion: log.info("sqlite/:memory: - creating") self.recreate_tables() + self.fdb.wrongDbVersion = False self.pcache = None # PlayerId cache self.cachemiss = 0 # Delete me later - using to count player cache misses @@ -1014,7 +1015,7 @@ class Database: if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") else: - c.execute("insert into tourneytypes values (0,1,0,0,0,0,0,null,0,0,0);") + c.execute("insert into TourneyTypes values (0,1,0,0,0,0,0,null,0,0,0);") #end def fillDefaultData @@ -1329,7 +1330,7 @@ class Database: raise FpdbError("invalid category") inserts.append( ( - hands_id, player_ids[i], start_cashes[i], positions[i], + hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - needed for hudcache card1, card2, card3, card4, startCards, winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], hudCache['street0VPI'][i], hudCache['street0Aggr'][i], @@ -1360,7 +1361,7 @@ class Database: c = self.get_cursor() c.executemany (""" INSERT INTO HandsPlayers - (handId, playerId, startCash, position, + (handId, playerId, startCash, position, tourneyTypeId, card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit, street0VPI, street0Aggr, street0_3BChance, street0_3BDone, street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, @@ -1381,7 +1382,7 @@ class Database: VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) ,inserts ) result.append( self.get_last_insert_id(c) ) # wrong? not used currently except: diff --git a/pyfpdb/GuiAutoImport.py b/pyfpdb/GuiAutoImport.py index 77e7fbdc..9e99908b 100755 --- a/pyfpdb/GuiAutoImport.py +++ b/pyfpdb/GuiAutoImport.py @@ -34,6 +34,7 @@ import string class GuiAutoImport (threading.Thread): def __init__(self, settings, config, sql): """Constructor for GuiAutoImport""" + self.importtimer = 0 self.settings=settings self.config=config self.sql = sql @@ -196,11 +197,14 @@ class GuiAutoImport (threading.Thread): self.do_import() interval = int(self.intervalEntry.get_text()) - gobject.timeout_add(interval*1000, self.do_import) + if self.importtimer != 0: + gobject.source_remove(self.importtimer) + self.importtimer = gobject.timeout_add(interval*1000, self.do_import) else: print "auto-import aborted - global lock not available" else: # toggled off + gobject.source_remove(self.importtimer) self.settings['global_lock'].release() self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer print "Stopping autoimport - global lock released." diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index ab36aa15..c4f3105f 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -27,11 +27,13 @@ import traceback import pygtk pygtk.require('2.0') import gtk +import gobject # fpdb/FreePokerTools modules import fpdb_simple import fpdb_import import Configuration +import Exceptions class GuiBulkImport(): @@ -53,12 +55,22 @@ class GuiBulkImport(): else: self.importer.RunImportThreaded() + def dopulse(self): + self.progressbar.pulse() + return True + def load_clicked(self, widget, data=None): # Does the lock acquisition need to be more sophisticated for multiple dirs? # (see comment above about what to do if pipe already open) if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired try: print "\nGlobal lock taken ..." + self.progressbar.set_text("Importing...") + self.progressbar.pulse() + while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7) + gtk.main_iteration(False) + self.timer = gobject.timeout_add(100, self.dopulse) + # get the dir to import from the chooser self.inputFile = self.chooser.get_filename() @@ -74,9 +86,7 @@ class GuiBulkImport(): cb_hmodel = self.cb_drophudcache.get_model() cb_hindex = self.cb_drophudcache.get_active() - self.lab_info.set_markup('Importing ...') # uses pango markup! - while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7) - gtk.main_iteration(False) + #self.lab_info.set_markup('Importing ...') # uses pango markup! if cb_index: self.importer.setDropIndexes(cb_model[cb_index][0]) @@ -91,7 +101,14 @@ class GuiBulkImport(): self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename) self.importer.setCallHud(False) starttime = time() - (stored, dups, partial, errs, ttime) = self.importer.runImport() + try: + (stored, dups, partial, errs, ttime) = self.importer.runImport() + except: + print "*** EXCEPTION DURING BULKIMPORT!!!" + raise Exceptions.FpdbError + finally: + gobject.source_remove(self.timer) + ttime = time() - starttime if ttime == 0: ttime = 1 @@ -106,7 +123,8 @@ class GuiBulkImport(): self.cb_drophudcache.set_active(0) self.lab_hdrop.set_sensitive(True) - self.lab_info.set_text("Import finished") + self.progressbar.set_text("Import Complete") + self.progressbar.set_fraction(0) except: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) @@ -251,9 +269,14 @@ class GuiBulkImport(): self.lab_spacer.show() # label - info - self.lab_info = gtk.Label() - self.table.attach(self.lab_info, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) - self.lab_info.show() +# self.lab_info = gtk.Label() +# self.table.attach(self.lab_info, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) +# self.lab_info.show() + self.progressbar = gtk.ProgressBar() + self.table.attach(self.progressbar, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions = gtk.SHRINK) + self.progressbar.set_text("Waiting...") + self.progressbar.set_fraction(0) + self.progressbar.show() # see how many hands are in the db and adjust accordingly tcursor = self.importer.database.cursor diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 4bae9ed8..e40694ea 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -40,6 +40,9 @@ import logging, logging.config logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf")) log = logging.getLogger("parser") +import pygtk +import gtk + class HandHistoryConverter(): READ_CHUNK_SIZE = 10000 # bytes to read at a time from file in tail mode @@ -82,13 +85,21 @@ follow : whether to tail -f the input""" # TODO: out_path should be sanity checked. out_dir = os.path.dirname(self.out_path) if not os.path.isdir(out_dir) and out_dir != '': - log.info("Creating directory '%s'" % out_dir) - os.makedirs(out_dir) + try: + os.makedirs(out_dir) + except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D + log.error("Unable to create output directory %s for HHC!" % out_dir) + print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir + # TODO: pop up a box to allow person to choose output directory? + # TODO: shouldn't that be done when we startup, actually? + else: + log.info("Created directory '%s'" % out_dir) try: self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') - log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) except: log.error("out_path %s couldn't be opened" % (self.out_path)) + else: + log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) self.follow = follow self.compiledPlayers = set() @@ -116,6 +127,9 @@ If in follow mode, wait for more data to turn up. Otherwise, finish at EOF. """ + while gtk.events_pending(): + gtk.main_iteration(False) + starttime = time.time() if not self.sanityCheck(): log.warning("Failed sanity check") @@ -412,10 +426,8 @@ or None if we fail to get the info """ log.debug("Reading stdin with %s" % self.codepage) # is this necessary? or possible? or what? in_fh = codecs.getreader('cp1252')(sys.stdin) else: - success = False for kodec in self.__listof(self.codepage): - if success: break - print "trying", kodec + #print "trying", kodec try: in_fh = codecs.open(self.in_path, 'r', kodec) in_fh.seek(self.index) @@ -423,9 +435,11 @@ or None if we fail to get the info """ self.obs = in_fh.read() self.index = in_fh.tell() in_fh.close() - success = True + break except: pass + else: + print "unable to read file with any codec in list!", self.in_path elif(self.filetype == "xml"): doc = xml.dom.minidom.parse(filename) self.doc = doc diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index eac1acf4..43b8731b 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -109,6 +109,7 @@ class Hud: win = gtk.Window() win.set_gravity(gtk.gdk.GRAVITY_STATIC) win.set_title("%s FPDBHUD" % (self.table.name)) + win.set_skip_taskbar_hint(True) win.set_decorated(False) win.set_opacity(self.colors["hudopacity"]) @@ -335,7 +336,8 @@ class Hud: for s in self.stat_dict: statd = self.stat_dict[s] try: - self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id'] + self.stat_windows[statd['seat']].player_id = statd['player_id'] + #self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id'] except: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here self.max = 10 self.create(hand, config, self.stat_dict, self.cards) @@ -364,17 +366,7 @@ class Hud: if not self.table.gdkhandle: self.table.gdkhandle = gtk.gdk.window_foreign_new(int(self.table.number)) # gtk handle to poker window -# window.window.reparent(self.table.gdkhandle, 0, 0) -# window.map() -# window.window.set_transient_for(self.table.gdkhandle) -# if os.name == "nt": -# print "window.window.handle=",window.window.handle -# oldparent = win32gui.SetParent(window.window.handle, self.table.number) -# print "oldparent=",oldparent -# win32gui.SendMessage(self.table.number, 0x0127) # WM_CHANGEUISTATE -# win32gui.SendMessage(self.table.number, 0x0128) # WM_UPDATEUISTATE -# window.present() - + window.window.set_transient_for(self.table.gdkhandle) class Stat_Window: @@ -496,7 +488,7 @@ class Stat_Window: self.window.move(self.x, self.y) - self.window.realize() # window must be realized before it has a gdkwindow so we can attach it to the table window.. + self.window.realize() # window must be realized before it has a gdkwindow so we can attach it to the table window.. self.topify_window(self.window) self.window.hide() @@ -640,7 +632,7 @@ if __name__== "__main__": c = Configuration.Config() #tables = Tables.discover(c) - t = Tables.discover_table_by_name(c, "Motorway") + t = Tables.discover_table_by_name(c, "Corona") if t is None: print "Table not found." db = Database.Database(c, 'fpdb', 'holdem') diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index bdc13a93..c8639fbc 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -377,7 +377,7 @@ class Sql: startTime DATETIME NOT NULL, endTime DATETIME, buyinChips INT, - tourneyName varchar(20), + tourneyName varchar(40), matrixIdProcessed TINYINT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */ rebuyChips INT DEFAULT 0, addonChips INT DEFAULT 0, @@ -399,7 +399,7 @@ class Sql: startTime timestamp without time zone, endTime timestamp without time zone, buyinChips INT, - tourneyName varchar(20), + tourneyName varchar(40), matrixIdProcessed SMALLINT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */ rebuyChips INT DEFAULT 0, addonChips INT DEFAULT 0, diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index c4752f16..fd2feca2 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -83,37 +83,30 @@ VERSION = "0.11" class fpdb: def tab_clicked(self, widget, tab_name): """called when a tab button is clicked to activate that tab""" - #print "start of tab_clicked" self.display_tab(tab_name) - #end def tab_clicked def add_and_display_tab(self, new_tab, new_tab_name): """just calls the component methods""" self.add_tab(new_tab, new_tab_name) self.display_tab(new_tab_name) - #end def add_and_display_tab def add_tab(self, new_tab, new_tab_name): """adds a tab, namely creates the button and displays it and appends all the relevant arrays""" - #print "start of add_tab" for i in self.tab_names: #todo: check this is valid - if i==new_tab_name: - return # we depend on this to not create duplicate tabs, there's no reason to raise an error here? -# raise FpdbError("duplicate tab_name not permitted") + if i == new_tab_name: + return # if tab already exists, just go to it self.tabs.append(new_tab) self.tab_names.append(new_tab_name) - new_tab_sel_button=gtk.ToggleButton(new_tab_name) + new_tab_sel_button = gtk.ToggleButton(new_tab_name) new_tab_sel_button.connect("clicked", self.tab_clicked, new_tab_name) self.tab_box.add(new_tab_sel_button) new_tab_sel_button.show() self.tab_buttons.append(new_tab_sel_button) - #end def add_tab def display_tab(self, new_tab_name): """displays the indicated tab""" - #print "start of display_tab, len(self.tab_names):",len(self.tab_names) tab_no = -1 for i, name in enumerate(self.tab_names): if name == new_tab_name: @@ -124,70 +117,68 @@ class fpdb: raise FpdbError("invalid tab_no") else: self.main_vbox.remove(self.current_tab) - #self.current_tab.destroy() self.current_tab=self.tabs[tab_no] self.main_vbox.add(self.current_tab) self.tab_buttons[tab_no].set_active(True) self.current_tab.show() - #end def display_tab def delete_event(self, widget, event, data=None): return False - #end def delete_event def destroy(self, widget, data=None): self.quit(widget) - #end def destroy def dia_about(self, widget, data=None): - print "todo: implement dia_about", - print " version = %s, requires database version %s" % (VERSION, "118") - #end def dia_about + #self.warning_box("About FPDB:\n\nFPDB was originally created by a guy named Steffen, sometime in 2008, \nand is mostly worked on these days by people named Eratosthenes, s0rrow, _mt, EricBlade, sqlcoder, and other strange people.\n\n", "ABOUT FPDB") + dia = gtk.AboutDialog() + dia.set_name("FPDB") + dia.set_version(VERSION) + dia.set_copyright("2008-2009, Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, and others") + dia.set_comments("GTK AboutDialog comments here") + dia.set_license("GPL v3") + dia.set_website("http://fpdb.sourceforge.net/") + dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, and others") + dia.set_program_name("FPDB") + dia.run() + dia.destroy() def dia_create_del_database(self, widget, data=None): - print "todo: implement dia_create_del_database" + self.warning_box("Unimplemented: Create/Delete Database") self.obtain_global_lock() self.release_global_lock() - #end def dia_create_del_database def dia_create_del_user(self, widget, data=None): - print "todo: implement dia_create_del_user" + self.warning_box("Unimplemented: Create/Delete user") self.obtain_global_lock() self.release_global_lock() - #end def dia_create_del_user def dia_database_stats(self, widget, data=None): - print "todo: implement dia_database_stats" - #string=fpdb_db.getDbStats(db, cursor) - #end def dia_database_stats + self.warning_box("Unimplemented: Database Stats") def dia_database_sessions(self, widget, data=None): - new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.sql) + new_sessions_thread = GuiSessionViewer.GuiSessionViewer(self.config, self.sql) self.threads.append(new_sessions_thread) sessions_tab=new_sessions_thread.get_vbox() self.add_and_display_tab(sessions_tab, "Sessions") def dia_delete_db_parts(self, widget, data=None): - print "todo: implement dia_delete_db_parts" + self.warning_box("Unimplemented: Delete Database Parts") self.obtain_global_lock() self.release_global_lock() - #end def dia_delete_db_parts def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None): - print "todo: implement dia_edit_profile" + self.warning_box("Unimplemented: Edit Profile") self.obtain_global_lock() self.release_global_lock() - #end def dia_edit_profile def dia_export_db(self, widget, data=None): - print "todo: implement dia_export_db" + self.warning_box("Unimplemented: Export Database") self.obtain_global_lock() self.release_global_lock() - #end def dia_export_db def dia_get_db_root_credentials(self): """obtains db root credentials from user""" - print "todo: implement dia_get_db_root_credentials" + self.warning_box("Unimplemented: Get Root Database Credentials") # user, pw=None, None # # dialog=gtk.Dialog(title="DB Credentials needed", parent=None, flags=0, @@ -203,17 +194,14 @@ class fpdb: # response=dialog.run() # dialog.destroy() # return (user, pw, response) - #end def dia_get_db_root_credentials def dia_import_db(self, widget, data=None): - print "todo: implement dia_import_db" + self.warning_box("Unimplemented: Import Database") self.obtain_global_lock() self.release_global_lock() - #end def dia_import_db def dia_licensing(self, widget, data=None): - print "todo: implement dia_licensing" - #end def dia_licensing + self.warning_box("Unimplemented: Licensing") def dia_load_profile(self, widget, data=None): """Dialogue to select a file to load a profile from""" @@ -237,7 +225,6 @@ class fpdb: #except: # pass self.release_global_lock() - #end def dia_load_profile def dia_recreate_tables(self, widget, data=None): """Dialogue that asks user to confirm that he wants to delete and recreate the tables""" @@ -267,7 +254,6 @@ class fpdb: print 'User cancelled recreating tables' #if not lock_released: self.release_global_lock() - #end def dia_recreate_tables def dia_recreate_hudcache(self, widget, data=None): if self.obtain_global_lock(): @@ -283,20 +269,15 @@ class fpdb: print 'User cancelled rebuilding hud cache' self.release_global_lock() - def dia_regression_test(self, widget, data=None): - print "todo: implement dia_regression_test" + self.warning_box("Unimplemented: Regression Test") self.obtain_global_lock() self.release_global_lock() - #end def dia_regression_test def dia_save_profile(self, widget, data=None): - print "todo: implement dia_save_profile" - #end def dia_save_profile - + self.warning_box("Unimplemented: Save Profile (try saving a HUD layout, that should do it)") + def diaSetupWizard(self, path): - print "todo: implement setup wizard" - print "setup wizard not implemented - please create the default configuration file:", path diaSetupWizard = gtk.Dialog(title="Fatal Error - Config File Missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK)) label = gtk.Label("Please copy the config file from the docs folder to:") @@ -313,7 +294,6 @@ class fpdb: response = diaSetupWizard.run() sys.exit(1) - #end def diaSetupWizard def get_menu(self, window): """returns the menu for this program""" @@ -328,6 +308,7 @@ class fpdb: