Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGonzalo Odiard <godiard@gmail.com>2012-10-05 20:49:44 (GMT)
committer Gonzalo Odiard <godiard@gmail.com>2012-10-09 13:30:31 (GMT)
commitc411b44e29d2f156ccd2838e5edfbb2655598d97 (patch)
treef79239faf138e2635c843e650a94aa814fa19d57
parent065e32d5ab0c42fcf51336d933cdc99febd3acca (diff)
Show the bookmarks in a tray like in Browse activity
The preview is saved in another table in the sqlite db. Signed-off-by: Gonzalo Odiard <gonzalo@laptop.org>
-rw-r--r--linkbutton.py108
-rw-r--r--readactivity.py119
-rw-r--r--readdb.py53
-rw-r--r--readtoolbar.py17
4 files changed, 294 insertions, 3 deletions
diff --git a/linkbutton.py b/linkbutton.py
new file mode 100644
index 0000000..3fd4579
--- /dev/null
+++ b/linkbutton.py
@@ -0,0 +1,108 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GdkPixbuf
+from gi.repository import GObject
+from gi.repository import Rsvg
+
+import os
+import StringIO
+import cairo
+from gettext import gettext as _
+import re
+import gc
+import logging
+
+from sugar3.graphics.palette import Palette
+from sugar3.graphics.tray import TrayButton
+from sugar3.graphics import style
+
+
+class LinkButton(TrayButton, GObject.GObject):
+ __gtype_name__ = 'LinkButton'
+ __gsignals__ = {
+ 'remove_link': (GObject.SignalFlags.RUN_FIRST,
+ None, ([int])),
+ 'go_to_bookmark': (GObject.SignalFlags.RUN_FIRST,
+ None, ([int])),
+ }
+
+ def __init__(self, buf, color, title, owner, page):
+ TrayButton.__init__(self)
+
+ # Color read from the Journal may be Unicode, but Rsvg needs
+ # it as single byte string:
+ if isinstance(color, unicode):
+ color = str(color)
+ self.set_image(buf, color.split(',')[1], color.split(',')[0])
+
+ self.page = int(page)
+ info = title + '\n' + owner
+ self.setup_rollover_options(info)
+
+ def set_image(self, buf, fill='#0000ff', stroke='#4d4c4f'):
+ img = Gtk.Image()
+ str_buf = StringIO.StringIO(buf)
+ thumb_surface = cairo.ImageSurface.create_from_png(str_buf)
+
+ bg_width, bg_height = style.zoom(120), style.zoom(110)
+ bg_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, bg_width,
+ bg_height)
+ context = cairo.Context(bg_surface)
+ # draw a rectangle in the background with the selected colors
+ context.set_line_width(style.zoom(10))
+ context.set_source_rgba(*style.Color(fill).get_rgba())
+ context.rectangle(0, 0, bg_width, bg_height)
+ context.fill_preserve()
+ context.set_source_rgba(*style.Color(stroke).get_rgba())
+ context.stroke()
+ # add the screenshot
+ dest_x = style.zoom(10)
+ dest_y = style.zoom(20)
+ context.set_source_surface(thumb_surface, dest_x, dest_y)
+ thumb_width, thumb_height = style.zoom(100), style.zoom(80)
+ context.rectangle(dest_x, dest_y, thumb_width, thumb_height)
+ context.fill()
+
+ pixbuf_bg = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0,
+ bg_width, bg_height)
+
+ img.set_from_pixbuf(pixbuf_bg)
+ self.set_icon_widget(img)
+ img.show()
+
+ def setup_rollover_options(self, info):
+ palette = Palette(info, text_maxlen=50)
+ self.set_palette(palette)
+
+ menu_item = Gtk.MenuItem(_('Go to Bookmark'))
+ menu_item.connect('activate', self.go_to_bookmark_cb)
+ palette.menu.append(menu_item)
+ menu_item.show()
+
+ menu_item = Gtk.MenuItem(_('Remove'))
+ menu_item.connect('activate', self.item_remove_cb)
+ palette.menu.append(menu_item)
+ menu_item.show()
+
+ def item_remove_cb(self, widget):
+ self.emit('remove_link', self.page)
+
+ def go_to_bookmark_cb(self, widget):
+ self.emit('go_to_bookmark', self.page)
diff --git a/readactivity.py b/readactivity.py
index 9efdbeb..a4272a5 100644
--- a/readactivity.py
+++ b/readactivity.py
@@ -23,6 +23,8 @@ import time
from gettext import gettext as _
import re
import md5
+import StringIO
+import cairo
import dbus
from gi.repository import GObject
@@ -42,8 +44,10 @@ from sugar3.graphics.toggletoolbutton import ToggleToolButton
from sugar3.graphics.alert import ConfirmationAlert
from sugar3.activity.widgets import ActivityToolbarButton
from sugar3.activity.widgets import StopButton
+from sugar3.graphics.tray import HTray
from sugar3 import network
from sugar3 import mime
+from sugar3 import profile
from sugar3.datastore import datastore
from sugar3.graphics.objectchooser import ObjectChooser
@@ -54,6 +58,7 @@ from readtoolbar import ViewToolbar
from bookmarkview import BookmarkView
from readdb import BookmarkManager
from sugarmenuitem import SugarMenuItem
+from linkbutton import LinkButton
_HARDWARE_MANAGER_INTERFACE = 'org.laptop.HardwareManager'
_HARDWARE_MANAGER_SERVICE = 'org.laptop.HardwareManager'
@@ -151,6 +156,9 @@ class ReadActivity(activity.Activity):
self._bookmark_view.connect('bookmark-changed',
self._update_bookmark_cb)
+ tray = HTray()
+ self.set_tray(tray, Gtk.PositionType.BOTTOM)
+
toolbar_box = ToolbarBox()
self.activity_button = ActivityToolbarButton(self)
@@ -177,6 +185,8 @@ class ReadActivity(activity.Activity):
self.__view_toolbar_go_fullscreen_cb)
self._view_toolbar.connect('toggle-index-show',
self.__toogle_navigator_cb)
+ self._view_toolbar.connect('toggle-tray-show',
+ self.__toogle_tray_cb)
view_toolbar_button = ToolbarButton(
page=self._view_toolbar,
icon_name='toolbar-view')
@@ -444,6 +454,14 @@ class ReadActivity(activity.Activity):
if scrollbar_pos > -1:
self._view.set_vertical_pos(scrollbar_pos)
+ def __toogle_tray_cb(self, button, visible):
+ if visible:
+ logging.error('Show tray')
+ self.tray.show()
+ else:
+ logging.error('Hide tray')
+ self.tray.hide()
+
def __num_page_entry_insert_text_cb(self, entry, text, length, position):
if not re.match('[0-9]', text):
entry.emit_stop_by_name('insert-text')
@@ -853,6 +871,24 @@ class ReadActivity(activity.Activity):
filehash = get_md5(filepath)
self._bookmarkmanager = BookmarkManager(filehash)
+ self._bookmarkmanager.connect('added_bookmark',
+ self._added_bookmark_cb)
+ self._bookmarkmanager.connect('removed_bookmark',
+ self._removed_bookmark_cb)
+
+ # Add the bookmarks to the tray
+ color = profile.get_color().to_string()
+ owner = profile.get_nick_name()
+ for bookmark in self._bookmarkmanager.get_bookmarks():
+ page = bookmark.page_no
+ title = _('Page %d') % page
+ thumb = self._bookmarkmanager.get_bookmark_preview(page)
+ if thumb is None:
+ logging.error('Preview NOT FOUND')
+ thumb = self._get_screenshot()
+ logging.error('Add link to tray page %d preview %s', page, thumb)
+ self._add_link_totray(page, thumb, color, title, owner)
+
self._bookmark_view.set_bookmarkmanager(self._bookmarkmanager)
self._update_toc()
self._view.connect_page_changed_handler(self.__page_changed_cb)
@@ -1042,3 +1078,86 @@ class ReadActivity(activity.Activity):
def __view_toolbar_go_fullscreen_cb(self, view_toolbar):
self.fullscreen()
+
+ def _added_bookmark_cb(self, bookmarkmanager, page):
+ logging.error('Bookmark added page %d', page)
+ title = _('Page %d') % page
+ color = profile.get_color().to_string()
+ owner = profile.get_nick_name()
+ thumb = self._get_screenshot()
+ self._add_link_totray(page, thumb, color, title, owner)
+ bookmarkmanager.add_bookmark_preview(page - 1, thumb)
+
+ def _removed_bookmark_cb(self, bookmarkmanager, page):
+ logging.error('Bookmark removed page %d', page)
+ # remove button from tray
+ for button in self.tray.get_children():
+ if button.page == page:
+ self.tray.remove_item(button)
+ if len(self.tray.get_children()) == 0:
+ self.tray.hide()
+ self._view_toolbar.traybutton.props.active = False
+
+ def _add_link_totray(self, page, buf, color, title, owner):
+ ''' add a link to the tray '''
+ item = LinkButton(buf, color, title, owner, page)
+ item.connect('clicked', self._bookmark_button_clicked_cb, page)
+ item.connect('remove_link', self._bookmark_button_removed_cb)
+ self.tray.show()
+ self.tray.add_item(item)
+ item.show()
+ self._view_toolbar.traybutton.props.active = True
+
+ def _bookmark_button_clicked_cb(self, button, page):
+ self._view.set_current_page(page - 1)
+
+ def _bookmark_button_removed_cb(self, button, page):
+ self._bookmark_view.del_bookmark(page - 1)
+
+ def _get_screenshot(self):
+ """Copied from activity.get_preview()
+ """
+ if self.canvas is None or not hasattr(self.canvas, 'get_window'):
+ return None
+
+ window = self.canvas.get_window()
+ alloc = self.canvas.get_allocation()
+
+ dummy_cr = Gdk.cairo_create(window)
+ target = dummy_cr.get_target()
+ canvas_width, canvas_height = alloc.width, alloc.height
+ screenshot_surface = target.create_similar(cairo.CONTENT_COLOR,
+ canvas_width, canvas_height)
+ del dummy_cr, target
+
+ cr = cairo.Context(screenshot_surface)
+ r, g, b, a_ = style.COLOR_PANEL_GREY.get_rgba()
+ cr.set_source_rgb(r, g, b)
+ cr.paint()
+ self.canvas.draw(cr)
+ del cr
+
+ preview_width, preview_height = style.zoom(100), style.zoom(80)
+ preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ preview_width, preview_height)
+ cr = cairo.Context(preview_surface)
+
+ scale_w = preview_width * 1.0 / canvas_width
+ scale_h = preview_height * 1.0 / canvas_height
+ scale = min(scale_w, scale_h)
+
+ translate_x = int((preview_width - (canvas_width * scale)) / 2)
+ translate_y = int((preview_height - (canvas_height * scale)) / 2)
+
+ cr.translate(translate_x, translate_y)
+ cr.scale(scale, scale)
+
+ cr.set_source_rgba(1, 1, 1, 0)
+ cr.set_operator(cairo.OPERATOR_SOURCE)
+ cr.paint()
+ cr.set_source_surface(screenshot_surface)
+ cr.paint()
+
+ preview_str = StringIO.StringIO()
+ preview_surface.write_to_png(preview_str)
+ return preview_str.getvalue()
diff --git a/readdb.py b/readdb.py
index 41c28ee..1df587f 100644
--- a/readdb.py
+++ b/readdb.py
@@ -21,7 +21,9 @@ import os
import shutil
import sqlite3
import time
+import base64
+from gi.repository import GObject
from sugar3 import profile
from readbookmark import Bookmark
@@ -75,9 +77,24 @@ def _init_db_highlights(conn):
conn.commit()
-class BookmarkManager:
+def _init_db_previews(conn):
+ conn.execute('CREATE TABLE IF NOT EXISTS PREVIEWS ' +
+ '(md5 TEXT, page INTEGER, ' +
+ 'preview)')
+ conn.commit()
+
+
+class BookmarkManager(GObject.GObject):
+
+ __gsignals__ = {
+ 'added_bookmark': (GObject.SignalFlags.RUN_FIRST,
+ None, ([int])),
+ 'removed_bookmark': (GObject.SignalFlags.RUN_FIRST,
+ None, ([int])),
+ }
def __init__(self, filehash):
+ GObject.GObject.__init__(self)
self._filehash = filehash
dbpath = _init_db()
@@ -86,6 +103,7 @@ class BookmarkManager:
self._conn = sqlite3.connect(dbpath)
_init_db_highlights(self._conn)
+ _init_db_previews(self._conn)
self._conn.text_factory = lambda x: unicode(x, "utf-8", "ignore")
@@ -98,6 +116,7 @@ class BookmarkManager:
self._color = profile.get_color().to_string()
def add_bookmark(self, page, content, local=1):
+ logging.debug('add_bookmark page %d', page)
# locale = 0 means that this is a bookmark originally
# created by the person who originally shared the file
timestamp = time.time()
@@ -108,16 +127,40 @@ class BookmarkManager:
self._conn.commit()
self._resync_bookmark_cache()
+ self.emit('added_bookmark', page + 1)
def del_bookmark(self, page):
# We delete only the locally made bookmark
-
+ logging.debug('del_bookmark page %d', page)
t = (self._filehash, page, self._user)
self._conn.execute('delete from bookmarks ' + \
'where md5=? and page=? and user=?', t)
self._conn.commit()
-
+ self._del_bookmark_preview(page)
self._resync_bookmark_cache()
+ self.emit('removed_bookmark', page + 1)
+
+ def add_bookmark_preview(self, page, preview):
+ logging.debug('add_bookmark_preview page %d', page)
+ t = (self._filehash, page, base64.b64encode(preview))
+ self._conn.execute('insert into previews values ' + \
+ '(?, ?, ?)', t)
+ self._conn.commit()
+
+ def _del_bookmark_preview(self, page):
+ logging.debug('del_bookmark_preview page %d', page)
+ t = (self._filehash, page)
+ self._conn.execute('delete from previews ' + \
+ 'where md5=? and page=?', t)
+ self._conn.commit()
+
+ def get_bookmark_preview(self, page):
+ logging.debug('get_bookmark page %d', page)
+ rows = self._conn.execute('select preview from previews ' + \
+ 'where md5=? and page=?', (self._filehash, page))
+ for row in rows:
+ return base64.b64decode(row[0])
+ return None
def _populate_bookmarks(self):
# TODO: Figure out if caching the entire set of bookmarks
@@ -127,6 +170,10 @@ class BookmarkManager:
for row in rows:
self._bookmarks.append(Bookmark(row))
+ logging.debug('loading %d bookmarks', len(self._bookmarks))
+
+ def get_bookmarks(self):
+ return self._bookmarks
def get_bookmarks_for_page(self, page):
bookmarks = []
diff --git a/readtoolbar.py b/readtoolbar.py
index 737c55d..6d1e02b 100644
--- a/readtoolbar.py
+++ b/readtoolbar.py
@@ -167,6 +167,8 @@ class ViewToolbar(Gtk.Toolbar):
([])),
'toggle-index-show': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
([bool])),
+ 'toggle-tray-show': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
+ ([bool])),
}
def __init__(self):
@@ -224,6 +226,14 @@ class ViewToolbar(Gtk.Toolbar):
self.insert(self._fullscreen, -1)
self._fullscreen.show()
+ self.traybutton = ToggleToolButton('tray-show')
+ self.traybutton.set_icon_name('tray-favourite')
+ self.traybutton.connect('toggled', self.__tray_toggled_cb)
+ #self.traybutton.props.sensitive = False
+ self.traybutton.props.active = False
+ self.insert(self.traybutton, -1)
+ self.traybutton.show()
+
self._view_notify_zoom_handler = None
def set_view(self, view):
@@ -275,3 +285,10 @@ class ViewToolbar(Gtk.Toolbar):
def _fullscreen_cb(self, button):
self.emit('go-fullscreen')
+
+ def __tray_toggled_cb(self, button):
+ self.emit('toggle-tray-show', button.get_active())
+ if button.props.active:
+ self.traybutton.set_tooltip(_('Show Tray'))
+ else:
+ self.traybutton.set_tooltip(_('Hide Tray'))