[PATCH] Browse: add shortcuts for PDF that are consistent with Read

Manuel QuiƱones manuq at laptop.org
Sun Jul 24 15:51:56 EDT 2011


This patch adds the same shortcuts as Read for zooming and scrolling
pdf files in Browse.  This is a bug reported in #10514.

The patch is against the the repo [1] with a modified version of
Browse that allows pdf reading.

[1]: git://git.sugarlabs.org/~godiard/browse/inline-pdf-11-2.git

The shortcuts are:

- Arrow keys, as well as DPAD buttons, for step scrolling
- X and O buttons for vertical page scrolling, respectively
- Circle and Check buttons for zoom in and out, respectively

The DPAD buttons behaviour change accordingly when the screen is
rotated.

At the time of sending this patch, there is a related bug in Browse
that doesn't let the pdf area grab the focus.  Please refer to the
comments in #10514.

Signed-off-by: Manuel QuiƱones <manuq at laptop.org>
---
 bin/sugar-pdf-viewer |  226 ++++++++++++++++++++++++++++++++------------------
 1 files changed, 146 insertions(+), 80 deletions(-)

diff --git a/bin/sugar-pdf-viewer b/bin/sugar-pdf-viewer
index b9719ec..b4d6ecc 100755
--- a/bin/sugar-pdf-viewer
+++ b/bin/sugar-pdf-viewer
@@ -36,12 +36,11 @@ class ViewerToolbar(gtk.Toolbar):
                               ([]))
     }
 
-    def __init__(self, evince_view):
+    def __init__(self, evince_viewer):
         gtk.Toolbar.__init__(self)
         self.set_style(gtk.TOOLBAR_ICONS)
 
-        self._evince_view = evince_view
-        self._document = None
+        self._evince_viewer = evince_viewer
 
         self._prev = ToolButton('go-previous-paired')
         self._prev.connect('clicked', self._prev_cb)
@@ -105,81 +104,47 @@ class ViewerToolbar(gtk.Toolbar):
 
         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._evince_viewer.zoom_in()
         self._update_zoom_buttons()
 
     def _zoom_out_cb(self, button):
-        self.zoom_out()
+        self._evince_viewer.zoom_out()
+        self._update_zoom_buttons()
 
-    def zoom_to_width(self):
-        self._model.props.sizing_mode = evince.SIZING_FIT_WIDTH
+    def _zoom_to_width_cb(self, button):
+        self._evince_viewer.zoom_to_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()
+        self._evince_viewer.save()
 
     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._zoom_in.props.sensitive = self._evince_viewer.can_zoom_in()
+        self._zoom_out.props.sensitive = self._evince_viewer.can_zoom_out()
 
+    def setup(self):
         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)
+        n_pages = self._evince_viewer.get_document_n_pages()
+        self._page_spinner_adjustment.props.upper = n_pages
+        self._evince_viewer.set_page_changed_callback(self._page_changed_cb)
 
         self._update_zoom_buttons()
         self._update_nav_buttons()
 
     def _prev_cb(self, button):
-        self._evince_view.previous_page()
+        self._evince_viewer.previous_page()
 
     def _next_cb(self, button):
-        self._evince_view.next_page()
+        self._evince_viewer.next_page()
 
     def _update_nav_buttons(self):
-        current_page = self._model.props.page
+        current_page = self._evince_viewer.get_current_page()
         self._prev.props.sensitive = current_page > 0
         self._next.props.sensitive = \
-            current_page < self._document.get_n_pages() - 1
+            current_page < self._evince_viewer.get_document_n_pages() - 1
 
         self._page_spinner_adjustment.handler_block(
                 self._page_spinner_adjustment_value_changed_id)
@@ -192,13 +157,12 @@ class ViewerToolbar(gtk.Toolbar):
 
     def _page_spinner_adjustment_value_changed_cb(self, adjustment):
         page = adjustment.get_value() - 1
-        if self._document:
-            self._model.props.page = int(page)
+        self._evince_viewer.change_to_page(page)
 
 
-def toolbar_needs_update_size_cb(widget, view, scrolledwindow):
-    if hasattr(view, 'update_view_size'):
-        view.update_view_size(scrolledwindow)
+def toolbar_needs_update_size_cb(widget, viewer_view, scrolledwindow):
+    if hasattr(viewer_view, 'update_view_size'):
+        viewer_view.update_view_size(scrolledwindow)
 
 
 def _get_screen_dpi():
