From 1e71c79f110f825596551d8e9bff0978c0128e9d Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Sun, 11 Apr 2010 22:32:36 +0000 Subject: erase (in 'demo' mode), hover effect, style fixes --- diff --git a/janitor.py b/janitor.py index d64ed6b..16a6872 100644 --- a/janitor.py +++ b/janitor.py @@ -29,6 +29,7 @@ from sugar.activity.widgets import StopButton from sugar.activity import activity from sugar.datastore import datastore import sugar.env +from sugar.graphics import style from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toolbarbox import ToolbarBox from sugar.graphics.toolbarbox import ToolbarButton @@ -61,6 +62,14 @@ def format_size(size): return _('%4d GB') % (size / 1024**3) +class EraseButton(ToolButton): + + def __init__(self, **kwargs): + ToolButton.__init__(self, 'edit-delete', **kwargs) + self.props.tooltip = _('Erase selected entries') + self.props.accelerator = '' + + class JanitorActivity(activity.Activity): _store_columns = [ @@ -69,15 +78,16 @@ class JanitorActivity(activity.Activity): gobject.TYPE_UINT64, gobject.TYPE_FLOAT, gobject.TYPE_STRING, + gobject.TYPE_PYOBJECT, ] NUM_COLUMNS = len(_store_columns) - COLUMN_SELECT, COLUMN_TITLE, COLUMN_SIZE_INT, COLUMN_SIZE_PERCENT, \ - COLUMN_SIZE_TEXT = range(NUM_COLUMNS) + COLUMN_SELECTED, COLUMN_TITLE, COLUMN_SIZE_INT, COLUMN_SIZE_PERCENT, \ + COLUMN_SIZE_TEXT, COLUMN_OBJECT_ID = range(NUM_COLUMNS) _view_columns = [ {'name': 'Select', 'renderer': gtk.CellRendererToggle, - 'view_args': {'active': COLUMN_SELECT}, + 'view_args': {'active': COLUMN_SELECTED}, 'callback': lambda cell, path, self: self._select_toggled(cell, path), }, {'name': 'Title', @@ -108,32 +118,63 @@ class JanitorActivity(activity.Activity): def _setup_canvas(self): vbox = gtk.VBox() - scrolled_window = gtk.ScrolledWindow() - scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) self._create_list_model() self._list_view = gtk.TreeView(self._list_model) - self._list_view.set_rules_hint(True) + self._list_view.set_hover_selection(True) + self._list_view.modify_base(gtk.STATE_NORMAL, + style.COLOR_WHITE.get_gdk_color()) + self._list_view.modify_base(gtk.STATE_ACTIVE, + style.COLOR_HIGHLIGHT.get_gdk_color()) + self._list_view.modify_base(gtk.STATE_SELECTED, + style.COLOR_HIGHLIGHT.get_gdk_color()) + self._list_view.modify_bg(gtk.STATE_NORMAL, + style.COLOR_PANEL_GREY.get_gdk_color()) + + # big hack to make the scrollbar not "overwrite" the header, from + # http://mail.gnome.org/archives/gtk-list/2008-November/msg00111.html + list_scroll = gtk.VScrollbar(self._list_view.get_vadjustment()) + list_hbox = gtk.HBox(False, 0) + list_vbox = gtk.VBox(False, 0) + list_pad_widget = gtk.EventBox() + list_pad_widget.modify_bg(gtk.STATE_NORMAL, + style.COLOR_PANEL_GREY.get_gdk_color()) + list_hbox.pack_start(self._list_view, True, True, 0) + list_hbox.pack_start(list_vbox, False, False, 0) + list_vbox.pack_start(list_pad_widget, False, False, 0) + list_vbox.pack_start(list_scroll, True, True, 0) + list_vbox.show() + list_pad_widget.show() + list_scroll.show() + list_hbox.show() + self._list_view.connect('map', self.__list_view_map_cb, list_pad_widget) - scrolled_window.add(self._list_view) self._setup_list_view_columns() sort_column_idx = [idx for idx, column in enumerate(self._view_columns) if column['name'] == 'Size'][0] self._list_model.set_sort_column_id(sort_column_idx, gtk.SORT_DESCENDING) self._list_view.show() - scrolled_window.show() - vbox.add(scrolled_window) + vbox.add(list_hbox) self.set_canvas(vbox) vbox.show() + def __list_view_map_cb(self, list_view, pad_widget): + x, y = list_view.convert_bin_window_to_widget_coords(0, 0) + pad_widget.set_size_request(-1, y) + def _setup_toolbar(self): toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) - toolbar_box.toolbar.insert(activity_button, 0) + toolbar_box.toolbar.insert(activity_button, -1) activity_button.show() + erase_button = EraseButton() + erase_button.connect('clicked', self.__erase_cb) + toolbar_box.toolbar.insert(erase_button, -1) + erase_button.show() + separator = gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) @@ -148,6 +189,12 @@ class JanitorActivity(activity.Activity): toolbar_box.show() def _setup_list_view_columns(self): + def column_label_map_cb(label): + # another bad hack to work around GTK limitations + header_button = label.get_parent().get_parent().get_parent() + header_button.modify_bg(gtk.STATE_NORMAL, + style.COLOR_PANEL_GREY.get_gdk_color()) + for idx, column in enumerate(self._view_columns): renderer = column['renderer']() if column.get('ellipsize'): @@ -165,6 +212,13 @@ class JanitorActivity(activity.Activity): view_column = gtk.TreeViewColumn(_(column['name']), renderer, **column['view_args']) + column_label = gtk.Label(_(column['name'])) + column_label.modify_fg(gtk.STATE_NORMAL, + style.COLOR_BLACK.get_gdk_color()) + column_label.connect('map', column_label_map_cb) + column_label.show() + view_column.set_widget(column_label) + if isinstance(renderer, gtk.CellRendererText): view_column.props.expand = True @@ -196,6 +250,7 @@ class JanitorActivity(activity.Activity): entries.append({ 'size': size, 'title': metadata.get('title', ''), + 'object_id': jobject.object_id, }) jobject.destroy() @@ -210,7 +265,8 @@ class JanitorActivity(activity.Activity): self.COLUMN_TITLE, entry['title'], self.COLUMN_SIZE_INT, entry['size'], self.COLUMN_SIZE_PERCENT, percent, - self.COLUMN_SIZE_TEXT, format_size(entry['size'])) + self.COLUMN_SIZE_TEXT, format_size(entry['size']), + self.COLUMN_OBJECT_ID, entry['object_id']) def _get_size(self, jobject): """Return the file size for a Journal object.""" @@ -224,8 +280,30 @@ class JanitorActivity(activity.Activity): def _select_toggled(self, cell, path): """Called when a 'Select' cell is toggled.""" giter = self._list_model.get_iter((int(path), )) - selected = self._list_model.get_value(giter, self.COLUMN_SELECT) - self._list_model.set(giter, self.COLUMN_SELECT, not selected) + selected = self._list_model.get_value(giter, self.COLUMN_SELECTED) + self._list_model.set(giter, self.COLUMN_SELECTED, not selected) + + def __erase_cb(self, button): + self._apply_action(self._get_selection(), self._erase) + + def _get_selection(self): + """Return object_ids of all selected entries.""" + return [row[self.COLUMN_OBJECT_ID] for row in self._list_model + if row[self.COLUMN_SELECTED]] + + def _apply_action(self, entries, action): + """Apply action to all entries.""" + [action(entry) for entry in entries] + + def _erase(self, object_id): + """Delete given entry from data store.""" + for row in self._list_model: + if row[self.COLUMN_OBJECT_ID] == object_id: + self._list_model.remove(row.iter) + return + + raise ValueError('object_id %r not found in self._list_model' % ( + object_id, )) sugar.logger.start() -- cgit v0.9.1