diff --git a/epubadapter.py b/epubadapter.py index 964f915..b03966f 100644 --- a/epubadapter.py +++ b/epubadapter.py @@ -44,6 +44,9 @@ pass def can_zoom_to_width(self): + return False + + def can_highlight(self): return False def connect_zoom_handler(self, handler): diff --git a/evinceadapter.py b/evinceadapter.py index ad79189..c37562c 100644 --- a/evinceadapter.py +++ b/evinceadapter.py @@ -109,6 +109,9 @@ self._model.props.sizing_mode) self.metadata['Read_sizing_mode'] = "fit-width" + def can_highlight(self): + return False + def get_zoom(self): ''' Returns the current zoom level diff --git a/readactivity.py b/readactivity.py index c063027..2a43084 100644 --- a/readactivity.py +++ b/readactivity.py @@ -48,7 +48,7 @@ from readtoolbar import EditToolbar, ViewToolbar from readsidebar import Sidebar from readtopbar import TopBar - +from readdb import BookmarkManager import epubadapter import evinceadapter import textadapter @@ -233,6 +233,16 @@ self._bookmarker.show() toolbar_box.toolbar.insert(bookmark_item, -1) bookmark_item.show() + + self._highlight_item = gtk.ToolItem() + self._highlight = ToggleToolButton('format-text-underline') + self._highlight.set_tooltip(_('Highlight')) + self._highlight.props.sensitive = False + self._highlight_id = self._highlight.connect('clicked', \ + self.__highlight_cb) + self._highlight_item.add(self._highlight) + toolbar_box.toolbar.insert(self._highlight_item, -1) + self._highlight_item.show_all() separator = gtk.SeparatorToolItem() separator.props.draw = False @@ -417,19 +427,45 @@ def __go_forward_page_cb(self, button): self._view.next_page() + def __highlight_cb(self, button): + tuples_list = self._bookmarkmanager.get_highlights( + self._view.get_current_page()) + selection_tuple = self._view.get_selection_bounds() + cursor_position = self._view.get_cursor_position() + + old_highlight_found = None + for compare_tuple in tuples_list: + if selection_tuple: + if selection_tuple[0] >= compare_tuple[0] and \ + selection_tuple[1] <= compare_tuple[1]: + old_highlight_found = compare_tuple + break + if cursor_position >= compare_tuple[0] and \ + cursor_position <= compare_tuple[1]: + old_highlight_found = compare_tuple + break + + if old_highlight_found == None: + self._bookmarkmanager.add_highlight( + self._view.get_current_page(), selection_tuple) + else: + self._bookmarkmanager.del_highlight( + self._view.get_current_page(), old_highlight_found) + + self._view.show_highlights(self._bookmarkmanager.get_highlights( + self._view.get_current_page())) + def __prev_bookmark_activate_cb(self, menuitem): page = self._view.get_current_page() - bookmarkmanager = self._sidebar.get_bookmarkmanager() - - prev_bookmark = bookmarkmanager.get_prev_bookmark_for_page(page) + + prev_bookmark = self._bookmarkmanager.get_prev_bookmark_for_page(page) if prev_bookmark is not None: self._view.set_current_page(prev_bookmark.page_no) def __next_bookmark_activate_cb(self, menuitem): page = self._view.get_current_page() - bookmarkmanager = self._sidebar.get_bookmarkmanager() - - next_bookmark = bookmarkmanager.get_next_bookmark_for_page(page) + + next_bookmark = self._bookmarkmanager.get_next_bookmark_for_page(page) if next_bookmark is not None: self._view.set_current_page(next_bookmark.page_no) @@ -451,6 +487,10 @@ self._bookmarker.props.active = \ self._sidebar.is_showing_local_bookmark() self._bookmarker.handler_unblock(self._bookmarker_toggle_handler_id) + + tuples_list = self._bookmarkmanager.get_highlights( + self._view.get_current_page()) + self._view.show_highlights(tuples_list) def _update_nav_buttons(self): current_page = self._view.get_current_page() @@ -766,17 +806,13 @@ self._topbar.set_view(self._view) filehash = get_md5(filepath) - self._sidebar.set_bookmarkmanager(filehash) - + self._bookmarkmanager = BookmarkManager(filehash) + self._sidebar.set_bookmarkmanager(self._bookmarkmanager) self._update_nav_buttons() self._update_toc() - self._view.connect_page_changed_handler(self.__page_changed_cb) - - self._view.load_metadata(self) - - self._view_toolbar._update_zoom_buttons() + self._update_toolbars() self._edit_toolbar._search_entry.props.text = \ self.metadata.get('Read_search', '') @@ -792,6 +828,11 @@ self._share_document() except Exception, e: _logger.debug('Sharing failed: %s', e) + + def _update_toolbars(self): + self._view_toolbar._update_zoom_buttons() + if not self._view.can_highlight(): + self._highlight_item.hide() def _share_document(self): """Share the document.""" @@ -857,6 +898,33 @@ def _view_selection_changed_cb(self, view): self._edit_toolbar.copy.props.sensitive = view.get_has_selection() + if self._view.can_highlight(): + # Verify if the selection already exist or the cursor + # is in a highlighted area + cursor_position = self._view.get_cursor_position() + logging.debug('cursor position %d' % cursor_position) + selection_tuple = self._view.get_selection_bounds() + tuples_list = self._bookmarkmanager.get_highlights( \ + self._view.get_current_page()) + in_bounds = False + for highlight_tuple in tuples_list: + logging.debug('control tuple %s' % str(highlight_tuple)) + if selection_tuple: + if selection_tuple[0] >= highlight_tuple[0] and \ + selection_tuple[1] <= highlight_tuple[1]: + in_bounds = True + break + if cursor_position >= highlight_tuple[0] and \ + cursor_position <= highlight_tuple[1]: + in_bounds = True + break + + self._highlight.props.sensitive = \ + view.get_has_selection() or in_bounds + + self._highlight.handler_block(self._highlight_id) + self._highlight.set_active(in_bounds) + self._highlight.handler_unblock(self._highlight_id) def _edit_toolbar_copy_cb(self, button): self._view.copy() diff --git a/readdb.py b/readdb.py index fe4ef90..f63564f 100644 --- a/readdb.py +++ b/readdb.py @@ -17,7 +17,7 @@ import logging -import os, os.path +import os import shutil import sqlite3 import time @@ -54,7 +54,8 @@ shutil.copy(olddbpath, dbpath) conn = sqlite3.connect(dbpath) - conn.execute("CREATE TABLE temp_bookmarks AS SELECT md5, page, title 'content', timestamp, user, color, local FROM bookmarks") + conn.execute("CREATE TABLE temp_bookmarks AS SELECT md5, page, " + \ + "title 'content', timestamp, user, color, local FROM bookmarks") conn.execute("ALTER TABLE bookmarks RENAME TO bookmarks_old") conn.execute("ALTER TABLE temp_bookmarks RENAME TO bookmarks") conn.execute("DROP TABLE bookmarks_old") @@ -67,6 +68,13 @@ return None +def _init_db_highlights(conn): + conn.execute('CREATE TABLE IF NOT EXISTS HIGHLIGHTS ' + + '(md5 TEXT, page INTEGER, ' + + 'init_pos INTEGER, end_pos INTEGER)') + conn.commit() + + class BookmarkManager: def __init__(self, filehash): @@ -77,40 +85,46 @@ assert dbpath != None self._conn = sqlite3.connect(dbpath) + _init_db_highlights(self._conn) + self._conn.text_factory = lambda x: unicode(x, "utf-8", "ignore") self._bookmarks = [] self._populate_bookmarks() + self._highlights = {0: []} + self._populate_highlights() + + client = gconf.client_get_default() + self._user = client.get_string("/desktop/sugar/user/nick") + self._color = client.get_string("/desktop/sugar/user/color") def add_bookmark(self, page, content, local=1): # locale = 0 means that this is a bookmark originally # created by the person who originally shared the file timestamp = time.time() - client = gconf.client_get_default() - user = client.get_string("/desktop/sugar/user/nick") - color = client.get_string("/desktop/sugar/user/color") - - t = (self._filehash, page, content, timestamp, user, color, local) - self._conn.execute('insert into bookmarks values (?, ?, ?, ?, ?, ?, ?)', t) + t = (self._filehash, page, content, timestamp, self._user, \ + self._color, local) + self._conn.execute('insert into bookmarks values ' + \ + '(?, ?, ?, ?, ?, ?, ?)', t) self._conn.commit() self._resync_bookmark_cache() def del_bookmark(self, page): - client = gconf.client_get_default() - user = client.get_string("/desktop/sugar/user/nick") - # We delete only the locally made bookmark - t = (self._filehash, page, user) - self._conn.execute('delete from bookmarks where md5=? and page=? and user=?', t) + t = (self._filehash, page, self._user) + self._conn.execute('delete from bookmarks ' + \ + 'where md5=? and page=? and user=?', t) self._conn.commit() self._resync_bookmark_cache() def _populate_bookmarks(self): - # TODO: Figure out if caching the entire set of bookmarks is a good idea or not - rows = self._conn.execute('select * from bookmarks where md5=? order by page', (self._filehash, )) + # TODO: Figure out if caching the entire set of bookmarks + # is a good idea or not + rows = self._conn.execute('select * from bookmarks ' + \ + 'where md5=? order by page', (self._filehash, )) for row in rows: self._bookmarks.append(Bookmark(row)) @@ -155,3 +169,40 @@ return bookmark return None + + def get_highlights(self, page): + try: + return self._highlights[page] + except KeyError: + self._highlights[page] = [] + return self._highlights[page] + + def add_highlight(self, page, highlight_tuple): + logging.error('Adding hg page %d %s' % (page, highlight_tuple)) + self.get_highlights(page).append(highlight_tuple) + + t = (self._filehash, page, highlight_tuple[0], + highlight_tuple[1]) + self._conn.execute('insert into highlights values ' + \ + '(?, ?, ?, ?)', t) + self._conn.commit() + + def del_highlight(self, page, highlight_tuple): + self._highlights[page].remove(highlight_tuple) + t = (self._filehash, page, highlight_tuple[0], \ + highlight_tuple[1]) + self._conn.execute('delete from highlights ' + \ + 'where md5=? and page=? and init_pos=? and end_pos=?', \ + t) + self._conn.commit() + + def _populate_highlights(self): + rows = self._conn.execute('select * from highlights ' + \ + 'where md5=? order by page', (self._filehash, )) + for row in rows: + # md5 = row[0] + page = row[1] + init_pos = row[2] + end_pos = row[3] + highlight_tuple = [init_pos, end_pos] + self.get_highlights(page).append(highlight_tuple) diff --git a/readsidebar.py b/readsidebar.py index c22d462..041b478 100644 --- a/readsidebar.py +++ b/readsidebar.py @@ -145,8 +145,8 @@ self._is_showing_local_bookmark = False - def set_bookmarkmanager(self, filehash): - self._bookmark_manager = BookmarkManager(filehash) + def set_bookmarkmanager(self, bookmark_manager): + self._bookmark_manager = bookmark_manager def get_bookmarkmanager(self): return (self._bookmark_manager) diff --git a/textadapter.py b/textadapter.py index c3709e5..a82c153 100644 --- a/textadapter.py +++ b/textadapter.py @@ -50,6 +50,11 @@ self._zoom = 100 self.font_zoom_relation = self._zoom / self._font_size self._current_page = 0 + + self.highlight_tag = self.textview.get_buffer().create_tag() + self.highlight_tag.set_property('underline', 'single') + self.highlight_tag.set_property('foreground', 'black') + self.highlight_tag.set_property('background', 'yellow') def load_document(self, file_path): self._etext_file = open(file_path.replace('file://', ''), 'r') @@ -87,6 +92,30 @@ textbuffer = self.textview.get_buffer() label_text = label_text + '\n\n\n' textbuffer.set_text(label_text) + + def can_highlight(self): + return True + + def get_selection_bounds(self): + if self.textview.get_buffer().get_selection_bounds(): + begin, end = self.textview.get_buffer().get_selection_bounds() + return [begin.get_offset(), end.get_offset()] + else: + return [] + + def get_cursor_position(self): + insert_mark = self.textview.get_buffer().get_insert() + return self.textview.get_buffer().get_iter_at_mark( \ + insert_mark).get_offset() + + def show_highlights(self, tuples_list): + textbuffer = self.textview.get_buffer() + bounds = textbuffer.get_bounds() + textbuffer.remove_all_tags(bounds[0], bounds[1]) + for highlight_tuple in tuples_list: + iterStart = textbuffer.get_iter_at_offset(highlight_tuple[0]) + iterEnd = textbuffer.get_iter_at_offset(highlight_tuple[1]) + textbuffer.apply_tag(self.highlight_tag, iterStart, iterEnd) def connect_page_changed_handler(self, handler): self.connect('page-changed', handler) @@ -148,7 +177,7 @@ def get_current_file(self): pass - def update_metadata(self): + def update_metadata(self, activity): pass def copy(self):