Logo Search packages:      
Sourcecode: jppy version File versions  Download package

base.py

import pygtk
pygtk.require("2.0")
import gtk
import gobject
import gnome.ui
from renderers import PyObjectRenderer, ListItemRenderer
import mx.DateTime
import types
import pyparsing
import ConfigParser
import jppy
import os

class pane:
    def __init__(self, gladefile, wTree):
        self.wTree = wTree
        self.gladefile = gladefile
        self.iter = None

        if not self.model:
            raise NotImplementedError("Model not provided")
        if not self.view:
            raise NotImplementedError("View not provided")            
        if not self.recordCategoryOpenMenu:
            raise NotImplementedError("Record category widget not provided")
        if not self.categoryFilterVBox:
            raise NotImplementedError("Category filter vbox not provided")

        # the listview which shows records
        self.view.set_model(self.model)
        self.view.set_headers_visible(True)
        self.view.get_selection().connect("changed",
                                          self.on_TreeView_selection_changed)
        self.view.show()


        # the right click pop-up menu used to select which columns to view
        self.rightClickColumnMenu = gtk.Menu()
        for n, attribute, label, widgetname, gtype, pytype in self.model.columns:
            if label:
                menuitem = gtk.CheckMenuItem(label=label)
                menuitem.set_data("attribute",n)
                if n < 4:
                    menuitem.set_active(1)
                menuitem.connect_object("toggled",
                                        self.on_ColumnMenu_toggled,
                                        self.rightClickColumnMenu,
                                        self.view,
                                        self.model)

                menuitem.show()
                self.rightClickColumnMenu.append(menuitem)

        # category filter selector
        # as to be build at init time, because
        # the categories can change
        menu = gtk.Menu()
        for category in self.model.available_categories():
            menuitem = gtk.MenuItem(label=category)
            menuitem.show()
            menu.append(menuitem)
        self.recordCategoryOpenMenu.set_menu(menu)

        self.categoryCheckboxes = []
        self.categoryFilterVBox.hide()
        
        for category,n in self.model.available_categories_indexed():
            checkbox = gtk.CheckButton(label=category)
            checkbox.set_data("category_number", n)
            checkbox.connect_object("toggled", 
                                    self.on_Categories_toggled,
                                    self.categoryFilterVBox,
                                    self.model,
                                    self.categoryCheckboxes)
            
            self.categoryCheckboxes.append(checkbox)
            self.categoryFilterVBox.pack_start(checkbox)
            checkbox.show()
        self.categoryFilterVBox.show()        
            
        # connect each field widget to change-handlers
        for n, attribute, label, widgetname, gtype, pytype in self.model.columns:
            w = self.wTree.get_widget(widgetname)
            if w:
                w.set_data("attribute", n)
                w.set_data("model", self.model)
                if isinstance(w,gtk.Entry):
                    w.connect("changed", self.on_entry_change)
                elif isinstance(w,gtk.TextView):
                    buffer = w.get_buffer()
                    buffer.connect_object("changed", self.on_textview_change, w)
                elif isinstance(w,gtk.OptionMenu):
                    w.connect("changed", self.on_optionmenu_change)
                elif isinstance(w,gtk.CheckButton):
                    w.connect("toggled", self.on_checkbutton_change)
                elif isinstance(w,gnome.ui.DateEdit):
                    w.connect("date-changed", self.on_dateedit_change)
                    w.connect("time-changed", self.on_dateedit_change)
                else:
                    print "How do I deal with type %s for %s?" % (type(w), attribute)


        # initial display
        self.on_ColumnMenu_toggled(self.rightClickColumnMenu,
                                   self.view,
                                   self.model)
    def widgetValidCheckboxToggle(self, cb, w, callback):
        if cb.get_active():
            w.set_sensitive(True)
        else:
            w.set_sensitive(False)
        callback(w)

    def joinValidCheckboxToWidget(self, checkbox, widget, callback):
        widget.set_data("isvalidCheckbox",checkbox)
        checkbox.connect("toggled",self.widgetValidCheckboxToggle, widget, callback)        

    def quit(self):
        self.model.save_to_disk()

    def on_NewButton(self, widget, model, listview, focuswidgetname):
        iter = model.append()
        ticked = filter(lambda b: b.state, self.categoryCheckboxes)
        if len(ticked) == 1:
            record = self.model.get_value(iter,0)
            record.category = ticked[0].get_data('category_number')
        listview.scroll_to_cell(model.get_path(iter))
        selection = listview.get_selection()
        selection.select_iter(iter)
        self.wTree.get_widget(focuswidgetname).grab_focus()
        if hasattr(self, "deleteButton"):
            self.deleteButton.set_sensitive(False)

    def on_SaveButton(self, widget, model):
        model.save_to_disk()

    def on_RevertButton(self, widget, model):
        path = self.model.get_path(self.iter)
        model.rescan_database(save=0)
        try:
            newiter = self.model.get_iter(path)
        except ValueError:
            path = (len(self.model.records)-1,0)
            newiter = self.model.get_iter(path)
        selection = self.view.get_selection()
        selection.select_iter(newiter)
        self.view.scroll_to_cell(path)

    def on_DeleteButton(self, widget):
        record_name = str(self.model.get_value(self.iter,0))
        if self.delete_record_confirmation(record_name) == gtk.RESPONSE_OK:
            path = self.model.get_path(self.iter)
            self.model.remove(self.iter)

            try:
                newiter = self.model.get_iter(path)
            except ValueError:
                path = (len(self.model.records)-1,0)
                newiter = self.model.get_iter(path)
            self.view.scroll_to_cell(path)                
            selection = self.view.get_selection()
            selection.select_iter(newiter)

    def on_TopButton(self, widget):
        textview, buffer = self.focus_notes()
        iter = buffer.get_start_iter()
        textview.scroll_to_iter(iter,0)
        buffer.place_cursor(iter)

    def on_BottomButton(self, widget):
        textview, buffer = self.focus_notes()
        iter = buffer.get_end_iter()
        textview.scroll_to_iter(iter,0)
        buffer.place_cursor(iter)

    def on_FilterButton(self, widget, focuswidgetname):
        self.wTree.get_widget(focuswidgetname).grab_focus()

    def on_FilterTypeCheckbox(self, widget, entrywidgetname):
        if widget.get_active() == True:
            self.wTree.get_widget(entrywidgetname).set_data('searchType', 'simple')
        else:
            self.wTree.get_widget(entrywidgetname).set_data('searchType', 'query')
        self.wTree.get_widget(entrywidgetname).grab_focus()            
            
    def on_textview_change(self, widget):
        iter = widget.get_data("iter")
        if iter:
            n = widget.get_data("attribute")
            model = widget.get_data("model")
            buffer= widget.get_buffer()
            begin = buffer.get_start_iter()
            end   = buffer.get_end_iter()
            text  = buffer.get_text(begin,end,True)
            try:
                model.set_value(iter, n, text)
            except UnicodeEncodeError, e:
                dialog = gtk.MessageDialog(None,                              # yeah, yeah.
                                           gtk.DIALOG_DESTROY_WITH_PARENT,    # I know.
                                           gtk.MESSAGE_ERROR,
                                           gtk.BUTTONS_CLOSE,
                                           "Unable to save value.\nError: %s" % e)
                dialog.run()
                dialog.destroy()

    def on_entry_change(self, widget):
        iter = widget.get_data("iter")
        if iter:
            n = widget.get_data("attribute")
            model = widget.get_data("model")
            cb = widget.get_data("isvalidCheckbox")
            if cb and not cb.get_active():
                return
            text = widget.get_text()
            model.set_value(iter, n, text)

    def on_optionmenu_change(self, widget):
        iter = widget.get_data("iter")
        if iter:
            n = widget.get_data("attribute")
            model = widget.get_data("model")
            num = widget.get_history()
            model.set_value(iter, n, num)

    def on_checkbutton_change(self, widget):
        iter = widget.get_data("iter")
        if iter:
            n = widget.get_data("attribute")
            model = widget.get_data("model")
            if widget.get_active() == True:
                num = True
            else:
                num = False
            model.set_value(iter, n, num)

    def on_dateedit_change(self, widget):
        iter = widget.get_data("iter")
        if iter:
            n = widget.get_data("attribute")
            model = widget.get_data("model")
            cb = widget.get_data("isvalidCheckbox")
            if cb and not cb.get_active():
                date = None
            else:
                t = widget.get_time()
                date = mx.DateTime.DateFromTicks(t)
            model.set_value(iter, n, date)

    def on_columnentry_change(self, widget, row, value=None):
        print widget, row, value
        if value == None:
            # we're toggling
            value = not widget.get_active()
        # changes made directly in the list view at the top
        n = widget.get_data("attribute")
        model = widget.get_data("model")        
        path = (int(row),)
        iter = model.get_iter(path)
        try:
            model.set_value(iter, n, value)
        except TypeError, e:
            dialog = gtk.MessageDialog(None,                              # yeah, yeah.
                                       gtk.DIALOG_DESTROY_WITH_PARENT,    # I know.
                                       gtk.MESSAGE_ERROR,
                                       gtk.BUTTONS_CLOSE,
                                       "Invalid value - %s" % e)
            dialog.run()
            dialog.destroy()
        self.updateDetailsView(iter)        
            
    def putRecordValuesIntoWidgets(self, model, iter):
        record = model.get_value(iter,0)
        
        for n, attribute, label, widgetname, gtype, pytype in model.columns:
            if widgetname:
                widget = self.wTree.get_widget(widgetname)
                if widget:
                    widget.set_data("iter", None) # don't try and perform
                                                  # updates on this change
                    #print label, record
                    if attribute in record.keys():
                        value = record[attribute]
                    else:
                        value = getattr(record,attribute)
                    cb = widget.get_data("isvalidCheckbox")
                    #print label, cb
                    #print label, n, model.getStringNameForValue(n, value)
                    if cb:
                        if value == None:
                            widget.set_sensitive(False)
                            if isinstance(widget,gnome.ui.DateEdit):
                                widget.set_time(int(mx.DateTime.now().ticks()))
                            cb.set_active(False)
                            widget.set_data("iter", iter)
                            continue
                        else:
                            widget.set_sensitive(True)
                            cb.set_active(True)
                            
                    if isinstance(widget,gtk.Entry):
                        widget.set_text(str(value))
                    elif isinstance(widget,gtk.TextView):
                        buffer = widget.get_buffer()
                        buffer.set_text(value)        
                    elif isinstance(widget,gtk.OptionMenu):
                        widget.set_history(int(value))
                    elif isinstance(widget,gtk.CheckButton):
                        if value == 1:
                            widget.set_active(True)
                        else:
                            widget.set_active(False)
                    elif isinstance(widget,gnome.ui.DateEdit):
                        try:
                            t = int(value.ticks())
                            widget.set_time(t)
                        except mx.DateTime.Error, e:
                            print "WARNING: Date %s - %s" % (value, e)
                            print "attribute: %s label: %s" % (attribute, label)
                    else:
                        print "How do I deal with type %s for %s" % (type(widget),
                                                                     attribute)
                    widget.set_data("iter", iter)

    def on_TreeView_selection_changed(self, selection):
        if hasattr(self, "deleteButton"):
            self.deleteButton.set_sensitive(True)
        model, iter = selection.get_selected()
        model.save_to_disk()
        if iter is not None:
            self.updateDetailsView(iter)
        else: # nothing selected
            self.clearDetailsView()

    def delete_record_confirmation(self, name):
        dialog = gtk.MessageDialog(None,                           # 
                                   gtk.DIALOG_DESTROY_WITH_PARENT, # what parent ? ;-)
                                   gtk.MESSAGE_QUESTION,
                                   gtk.BUTTONS_OK_CANCEL,
                                   "Delete record\n%s?" % name)
        dialog.set_property('window_position',gtk.WIN_POS_MOUSE)
        res = dialog.run()
        dialog.destroy()
        return res


    def on_Categories_toggled(self, widget, model, checkboxes):
        selected = []
        for checkbox in checkboxes:
            if checkbox.get_active():
                selected.append(checkbox.get_data("category_number"))
        model.setCategoryFilter(selected)
        model.rescan_database()
        self.clearDetailsView()
        

    def on_FilterEntry_keyrelease(self, widget, event, model):
        if event.keyval in (gtk.keysyms.Left, gtk.keysyms.Right):
            return

        if widget.get_data("searchType") is None:
            widget.set_data("searchType","simple")

        text = widget.get_text()
        if len(text) == 0 or len(text) > 2 or event.keyval == gtk.keysyms.Return:
            if widget.get_data("searchType") == "query":
                try:
                    model.setQueryFilterTerm(text)
                    widget.modify_base(gtk.STATE_NORMAL,
                                       gtk.gdk.color_parse('#0F0'))
                except pyparsing.ParseException, e:
                    widget.modify_base(gtk.STATE_NORMAL,
                                       gtk.gdk.color_parse('#F00'))
                    return # don't bother running query
            else:
                model.setSearchTerm(text)
                widget.modify_base(gtk.STATE_NORMAL,
                                   gtk.gdk.color_parse('#FFF'))
            model.rescan_database()
            self.clearDetailsView()
            
        
    def on_ColumnMenu_toggled(self, widget, listview, model):
        for column in listview.get_columns():
            listview.remove_column(column)
        for child in widget.get_children():
            if child.active:

                attribute   = child.get_data("attribute")
                field_detail = model.columns[attribute-1]

                namesColumn = model.getColumnForNamesList(attribute)

                #import pdb
                #pdb.set_trace()
                #print 2
                max_width = None
                if namesColumn:
                    renderer=ListItemRenderer()
                    renderer.set_data("attribute", attribute)
                    renderer.set_data("model", model)
                    renderer_attribute = "index"                    
                elif field_detail[5] == mx.DateTime.DateTimeType:
                    renderer=PyObjectRenderer()
                    renderer.set_data("attribute", attribute)
                    renderer.set_data("model", model)
                    renderer_attribute = "value"
                elif field_detail[5] == types.BooleanType:
                    renderer=gtk.CellRendererToggle()
                    renderer.connect("toggled", self.on_columnentry_change)
                    renderer.set_data("attribute", attribute)
                    renderer.set_data("model", model)
                    renderer_attribute = "active"
                else:
                    renderer = gtk.CellRendererText()
                    if model.shouldListViewShowOneLine():
                        renderer.set_fixed_height_from_font(1)
                        renderer.set_property("editable",False)
                        max_width = 400
                    else:
                        renderer.set_property("editable",True)                        
                    renderer.connect("edited", self.on_columnentry_change)
                    renderer.set_data("attribute", attribute)
                    renderer.set_data("model", model)
                    renderer_attribute = "text"

                column=gtk.TreeViewColumn(field_detail[2])

                column.pack_start(renderer,expand=True)
                column.add_attribute(renderer, renderer_attribute, attribute)
                if namesColumn:
                    column.add_attribute(renderer, "names", namesColumn)

                column.set_data("attribute",attribute)
                column.set_flags(gtk.CAN_FOCUS)
                column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
                column.set_resizable(True)
                column.set_reorderable(True)
                if max_width:
                    print "Fixing width at %d for %s" % (max_width, field_detail)
                    column.set_max_width(max_width)
                    column.set_min_width(200)                    
                #column.set_max_width(400)

                listview.append_column(column)
                
        listview.get_columns()[0].set_sort_indicator(True)
        listview.get_columns()[0].set_sort_order(gtk.SORT_ASCENDING)
        
        self.clearDetailsView()
        
    def on_TreeView_button_press_event(self,widget,event,menu):
        if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
            menu.popup(None,None,None,event.button, event.time)

    def focus_notes(self):
        raise NotImplementedError

    def clearDetailsView(self):
        print "Clearing"
        self.iter = None        
        for n, attribute, label, widgetname, gtype, pytype in self.model.columns:
            if widgetname:
                widget = self.wTree.get_widget(widgetname)
                if widget:
                    widget.set_data("iter", None)                    
                    if isinstance(widget,gtk.Entry):
                        widget.set_text("")
                    elif isinstance(widget,gtk.TextView):
                        buffer = widget.get_buffer()
                        buffer.set_text("")
                    elif isinstance(widget,gtk.OptionMenu):
                        widget.set_history(0)
                    elif isinstance(widget,gtk.CheckButton):
                        widget.checked = 0
                    elif isinstance(widget,gnome.ui.DateEdit):
                        widget.set_time(946684800) # 2000
                    else:
                        print "How do I deal with type %s for %s?" % (type(widget),
                                                                      attribute)
        selection = self.view.get_selection()
        try:
            iter = self.model.get_iter_first()
        except ValueError:
            return
        if iter is None:
            return
        selection.select_iter(iter)
        self.view.scroll_to_cell(self.model.get_path(iter))
        self.updateDetailsView(iter)

    def updateDetailsView(self, iter):
        self.iter = None
        record = self.model.get_value(iter,0)
        #print "Showing %s" % record
        self.putRecordValuesIntoWidgets(self.model, iter)
        #print "Shown %s" % record
        self.iter = iter

    def _execCommandFromConfig(self, section, setting, record):
        try:
            configcmd = jppy.config.get(section, setting, raw=True)
        except ConfigParser.NoOptionError, e:
            d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
                                  "Error with ~/.jppyrc: %s" % (e))
            d.run()
            d.destroy()
            return
        try:
            cmd = configcmd % dict(record.items())
        except KeyError:
            d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
                                  "Error with ~/.jppyrc: Invalid key used in '%s'" % (configcmd))
            d.run()
            d.destroy()
            return
        print cmd
        os.system(cmd)
        

Generated by  Doxygen 1.6.0   Back to index