Bookmark support
Sayamindu Dasgupta
15 years ago
33 | 33 | from sugar.graphics.objectchooser import ObjectChooser |
34 | 34 | |
35 | 35 | from readtoolbar import EditToolbar, ReadToolbar, ViewToolbar |
36 | from readsidebar import Sidebar | |
36 | 37 | |
37 | 38 | _HARDWARE_MANAGER_INTERFACE = 'org.laptop.HardwareManager' |
38 | 39 | _HARDWARE_MANAGER_SERVICE = 'org.laptop.HardwareManager' |
108 | 109 | self._view.set_screen_dpi(_get_screen_dpi()) |
109 | 110 | self._view.connect('notify::has-selection', |
110 | 111 | self._view_notify_has_selection_cb) |
112 | ||
113 | self._sidebar = Sidebar() | |
114 | self._sidebar.show() | |
111 | 115 | |
112 | 116 | toolbox = activity.ActivityToolbox(self) |
113 | 117 | |
121 | 125 | toolbox.add_toolbar(_('Edit'), self._edit_toolbar) |
122 | 126 | self._edit_toolbar.show() |
123 | 127 | |
124 | self._read_toolbar = ReadToolbar(self._view) | |
128 | self._read_toolbar = ReadToolbar(self._view, self._sidebar) | |
125 | 129 | toolbox.add_toolbar(_('Read'), self._read_toolbar) |
126 | 130 | self._read_toolbar.show() |
127 | 131 | |
136 | 140 | self.set_toolbox(toolbox) |
137 | 141 | toolbox.show() |
138 | 142 | |
139 | scrolled = gtk.ScrolledWindow() | |
140 | scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | |
141 | scrolled.props.shadow_type = gtk.SHADOW_NONE | |
142 | ||
143 | scrolled.add(self._view) | |
143 | self._scrolled = gtk.ScrolledWindow() | |
144 | self._scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | |
145 | self._scrolled.props.shadow_type = gtk.SHADOW_NONE | |
146 | ||
147 | self._scrolled.add(self._view) | |
144 | 148 | self._view.show() |
145 | ||
146 | self.set_canvas(scrolled) | |
147 | scrolled.show() | |
149 | ||
150 | hbox = gtk.HBox() | |
151 | hbox.pack_start(self._sidebar, expand=False, fill=False) | |
152 | hbox.pack_start(self._scrolled, expand=True, fill=True) | |
153 | ||
154 | self.set_canvas(hbox) | |
155 | self._scrolled.show() | |
156 | hbox.show() | |
148 | 157 | |
149 | 158 | # Set up for idle suspend |
150 | 159 | self._idle_timer = 0 |
169 | 178 | _HARDWARE_MANAGER_OBJECT_PATH) |
170 | 179 | self._service = dbus.Interface(proxy, |
171 | 180 | _HARDWARE_MANAGER_INTERFACE) |
172 | scrolled.props.vadjustment.connect("value-changed", | |
181 | self._scrolled.props.vadjustment.connect("value-changed", | |
173 | 182 | self._user_action_cb) |
174 | scrolled.props.hadjustment.connect("value-changed", | |
183 | self._scrolled.props.hadjustment.connect("value-changed", | |
175 | 184 | self._user_action_cb) |
176 | 185 | self.connect("focus-in-event", self._focus_in_event_cb) |
177 | 186 | self.connect("focus-out-event", self._focus_out_event_cb) |
446 | 455 | self._want_document = False |
447 | 456 | self._view.set_document(self._document) |
448 | 457 | self._edit_toolbar.set_document(self._document) |
449 | self._read_toolbar.set_document(self._document) | |
458 | self._read_toolbar.set_document(self._document, filepath) | |
450 | 459 | |
451 | 460 | if not self.metadata['title_set_by_user'] == '1': |
452 | 461 | info = self._document.get_info() |
460 | 469 | _logger.debug('Found sizing mode: %s', sizing_mode) |
461 | 470 | if sizing_mode == "best-fit": |
462 | 471 | self._view.props.sizing_mode = evince.SIZING_BEST_FIT |
463 | self._view.update_view_size(self.canvas) | |
472 | self._view.update_view_size(self._scrolled) | |
464 | 473 | elif sizing_mode == "free": |
465 | 474 | self._view.props.sizing_mode = evince.SIZING_FREE |
466 | 475 | self._view.props.zoom = float(self.metadata.get('Read_zoom', '1.0')) |
467 | 476 | _logger.debug('Set zoom to %f', self._view.props.zoom) |
468 | 477 | elif sizing_mode == "fit-width": |
469 | 478 | self._view.props.sizing_mode = evince.SIZING_FIT_WIDTH |
470 | self._view.update_view_size(self.canvas) | |
479 | self._view.update_view_size(self._scrolled) | |
471 | 480 | else: |
472 | 481 | # this may happen when we get a document from a buddy with a later |
473 | 482 | # version of Read, for example. |
577 | 586 | _logger.debug("Keyname Release: %s, time: %s", keyname, event.time) |
578 | 587 | |
579 | 588 | def __view_toolbar_needs_update_size_cb(self, view_toolbar): |
580 | self._view.update_view_size(self.canvas) | |
589 | self._view.update_view_size(self._scrolled) | |
581 | 590 | |
582 | 591 | def __view_toolbar_go_fullscreen_cb(self, view_toolbar): |
583 | 592 | self.fullscreen() |
0 | class Bookmark: | |
1 | def __init__(self, data): | |
2 | self.md5 = data[0] | |
3 | self.page_no = data[1] | |
4 | self.title = data[2] | |
5 | self.timestamp = data[3] | |
6 | self.nick = data[4] | |
7 | self.color = data[5] | |
8 | self.local = data[6] | |
9 | ||
10 | def belongstopage(self, page_no): | |
11 | return self.page_no == page_no | |
12 | ||
13 | def is_local(self): | |
14 | return bool(self.local)⏎ |
0 | import logging | |
1 | ||
2 | import sqlite3 | |
3 | import time | |
4 | ||
5 | import gconf | |
6 | ||
7 | from readbookmark import Bookmark | |
8 | ||
9 | _logger = logging.getLogger('read-activity') | |
10 | ||
11 | class BookmarkManager: | |
12 | def __init__(self, hash, dbpath='read.db'): | |
13 | self._hash = hash | |
14 | self._conn = sqlite3.connect(dbpath) | |
15 | self._cur = self._conn.cursor() | |
16 | ||
17 | self._bookmarks = [] | |
18 | self._populate_bookmarks() | |
19 | ||
20 | def add_bookmark(self, page, title, local=1): | |
21 | # locale = 0 means that this is a bookmark originally | |
22 | # created by the person who originally shared the file | |
23 | timestamp = time.time() | |
24 | client = gconf.client_get_default() | |
25 | user = client.get_string("/desktop/sugar/user/nick") | |
26 | color = client.get_string("/desktop/sugar/user/color") | |
27 | ||
28 | t = (self._hash, page, title, timestamp, user, color, local) | |
29 | self._cur.execute('insert into bookmarks values (?, ?, ?, ?, ?, ?, ?)', t) | |
30 | self._conn.commit() | |
31 | ||
32 | self._resync_bookmark_cache() | |
33 | ||
34 | def del_bookmark(self, page): | |
35 | client = gconf.client_get_default() | |
36 | user = client.get_string("/desktop/sugar/user/nick") | |
37 | ||
38 | # We delete only the locally made bookmark | |
39 | ||
40 | t = (self._hash, page, user) | |
41 | self._cur.execute('delete from bookmarks where md5=? and page=? and user=?', t) | |
42 | self._conn.commit() | |
43 | ||
44 | self._resync_bookmark_cache() | |
45 | ||
46 | def _populate_bookmarks(self): | |
47 | # TODO: Figure out if caching the entire set of bookmarks is a good idea or not | |
48 | self._cur.execute('select * from bookmarks where md5=?', (self._hash,)) | |
49 | ||
50 | for row in self._cur: | |
51 | self._bookmarks.append(Bookmark(row)) | |
52 | ||
53 | def get_bookmarks_for_page(self, page): | |
54 | bookmarks = [] | |
55 | for bookmark in self._bookmarks: | |
56 | if bookmark.belongstopage(page): | |
57 | bookmarks.append(bookmark) | |
58 | ||
59 | return bookmarks | |
60 | ||
61 | def _resync_bookmark_cache(self): | |
62 | # To be called when a new bookmark has been added/removed | |
63 | self._bookmarks = [] | |
64 | self._populate_bookmarks()⏎ |
0 | import logging | |
1 | ||
2 | import gtk | |
3 | ||
4 | from sugar.graphics.icon import Icon | |
5 | from sugar.graphics.xocolor import XoColor | |
6 | ||
7 | from readbookmark import Bookmark | |
8 | from readdb import BookmarkManager | |
9 | ||
10 | from gettext import gettext as _ | |
11 | ||
12 | _logger = logging.getLogger('read-activity') | |
13 | ||
14 | class Sidebar(gtk.EventBox): | |
15 | def __init__(self): | |
16 | gtk.EventBox.__init__(self) | |
17 | self.set_size_request(20, -1) | |
18 | # Take care of the background first | |
19 | white = gtk.gdk.color_parse("white") | |
20 | self.modify_bg(gtk.STATE_NORMAL, white) | |
21 | ||
22 | self._box = gtk.VButtonBox() | |
23 | self._box.set_layout(gtk.BUTTONBOX_CENTER) | |
24 | self.add(self._box) | |
25 | ||
26 | self._box.show() | |
27 | self.show() | |
28 | ||
29 | self._bookmarks = [] | |
30 | self._bookmark_manager = None | |
31 | self._is_showing_local_bookmark = False | |
32 | ||
33 | def _add_bookmark_icon(self, bookmark): | |
34 | xocolor = XoColor(bookmark.color) | |
35 | bookmark_icon = Icon(icon_name = 'emblem-favorite', \ | |
36 | pixel_size = 18, xo_color = xocolor) | |
37 | bookmark_icon.set_tooltip_text(_("Stupid tooltip")) | |
38 | self._box.pack_start(bookmark_icon ,expand=False,fill=False) | |
39 | bookmark_icon.show_all() | |
40 | ||
41 | self._bookmarks.append(bookmark_icon) | |
42 | ||
43 | if bookmark.is_local(): | |
44 | self._is_showing_local_bookmark = True | |
45 | ||
46 | def _clear_bookmarks(self): | |
47 | for bookmark_icon in self._bookmarks: | |
48 | bookmark_icon.hide() #XXX: Is this needed?? | |
49 | bookmark_icon.destroy() | |
50 | ||
51 | self._bookmarks = [] | |
52 | ||
53 | self._is_showing_local_bookmark = False | |
54 | ||
55 | def set_bookmarkmanager(self, filehash): | |
56 | self._bookmark_manager = BookmarkManager(filehash) | |
57 | ||
58 | def update_for_page(self, page): | |
59 | self._clear_bookmarks() | |
60 | if self._bookmark_manager is None: | |
61 | return | |
62 | ||
63 | bookmarks = self._bookmark_manager.get_bookmarks_for_page(page) | |
64 | ||
65 | for bookmark in bookmarks: | |
66 | self._add_bookmark_icon(bookmark) | |
67 | ||
68 | def add_bookmark(self, page): | |
69 | self._bookmark_manager.add_bookmark(page, '') #TODO: Implement title support | |
70 | self.update_for_page(page) | |
71 | ||
72 | def del_bookmark(self, page): | |
73 | self._bookmark_manager.del_bookmark(page) | |
74 | self.update_for_page(page) | |
75 | ||
76 | def is_showing_local_bookmark(self): | |
77 | return self._is_showing_local_bookmark⏎ |
22 | 22 | import gtk |
23 | 23 | import evince |
24 | 24 | |
25 | import md5 | |
26 | ||
25 | 27 | from sugar.graphics.toolbutton import ToolButton |
28 | from sugar.graphics.toggletoolbutton import ToggleToolButton | |
26 | 29 | from sugar.graphics.menuitem import MenuItem |
27 | 30 | from sugar.graphics import iconentry |
28 | 31 | from sugar.activity import activity |
32 | from sugar.graphics.icon import Icon | |
33 | from sugar.graphics.xocolor import XoColor | |
34 | ||
35 | def get_md5(filename): #FIXME: Should be moved somewhere else | |
36 | filename = filename.replace('file://', '') #XXX: hack | |
37 | fh = open(filename) | |
38 | digest = md5.new() | |
39 | while 1: | |
40 | buf = fh.read(4096) | |
41 | if buf == "": | |
42 | break | |
43 | digest.update(buf) | |
44 | fh.close() | |
45 | return digest.hexdigest() | |
46 | ||
29 | 47 | |
30 | 48 | class EditToolbar(activity.EditToolbar): |
31 | 49 | __gtype_name__ = 'EditToolbar' |
163 | 181 | class ReadToolbar(gtk.Toolbar): |
164 | 182 | __gtype_name__ = 'ReadToolbar' |
165 | 183 | |
166 | def __init__(self, evince_view): | |
184 | def __init__(self, evince_view, sidebar): | |
167 | 185 | gtk.Toolbar.__init__(self) |
168 | 186 | |
169 | 187 | self._evince_view = evince_view |
188 | self._sidebar = sidebar | |
170 | 189 | self._document = None |
171 | 190 | |
172 | 191 | self._back = ToolButton('go-previous') |
235 | 254 | self.insert(navitem, -1) |
236 | 255 | navitem.show() |
237 | 256 | |
238 | ||
239 | def set_document(self, document): | |
257 | spacer = gtk.SeparatorToolItem() | |
258 | self.insert(spacer, -1) | |
259 | spacer.show() | |
260 | ||
261 | bookmarkitem = gtk.ToolItem() | |
262 | self._bookmarker = ToggleToolButton('emblem-favorite') | |
263 | self._bookmarker_toggle_handler_id = self._bookmarker.connect('toggled', | |
264 | self._bookmarker_toggled_cb) | |
265 | ||
266 | bookmarkitem.add(self._bookmarker) | |
267 | ||
268 | self.insert(bookmarkitem, -1) | |
269 | bookmarkitem.show_all() | |
270 | ||
271 | def set_document(self, document, filepath): | |
272 | hash = get_md5(filepath) | |
240 | 273 | self._document = document |
241 | 274 | page_cache = self._document.get_page_cache() |
242 | 275 | page_cache.connect('page-changed', self._page_changed_cb) |
243 | 276 | self._update_nav_buttons() |
244 | 277 | self._update_toc() |
278 | self._sidebar.set_bookmarkmanager(hash) | |
245 | 279 | |
246 | 280 | def _num_page_entry_insert_text_cb(self, entry, text, length, position): |
247 | 281 | if not re.match('[0-9]', text): |
268 | 302 | |
269 | 303 | def _go_forward_cb(self, button): |
270 | 304 | self._evince_view.next_page() |
305 | ||
306 | def _bookmarker_toggled_cb(self, button): | |
307 | page = self._document.get_page_cache().get_current_page() | |
308 | if self._bookmarker.props.active: | |
309 | self._sidebar.add_bookmark(page) | |
310 | else: | |
311 | self._sidebar.del_bookmark(page) | |
271 | 312 | |
272 | 313 | def _page_changed_cb(self, page, proxy): |
273 | 314 | self._update_nav_buttons() |
274 | 315 | if hasattr(self._document, 'has_document_links'): |
275 | 316 | if self._document.has_document_links(): |
276 | 317 | self._toc_select_active_page() |
277 | ||
318 | ||
319 | self._sidebar.update_for_page(self._document.get_page_cache().get_current_page()) | |
320 | ||
321 | self._bookmarker.handler_block(self._bookmarker_toggle_handler_id) | |
322 | self._bookmarker.props.active = self._sidebar.is_showing_local_bookmark() | |
323 | self._bookmarker.handler_unblock(self._bookmarker_toggle_handler_id) | |
324 | ||
278 | 325 | def _update_nav_buttons(self): |
279 | 326 | current_page = self._document.get_page_cache().get_current_page() |
280 | 327 | self._back.props.sensitive = current_page > 0 |