diff --git a/.gitignore b/.gitignore index e7f7ec6..1eab28e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ locale MANIFEST dist/ -epubview/.svn/ diff --git a/activity/activity.info b/activity/activity.info index 31a0dba..4b68ae8 100644 --- a/activity/activity.info +++ b/activity/activity.info @@ -4,7 +4,7 @@ icon = activity-read exec = sugar-activity readactivity.ReadActivity activity_version = 118 -mime_types = application/pdf;image/vnd.djvu;image/x.djvu;image/tiff;application/epub+zip;text/plain;application/zip;application/x-cbz +mime_types = application/pdf;image/vnd.djvu;image/x.djvu;image/tiff;text/plain;application/zip;application/x-cbz license = GPLv2+ summary = Use this activity when you are ready to read! Remember to flip your computer around to feel like you are really holding a book! categories = language documents media system diff --git a/activity/mimetypes.xml b/activity/mimetypes.xml deleted file mode 100644 index 5c27572..0000000 --- a/activity/mimetypes.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Epub document - - - diff --git a/epubadapter.py b/epubadapter.py deleted file mode 100644 index c6dcfd3..0000000 --- a/epubadapter.py +++ /dev/null @@ -1,309 +0,0 @@ -from gi.repository import GObject -import logging - -import epubview - -# import speech - -from cStringIO import StringIO - -_logger = logging.getLogger('read-activity') - - -class EpubViewer(epubview.EpubView): - - def __init__(self): - epubview.EpubView.__init__(self) - - def setup(self, activity): - self.set_screen_dpi(activity.dpi) - self.connect('selection-changed', - activity._view_selection_changed_cb) - - activity._hbox.pack_start(self, True, True, 0) - self.show_all() - self._modified_files = [] - - # text to speech initialization - self.current_word = 0 - self.word_tuples = [] - - def load_document(self, file_path): - self.set_document(EpubDocument(self, file_path.replace('file://', ''))) - # speech.highlight_cb = self.highlight_next_word - # speech.reset_cb = self.reset_text_to_speech - # speech.end_text_cb = self.get_more_text - - def load_metadata(self, activity): - - self.metadata = activity.metadata - - if not self.metadata['title_set_by_user'] == '1': - title = self._epub._info._get_title() - if title: - self.metadata['title'] = title - if 'Read_zoom' in self.metadata: - try: - logging.error('Loading zoom %s', self.metadata['Read_zoom']) - self.set_zoom(float(self.metadata['Read_zoom'])) - except: - pass - - def update_metadata(self, activity): - self.metadata = activity.metadata - self.metadata['Read_zoom'] = self.get_zoom() - - def zoom_to_width(self): - pass - - def zoom_to_best_fit(self): - pass - - def zoom_to_actual_size(self): - pass - - def can_zoom_to_width(self): - return False - - def can_highlight(self): - return True - - def show_highlights(self, page): - # we save the highlights in the page as html - pass - - def toggle_highlight(self, highlight): - self._view.set_editable(True) - - if highlight: - self._view.execute_script( - 'document.execCommand("backColor", false, "yellow");') - else: - # need remove the highlight nodes - js = """ - var selObj = window.getSelection(); - var range = selObj.getRangeAt(0); - var node = range.startContainer; - while (node.parentNode != null) { - if (node.localName == "span") { - if (node.hasAttributes()) { - var attrs = node.attributes; - for(var i = attrs.length - 1; i >= 0; i--) { - if (attrs[i].name == "style" && - attrs[i].value == "background-color: yellow;") { - node.removeAttribute("style"); - break; - }; - }; - }; - }; - node = node.parentNode; - };""" - self._view.execute_script(js) - - self._view.set_editable(False) - # mark the file as modified - current_file = self.get_current_file() - logging.error('file %s was modified', current_file) - if current_file not in self._modified_files: - self._modified_files.append(current_file) - GObject.idle_add(self._save_page) - - def _save_page(self): - oldtitle = self._view.get_title() - self._view.execute_script( - "document.title=document.documentElement.innerHTML;") - html = self._view.get_title() - file_path = self.get_current_file().replace('file:///', '/') - logging.error(html) - with open(file_path, 'w') as fd: - header = """ - - """ - fd.write(header) - fd.write(html) - fd.write('') - self._view.execute_script('document.title=%s;' % oldtitle) - - def save(self, file_path): - if self._modified_files: - self._epub.write(file_path) - return True - - return False - - def in_highlight(self): - # Verify if the selection already exist or the cursor - # is in a highlighted area - page_title = self._view.get_title() - js = """ - var selObj = window.getSelection(); - var range = selObj.getRangeAt(0); - var node = range.startContainer; - var onHighlight = false; - while (node.parentNode != null) { - if (node.localName == "span") { - if (node.hasAttributes()) { - var attrs = node.attributes; - for(var i = attrs.length - 1; i >= 0; i--) { - if (attrs[i].name == "style" && - attrs[i].value == "background-color: yellow;") { - onHighlight = true; - }; - }; - }; - }; - node = node.parentNode; - }; - document.title=onHighlight;""" - self._view.execute_script(js) - on_highlight = self._view.get_title() == 'true' - self._view.execute_script('document.title = "%s";' % page_title) - # the second parameter is only used in the text backend - return on_highlight, None - - def can_do_text_to_speech(self): - return False - - def can_rotate(self): - return False - - def get_marked_words(self): - "Adds a mark between each word of text." - i = self.current_word - file_str = StringIO() - file_str.write(' ') - end_range = i + 40 - if end_range > len(self.word_tuples): - end_range = len(self.word_tuples) - for word_tuple in self.word_tuples[self.current_word:end_range]: - file_str.write('' + - word_tuple[2].encode('utf-8')) - i = i + 1 - self.current_word = i - file_str.write('') - return file_str.getvalue() - - def get_more_text(self): - pass - """ - if self.current_word < len(self.word_tuples): - speech.stop() - more_text = self.get_marked_words() - speech.play(more_text) - else: - if speech.reset_buttons_cb is not None: - speech.reset_buttons_cb() - """ - - def reset_text_to_speech(self): - self.current_word = 0 - - def highlight_next_word(self, word_count): - pass - """ - TODO: disabled because javascript can't be executed - with the velocity needed - self.current_word = word_count - self._view.highlight_next_word() - return True - """ - - def connect_zoom_handler(self, handler): - self._zoom_handler = handler - self._view_notify_zoom_handler = \ - self.connect('notify::scale', handler) - return self._view_notify_zoom_handler - - def connect_page_changed_handler(self, handler): - self.connect('page-changed', handler) - - def _try_load_page(self, n): - if self._ready: - self._load_page(n) - return False - else: - return True - - def set_screen_dpi(self, dpi): - return - - def find_set_highlight_search(self, set_highlight_search): - self._view.set_highlight_text_matches(set_highlight_search) - - def set_current_page(self, n): - # When the book is being loaded, calling this does not help - # In such a situation, we go into a loop and try to load the - # supplied page when the book has loaded completely - n += 1 - if self._ready: - self._load_page(n) - else: - GObject.timeout_add(200, self._try_load_page, n) - - def get_current_page(self): - return int(self._loaded_page) - 1 - - def get_current_link(self): - # the _loaded_filename include all the path, - # need only the part included in the link - return self._loaded_filename[len(self._epub._tempdir) + 1:] - - def update_toc(self, activity): - if self._epub.has_document_links(): - activity.show_navigator_button() - activity.set_navigator_model(self._epub.get_links_model()) - return True - else: - return False - - def get_link_iter(self, current_link): - """ - Returns the iter related to a link - """ - link_iter = self._epub.get_links_model().get_iter_first() - - while link_iter is not None and \ - self._epub.get_links_model().get_value(link_iter, 1) \ - != current_link: - link_iter = self._epub.get_links_model().iter_next(link_iter) - return link_iter - - def find_changed(self, job, page=None): - self._find_changed(job) - - def handle_link(self, link): - self._load_file(link) - - def setup_find_job(self, text, updated_cb): - self._find_job = JobFind(document=self._epub, - start_page=0, n_pages=self.get_pagecount(), - text=text, case_sensitive=False) - self._find_updated_handler = self._find_job.connect('updated', - updated_cb) - return self._find_job, self._find_updated_handler - - -class EpubDocument(epubview.Epub): - - def __init__(self, view, docpath): - epubview.Epub.__init__(self, docpath) - self._page_cache = view - - def get_n_pages(self): - return int(self._page_cache.get_pagecount()) - - def has_document_links(self): - return True - - def get_links_model(self): - return self.get_toc_model() - - -class JobFind(epubview.JobFind): - - def __init__(self, document, start_page, n_pages, text, - case_sensitive=False): - epubview.JobFind.__init__(self, document, start_page, n_pages, text, - case_sensitive=False) diff --git a/epubview/__init__.py b/epubview/__init__.py deleted file mode 100644 index 20d9fc6..0000000 --- a/epubview/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2009 One Laptop Per Child -# Author: Sayamindu Dasgupta -# -# 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 - -from epub import _Epub as Epub -from epubview import _View as EpubView -from jobs import _JobFind as JobFind diff --git a/epubview/epub.py b/epubview/epub.py deleted file mode 100644 index 38ccf98..0000000 --- a/epubview/epub.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright 2009 One Laptop Per Child -# Author: Sayamindu Dasgupta -# -# 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 zipfile -import tempfile -import os -import xml.etree.ElementTree as etree -import shutil -import logging - -import navmap -import epubinfo - - -class _Epub(object): - - def __init__(self, _file): - """ - _file: can be either a path to a file (a string) or a file-like object. - """ - self._file = _file - self._zobject = None - self._opfpath = None - self._ncxpath = None - self._basepath = None - self._tempdir = tempfile.mkdtemp() - - if not self._verify(): - print 'Warning: This does not seem to be a valid epub file' - - self._get_opf() - self._get_ncx() - - ncxfile = self._zobject.open(self._ncxpath) - opffile = self._zobject.open(self._opfpath) - self._navmap = navmap.NavMap(opffile, ncxfile, self._basepath) - - opffile = self._zobject.open(self._opfpath) - self._info = epubinfo.EpubInfo(opffile) - - self._unzip() - - def _unzip(self): - # This is broken upto python 2.7 - # self._zobject.extractall(path = self._tempdir) - orig_cwd = os.getcwd() - os.chdir(self._tempdir) - for name in self._zobject.namelist(): - # Some weird zip file entries start with a slash, - # and we don't want to write to the root directory - try: - if name.startswith(os.path.sep): - name = name[1:] - if name.endswith(os.path.sep) or name.endswith('\\'): - os.makedirs(name) - except: - logging.error('ERROR unziping %s', name) - else: - self._zobject.extract(name) - os.chdir(orig_cwd) - - def _get_opf(self): - containerfile = self._zobject.open('META-INF/container.xml') - - tree = etree.parse(containerfile) - root = tree.getroot() - - r_id = './/{urn:oasis:names:tc:opendocument:xmlns:container}rootfile' - for element in root.iterfind(r_id): - if element.get('media-type') == 'application/oebps-package+xml': - self._opfpath = element.get('full-path') - - if self._opfpath.rpartition('/')[0]: - self._basepath = self._opfpath.rpartition('/')[0] + '/' - else: - self._basepath = '' - - containerfile.close() - - def _get_ncx(self): - opffile = self._zobject.open(self._opfpath) - - tree = etree.parse(opffile) - root = tree.getroot() - - spine = root.find('.//{http://www.idpf.org/2007/opf}spine') - tocid = spine.get('toc') - - for element in root.iterfind('.//{http://www.idpf.org/2007/opf}item'): - if element.get('id') == tocid: - self._ncxpath = self._basepath + element.get('href') - - opffile.close() - - def _verify(self): - ''' - Method to crudely check to verify that what we - are dealing with is a epub file or not - ''' - if isinstance(self._file, basestring): - if not os.path.exists(self._file): - return False - - self._zobject = zipfile.ZipFile(self._file) - - if 'mimetype' not in self._zobject.namelist(): - return False - - mtypefile = self._zobject.open('mimetype') - mimetype = mtypefile.readline() - - # Some files seem to have trailing characters - if not mimetype.startswith('application/epub+zip'): - return False - - return True - - def get_toc_model(self): - ''' - Returns a GtkTreeModel representation of the - Epub table of contents - ''' - return self._navmap.get_gtktreestore() - - def get_flattoc(self): - ''' - Returns a flat (linear) list of files to be - rendered. - ''' - return self._navmap.get_flattoc() - - def get_basedir(self): - ''' - Returns the base directory where the contents of the - epub has been unzipped - ''' - return self._tempdir - - def get_info(self): - ''' - Returns a EpubInfo object title - ''' - return self._info.title - - def write(self, file_path): - '''Create the ZIP archive. - The mimetype must be the first file in the archive - and it must not be compressed.''' - - # The EPUB must contain the META-INF and mimetype files at the root, so - # we'll create the archive in the working directory first - # and move it later - current_dir = os.getcwd() - os.chdir(self._tempdir) - - # Open a new zipfile for writing - epub = zipfile.ZipFile(file_path, 'w') - - # Add the mimetype file first and set it to be uncompressed - epub.write('mimetype', compress_type=zipfile.ZIP_STORED) - - # For the remaining paths in the EPUB, add all of their files - # using normal ZIP compression - self._scan_dir('.', epub) - - epub.close() - os.chdir(current_dir) - - def _scan_dir(self, path, epub_file): - for p in os.listdir(path): - logging.error('add file %s', p) - if os.path.isdir(os.path.join(path, p)): - self._scan_dir(os.path.join(path, p), epub_file) - else: - if p != 'mimetype': - epub_file.write( - os.path.join(path, p), - compress_type=zipfile.ZIP_DEFLATED) - - def close(self): - ''' - Cleans up (closes open zip files and deletes - uncompressed content of Epub. - Please call this when a file is being closed or during - application exit. - ''' - self._zobject.close() - shutil.rmtree(self._tempdir) diff --git a/epubview/epubinfo.py b/epubview/epubinfo.py deleted file mode 100644 index 5014be4..0000000 --- a/epubview/epubinfo.py +++ /dev/null @@ -1,114 +0,0 @@ -import xml.etree.ElementTree as etree - - -class EpubInfo(): - - # TODO: Cover the entire DC range - - def __init__(self, opffile): - self._tree = etree.parse(opffile) - self._root = self._tree.getroot() - self._e_metadata = self._root.find( - '{http://www.idpf.org/2007/opf}metadata') - - self.title = self._get_title() - self.creator = self._get_creator() - self.date = self._get_date() - self.subject = self._get_subject() - self.source = self._get_source() - self.rights = self._get_rights() - self.identifier = self._get_identifier() - self.language = self._get_language() - self.summary = self._get_description() - self.cover_image = self._get_cover_image() - - def _get_data(self, tagname): - element = self._e_metadata.find(tagname) - return element.text - - def _get_title(self): - try: - ret = self._get_data('.//{http://purl.org/dc/elements/1.1/}title') - except AttributeError: - return None - - return ret - - def _get_description(self): - try: - ret = self._get_data( - './/{http://purl.org/dc/elements/1.1/}description') - except AttributeError: - return None - - return ret - - def _get_creator(self): - try: - ret = self._get_data( - './/{http://purl.org/dc/elements/1.1/}creator') - except AttributeError: - return None - return ret - - def _get_date(self): - # TODO: iter - try: - ret = self._get_data('.//{http://purl.org/dc/elements/1.1/}date') - except AttributeError: - return None - - return ret - - def _get_source(self): - try: - ret = self._get_data('.//{http://purl.org/dc/elements/1.1/}source') - except AttributeError: - return None - - return ret - - def _get_rights(self): - try: - ret = self._get_data('.//{http://purl.org/dc/elements/1.1/}rights') - except AttributeError: - return None - - return ret - - def _get_identifier(self): - # TODO: iter - element = self._e_metadata.find( - './/{http://purl.org/dc/elements/1.1/}identifier') - - if element is not None: - return {'id': element.get('id'), 'value': element.text} - else: - return None - - def _get_language(self): - try: - ret = self._get_data( - './/{http://purl.org/dc/elements/1.1/}language') - except AttributeError: - return None - - return ret - - def _get_subject(self): - try: - subjectlist = [] - for element in self._e_metadata.iterfind( - './/{http://purl.org/dc/elements/1.1/}subject'): - subjectlist.append(element.text) - except AttributeError: - return None - - return subjectlist - - def _get_cover_image(self): - element = self._e_metadata.find('{http://www.idpf.org/2007/opf}meta') - if element is not None and element.get('name') == 'cover': - return element.get('content') - else: - return None diff --git a/epubview/epubview.py b/epubview/epubview.py deleted file mode 100644 index acf6ceb..0000000 --- a/epubview/epubview.py +++ /dev/null @@ -1,712 +0,0 @@ -# Copyright 2009 One Laptop Per Child -# Author: Sayamindu Dasgupta -# -# 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 - -from gi.repository import Gtk -from gi.repository import GObject -from gi.repository import Gdk -import widgets - -import logging -import os.path -import math -import shutil - -from jobs import _JobPaginator as _Paginator - -LOADING_HTML = ''' -
-

