diff options
Diffstat (limited to 'src/jarabe/journal/view.py')
-rw-r--r-- | src/jarabe/journal/view.py | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/src/jarabe/journal/view.py b/src/jarabe/journal/view.py new file mode 100644 index 0000000..61b11dc --- /dev/null +++ b/src/jarabe/journal/view.py @@ -0,0 +1,292 @@ +# Copyright (C) 2009, Tomeu Vizoso +# Copyright (C) 2010, Aleksey Lim +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import logging +from gettext import gettext as _ +import time + +import gobject +import gtk +import hippo + +from sugar.graphics import style +from sugar.graphics.icon import CanvasIcon +from sugar.graphics.icon import Icon + +from jarabe.journal import model +from jarabe.journal.listview import ListView +from jarabe.journal.thumbsview import ThumbsView + + +UPDATE_INTERVAL = 300 + +VIEW_LIST = 0 +VIEW_THUMBS = 1 +_MESSAGE_PROGRESS = 2 +_MESSAGE_EMPTY_JOURNAL = 3 +_MESSAGE_NO_MATCH = 4 + +PAGE_SIZE = 10 + + +class View(gtk.EventBox): + + __gsignals__ = { + 'clear-clicked': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([])), + 'entry-activated': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([str])), + } + + def __init__(self): + gtk.EventBox.__init__(self) + + self._query = {} + self._result_set = None + self._pages = {} + self._current_page = None + self._view = None + self._last_progress_bar_pulse = None + + self._page_ctors = { + VIEW_LIST: lambda: self._view_new(ListView), + VIEW_THUMBS: lambda: self._view_new(ThumbsView), + _MESSAGE_PROGRESS: self._progress_new, + _MESSAGE_EMPTY_JOURNAL: self._message_new, + _MESSAGE_NO_MATCH: self._message_new, + } + + self.connect('destroy', self.__destroy_cb) + + # Auto-update stuff + self._fully_obscured = True + self._dirty = False + self._update_dates_timer = None + + model.created.connect(self.__model_created_cb) + model.updated.connect(self.__model_updated_cb) + model.deleted.connect(self.__model_deleted_cb) + + self.view = VIEW_LIST + + def get_view(self): + return self._pages[self._view].child + + def set_view(self, view): + if self._page == self._view: + # change view only if current page is view as well + self._page = view + self._view = view + self.view.result_set = self._result_set + + view = property(get_view, set_view) + + def set_hover_selection(self, hover_selection): + for i in self._view_widgets: + i.child.props.hover_selection = hover_selection + + hover_selection = gobject.property(type=bool, default=False, + setter=set_hover_selection) + + def _set_page(self, page): + if self._current_page == page: + return + self._current_page = page + + if page in self._pages: + child = self._pages[page] + else: + child = self._page_ctors[page]() + child.show_all() + self._pages[page] = child + + if self.child is not None: + self.remove(self.child) + self.add(child) + + def _get_page(self): + return self._current_page + + _page = property(_get_page, _set_page) + + def __model_created_cb(self, sender, **kwargs): + self._set_dirty() + + def __model_updated_cb(self, sender, **kwargs): + self._set_dirty() + + def __model_deleted_cb(self, sender, **kwargs): + self._set_dirty() + + def __destroy_cb(self, widget): + if self._result_set is not None: + self._result_set.stop() + + 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('View._refresh query %r', self._query) + + if self._result_set is not None: + self._result_set.stop() + self._dirty = False + + self._result_set = model.find(self._query, PAGE_SIZE) + self._result_set.ready.connect(self.__result_set_ready_cb) + self._result_set.progress.connect(self.__result_set_progress_cb) + self._result_set.setup() + + self._page = self._view + self.view.result_set = self._result_set + + def __result_set_ready_cb(self, **kwargs): + if self._result_set.length == 0: + if self._is_query_empty(): + self._page = _MESSAGE_EMPTY_JOURNAL + else: + self._page = _MESSAGE_NO_MATCH + else: + self._page = self._view + self.view.result_set = self._result_set + + 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 __result_set_progress_cb(self, **kwargs): + if self._page != _MESSAGE_PROGRESS: + self._last_progress_bar_pulse = time.time() + self._page = _MESSAGE_PROGRESS + + if time.time() - self._last_progress_bar_pulse > 0.05: + self.child.pulse() + self._last_progress_bar_pulse = time.time() + + def _view_new(self, view_class): + view = view_class() + view.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color()) + view.connect('entry-activated', self.__entry_activated_cb) + + scrolled_view = gtk.ScrolledWindow() + scrolled_view.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scrolled_view.add(view) + + return scrolled_view + + def _progress_new(self): + alignment = gtk.Alignment(xalign=0.5, yalign=0.5, xscale=0.5) + + progress_bar = gtk.ProgressBar() + progress_bar.props.pulse_step = 0.01 + alignment.add(progress_bar) + + return alignment + + def _message_new(self): + canvas = hippo.Canvas() + + 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 self._page == _MESSAGE_EMPTY_JOURNAL: + text = _('Your Journal is empty') + elif self._page == _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 self._page == _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) + + return canvas + + def __clear_button_clicked_cb(self, button): + self.emit('clear-clicked') + + def update_dates(self): + self.view.refill() + + def _set_dirty(self): + if self._fully_obscured: + self._dirty = True + else: + self.refresh() + + def set_is_visible(self, visible): + if visible != self._fully_obscured: + return + + 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 + + def __entry_activated_cb(self, sender, uid): + self.emit('entry-activated', uid) |