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..c89546ca 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -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/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/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 @@ -