#!/usr/bin/env python # Copyright (C) 2008, 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 gtk import gobject import evince from sugar.datastore import datastore from sugar.graphics.toolbutton import ToolButton from sugar import mime import sys import os class ViewerToolbar(gtk.Toolbar): __gtype_name__ = 'ViewerToolbar' __gsignals__ = { 'needs-update-size': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])) } def __init__(self, evince_view): gtk.Toolbar.__init__(self) self.set_style(gtk.TOOLBAR_ICONS) self._evince_view = evince_view self._document = None self._prev = ToolButton('go-previous-paired') self._prev.connect('clicked', self._prev_cb) self.insert(self._prev, -1) self._prev.props.sensitive = False self._prev.show() self._next = ToolButton('go-next-paired') self._next.connect('clicked', self._next_cb) self.insert(self._next, -1) self._next.props.sensitive = False self._next.show() self._page_spinner_adjustment = \ gtk.Adjustment(value=1, lower=1, upper=1, step_incr=1) self._page_spinner_adjustment_value_changed_id = \ self._page_spinner_adjustment.connect('value-changed', self._page_spinner_adjustment_value_changed_cb) self._page_spinner = \ gtk.SpinButton(adjustment=self._page_spinner_adjustment, climb_rate=0.2, digits=0) self._page_spinner.props.sensitive = False item = gtk.ToolItem() item.add(self._page_spinner) self.insert(item, -1) item.show_all() separator = gtk.SeparatorToolItem() separator.set_draw(True) separator.set_expand(False) self.insert(separator, -1) separator.show() self._zoom_out = ToolButton('zoom-out') self._zoom_out.connect('clicked', self._zoom_out_cb) self.insert(self._zoom_out, -1) self._zoom_out.show() self._zoom_in = ToolButton('zoom-in') self._zoom_in.connect('clicked', self._zoom_in_cb) self.insert(self._zoom_in, -1) self._zoom_in.show() self._zoom_to_width = ToolButton('zoom-best-fit') self._zoom_to_width.connect('clicked', self._zoom_to_width_cb) self.insert(self._zoom_to_width, -1) self._zoom_to_width.show() separator1 = gtk.SeparatorToolItem() separator1.set_draw(False) separator1.set_expand(True) self.insert(separator1, -1) separator1.show() self._save = gtk.ToolButton(gtk.STOCK_SAVE) self._save.connect('clicked', self._save_cb) self.insert(self._save, -1) self._save.show() self._update_zoom_buttons() def zoom_in(self): self._model.props.sizing_mode = evince.SIZING_FREE self._evince_view.zoom_in() self._update_zoom_buttons() def _zoom_in_cb(self, button): self.zoom_in() def zoom_out(self): self._model.props.sizing_mode = evince.SIZING_FREE self._evince_view.zoom_out() self._update_zoom_buttons() def _zoom_out_cb(self, button): self.zoom_out() def zoom_to_width(self): self._model.props.sizing_mode = evince.SIZING_FIT_WIDTH self.emit('needs-update-size') self._update_zoom_buttons() return False def _zoom_to_width_cb(self, button): self.zoom_to_width() def _save_cb(self, button): title = self._document.get_title() fpath = sys.argv[1] # XXX: Bleh entry = datastore.create() entry.set_file_path(fpath) # For certain sites, PDFs get saved as foo.php, etc # An example would be the Nepali repository @ pustakalay.org # We need to force file sniffing here, otherwise the file gets # stored in the datastore with the mimetype application/x-php, etc entry.metadata['mime_type'] = mime.get_for_file(fpath) if title: entry.metadata['title'] = title else: entry.metadata['title'] = os.path.basename(sys.argv[1]) datastore.write(entry) entry.destroy() def _update_zoom_buttons(self): self._zoom_in.props.sensitive = self._evince_view.can_zoom_in() self._zoom_out.props.sensitive = self._evince_view.can_zoom_out() def set_document(self, document, model): self._document = document self._model = model self._page_spinner.props.sensitive = True self._page_spinner_adjustment.props.upper = \ self._document.get_n_pages() self._model.connect('page-changed', self._page_changed_cb) self._update_zoom_buttons() self._update_nav_buttons() def _prev_cb(self, button): self._evince_view.previous_page() def _next_cb(self, button): self._evince_view.next_page() def _update_nav_buttons(self): current_page = self._model.props.page self._prev.props.sensitive = current_page > 0 self._next.props.sensitive = \ current_page < self._document.get_n_pages() - 1 self._page_spinner_adjustment.handler_block( self._page_spinner_adjustment_value_changed_id) self._page_spinner_adjustment.set_value(current_page + 1) self._page_spinner_adjustment.handler_unblock( self._page_spinner_adjustment_value_changed_id) def _page_changed_cb(self, model, page_from, page_to): self._update_nav_buttons() def _page_spinner_adjustment_value_changed_cb(self, adjustment): page = adjustment.get_value() - 1 if self._document: self._model.props.page = int(page) def toolbar_needs_update_size_cb(widget, view, scrolledwindow): if hasattr(view, 'update_view_size'): view.update_view_size(scrolledwindow) def _get_screen_dpi(): xft_dpi = gtk.settings_get_default().get_property('gtk-xft-dpi') return float(xft_dpi / 1024) def main(filename): if hasattr(evince, 'evince_embed_init'): # if we use evince-2.24 evince.evince_embed_init() print "opening file %s" % filename document = evince.document_factory_get_document('file://' + filename) win = gtk.Window() win.connect('destroy', lambda w: gtk.main_quit()) vbox = gtk.VBox() scrolledwindow = gtk.ScrolledWindow() view = evince.View() model = evince.DocumentModel() model.set_document(document) view.set_model(model) # set dpi dpi = _get_screen_dpi() min_scale = model.get_min_scale() max_scale = model.get_max_scale() model.set_min_scale(min_scale * dpi / 72.0) model.set_max_scale(max_scale * dpi / 72.0) scrolledwindow.add(view) toolbar = ViewerToolbar(view) toolbar.connect('needs-update-size', toolbar_needs_update_size_cb, view, scrolledwindow) toolbar.set_document(document, model) # We need to wait for sometime before calling this #gobject.timeout_add(1200, toolbar.zoom_to_width) vbox.pack_start(toolbar, expand=False, fill=False) vbox.pack_start(scrolledwindow) win.add(vbox) win.show_all() gtk.main() if __name__ == '__main__': main(sys.argv[1])