diff options
Diffstat (limited to 'src/jarabe/journal/listview.py')
-rw-r--r-- | src/jarabe/journal/listview.py | 310 |
1 files changed, 59 insertions, 251 deletions
diff --git a/src/jarabe/journal/listview.py b/src/jarabe/journal/listview.py index 251388d..36cd06a 100644 --- a/src/jarabe/journal/listview.py +++ b/src/jarabe/journal/listview.py @@ -20,12 +20,11 @@ import time import gobject import gtk -import hippo import gconf import pango from sugar.graphics import style -from sugar.graphics.icon import CanvasIcon, Icon, CellRendererIcon +from sugar.graphics.icon import CellRendererIcon from sugar.graphics.xocolor import XoColor from sugar import util @@ -61,32 +60,14 @@ class BaseListView(gtk.Bin): __gtype_name__ = 'JournalBaseListView' __gsignals__ = { - 'clear-clicked': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - ([])) + 'detail-clicked': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([object])) } def __init__(self): - self._query = {} - self._model = None - self._progress_bar = None - self._last_progress_bar_pulse = None - - gobject.GObject.__init__(self) - - self.connect('destroy', self.__destroy_cb) - - self._scrolled_window = gtk.ScrolledWindow() - self._scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - self.add(self._scrolled_window) - self._scrolled_window.show() - - self.tree_view = TreeView() - self.tree_view.props.fixed_height_mode = True - self.tree_view.modify_base(gtk.STATE_NORMAL, - style.COLOR_WHITE.get_gdk_color()) - self._scrolled_window.add(self.tree_view) - self.tree_view.show() + gtk.TreeView.__init__(self) + self.props.fixed_height_mode = True self.cell_title = None self.cell_icon = None @@ -94,32 +75,45 @@ class BaseListView(gtk.Bin): self.date_column = None self._add_columns() - self.tree_view.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, - [('text/uri-list', 0, 0), - ('journal-object-id', 0, 0)], - gtk.gdk.ACTION_COPY) + self.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, + [('text/uri-list', 0, 0), ('journal-object-id', 0, 0)], + gtk.gdk.ACTION_COPY) + + self.cell_title.props.editable = True + self.cell_title.connect('edited', self.__cell_title_edited_cb) - # Auto-update stuff - self._fully_obscured = True - self._dirty = False - self._refresh_idle_handler = None - self._update_dates_timer = None + self.cell_icon.connect('clicked', self.__icon_clicked_cb) + self.cell_icon.connect('detail-clicked', self.__detail_clicked_cb) - model.created.connect(self.__model_created_cb) - model.updated.connect(self.__model_updated_cb) - model.deleted.connect(self.__model_deleted_cb) + cell_detail = CellRendererDetail(self) + cell_detail.connect('clicked', self.__detail_cell_clicked_cb) - def __model_created_cb(self, sender, **kwargs): - self._set_dirty() + column = gtk.TreeViewColumn('') + column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED + column.props.fixed_width = cell_detail.props.width + column.pack_start(cell_detail) + self.append_column(column) - def __model_updated_cb(self, sender, **kwargs): - self._set_dirty() + self.connect('notify::hover-selection', + self.__notify_hover_selection_cb) - def __model_deleted_cb(self, sender, **kwargs): - self._set_dirty() + def __notify_hover_selection_cb(self, widget, pspec): + self.cell_icon.props.show_palette = not self.props.hover_selection + + def do_size_request(self, requisition): + # HACK: We tell the model that the view is just resizing so it can avoid + # hitting both D-Bus and disk. + model = self.get_model() + if model is not None: + model.view_is_resizing = True + try: + gtk.TreeView.do_size_request(self, requisition) + finally: + if model is not None: + model.view_is_resizing = False def _add_columns(self): - cell_favorite = CellRendererFavorite(self.tree_view) + cell_favorite = CellRendererFavorite(self) cell_favorite.connect('clicked', self.__favorite_clicked_cb) column = gtk.TreeViewColumn('') @@ -127,9 +121,9 @@ class BaseListView(gtk.Bin): column.props.fixed_width = cell_favorite.props.width column.pack_start(cell_favorite) column.set_cell_data_func(cell_favorite, self.__favorite_set_data_cb) - self.tree_view.append_column(column) + self.append_column(column) - self.cell_icon = CellRendererActivityIcon(self.tree_view) + self.cell_icon = CellRendererActivityIcon(self) column = gtk.TreeViewColumn('') column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED @@ -137,8 +131,8 @@ class BaseListView(gtk.Bin): column.pack_start(self.cell_icon) column.add_attribute(self.cell_icon, 'file-name', ListModel.COLUMN_ICON) column.add_attribute(self.cell_icon, 'xo-color', - ListModel.COLUMN_ICON_COLOR) - self.tree_view.append_column(column) + ListModel.COLUMN_ICON_COLOR) + self.append_column(column) self.cell_title = gtk.CellRendererText() self.cell_title.props.ellipsize = pango.ELLIPSIZE_MIDDLE @@ -152,15 +146,15 @@ class BaseListView(gtk.Bin): self._title_column.add_attribute(self.cell_title, 'markup', ListModel.COLUMN_TITLE) self._title_column.connect('clicked', self.__header_clicked_cb) - self.tree_view.append_column(self._title_column) + self.append_column(self._title_column) buddies_column = gtk.TreeViewColumn('') buddies_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED - self.tree_view.append_column(buddies_column) + self.append_column(buddies_column) for column_index in [ListModel.COLUMN_BUDDY_1, ListModel.COLUMN_BUDDY_2, ListModel.COLUMN_BUDDY_3]: - cell_icon = CellRendererBuddy(self.tree_view, + cell_icon = CellRendererBuddy(self, column_index=column_index) buddies_column.pack_start(cell_icon) buddies_column.props.fixed_width += cell_icon.props.width @@ -186,7 +180,7 @@ class BaseListView(gtk.Bin): self.date_column.pack_start(cell_text) self.date_column.add_attribute(cell_text, 'text', ListModel.COLUMN_DATE) self.date_column.connect('clicked', self.__header_clicked_cb) - self.tree_view.append_column(self.date_column) + self.append_column(self.date_column) def __header_clicked_cb(self, column_clicked): if column_clicked == self._title_column: @@ -206,7 +200,7 @@ class BaseListView(gtk.Bin): else: self._query['order_by'] = ['+timestamp'] - self.refresh() + self._refresh() # Need to update the column indicators after the model has been reset if self._query['order_by'] == ['-timestamp']: @@ -237,19 +231,8 @@ class BaseListView(gtk.Bin): width, height_ = layout.get_size() return pango.PIXELS(width) - def do_size_allocate(self, allocation): - self.allocation = allocation - self.child.size_allocate(allocation) - - def do_size_request(self, requisition): - requisition.width, requisition.height = self.child.size_request() - - def __destroy_cb(self, widget): - if self._model is not None: - self._model.stop() - def __favorite_set_data_cb(self, column, cell, tree_model, tree_iter): - favorite = self._model[tree_iter][ListModel.COLUMN_FAVORITE] + favorite = self.get_model()[tree_iter][ListModel.COLUMN_FAVORITE] if favorite: client = gconf.client_get_default() color = XoColor(client.get_string('/desktop/sugar/user/color')) @@ -259,7 +242,7 @@ class BaseListView(gtk.Bin): cell.props.fill_color = style.COLOR_WHITE.get_svg() def __favorite_clicked_cb(self, cell, path): - row = self._model[path] + row = self.get_model()[path] metadata = model.get(row[ListModel.COLUMN_UID]) if metadata['keep'] == '1': metadata['keep'] = '0' @@ -267,212 +250,37 @@ class BaseListView(gtk.Bin): metadata['keep'] = '1' model.write(metadata, update_mtime=False) - def update_with_query(self, query_dict): - logging.debug('ListView.update_with_query') - self._query = query_dict - - if 'order_by' not in self._query: - self._query['order_by'] = ['+timestamp'] - - self.refresh() - - def refresh(self): - logging.debug('ListView.refresh query %r', self._query) - self._stop_progress_bar() - self._start_progress_bar() - - if self._model is not None: - self._model.stop() - - self._model = ListModel(self._query) - self._model.connect('ready', self.__model_ready_cb) - self._model.connect('progress', self.__model_progress_cb) - self._model.setup() - - def __model_ready_cb(self, tree_model): - self._stop_progress_bar() - - # Cannot set it up earlier because will try to access the model and it - # needs to be ready. - self.tree_view.set_model(self._model) - - if len(tree_model) == 0: - if self._is_query_empty(): - self._show_message(MESSAGE_EMPTY_JOURNAL) - else: - self._show_message(MESSAGE_NO_MATCH) - else: - self._clear_message() - - def _is_query_empty(self): - # FIXME: This is a hack, we shouldn't have to update this every time - # a new search term is added. - if self._query.get('query', '') or self._query.get('mime_type', '') or \ - self._query.get('keep', '') or self._query.get('mtime', '') or \ - self._query.get('activity', ''): - return False - else: - return True - - def __model_progress_cb(self, tree_model): - if time.time() - self._last_progress_bar_pulse > 0.05: - if self._progress_bar is not None: - self._progress_bar.pulse() - self._last_progress_bar_pulse = time.time() - - def _start_progress_bar(self): - alignment = gtk.Alignment(xalign=0.5, yalign=0.5, xscale=0.5) - self.remove(self.child) - self.add(alignment) - alignment.show() - - self._progress_bar = gtk.ProgressBar() - self._progress_bar.props.pulse_step = 0.01 - self._last_progress_bar_pulse = time.time() - alignment.add(self._progress_bar) - self._progress_bar.show() - - def _stop_progress_bar(self): - if self.child != self._progress_bar: - return - self.remove(self.child) - self.add(self._scrolled_window) - - def _show_message(self, message): - canvas = hippo.Canvas() - self.remove(self.child) - self.add(canvas) - canvas.show() - - box = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL, - background_color=style.COLOR_WHITE.get_int(), - yalign=hippo.ALIGNMENT_CENTER, - spacing=style.DEFAULT_SPACING, - padding_bottom=style.GRID_CELL_SIZE) - canvas.set_root(box) - - icon = CanvasIcon(size=style.LARGE_ICON_SIZE, - icon_name='activity-journal', - stroke_color = style.COLOR_BUTTON_GREY.get_svg(), - fill_color = style.COLOR_TRANSPARENT.get_svg()) - box.append(icon) - - if message == MESSAGE_EMPTY_JOURNAL: - text = _('Your Journal is empty') - elif message == MESSAGE_NO_MATCH: - text = _('No matching entries') - else: - raise ValueError('Invalid message') - - text = hippo.CanvasText(text=text, - xalign=hippo.ALIGNMENT_CENTER, - font_desc=style.FONT_BOLD.get_pango_desc(), - color = style.COLOR_BUTTON_GREY.get_int()) - box.append(text) - - if message == MESSAGE_NO_MATCH: - button = gtk.Button(label=_('Clear search')) - button.connect('clicked', self.__clear_button_clicked_cb) - button.props.image = Icon(icon_name='dialog-cancel', - icon_size=gtk.ICON_SIZE_BUTTON) - canvas_button = hippo.CanvasWidget(widget=button, - xalign=hippo.ALIGNMENT_CENTER) - box.append(canvas_button) - - def __clear_button_clicked_cb(self, button): - self.emit('clear-clicked') - - def _clear_message(self): - self.remove(self.child) - self.add(self._scrolled_window) - self._scrolled_window.show() - def update_dates(self): logging.debug('ListView.update_dates') - visible_range = self.tree_view.get_visible_range() + visible_range = self.get_visible_range() if visible_range is None: return path, end_path = visible_range while True: - x, y, width, height = self.tree_view.get_cell_area(path, - self.date_column) - x, y = self.tree_view.convert_tree_to_widget_coords(x, y) - self.tree_view.queue_draw_area(x, y, width, height) + x, y, width, height = self.get_cell_area(path, self.date_column) + x, y = self.convert_tree_to_widget_coords(x, y) + self.queue_draw_area(x, y, width, height) if path == end_path: break else: - next_iter = self._model.iter_next(self._model.get_iter(path)) - path = self._model.get_path(next_iter) - - def _set_dirty(self): - if self._fully_obscured: - self._dirty = True - else: - self.refresh() - - def set_is_visible(self, visible): - logging.debug('canvas_visibility_notify_event_cb %r', visible) - if visible: - self._fully_obscured = False - if self._dirty: - self.refresh() - if self._update_dates_timer is None: - logging.debug('Adding date updating timer') - self._update_dates_timer = \ - gobject.timeout_add_seconds(UPDATE_INTERVAL, - self.__update_dates_timer_cb) - else: - self._fully_obscured = True - if self._update_dates_timer is not None: - logging.debug('Remove date updating timer') - gobject.source_remove(self._update_dates_timer) - self._update_dates_timer = None - - def __update_dates_timer_cb(self): - self.update_dates() - return True - -class ListView(BaseListView): - __gtype_name__ = 'JournalListView' - - __gsignals__ = { - 'detail-clicked': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - ([object])) - } - - def __init__(self): - BaseListView.__init__(self) - - self.cell_title.props.editable = True - self.cell_title.connect('edited', self.__cell_title_edited_cb) - - self.cell_icon.connect('clicked', self.__icon_clicked_cb) - self.cell_icon.connect('detail-clicked', self.__detail_clicked_cb) - - cell_detail = CellRendererDetail(self.tree_view) - cell_detail.connect('clicked', self.__detail_cell_clicked_cb) - - column = gtk.TreeViewColumn('') - column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED - column.props.fixed_width = cell_detail.props.width - column.pack_start(cell_detail) - self.tree_view.append_column(column) + next_iter = self.get_model().iter_next( + self.get_model().get_iter(path)) + path = self.get_model().get_path(next_iter) def __detail_cell_clicked_cb(self, cell, path): - row = self.tree_view.get_model()[path] + row = self.get_model()[path] self.emit('detail-clicked', row[ListModel.COLUMN_UID]) def __detail_clicked_cb(self, cell, uid): self.emit('detail-clicked', uid) def __icon_clicked_cb(self, cell, path): - row = self.tree_view.get_model()[path] + row = self.get_model()[path] metadata = model.get(row[ListModel.COLUMN_UID]) misc.resume(metadata) def __cell_title_edited_cb(self, cell, path, new_text): - row = self._model[path] + row = self.get_model()[path] metadata = model.get(row[ListModel.COLUMN_UID]) metadata['title'] = new_text model.write(metadata, update_mtime=False) |