millions of changes, highlights:

- started validating user input on create/add database
- implemented fuctionality to create sqlite databases
- never worked with sqlite,, you can not create multiple dbs in one file, so removed db attr again
- a nice todo list

Signed-off-by: fpdb-mme <jUrner@arcor.de>
This commit is contained in:
fpdb-mme 2009-11-01 07:36:18 +01:00
parent 2ae58f8947
commit bcbafc160d

View File

@ -1,3 +1,18 @@
"""Database manager
@todo: (gtk) how to validate user input in gtk.Dialog? as soon as the user clicks ok the dialog is dead. we use a while loop as workaround. not nice
@todo: (fpdb) we need the application name 'fpdb' from somewhere to put it in dialog titles
@todo: (all dialogs) save/restore size and pos
@todo: (WidgetDatabaseManager) give database status meaningful colors
@todo: (WidgetDatabaseManager) implement database purging
@todo: (WidgetDatabaseManager) implement database export
@todo: (WidgetDatabaseManager) what to do on database doubleclick?
@todo: (WidgetDatabaseManager) context menu for database tree
@todo: (WidgetDatabaseManager) initializing/validating databases may take a while. how to give feedback?
"""
import os import os
import pygtk import pygtk
@ -48,8 +63,7 @@ class DatabaseManager(gobject.GObject):
self._databases.append(database) self._databases.append(database)
def remove_database(self, database): def remove_database(self, database):
self._databases.remove(database) self._databases.remove(database)
def init_database(self, database):
pass
def activate_database(self, database): def activate_database(self, database):
if self._activeDatabase is not None: if self._activeDatabase is not None:
self._activeDatabase.status = self._activeDatabase.StatusInactive self._activeDatabase.status = self._activeDatabase.StatusInactive
@ -68,7 +82,7 @@ class DatabaseManager(gobject.GObject):
gobject.type_register(DatabaseManager) gobject.type_register(DatabaseManager)
gobject.signal_new('database-activated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, )) gobject.signal_new('database-activated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
gobject.signal_new('database-deactivated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, )) gobject.signal_new('database-deactivated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
gobject.signal_new('database-error', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
class DatabaseTypeMeta(type): class DatabaseTypeMeta(type):
def __new__(klass, name, bases, kws): def __new__(klass, name, bases, kws):
@ -86,6 +100,19 @@ class DatabaseTypeBase(object):
StatusInactive = 'inactive' StatusInactive = 'inactive'
StatusError = 'error' #TODO: not implemented StatusError = 'error' #TODO: not implemented
#TODO: not happy with returning error string. just being too lazy to impl dozens of error codes for later translation
def init_new_database(self):
"""initializes a new empty database
@return: (str) error if something goes wrong, None otherwise
"""
raise NotImplementedError()
def validate_database(self):
"""checks if the database is valid
@return: (str) error if something goes wrong, None otherwise
"""
raise NotImplementedError()
class DatabaseTypePostgres(DatabaseTypeBase): class DatabaseTypePostgres(DatabaseTypeBase):
Type = 'postgres' Type = 'postgres'
@classmethod @classmethod
@ -100,6 +127,14 @@ class DatabaseTypePostgres(DatabaseTypeBase):
self.database = database self.database = database
self.status = self.StatusInactive self.status = self.StatusInactive
#TODO: implement
def init_new_database(self):
pass
#TODO: implement
def validate_database(self):
pass
class DatabaseTypeMysql(DatabaseTypeBase): class DatabaseTypeMysql(DatabaseTypeBase):
Type = 'mysql' Type = 'mysql'
@classmethod @classmethod
@ -114,6 +149,15 @@ class DatabaseTypeMysql(DatabaseTypeBase):
self.database = database self.database = database
self.status = self.StatusInactive self.status = self.StatusInactive
#TODO: implement
def init_new_database(self):
pass
#TODO: implement
def validate_database(self):
pass
class DatabaseTypeSqLite(DatabaseTypeBase): class DatabaseTypeSqLite(DatabaseTypeBase):
Type = 'sqlite' Type = 'sqlite'
@classmethod @classmethod
@ -122,9 +166,27 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
def __init__(self, name='', host='', file='', database='fpdb'): def __init__(self, name='', host='', file='', database='fpdb'):
self.name = name self.name = name
self.file = file self.file = file
self.database = database
self.status = self.StatusInactive self.status = self.StatusInactive
def init_new_database(self):
# make shure all attrs are specified
if not self.file:
return 'no database file specified'
# create file if necessary (this will truncate file if it exists)
try:
open(self.file, 'w').close()
except IOError:
return 'can not write file'
#TODO: init tables (...)
def validate_database(self):
pass
#TODO: check if tables (...) exist
#TODO: how do we want to handle unsupported database types? #TODO: how do we want to handle unsupported database types?
# ..uncomment to remove unsupported database types # ..uncomment to remove unsupported database types
#try: import psycopg2 #try: import psycopg2
@ -135,6 +197,20 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
#except ImportError: del DatabaseManager.DatabaseTypes['sqlite'] #except ImportError: del DatabaseManager.DatabaseTypes['sqlite']
#*************************************************************************************************************************** #***************************************************************************************************************************
#TODO: there is not title (on linux), wtf?
def DialogError(parent=None, msg=''):
dlg = gtk.MessageDialog(
parent=parent,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
type=gtk.MESSAGE_ERROR,
buttons=gtk.BUTTONS_OK,
message_format=msg,
)
dlg.run()
dlg.destroy()
return None
#TODO: derrive from gtk.VBox? #TODO: derrive from gtk.VBox?
class WidgetDatabaseProperties(gtk.VBox): class WidgetDatabaseProperties(gtk.VBox):
@ -189,7 +265,7 @@ class WidgetDatabaseProperties(gtk.VBox):
dlg.destroy() dlg.destroy()
#TODO: bit ugly this thingy. try to find a better way to map database attrs to gtk widgets
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=''):
""" """
@ -243,16 +319,6 @@ class WidgetDatabaseProperties(gtk.VBox):
canEdit=True, canEdit=True,
tooltip='Any name you like to name the database ' tooltip='Any name you like to name the database '
), ),
self.FieldWidget(
text='Db:',
attrDatabase='database',
widget=gtk.Entry(),
defaultValue='',
attrGet='get_text',
attrSet='set_text',
canEdit=False,
tooltip='Name of the database to create'
),
self.FieldWidget( self.FieldWidget(
text='File:', text='File:',
attrDatabase='file', attrDatabase='file',
@ -303,6 +369,16 @@ class WidgetDatabaseProperties(gtk.VBox):
canEdit=False, canEdit=False,
tooltip='Password used to login to the host' tooltip='Password used to login to the host'
), ),
self.FieldWidget(
text='Db:',
attrDatabase='database',
widget=gtk.Entry(),
defaultValue='',
attrGet='get_text',
attrSet='set_text',
canEdit=False,
tooltip='Name of the database'
),
) )
# setup database type combo # setup database type combo
@ -403,13 +479,16 @@ class DialogDatabaseProperties(gtk.Dialog):
#TODO: derrive from gtk.VBox? #TODO: derrive from gtk.VBox?
# ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete # ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete
class WidgetDatabaseManager(gtk.VBox): class WidgetDatabaseManager(gtk.VBox):
"""
"""
def __init__(self, databaseManager, parentWidget=None): def __init__(self, databaseManager, parentWidget=None):
gtk.VBox.__init__(self) gtk.VBox.__init__(self)
self.parentWidget = parentWidget self.parentWidget = parentWidget
self.databaseManager = databaseManager self.databaseManager = databaseManager
self.databaseManager.connect('database-activated', self.on_database_activated) self.databaseManager.connect('database-activated', self.on_database_manager_database_activated)
self.databaseManager.connect('database-deactivated', self.on_database_deactivated) self.databaseManager.connect('database-deactivated', self.on_database_manager_database_deactivated)
self.databaseStatusNames = { self.databaseStatusNames = {
DatabaseTypeBase.StatusActive: 'Active', DatabaseTypeBase.StatusActive: 'Active',
DatabaseTypeBase.StatusInactive: 'Inactive', DatabaseTypeBase.StatusInactive: 'Inactive',
@ -504,7 +583,7 @@ class WidgetDatabaseManager(gtk.VBox):
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database)) model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
def on_database_activated(self, databaseManager, idDatabase): def on_database_manager_database_activated(self, databaseManager, idDatabase):
database = self.databaseManager.database_from_id(idDatabase) database = self.databaseManager.database_from_id(idDatabase)
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
for row in iter(model): for row in iter(model):
@ -515,7 +594,7 @@ class WidgetDatabaseManager(gtk.VBox):
raise ValueError('database not found') raise ValueError('database not found')
def on_database_deactivated(self, databaseManager, idDatabase): def on_database_manager_database_deactivated(self, databaseManager, idDatabase):
database = self.databaseManager.database_from_id(idDatabase) database = self.databaseManager.database_from_id(idDatabase)
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
for row in iter(model): for row in iter(model):
@ -539,46 +618,80 @@ class WidgetDatabaseManager(gtk.VBox):
#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):
databaseType = self.databaseManager.get_default_database_type() databaseKlass = self.databaseManager.get_default_database_type()
if databaseType is None: if databaseKlass is None:
raise ValueError('no defult database type set') raise ValueError('no default database type set')
dlg = DialogDatabaseProperties( database = databaseKlass()
self.databaseManager,
databaseType(), while True:
parent=self.parentWidget, dlg = DialogDatabaseProperties(
mode=WidgetDatabaseProperties.ModeNew, self.databaseManager,
title='[New database] - database properties' database,
) parent=self.parentWidget,
if dlg.run() == gtk.RESPONSE_REJECT: mode=WidgetDatabaseProperties.ModeNew,
pass title='New database'
if dlg.run() == gtk.RESPONSE_ACCEPT: )
database = dlg.get_widget_database_properties().get_database() response = dlg.run()
#TODO: sanity checks + init databse if necessary if response == gtk.RESPONSE_ACCEPT:
self.databaseManager.add_database(database) database = dlg.get_widget_database_properties().get_database()
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) #TODO: initing may or may not take a while. how to handle?
dlg.destroy() error = database.init_new_database()
if error:
DialogError(parent=dlg, msg=error)
dlg.destroy()
continue
else:
database = None
dlg.destroy()
break
def on_button_database_add_clicked(self, button): if database is None:
databaseType = self.databaseManager.get_default_database_type() return
if databaseType is None:
raise ValueError('no defult database type set') self.databaseManager.add_database(database)
dlg = DialogDatabaseProperties( model = self.treeDatabases.get_model()
self.databaseManager, it = model.append()
databaseType(), model.set_value(it, self.treeDatabaseColumns['name'], database.name)
parent=self.parentWidget, model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
mode=WidgetDatabaseProperties.ModeAdd, model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
title='[Add database] - database properties' model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
)
if dlg.run() == gtk.RESPONSE_REJECT:
pass def on_button_database_add_clicked(self, button):
if dlg.run() == gtk.RESPONSE_ACCEPT: databaseKlass = self.databaseManager.get_default_database_type()
database = dlg.get_widget_database_properties().get_database() if databaseKlass is None:
#TODO: sanity checks raise ValueError('no defult database type set')
database = databaseKlass()
while True:
dlg = DialogDatabaseProperties(
self.databaseManager,
database,
parent=self.parentWidget,
mode=WidgetDatabaseProperties.ModeAdd,
title='Add database'
)
response = dlg.run()
if response == gtk.RESPONSE_ACCEPT:
database = dlg.get_widget_database_properties().get_database()
#TODO: validating may or may not take a while. how to handle?
error = database.validate_database()
if error:
DialogError(parent=self.parentWidget, msg=error)
dlg.destroy()
continue
else:
database = None
dlg.destroy()
break
if database is None:
return
self.databaseManager.add_database(database) self.databaseManager.add_database(database)
model = self.treeDatabases.get_model() model = self.treeDatabases.get_model()
it = model.append() it = model.append()
print database.name
model.set_value(it, self.treeDatabaseColumns['name'], database.name) model.set_value(it, self.treeDatabaseColumns['name'], database.name)
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] ) model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() ) model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
@ -598,11 +711,12 @@ class WidgetDatabaseManager(gtk.VBox):
database, database,
parent=self.parentWidget, parent=self.parentWidget,
mode=WidgetDatabaseProperties.ModeEdit, mode=WidgetDatabaseProperties.ModeEdit,
title='[Edit database] - database properties' title='Edit database'
) )
if dlg.run() == gtk.RESPONSE_REJECT: response = dlg.run()
if response == gtk.RESPONSE_REJECT:
pass pass
if dlg.run() == gtk.RESPONSE_ACCEPT: elif response == gtk.RESPONSE_ACCEPT:
database = dlg.get_database() database = dlg.get_database()
selection = self.treeDatabases.get_selection() selection = self.treeDatabases.get_selection()
if selection is not None: if selection is not None:
@ -634,7 +748,7 @@ class WidgetDatabaseManager(gtk.VBox):
class DialogDatabaseManager(gtk.Dialog): class DialogDatabaseManager(gtk.Dialog):
def __init__(self, databaseManager, parent=None): def __init__(self, databaseManager, parent=None):
gtk.Dialog.__init__(self, gtk.Dialog.__init__(self,
title="My dialog", title="Databases",
parent=parent, parent=parent,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
buttons=( buttons=(