diff --git a/gfx/fpdb-cards.png b/gfx/fpdb-cards.png new file mode 100644 index 00000000..4d14be62 Binary files /dev/null and b/gfx/fpdb-cards.png differ diff --git a/gfx/img-PokerStars-Small.xpm b/gfx/img-PokerStars-Small.xpm new file mode 100644 index 00000000..f4fd457d --- /dev/null +++ b/gfx/img-PokerStars-Small.xpm @@ -0,0 +1,92 @@ +/* XPM */ +/* C:\Program Files\PokerStars\PokerStarsUpdate.exe */ +static char *icon[] = { +"48 48 40 2", +"01 c #800000", +"08 c #C0DCC0", +"4C c #7F1F00", +"6C c #AA0000", +"6D c #AA0055", +"70 c #AA1F00", +"90 c #D40000", +"91 c #D40055", +"94 c #D41F00", +"95 c #D41F55", +"99 c #D43F55", +"9D c #D45F55", +"9E c #D45FAA", +"A1 c #D47F55", +"A2 c #D47FAA", +"A5 c #D49F55", +"A6 c #D49FAA", +"AA c #D4BFAA", +"AE c #D4DFAA", +"AF c #D4DFFF", +"B4 c #FF0055", +"B6 c #FF1F00", +"B7 c #FF1F55", +"BA c #FF3F00", +"BB c #FF3F55", +"BE c #FF5F00", +"BF c #FF5F55", +"C3 c #FF7F55", +"C4 c #FF7FAA", +"C7 c #FF9F55", +"C8 c #FF9FAA", +"CC c #FFBFAA", +"CD c #FFBFFF", +"D0 c #FFDFAA", +"D1 c #FFDFFF", +"D5 c #FFCCFF", +"F6 c #FFFBF0", +"F9 c #FF0000", +"FF c #FFFFFF", +" c None", +"707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", +"6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAAD1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6949DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6BFBBF999F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A6A2C7B6F9F99DD1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A2C8CCBFB6B4F99099F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6C8CCC3BEB7F9F9F99099F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2C8D0C7BFBBB6F9B4F9F99099F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A6AAD0C8C3C3BBF9F9F9F9B4F99099D1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFA6C8D0CCC7C3BFBAB6B4F9F9F99090909DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFA2CCF6CCC8C3BFBEBBF9F9F9B4F9F9B4909099F6FFFFFFFFFFFFFFFFFFFFFFFFFF6C", +"70FFFFFFFFFFFFFFFFFFFFFFFFA6CCD1CCC7C3C3BFBAB6B7F9F9F9B490F990906C99FFFFFFD1FFFFFFD1FFFFFFD1FF70", +"6CFFFFFFFFFFFFFFFFFFFFFFAAC8F6CCC7C8C3BFBFBFB6C4B7F9F9F9F9F99190906C9DFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFD1FFFFFFD1FFFFFFAAC8F6CCCCC8C3C3C3BEBBB6F6BFF9B4F9B490F99091906CA2FFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFD1A6F6CCCCC7C7C3C3BFBBBABFFFC8F9F9F990F9909090906C90AAFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFF6A6D0D1CCC8C7C3C3BFBEBFB6CCFFF6F9F9F9B4F9B49090906C6C95F6FFFFFFFFFFFFFFFFFF6C", +"6CFFFFFFFFFFFFFFFFAACCF6CCCCC7C4C3BFBEBBBABBD1FFFFBFF9F9F990F9F99190956C6C99FFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFD1C8F6CCCCC8C7C7C8C7C8C7C3C8F6FFF6CDBFBBBFBBBFBF9090906C6C6CA6FFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFAAF6D0CCC8C7C3C4D0FFFFFFFFF6F6FFFFF6FFFFFFFFD199F9909090706C99F6FFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFD5CCD1CCCCC7C3C3C3BFC8F6FFFFFFFFFFFFFFFFFFFFC895F990B490916C016CA2FFFFFFFFFFFFFF6C", +"6CFFFFFFFFFFF6AAD1D0CCC7C8C3C3C3BFBEBFD1FFFFFFFFFFFFFFFFA1F9F990F9909090906C0170F6FFFFFFFFFFFF70", +"70FFFFFFFFFFD1CCD0CCC8C8C3C3BFBFBFBABBBACCFFFFFFFFFFD1BBF9F990B490B490906D6C6C6CA6FFFFFFFFFFFF70", +"70FFFFFFFFF6AACCD1CCC7C7C3C3BFBEBFBABABBD1FFFFFFFFFFF699F990B4F990F99090906C700199FFFFFFFFFFFF70", +"70FFFFFFFFFFA6D0CCC8C7C3C3BFBFBFBABBB6BFF6FFFFFFFFFFFFC8F9F990F99091F99190906C0194D1FFFFFFFFFF6C", +"6CFFFFFFFFF6C8CCCCC7C4C3BFBFBEBFBABBB6C8FFFFCCBBC4FFFFD091F9F991F9F990F9906C6D016CAAFFFFFFFFFF70", +"70FFFFFFF6D5A5CCC8C7C3C3BFBEBBBABBBAB6F6F6C4F9F9F9BBD1FFBBF990F9F991F99091906C016CA2FFFFFFFFFF70", +"70FFFFFFFFAEC4C7C7C3BFBFBEBFBABBB6B6BBD1BBF9F9F9F9F9B6CCC8F9B4F990F990909090706C6CA2F6FFFFFFFF70", +"70FFFFFFFFCCC3C8C3C3BFBEBBBABBBAB6B7BBB6F9F9F9B4F9F9F9B4BBB690F9B490B49090916C016CA1FFFFFFFFFF6C", +"6CFFFFFFFFD19DC3BFBFBFBBBABBB6B7B6F9F9F9F9B4F9F9F9B4F9F9F9B4F9F9F9F990B4906C6C016CC8FFFFFFFFFF70", +"70FFFFFFFFF69DBEBFBEBABABBB6B6B6F9F9F9B4F990F9B4F9F9F9F9F9F9F991F990F99090706C016CAAFFFFFFFFFF70", +"70FFFFFFFFFFA2B6BBBAB7B6B6B6B4F9B4F991909090F9F9F990B4F9B4F9F9F9F9B49090906D6C0199FFFFFFFFFFFF70", +"70FFFFFFFFF6F694F9B6B6B4F9F9F9F990F9909090C8A2F999CC95F9F9F9B4F9909090916C6C0190A6FFFFFFFFFFFF6C", +"6CFFFFFFFFFFFFCC91F990F9B4F991F991906C909DFFCCF9BFFFCCF9F9F990F9F991906C70016CA2FFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFC895909090909090906C909EFFFFA2F995FFFFA6B790F99190906C6C6C6CC4F6F6FFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFAEBF9590906C906C99C8FFF6FFBFB69008FFFFF69DB7906C6C6C9499D5F6F6FFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFD0A6A2C3A6CCFFFFFFFF08BBF990A2F6FFFFFFF6CCC8C8CCAFFFF6FFFFFFFFFFFFFFFFFF6C", +"6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6BFF99095F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D1A1BFF9906CA6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2C3BBF9F96C95F6F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6A1C3B6F9B4906C99FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", +"6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAAC3C3BAB4F9F990906C9DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD19DBBBBB6F9F9F990F990909099AAFFFFFFFFFFFFFFFFFFF6FFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A2A1BF9D9EBFA2BFA2BFA29DA2BFA2CCFFFFFFFFF6FFFFFFFFFFFFFFFFFFFF70", +"70FFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FFFFFFFFFFFFFFFFFFFFFFFFF6FFF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", +"6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", +"704C706C7001706C7001706C70706C7070707070707070706C7070707070704C707001707001706C704C6C7070017070"}; diff --git a/packaging/debian/changelog b/packaging/debian/changelog index ce102bf5..ec66f4a7 100644 --- a/packaging/debian/changelog +++ b/packaging/debian/changelog @@ -1,3 +1,9 @@ +free-poker-tools (0.12-1) unstable; urgency=low + + * New release + + -- Mika Bostrom Mon, 26 Oct 2009 17:49:07 +0200 + free-poker-tools (0.11.3+git20091023) unstable; urgency=low * Snapshot release diff --git a/packaging/debian/python-fpdb.postinst b/packaging/debian/python-fpdb.postinst index 1f618958..9680be90 100644 --- a/packaging/debian/python-fpdb.postinst +++ b/packaging/debian/python-fpdb.postinst @@ -3,3 +3,4 @@ # When installed into .../fpdb/ the script gets mode 644 # Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack chmod 755 /usr/bin/fpdb +chmod 755 /usr/share/pyshared/fpdb/HUD_main.py diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 5dba6aac..5b06dc31 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -132,8 +132,8 @@ class Site: if self.use_frames == "": self.use_frames = False if self.font == "": self.font = "Sans" - if self.hudbgcolor == "": self.hudbgcolor = "000000" - if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF" + if self.hudbgcolor == "": self.hudbgcolor = "#000000" + if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF" def __str__(self): temp = "Site = " + self.site_name + "\n" @@ -648,7 +648,7 @@ class Config: # Allow to change the menu appearance def get_hud_ui_parameters(self): hui = {} - + default_text = 'FPDB Menu - Right click\nLeft-Drag to Move' try: hui['label'] = self.ui.label diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 1533c05c..ba71310b 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1145,6 +1145,7 @@ class Database: c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") + c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')") if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") elif self.backend == self.PGSQL: @@ -1264,63 +1265,6 @@ class Database: print "Error during fdb.lock_for_insert:", str(sys.exc_value) #end def lock_for_insert - def getGameTypeId(self, siteid, game): - c = self.get_cursor() - #FIXME: Fixed for NL at the moment - c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'], - int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100))) - tmp = c.fetchone() - if (tmp == None): - hilo = "h" - if game['category'] in ['studhilo', 'omahahilo']: - hilo = "s" - elif game['category'] in ['razz','27_3draw','badugi']: - hilo = "l" - tmp = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo, - int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) ) - return tmp[0] - - def getSqlPlayerIDs(self, pnames, siteid): - result = {} - if(self.pcache == None): - self.pcache = LambdaDict(lambda key:self.insertPlayer(key, siteid)) - - for player in pnames: - result[player] = self.pcache[player] - # NOTE: Using the LambdaDict does the same thing as: - #if player in self.pcache: - # #print "DEBUG: cachehit" - # pass - #else: - # self.pcache[player] = self.insertPlayer(player, siteid) - #result[player] = self.pcache[player] - - return result - - def insertPlayer(self, name, site_id): - result = None - c = self.get_cursor() - q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" - q = q.replace('%s', self.sql.query['placeholder']) - - #print "DEBUG: name: %s site: %s" %(name, site_id) - - c.execute (q, (site_id, name)) - - tmp = c.fetchone() - if (tmp == None): #new player - c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) - ,(name, site_id)) - #Get last id might be faster here. - #c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) - tmp = [self.get_last_insert_id(c)] - return tmp[0] - - def insertGameTypes(self, row): - c = self.get_cursor() - c.execute( self.sql.query['insertGameTypes'], row ) - return [self.get_last_insert_id(c)] - def store_the_hand(self, h): """Take a HandToWrite object and store it in the db""" @@ -1668,6 +1612,64 @@ class Database: # street4CheckCallRaiseChance, # street4CheckCallRaiseDone) + def getGameTypeId(self, siteid, game): + c = self.get_cursor() + #FIXME: Fixed for NL at the moment + c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'], + int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100))) + tmp = c.fetchone() + if (tmp == None): + hilo = "h" + if game['category'] in ['studhilo', 'omahahilo']: + hilo = "s" + elif game['category'] in ['razz','27_3draw','badugi']: + hilo = "l" + tmp = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo, + int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) ) + return tmp[0] + + def getSqlPlayerIDs(self, pnames, siteid): + result = {} + if(self.pcache == None): + self.pcache = LambdaDict(lambda key:self.insertPlayer(key, siteid)) + + for player in pnames: + result[player] = self.pcache[player] + # NOTE: Using the LambdaDict does the same thing as: + #if player in self.pcache: + # #print "DEBUG: cachehit" + # pass + #else: + # self.pcache[player] = self.insertPlayer(player, siteid) + #result[player] = self.pcache[player] + + return result + + def insertPlayer(self, name, site_id): + result = None + c = self.get_cursor() + q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" + q = q.replace('%s', self.sql.query['placeholder']) + + #print "DEBUG: name: %s site: %s" %(name, site_id) + + c.execute (q, (site_id, name)) + + tmp = c.fetchone() + if (tmp == None): #new player + c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) + ,(name, site_id)) + #Get last id might be faster here. + #c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) + tmp = [self.get_last_insert_id(c)] + return tmp[0] + + def insertGameTypes(self, row): + c = self.get_cursor() + c.execute( self.sql.query['insertGameTypes'], row ) + return [self.get_last_insert_id(c)] + + ################################# # Finish of NEWIMPORT CODE diff --git a/pyfpdb/DatabaseManager.py b/pyfpdb/DatabaseManager.py new file mode 100644 index 00000000..ddaa6fcd --- /dev/null +++ b/pyfpdb/DatabaseManager.py @@ -0,0 +1,562 @@ + +import os +import pygtk +pygtk.require('2.0') +import gtk + +#******************************************************************************************************* +class DatabaseManager(object): + DatabaseTypes = {} + + @classmethod + def from_fpdb(klass, data, defaultDatabaseType=None): + #TODO: parse whatever data is + #TODO: sort out unsupported databases passed by user and log + databases = ( + DatabaseTypeSqLite(name='myDb'), + DatabaseTypeSqLite(name='myDb2'), + + ) + return klass(databases=databases, defaultDatabaseType=defaultDatabaseType) + + + def __init__(self, databases=None, defaultDatabaseType=None): + self._defaultDatabaseType = defaultDatabaseType + self._databases = [] if databases is None else list(databases) + def __iter__(self): + return iter(self._databases) + def set_default_database_type(self, databaseType): + self._defaultDatabaseType = defaultDatabaseType + def get_default_database_type(self): + return self._defaultDatabaseType + def database_from_id(self, idDatabase): + for database in self._databases: + if idDatabase == id(database): + return database + def database_id(self, database): + return id(database) + def add_database(self, database): + if database in self._databases: + raise ValueError('database already registered') + self._databases.append(database) + def remove_database(self, database): + self._databases.remove(database) + def init_database(self, database): + pass + +class DatabaseTypeMeta(type): + def __new__(klass, name, bases, kws): + newKlass = type.__new__(klass, name, bases, kws) + if newKlass.Type is not None: + if newKlass.Type in DatabaseManager.DatabaseTypes: + raise ValueError('data base type already registered for: %s' % newKlass.Type) + DatabaseManager.DatabaseTypes[newKlass.Type] = newKlass + return newKlass + +class DatabaseTypeBase(object): + __metaclass__ = DatabaseTypeMeta + Type = None + Params = () + +class DatabaseTypePostgres(DatabaseTypeBase): + Type = 'postgres' + @classmethod + def display_name(klass): + return 'Postgres' + def __init__(self, name='', host='localhost', port=5432, user='postgres', password='', database='fpdb'): + self.name = name + self.host = host + self.port = port + self.user = user + self.password = password + self.database = database + +class DatabaseTypeMysql(DatabaseTypeBase): + Type = 'mysql' + @classmethod + def display_name(klass): + return 'MySql' + def __init__(self, name='', host='localhost', port=3306, user='root', password='', database='fpdb'): + self.name = name + self.host = host + self.port = port + self.user = user + self.password = password + self.database = database + +class DatabaseTypeSqLite(DatabaseTypeBase): + Type = 'sqlite' + @classmethod + def display_name(klass): + return 'SqLite' + def __init__(self, name='', host='', file='', database='fpdb'): + self.name = name + self.file = file + self.database = database + +#TODO: how do we want to handle unsupported database types? +# ..uncomment to remove unsupported database types +#try: import psycopg2 +#except ImportError: del DatabaseManager.DatabaseTypes['postgres'] +#try: import MySQLdb +#except ImportError: del DatabaseManager.DatabaseTypes['mysql'] +#try: import sqlite3 +#except ImportError: del DatabaseManager.DatabaseTypes['sqlite'] + +#*************************************************************************************************************************** +#TODO: derrive from gtk.VBox? +class WidgetDatabaseProperties(gtk.VBox): + + ModeNew = 0 + ModeEdit = 1 + ModeAdd = 2 + + class SqLiteFileChooserButton(gtk.HBox): + #NOTE: for some weird reason it is impossible to let the user choose a non exiting filename with gtk.FileChooserButton, so impl our own on the fly + def __init__(self, widgetDatabaseProperties, parentWidget): + gtk.HBox.__init__(self) + self.set_homogeneous(False) + + self.parentWidget = parentWidget + self.widgetDatabaseProperties = widgetDatabaseProperties + self.entry = gtk.Entry() + self.button = gtk.Button('...') + self.button.connect('clicked', self.on_button_clicked) + + # layout widgets + self.pack_start(self.entry, True, True) + self.pack_start(self.button, False, False) + + def get_filename(self): + return self.entry.get_text() + + def set_filename(self, name): + self.entry.set_text(name) + + def on_button_clicked(self, button): + if self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeAdd: + action = gtk.FILE_CHOOSER_ACTION_OPEN + elif self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeNew: + action = gtk.FILE_CHOOSER_ACTION_SAVE + else: + raise ValueError('unsupported dialog mode') + dlg = gtk.FileChooserDialog( + title='Choose an exiting database file or type in name of a new one', + parent=self.parentWidget, + action=action, + buttons=( + gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_OK, + ), + backend=None + ) + dlg.set_default_response(gtk.RESPONSE_OK) + dlg.set_do_overwrite_confirmation(True) + if dlg.run() == gtk.RESPONSE_OK: + fileName = dlg.get_filename() + self.set_filename(fileName) + dlg.destroy() + + + + class FieldWidget(object): + def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''): + """ + @param canEdit: True if the user can edit the attr in edit mode, False otherwise + """ + self._label = gtk.Label(text) + self._attrDatabase = attrDatabase + self._widget = widget + self._defaultValue = defaultValue + self._attrGetter=None, + self._attrGet = attrGet + self._attrSet = attrSet + self._canEdit = canEdit + + self._label.set_tooltip_text(tooltip) + self._widget.set_tooltip_text(tooltip) + + def widget(self): + return self._widget + def label(self): + return self._label + def is_sensitive(self, database): + return hasattr(database, self._attrDatabase) + def can_edit(self): + return self._canEdit + def set_sensitive(self, flag): + self._label.set_sensitive(flag) + self._widget.set_sensitive(flag) + def value_from_database(self, database): + getattr(self._widget, self._attrSet)( getattr(database, self._attrDatabase) ) + def value_to_database(self, database): + setattr(database, self._attrDatabase, getattr(self._widget, self._attrGet)() ) + def reset_value(self): + getattr(self._widget, self._attrSet)(self._defaultValue) + + def __init__(self, databaseManager, database, mode=ModeEdit, parentWidget=None): + gtk.VBox.__init__(self) + + self.databaseManager = databaseManager + self.database = database + self.mode = mode + self.parentWidget = parentWidget + self.fieldWidgets = ( + self.FieldWidget( + text='Name:', + attrDatabase='name', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=True, + tooltip='Any name you like to name the database ' + ), + self.FieldWidget( + text='Db:', + attrDatabase='database', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='Name of the database to create' + ), + self.FieldWidget( + text='File:', + attrDatabase='file', + widget=self.SqLiteFileChooserButton(self, self.parentWidget), + defaultValue='', + attrGet='get_filename', + attrSet='set_filename', + canEdit=False, + tooltip='Fully qualified path of the file to hold the database ' + ), + self.FieldWidget( + text='Host:', + attrDatabase='host', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='Host the database is located at' + ), + self.FieldWidget( + text='Port:', + attrDatabase='port', + widget=gtk.SpinButton(adjustment=gtk.Adjustment(value=0, lower=0, upper=999999, step_incr=1, page_incr=10) ), + defaultValue=0, + attrGet='get_value', + attrSet='set_value', + canEdit=False, + tooltip='Port to use to connect to the host' + ), + self.FieldWidget( + text='User:', + attrDatabase='user', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='User name used to login to the host' + ), + self.FieldWidget( + text='Pwd:', + attrDatabase='password', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='Password used to login to the host' + ), + ) + + # setup database type combo + self.comboType = gtk.ComboBox() + listStore= gtk.ListStore(str, str) + self.comboType.set_model(listStore) + cell = gtk.CellRendererText() + self.comboType.pack_start(cell, True) + self.comboType.add_attribute(cell, 'text', 0) + self.comboType.connect('changed', self.on_combo_type_changed) + + # fill database type combo with available database klasses. we store (databaseDisplayName, databaseType) in our model for later lookup + iCurrentDatabase = 0 + databaseTypes = [(klass.display_name(), klass.Type) for klass in databaseManager.DatabaseTypes.values()] + databaseTypes.sort() + for i, (databaseDisplayName, databaseType) in enumerate(databaseTypes): + listStore.append( (databaseDisplayName, databaseType) ) + if databaseType == self.database.Type: + iCurrentDatabase = i + if self.mode == self.ModeEdit or len(databaseTypes) < 2: + self.comboType.set_button_sensitivity(gtk.SENSITIVITY_OFF) + + # init and layout field widgets + self.pack_start(self.comboType, False, False, 2) + table = gtk.Table(rows=len(self.fieldWidgets) +1, columns=2, homogeneous=False) + self.pack_start(table, False, False, 2) + for i,fieldWidget in enumerate(self.fieldWidgets): + table.attach(fieldWidget.label(), 0, 1, i, i+1, xoptions=gtk.FILL) + table.attach(fieldWidget.widget(), 1, 2, i, i+1) + + # init widget + self.comboType.set_active(iCurrentDatabase) + self._adjust_widgets(self.database) + + def _adjust_widgets(self, database): + for fieldWidget in self.fieldWidgets: + isSensitive = fieldWidget.is_sensitive(database) + if isSensitive: + fieldWidget.value_from_database(database) + else: + fieldWidget.reset_value() + if self.mode == self.ModeEdit: + isSensitive = isSensitive and fieldWidget.can_edit() + fieldWidget.set_sensitive(isSensitive) + + + def on_combo_type_changed(self, combo): + i = self.comboType.get_active() + if i < 0: + return + + # check if we need to init a new database + currentDatabaseType = self.comboType.get_model()[i][1] + if currentDatabaseType == self.database.Type: + return + + # create new empty database + #NOTE: we dont register it in DatabaseManager + self.database = self.databaseManager.DatabaseTypes[currentDatabaseType]() + self._adjust_widgets(self.database) + + + def get_database(self): + for fieldWidget in self.fieldWidgets: + if fieldWidget.is_sensitive(self.database): + fieldWidget.value_to_database(self.database) + return self.database + + +class DialogDatabaseProperties(gtk.Dialog): + def __init__(self, databaseManager, database, parent=None, mode=WidgetDatabaseProperties.ModeEdit, title=''): + gtk.Dialog.__init__(self, + title=title, + parent=parent, + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + buttons=( + gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, + ) + ) + self.connect('response', self.on_dialog_response) + + # setup widget + self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database, mode=mode, parentWidget=self) + self.vbox.pack_start(self.widgetDatabaseProperties, True, True) + self.show_all() + + def get_widget_database_properties(self): + return self.widgetDatabaseProperties + + def on_dialog_response(self, dlg, responseId): + if responseId == gtk.RESPONSE_REJECT: + pass + elif responseId == gtk.RESPONSE_ACCEPT: + pass + + +#TODO: derrive from gtk.VBox? +# ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete +class WidgetDatabaseManager(gtk.VBox): + def __init__(self, databaseManager, parentWidget=None): + gtk.VBox.__init__(self) + + self.databaseManager = databaseManager + self.parentWidget = parentWidget + + #TODO: dono how to make word wrap work as expected + self.labelInfo = gtk.Label('database management') + self.labelInfo.set_line_wrap(True) + self.labelInfo.set_selectable(True) + self.labelInfo.set_single_line_mode(False) + self.labelInfo.set_alignment(0, 0) + + # database management buttons + + #TODO: bit messy the distinction New/Add/Edit. we'd have to pass three flags to DialogDatabaseProperties + # to handle this. maybe drop Edit (is just a Remove + Add), to keep things simple + self.buttonDatabaseNew = gtk.Button("New..") + self.buttonDatabaseNew.set_tooltip_text('creates a new database') + self.buttonDatabaseNew.connect('clicked', self.on_button_database_new_clicked) + self.buttonDatabaseAdd = gtk.Button("Add..") + self.buttonDatabaseAdd.set_tooltip_text('adds an existing database') + self.buttonDatabaseAdd.connect('clicked', self.on_button_database_add_clicked) + self.buttonDatabaseEdit = gtk.Button("Edit..") + self.buttonDatabaseEdit.set_tooltip_text('edit database settings') + self.buttonDatabaseEdit.connect('clicked', self.on_button_database_edit_clicked) + self.buttonDatabaseEdit.set_sensitive(False) + self.buttonDatabaseRemove = gtk.Button("Remove") + self.buttonDatabaseRemove.set_tooltip_text('removes the database from the list') + self.buttonDatabaseRemove.set_sensitive(False) + + #TODO: i dont think we should do any real database management here. maybe drop it + self.buttonDatabaseDelete = gtk.Button("Delete") + self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it') + self.buttonDatabaseDelete.set_sensitive(False) + + # init database tree + self.treeDatabases = gtk.TreeView() + self.treeDatabaseColumns = ( #NOTE: column names starting with '_' will be hidden + 'Name', + 'Status', + 'Type', + '_id', + ) + + store = gtk.ListStore(str, str, str, int) + self.treeDatabases.set_model(store) + columns = ('Name', 'Status', 'Type', '_id') + for i, column in enumerate(columns): + col = gtk.TreeViewColumn(column, gtk.CellRendererText(), text=i) + self.treeDatabases.append_column(col) + if column.startswith('_'): + col.set_visible(False) + + self.treeDatabaseColumns = dict([(name, i) for (i, name) in enumerate(self.treeDatabaseColumns)]) + self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed) + + # layout widgets + vbox = gtk.VBox(self) + vbox.pack_start(self.labelInfo, False, False, 2) + vbox.pack_start(gtk.HSeparator(), False, False, 2) + hbox = gtk.HBox() + self.add(hbox) + hbox.set_homogeneous(False) + vbox = gtk.VBox() + hbox.pack_start(vbox, False, False, 2) + vbox.pack_start(self.buttonDatabaseNew, False, False, 2) + vbox.pack_start(self.buttonDatabaseAdd, False, False, 2) + vbox.pack_start(self.buttonDatabaseEdit, False, False, 2) + vbox.pack_start(self.buttonDatabaseRemove, False, False, 2) + vbox.pack_start(self.buttonDatabaseDelete, False, False, 2) + box = gtk.VBox() + vbox.pack_start(box, True, True, 0) + + hbox.pack_start(gtk.VSeparator(), False, False, 2) + hbox.pack_end(self.treeDatabases, True, True, 2) + + self.show_all() + + # init widget + for database in self.databaseManager: + self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) + + #TODO: for some reason i have to click OK/Cancel twice to close the dialog + def on_button_database_new_clicked(self, button): + databaseType = self.databaseManager.get_default_database_type() + if databaseType is None: + raise ValueError('no defult database type set') + dlg = DialogDatabaseProperties( + self.databaseManager, + databaseType(), + parent=self.parentWidget, + mode=WidgetDatabaseProperties.ModeNew, + title='[New database] - database properties' + ) + if dlg.run() == gtk.RESPONSE_REJECT: + pass + if dlg.run() == gtk.RESPONSE_ACCEPT: + database = dlg.get_widget_database_properties().get_database() + #TODO: sanity checks + init databse if necessary + self.databaseManager.add_database(database) + self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) + dlg.destroy() + + def on_button_database_add_clicked(self, button): + databaseType = self.databaseManager.get_default_database_type() + if databaseType is None: + raise ValueError('no defult database type set') + dlg = DialogDatabaseProperties( + self.databaseManager, + databaseType(), + parent=self.parentWidget, + mode=WidgetDatabaseProperties.ModeAdd, + title='[Add database] - database properties' + ) + if dlg.run() == gtk.RESPONSE_REJECT: + pass + if dlg.run() == gtk.RESPONSE_ACCEPT: + database = dlg.get_widget_database_properties().get_database() + #TODO: sanity checks + self.databaseManager.add_database(database) + self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) + dlg.destroy() + + def on_button_database_edit_clicked(self, button): + selection = self.treeDatabases.get_selection() + if selection is None: + return + + model, iter = selection.get_selected() + idDatabase = model.get_value(iter, self.treeDatabaseColumns['_id']) + database = self.databaseManager.database_from_id(idDatabase) + dlg = DialogDatabaseProperties( + self.databaseManager, + database=database, + parent=self.parentWidget, + mode=WidgetDatabaseProperties.ModeEdit, + title='[Edit database] - database properties' + ) + if dlg.run() == gtk.RESPONSE_REJECT: + pass + if dlg.run() == gtk.RESPONSE_ACCEPT: + database = dlg.get_database() + selection = self.treeDatabases.get_selection() + if selection is not None: + model, iter = selection.get_selected() + model.set_value(iter, 0, database.name) + dlg.destroy() + + def on_tree_databases_selection_changed(self, treeSelection): + hasSelection = bool(treeSelection.count_selected_rows()) + + # enable/disable selection dependend widgets + self.buttonDatabaseEdit.set_sensitive(hasSelection) + self.buttonDatabaseRemove.set_sensitive(hasSelection) + self.buttonDatabaseDelete.set_sensitive(hasSelection) + + +class DialogDatabaseManager(gtk.Dialog): + def __init__(self, databaseManager, parent=None): + gtk.Dialog.__init__(self, + title="My dialog", + parent=parent, + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + buttons=( + gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, + )) + #self.set_size_request(260, 250) + self.widgetDatabaseManager = WidgetDatabaseManager(databaseManager, parentWidget=self) + self.vbox.pack_start(self.widgetDatabaseManager, True, True) + self.show_all() + +#************************************************************************************************** +if __name__ == '__main__': + databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite) + + #d = DialogDatabaseProperties( + # DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite), + #database=DatabaseTypePostgres(), + # database=None, + # ) + d = DialogDatabaseManager(databaseManager) + d.connect("destroy", gtk.main_quit) + d.run() + #gtk.main() + + diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 106bd038..56b0d489 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -56,7 +56,10 @@ class DerivedStats(): # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and # those values remain default in stud. - boardcards = hand.board['FLOP'] + hand.board['TURN'] + hand.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] + boardcards = [] + for street in hand.communityStreets: + boardcards += hand.board[street] + boardcards += [u'0x', u'0x', u'0x', u'0x', u'0x'] cards = [Card.encodeCard(c) for c in boardcards[0:5]] self.hands['boardcard1'] = cards[0] self.hands['boardcard2'] = cards[1] @@ -809,24 +812,11 @@ class DerivedStats(): self.hands['playersAtStreet4'] = 0 self.hands['playersAtShowdown'] = 0 - for street in hand.actionStreets: + for (i, street) in enumerate(hand.actionStreets[2:]): actors = {} for act in hand.actions[street]: actors[act[0]] = 1 - #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys())) - if hand.gametype['base'] in ("hold"): - if street in "FLOP": self.hands['playersAtStreet1'] = len(actors.keys()) - elif street in "TURN": self.hands['playersAtStreet2'] = len(actors.keys()) - elif street in "RIVER": self.hands['playersAtStreet3'] = len(actors.keys()) - elif hand.gametype['base'] in ("stud"): - if street in "FOURTH": self.hands['playersAtStreet1'] = len(actors.keys()) - elif street in "FIFTH": self.hands['playersAtStreet2'] = len(actors.keys()) - elif street in "SIXTH": self.hands['playersAtStreet3'] = len(actors.keys()) - elif street in "SEVENTH": self.hands['playersAtStreet4'] = len(actors.keys()) - elif hand.gametype['base'] in ("draw"): - if street in "DRAWONE": self.hands['playersAtStreet1'] = len(actors.keys()) - elif street in "DRAWTWO": self.hands['playersAtStreet2'] = len(actors.keys()) - elif street in "DRAWTHREE": self.hands['playersAtStreet3'] = len(actors.keys()) + self.hands['playersAtStreet%s' % str(i+1)] = len(actors.keys()) #Need playersAtShowdown diff --git a/pyfpdb/EverleafToFpdb.py b/pyfpdb/EverleafToFpdb.py index 2835b6ff..fcd76c25 100755 --- a/pyfpdb/EverleafToFpdb.py +++ b/pyfpdb/EverleafToFpdb.py @@ -304,5 +304,5 @@ if __name__ == "__main__": LOG_FILENAME = './logging.out' logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity) - e = Everleaf(in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True, debugging=True) + e = Everleaf(in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 4011ba00..670554e7 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -20,6 +20,7 @@ import pygtk pygtk.require('2.0') import gtk import os +import sys import traceback from time import * #import pokereval @@ -32,11 +33,12 @@ try: from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from numpy import arange, cumsum from pylab import * -except ImportError: +except ImportError, inst: print """Failed to load libs for graphing, graphing will not function. Please in stall numpy and matplotlib if you want to use graphs.""" print """This is of no consequence for other parts of the program, e.g. import and HUD are NOT affected by this problem.""" + print "ImportError: %s" % inst.args import fpdb_import import Database diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py index 7695cf73..79fe3191 100755 --- a/pyfpdb/GuiSessionViewer.py +++ b/pyfpdb/GuiSessionViewer.py @@ -37,11 +37,10 @@ try: # from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ # DayLocator, MONDAY, timezone -except: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) +except ImportError, inst: print """Failed to load numpy in Session Viewer""" - print """This is of no consequence as the module currently doesn't do anything.""" + print """This is of no consequence as the page is broken and only of interest to developers.""" + print "ImportError: %s" % inst.args import Card import fpdb_import @@ -249,6 +248,8 @@ class GuiSessionViewer (threading.Thread): nametest = nametest.replace("L", "") nametest = nametest.replace(",)",")") q = q.replace("", nametest) + q = q.replace("", "%s") + self.db.cursor.execute(q) THRESHOLD = 1800 hands = self.db.cursor.fetchall() diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index 34a8f16d..e879e977 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -4,7 +4,6 @@ -