[gnome-documents/wip/lokdocview-rebase: 1/27] Add new class, LOKView, for LOKDocView widget



commit 287287c837cdd28ba5c7d7f574fa418b044a0337
Author: Pranav Kant <pranavk gnome org>
Date:   Tue Aug 11 21:11:11 2015 +0530

    Add new class, LOKView, for LOKDocView widget
    
    Use this widget, now, to open 'open document' format documents.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=753686

 data/org.gnome.Documents.data.gresource.xml |    1 +
 data/ui/lokview-menu.ui                     |   16 ++
 src/application.js                          |    6 +-
 src/documents.js                            |   45 ++++-
 src/embed.js                                |   82 +++++--
 src/lokview.js                              |  371 +++++++++++++++++++++++++++
 src/mainWindow.js                           |    1 +
 src/org.gnome.Documents.src.gresource.xml   |    1 +
 src/preview.js                              |    4 +
 src/windowMode.js                           |    3 +-
 10 files changed, 502 insertions(+), 28 deletions(-)
---
diff --git a/data/org.gnome.Documents.data.gresource.xml b/data/org.gnome.Documents.data.gresource.xml
index e374424..3a6be94 100644
--- a/data/org.gnome.Documents.data.gresource.xml
+++ b/data/org.gnome.Documents.data.gresource.xml
@@ -6,6 +6,7 @@
     <file preprocess="xml-stripblanks">ui/organize-collection-dialog.ui</file>
     <file preprocess="xml-stripblanks">ui/preview-context-menu.ui</file>
     <file preprocess="xml-stripblanks">ui/preview-menu.ui</file>
+    <file preprocess="xml-stripblanks">ui/lokview-menu.ui</file>
     <file preprocess="xml-stripblanks">ui/selection-menu.ui</file>
     <file preprocess="xml-stripblanks">ui/selection-toolbar.ui</file>
     <file preprocess="xml-stripblanks">ui/view-menu.ui</file>
