Merge branch 'master' of git://git.assembla.com/fpdboz

This commit is contained in:
Mika Bostrom 2009-10-31 08:02:49 +02:00
commit 0615efcf4a
8 changed files with 482 additions and 387 deletions

View File

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

View File

@ -8,13 +8,42 @@ import gtk
class DatabaseManager(object):
DatabaseTypes = {}
def __init__(self, defaultDatabaseType=None):
@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)
@ -27,96 +56,109 @@ class DatabaseTypeMeta(type):
class DatabaseTypeBase(object):
__metaclass__ = DatabaseTypeMeta
Type = None
Params = ()
class DatabaseTypePostgres(DatabaseTypeBase):
Type = 'postgres'
def __init__(self, host='localhost', port=5432, user='postgres', password='', database='fpdb', name=''):
@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
self.name = name
class DatabaseTypeMysql(DatabaseTypeBase):
Type = 'mysql'
def __init__(self, host='localhost', port=3306, user='root', password='', database='fpdb', name=''):
@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
self.name = name
class DatabaseTypeSqLite(DatabaseTypeBase):
Type = 'sqlite'
def __init__(self, host='', file='', name=''):
self.file = file
@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']
#***************************************************************************************************************************
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
#
#TODO: derrive from gtk.VBox?
class WidgetDatabaseProperties(gtk.VBox):
ModeEdit = 0x1
ModeAdd = 0x2
ModeNew = 0x4
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=''):
"""
@ -152,11 +194,14 @@ class WidgetDatabaseProperties(gtk.VBox):
def reset_value(self):
getattr(self._widget, self._attrSet)(self._defaultValue)
def __init__(self, databaseManager, database=None, flags=ModeEdit):
def __init__(self, databaseManager, database, mode=ModeEdit, parentWidget=None):
gtk.VBox.__init__(self)
self.flags = flags
self.fieldWidgets = ( #fieldName--> fieldHandler
self.databaseManager = databaseManager
self.database = database
self.mode = mode
self.parentWidget = parentWidget
self.fieldWidgets = (
self.FieldWidget(
text='Name:',
attrDatabase='name',
@ -165,57 +210,7 @@ class WidgetDatabaseProperties(gtk.VBox):
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=''
tooltip='Any name you like to name the database '
),
self.FieldWidget(
text='Db:',
@ -225,7 +220,57 @@ class WidgetDatabaseProperties(gtk.VBox):
attrGet='get_text',
attrSet='set_text',
canEdit=False,
tooltip=''
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'
),
)
@ -236,10 +281,18 @@ class WidgetDatabaseProperties(gtk.VBox):
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)
# 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)
@ -250,60 +303,37 @@ class WidgetDatabaseProperties(gtk.VBox):
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)
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:
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)
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 > -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)
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):
@ -312,16 +342,7 @@ class WidgetDatabaseProperties(gtk.VBox):
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'
def __init__(self, databaseManager, database, parent=None, mode=WidgetDatabaseProperties.ModeEdit, title=''):
gtk.Dialog.__init__(self,
title=title,
parent=parent,
@ -334,13 +355,12 @@ class DialogDatabaseProperties(gtk.Dialog):
self.connect('response', self.on_dialog_response)
# setup widget
self.flags = flags
self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database=database, flags=self.flags)
self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database, mode=mode, parentWidget=self)
self.vbox.pack_start(self.widgetDatabaseProperties, True, True)
self.widgetDatabaseProperties.show_all()
self.show_all()
def get_database(self):
return self.widgetDatabaseProperties.get_database()
def get_widget_database_properties(self):
return self.widgetDatabaseProperties
def on_dialog_response(self, dlg, responseId):
if responseId == gtk.RESPONSE_REJECT:
@ -348,21 +368,15 @@ class DialogDatabaseProperties(gtk.Dialog):
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)
#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')
@ -394,22 +408,33 @@ class DialogDatabase(gtk.Dialog):
self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it')
self.buttonDatabaseDelete.set_sensitive(False)
# database tree
# init database tree
self.treeDatabases = gtk.TreeView()
store = gtk.ListStore(str, str, str)
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')
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
self.vbox.pack_start(self.labelInfo, False, False, 2)
self.vbox.pack_start(gtk.HSeparator(), False, False, 2)
vbox = gtk.VBox(self)
vbox.pack_start(self.labelInfo, False, False, 2)
vbox.pack_start(gtk.HSeparator(), False, False, 2)
hbox = gtk.HBox()
self.vbox.add(hbox)
self.add(hbox)
hbox.set_homogeneous(False)
vbox = gtk.VBox()
hbox.pack_start(vbox, False, False, 2)
@ -425,29 +450,67 @@ class DialogDatabase(gtk.Dialog):
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):
dlg = DialogDatabaseProperties(self.databaseManager, parent=self, flags=WidgetDatabaseProperties.ModeNew)
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_database()
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type) )
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):
dlg = DialogDatabaseProperties(self.databaseManager, parent=self, flags=WidgetDatabaseProperties.ModeAdd)
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_database()
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type) )
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):
dlg = DialogDatabaseProperties(self.databaseManager, parent=self, flags=WidgetDatabaseProperties.ModeEdit)
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:
@ -466,17 +529,32 @@ class DialogDatabase(gtk.Dialog):
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 = DialogDatabase(DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite))
d = DialogDatabaseManager(databaseManager)
d.connect("destroy", gtk.main_quit)
d.run()
#gtk.main()

View File

@ -32,12 +32,11 @@ try:
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
from numpy import arange, cumsum
from pylab import *
except ImportError as inst:
except ImportError:
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

View File

@ -37,10 +37,11 @@ try:
# from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
# DayLocator, MONDAY, timezone
except ImportError as inst:
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
print """Failed to load numpy in Session Viewer"""
print """This is of no consequence as the page is broken and only of interest to developers."""
print "ImportError: %s" % inst.args
print """This is of no consequence as the module currently doesn't do anything."""
import Card
import fpdb_import

