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/pyfpdb/DatabaseManager.py b/pyfpdb/DatabaseManager.py new file mode 100644 index 00000000..a9269654 --- /dev/null +++ b/pyfpdb/DatabaseManager.py @@ -0,0 +1,484 @@ + +import os +import pygtk +pygtk.require('2.0') +import gtk + +#******************************************************************************************************* +class DatabaseManager(object): + DatabaseTypes = {} + + def __init__(self, defaultDatabaseType=None): + self._defaultDatabaseType = defaultDatabaseType + def set_default_database_type(self, databaseType): + self._defaultDatabaseType = defaultDatabaseType + def get_default_database_type(self): + return self._defaultDatabaseType + +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 + +class DatabaseTypePostgres(DatabaseTypeBase): + Type = 'postgres' + def __init__(self, host='localhost', port=5432, user='postgres', password='', database='fpdb', name=''): + self.host = host + self.port = port + self.user = user + self.password = password + self.database = database + self.name = name + +class DatabaseTypeMysql(DatabaseTypeBase): + Type = 'mysql' + def __init__(self, host='localhost', port=3306, user='root', password='', database='fpdb', name=''): + self.host = host + self.port = port + self.user = user + self.password = password + self.database = database + self.name = name + +class DatabaseTypeSqLite(DatabaseTypeBase): + Type = 'sqlite' + def __init__(self, host='', file='', name=''): + self.file = file + self.name = name + +#*************************************************************************************************************************** +class MyFileChooserButton(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): + gtk.HBox.__init__(self) + self.set_homogeneous(False) + + 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): + dlg = gtk.FileChooserDialog( + title='Choose an exiting database file or type in name of a new one', + parent=None, + action=gtk.FILE_CHOOSER_ACTION_SAVE, + buttons=( + gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_OK, + ), + backend=None + ) + dlg.connect('confirm-overwrite', self.on_dialog_confirm_overwrite) + dlg.set_default_response(gtk.RESPONSE_OK) + dlg.set_do_overwrite_confirmation(True) + if dlg.run() == gtk.RESPONSE_OK: + self.set_filename(dlg.get_filename()) + dlg.destroy() + + #TODO: when the user selects a sqLite database file we got three possible actions + # 1. user types in a new filename. easy one, create the file + # 2. user selectes a file with the intention to overwrite it + # 3. user selects a file with the intention to plug an existing database file in + #IDEA: impl open_existing as plug in, never overwrite, cos we can not guess + #PROBLEMS: how to validate an existing file is a database? + def on_dialog_confirm_overwrite(self, dlg): + print dlg.get_filename() + + gtk.FILE_CHOOSER_CONFIRMATION_CONFIRM + #The file chooser will present its stock dialog to confirm overwriting an existing file. + + gtk.FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME + #The file chooser will terminate and accept the user's choice of a file name. + + gtk.FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN + # + + +class WidgetDatabaseProperties(gtk.VBox): + ModeEdit = 0x1 + ModeAdd = 0x2 + ModeNew = 0x4 + + 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=None, flags=ModeEdit): + gtk.VBox.__init__(self) + + self.flags = flags + self.fieldWidgets = ( #fieldName--> fieldHandler + self.FieldWidget( + text='Name:', + attrDatabase='name', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=True, + tooltip='' + ), + self.FieldWidget( + text='File:', + attrDatabase='file', + widget=MyFileChooserButton(), + defaultValue='', + attrGet='get_filename', + attrSet='set_filename', + canEdit=False, + tooltip='' + ), + self.FieldWidget( + text='Host:', + attrDatabase='host', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='' + ), + 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='' + ), + self.FieldWidget( + text='User:', + attrDatabase='user', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='' + ), + self.FieldWidget( + text='Pwd:', + attrDatabase='password', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='' + ), + self.FieldWidget( + text='Db:', + attrDatabase='database', + widget=gtk.Entry(), + defaultValue='', + attrGet='get_text', + attrSet='set_text', + canEdit=False, + tooltip='' + ), + ) + + # 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) + # fill out combo with database type. we store (displayName, databaseType) in our model for later lookup + for dbType, dbDisplayName in sorted([(klass.Type, klass.Type) for klass in databaseManager.DatabaseTypes.values()]): + listStore.append( (dbDisplayName, dbType) ) + self.comboType.connect('changed', self.on_combo_type_changed) + + # 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 + + # if a database has been passed user is not allowed to change database type + if database is None: + self.comboType.set_button_sensitivity(gtk.SENSITIVITY_ON) + else: + self.comboType.set_button_sensitivity(gtk.SENSITIVITY_OFF) + + # set current database + self.databaseManager = databaseManager + self.database= None + if database is None: + databaseType = self.databaseManager.get_default_database_type() + if databaseType is not None: + database = databaseType() + if database is not None: + self.set_database(database) + + def on_combo_type_changed(self, combo): + i = self.comboType.get_active() + if i > -1: + # change database if necessary + currentDatabaseType = self.comboType.get_model()[i][1] + if currentDatabaseType != self.database.Type: + newDatabase = self.databaseManager.DatabaseTypes[currentDatabaseType]() + self.set_database(newDatabase) + + def set_database(self, database): + self.database = database + + # adjust database type combo if necessary + i = self.comboType.get_active() + if i == -1: + currentDatabaseType = None + else: + currentDatabaseType = self.comboType.get_model()[i][1] + if currentDatabaseType != self.database.Type: + for i, row in enumerate(self.comboType.get_model()): + if row[1] == self.database.Type: + self.comboType.set_active(i) + break + else: + raise ValueError('unknown database type') + + # adjust field widgets to database + for fieldWidget in self.fieldWidgets: + isSensitive = fieldWidget.is_sensitive(self.database) + if isSensitive: + fieldWidget.value_from_database(self.database) + else: + fieldWidget.reset_value() + if self.flags & self.ModeEdit: + isSensitive = isSensitive and fieldWidget.can_edit() + fieldWidget.set_sensitive(isSensitive) + + 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=None,parent=None, flags=WidgetDatabaseProperties.ModeEdit): + if flags & WidgetDatabaseProperties.ModeEdit: + title = '[Edit database] - database properties' + elif flags & WidgetDatabaseProperties.ModeAdd: + title = '[Add database] - database properties' + elif flags & WidgetDatabaseProperties.ModeNew: + title = '[New database] - database properties' + else: + title = 'database properties' + + 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.flags = flags + self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database=database, flags=self.flags) + self.vbox.pack_start(self.widgetDatabaseProperties, True, True) + self.widgetDatabaseProperties.show_all() + + def get_database(self): + return self.widgetDatabaseProperties.get_database() + + def on_dialog_response(self, dlg, responseId): + if responseId == gtk.RESPONSE_REJECT: + pass + elif responseId == gtk.RESPONSE_ACCEPT: + pass + + +#TODO: just boilerplate code +class DialogDatabase(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.databaseManager = databaseManager + + #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) + + # database tree + self.treeDatabases = gtk.TreeView() + store = gtk.ListStore(str, str, str) + self.treeDatabases.set_model(store) + columns = ('Name', 'Status', 'Type') + for i, column in enumerate(columns): + col = gtk.TreeViewColumn(column, gtk.CellRendererText(), text=i) + self.treeDatabases.append_column(col) + self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed) + + # layout widgets + self.vbox.pack_start(self.labelInfo, False, False, 2) + self.vbox.pack_start(gtk.HSeparator(), False, False, 2) + + hbox = gtk.HBox() + self.vbox.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() + + + #TODO: for some reason i have to click OK/Cancel twice to close the dialog + def on_button_database_new_clicked(self, button): + dlg = DialogDatabaseProperties(self.databaseManager, parent=self, flags=WidgetDatabaseProperties.ModeNew) + if dlg.run() == gtk.RESPONSE_REJECT: + pass + if dlg.run() == gtk.RESPONSE_ACCEPT: + database = dlg.get_database() + self.treeDatabases.get_model().append( (database.name, 'foo', database.Type) ) + dlg.destroy() + + def on_button_database_add_clicked(self, button): + dlg = DialogDatabaseProperties(self.databaseManager, parent=self, flags=WidgetDatabaseProperties.ModeAdd) + if dlg.run() == gtk.RESPONSE_REJECT: + pass + if dlg.run() == gtk.RESPONSE_ACCEPT: + database = dlg.get_database() + self.treeDatabases.get_model().append( (database.name, 'foo', database.Type) ) + dlg.destroy() + + def on_button_database_edit_clicked(self, button): + dlg = DialogDatabaseProperties(self.databaseManager, parent=self, flags=WidgetDatabaseProperties.ModeEdit) + 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) + + + + +#************************************************************************************************** +if __name__ == '__main__': + #d = DialogDatabaseProperties( + # DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite), + #database=DatabaseTypePostgres(), + # database=None, + # ) + d = DialogDatabase(DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite)) + 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 9387bdb7..9ce5c17a 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -33,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 as 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..5711cb89 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 as 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 diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index ef67749d..0b3c4f4a 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -626,7 +626,12 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.load_profile() self.statusIcon = gtk.StatusIcon() - self.statusIcon.set_from_stock(gtk.STOCK_HOME) + if os.path.exists('../gfx/fpdb-cards.png'): + self.statusIcon.set_from_file('../gfx/fpdb-cards.png') + elif os.path.exists('/usr/share/pixmaps/fpdb-cards.png'): + self.statusIcon.set_from_file('/usr/share/pixmaps/fpdb-cards.png') + else: + self.statusIcon.set_from_stock(gtk.STOCK_HOME) self.statusIcon.set_tooltip("Free Poker Database") self.statusIcon.connect('activate', self.statusicon_activate) self.statusMenu = gtk.Menu() @@ -673,8 +678,14 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") pass def statusicon_activate(self, widget, data = None): - self.window.show() - self.window.present() + # Let's allow the tray icon to toggle window visibility, the way + # most other apps work + shown = self.window.get_property('visible') + if shown: + self.window.hide() + else: + self.window.show() + self.window.present() def warning_box(self, str, diatitle="FPDB WARNING"): diaWarning = gtk.Dialog(title=diatitle, parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 986c747f..da0bbbe7 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -77,10 +77,11 @@ class fpdb_db: import MySQLdb if use_pool: MySQLdb = pool.manage(MySQLdb, pool_size=5) - try: - self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) - except: - raise FpdbMySQLFailedError("MySQL connection failed") +# try: + self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) + #TODO: Add port option +# except: +# raise FpdbMySQLFailedError("MySQL connection failed") elif backend==fpdb_db.PGSQL: import psycopg2 import psycopg2.extensions diff --git a/setup.py b/setup.py index 0ba21bf0..a9f317c9 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from distutils.core import setup setup(name = 'fpdb', description = 'Free Poker Database', - version = '0.11.3', + version = '0.12', author = 'FPDB team', author_email = 'fpdb-main@lists.sourceforge.net', packages = ['fpdb'], @@ -15,7 +15,9 @@ setup(name = 'fpdb', ['docs/readme.txt', 'docs/release-notes.txt', 'docs/tabledesign.html', 'THANKS.txt']), ('/usr/share/pixmaps', - ['gfx/fpdb-icon.png']), + ['gfx/fpdb-icon.png', 'gfx/fpdb-icon2.png', + 'gfx/fpdb-cards.png' + ]), ('/usr/share/applications', ['files/fpdb.desktop']), ('/usr/share/python-fpdb',