diff --git a/data/ui/lokview-menu.ui b/data/ui/lokview-menu.ui
new file mode 100644
index 0000000..5bd5f4a
--- /dev/null
+++ b/data/ui/lokview-menu.ui
@@ -0,0 +1,16 @@
+<interface>
+  <menu id="lokview-menu">
+    <section>
+      <item>
+        <attribute name="action">app.zoom-in</attribute>
+        <attribute name="label" translatable="yes">Zoom In</attribute>
+        <attribute name="accel">&lt;Primary&gt;plus</attribute>
+      </item>
+      <item>
+        <attribute name="action">app.zoom-out</attribute>
+        <attribute name="label" translatable="yes">Zoom Out</attribute>
+        <attribute name="accel">&lt;Primary&gt;minus</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>
diff --git a/src/application.js b/src/application.js
index 066e3ea..77a0848 100644
--- a/src/application.js
+++ b/src/application.js
@@ -594,9 +594,11 @@ const Application = new Lang.Class({
             { name: 'find-prev', accels: ['<Shift><Primary>g'],
               window_mode: WindowMode.WindowMode.PREVIEW },
             { name: 'zoom-in', accels: ['<Primary>plus', '<Primary>equal'],
-              window_mode: WindowMode.WindowMode.PREVIEW },
+              window_modes: [WindowMode.WindowMode.PREVIEW,
+                             WindowMode.WindowMode.LOKVIEW] },
             { name: 'zoom-out', accels: ['<Primary>minus'],
-              window_mode: WindowMode.WindowMode.PREVIEW },
+              window_modes: [WindowMode.WindowMode.PREVIEW,
+                             WindowMode.WindowMode.LOKVIEW] },
             { name: 'rotate-left', accels: ['<Primary>Left'],
               window_mode: WindowMode.WindowMode.PREVIEW },
             { name: 'rotate-right', accels: ['<Primary>Right'],
diff --git a/src/documents.js b/src/documents.js
index a963f29..7f335ee 100644
--- a/src/documents.js
+++ b/src/documents.js
@@ -44,6 +44,29 @@ const Search = imports.search;
 const TrackerUtils = imports.trackerUtils;
 const Utils = imports.utils;
 
+const openDocumentFormats = ['application/vnd.oasis.opendocument.text',
+                             'application/vnd.oasis.opendocument.text-template',
+                             'application/vnd.oasis.opendocument.text-web',
+                             'application/vnd.oasis.opendocument.text-master',
+                             'application/vnd.oasis.opendocument.graphics',
+                             'application/vnd.oasis.opendocument.graphics-template',
+                             'application/vnd.oasis.opendocument.presentation',
+                             'application/vnd.oasis.opendocument.presentation-template',
+                             'application/vnd.oasis.opendocument.spreadsheet',
+                             'application/vnd.oasis.opendocument.spreadsheet-template',
+                             'application/vnd.oasis.opendocument.chart',
+                             'application/vnd.oasis.opendocument.formula',
+                             'application/vnd.oasis.opendocument.database',
+                             'application/vnd.oasis.opendocument.image',
+                             'application/vnd.openofficeorg.extension'];
+
+// These are the documents consisting of document parts.
+const openDocumentPartFormats = ['application/vnd.oasis.opendocument.presentation',
+                                 'application/vnd.oasis.opendocument.presentation-template',
+                                 'application/vnd.oasis.opendocument.spreadsheet',
+                                 'application/vnd.oasis.opendocument.spreadsheet-template',];
+
+
 const DeleteItemJob = new Lang.Class({
     Name: 'DeleteItemJob',
 // deletes the given resource
@@ -665,6 +688,18 @@ const DocCommon = new Lang.Class({
             retval = '{ ?urn nie:isPartOf <' + this.id + '> }';
 
         return retval;
+    },
+
+    isOpenDocumentPartDocument: function() {
+        if (openDocumentPartFormats.indexOf(this.mimeType) != -1)
+            return true;
+        return false;
+    },
+
+    isOpenDocumentFormat: function() {
+        if (openDocumentFormats.indexOf(this.mimeType) != -1)
+            return true;
+        return false;
     }
 });
 Signals.addSignalMethods(DocCommon.prototype);
@@ -741,6 +776,11 @@ const LocalDocument = new Lang.Class({
             return;
         }
 
+        if (this.isOpenDocumentFormat()) {
+            callback (this, null, null);
+            return;
+        }
+
         GdPrivate.pdf_loader_load_uri_async(this.uri, passwd, cancellable, Lang.bind(this,
             function(source, res) {
                 try {
@@ -1348,7 +1388,8 @@ const DocumentManager = new Lang.Class({
 
         // save loaded model and signal
         this._activeDocModel = docModel;
-        this._activeDocModel.set_continuous(false);
+        if (this._activeModel)
+            this._activeDocModel.set_continuous(false);
 
         // load metadata
         this._connectMetadata(docModel);
@@ -1464,6 +1505,8 @@ const DocumentManager = new Lang.Class({
     },
 
     _connectMetadata: function(docModel) {
+        if (!docModel)
+            return;
         let evDoc = docModel.get_document();
         let file = Gio.File.new_for_uri(evDoc.get_uri());
         if (!GdPrivate.is_metadata_supported_for_file(file))
diff --git a/src/embed.js b/src/embed.js
index f21c0cd..923e3a1 100644
--- a/src/embed.js
+++ b/src/embed.js
@@ -33,6 +33,7 @@ const Selections = imports.selections;
 const View = imports.view;
 const WindowMode = imports.windowMode;
 const Documents = imports.documents;
+const LOKView = imports.lokview;
 
 const EvView = imports.gi.EvinceView;
 const Gd = imports.gi.Gd;
@@ -86,8 +87,11 @@ const Embed = new Lang.Class({
         this._search = new View.ViewContainer(WindowMode.WindowMode.SEARCH);
         this._stack.add_named(this._search, 'search');
 
-        this._preview = new Preview.PreviewView(this._stackOverlay);
-        this._stack.add_named(this._preview, 'preview');
+        this._previewEv = new Preview.PreviewView(this._stackOverlay);
+        this._stack.add_named(this._previewEv, 'preview-ev');
+
+        this._previewLOK = new LOKView.LOKView(this._stackOverlay);
+        this._stack.add_named(this._previewLOK, 'preview-lok');
 
         this._edit = new Edit.EditView();
         this._stack.add_named(this._edit, 'edit');
@@ -147,7 +151,7 @@ const Embed = new Lang.Class({
             view = this._documents;
             break;
         case WindowMode.WindowMode.PREVIEW:
-            view = this._preview;
+            view = this._previewEv;
             break;
         case WindowMode.WindowMode.SEARCH:
             view = this._search;
@@ -181,7 +185,7 @@ const Embed = new Lang.Class({
             page = 'documents';
             break;
         case WindowMode.WindowMode.PREVIEW:
-            page = 'preview';
+            page = 'preview-ev';
             break;
         case WindowMode.WindowMode.SEARCH:
             page = 'search';
@@ -269,6 +273,11 @@ const Embed = new Lang.Class({
                 Application.documentManager.reloadActiveItem();
             this._prepareForPreview();
             break;
+        case WindowMode.WindowMode.LOKVIEW:
+            if (oldMode == WindowMode.WindowMode.EDIT)
+                Application.documentManager.reloadActiveItem();
+            this._prepareForLOKView();
+            break;
         case WindowMode.WindowMode.EDIT:
             this._prepareForEdit();
             break;
@@ -325,8 +334,11 @@ const Embed = new Lang.Class({
         }
     },
 
-    _onLoadStarted: function() {
-        Application.modeController.setWindowMode(WindowMode.WindowMode.PREVIEW);
+    _onLoadStarted: function(manager, doc) {
+        if (doc.isOpenDocumentFormat())
+            Application.modeController.setWindowMode(WindowMode.WindowMode.LOKVIEW);
+        else
+            Application.modeController.setWindowMode(WindowMode.WindowMode.PREVIEW);
 
         this._clearLoadTimer();
         this._loadShowId = Mainloop.timeout_add(_PDF_LOADER_TIMEOUT, Lang.bind(this,
@@ -340,18 +352,23 @@ const Embed = new Lang.Class({
     },
 
     _onLoadFinished: function(manager, doc, docModel) {
-        if (Application.application.isBooks)
-            docModel.set_sizing_mode(EvView.SizingMode.FIT_PAGE);
-        else
-            docModel.set_sizing_mode(EvView.SizingMode.AUTOMATIC);
-        docModel.set_page_layout(EvView.PageLayout.AUTOMATIC);
-        this._toolbar.setModel(docModel);
-        this._preview.setModel(docModel);
-        this._preview.grab_focus();
+        if (doc && docModel) {
+            if (Application.application.isBooks)
+                docModel.set_sizing_mode(EvView.SizingMode.FIT_PAGE);
+            else
+                docModel.set_sizing_mode(EvView.SizingMode.AUTOMATIC);
+            docModel.set_page_layout(EvView.PageLayout.AUTOMATIC);
+            this._toolbar.setModel(docModel);
+            this._previewEv.setModel(docModel);
+            this._previewEv.grab_focus();
+        }
 
         this._clearLoadTimer();
         this._spinner.stop();
-        this._stack.set_visible_child_name('preview');
+        if (doc != null && docModel == null)
+            this._stack.set_visible_child_name('preview-lok');
+        else
+            this._stack.set_visible_child_name('preview-ev');
     },
 
     _onLoadError: function(manager, doc, message, exception) {
@@ -394,8 +411,10 @@ const Embed = new Lang.Class({
             break;
         }
 
-        if (this._preview)
-            this._preview.reset();
+        if (this._previewEv)
+            this._previewEv.reset();
+        if (this._previewLOK)
+            this._previewLOK.reset();
         if (this._edit)
             this._edit.setUri(null);
 
@@ -419,36 +438,51 @@ const Embed = new Lang.Class({
             this._toolbar.destroy();
 
         // pack the toolbar
-        this._toolbar = new Preview.PreviewToolbar(this._preview);
+        this._toolbar = new Preview.PreviewToolbar(this._previewEv);
         this._titlebar.add(this._toolbar);
 
-        this._stack.set_visible_child_name('preview');
+        this._stack.set_visible_child_name('preview-ev');
     },
 
     _prepareForEdit: function() {
-        if (this._preview)
-            this._preview.setModel(null);
+        if (this._previewEv)
+            this._previewEv.setModel(null);
         if (this._toolbar)
             this._toolbar.destroy();
 
         // pack the toolbar
-        this._toolbar = new Edit.EditToolbar(this._preview);
+        this._toolbar = new Edit.EditToolbar(this._previewEv);
         this._titlebar.add(this._toolbar);
 
         this._stack.set_visible_child_name('edit');
     },
 
+    _prepareForLOKView: function() {
+        if (this._previewEv)
+            this._previewEv.setModel(null);
+        if (this._edit)
+            this._edit.setUri(null);
+        if (this._toolbar)
+            this._toolbar.destroy();
+
+        // pack the toolbar
+        this._toolbar = new LOKView.LOKViewToolbar(this._previewLOK);
+        this._titlebar.add(this._toolbar);
+
+        this._stack.set_visible_child_name('preview-lok');
+    },
+
     getMainToolbar: function() {
         let windowMode = Application.modeController.getWindowMode();
         let fullscreen = Application.modeController.getFullscreen();
 
         if (fullscreen && (windowMode == WindowMode.WindowMode.PREVIEW))
-            return this._preview.getFullscreenToolbar();
+            return this._previewEv.getFullscreenToolbar();
         else
             return this._toolbar;
     },
 
     getPreview: function() {
-        return this._preview;
+        return this._previewEv;
     }
 });
diff --git a/src/lokview.js b/src/lokview.js
new file mode 100644
index 0000000..db13c21
--- /dev/null
+++ b/src/lokview.js
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2015 Pranav Kant
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Pranav Kant <pranavk gnome org>
+ *
+ */
+
+const LOKDocView = imports.gi.LOKDocView;
+const Soup = imports.gi.Soup;
+const Gd = imports.gi.Gd;
+const GdPrivate = imports.gi.GdPrivate;
+const Gdk = imports.gi.Gdk;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const _ = imports.gettext.gettext;
+
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Signals = imports.signals;
+const Tweener = imports.tweener.tweener;
+
+const Application = imports.application;
+const MainToolbar = imports.mainToolbar;
+const Searchbar = imports.searchbar;
+const Utils = imports.utils;
+const View = imports.view;
+const WindowMode = imports.windowMode;
+const Documents = imports.documents;
+
+// FIXME: https://bugs.documentfoundation.org/show_bug.cgi?id=96247
+const LO_PATH = '/usr/lib64/libreoffice/program'
+
+const LOKView = new Lang.Class({
+    Name: 'LOKView',
+    Extends: Gtk.Overlay,
+
+    _init: function() {
+        this._uri = null;
+
+        this.parent();
+        this.get_style_context().add_class('documents-scrolledwin');
+
+        this._sw = new Gtk.ScrolledWindow({hexpand: true,
+                                           vexpand: true});
+
+        this._progressBar = new Gtk.ProgressBar({ halign: Gtk.Align.FILL,
+                                                  valign: Gtk.Align.START });
+        this._progressBar.get_style_context().add_class('osd');
+        this.add_overlay(this._progressBar);
+
+        this.add(this._sw);
+        this._createView();
+
+        this.show_all();
+
+        this._zoomIn = Application.application.lookup_action('zoom-in');
+        let zoomInId = this._zoomIn.connect('activate', Lang.bind(this,
+            function() {
+                let zoomLevel = this.view.get_zoom();
+                this.view.set_zoom(zoomLevel * 2);
+            }));
+
+        this._zoomOut = Application.application.lookup_action('zoom-out');
+        let zoomOutId = this._zoomOut.connect('activate', Lang.bind(this,
+            function() {
+                let zoomLevel = this.view.get_zoom();
+                this.view.set_zoom(zoomLevel / 2);
+            }));
+
+        Application.documentManager.connect('load-started',
+                                            Lang.bind(this, this._onLoadStarted));
+        Application.documentManager.connect('load-finished',
+                                            Lang.bind(this, this._onLoadFinished));
+
+        this.connect('destroy', Lang.bind(this,
+           function() {
+               this._zoomIn.disconnect(zoomInId);
+               this._zoomOut.disconnect(zoomOutId);
+           }));
+    },
+
+    _onLoadStarted: function() {
+
+    },
+
+    open_document_cb: function(res, doc) {
+        // TODO: Call _finish and check failure
+        if (this._doc.isOpenDocumentPartDocument()) {
+            this.hasParts = true;
+            this.totalParts = this.view.get_parts();
+            this.currentPart = this.view.get_part();
+        } else
+            this.hasParts = false;
+
+        this._progressBar.hide();
+        this.view.show();
+    },
+
+    _onLoadFinished: function(manager, doc, docModel) {
+        if (docModel == null && doc != null) {
+            let location = doc.uri.replace ('file://', '');
+            this._doc = doc;
+            this.view.open_document(location, null, Lang.bind(this, this.open_document_cb), null);
+            this._progressBar.show();
+        }
+    },
+
+    reset: function () {
+        this.view.hide()
+    },
+
+    _createView: function() {
+        this.view = LOKDocView.View.new(LO_PATH, null, null);
+        this._sw.add(this.view);
+        this.view.connect('load-changed', Lang.bind(this, this._onProgressChanged));
+
+        this._navControls = new LOKViewNavControls(this, this);
+    },
+
+    _onProgressChanged: function() {
+        this._progressBar.fraction = this.view.load_progress;
+    },
+});
+Signals.addSignalMethods(LOKView.prototype);
+
+const LOKViewToolbar = new Lang.Class({
+    Name: 'LOKViewToolbar',
+    Extends: MainToolbar.MainToolbar,
+
+    _init: function(lokView) {
+        this._lokView = lokView;
+
+        this.parent();
+        this.toolbar.set_show_close_button(true);
+
+        this._gearMenu = Application.application.lookup_action('gear-menu');
+        this._gearMenu.enabled = true;
+
+        this._lokView._zoomIn.enabled = true;
+        this._lokView._zoomOut.enabled = true;
+
+        // back button, on the left of the toolbar
+        let backButton = this.addBackButton();
+        backButton.connect('clicked', Lang.bind(this,
+            function() {
+                Application.documentManager.setActiveItem(null);
+                Application.modeController.goBack();
+            }));
+
+        // menu button, on the right of the toolbar
+        let lokViewMenu = this._getLOKViewMenu();
+        let menuButton = new Gtk.MenuButton({ image: new Gtk.Image ({ icon_name: 'open-menu-symbolic' }),
+                                              menu_model: lokViewMenu,
+                                              action_name: 'app.gear-menu' });
+        this.toolbar.pack_end(menuButton);
+
+        // search button, on the right of the toolbar
+        this.addSearchButton();
+
+        this._setToolbarTitle();
+        this.toolbar.show_all();
+    },
+
+    createSearchbar: function() {
+    },
+
+    _getLOKViewMenu: function() {
+        let builder = new Gtk.Builder();
+        builder.add_from_resource('/org/gnome/Documents/ui/lokview-menu.ui');
+        let menu = builder.get_object('lokview-menu');
+
+        return menu;
+    },
+
+    handleEvent: function(event) {
+        return false;
+    },
+
+    _setToolbarTitle: function() {
+        let primary = null;
+        let doc = Application.documentManager.getActiveItem();
+
+        if (doc)
+            primary = doc.name;
+
+        this.toolbar.set_title(primary);
+    }
+});
+
+const _LOKVIEW_NAVBAR_MARGIN = 30;
+const _AUTO_HIDE_TIMEOUT = 2;
+
+const LOKViewNavControls = new Lang.Class({
+    Name: 'LOKViewNavControls',
+
+    _init: function(lokView, overlay) {
+        this._lokView = lokView;
+        this._overlay = overlay;
+
+        this._visible = false;
+        this._visibleInternal = false;
+        this._pageChangedId = 0;
+        this._autoHideId = 0;
+        this._motionId = 0;
+
+        this.prev_widget = new Gtk.Button({ image: new Gtk.Image ({ icon_name: 'go-previous-symbolic',
+                                                                    pixel_size: 16 }),
+                                            margin_start: _LOKVIEW_NAVBAR_MARGIN,
+                                            margin_end: _LOKVIEW_NAVBAR_MARGIN,
+                                            halign: Gtk.Align.START,
+                                            valign: Gtk.Align.CENTER });
+        this.prev_widget.get_style_context().add_class('osd');
+        this._overlay.add_overlay(this.prev_widget);
+        this.prev_widget.connect('clicked', Lang.bind(this, this._onPrevClicked));
+        this.prev_widget.connect('enter-notify-event', Lang.bind(this, this._onEnterNotify));
+        this.prev_widget.connect('leave-notify-event', Lang.bind(this, this._onLeaveNotify));
+
+        this.next_widget = new Gtk.Button({ image: new Gtk.Image ({ icon_name: 'go-next-symbolic',
+                                                                    pixel_size: 16 }),
+                                            margin_start: _LOKVIEW_NAVBAR_MARGIN,
+                                            margin_end: _LOKVIEW_NAVBAR_MARGIN,
+                                            halign: Gtk.Align.END,
+                                            valign: Gtk.Align.CENTER });
+        this.next_widget.get_style_context().add_class('osd');
+        this._overlay.add_overlay(this.next_widget);
+        this.next_widget.connect('clicked', Lang.bind(this, this._onNextClicked));
+        this.next_widget.connect('enter-notify-event', Lang.bind(this, this._onEnterNotify));
+        this.next_widget.connect('leave-notify-event', Lang.bind(this, this._onLeaveNotify));
+        this._overlay.connect('motion-notify-event', Lang.bind(this, this._onMotion));
+    },
+
+    _onEnterNotify: function() {
+        this._unqueueAutoHide();
+        return false;
+    },
+
+    _onLeaveNotify: function() {
+        this._queueAutoHide();
+        return false;
+    },
+
+    _motionTimeout: function() {
+        this._motionId = 0;
+        this._visibleInternal = true;
+        this._updateVisibility();
+        this._queueAutoHide();
+        return false;
+    },
+
+    _onMotion: function(widget, event) {
+        if (this._motionId != 0) {
+            return false;
+        }
+
+        let device = event.get_source_device();
+        if (device.input_source == Gdk.InputSource.TOUCHSCREEN) {
+            return false;
+        }
+
+        this._motionId = Mainloop.idle_add(Lang.bind(this, this._motionTimeout));
+        return false;
+    },
+
+    _onPrevClicked: function() {
+        let currentPart = this._lokView.view.get_part();
+        currentPart -= 1;
+        if (currentPart < 0)
+            return;
+        this._lokView.view.set_part(currentPart);
+        this._lokView.currentPart = currentPart;
+    },
+
+    _onNextClicked: function() {
+        let totalParts  = this._lokView.view.get_parts();
+        let currentPart = this._lokView.view.get_part();
+        currentPart += 1;
+        if (currentPart > totalParts)
+            return;
+        this._lokView.view.set_part(currentPart);
+        this._lokView.currentPart = currentPart;
+    },
+
+    _autoHide: function() {
+        this._autoHideId = 0;
+        this._visibleInternal = false;
+        this._updateVisibility();
+        return false;
+    },
+
+    _unqueueAutoHide: function() {
+        if (this._autoHideId == 0)
+            return;
+
+        Mainloop.source_remove(this._autoHideId);
+        this._autoHideId = 0;
+    },
+
+    _queueAutoHide: function() {
+        this._unqueueAutoHide();
+        //FIXME: disable this temporarily till motion-notify-event works
+        //this._autoHideId = Mainloop.timeout_add_seconds(_AUTO_HIDE_TIMEOUT, Lang.bind(this, 
this._autoHide));
+    },
+
+    _updateVisibility: function() {
+        if (!this._lokView.hasParts) {
+            this._fadeOutButton(this.prev_widget);
+            this._fadeOutButton(this.next_widget);
+            return;
+        }
+
+        if (this._lokView.currentPart > 0)
+            this._fadeInButton(this.prev_widget);
+        else
+            this._fadeOutButton(this.prev_widget);
+
+        if (this._lokView.currentPart < this._lokView.totalParts)
+            this._fadeInButton(this.next_widget);
+        else
+            this._fadeOutButton(this.next_widget);
+    },
+
+    _fadeInButton: function(widget) {
+        widget.show_all();
+        Tweener.addTween(widget, { opacity: 1,
+                                   time: 0.30,
+                                   transition: 'easeOutQuad' });
+    },
+
+    _fadeOutButton: function(widget) {
+        Tweener.addTween(widget, { opacity: 0,
+                                   time: 0.30,
+                                   transition: 'easeOutQuad',
+                                   onComplete: function() {
+                                       widget.hide();
+                                   },
+                                   onCompleteScope: this });
+    },
+
+    show: function() {
+        this._visible = true;
+        this._visibleInternal = true;
+        this._updateVisibility();
+        this._queueAutoHide();
+    },
+
+    hide: function() {
+        this._visible = false;
+        this._visibleInternal = false;
+        this._updateVisibility();
+    },
+
+    destroy: function() {
+        this.prev_widget.destroy();
+        this.next_widget.destroy();
+    }
+});
diff --git a/src/mainWindow.js b/src/mainWindow.js
index 35bd61d..5c47483 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -202,6 +202,7 @@ const MainWindow = new Lang.Class({
         case WindowMode.WindowMode.SEARCH:
             return this._handleKeyOverview(event);
         case WindowMode.WindowMode.EDIT:
+        case WindowMode.WindowMode.LOKVIEW:
             return false;
         default:
             throw(new Error('Not handled'));
diff --git a/src/org.gnome.Documents.src.gresource.xml b/src/org.gnome.Documents.src.gresource.xml
index a2baba3..a3b26db 100644
--- a/src/org.gnome.Documents.src.gresource.xml
+++ b/src/org.gnome.Documents.src.gresource.xml
@@ -5,6 +5,7 @@
     <file>changeMonitor.js</file>
     <file>documents.js</file>
     <file>edit.js</file>
+    <file>lokview.js</file>
     <file>embed.js</file>
     <file>errorBox.js</file>
     <file>main.js</file>
diff --git a/src/preview.js b/src/preview.js
index 4158105..12ebecb 100644
--- a/src/preview.js
+++ b/src/preview.js
@@ -100,6 +100,8 @@ const PreviewView = new Lang.Class({
         this._zoomIn = Application.application.lookup_action('zoom-in');
         let zoomInId = this._zoomIn.connect('activate', Lang.bind(this,
             function() {
+                if (!this._model)
+                    return;
                 this._model.set_sizing_mode(EvView.SizingMode.FREE);
                 this.view.zoom_in();
             }));
@@ -107,6 +109,8 @@ const PreviewView = new Lang.Class({
         this._zoomOut = Application.application.lookup_action('zoom-out');
         let zoomOutId = this._zoomOut.connect('activate', Lang.bind(this,
             function() {
+                if (!this._model)
+                    return;
                 this._model.set_sizing_mode(EvView.SizingMode.FREE);
                 this.view.zoom_out();
             }));
diff --git a/src/windowMode.js b/src/windowMode.js
index ce63d9f..108608f 100644
--- a/src/windowMode.js
+++ b/src/windowMode.js
@@ -32,7 +32,8 @@ const WindowMode = {
     PREVIEW: 2,
     EDIT: 3,
     COLLECTIONS: 4,
-    SEARCH: 5
+    SEARCH: 5,
+    LOKVIEW: 6
 };
 
 const ModeController = new Lang.Class({


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]