Merge branch 'master' of git://git.assembla.com/fpdboz
This commit is contained in:
commit
0615efcf4a
|
@ -1145,6 +1145,7 @@ class Database:
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')")
|
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 ('Absolute', 'USD')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', '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:
|
if self.backend == self.SQLITE:
|
||||||
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
|
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
|
||||||
elif self.backend == self.PGSQL:
|
elif self.backend == self.PGSQL:
|
||||||
|
@ -1264,63 +1265,6 @@ class Database:
|
||||||
print "Error during fdb.lock_for_insert:", str(sys.exc_value)
|
print "Error during fdb.lock_for_insert:", str(sys.exc_value)
|
||||||
#end def lock_for_insert
|
#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):
|
def store_the_hand(self, h):
|
||||||
"""Take a HandToWrite object and store it in the db"""
|
"""Take a HandToWrite object and store it in the db"""
|
||||||
|
|
||||||
|
@ -1668,6 +1612,64 @@ class Database:
|
||||||
# street4CheckCallRaiseChance,
|
# street4CheckCallRaiseChance,
|
||||||
# street4CheckCallRaiseDone)
|
# 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
|
# Finish of NEWIMPORT CODE
|
||||||
|
|
|
@ -8,12 +8,41 @@ import gtk
|
||||||
class DatabaseManager(object):
|
class DatabaseManager(object):
|
||||||
DatabaseTypes = {}
|
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._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):
|
def set_default_database_type(self, databaseType):
|
||||||
self._defaultDatabaseType = defaultDatabaseType
|
self._defaultDatabaseType = defaultDatabaseType
|
||||||
def get_default_database_type(self):
|
def get_default_database_type(self):
|
||||||
return self._defaultDatabaseType
|
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):
|
class DatabaseTypeMeta(type):
|
||||||
def __new__(klass, name, bases, kws):
|
def __new__(klass, name, bases, kws):
|
||||||
|
@ -27,95 +56,108 @@ class DatabaseTypeMeta(type):
|
||||||
class DatabaseTypeBase(object):
|
class DatabaseTypeBase(object):
|
||||||
__metaclass__ = DatabaseTypeMeta
|
__metaclass__ = DatabaseTypeMeta
|
||||||
Type = None
|
Type = None
|
||||||
|
Params = ()
|
||||||
|
|
||||||
class DatabaseTypePostgres(DatabaseTypeBase):
|
class DatabaseTypePostgres(DatabaseTypeBase):
|
||||||
Type = 'postgres'
|
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.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.user = user
|
self.user = user
|
||||||
self.password = password
|
self.password = password
|
||||||
self.database = database
|
self.database = database
|
||||||
self.name = name
|
|
||||||
|
|
||||||
class DatabaseTypeMysql(DatabaseTypeBase):
|
class DatabaseTypeMysql(DatabaseTypeBase):
|
||||||
Type = 'mysql'
|
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.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.user = user
|
self.user = user
|
||||||
self.password = password
|
self.password = password
|
||||||
self.database = database
|
self.database = database
|
||||||
self.name = name
|
|
||||||
|
|
||||||
class DatabaseTypeSqLite(DatabaseTypeBase):
|
class DatabaseTypeSqLite(DatabaseTypeBase):
|
||||||
Type = 'sqlite'
|
Type = 'sqlite'
|
||||||
def __init__(self, host='', file='', name=''):
|
@classmethod
|
||||||
self.file = file
|
def display_name(klass):
|
||||||
|
return 'SqLite'
|
||||||
|
def __init__(self, name='', host='', file='', database='fpdb'):
|
||||||
self.name = name
|
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):
|
#TODO: derrive from gtk.VBox?
|
||||||
#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):
|
class WidgetDatabaseProperties(gtk.VBox):
|
||||||
ModeEdit = 0x1
|
|
||||||
ModeAdd = 0x2
|
ModeNew = 0
|
||||||
ModeNew = 0x4
|
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):
|
class FieldWidget(object):
|
||||||
def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''):
|
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):
|
def reset_value(self):
|
||||||
getattr(self._widget, self._attrSet)(self._defaultValue)
|
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)
|
gtk.VBox.__init__(self)
|
||||||
|
|
||||||
self.flags = flags
|
self.databaseManager = databaseManager
|
||||||
self.fieldWidgets = ( #fieldName--> fieldHandler
|
self.database = database
|
||||||
|
self.mode = mode
|
||||||
|
self.parentWidget = parentWidget
|
||||||
|
self.fieldWidgets = (
|
||||||
self.FieldWidget(
|
self.FieldWidget(
|
||||||
text='Name:',
|
text='Name:',
|
||||||
attrDatabase='name',
|
attrDatabase='name',
|
||||||
|
@ -165,57 +210,7 @@ class WidgetDatabaseProperties(gtk.VBox):
|
||||||
attrGet='get_text',
|
attrGet='get_text',
|
||||||
attrSet='set_text',
|
attrSet='set_text',
|
||||||
canEdit=True,
|
canEdit=True,
|
||||||
tooltip=''
|
tooltip='Any name you like to name the database '
|
||||||
),
|
|
||||||
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(
|
self.FieldWidget(
|
||||||
text='Db:',
|
text='Db:',
|
||||||
|
@ -225,7 +220,57 @@ class WidgetDatabaseProperties(gtk.VBox):
|
||||||
attrGet='get_text',
|
attrGet='get_text',
|
||||||
attrSet='set_text',
|
attrSet='set_text',
|
||||||
canEdit=False,
|
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,11 +281,19 @@ class WidgetDatabaseProperties(gtk.VBox):
|
||||||
cell = gtk.CellRendererText()
|
cell = gtk.CellRendererText()
|
||||||
self.comboType.pack_start(cell, True)
|
self.comboType.pack_start(cell, True)
|
||||||
self.comboType.add_attribute(cell, 'text', 0)
|
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)
|
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
|
# init and layout field widgets
|
||||||
self.pack_start(self.comboType, False, False, 2)
|
self.pack_start(self.comboType, False, False, 2)
|
||||||
table = gtk.Table(rows=len(self.fieldWidgets) +1, columns=2, homogeneous=False)
|
table = gtk.Table(rows=len(self.fieldWidgets) +1, columns=2, homogeneous=False)
|
||||||
|
@ -250,59 +303,36 @@ class WidgetDatabaseProperties(gtk.VBox):
|
||||||
table.attach(fieldWidget.widget(), 1, 2, i, i+1)
|
table.attach(fieldWidget.widget(), 1, 2, i, i+1)
|
||||||
|
|
||||||
# init widget
|
# init widget
|
||||||
|
self.comboType.set_active(iCurrentDatabase)
|
||||||
|
self._adjust_widgets(self.database)
|
||||||
|
|
||||||
# if a database has been passed user is not allowed to change database type
|
def _adjust_widgets(self, database):
|
||||||
if database is None:
|
for fieldWidget in self.fieldWidgets:
|
||||||
self.comboType.set_button_sensitivity(gtk.SENSITIVITY_ON)
|
isSensitive = fieldWidget.is_sensitive(database)
|
||||||
|
if isSensitive:
|
||||||
|
fieldWidget.value_from_database(database)
|
||||||
else:
|
else:
|
||||||
self.comboType.set_button_sensitivity(gtk.SENSITIVITY_OFF)
|
fieldWidget.reset_value()
|
||||||
|
if self.mode == self.ModeEdit:
|
||||||
|
isSensitive = isSensitive and fieldWidget.can_edit()
|
||||||
|
fieldWidget.set_sensitive(isSensitive)
|
||||||
|
|
||||||
# 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):
|
def on_combo_type_changed(self, combo):
|
||||||
i = self.comboType.get_active()
|
i = self.comboType.get_active()
|
||||||
if i > -1:
|
if i < 0:
|
||||||
# change database if necessary
|
return
|
||||||
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):
|
# check if we need to init a new database
|
||||||
self.database = database
|
currentDatabaseType = self.comboType.get_model()[i][1]
|
||||||
|
if currentDatabaseType == self.database.Type:
|
||||||
|
return
|
||||||
|
|
||||||
# adjust database type combo if necessary
|
# create new empty database
|
||||||
i = self.comboType.get_active()
|
#NOTE: we dont register it in DatabaseManager
|
||||||
if i == -1:
|
self.database = self.databaseManager.DatabaseTypes[currentDatabaseType]()
|
||||||
currentDatabaseType = None
|
self._adjust_widgets(self.database)
|
||||||
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):
|
def get_database(self):
|
||||||
for fieldWidget in self.fieldWidgets:
|
for fieldWidget in self.fieldWidgets:
|
||||||
|
@ -312,16 +342,7 @@ class WidgetDatabaseProperties(gtk.VBox):
|
||||||
|
|
||||||
|
|
||||||
class DialogDatabaseProperties(gtk.Dialog):
|
class DialogDatabaseProperties(gtk.Dialog):
|
||||||
def __init__(self, databaseManager, database=None,parent=None, flags=WidgetDatabaseProperties.ModeEdit):
|
def __init__(self, databaseManager, database, parent=None, mode=WidgetDatabaseProperties.ModeEdit, title=''):
|
||||||
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,
|
gtk.Dialog.__init__(self,
|
||||||
title=title,
|
title=title,
|
||||||
parent=parent,
|
parent=parent,
|
||||||
|
@ -334,13 +355,12 @@ class DialogDatabaseProperties(gtk.Dialog):
|
||||||
self.connect('response', self.on_dialog_response)
|
self.connect('response', self.on_dialog_response)
|
||||||
|
|
||||||
# setup widget
|
# setup widget
|
||||||
self.flags = flags
|
self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database, mode=mode, parentWidget=self)
|
||||||
self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database=database, flags=self.flags)
|
|
||||||
self.vbox.pack_start(self.widgetDatabaseProperties, True, True)
|
self.vbox.pack_start(self.widgetDatabaseProperties, True, True)
|
||||||
self.widgetDatabaseProperties.show_all()
|
self.show_all()
|
||||||
|
|
||||||
def get_database(self):
|
def get_widget_database_properties(self):
|
||||||
return self.widgetDatabaseProperties.get_database()
|
return self.widgetDatabaseProperties
|
||||||
|
|
||||||
def on_dialog_response(self, dlg, responseId):
|
def on_dialog_response(self, dlg, responseId):
|
||||||
if responseId == gtk.RESPONSE_REJECT:
|
if responseId == gtk.RESPONSE_REJECT:
|
||||||
|
@ -349,20 +369,14 @@ class DialogDatabaseProperties(gtk.Dialog):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
#TODO: just boilerplate code
|
#TODO: derrive from gtk.VBox?
|
||||||
class DialogDatabase(gtk.Dialog):
|
# ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete
|
||||||
def __init__(self, databaseManager, parent=None):
|
class WidgetDatabaseManager(gtk.VBox):
|
||||||
gtk.Dialog.__init__(self,
|
def __init__(self, databaseManager, parentWidget=None):
|
||||||
title="My dialog",
|
gtk.VBox.__init__(self)
|
||||||
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
|
self.databaseManager = databaseManager
|
||||||
|
self.parentWidget = parentWidget
|
||||||
|
|
||||||
#TODO: dono how to make word wrap work as expected
|
#TODO: dono how to make word wrap work as expected
|
||||||
self.labelInfo = gtk.Label('database management')
|
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_tooltip_text('removes the database from the list and deletes it')
|
||||||
self.buttonDatabaseDelete.set_sensitive(False)
|
self.buttonDatabaseDelete.set_sensitive(False)
|
||||||
|
|
||||||
# database tree
|
# init database tree
|
||||||
self.treeDatabases = gtk.TreeView()
|
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)
|
self.treeDatabases.set_model(store)
|
||||||
columns = ('Name', 'Status', 'Type')
|
columns = ('Name', 'Status', 'Type', '_id')
|
||||||
for i, column in enumerate(columns):
|
for i, column in enumerate(columns):
|
||||||
col = gtk.TreeViewColumn(column, gtk.CellRendererText(), text=i)
|
col = gtk.TreeViewColumn(column, gtk.CellRendererText(), text=i)
|
||||||
self.treeDatabases.append_column(col)
|
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)
|
self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed)
|
||||||
|
|
||||||
# layout widgets
|
# layout widgets
|
||||||
self.vbox.pack_start(self.labelInfo, False, False, 2)
|
vbox = gtk.VBox(self)
|
||||||
self.vbox.pack_start(gtk.HSeparator(), False, False, 2)
|
vbox.pack_start(self.labelInfo, False, False, 2)
|
||||||
|
vbox.pack_start(gtk.HSeparator(), False, False, 2)
|
||||||
hbox = gtk.HBox()
|
hbox = gtk.HBox()
|
||||||
self.vbox.add(hbox)
|
self.add(hbox)
|
||||||
hbox.set_homogeneous(False)
|
hbox.set_homogeneous(False)
|
||||||
vbox = gtk.VBox()
|
vbox = gtk.VBox()
|
||||||
hbox.pack_start(vbox, False, False, 2)
|
hbox.pack_start(vbox, False, False, 2)
|
||||||
|
@ -426,28 +451,66 @@ class DialogDatabase(gtk.Dialog):
|
||||||
|
|
||||||
self.show_all()
|
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
|
#TODO: for some reason i have to click OK/Cancel twice to close the dialog
|
||||||
def on_button_database_new_clicked(self, button):
|
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:
|
if dlg.run() == gtk.RESPONSE_REJECT:
|
||||||
pass
|
pass
|
||||||
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
||||||
database = dlg.get_database()
|
database = dlg.get_widget_database_properties().get_database()
|
||||||
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type) )
|
#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()
|
dlg.destroy()
|
||||||
|
|
||||||
def on_button_database_add_clicked(self, button):
|
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:
|
if dlg.run() == gtk.RESPONSE_REJECT:
|
||||||
pass
|
pass
|
||||||
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
||||||
database = dlg.get_database()
|
database = dlg.get_widget_database_properties().get_database()
|
||||||
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type) )
|
#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()
|
dlg.destroy()
|
||||||
|
|
||||||
def on_button_database_edit_clicked(self, button):
|
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:
|
if dlg.run() == gtk.RESPONSE_REJECT:
|
||||||
pass
|
pass
|
||||||
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
||||||
|
@ -467,16 +530,31 @@ class DialogDatabase(gtk.Dialog):
|
||||||
self.buttonDatabaseDelete.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__':
|
if __name__ == '__main__':
|
||||||
|
databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite)
|
||||||
|
|
||||||
#d = DialogDatabaseProperties(
|
#d = DialogDatabaseProperties(
|
||||||
# DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite),
|
# DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite),
|
||||||
#database=DatabaseTypePostgres(),
|
#database=DatabaseTypePostgres(),
|
||||||
# database=None,
|
# database=None,
|
||||||
# )
|
# )
|
||||||
d = DialogDatabase(DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite))
|
d = DialogDatabaseManager(databaseManager)
|
||||||
d.connect("destroy", gtk.main_quit)
|
d.connect("destroy", gtk.main_quit)
|
||||||
d.run()
|
d.run()
|
||||||
#gtk.main()
|
#gtk.main()
|
||||||
|
|
|
@ -32,12 +32,11 @@ try:
|
||||||
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
|
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
|
||||||
from numpy import arange, cumsum
|
from numpy import arange, cumsum
|
||||||
from pylab import *
|
from pylab import *
|
||||||
except ImportError as inst:
|
except ImportError:
|
||||||
print """Failed to load libs for graphing, graphing will not function. Please in
|
print """Failed to load libs for graphing, graphing will not function. Please in
|
||||||
stall numpy and matplotlib if you want to use graphs."""
|
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
|
print """This is of no consequence for other parts of the program, e.g. import
|
||||||
and HUD are NOT affected by this problem."""
|
and HUD are NOT affected by this problem."""
|
||||||
print "ImportError: %s" % inst.args
|
|
||||||
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import Database
|
import Database
|
||||||
|
|
|
@ -37,10 +37,11 @@ try:
|
||||||
# from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
|
# from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
|
||||||
# DayLocator, MONDAY, timezone
|
# 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 """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 """This is of no consequence as the module currently doesn't do anything."""
|
||||||
print "ImportError: %s" % inst.args
|
|
||||||
|
|
||||||
import Card
|
import Card
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
|
|
|
@ -566,6 +566,7 @@ Left-Drag to Move"
|
||||||
<hhc site="Absolute" converter="AbsoluteToFpdb"/>
|
<hhc site="Absolute" converter="AbsoluteToFpdb"/>
|
||||||
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
|
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
|
||||||
<hhc site="Betfair" converter="BetfairToFpdb"/>
|
<hhc site="Betfair" converter="BetfairToFpdb"/>
|
||||||
|
<hhc site="Partouche" converter="PartoucheToFpdb"/>
|
||||||
</hhcs>
|
</hhcs>
|
||||||
|
|
||||||
<supported_databases>
|
<supported_databases>
|
||||||
|
|
|
@ -189,99 +189,95 @@ class HUD_main(object):
|
||||||
# be passed to HUDs for use in the gui thread. HUD objects should not
|
# 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
|
# need their own access to the database, but should open their own
|
||||||
# if it is required.
|
# if it is required.
|
||||||
try:
|
self.db_connection = Database.Database(self.config)
|
||||||
self.db_connection = Database.Database(self.config)
|
tourny_finder = re.compile('(\d+) (\d+)')
|
||||||
tourny_finder = re.compile('(\d+) (\d+)')
|
|
||||||
|
|
||||||
# get hero's screen names and player ids
|
# get hero's screen names and player ids
|
||||||
self.hero, self.hero_ids = {}, {}
|
self.hero, self.hero_ids = {}, {}
|
||||||
for site in self.config.get_supported_sites():
|
for site in self.config.get_supported_sites():
|
||||||
result = self.db_connection.get_site_id(site)
|
result = self.db_connection.get_site_id(site)
|
||||||
if result:
|
if result:
|
||||||
site_id = result[0][0]
|
site_id = result[0][0]
|
||||||
self.hero[site_id] = self.config.supported_sites[site].screen_name
|
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.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
|
while 1: # wait for a new hand number on stdin
|
||||||
new_hand_id = sys.stdin.readline()
|
new_hand_id = sys.stdin.readline()
|
||||||
new_hand_id = string.rstrip(new_hand_id)
|
new_hand_id = string.rstrip(new_hand_id)
|
||||||
if new_hand_id == "": # blank line means quit
|
if new_hand_id == "": # blank line means quit
|
||||||
self.destroy()
|
self.destroy()
|
||||||
break # this thread is not always killed immediately with gtk.main_quit()
|
break # this thread is not always killed immediately with gtk.main_quit()
|
||||||
# get basic info about the new hand from the db
|
# get basic info about the new hand from the db
|
||||||
# if there is a db error, complain, skip hand, and proceed
|
# if there is a db error, complain, skip hand, and proceed
|
||||||
try:
|
try:
|
||||||
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
|
(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)
|
cards = self.db_connection.get_cards(new_hand_id)
|
||||||
comm_cards = self.db_connection.get_common_cards(new_hand_id)
|
comm_cards = self.db_connection.get_common_cards(new_hand_id)
|
||||||
if comm_cards != {}: # stud!
|
if comm_cards != {}: # stud!
|
||||||
cards['common'] = comm_cards['common']
|
cards['common'] = comm_cards['common']
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
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])
|
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
|
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)))
|
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
|
continue
|
||||||
|
|
||||||
if type == "tour": # hand is from a tournament
|
else:
|
||||||
mat_obj = tourny_finder.search(table_name)
|
temp_key = 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
|
|
||||||
|
|
||||||
# Update an existing HUD
|
# Update an existing HUD
|
||||||
if temp_key in self.hud_dict:
|
if temp_key in self.hud_dict:
|
||||||
try:
|
try:
|
||||||
# get stats using hud's specific params
|
# get stats using hud's specific params
|
||||||
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
|
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'])
|
, 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])
|
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:
|
except:
|
||||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
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])
|
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
|
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)))
|
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
|
||||||
continue
|
continue
|
||||||
self.hud_dict[temp_key].stat_dict = stat_dict
|
self.hud_dict[temp_key].stat_dict = stat_dict
|
||||||
self.hud_dict[temp_key].cards = cards
|
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]
|
[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)
|
self.update_HUD(new_hand_id, temp_key, self.config)
|
||||||
|
|
||||||
# Or create a new HUD
|
# 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:
|
else:
|
||||||
try:
|
tablewindow = Tables.discover_table_by_name(self.config, table_name)
|
||||||
# get stats using default params
|
if tablewindow == None:
|
||||||
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:
|
|
||||||
# If no client window is found on the screen, complain and continue
|
# If no client window is found on the screen, complain and continue
|
||||||
if type == "tour":
|
if type == "tour":
|
||||||
table_name = "%s %s" % (tour_number, tab_number)
|
table_name = "%s %s" % (tour_number, tab_number)
|
||||||
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
|
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
|
||||||
else:
|
else:
|
||||||
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
|
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
|
||||||
self.db_connection.connection.rollback()
|
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 __name__== "__main__":
|
if __name__== "__main__":
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,8 @@ def discover_nt_by_name(c, tablename):
|
||||||
try:
|
try:
|
||||||
# maybe it's better to make global titles[hwnd] decoding?
|
# 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
|
# 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:
|
except:
|
||||||
continue
|
continue
|
||||||
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
|
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 '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?
|
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)
|
temp = decode_windows(c, titles[hwnd], hwnd)
|
||||||
#print "attach to window", temp
|
print "attach to window", temp
|
||||||
return decode_windows(c, titles[hwnd], hwnd)
|
return temp
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def discover_nt_tournament(c, tour_number, tab_number):
|
def discover_nt_tournament(c, tour_number, tab_number):
|
||||||
|
@ -257,9 +258,12 @@ def discover_nt_tournament(c, tour_number, tab_number):
|
||||||
titles ={}
|
titles ={}
|
||||||
win32gui.EnumWindows(win_enum_handler, titles)
|
win32gui.EnumWindows(win_enum_handler, titles)
|
||||||
for hwnd in titles:
|
for hwnd in titles:
|
||||||
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
|
# 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 'Chat:' in titles[hwnd]: continue
|
||||||
if 'HUD:' in titles[hwnd]: continue # FPDB HUD window
|
# 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]):
|
if re.search(search_string, titles[hwnd]):
|
||||||
return decode_windows(c, titles[hwnd], hwnd)
|
return decode_windows(c, titles[hwnd], hwnd)
|
||||||
|
@ -268,21 +272,33 @@ def discover_nt_tournament(c, tour_number, tab_number):
|
||||||
def get_nt_exe(hwnd):
|
def get_nt_exe(hwnd):
|
||||||
"""Finds the name of the executable that the given window handle belongs to."""
|
"""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
|
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"
|
# enable "debug process"
|
||||||
privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME)
|
privilege_id = win32security.LookupPrivilegeValue(None,
|
||||||
old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)])
|
win32security.SE_DEBUG_NAME)
|
||||||
|
old_privs = win32security.AdjustTokenPrivileges(hToken, 0,
|
||||||
|
[(privilege_id,
|
||||||
|
win32security.SE_PRIVILEGE_ENABLED)])
|
||||||
|
|
||||||
# Open the process, and query it's filename
|
# Open the process, and query it's filename
|
||||||
processid = win32process.GetWindowThreadProcessId(hwnd)
|
processid = win32process.GetWindowThreadProcessId(hwnd)
|
||||||
pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1])
|
pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION |
|
||||||
exename = win32process.GetModuleFileNameEx(pshandle, 0)
|
win32con.PROCESS_VM_READ, False,
|
||||||
|
processid[1])
|
||||||
# clean up
|
try:
|
||||||
win32api.CloseHandle(pshandle)
|
exename = win32process.GetModuleFileNameEx(pshandle, 0)
|
||||||
win32api.CloseHandle(hToken)
|
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
|
return exename
|
||||||
|
|
||||||
|
@ -305,6 +321,8 @@ def decode_windows(c, title, hwnd):
|
||||||
info['width'] = int( width ) - 2*b_width
|
info['width'] = int( width ) - 2*b_width
|
||||||
info['height'] = int( height ) - b_width - tb_height
|
info['height'] = int( height ) - b_width - tb_height
|
||||||
info['exe'] = get_nt_exe(hwnd)
|
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'])
|
title_bits = re.split(' - ', info['title'])
|
||||||
info['name'] = title_bits[0]
|
info['name'] = title_bits[0]
|
||||||
|
|
|
@ -78,7 +78,7 @@ class fpdb_db:
|
||||||
if use_pool:
|
if use_pool:
|
||||||
MySQLdb = pool.manage(MySQLdb, pool_size=5)
|
MySQLdb = pool.manage(MySQLdb, pool_size=5)
|
||||||
# try:
|
# 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
|
#TODO: Add port option
|
||||||
# except:
|
# except:
|
||||||
# raise FpdbMySQLFailedError("MySQL connection failed")
|
# raise FpdbMySQLFailedError("MySQL connection failed")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user