Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/bin/sugar-pdf-viewer
diff options
context:
space:
mode:
Diffstat (limited to 'bin/sugar-pdf-viewer')
-rwxr-xr-xbin/sugar-pdf-viewer252
1 files changed, 252 insertions, 0 deletions
diff --git a/bin/sugar-pdf-viewer b/bin/sugar-pdf-viewer
new file mode 100755
index 0000000..db8d69d
--- /dev/null
+++ b/bin/sugar-pdf-viewer
@@ -0,0 +1,252 @@
+#!/usr/bin/env python
+# Copyright (C) 2008, 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 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])