From 91e7bba27adccc2d9815afed104b678366ecb62a Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Fri, 8 May 2009 22:38:50 +0200 Subject: gui redesign in glade, database layout 0.3 complete redesign of the gui with glade-3 gui loading with gtk.glade.XML move to db layout 0.3 with completed column --- item.py | 15 +- storage/sqlite.py | 26 ++-- ui/todolist.glade | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui/ui_pygtk.py | 187 ++++++++++------------- 4 files changed, 559 insertions(+), 117 deletions(-) create mode 100644 ui/todolist.glade diff --git a/item.py b/item.py index b15fb8e..d1d8427 100644 --- a/item.py +++ b/item.py @@ -3,16 +3,20 @@ class item: readOnly = ['id'] - def __init__(self, title=None, created=None, priority=None, description=None, row=None): - if row == None: + def __init__(self, title=None, created=None, priority=None, description=None, completed=None, row=None): + if title != None: self.__dict__['id'] = -1 self.title = title self.created = created self.priority = priority self.description = description + self.completed = completed else: - self.__init__(row[1], row[2], row[3], row[4]) - self.__dict__['id'] = row[0] + id = row[0] + + row.__delitem__(0) + apply(self.__init__, row) + self.__dict__['id'] = id def setId(self, id): if self.id == -1: @@ -33,6 +37,9 @@ class item: def getDescription(self): return self.description + def getCompleted(self): + return self.completed + def __setattr__(self, name, value): if name not in item.readOnly: if name not in self.__dict__ or self.__dict__[name] != value: diff --git a/storage/sqlite.py b/storage/sqlite.py index 09e55fc..bfdae42 100644 --- a/storage/sqlite.py +++ b/storage/sqlite.py @@ -6,7 +6,7 @@ from item import item from pysqlite2 import dbapi2 as sqliteBackend class sqlite(storageBase): - dbVersion = '0.2' + dbVersion = '0.3' def __init__(self): self.con = sqliteBackend.connect(self.getConfigDir() + '/data.sqlite') @@ -48,14 +48,20 @@ class sqlite(storageBase): self.con.commit() def update_db(self, updateFrom): - print 'updating todo table...' - if updateFrom == '0.1': + print 'updating todo table from %s...' % updateFrom + if updateFrom == ('0.1',): self.cur.execute('''alter table todo add desc BLOB''') self.con.commit() - updateFrom = '0.2' + updateFrom = ('0.2',) - self.cur.execute("update control set value = ? where setting = 'db-version'", (sqlite.dbVersion,)) + if updateFrom == ('0.2',): + self.cur.execute('''alter table todo + add completed INTEGER(1) DEFAULT (0)''') + self.con.commit() + updateFrom = ('0.3',) + + self.cur.execute("update control set value = ? where setting = 'db-version'", updateFrom) self.con.commit() def __del__(self): @@ -65,17 +71,17 @@ class sqlite(storageBase): items = itemList(self) todos = self.cur.execute('select * from todo').fetchall() for todo in todos: - items += item(row=todo) + items += item(row=list(todo)) return items def notifyChange(self, sender): if sender.getId() >= 0: - self.cur.execute('update todo set title=?, createdAt=?, priority=?, desc=? where id=?', - (sender.getTitle(), sender.getCreatedAt(), sender.getPriority(), sender.getId(), sender.getDescription())) + self.cur.execute('update todo set title=?, createdAt=?, priority=?, desc=?, completed=? where id=?', + (sender.getTitle(), sender.getCreatedAt(), sender.getPriority(), sender.getDescription(), sender.getCompleted(), sender.getId())) self.con.commit() else: - self.cur.execute('insert into todo (title, createdAt, priority, desc) VALUES (?, ?, ?, ?)', - (sender.getTitle(), sender.getCreatedAt(), sender.getPriority(), sender.getDescription())) + self.cur.execute('insert into todo (title, createdAt, priority, desc, completed) VALUES (?, ?, ?, ?, ?)', + (sender.getTitle(), sender.getCreatedAt(), sender.getPriority(), sender.getDescription(), sender.getCompleted())) self.con.commit() sender.setId(self.cur.execute('select last_insert_rowid()').fetchone()[0]) diff --git a/ui/todolist.glade b/ui/todolist.glade new file mode 100644 index 0000000..1b1a732 --- /dev/null +++ b/ui/todolist.glade @@ -0,0 +1,448 @@ + + + + + + ToDo + + + + True + + + True + + + True + _File + True + + + True + + + True + gtk-quit + True + True + + + + + + + + + + True + _Edit + True + + + True + + + True + gtk-cut + True + True + + + + + True + gtk-copy + True + True + + + + + True + gtk-paste + True + True + + + + + True + gtk-delete + True + True + + + + + + + + + True + _View + True + + + + + True + _Help + True + + + True + + + True + gtk-about + True + True + + + + + + + + + + False + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + + + True + True + True + + + + + + 1 + + + + + True + 7 + GTK_BUTTONBOX_SPREAD + + + True + True + True + gtk-add + True + 0 + + + + + True + True + True + gtk-remove + True + 0 + + + 1 + + + + + True + True + True + gtk-edit + True + 0 + + + + 2 + + + + + False + 7 + 2 + + + + + True + 2 + + + False + 3 + + + + + + + 5 + False + True + GTK_WIN_POS_CENTER_ON_PARENT + GDK_WINDOW_TYPE_HINT_DIALOG + + + True + 2 + + + True + True + 2009 + 4 + 5 + + + False + False + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-cancel + True + 1 + + + + + True + True + True + gtk-ok + True + 0 + + + 1 + + + + + False + GTK_PACK_END + + + + + + + 5 + Edit + GTK_WIN_POS_CENTER_ON_PARENT + GDK_WINDOW_TYPE_HINT_DIALOG + + + True + 2 + + + True + 4 + 2 + 7 + 7 + + + True + + + True + True + + + + + True + True + True + Select... + 0 + + + False + False + 1 + + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + 0 + 0 + Due: + + + 2 + 3 + GTK_FILL + + + + + + True + + + + True + True + + + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + + + True + True + + + + + 1 + 2 + 3 + 4 + + + + + True + True + + + 1 + 2 + + + + + + True + 0 + 0 + Description: + + + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + 0 + 0 + Priority: + + + 1 + 2 + GTK_FILL + + + + + + True + 0 + 0 + Title: + + + GTK_FILL + + + + + + 7 + 1 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-cancel + True + 0 + + + + + True + True + True + gtk-ok + True + 1 + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/ui/ui_pygtk.py b/ui/ui_pygtk.py index ad16173..d41d34d 100644 --- a/ui/ui_pygtk.py +++ b/ui/ui_pygtk.py @@ -4,67 +4,57 @@ import pygtk pygtk.require('2.0') import gtk +import gtk.glade import gobject import item -from license import version, gpl_3 import time +from license import version, gpl_3 class ui_pygtk: def __init__(self, itemList): self.itemList = itemList - # create ui - # main window - self.main_window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.main_window.connect('destroy', self.destroy_callback) - - self.main_window.set_title('ToDo') - self.main_window.set_size_request(10, 10) - self.main_window.resize(100, 100) - self.main_window.move(10, 10) - - # todolist scroll window - todo_scroll = gtk.ScrolledWindow() - todo_scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - + # load ui from glade file + glade = gtk.glade.XML ("todolist.glade") + self.main_window = glade.get_widget('main_window') + + self.edit_dialog = glade.get_widget('edit_dialog') + self.edit_dialog.title_field = glade.get_widget('title_field') + self.edit_dialog.priority_field = glade.get_widget('priority_field') + self.edit_dialog.desc_field = glade.get_widget('description_field') + self.main_window.todolist = glade.get_widget('todolist') + + # connect the defined signales + dic = {"on_menu_about_clicked" : self.about_clicked_callback, + "on_menu_quit_clicked" : gtk.main_quit, + "on_main_window_destroy" : gtk.main_quit, + "on_treeview_row_activated" : self.item_double_clicked_callback, + "on_edit_clicked" : self.edit_clicked_callback} + glade.signal_autoconnect(dic) + + # fill the treeview with data liststore = gtk.ListStore(object) for items in self.itemList: liststore.append([items]) - todolist = gtk.TreeView(liststore) - - for i, column in enumerate ([['Id', 'getId'], - ['ToDo', 'getTitle'], - ['...', 'getDescription'], - ['Erstellt am', ['getCreatedAt', - (lambda x: time.strftime('%d.%m.%Y %H:%M:%S', time.localtime(x)))]] - ]): - todolist.append_column(self.create_column(i, column[0], column[1], liststore)) - - todo_scroll.add(todolist) + self.main_window.todolist.set_model(liststore) + self.main_window.todolist.append_column(self.create_column(0, 'Finished', 'getCompleted', liststore, gtk.CellRendererToggle())) + for column in ([['Id', 'getId'], + ['ToDo', 'getTitle'], + ['...', 'getDescription'], + ['Erstellt am', ['getCreatedAt', + (lambda x: time.strftime('%d.%m.%Y %H:%M:%S', time.localtime(x)))]] + ]): + self.main_window.todolist.append_column(self.create_column(len(self.main_window.todolist.get_columns())+1, column[0], column[1], liststore)) - # statusbar - statusbar = gtk.Statusbar() - - # join elemnts - # main content box - main_content_box = gtk.VBox(False, 1) - main_content_box.pack_start(self.get_main_menu(), False, True, 0) - main_content_box.pack_start(todo_scroll, True, True, 0) - main_content_box.pack_start(statusbar, False, False, 0) - - self.main_window.add(main_content_box) - # start ui self.main_window.show_all() gtk.main() return - ######################################################### - # create gui - ######################################################### - def create_column(self, id, title, data, treemodel, cellRenderer=gtk.CellRendererText()): + # abstract mmethod to create a column for the data + # from the item objects in the treeview column = gtk.TreeViewColumn(title, cellRenderer) column.set_cell_data_func(cellRenderer, self.item_data_callback, data) @@ -78,64 +68,12 @@ class ui_pygtk: [iter1, iter2])))) return column - def get_main_menu(self): - if 'mainmenu' not in self.__dict__: - quit_action = gtk.Action('Quit', '_Quit', 'Exit Todolist', gtk.STOCK_QUIT) - quit_action.connect('activate', self.destroy_callback) - - settings_action = gtk.Action('Settings', '_Settings', 'Settings', gtk.STOCK_PREFERENCES) - settings_action.set_property('sensitive', False) - #settings_action.connect('activate', self.show_settings) - - #delete_action = gtk.Action('Delete', '_Delete', 'Delete a post', - # gtk.STOCK_DELETE) - #delete_action.connect('activate', self.delete_tweet) - - about_action = gtk.Action('About', '_About', 'About Todolist', gtk.STOCK_ABOUT) - about_action.connect('activate', self.about_click_callback) - - file_action = gtk.Action('File', '_File', 'File', None) - edit_action = gtk.Action('Edit', '_Edit', 'Edit', None) - help_action = gtk.Action('Help', '_Help', 'Help', None) - - action_group = gtk.ActionGroup('MainMenu') - action_group.add_action_with_accel(quit_action, None) # None = default - action_group.add_action(settings_action) - action_group.add_action(file_action) - action_group.add_action(edit_action) - action_group.add_action(help_action) - action_group.add_action(about_action) - - # definition of the UI - uimanager = gtk.UIManager() - uimanager.insert_action_group(action_group, 0) - uimanager.add_ui_from_string(''' - - - - - - - - - - - - - - - ''') - - self.main_window.add_accel_group(uimanager.get_accel_group()) - self.main_menu = uimanager.get_widget('/MainMenu') - - return self.main_menu - ######################################################### # callbacks ######################################################### def item_data_callback(self, column, cell, model, iter, userdata=None): + # method to get the data from the item object for one column data='' if (userdata == None): # try to convert the object to string @@ -151,18 +89,15 @@ class ui_pygtk: data = getattr(model.get_value(iter, 0), userdata)() # set the data as cell content - if cell is not None: + if isinstance(cell, gtk.CellRendererText) : cell.set_property('text', data) + elif isinstance(cell, gtk.CellRendererToggle) : + cell.set_property('active', data) else: return data - def destroy_callback(self, widget, data=None): - gtk.main_quit() - return - - def about_click_callback(self, widget, data=None): - """Show the about dialog.""" - + def about_clicked_callback(self, widget, data=None): + # show the about dialog about_window = gtk.AboutDialog() about_window.set_name('Todolist') about_window.set_version(version) @@ -172,3 +107,49 @@ class ui_pygtk: about_window.run() about_window.hide() return + + def edit_clicked_callback(self, widget, data=None): + # edit btn click + treeview = self.main_window.todolist + if (treeview.get_selection().count_selected_rows() == 1): + item = treeview.get_model().get_value(treeview.get_selection().get_selected()[1], 0) + + if self.edit_item(item): + sort = list(treeview.get_model().get_sort_column_id()) + treeview.get_model().set_sort_column_id(0, gtk.SORT_ASCENDING) + apply( treeview.get_model(), sort) + + def item_double_clicked_callback(self, treeview, path, view_column, user_data=None): + # dbl click on treeview row to edit item + model = treeview.get_model() + item = model.get_value(model.get_iter(path), 0) + + if self.edit_item(item): + sort = list(model.get_sort_column_id()) + model.set_sort_column_id(0, gtk.SORT_ASCENDING) + apply(model.set_sort_column_id, sort) + return + + ######################################################### + # helper methods + ######################################################### + + def edit_item(self, item): + # helper method to edit item + self.edit_dialog.title_field.set_text(item.getTitle()) + self.edit_dialog.priority_field.set_text(item.getPriority().__str__()) + + text_buffer = gtk.TextBuffer() + if item.getDescription() != None: + text_buffer.set_text(item.getDescription()) + self.edit_dialog.desc_field.set_buffer(text_buffer) + + successfull = self.edit_dialog.run() + self.edit_dialog.hide() + + if (successfull): + item.title = self.edit_dialog.title_field.get_text() + item.priority = self.edit_dialog.priority_field.get_text() + item.description = text_buffer.get_text(text_buffer.get_start_iter(), text_buffer.get_end_iter()) + + return successfull -- cgit v1.2.3