@@ -206,45 +170,147 @@ def _get_screen_dpi():
     return float(xft_dpi / 1024)
 
 
+class EvinceViewer():
+    def __init__(self):
+        self._document = None
+        self._view = evince.View()
+        self._model = evince.DocumentModel()
+        self._view.set_model(self._model)
+
+    def load_document(self, filename):
+        try:
+            print "opening file %s" % filename
+            file_path = 'file://' + filename
+            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.set_document(self._document)
+            # set scale based on dpi:
+            dpi = _get_screen_dpi()
+            min_scale = self._model.get_min_scale()
+            max_scale = self._model.get_max_scale()
+            self._model.set_min_scale(min_scale * dpi / 72.0)
+            self._model.set_max_scale(max_scale * dpi / 72.0)
+
+    def get_view(self):
+        return self._view
+
+    def change_to_page(self, page):
+        self._model.props.page = int(page)
+
+    def can_zoom_in(self):
+        return self._view.can_zoom_in()
+
+    def can_zoom_out(self):
+        return self._view.can_zoom_out()
+
+    def zoom_in(self):
+        self._model.props.sizing_mode = evince.SIZING_FREE
+        self._view.zoom_in()
+
+    def zoom_out(self):
+        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 get_document_n_pages(self):
+        return self._document.get_n_pages()
+
+    def get_current_page(self):
+        return self._model.props.page
+
+    def set_page_changed_callback(self, callback):
+        self._model.connect('page-changed', callback)
+
+    def previous_page(self):
+        return self._view.previous_page()
+
+    def next_page(self):
+        return self._view.next_page()
+
+    def save(self):
+        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 _key_press_event_cb(widget, event, evince_viewer):
+    keyname = gtk.gdk.keyval_name(event.keyval)
+    view = evince_viewer.get_view()
+    if keyname == 'KP_Home':
+        evince_viewer.zoom_in()
+        return True
+    elif keyname == 'KP_End':
+        evince_viewer.zoom_out()
+        return True
+    elif keyname == 'Page_Up' or keyname == 'KP_Page_Up':
+        view.scroll(gtk.SCROLL_PAGE_BACKWARD, False)
+        return True
+    elif keyname == 'Page_Down' or keyname == 'KP_Page_Down':
+        view.scroll(gtk.SCROLL_PAGE_FORWARD, False)
+        return True
+    elif keyname == 'Up' or keyname == 'KP_Up':
+        view.scroll(gtk.SCROLL_STEP_BACKWARD, False)
+        return True
+    elif keyname == 'Down' or keyname == 'KP_Down':
+        view.scroll(gtk.SCROLL_STEP_FORWARD, False)
+        return True
+    elif keyname == 'Left' or keyname == 'KP_Left':
+        view.scroll(gtk.SCROLL_STEP_BACKWARD, True)
+        return True
+    elif keyname == 'Right' or keyname == 'KP_Right':
+        view.scroll(gtk.SCROLL_STEP_FORWARD, True)
+        return True
+    else:
+        return False
+
+
 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)
+
+    evince_viewer = EvinceViewer()
+    evince_viewer.load_document(filename)
 
     win = gtk.Window()
     win.connect('destroy', lambda w: gtk.main_quit())
     vbox = gtk.VBox()
     scrolledwindow = gtk.ScrolledWindow()
+    scrolledwindow.add(evince_viewer.get_view())
 
-    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 = ViewerToolbar(evince_viewer)
     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)
+        toolbar_needs_update_size_cb, evince_viewer.get_view(), scrolledwindow)
+    toolbar.setup()
 
     vbox.pack_start(toolbar, expand=False, fill=False)
     vbox.pack_start(scrolledwindow)
     win.add(vbox)
 
+    win.connect('key-press-event', _key_press_event_cb, evince_viewer)
     win.show_all()
-
     gtk.main()
 
 if __name__ == '__main__':
-- 
1.7.4.4




More information about the Devel mailing list