Loading...

-
-''' - - -class _View(Gtk.HBox): - - __gproperties__ = { - 'scale': (GObject.TYPE_FLOAT, 'the zoom level', - 'the zoom level of the widget', - 0.5, 4.0, 1.0, GObject.PARAM_READWRITE), - } - __gsignals__ = { - 'page-changed': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, - ([int, int])), - 'selection-changed': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, - ([])), - } - - def __init__(self): - GObject.threads_init() - Gtk.HBox.__init__(self) - - self.connect("destroy", self._destroy_cb) - - self._ready = False - self._paginator = None - self._loaded_page = -1 - self._file_loaded = True - # self._old_scrollval = -1 - self._loaded_filename = None - self._pagecount = -1 - self.__going_fwd = True - self.__going_back = False - self.__page_changed = False - self._has_selection = False - self.scale = 1.0 - self._epub = None - self._findjob = None - self.__in_search = False - self.__search_fwd = True - self._filelist = None - self._internal_link = None - - self._sw = Gtk.ScrolledWindow() - self._view = widgets._WebView() - self._view.load_string(LOADING_HTML, 'text/html', 'utf-8', '/') - settings = self._view.get_settings() - settings.props.default_font_family = 'DejaVu LGC Serif' - settings.props.enable_plugins = False - settings.props.default_encoding = 'utf-8' - self._view.connect('load-finished', self._view_load_finished_cb) - self._view.connect('scroll-event', self._view_scroll_event_cb) - self._view.connect('key-press-event', self._view_keypress_event_cb) - self._view.connect('selection-changed', - self._view_selection_changed_cb) - self._view.connect_after('populate-popup', - self._view_populate_popup_cb) - self._view.connect('touch-change-page', self.__touch_page_changed_cb) - - self._sw.add(self._view) - self._v_vscrollbar = self._sw.get_vscrollbar() - self._v_scrollbar_value_changed_cb_id = self._v_vscrollbar.connect( - 'value-changed', self._v_scrollbar_value_changed_cb) - self._scrollbar = Gtk.VScrollbar() - self._scrollbar_change_value_cb_id = self._scrollbar.connect( - 'change-value', self._scrollbar_change_value_cb) - - overlay = Gtk.Overlay() - hbox = Gtk.HBox() - overlay.add(hbox) - hbox.add(self._sw) - - self._scrollbar.props.halign = Gtk.Align.END - self._scrollbar.props.valign = Gtk.Align.FILL - overlay.add_overlay(self._scrollbar) - - self.pack_start(overlay, True, True, 0) - - self._view.set_can_default(True) - self._view.set_can_focus(True) - - def map_cp(widget): - widget.setup_touch() - widget.disconnect(self._setup_handle) - - self._setup_handle = self._view.connect('map', map_cp) - - def set_document(self, epubdocumentinstance): - ''' - Sets document (should be a Epub instance) - ''' - self._epub = epubdocumentinstance - GObject.idle_add(self._paginate) - - def do_get_property(self, property): - if property.name == 'has-selection': - return self._has_selection - elif property.name == 'scale': - return self.scale - else: - raise AttributeError('unknown property %s' % property.name) - - def do_set_property(self, property, value): - if property.name == 'scale': - self.__set_zoom(value) - else: - raise AttributeError('unknown property %s' % property.name) - - def get_has_selection(self): - ''' - Returns True if any part of the content is selected - ''' - return self._view.can_copy_clipboard() - - def get_zoom(self): - ''' - Returns the current zoom level - ''' - return self.get_property('scale') * 100.0 - - def set_zoom(self, value): - ''' - Sets the current zoom level - ''' - scrollbar_pos = self.get_vertical_pos() - self._view.set_zoom_level(value / 100.0) - self.set_vertical_pos(scrollbar_pos) - - def _get_scale(self): - ''' - Returns the current zoom level - ''' - return self.get_property('scale') - - def _set_scale(self, value): - ''' - Sets the current zoom level - ''' - self.set_property('scale', value) - - def zoom_in(self): - ''' - Zooms in (increases zoom level by 0.1) - ''' - if self.can_zoom_in(): - scrollbar_pos = self.get_vertical_pos() - self._set_scale(self._get_scale() + 0.1) - self.set_vertical_pos(scrollbar_pos) - return True - else: - return False - - def zoom_out(self): - ''' - Zooms out (decreases zoom level by 0.1) - ''' - if self.can_zoom_out(): - scrollbar_pos = self.get_vertical_pos() - self._set_scale(self._get_scale() - 0.1) - self.set_vertical_pos(scrollbar_pos) - return True - else: - return False - - def get_vertical_pos(self): - """ - Used to save the scrolled position and restore when needed - """ - return self._v_vscrollbar.get_adjustment().get_value() - - def set_vertical_pos(self, position): - """ - Used to save the scrolled position and restore when needed - """ - self._v_vscrollbar.get_adjustment().set_value(position) - - def can_zoom_in(self): - ''' - Returns True if it is possible to zoom in further - ''' - if self.scale < 4: - return True - else: - return False - - def can_zoom_out(self): - ''' - Returns True if it is possible to zoom out further - ''' - if self.scale > 0.5: - return True - else: - return False - - def get_current_page(self): - ''' - Returns the currently loaded page - ''' - return self._loaded_page - - def get_current_file(self): - ''' - Returns the currently loaded XML file - ''' - # return self._loaded_filename - if self._paginator: - return self._paginator.get_file_for_pageno(self._loaded_page) - else: - return None - - def get_pagecount(self): - ''' - Returns the pagecount of the loaded file - ''' - return self._pagecount - - def set_current_page(self, n): - ''' - Loads page number n - ''' - if n < 1 or n > self._pagecount: - return False - self._load_page(n) - return True - - def next_page(self): - ''' - Loads next page if possible - Returns True if transition to next page is possible and done - ''' - if self._loaded_page == self._pagecount: - return False - self._load_next_page() - return True - - def previous_page(self): - ''' - Loads previous page if possible - Returns True if transition to previous page is possible and done - ''' - if self._loaded_page == 1: - return False - self._load_prev_page() - return True - - def scroll(self, scrolltype, horizontal): - ''' - Scrolls through the pages. - Scrolling is horizontal if horizontal is set to True - Valid scrolltypes are: - Gtk.ScrollType.PAGE_BACKWARD, Gtk.ScrollType.PAGE_FORWARD, - Gtk.ScrollType.STEP_BACKWARD, Gtk.ScrollType.STEP_FORWARD - Gtk.ScrollType.STEP_START and Gtk.ScrollType.STEP_STOP - ''' - if scrolltype == Gtk.ScrollType.PAGE_BACKWARD: - self.__going_back = True - self.__going_fwd = False - if not self._do_page_transition(): - self._view.move_cursor(Gtk.MovementStep.PAGES, -1) - elif scrolltype == Gtk.ScrollType.PAGE_FORWARD: - self.__going_back = False - self.__going_fwd = True - if not self._do_page_transition(): - self._view.move_cursor(Gtk.MovementStep.PAGES, 1) - elif scrolltype == Gtk.ScrollType.STEP_BACKWARD: - self.__going_fwd = False - self.__going_back = True - if not self._do_page_transition(): - self._view.move_cursor(Gtk.MovementStep.DISPLAY_LINES, -1) - elif scrolltype == Gtk.ScrollType.STEP_FORWARD: - self.__going_fwd = True - self.__going_back = False - if not self._do_page_transition(): - self._view.move_cursor(Gtk.MovementStep.DISPLAY_LINES, 1) - elif scrolltype == Gtk.ScrollType.START: - self.__going_back = True - self.__going_fwd = False - if not self._do_page_transition(): - self.set_current_page(1) - elif scrolltype == Gtk.ScrollType.END: - self.__going_back = False - self.__going_fwd = True - if not self._do_page_transition(): - self.set_current_page(self._pagecount - 1) - else: - print ('Got unsupported scrolltype %s' % str(scrolltype)) - - def __touch_page_changed_cb(self, widget, forward): - if forward: - self.scroll(Gtk.ScrollType.PAGE_FORWARD, False) - else: - self.scroll(Gtk.ScrollType.PAGE_BACKWARD, False) - - def copy(self): - ''' - Copies the current selection to clipboard. - ''' - self._view.copy_clipboard() - - def find_next(self): - ''' - Highlights the next matching item for current search - ''' - self._view.grab_focus() - - if self._view.search_text(self._findjob.get_search_text(), - self._findjob.get_case_sensitive(), - True, False): - return - else: - path = os.path.join(self._epub.get_basedir(), - self._findjob.get_next_file()) - self.__in_search = True - self.__search_fwd = True - self._load_file(path) - - def find_previous(self): - ''' - Highlights the previous matching item for current search - ''' - self._view.grab_focus() - - if self._view.search_text(self._findjob.get_search_text(), - self._findjob.get_case_sensitive(), - False, False): - return - else: - path = os.path.join(self._epub.get_basedir(), - self._findjob.get_prev_file()) - self.__in_search = True - self.__search_fwd = False - self._load_file(path) - - def _find_changed(self, job): - self._view.grab_focus() - self._findjob = job - self._mark_found_text() - self.find_next() - - def _mark_found_text(self): - self._view.unmark_text_matches() - self._view.mark_text_matches( - self._findjob.get_search_text(), - case_sensitive=self._findjob.get_case_sensitive(), limit=0) - self._view.set_highlight_text_matches(True) - - def __set_zoom(self, value): - self._view.set_zoom_level(value) - self.scale = value - - def _view_populate_popup_cb(self, view, menu): - menu.destroy() # HACK - return - - def _view_selection_changed_cb(self, view): - self.emit('selection-changed') - - def _view_keypress_event_cb(self, view, event): - name = Gdk.keyval_name(event.keyval) - if name == 'Page_Down' or name == 'Down': - self.__going_back = False - self.__going_fwd = True - elif name == 'Page_Up' or name == 'Up': - self.__going_back = True - self.__going_fwd = False - - self._do_page_transition() - - def _view_scroll_event_cb(self, view, event): - if event.direction == Gdk.ScrollDirection.DOWN: - self.__going_back = False - self.__going_fwd = True - elif event.direction == Gdk.ScrollDirection.UP: - self.__going_back = True - self.__going_fwd = False - - self._do_page_transition() - - def _do_page_transition(self): - if self.__going_fwd: - if self._v_vscrollbar.get_value() >= \ - self._v_vscrollbar.props.adjustment.props.upper - \ - self._v_vscrollbar.props.adjustment.props.page_size: - self._load_page(self._loaded_page + 1) - return True - elif self.__going_back: - if self._v_vscrollbar.get_value() == \ - self._v_vscrollbar.props.adjustment.props.lower: - self._load_page(self._loaded_page - 1) - return True - - return False - - def _view_load_finished_cb(self, v, frame): - - self._file_loaded = True - filename = self._view.props.uri.replace('file://', '') - if os.path.exists(filename.replace('xhtml', 'xml')): - # Hack for making javascript work - filename = filename.replace('xhtml', 'xml') - - filename = filename.split('#')[0] # Get rid of anchors - - if self._loaded_page < 1 or filename is None: - return False - - self._loaded_filename = filename - - remfactor = self._paginator.get_remfactor_for_file(filename) - pages = self._paginator.get_pagecount_for_file(filename) - extra = int(math.ceil( - remfactor * self._view.get_page_height() / (pages - remfactor))) - if extra > 0: - self._view.add_bottom_padding(extra) - - if self.__in_search: - self._mark_found_text() - self._view.search_text(self._findjob.get_search_text(), - self._findjob.get_case_sensitive(), - self.__search_fwd, False) - self.__in_search = False - else: - if self.__going_back: - # We need to scroll to the last page - self._scroll_page_end() - else: - self._scroll_page() - - # process_file = True - if self._internal_link is not None: - self._view.go_to_link(self._internal_link) - vertical_pos = \ - self._view.get_vertical_position_element(self._internal_link) - # set the page number based in the vertical position - initial_page = self._paginator.get_base_pageno_for_file(filename) - self._loaded_page = initial_page + int( - vertical_pos / self._paginator.get_single_page_height()) - - # There are epub files, created with Calibre, - # where the link in the index points to the end of the previos - # file to the needed chapter. - # if the link is at the bottom of the page, we open the next file - one_page_height = self._paginator.get_single_page_height() - self._internal_link = None - if vertical_pos > self._view.get_page_height() - one_page_height: - logging.error('bottom page link, go to next file') - next_file = self._paginator.get_next_filename(filename) - if next_file is not None: - logging.error('load next file %s', next_file) - self.__in_search = False - self.__going_back = False - # process_file = False - GObject.idle_add(self._load_file, next_file) - -# if process_file: -# # prepare text to speech -# html_file = open(self._loaded_filename) -# soup = BeautifulSoup.BeautifulSoup(html_file) -# body = soup.find('body') -# tags = body.findAll(text=True) -# self._all_text = ''.join([tag for tag in tags]) -# self._prepare_text_to_speech(self._all_text) - - def _prepare_text_to_speech(self, page_text): - i = 0 - j = 0 - word_begin = 0 - word_end = 0 - ignore_chars = [' ', '\n', u'\r', '_', '[', '{', ']', '}', '|', - '<', '>', '*', '+', '/', '\\'] - ignore_set = set(ignore_chars) - self.word_tuples = [] - len_page_text = len(page_text) - while i < len_page_text: - if page_text[i] not in ignore_set: - word_begin = i - j = i - while j < len_page_text and page_text[j] not in ignore_set: - j = j + 1 - word_end = j - i = j - word_tuple = (word_begin, word_end, - page_text[word_begin: word_end]) - if word_tuple[2] != u'\r': - self.word_tuples.append(word_tuple) - i = i + 1 - - def _scroll_page_end(self): - v_upper = self._v_vscrollbar.props.adjustment.props.upper - # v_page_size = self._v_vscrollbar.props.adjustment.props.page_size - self._v_vscrollbar.set_value(v_upper) - - def _scroll_page(self): - pageno = self._loaded_page - - v_upper = self._v_vscrollbar.props.adjustment.props.upper - v_page_size = self._v_vscrollbar.props.adjustment.props.page_size - - scrollfactor = self._paginator.get_scrollfactor_pos_for_pageno(pageno) - self._v_vscrollbar.set_value((v_upper - v_page_size) * scrollfactor) - - def _paginate(self): - filelist = [] - for i in self._epub._navmap.get_flattoc(): - filelist.append(os.path.join(self._epub._tempdir, i)) - # init files info - self._filelist = filelist - self._paginator = _Paginator(filelist) - self._paginator.connect('paginated', self._paginated_cb) - - def get_filelist(self): - return self._filelist - - def get_tempdir(self): - return self._epub._tempdir - - def _load_next_page(self): - self._load_page(self._loaded_page + 1) - - def _load_prev_page(self): - self._load_page(self._loaded_page - 1) - - def _v_scrollbar_value_changed_cb(self, scrollbar): - if self._loaded_page < 1: - return - scrollval = scrollbar.get_value() - scroll_upper = self._v_vscrollbar.props.adjustment.props.upper - scroll_page_size = self._v_vscrollbar.props.adjustment.props.page_size - - if self.__going_fwd and not self._loaded_page == self._pagecount: - if self._paginator.get_file_for_pageno(self._loaded_page) != \ - self._paginator.get_file_for_pageno(self._loaded_page + 1): - # We don't need this if the next page is in another file - return - - scrollfactor_next = \ - self._paginator.get_scrollfactor_pos_for_pageno( - self._loaded_page + 1) - if scrollval > 0: - scrollfactor = scrollval / (scroll_upper - scroll_page_size) - else: - scrollfactor = 0 - if scrollfactor >= scrollfactor_next: - self._on_page_changed(self._loaded_page, self._loaded_page + 1) - elif self.__going_back and self._loaded_page > 1: - if self._paginator.get_file_for_pageno(self._loaded_page) != \ - self._paginator.get_file_for_pageno(self._loaded_page - 1): - return - - scrollfactor_cur = \ - self._paginator.get_scrollfactor_pos_for_pageno( - self._loaded_page) - if scrollval > 0: - scrollfactor = scrollval / (scroll_upper - scroll_page_size) - else: - scrollfactor = 0 - - if scrollfactor <= scrollfactor_cur: - self._on_page_changed(self._loaded_page, self._loaded_page - 1) - - def _on_page_changed(self, oldpage, pageno): - if oldpage == pageno: - return - self.__page_changed = True - self._loaded_page = pageno - self._scrollbar.handler_block(self._scrollbar_change_value_cb_id) - self._scrollbar.set_value(pageno) - self._scrollbar.handler_unblock(self._scrollbar_change_value_cb_id) - # the indexes in read activity are zero based - self.emit('page-changed', (oldpage - 1), (pageno - 1)) - - def _load_page(self, pageno): - if pageno > self._pagecount or pageno < 1: - # TODO: Cause an exception - return - if self._loaded_page == pageno: - return - - filename = self._paginator.get_file_for_pageno(pageno) - filename = filename.replace('file://', '') - - if filename != self._loaded_filename: - self._loaded_filename = filename - if not self._file_loaded: - # wait until the file is loaded - return - self._file_loaded = False - - """ - TODO: disabled because javascript can't be executed - with the velocity needed - # Copy javascript to highligth text to speech - destpath, destname = os.path.split(filename.replace('file://', '')) - shutil.copy('./epubview/highlight_words.js', destpath) - self._insert_js_reference(filename.replace('file://', ''), - destpath) - IMPORTANT: Find a way to do this without modify the files - now text highlight is implemented and the epub file is saved - """ - - if filename.endswith('xml'): - dest = filename.replace('xml', 'xhtml') - if not os.path.exists(dest): - os.symlink(filename, dest) - self._view.load_uri('file://' + dest) - else: - self._view.load_uri('file://' + filename) - else: - self._loaded_page = pageno - self._scroll_page() - self._on_page_changed(self._loaded_page, pageno) - - def _insert_js_reference(self, file_name, path): - js_reference = '' - o = open(file_name + '.tmp', 'a') - for line in open(file_name): - line = line.replace('', js_reference + '') - o.write(line + "\n") - o.close() - shutil.copy(file_name + '.tmp', file_name) - - def _load_file(self, path): - self._internal_link = None - if path.find('#') > -1: - self._internal_link = path[path.find('#'):] - path = path[:path.find('#')] - - for filepath in self._filelist: - if filepath.endswith(path): - self._view.load_uri('file://' + filepath) - oldpage = self._loaded_page - self._loaded_page = \ - self._paginator.get_base_pageno_for_file(filepath) - self._scroll_page() - self._on_page_changed(oldpage, self._loaded_page) - break - - def _scrollbar_change_value_cb(self, range, scrolltype, value): - if scrolltype == Gtk.ScrollType.STEP_FORWARD: - self.__going_fwd = True - self.__going_back = False - if not self._do_page_transition(): - self._view.move_cursor(Gtk.MovementStep.DISPLAY_LINES, 1) - elif scrolltype == Gtk.ScrollType.STEP_BACKWARD: - self.__going_fwd = False - self.__going_back = True - if not self._do_page_transition(): - self._view.move_cursor(Gtk.MovementStep.DISPLAY_LINES, -1) - elif scrolltype == Gtk.ScrollType.JUMP or \ - scrolltype == Gtk.ScrollType.PAGE_FORWARD or \ - scrolltype == Gtk.ScrollType.PAGE_BACKWARD: - if value > self._scrollbar.props.adjustment.props.upper: - self._load_page(self._pagecount) - else: - self._load_page(round(value)) - else: - print 'Warning: unknown scrolltype %s with value %f' \ - % (str(scrolltype), value) - - # FIXME: This should not be needed here - self._scrollbar.set_value(self._loaded_page) - - if self.__page_changed: - self.__page_changed = False - return False - else: - return True - - def _paginated_cb(self, object): - self._ready = True - - self._pagecount = self._paginator.get_total_pagecount() - self._scrollbar.set_range(1.0, self._pagecount - 1.0) - self._scrollbar.set_increments(1.0, 1.0) - self._view.grab_focus() - self._view.grab_default() - - def _destroy_cb(self, widget): - self._epub.close() diff --git a/epubview/highlight_words.js b/epubview/highlight_words.js deleted file mode 100644 index ffa5e9a..0000000 --- a/epubview/highlight_words.js +++ /dev/null @@ -1,89 +0,0 @@ - var parentElement; - var actualChild; - var actualWord; - var words; - var originalNode = null; - var modifiedNode = null; - - function trim(s) { - s = ( s || '' ).replace( /^\s+|\s+$/g, '' ); - return s.replace(/[\n\r\t]/g,' '); - } - - - function init() { - parentElement = document.getElementsByTagName("body")[0]; - actualChild = new Array(); - actualWord = 0; - actualChild.push(0); - } - - function highLightNextWordInt() { - var nodeList = parentElement.childNodes; - ini_posi = actualChild[actualChild.length - 1]; - for (var i=ini_posi; i < nodeList.length; i++) { - var node = nodeList[i]; - if ((node.nodeName == "#text") && (trim(node.nodeValue) != '')) { - node_text = trim(node.nodeValue); - words = node_text.split(" "); - if (actualWord < words.length) { - originalNode = document.createTextNode(node.nodeValue); - - prev_text = ''; - for (var p1 = 0; p1 < actualWord; p1++) { - prev_text = prev_text + words[p1] + " "; - } - var textNode1 = document.createTextNode(prev_text); - var textNode2 = document.createTextNode(words[actualWord]+" "); - post_text = ''; - for (var p2 = actualWord + 1; p2 < words.length; p2++) { - post_text = post_text + words[p2] + " "; - } - var textNode3 = document.createTextNode(post_text); - var newParagraph = document.createElement('p'); - var boldNode = document.createElement('b'); - boldNode.appendChild(textNode2); - newParagraph.appendChild(textNode1); - newParagraph.appendChild(boldNode); - newParagraph.appendChild(textNode3); - - parentElement.insertBefore(newParagraph, node); - parentElement.removeChild(node); - modifiedNode = newParagraph; - - actualWord = actualWord + 1; - if (actualWord >= words.length) { - actualChild.pop(); - actualChild[actualChild.length - 1] = actualChild[actualChild.length - 1] + 2; - actualWord = 0; - parentElement = parentElement.parentNode; - } - } - throw "exit"; - } else { - if (node.childNodes.length > 0) { - parentElement = node; - actualChild.push(0); - actualWord = 0; - highLightNextWordInt(); - actualChild.pop(); - } - } - } - return; - } - - - function highLightNextWord() { - if (typeof parentElement == "undefined") { - init(); - } - if (originalNode != null) { - modifiedNode.parentNode.insertBefore(originalNode, modifiedNode); - modifiedNode.parentNode.removeChild(modifiedNode); - } - try { - highLightNextWordInt(); - } catch(er) { - } - } diff --git a/epubview/jobs.py b/epubview/jobs.py deleted file mode 100644 index e8a5762..0000000 --- a/epubview/jobs.py +++ /dev/null @@ -1,327 +0,0 @@ -# Copyright 2009 One Laptop Per Child -# Author: Sayamindu Dasgupta -# -# 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 - - -from gi.repository import GObject -from gi.repository import Gtk -import widgets -import math -import os.path -import xml.etree.ElementTree as etree - -import threading - -PAGE_WIDTH = 135 -PAGE_HEIGHT = 216 - - -def _pixel_to_mm(pixel, dpi): - inches = pixel / dpi - return int(inches / 0.03937) - - -def _mm_to_pixel(mm, dpi): - inches = mm * 0.03937 - return int(inches * dpi) - - -class SearchThread(threading.Thread): - - def __init__(self, obj): - threading.Thread.__init__(self) - self.obj = obj - self.stopthread = threading.Event() - - def _start_search(self): - for entry in self.obj.flattoc: - if self.stopthread.isSet(): - break - filepath = os.path.join(self.obj._document.get_basedir(), entry) - f = open(filepath) - if self._searchfile(f): - self.obj._matchfilelist.append(entry) - f.close() - - self.obj._finished = True - GObject.idle_add(self.obj.emit, 'updated') - - return False - - def _searchfile(self, fileobj): - tree = etree.parse(fileobj) - root = tree.getroot() - - body = None - for child in root: - if child.tag.endswith('body'): - body = child - - if body is None: - return False - - for child in body.iter(): - if child.text is not None: - if child.text.lower().find(self.obj._text.lower()) > -1: - return True - - return False - - def run(self): - self._start_search() - - def stop(self): - self.stopthread.set() - - -class _JobPaginator(GObject.GObject): - - __gsignals__ = { - 'paginated': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ([])), - } - - def __init__(self, filelist): - GObject.GObject.__init__(self) - - self._filelist = filelist - self._filedict = {} - self._pagemap = {} - - self._bookheight = 0 - self._count = 0 - self._pagecount = 0 - - # TODO - """ - self._screen = Gdk.Screen.get_default() - self._old_fontoptions = self._screen.get_font_options() - options = cairo.FontOptions() - options.set_hint_style(cairo.HINT_STYLE_MEDIUM) - options.set_antialias(cairo.ANTIALIAS_GRAY) - options.set_subpixel_order(cairo.SUBPIXEL_ORDER_DEFAULT) - options.set_hint_metrics(cairo.HINT_METRICS_DEFAULT) - self._screen.set_font_options(options) - """ - - self._temp_win = Gtk.Window() - self._temp_view = widgets._WebView(only_to_measure=True) - - settings = self._temp_view.get_settings() - settings.props.default_font_family = 'DejaVu LGC Serif' - settings.props.sans_serif_font_family = 'DejaVu LGC Sans' - settings.props.serif_font_family = 'DejaVu LGC Serif' - settings.props.monospace_font_family = 'DejaVu LGC Sans Mono' - settings.props.enforce_96_dpi = True - # FIXME: This does not seem to work - # settings.props.auto_shrink_images = False - settings.props.enable_plugins = False - settings.props.default_font_size = 12 - settings.props.default_monospace_font_size = 10 - settings.props.default_encoding = 'utf-8' - - sw = Gtk.ScrolledWindow() - sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER) - self._dpi = 96 - self._single_page_height = _mm_to_pixel(PAGE_HEIGHT, self._dpi) - sw.set_size_request(_mm_to_pixel(PAGE_WIDTH, self._dpi), - self._single_page_height) - sw.add(self._temp_view) - self._temp_win.add(sw) - self._temp_view.connect('load-finished', self._page_load_finished_cb) - - self._temp_win.show_all() - self._temp_win.unmap() - - self._temp_view.open(self._filelist[self._count]) - - def get_single_page_height(self): - """ - Returns the height in pixels of a single page - """ - return self._single_page_height - - def get_next_filename(self, actual_filename): - for n in range(len(self._filelist)): - filename = self._filelist[n] - if filename == actual_filename: - if n < len(self._filelist): - return self._filelist[n + 1] - return None - - def _page_load_finished_cb(self, v, frame): - f = v.get_main_frame() - pageheight = v.get_page_height() - - if pageheight <= self._single_page_height: - pages = 1 - else: - pages = pageheight / float(self._single_page_height) - for i in range(1, int(math.ceil(pages) + 1)): - if pages - i < 0: - pagelen = (pages - math.floor(pages)) / pages - else: - pagelen = 1 / pages - self._pagemap[float(self._pagecount + i)] = \ - (f.props.uri, (i - 1) / math.ceil(pages), pagelen) - - self._pagecount += int(math.ceil(pages)) - self._filedict[f.props.uri.replace('file://', '')] = \ - (math.ceil(pages), math.ceil(pages) - pages) - self._bookheight += pageheight - - if self._count + 1 >= len(self._filelist): - # TODO - # self._screen.set_font_options(self._old_fontoptions) - self.emit('paginated') - GObject.idle_add(self._cleanup) - else: - self._count += 1 - self._temp_view.open(self._filelist[self._count]) - - def _cleanup(self): - self._temp_win.destroy() - - def get_file_for_pageno(self, pageno): - ''' - Returns the file in which pageno occurs - ''' - return self._pagemap[pageno][0] - - def get_scrollfactor_pos_for_pageno(self, pageno): - ''' - Returns the position scrollfactor (fraction) for pageno - ''' - return self._pagemap[pageno][1] - - def get_scrollfactor_len_for_pageno(self, pageno): - ''' - Returns the length scrollfactor (fraction) for pageno - ''' - return self._pagemap[pageno][2] - - def get_pagecount_for_file(self, filename): - ''' - Returns the number of pages in file - ''' - return self._filedict[filename][0] - - def get_base_pageno_for_file(self, filename): - ''' - Returns the pageno which begins in filename - ''' - for key in self._pagemap.keys(): - if self._pagemap[key][0].replace('file://', '') == filename: - return key - - return None - - def get_remfactor_for_file(self, filename): - ''' - Returns the remainder - factor (1 - fraction length of last page in file) - ''' - return self._filedict[filename][1] - - def get_total_pagecount(self): - ''' - Returns the total pagecount for the Epub file - ''' - return self._pagecount - - def get_total_height(self): - ''' - Returns the total height of the Epub in pixels - ''' - return self._bookheight - - -class _JobFind(GObject.GObject): - __gsignals__ = { - 'updated': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ([])), - } - - def __init__(self, document, start_page, n_pages, text, - case_sensitive=False): - """ - Only case_sensitive=False is implemented - """ - GObject.GObject.__init__(self) - - self._finished = False - self._document = document - self._start_page = start_page - self._n_pages = n_pages - self._text = text - self._case_sensitive = case_sensitive - self.flattoc = self._document.get_flattoc() - self._matchfilelist = [] - self._current_file_index = 0 - self.threads = [] - - s_thread = SearchThread(self) - self.threads.append(s_thread) - s_thread.start() - - def cancel(self): - ''' - Cancels the search job - ''' - for s_thread in self.threads: - s_thread.stop() - - def is_finished(self): - ''' - Returns True if the entire search job has been finished - ''' - return self._finished - - def get_next_file(self): - ''' - Returns the next file which has the search pattern - ''' - self._current_file_index += 1 - try: - path = self._matchfilelist[self._current_file_index] - except IndexError: - self._current_file_index = 0 - path = self._matchfilelist[self._current_file_index] - - return path - - def get_prev_file(self): - ''' - Returns the previous file which has the search pattern - ''' - self._current_file_index -= 1 - try: - path = self._matchfilelist[self._current_file_index] - except IndexError: - self._current_file_index = -1 - path = self._matchfilelist[self._current_file_index] - - return path - - def get_search_text(self): - ''' - Returns the search text - ''' - return self._text - - def get_case_sensitive(self): - ''' - Returns True if the search is case-sensitive - ''' - return self._case_sensitive diff --git a/epubview/navmap.py b/epubview/navmap.py deleted file mode 100644 index bbb1f44..0000000 --- a/epubview/navmap.py +++ /dev/null @@ -1,102 +0,0 @@ -import xml.etree.ElementTree as etree -from gi.repository import Gtk - - -class NavPoint(object): - - def __init__(self, label, contentsrc, children=[]): - self._label = label - self._contentsrc = contentsrc - self._children = children - - def get_label(self): - return self._label - - def get_contentsrc(self): - return self._contentsrc - - def get_children(self): - return self._children - - -class NavMap(object): - def __init__(self, opffile, ncxfile, basepath): - self._basepath = basepath - self._opffile = opffile - self._tree = etree.parse(ncxfile) - self._root = self._tree.getroot() - self._gtktreestore = Gtk.TreeStore(str, str) - self._flattoc = [] - - self._populate_flattoc() - self._populate_toc() - - def _populate_flattoc(self): - tree = etree.parse(self._opffile) - root = tree.getroot() - - itemmap = {} - manifest = root.find('.//{http://www.idpf.org/2007/opf}manifest') - for element in manifest.iterfind('{http://www.idpf.org/2007/opf}item'): - itemmap[element.get('id')] = element - - spine = root.find('.//{http://www.idpf.org/2007/opf}spine') - for element in spine.iterfind('{http://www.idpf.org/2007/opf}itemref'): - idref = element.get('idref') - href = itemmap[idref].get('href') - self._flattoc.append(self._basepath + href) - - self._opffile.close() - - def _populate_toc(self): - navmap = self._root.find( - '{http://www.daisy.org/z3986/2005/ncx/}navMap') - for navpoint in navmap.iterfind( - './{http://www.daisy.org/z3986/2005/ncx/}navPoint'): - self._process_navpoint(navpoint) - - def _gettitle(self, navpoint): - text = navpoint.find( - './{http://www.daisy.org/z3986/2005/ncx/}' + - 'navLabel/{http://www.daisy.org/z3986/2005/ncx/}text') - return text.text - - def _getcontent(self, navpoint): - text = navpoint.find( - './{http://www.daisy.org/z3986/2005/ncx/}content') - if text is not None: - return self._basepath + text.get('src') - else: - return "" - - def _process_navpoint(self, navpoint, parent=None): - title = self._gettitle(navpoint) - content = self._getcontent(navpoint) - - # print title, content - - iter = self._gtktreestore.append(parent, [title, content]) - # self._flattoc.append((title, content)) - - childnavpointlist = list(navpoint.iterfind( - './{http://www.daisy.org/z3986/2005/ncx/}navPoint')) - - if len(childnavpointlist): - for childnavpoint in childnavpointlist: - self._process_navpoint(childnavpoint, parent=iter) - else: - return - - def get_gtktreestore(self): - ''' - Returns a GtkTreeModel representation of the - Epub table of contents - ''' - return self._gtktreestore - - def get_flattoc(self): - ''' - Returns a flat (linear) list of files to be - rendered. - ''' - return self._flattoc diff --git a/epubview/widgets.py b/epubview/widgets.py deleted file mode 100644 index ff9de7c..0000000 --- a/epubview/widgets.py +++ /dev/null @@ -1,117 +0,0 @@ -import logging - -import gi -gi.require_version('WebKit', '3.0') - -from gi.repository import WebKit -from gi.repository import Gdk -from gi.repository import GObject - - -class _WebView(WebKit.WebView): - - __gsignals__ = { - 'touch-change-page': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, - ([bool])), } - - def __init__(self, only_to_measure=False): - WebKit.WebView.__init__(self) - self._only_to_measure = only_to_measure - - def setup_touch(self): - self.get_window().set_events( - self.get_window().get_events() | Gdk.EventMask.TOUCH_MASK) - self.connect('event', self.__event_cb) - - def __event_cb(self, widget, event): - if event.type == Gdk.EventType.TOUCH_BEGIN: - x = event.touch.x - view_width = widget.get_allocation().width - if x > view_width * 3 / 4: - self.emit('touch-change-page', True) - elif x < view_width * 1 / 4: - self.emit('touch-change-page', False) - - def get_page_height(self): - ''' - Gets height (in pixels) of loaded (X)HTML page. - This is done via javascript at the moment - ''' - hide_scrollbar_js = '' - if self._only_to_measure: - hide_scrollbar_js = \ - 'document.documentElement.style.overflow = "hidden";' - - oldtitle = self.get_main_frame().get_title() - - js = """ - document.documentElement.style.margin = "50px"; - if (document.body == null) { - document.title = 0; - } else { - %s - document.title=Math.max(document.body.scrollHeight, - document.body.offsetHeight, - document.documentElement.clientHeight, - document.documentElement.scrollHeight, - document.documentElement.offsetHeight); - }; - """ % hide_scrollbar_js - self.execute_script(js) - ret = self.get_main_frame().get_title() - self.execute_script('document.title=%s;' % oldtitle) - try: - return int(ret) - except ValueError: - return 0 - - def add_bottom_padding(self, incr): - ''' - Adds incr pixels of padding to the end of the loaded (X)HTML page. - This is done via javascript at the moment - ''' - js = """ - var newdiv = document.createElement("div"); - newdiv.style.height = "%dpx"; - document.body.appendChild(newdiv); - """ % incr - self.execute_script(js) - - def highlight_next_word(self): - ''' - Highlight next word (for text to speech) - ''' - self.execute_script('highLightNextWord();') - - def go_to_link(self, id_link): - self.execute_script('window.location.href = "%s";' % id_link) - - def get_vertical_position_element(self, id_link): - ''' - Get the vertical position of a element, in pixels - ''' - # remove the first '#' char - id_link = id_link[1:] - oldtitle = self.get_main_frame().get_title() - js = """ - obj = document.getElementById('%s'); - var top = 0; - if(obj.offsetParent) { - while(1) { - top += obj.offsetTop; - if(!obj.offsetParent) { - break; - }; - obj = obj.offsetParent; - }; - } else if(obj.y) { - top += obj.y; - }; - document.title=top;""" % id_link - self.execute_script(js) - ret = self.get_main_frame().get_title() - self.execute_script('document.title=%s;' % oldtitle) - try: - return int(ret) - except ValueError: - return 0 diff --git a/readactivity.py b/readactivity.py index 2d78f83..6143876 100644 --- a/readactivity.py +++ b/readactivity.py @@ -822,7 +822,7 @@ del self.unused_download_tubes # Use the suggested file, the mime is not recognized if the extension - # is wrong in some cases (epub) + # is wrong in some cases temp_dir = os.path.dirname(tempfile) new_name = os.path.join(temp_dir, suggested_name) os.rename(tempfile, new_name) @@ -976,10 +976,7 @@ else: mimetype = self.metadata['mime_type'] - if mimetype == 'application/epub+zip': - import epubadapter - self._view = epubadapter.EpubViewer() - elif mimetype == 'text/plain' or mimetype == 'application/zip': + if mimetype == 'text/plain' or mimetype == 'application/zip': import textadapter self._view = textadapter.TextViewer() elif mimetype == 'application/x-cbz':