예제 #1
0
class hyper_link(clickable_eventbox):

    gproperty('normal-markup', str, '<span color="#0000c0">%s</span>')
    gproperty('active-markup', str, '<span color="#c00000">%s</span>')
    gproperty('hover-markup', str, '<u><span color="#0000c0">%s</span></u>')

    def __init__(self, text=''):
        self.__gproperties = {}
        self.__label = gtk.Label()
        clickable_eventbox.__init__(self, self.__label)
        self.set_border_width(1)
        self.add_events(gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK)
        self.connect('enter-notify-event', self.on_hover_changed, True)
        self.connect('leave-notify-event', self.on_hover_changed, False)
        self.connect('active', self.on_active_changed, True)
        self.connect('unactive', self.on_active_changed, False)
        self.__text = None
        self.__is_active = False
        self.__is_hover = False
        self.set_text(text)

    def do_set_property(self, prop, value):
        self.__gproperties[prop.name] = value

    def do_get_property(self, prop):
        return self.__gproperties.setdefault(prop.name, prop.default_value)

    def set_text(self, text):
        self.__text = text
        self.__update_look()

    def on_hover_changed(self, eb, event, hover):
        self.__is_hover = hover
        self.__update_look()

    def on_active_changed(self, eb, active):
        self.__is_active = active
        self.__update_look()

    def __update_look(self):
        if self.__is_active:
            state = 'active'
        elif self.__is_hover:
            state = 'hover'
        else:
            state = 'normal'
        markup_string = self.get_property('%s-markup' % state)
        self.__label.set_markup(markup_string % escape(self.__text))