View File

@ -566,6 +566,7 @@ Left-Drag to Move"
<hhc site="Absolute" converter="AbsoluteToFpdb"/>
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
<hhc site="Betfair" converter="BetfairToFpdb"/>
<hhc site="Partouche" converter="PartoucheToFpdb"/>
</hhcs>
<supported_databases>

View File

@ -189,99 +189,95 @@ class HUD_main(object):
# be passed to HUDs for use in the gui thread. HUD objects should not
# need their own access to the database, but should open their own
# if it is required.
try:
self.db_connection = Database.Database(self.config)
tourny_finder = re.compile('(\d+) (\d+)')
# get hero's screen names and player ids
self.hero, self.hero_ids = {}, {}
for site in self.config.get_supported_sites():
result = self.db_connection.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id])
self.db_connection = Database.Database(self.config)
tourny_finder = re.compile('(\d+) (\d+)')
while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id)
if new_hand_id == "": # blank line means quit
self.destroy()
break # this thread is not always killed immediately with gtk.main_quit()
# get hero's screen names and player ids
self.hero, self.hero_ids = {}, {}
for site in self.config.get_supported_sites():
result = self.db_connection.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id])
while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id)
if new_hand_id == "": # blank line means quit
self.destroy()
break # this thread is not always killed immediately with gtk.main_quit()
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
try:
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
try:
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
cards['common'] = comm_cards['common']
except Exception, err:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
cards['common'] = comm_cards['common']
except Exception, err:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
if type == "tour": # hand is from a tournament
mat_obj = tourny_finder.search(table_name)
if mat_obj:
(tour_number, tab_number) = mat_obj.group(1, 2)
temp_key = tour_number
else: # tourney, but can't get number and table
print "could not find tournament: skipping "
#sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
continue
if type == "tour": # hand is from a tournament
mat_obj = tourny_finder.search(table_name)
if mat_obj:
(tour_number, tab_number) = mat_obj.group(1, 2)
temp_key = tour_number
else: # tourney, but can't get number and table
print "could not find tournament: skipping "
#sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
continue
else:
temp_key = table_name
else:
temp_key = table_name
# Update an existing HUD
if temp_key in self.hud_dict:
try:
# get stats using hud's specific params
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days'])
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config)
if temp_key in self.hud_dict:
try:
# get stats using hud's specific params
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days'])
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD
else:
try:
# get stats using default params
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
if type == "tour":
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else:
try:
# get stats using default params
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
if type == "tour":
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else:
tablewindow = Tables.discover_table_by_name(self.config, table_name)
if tablewindow == None:
tablewindow = Tables.discover_table_by_name(self.config, table_name)
if tablewindow == None:
# If no client window is found on the screen, complain and continue
if type == "tour":
table_name = "%s %s" % (tour_number, tab_number)
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
self.db_connection.connection.rollback()
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if type == "tour":
table_name = "%s %s" % (tour_number, tab_number)
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
self.db_connection.connection.rollback()
if __name__== "__main__":

