Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi_G <andigros72@googlemail.com>2011-07-24 00:44:57 (GMT)
committer Andi_G <andigros72@googlemail.com>2011-07-24 00:44:57 (GMT)
commit3183c8fa15aadf9d6363fd49a9ee706ef696444b (patch)
tree6922b02e242e2335ed1452fe8aea447617299da3
parent06ae426ec0a44b7daecdfab54710e9d6181f2566 (diff)
added missing files
-rw-r--r--epubview/__init__.pycbin383 -> 0 bytes
-rw-r--r--epubview/epub.pycbin4960 -> 0 bytes
-rw-r--r--epubview/epubinfo.pycbin3644 -> 0 bytes
-rw-r--r--epubview/epubview.pycbin19504 -> 0 bytes
-rw-r--r--epubview/highlight_words.js89
-rw-r--r--epubview/jobs.pycbin10512 -> 0 bytes
-rw-r--r--epubview/navmap.pycbin4546 -> 0 bytes
-rw-r--r--epubview/widgets.pycbin1778 -> 0 bytes
-rw-r--r--evinceadapter.py259
-rw-r--r--speech.py44
-rw-r--r--textadapter.py516
11 files changed, 908 insertions, 0 deletions
diff --git a/epubview/__init__.pyc b/epubview/__init__.pyc
deleted file mode 100644
index 2c23dd5..0000000
--- a/epubview/__init__.pyc
+++ /dev/null
Binary files differ
diff --git a/epubview/epub.pyc b/epubview/epub.pyc
deleted file mode 100644
index ad0d223..0000000
--- a/epubview/epub.pyc
+++ /dev/null
Binary files differ
diff --git a/epubview/epubinfo.pyc b/epubview/epubinfo.pyc
deleted file mode 100644
index fdf1ad8..0000000
--- a/epubview/epubinfo.pyc
+++ /dev/null
Binary files differ
diff --git a/epubview/epubview.pyc b/epubview/epubview.pyc
deleted file mode 100644
index abbada9..0000000
--- a/epubview/epubview.pyc
+++ /dev/null
Binary files differ
diff --git a/epubview/highlight_words.js b/epubview/highlight_words.js
new file mode 100644
index 0000000..ffa5e9a
--- /dev/null
+++ b/epubview/highlight_words.js
@@ -0,0 +1,89 @@
+ 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.pyc b/epubview/jobs.pyc
deleted file mode 100644
index 4ba8785..0000000
--- a/epubview/jobs.pyc
+++ /dev/null
Binary files differ
diff --git a/epubview/navmap.pyc b/epubview/navmap.pyc
deleted file mode 100644
index 8eb322b..0000000
--- a/epubview/navmap.pyc
+++ /dev/null
Binary files differ
diff --git a/epubview/widgets.pyc b/epubview/widgets.pyc
deleted file mode 100644
index cffed84..0000000
--- a/epubview/widgets.pyc
+++ /dev/null
Binary files differ
diff --git a/evinceadapter.py b/evinceadapter.py
new file mode 100644
index 0000000..632ff96
--- /dev/null
+++ b/evinceadapter.py
@@ -0,0 +1,259 @@
+import gobject
+import logging
+import gtk
+
+import evince
+
+_logger = logging.getLogger('read-activity')
+
+
+class EvinceViewer():
+
+ def __init__(self):
+ self._view_notify_zoom_handler = None
+ self._view = evince.View()
+
+ def setup(self, activity):
+ self._activity = activity
+ self._view.connect('selection-changed',
+ activity._view_selection_changed_cb)
+
+ activity._scrolled = gtk.ScrolledWindow()
+ activity._scrolled.set_policy(gtk.POLICY_AUTOMATIC,
+ gtk.POLICY_AUTOMATIC)
+ activity._scrolled.props.shadow_type = gtk.SHADOW_NONE
+
+ activity._scrolled.add(self._view)
+ self._view.show()
+
+ activity._hbox.pack_start(activity._scrolled, expand=True, fill=True)
+ activity._scrolled.show()
+
+ self.dpi = activity.dpi
+
+ def load_document(self, file_path):
+ try:
+ self._document = evince.document_factory_get_document(file_path)
+ except gobject.GError, e:
+ _logger.error('Can not load document: %s', e)
+ return
+ else:
+ self._model = evince.DocumentModel()
+ self._model.set_document(self._document)
+ self._view.set_model(self._model)
+
+ # set dpi
+ min_scale = self._model.get_min_scale()
+ max_scale = self._model.get_max_scale()
+ self._model.set_min_scale(min_scale * self.dpi / 72.0)
+ self._model.set_max_scale(max_scale * self.dpi / 72.0)
+
+ def get_current_page(self):
+ return self._model.props.page
+
+ def set_current_page(self, page):
+ if page >= self._document.get_n_pages():
+ page = self._document.get_n_pages() - 1
+ elif page < 0:
+ page = 0
+ self._model.props.page = page
+
+ def get_pagecount(self):
+ '''
+ Returns the pagecount of the loaded file
+ '''
+ return self._document.get_n_pages()
+
+ def load_metadata(self, activity):
+
+ self.metadata = activity.metadata
+
+ if not self.metadata['title_set_by_user'] == '1':
+ title = self._document.get_title()
+ if title:
+ self.metadata['title'] = title
+
+ sizing_mode = self.metadata.get('Read_sizing_mode', 'fit-width')
+ _logger.debug('Found sizing mode: %s', sizing_mode)
+ if sizing_mode == "best-fit":
+ self._model.props.sizing_mode = evince.SIZING_BEST_FIT
+ if hasattr(self._view, 'update_view_size'):
+ self._view.update_view_size(self._scrolled)
+ elif sizing_mode == "free":
+ self._model.props.sizing_mode = evince.SIZING_FREE
+ self._model.props.scale = \
+ float(self.metadata.get('Read_zoom', '1.0'))
+ _logger.debug('Set zoom to %f', self._model.props.scale)
+ elif sizing_mode == "fit-width":
+ self._model.props.sizing_mode = evince.SIZING_FIT_WIDTH
+ if hasattr(self._view, 'update_view_size'):
+ self._view.update_view_size(self._scrolled)
+ else:
+ # this may happen when we get a document from a buddy with a later
+ # version of Read, for example.
+ _logger.warning("Unknown sizing_mode state '%s'", sizing_mode)
+ if self.metadata.get('Read_zoom', None) is not None:
+ self._model.props.scale = float(self.metadata['Read_zoom'])
+
+ def update_metadata(self, activity):
+ self.metadata = activity.metadata
+ self.metadata['Read_zoom'] = str(self._model.props.scale)
+
+ if self._model.props.sizing_mode == evince.SIZING_BEST_FIT:
+ self.metadata['Read_sizing_mode'] = "best-fit"
+ elif self._model.props.sizing_mode == evince.SIZING_FREE:
+ self.metadata['Read_sizing_mode'] = "free"
+ elif self._model.props.sizing_mode == evince.SIZING_FIT_WIDTH:
+ self.metadata['Read_sizing_mode'] = "fit-width"
+ else:
+ _logger.error("Don't know how to save sizing_mode state '%s'" %
+ self._model.props.sizing_mode)
+ self.metadata['Read_sizing_mode'] = "fit-width"
+
+ def can_highlight(self):
+ return False
+
+ def can_do_text_to_speech(self):
+ return False
+
+ def get_zoom(self):
+ '''
+ Returns the current zoom level
+ '''
+ return self._model.props.scale * 100
+
+ def set_zoom(self, value):
+ '''
+ Sets the current zoom level
+ '''
+ self._model.props.sizing_mode = evince.SIZING_FREE
+
+ if not self._view_notify_zoom_handler:
+ return
+
+ self._model.disconnect(self._view_notify_zoom_handler)
+ try:
+ self._model.props.scale = value / 100.0
+ finally:
+ self._view_notify_zoom_handler = self._model.connect(
+ 'notify::scale', self._zoom_handler)
+
+ def zoom_in(self):
+ '''
+ Zooms in (increases zoom level by 0.1)
+ '''
+ self._model.props.sizing_mode = evince.SIZING_FREE
+ self._view.zoom_in()
+
+ def zoom_out(self):
+ '''
+ Zooms out (decreases zoom level by 0.1)
+ '''
+ self._model.props.sizing_mode = evince.SIZING_FREE
+ self._view.zoom_out()
+
+ def zoom_to_width(self):
+ self._model.props.sizing_mode = evince.SIZING_FIT_WIDTH
+
+ def can_zoom_in(self):
+ '''
+ Returns True if it is possible to zoom in further
+ '''
+ return self._view.can_zoom_in()
+
+ def can_zoom_out(self):
+ '''
+ Returns True if it is possible to zoom out further
+ '''
+ return self._view.can_zoom_out()
+
+ def can_zoom_to_width(self):
+ return True
+
+ def zoom_to_best_fit(self):
+ self._model.props.sizing_mode = evince.SIZING_BEST_FIT
+
+ def zoom_to_actual_size(self):
+ self._model.props.sizing_mode = evince.SIZING_FREE
+ self._model.props.scale = 1.0
+
+ def connect_zoom_handler(self, handler):
+ self._zoom_handler = handler
+ self._view_notify_zoom_handler = \
+ self._model.connect('notify::scale', handler)
+ return self._view_notify_zoom_handler
+
+ def setup_find_job(self, text, updated_cb):
+ self._find_job = evince.JobFind(document=self._document, start_page=0,
+ n_pages=self._document.get_n_pages(),
+ text=text, case_sensitive=False)
+ self._find_updated_handler = self._find_job.connect('updated',
+ updated_cb)
+ evince.Job.scheduler_push_job(self._find_job,
+ evince.JOB_PRIORITY_NONE)
+ return self._find_job, self._find_updated_handler
+
+ def connect_page_changed_handler(self, handler):
+ self._model.connect('page-changed', handler)
+
+ def update_toc(self, activity):
+ return False
+
+ def find_set_highlight_search(self, set_highlight_search):
+ self._view.find_set_highlight_search(set_highlight_search)
+
+ def find_next(self):
+ '''
+ Highlights the next matching item for current search
+ '''
+ self._view.find_next()
+
+ def find_previous(self):
+ '''
+ Highlights the previous matching item for current search
+ '''
+ self._view.find_previous()
+
+ def find_changed(self, job, page=None):
+ self._view.find_changed(job, page)
+
+ def scroll(self, scrolltype, horizontal):
+ '''
+ Scrolls through the pages.
+ Scrolling is horizontal if horizontal is set to True
+ Valid scrolltypes are:
+ gtk.SCROLL_PAGE_BACKWARD, gtk.SCROLL_PAGE_FORWARD,
+ gtk.SCROLL_STEP_BACKWARD, gtk.SCROLL_STEP_FORWARD,
+ gtk.SCROLL_START and gtk.SCROLL_END
+ '''
+ _logger.error('scroll: %s', scrolltype)
+
+ if scrolltype == gtk.SCROLL_PAGE_BACKWARD:
+ self._view.scroll(gtk.SCROLL_PAGE_BACKWARD, horizontal)
+ elif scrolltype == gtk.SCROLL_PAGE_FORWARD:
+ self._view.scroll(gtk.SCROLL_PAGE_FORWARD, horizontal)
+ elif scrolltype == gtk.SCROLL_STEP_BACKWARD:
+ self._scroll_step(False, horizontal)
+ elif scrolltype == gtk.SCROLL_STEP_FORWARD:
+ self._scroll_step(True, horizontal)
+ elif scrolltype == gtk.SCROLL_START:
+ self.set_current_page(0)
+ elif scrolltype == gtk.SCROLL_END:
+ self.set_current_page(self._document.get_n_pages())
+ else:
+ print ('Got unsupported scrolltype %s' % str(scrolltype))
+
+ def _scroll_step(self, forward, horizontal):
+ if horizontal:
+ adj = self._activity._scrolled.get_hadjustment()
+ else:
+ adj = self._activity._scrolled.get_vadjustment()
+ value = adj.get_value()
+ step = adj.get_step_increment()
+ if forward:
+ adj.set_value(value + step)
+ else:
+ adj.set_value(value - step)
+
+ def copy(self):
+ self._view.copy()
diff --git a/speech.py b/speech.py
new file mode 100644
index 0000000..d950fbd
--- /dev/null
+++ b/speech.py
@@ -0,0 +1,44 @@
+# Copyright (C) 2008, 2009 James D. Simmons
+# Copyright (C) 2009 Aleksey S. Lim
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+_logger = logging.getLogger('read-etexts-activity')
+
+supported = True
+
+try:
+ import gst
+ gst.element_factory_make('espeak')
+ from speech_gst import *
+ _logger.info('use gst-plugins-espeak')
+except Exception, e:
+ _logger.info('disable gst-plugins-espeak: %s' % e)
+ try:
+ from speech_dispatcher import *
+ _logger.info('use speech-dispatcher')
+ except Exception, e:
+ supported = False
+ _logger.info('disable speech: %s' % e)
+
+voice = 'default'
+pitch = 0
+rate = 0
+
+highlight_cb = None
+end_text_cb = None
+reset_cb = None
diff --git a/textadapter.py b/textadapter.py
new file mode 100644
index 0000000..526f6f1
--- /dev/null
+++ b/textadapter.py
@@ -0,0 +1,516 @@
+import os
+import zipfile
+import logging
+import gtk
+import pango
+import gobject
+import threading
+
+from sugar import mime
+from sugar.graphics import style
+
+import speech
+
+PAGE_SIZE = 38
+
+
+class TextViewer(gobject.GObject):
+
+ __gsignals__ = {
+ 'zoom-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([int])),
+ 'page-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([int, int])),
+ 'selection-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ }
+
+ def setup(self, activity):
+ self._activity = activity
+ activity._scrolled = gtk.ScrolledWindow()
+ activity._scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ activity._scrolled.props.shadow_type = gtk.SHADOW_NONE
+
+ self._scrolled = activity._scrolled
+
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.set_cursor_visible(False)
+ self.textview.set_left_margin(50)
+ self.textview.set_right_margin(50)
+ self.textview.set_wrap_mode(gtk.WRAP_WORD)
+ self.textview.connect('button-release-event', \
+ self._view_buttonrelease_event_cb)
+ self.connect('selection-changed',
+ activity._view_selection_changed_cb)
+
+ activity._scrolled.add(self.textview)
+ self.textview.show()
+ activity._scrolled.show()
+ activity._hbox.pack_start(activity._scrolled, expand=True, fill=True)
+
+ self._font_size = style.zoom(10)
+ self.font_desc = pango.FontDescription("sans %d" % self._font_size)
+ self.textview.modify_font(self.font_desc)
+ 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')
+
+ # text to speech initialization
+ self.current_word = 0
+ self.word_tuples = []
+ self.spoken_word_tag = self.textview.get_buffer().create_tag()
+ self.spoken_word_tag.set_property('weight', pango.WEIGHT_BOLD)
+ self.normal_tag = self.textview.get_buffer().create_tag()
+ self.normal_tag.set_property('weight', pango.WEIGHT_NORMAL)
+
+ def load_document(self, file_path):
+
+ file_name = file_path.replace('file://', '')
+ mimetype = mime.get_for_file(file_path)
+ if mimetype == 'application/zip':
+ logging.error('opening zip file')
+ self.zf = zipfile.ZipFile(file_path.replace('file://', ''), 'r')
+ self.book_files = self.zf.namelist()
+ extract_path = os.path.join(self._activity.get_activity_root(),
+ 'instance')
+ for book_file in self.book_files:
+ if (book_file != 'annotations.pkl'):
+ self.zf.extract(book_file, extract_path)
+ file_name = os.path.join(extract_path, book_file)
+
+ logging.error('opening file_name %s' % file_name)
+ self._etext_file = open(file_name, 'r')
+
+ self.page_index = [0]
+ pagecount = 0
+ linecount = 0
+ while self._etext_file:
+ line = self._etext_file.readline()
+ if not line:
+ break
+ line_increment = (len(line) / 80) + 1
+ linecount = linecount + line_increment
+ if linecount >= PAGE_SIZE:
+ position = self._etext_file.tell()
+ self.page_index.append(position)
+ linecount = 0
+ pagecount = pagecount + 1
+ self._pagecount = pagecount + 1
+ self.set_current_page(0)
+
+ speech.highlight_cb = self.highlight_next_word
+
+ def _show_page(self, page_number):
+ position = self.page_index[page_number]
+ self._etext_file.seek(position)
+ linecount = 0
+ label_text = '\n\n\n'
+ while linecount < PAGE_SIZE:
+ line = self._etext_file.readline()
+ if not line:
+ break
+ else:
+ label_text = label_text + unicode(line, "iso-8859-1")
+ line_increment = (len(line) / 80) + 1
+ linecount = linecount + line_increment
+ textbuffer = self.textview.get_buffer()
+ label_text = label_text + '\n\n\n'
+ textbuffer.set_text(label_text)
+ self._prepare_text_to_speech(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)
+
+ def can_do_text_to_speech(self):
+ return True
+
+ def get_marked_words(self):
+ "Adds a mark between each word of text."
+ i = self.current_word
+ marked_up_text = '<speak> '
+ while i < len(self.word_tuples):
+ word_tuple = self.word_tuples[i]
+ marked_up_text = marked_up_text + '<mark name="' + str(i) + '"/>' \
+ + word_tuple[2]
+ i = i + 1
+ print marked_up_text
+ return marked_up_text + '</speak>'
+
+ 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 highlight_next_word(self, word_count):
+ if word_count < len(self.word_tuples):
+ word_tuple = self.word_tuples[word_count]
+ textbuffer = self.textview.get_buffer()
+ iterStart = textbuffer.get_iter_at_offset(word_tuple[0])
+ iterEnd = textbuffer.get_iter_at_offset(word_tuple[1])
+ bounds = textbuffer.get_bounds()
+ textbuffer.apply_tag(self.normal_tag, bounds[0], iterStart)
+ textbuffer.apply_tag(self.spoken_word_tag, iterStart, iterEnd)
+ v_adjustment = self._scrolled.get_vadjustment()
+ max = v_adjustment.upper - v_adjustment.page_size
+ max = max * word_count
+ max = max / len(self.word_tuples)
+ v_adjustment.value = max
+ self.current_word = word_count
+ return True
+
+ def load_metadata(self, activity):
+ pass
+
+ def set_current_page(self, page):
+ old_page = self._current_page
+ self._current_page = page
+ self._show_page(self._current_page)
+ self.emit('page-changed', old_page, self._current_page)
+
+ def scroll(self, scrolltype, horizontal):
+ v_adjustment = self._scrolled.get_vadjustment()
+ v_value = v_adjustment.value
+ if scrolltype in (gtk.SCROLL_PAGE_BACKWARD, gtk.SCROLL_PAGE_FORWARD):
+ step = v_adjustment.page_increment
+ else:
+ step = v_adjustment.step_increment
+
+ if scrolltype in (gtk.SCROLL_PAGE_BACKWARD, gtk.SCROLL_STEP_BACKWARD):
+ if v_value <= v_adjustment.lower:
+ self.previous_page()
+ v_adjustment.value = v_adjustment.upper - \
+ v_adjustment.page_size
+ return
+ if v_value > v_adjustment.lower:
+ new_value = v_value - step
+ if new_value < v_adjustment.lower:
+ new_value = v_adjustment.lower
+ v_adjustment.value = new_value
+ elif scrolltype in (gtk.SCROLL_PAGE_FORWARD, gtk.SCROLL_STEP_FORWARD):
+ if v_value >= v_adjustment.upper - v_adjustment.page_size:
+ self.next_page()
+ return
+ if v_value < v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_value + step
+ if new_value > v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.upper - v_adjustment.page_size
+ v_adjustment.value = new_value
+ elif scrolltype == gtk.SCROLL_START:
+ self.set_current_page(0)
+ elif scrolltype == gtk.SCROLL_END:
+ self.set_current_page(self._pagecount - 1)
+
+ def previous_page(self):
+ v_adjustment = self._scrolled.get_vadjustment()
+ v_adjustment.value = v_adjustment.upper - v_adjustment.page_size
+ self.set_current_page(self.get_current_page() - 1)
+
+ def next_page(self):
+ v_adjustment = self._scrolled.get_vadjustment()
+ v_adjustment.value = v_adjustment.lower
+ self.set_current_page(self.get_current_page() + 1)
+
+ def get_current_page(self):
+ return self._current_page
+
+ def get_pagecount(self):
+ return self._pagecount
+
+ def update_toc(self, activity):
+ pass
+
+ def handle_link(self, link):
+ pass
+
+ def get_current_file(self):
+ pass
+
+ def update_metadata(self, activity):
+ pass
+
+ def copy(self):
+ self.textview.get_buffer().copy_clipboard(gtk.Clipboard())
+
+ def update_view_size(self, _scrolled):
+ pass
+
+ def _view_buttonrelease_event_cb(self, view, event):
+ self._has_selection = \
+ self.textview.get_buffer().get_selection_bounds() != ()
+ self.emit('selection-changed')
+
+ def get_has_selection(self):
+ return self._has_selection
+
+ def find_set_highlight_search(self, True):
+ pass
+
+ def setup_find_job(self, text, _find_updated_cb):
+ self._find_job = _JobFind(self._etext_file, start_page=0,
+ n_pages=self._pagecount,
+ text=text, case_sensitive=False)
+ self._find_updated_handler = self._find_job.connect('updated',
+ _find_updated_cb)
+ return self._find_job, self._find_updated_handler
+
+ def find_next(self):
+ self._find_job.find_next()
+
+ def find_previous(self):
+ self._find_job.find_previous()
+
+ def find_changed(self, job, page):
+ self.set_current_page(job.get_page())
+ self._show_found_text(job.get_founded_tuple())
+
+ def _show_found_text(self, founded_tuple):
+ textbuffer = self.textview.get_buffer()
+ tag = textbuffer.create_tag()
+ tag.set_property('weight', pango.WEIGHT_BOLD)
+ tag.set_property('foreground', 'white')
+ tag.set_property('background', 'black')
+ iterStart = textbuffer.get_iter_at_offset(founded_tuple[1])
+ iterEnd = textbuffer.get_iter_at_offset(founded_tuple[2])
+ textbuffer.apply_tag(tag, iterStart, iterEnd)
+
+ def get_zoom(self):
+ return self.font_zoom_relation * self._font_size
+
+ def connect_zoom_handler(self, handler):
+ self._view_notify_zoom_handler = \
+ self.connect('zoom-changed', handler)
+ return self._view_notify_zoom_handler
+
+ def set_zoom(self, value):
+ self._zoom = value
+ self._font_size = int(self._zoom / self.font_zoom_relation)
+ self.font_desc.set_size(self._font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def zoom_in(self):
+ self._set_font_size(self._font_size + 1)
+
+ def zoom_out(self):
+ self._set_font_size(self._font_size - 1)
+
+ def _set_font_size(self, size):
+ self._font_size = size
+ self.font_desc.set_size(self._font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+ self._zoom = self.font_zoom_relation * self._font_size
+ self.emit('zoom-changed', self._zoom)
+
+ def zoom_to_width(self):
+ pass
+
+ def can_zoom_in(self):
+ return True
+
+ def can_zoom_out(self):
+ return self._font_size > 1
+
+ def can_zoom_to_width(self):
+ return False
+
+ def zoom_to_best_fit(self):
+ return False
+
+ def zoom_to_actual_size(self):
+ return False
+
+
+class _JobFind(gobject.GObject):
+
+ __gsignals__ = {
+ 'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+ }
+
+ def __init__(self, text_file, start_page, n_pages, text, \
+ case_sensitive=False):
+ gobject.GObject.__init__(self)
+ gtk.gdk.threads_init()
+
+ self._finished = False
+ self._text_file = text_file
+ self._start_page = start_page
+ self._n_pages = n_pages
+ self._text = text
+ self._case_sensitive = case_sensitive
+ 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_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
+
+ def find_next(self):
+ self.threads[-1].find_next()
+
+ def find_previous(self):
+ self.threads[-1].find_previous()
+
+ def get_page(self):
+ return self.threads[-1].get_page()
+
+ def get_founded_tuple(self):
+ return self.threads[-1].get_founded_tuple()
+
+
+class _SearchThread(threading.Thread):
+
+ def __init__(self, obj):
+ threading.Thread.__init__(self)
+ self.obj = obj
+ self.stopthread = threading.Event()
+
+ def _start_search(self):
+ pagecount = 0
+ linecount = 0
+ charcount = 0
+ self._found_records = []
+ self._current_found_item = -1
+ self.obj._text_file.seek(0)
+ while self.obj._text_file:
+ line = unicode(self.obj._text_file.readline(), "iso-8859-1")
+ line_length = len(line)
+ if not line:
+ break
+ line_increment = (len(line) / 80) + 1
+ linecount = linecount + line_increment
+ positions = self._allindices(line.lower(), self.obj._text.lower())
+ for position in positions:
+ found_pos = charcount + position + 3
+ found_tuple = (pagecount, found_pos, \
+ len(self.obj._text) + found_pos)
+ self._found_records.append(found_tuple)
+ self._current_found_item = 0
+ charcount = charcount + line_length
+ if linecount >= PAGE_SIZE:
+ linecount = 0
+ charcount = 0
+ pagecount = pagecount + 1
+ if self._current_found_item == 0:
+ self.current_found_tuple = \
+ self._found_records[self._current_found_item]
+ self._page = self.current_found_tuple[0]
+
+ gtk.gdk.threads_enter()
+ self.obj._finished = True
+ self.obj.emit('updated')
+ gtk.gdk.threads_leave()
+
+ return False
+
+ def _allindices(self, line, search, listindex=None, offset=0):
+ if listindex is None:
+ listindex = []
+ if (line.find(search) == -1):
+ return listindex
+ else:
+ offset = line.index(search) + offset
+ listindex.append(offset)
+ line = line[(line.index(search) + 1):]
+ return self._allindices(line, search, listindex, offset + 1)
+
+ def run(self):
+ self._start_search()
+
+ def stop(self):
+ self.stopthread.set()
+
+ def find_next(self):
+ self._current_found_item = self._current_found_item + 1
+ if self._current_found_item >= len(self._found_records):
+ self._current_found_item = len(self._found_records) - 1
+ self.current_found_tuple = \
+ self._found_records[self._current_found_item]
+ self._page = self.current_found_tuple[0]
+ self.obj.emit('updated')
+
+ def find_previous(self):
+ self._current_found_item = self._current_found_item - 1
+ if self._current_found_item <= 0:
+ self._current_found_item = 0
+ self.current_found_tuple = \
+ self._found_records[self._current_found_item]
+ self._page = self.current_found_tuple[0]
+ self.obj.emit('updated')
+
+ def get_page(self):
+ return self._page
+
+ def get_founded_tuple(self):
+ return self.current_found_tuple