diff options
Diffstat (limited to 'src/jarabe/journal/fields.py')
-rw-r--r-- | src/jarabe/journal/fields.py | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/src/jarabe/journal/fields.py b/src/jarabe/journal/fields.py new file mode 100644 index 0000000..a65a75d --- /dev/null +++ b/src/jarabe/journal/fields.py @@ -0,0 +1,426 @@ +# Copyright (C) 2006, Red Hat, Inc. +# Copyright (C) 2007, One Laptop Per Child +# 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 gtk +import gobject +import gconf +import simplejson + +from sugar.graphics import style +from sugar.graphics.xocolor import XoColor +from sugar.graphics.palette import Invoker +from sugar.graphics.palette import WidgetInvoker +from sugar.graphics.icon import Icon +from sugar.graphics.icon import get_surface + +from jarabe.journal.entry import Entry +from jarabe.journal.palettes import BuddyPalette +from jarabe.journal.palettes import ObjectPalette +from jarabe.journal import misc +from jarabe.journal import model +from jarabe.journal import controler +from jarabe.journal import preview + + +class _Button(gtk.Alignment): + + def __init__(self, **kwargs): + gtk.Alignment.__init__(self, xalign=0.5, yalign=0.5, xscale=0, yscale=0) + + self.metadata = None + self.prelight = False + + self.set_size_request(style.GRID_CELL_SIZE, -1) + + box = gtk.EventBox() + box.props.visible_window = False + box.show() + self.add(box) + + self.icon = Icon(**kwargs) + self.icon.show() + box.add(self.icon) + + box.connect('enter-notify-event', self.__enter_notify_event_cb) + box.connect('leave-notify-event', self.__leave_notify_event_cb) + box.connect('button-release-event', self.__button_release_event_cb) + + self.do_colors() + + def fill_in(self, metadata): + self.metadata = metadata + + def do_activate(self): + # stub + pass + + def do_colors(self): + if self.prelight: + self.icon.props.fill_color = style.COLOR_BLACK.get_svg() + else: + self.icon.props.fill_color = style.COLOR_BUTTON_GREY.get_svg() + + def __enter_notify_event_cb(self, widget, event): + x, y = self.get_pointer() + if x < 0 or x >= self.allocation.width or \ + y < 0 or y >= self.allocation.height: + return + self.prelight = True + self.do_colors() + + def __leave_notify_event_cb(self, widget, event): + self.prelight = False + self.do_colors() + + def __button_release_event_cb(self, widget, event): + if self.prelight: + self.do_activate() + + +class KeepIcon(_Button): + + def __init__(self): + self._keep_color = None + + _Button.__init__(self, + icon_name='emblem-favorite', + pixel_size=style.SMALL_ICON_SIZE) + + def fill_in(self, metadata): + _Button.fill_in(self, metadata) + + keep = metadata.get('keep', "") + if keep.isdigit(): + self._set_keep(int(keep)) + else: + self._set_keep(0) + + def do_colors(self): + if self.prelight: + if self._keep_color is None: + self.icon.props.stroke_color = \ + style.COLOR_BUTTON_GREY.get_svg() + self.icon.props.fill_color = style.COLOR_BUTTON_GREY.get_svg() + else: + stroke_color = style.Color(self._keep_color.get_stroke_color()) + fill_color = style.Color(self._keep_color.get_fill_color()) + self.icon.props.stroke_color = fill_color.get_svg() + self.icon.props.fill_color = stroke_color.get_svg() + else: + if self._keep_color is None: + self.icon.props.stroke_color = \ + style.COLOR_BUTTON_GREY.get_svg() + self.icon.props.fill_color = style.COLOR_TRANSPARENT.get_svg() + else: + self.icon.props.xo_color = self._keep_color + + def do_activate(self): + if not model.is_editable(self.metadata): + return + + if self._keep_color is None: + keep = 1 + else: + keep = 0 + + self.metadata['keep'] = str(keep) + model.write(self.metadata, update_mtime=False) + + self._set_keep(keep) + + def _set_keep(self, keep): + if keep: + client = gconf.client_get_default() + color = client.get_string('/desktop/sugar/user/color') + self._keep_color = XoColor(color) + else: + self._keep_color = None + + self.do_colors() + + +class _JournalObject(gtk.EventBox): + + def __init__(self, detail, paint_box): + gtk.EventBox.__init__(self) + + self.metadata = None + self._detail = detail + + self._invoker = WidgetInvoker(self) + self._invoker._position_hint = Invoker.AT_CURSOR + + self.props.visible_window = False + + self.modify_fg(gtk.STATE_NORMAL, + style.COLOR_PANEL_GREY.get_gdk_color()) + + self.connect_after('button-release-event', + self.__button_release_event_cb) + + self.connect('destroy', self.__destroy_cb) + if paint_box: + self.connect_after('expose-event', self.__expose_event_cb) + + # DND stuff + + self._drag = False + self._temp_drag_file_path = None + self.drag_source_set(gtk.gdk.BUTTON1_MASK, + [('text/uri-list', 0, 0), ('journal-object-id', 0, 0)], + gtk.gdk.ACTION_COPY) + self.connect('drag-begin', self.__drag_begin_cb) + self.connect('drag-data-get', self.__drag_data_get_cb) + self.connect('drag-end', self.__drag_end_cb) + + def fill_in(self, metadata): + self.metadata = metadata + self._invoker.palette = None + + def create_palette(self): + if self.metadata is not None: + return ObjectPalette(self.metadata, detail=self._detail) + + def __destroy_cb(self, icon): + if self._invoker is not None: + self._invoker.detach() + + def __expose_event_cb(self, widget, event): + x, y, width, height = self.allocation + fg = self.style.fg_gc[gtk.STATE_NORMAL] + self.window.draw_rectangle(fg, False, x, y, width - 1, height - 1) + + def __drag_begin_cb(self, widget, context): + self._drag = True + + if self._invoker.palette is not None: + self._invoker.palette.popdown(immediate=True) + + surface = get_surface( + file_name=misc.get_icon_name(self.metadata), + xo_color=misc.get_icon_color(self.metadata)) + pixmap, bitmask = _surface_to_pixels(self.window, surface) + + context.set_icon_pixmap(self.get_colormap(), pixmap, bitmask, + surface.get_width() / 2, surface.get_height() / 2) + + def __drag_data_get_cb(self, widget, context, selection, target_type, + event_time): + if selection.target == 'text/uri-list': + # Get hold of a reference so the temp file doesn't get deleted + self._temp_drag_file_path = model.get_file(self.metadata) + logging.debug('putting %r in selection', self._temp_drag_file_path) + selection.set(selection.target, 8, self._temp_drag_file_path) + + elif selection.target == 'journal-object-id': + selection.set(selection.target, 8, self.metadata['uid']) + + def __drag_end_cb(self, widget, context): + self._drag = False + self._temp_drag_file_path = None + + def __button_release_event_cb(self, button, event): + if not self._drag and self.metadata is not None: + misc.resume(self.metadata) + return True + + +class ObjectIcon(_JournalObject): + + def __init__(self, detail=True, paint_box=True, **kwargs): + _JournalObject.__init__(self, detail, paint_box) + + self._icon = Icon(**kwargs) + self._icon.show() + self.add(self._icon) + + def fill_in(self, metadata): + _JournalObject.fill_in(self, metadata) + self._icon.props.file = misc.get_icon_name(metadata) + self._icon.props.xo_color = misc.get_icon_color(metadata) + + +class Thumb(_JournalObject): + + def __init__(self, detail=True, paint_box=True): + _JournalObject.__init__(self, detail, paint_box) + + self._image = gtk.Image() + self._image.show() + self.add(self._image) + + def set_from_pixbuf(self, pixbuf): + self._image.set_from_pixbuf(pixbuf) + + +class Title(Entry): + + def __init__(self, **kwargs): + Entry.__init__(self, **kwargs) + + self.metadata = None + + self.connect_after('focus-out-event', self.__focus_out_event_cb) + + def fill_in(self, metadata): + self.metadata = metadata + self.props.text = metadata.get('title', _('Untitled')) + self.props.editable = model.is_editable(metadata) + + def __focus_out_event_cb(self, widget, event): + old_title = self.metadata.get('title', None) + new_title = self.props.text + + if old_title != new_title: + self.metadata['title'] = new_title + self.metadata['title_set_by_user'] = '1' + model.write(self.metadata, update_mtime=False) + + +class Buddies(gtk.Alignment): + + def __init__(self, buddies_max=None, **kwargs): + gtk.Alignment.__init__(self, **kwargs) + + self._buddies_max = buddies_max + + self._progress = gtk.ProgressBar() + self._progress.modify_bg(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self._progress.show() + + self._buddies = gtk.HBox() + self._buddies.show() + + def fill_in(self, metadata): + if self.child is not None: + self.remove(self.child) + + child = None + + if 'progress' in metadata: + child = self._progress + fraction = int(metadata['progress']) / 100. + self._progress.props.fraction = fraction + + elif 'buddies' in metadata and metadata['buddies']: + child = self._buddies + + buddies = simplejson.loads(metadata['buddies']).values() + buddies = buddies[:self._buddies_max] + + def show(icon, buddy): + icon.set_buddy(buddy) + icon.show() + + for icon in self._buddies: + if buddies: + show(icon, buddies.pop()) + else: + icon.hide() + + for buddy in buddies: + icon = _BuddyIcon() + show(icon, buddy) + self._buddies.add(icon) + + if self.child is not child: + if self.child is not None: + self.remove(self.child) + if child is not None: + self.add(child) + + +class Timestamp(gtk.Label): + + def __init__(self, **kwargs): + gobject.GObject.__init__(self, **kwargs) + self.props.selectable = True + + def fill_in(self, metadata): + self.props.label = misc.get_date(metadata) + + +class DetailsIcon(_Button): + def __init__(self): + _Button.__init__(self, + icon_name='go-right', + pixel_size=style.SMALL_ICON_SIZE, + stroke_color=style.COLOR_TRANSPARENT.get_svg()) + + def do_activate(self): + self.prelight = False + self.do_colors() + controler.details.send(None, uid=self.metadata['uid']) + + +class _BuddyIcon(gtk.EventBox): + + def __init__(self): + gtk.EventBox.__init__(self) + + self.buddy = None + + self.props.visible_window = False + + self._icon = Icon( + icon_name='computer-xo', + pixel_size=style.STANDARD_ICON_SIZE) + self._icon.show() + self.add(self._icon) + + self._invoker = WidgetInvoker(self) + self._invoker._position_hint = Invoker.AT_CURSOR + + self.connect('destroy', self.__destroy_cb) + + def set_buddy(self, buddy): + self.buddy = buddy + self._invoker.palette = None + nick_, color = buddy + self._icon.props.xo_color = XoColor(color) + + def create_palette(self): + return BuddyPalette(self.buddy) + + def __destroy_cb(self, icon): + if self._invoker is not None: + self._invoker.detach() + + +def _surface_to_pixels(drawable, surface): + width = surface.get_width() + height = surface.get_height() + + pixmap = gtk.gdk.Pixmap(drawable, width, height) + pixmap_context = pixmap.cairo_create() + pixmap_context.set_source_surface(surface) + pixmap_context.paint(); + + mask_row_size = (width + 7) / 8 + mask_size = height * mask_row_size + mask_data = '\x00' * mask_size + mask = gtk.gdk.bitmap_create_from_data(drawable, mask_data, width, height) + mask_context = mask.cairo_create() + mask_context.set_source_surface(surface) + mask_context.paint(); + + return pixmap, mask |