#!/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, gobject import evince from sugar.datastore import datastore import gnomevfs import shutil, sys, os, os.path from gettext import gettext as _ 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 = gtk.ToolButton(gtk.STOCK_GO_UP) self._prev.connect('clicked', self._prev_cb) self.insert(self._prev, -1) self._prev.props.sensitive = False self._prev.show() self._next = gtk.ToolButton(gtk.STOCK_GO_DOWN) 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=0, step_incr=1, page_incr=1, page_size=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 = gtk.ToolButton(gtk.STOCK_ZOOM_OUT) self._zoom_out.connect('clicked', self._zoom_out_cb) self.insert(self._zoom_out, -1) self._zoom_out.show() self._zoom_in = gtk.ToolButton(gtk.STOCK_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 = gtk.ToolButton(gtk.STOCK_ZOOM_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._evince_view.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._evince_view.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._evince_view.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): doc_info = self._document.get_info() fpath = sys.argv[1] #XXX: Bleh # Try to figure out if this thing is downloaded from the # internet or is a local file (eg: from the library) # If this is a downloaded file, we need some extra # magic (http://lists.laptop.org/pipermail/sugar/2008-October/009147.html) if os.path.basename(os.path.dirname(fpath)) == 'plugtmp': local = False dest = os.path.expandvars('$SUGAR_ACTIVITY_ROOT/instance') shutil.copy2(fpath, dest) fpath = os.path.join(dest, os.path.basename(fpath)) os.chmod(fpath, 0644) #XXX: Hopefully this is right else: local = True 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 file_info = gnomevfs.get_file_info(fpath, \ gnomevfs.FILE_INFO_GET_MIME_TYPE| \ gnomevfs.FILE_INFO_FORCE_SLOW_MIME_TYPE| \ gnomevfs.FILE_INFO_FOLLOW_LINKS|gnomevfs.FILE_INFO_DEFAULT) entry.metadata['mime_type'] = file_info.mime_type if doc_info.title: entry.metadata['title'] = doc_info.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): self._document = document page_cache = self._document.get_page_cache() page_cache.connect('page-changed', self._page_changed_cb) self._page_spinner.props.sensitive = True self._page_spinner_adjustment.props.upper = self._document.get_n_pages() 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._document.get_page_cache().get_current_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, page, proxy): self._update_nav_buttons() def _page_spinner_adjustment_value_changed_cb(self, adjustment): page = adjustment.get_value() - 1 if self._document: self._document.get_page_cache().set_current_page(int(page)) def toolbar_needs_update_size_cb(widget, view, scrolledwindow): view.update_view_size(scrolledwindow) def main(filename): evince.evince_embed_init() evince.job_queue_init() document = evince.factory_get_document('file://' + filename) win = gtk.Window() win.connect('destroy', lambda w: gtk.main_quit()) vbox = gtk.VBox() scrolledwindow = gtk.ScrolledWindow() xft_dpi = gtk.settings_get_default().get_property('gtk-xft-dpi') view = evince.View() view.set_screen_dpi(xft_dpi/1024) view.set_document(document) scrolledwindow.add(view) toolbar = ViewerToolbar(view) toolbar.connect('needs-update-size', toolbar_needs_update_size_cb, view, scrolledwindow) toolbar.set_document(document) # 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])