예제 #2
0
class Tree(gtk.VBox):
    """A treeview control with niceness."""
    #The fields for the model.
    FIELDS = (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_STRING)

    #The columns for the view.
    COLUMNS = [[gtk.CellRendererText, 'markup', 2]]

    #The signals for the widget.
    __gsignals__ = {
        'clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_PYOBJECT, )),
        'double-clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                           (gobject.TYPE_PYOBJECT, )),
        'right-clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                          (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
        'middle-clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                           (gobject.TYPE_PYOBJECT, )),
        'new-item': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
        'delete-item': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
        'edit-item': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())
    }

    gproperty('has-edit-box', bool, default=True)
    gproperty('headers-visible', bool, default=True)
    gproperty('icons-visible', bool, default=False)
    gproperty('markup-format-string', str, default='%(key)s')

    def do_get_property(self, prop):
        return self.__properties.setdefault(prop.name, prop.default_value)

    def do_set_property(self, prop, value):
        self.__properties[prop.name] = value

    EDIT_BUTTONS = False
    EDIT_BOX = False

    HEADERS_VISIBLE = False

    SORT_BY = None
    SORT_LIST = None
    SORT_AVAILABLE = None
    SORT_CONTROLS = False

    def __init__(self):
        self.__init_model()
        self.__init_view()
        self.__init_signals()
        self.__properties = {}

    def __init_view(self):
        """Load the widgets."""
        gtk.VBox.__init__(self)
        self.__sw = gtk.ScrolledWindow()
        self.pack_start(self.__sw)
        self.__sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.__view = gtk.TreeView(self.__model)
        self.__view.set_rules_hint(True)
        self.__view.set_enable_search(False)
        self.__view.set_model(self.__model)
        self.__sw.add(self.__view)
        self.__view.set_headers_visible(False)
        for column in self.__init_renderers():
            self.__view.append_column(column)
        if self.SORT_CONTROLS == True:
            sb = gtk.Expander()
            self.pack_start(sb, expand=False)
            l = gtk.Label('Sort')
            sb.set_label_widget(l)
            hb = gtk.HBox()
            sb.add(hb)
            self.__sortcombo = gtk.combo_box_new_text()
            hb.pack_start(self.__sortcombo)
            if self.SORT_AVAILABLE is not None:
                self.sort_available = dict(self.SORT_AVAILABLE)
                for attr, val in self.SORT_AVAILABLE:
                    self.__sortcombo.append_text(attr)
            self.__sortdir = gtk.ToggleToolButton(
                stock_id=gtk.STOCK_SORT_DESCENDING)
            hb.pack_start(self.__sortdir, expand=False)
            self.__sortdir.set_active(True)
            self.__sortcombo.set_active(0)
            self.__sortdir.connect('toggled', self.cb_sortdir_toggled)
            self.__sortcombo.connect('changed', self.cb_sortcombo_changed)
            self.__user_initiated_sort()
        if self.EDIT_BOX == True:
            self.__editbox = QuestionBox()
            self.pack_start(self.__editbox, expand=False)
        if self.EDIT_BUTTONS == True:
            self.__toolbar = toolbar.Toolbar()
            self.__toolbar.add_button('new', 'new', 'new', True)
            self.__toolbar.add_button('delete', 'delete', 'delete', True)
            self.__toolbar.add_button('edit', 'edit', 'Edit this item.', True)
            self.__toolbar.connect('clicked', self.cb_toolbar_clicked)
            self.pack_start(self.__toolbar, expand=False)
        self.__init_signals()
        if self.SORT_BY is not None:
            self.sort_by([self.SORT_BY])
        if self.SORT_LIST is not None:
            self.sort_by(self.SORT_LIST)
        self.show_all()

    def __init_model(self):
        """Initialise and return the model for the data."""
        self.__model = gtk.TreeStore(*self.FIELDS)
        return self.__model

    def __init_signals(self):
        def cb_toolbar_clicked(toolbar, action):
            if action == 'new':
                self.emit('new-item')
            elif action == 'delete':
                self.emit('delete-item')
            elif action == 'edit':
                self.emit('edit-item')
            self.__toolbar.emit_stop_by_name('clicked')

        if self.EDIT_BUTTONS == True:
            self.__toolbar.connect('clicked', cb_toolbar_clicked)

        def cb_cursor_changed(view):
            self.emit('clicked', self.selected)
            self.__view.emit_stop_by_name('cursor-changed')

        self.__view.connect('cursor-changed', cb_cursor_changed)

        def cb_row_activated(view, path, column):
            self.emit('double-clicked', self.selected)
            self.__view.emit_stop_by_name('row-activated')

        self.__view.connect_after('row-activated', cb_row_activated)

        def cb_button_press_event(source, event):
            if event.button == 3:
                pathinf = self.__view.get_path_at_pos(int(event.x),
                                                      int(event.y))
                self.__view.emit_stop_by_name('button-press-event')
                if pathinf is not None:
                    path, col, cellx, celly = pathinf
                    self.__view.grab_focus()
                    self.__view.set_cursor(path, None, 0)
                    self.emit('right-clicked', self.selected, event)
                else:
                    self.emit('right-clicked', None, event)
                return True
            if event.button == 2:
                pathinf = self.__view.get_path_at_pos(int(event.x),
                                                      int(event.y))
                if pathinf is not None:
                    path, col, cellx, celly = pathinf
                    self.__view.grab_focus()
                    self.__view.set_cursor(path, None, 0)
                    self.__view.emit_stop_by_name('button-press-event')
                    self.emit('middle-clicked', self.selected)
                    return True

        self.__view.add_events(gtk.gdk.BUTTON_PRESS_MASK)
        self.__view.connect('button-press-event', cb_button_press_event)

    def __init_renderers(self):
        """Initialise the renderers."""
        for renderer_type, attribute, field in self.COLUMNS:
            renderer = renderer_type()
            renderer.set_property('ypad', 1)
            column = gtk.TreeViewColumn(attribute, renderer,
                                        **{attribute: field})
            column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
            yield column

    def add_item(self, item, key=None, parent=None):
        """Add an item to the tree."""
        if key is None:
            key = item.key
        else:
            item.key = key
        titem = TreeItem(key, item)
        row = [key, titem, self.__get_markup(item)]
        niter = self.model.append(parent, row)

        def reset():
            self.model.set_value(niter, 2, self.get_markup(item))

        titem.reset_markup = reset
        item.reset_markup = reset
        return niter

    def __get_markup(self, item):
        unmangled = {}
        markup_fmt = self.get_property('markup-format-string')
        for k in dir(item):
            if k in markup_fmt:
                unmangled[k] = getattr(item, k)
        markup_string = markup_fmt % unmangled
        return markup_string

    get_markup = __get_markup

    def add_items(self, items):
        """Add items to the tree."""
        for item in items:
            self.add_item(item)

    def clear(self):
        """Clear the tree."""
        self.__model.clear()

    def del_item(self):
        """Removes the currently selected item from the tree."""
        selected_path = self.__get_selected_path()
        if selected_path:
            self.__model.emit('row-deleted', selected_path)

    def set_items(self, items):
        """Set the items in the tree from the item list."""
        self.clear()
        self.add_items(items)

    def question(self, callback, prompt):
        self.__editbox.question(callback, prompt)

    def sort_by(self, attrnames, sortcolid=0, columnid=1, direction=1):
        def comparemethod(model, iter1, iter2):
            v1 = model.get_value(iter1, columnid)
            v2 = model.get_value(iter2, columnid)

            def cmpvs(attrname, v1, v2):
                attr1 = attr2 = None
                if v1 is not None:
                    attr1 = getattr(v1.value, attrname, None)
                if v2 is not None:
                    attr2 = getattr(v2.value, attrname, None)
                if attr1 is None and attr2 is None:
                    return 0
                elif attr1 is None:
                    return 0
                elif attr2 is None:
                    return 0
                else:
                    return cmp(attr2, attr1)

            for attrname in attrnames + ['key']:
                compd = cmpvs(attrname, v1, v2)
                if compd != 0:
                    return direction * compd
            return 0

        self.__model.set_sort_column_id(sortcolid, gtk.SORT_DESCENDING)
        self.__model.set_sort_func(sortcolid, comparemethod)
        #self.__view.set_model(self.__model)

    def __get_model(self):
        """Return the Tree Model."""
        return self.__model

    model = property(__get_model)

    def __get_view(self):
        return self.__view

    view = property(__get_view)

    def __get_selected(self, column=1):
        """Get the selected item."""
        ite = self.__get_selected_iter()
        if ite:
            return self.__get(ite, column)

    selected = property(__get_selected)

    def get_selected_key(self):
        return self.__get_selected(0)

    selected_key = property(get_selected_key)

    def set_selected(self, key):
        """Set the selected item to the first item matching the key."""
        key = str(key)
        for row in self.model:
            if row[0] == key:
                self.__view.set_cursor(row.path)
                return True
        return False

    def __get_selected_iter(self):
        """Get the selected Tree Model Iter."""
        path = self.__get_selected_path()
        if path:
            return self.__model.get_iter(path)

    selected_iter = property(__get_selected_iter)

    def __get_selected_path(self):
        """Get the selected Tree View Path."""
        return self.__view.get_cursor()[0]

    selected_path = property(__get_selected_path)

    def __get(self, niter, column):
        """Get a cell's vlue from the Tree Model."""
        return self.__model.get_value(niter, column)

    get = __get

    def __set(self, niter, column, value):
        self.__model.set_value(niter, column, value)

    set = __set

    def cb_toolbar_clicked(self, toolbar, action):
        if action == 'new':
            self.emit('new-item')
        elif action == 'edit':
            self.emit('edit-item')
        elif action == 'delete':
            self.emit('delete-item')
        toolbar.emit_stop_by_name('clicked')

    def cb_sortcombo_changed(self, combo):
        self.__user_initiated_sort()

    def cb_sortdir_toggled(self, toggle):
        self.__user_initiated_sort()

    def __user_initiated_sort(self):
        text = self.__sortcombo.get_active_text()
        if self.__sortdir.get_active():
            direction = 1  #gtk.SORT_DESCENDING
        else:
            direction = -1  #gtk.SORT_ASCENDING
        self.sort_by([self.sort_available[text]], direction=direction)