diff options
Diffstat (limited to 'epubview/jobs.py')
-rw-r--r-- | epubview/jobs.py | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/epubview/jobs.py b/epubview/jobs.py new file mode 100644 index 0000000..de276b3 --- /dev/null +++ b/epubview/jobs.py @@ -0,0 +1,248 @@ +# Copyright 2009 One Laptop Per Child +# Author: Sayamindu Dasgupta <sayamindu@laptop.org> +# +# 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 gobject +import gtk +import widgets +import cairo + +import math +import os.path +import BeautifulSoup + +import epub + +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 + name, file = entry + filepath = os.path.join(self.obj._document.get_basedir(), file) + f = open(filepath) + if self._searchfile(f): + self.obj._matchfilelist.append(file) + f.close() + + gtk.gdk.threads_enter() + self.obj._finished = True + self.obj.emit('updated') + gtk.gdk.threads_leave() + + return False + + def _searchfile(self, fileobj): + soup = BeautifulSoup.BeautifulSoup(fileobj) + body = soup.find('body') + tags = body.findChildren(True) + for tag in tags: + if not tag.string is None: + if tag.string.find(self.obj._text) > -1: + return True + + return False + + def run (self): + self._start_search() + + def stop(self): + self.stopthread.set() + + + +class _JobPaginator(gobject.GObject): + __gsignals__ = { + 'paginated': (gobject.SIGNAL_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 + + self._screen = gtk.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() + + 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 + #settings.props.auto_shrink_images = False #FIXME: This does not seem to work + 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.POLICY_NEVER, gtk.POLICY_NEVER) + self._dpi = 96 + sw.set_size_request(_mm_to_pixel(PAGE_WIDTH, self._dpi), _mm_to_pixel(PAGE_HEIGHT, self._dpi)) + 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.unrealize() + + self._temp_view.open(self._filelist[self._count]) + + def _page_load_finished_cb(self, v, frame): + f = v.get_main_frame() + pageheight = v.get_page_height() + + if pageheight <= _mm_to_pixel(PAGE_HEIGHT, self._dpi): + pages = 1 + else: + pages = pageheight/float(_mm_to_pixel(PAGE_HEIGHT, self._dpi)) + 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 += 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): + self._temp_win.destroy() + self._screen.set_font_options(self._old_fontoptions) + self.emit('paginated') + else: + self._count += 1 + self._temp_view.open(self._filelist[self._count]) + + + def get_file_for_pageno(self, pageno): + return self._pagemap[pageno][0] + + def get_scrollfactor_pos_for_pageno(self, pageno): + return self._pagemap[pageno][1] + + def get_scrollfactor_len_for_pageno(self, pageno): + return self._pagemap[pageno][2] + + def get_pagecount_for_file(self, file): + return self._filedict[file][0] + + def get_remfactor_for_file(self, file): + return self._filedict[file][1] + + def get_total_pagecount(self): + return self._pagecount + + def get_total_height(self): + return self._bookheight + + +class _JobFind(gobject.GObject): + __gsignals__ = { + 'updated': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([])) + } + def __init__(self, document, start_page, n_pages, text, case_sensitive=False): + gobject.GObject.__init__(self) + gtk.threads_init() + + 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): + for s_thread in self.threads: + s_thread.stop() + + def is_finished(self): + return self._finished + + def get_next_file(self): + 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): + 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): + return self._text + + def get_case_sensitive(self): + return self._case_sensitive |