View File

@ -238,7 +238,8 @@ def discover_nt_by_name(c, tablename):
try:
# maybe it's better to make global titles[hwnd] decoding?
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower(): continue
if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower():
continue
except:
continue
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
@ -246,8 +247,8 @@ def discover_nt_by_name(c, tablename):
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches?
temp = decode_windows(c, titles[hwnd], hwnd)
#print "attach to window", temp
return decode_windows(c, titles[hwnd], hwnd)
print "attach to window", temp
return temp
return None
def discover_nt_tournament(c, tour_number, tab_number):
@ -257,9 +258,12 @@ def discover_nt_tournament(c, tour_number, tab_number):
titles ={}
win32gui.EnumWindows(win_enum_handler, titles)
for hwnd in titles:
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
if 'HUD:' in titles[hwnd]: continue # FPDB HUD window
# Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
if 'Chat:' in titles[hwnd]: continue
# Everleaf Network HH viewer window
if 'History for table:' in titles[hwnd]: continue
# FPDB HUD window
if 'HUD:' in titles[hwnd]: continue
if re.search(search_string, titles[hwnd]):
return decode_windows(c, titles[hwnd], hwnd)
@ -268,22 +272,34 @@ def discover_nt_tournament(c, tour_number, tab_number):
def get_nt_exe(hwnd):
"""Finds the name of the executable that the given window handle belongs to."""
# Request privileges to enable "debug process", so we can later use PROCESS_VM_READ, retardedly required to GetModuleFileNameEx()
# Request privileges to enable "debug process", so we can later use
# PROCESS_VM_READ, retardedly required to GetModuleFileNameEx()
priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), priv_flags)
hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(),
priv_flags)
# enable "debug process"
privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME)
old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)])
privilege_id = win32security.LookupPrivilegeValue(None,
win32security.SE_DEBUG_NAME)
old_privs = win32security.AdjustTokenPrivileges(hToken, 0,
[(privilege_id,
win32security.SE_PRIVILEGE_ENABLED)])
# Open the process, and query it's filename
processid = win32process.GetWindowThreadProcessId(hwnd)
pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1])
exename = win32process.GetModuleFileNameEx(pshandle, 0)
# clean up
win32api.CloseHandle(pshandle)
win32api.CloseHandle(hToken)
pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION |
win32con.PROCESS_VM_READ, False,
processid[1])
try:
exename = win32process.GetModuleFileNameEx(pshandle, 0)
except pywintypes.error:
# insert code to call GetProcessImageName if we can find it..
# returning None from here will hopefully break all following code
exename = None
finally:
# clean up
win32api.CloseHandle(pshandle)
win32api.CloseHandle(hToken)
return exename
def decode_windows(c, title, hwnd):
@ -305,6 +321,8 @@ def decode_windows(c, title, hwnd):
info['width'] = int( width ) - 2*b_width
info['height'] = int( height ) - b_width - tb_height
info['exe'] = get_nt_exe(hwnd)
print "get_nt_exe returned ", info['exe']
# TODO: 'width' here is all sorts of screwed up.
title_bits = re.split(' - ', info['title'])
info['name'] = title_bits[0]

View File

@ -78,7 +78,7 @@ class fpdb_db:
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)
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")