[sushi] mainwindow: add a spinnerBox pseudo-renderer to use for loading feedback



commit 4d469b2bfa955b2f5e55defcac74552463b73552
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Fri May 13 17:21:43 2011 -0400

    mainwindow: add a spinnerBox pseudo-renderer to use for loading feedback
    
    Instead of having every plugin implement its own loading spinbox, make
    it a window-owned renderer, and let the window do all the
    allocation/positioning magic.

 src/Makefile-js.am      |    1 +
 src/js/ui/mainWindow.js |   65 ++++++++++++++++++++++++--------------
 src/js/ui/spinnerBox.js |   81 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+), 24 deletions(-)
---
diff --git a/src/Makefile-js.am b/src/Makefile-js.am
index 18f580d..82d7edb 100644
--- a/src/Makefile-js.am
+++ b/src/Makefile-js.am
@@ -6,6 +6,7 @@ dist_jsui_DATA = \
     js/ui/fallbackRenderer.js \
     js/ui/mainWindow.js \
     js/ui/mimeHandler.js \
+    js/ui/spinnerBox.js \
     js/ui/utils.js
 
 jsviewersdir = $(pkgdatadir)/js/viewers
diff --git a/src/js/ui/mainWindow.js b/src/js/ui/mainWindow.js
index 2509d54..9d8957f 100644
--- a/src/js/ui/mainWindow.js
+++ b/src/js/ui/mainWindow.js
@@ -15,6 +15,7 @@ const Mainloop = imports.mainloop;
 
 const MimeHandler = imports.ui.mimeHandler;
 const Constants = imports.util.constants;
+const SpinnerBox = imports.ui.spinnerBox;
 
 const Sushi = imports.gi.Sushi;
 
@@ -246,18 +247,50 @@ MainWindow.prototype = {
             delete this._renderer;
         }
 
-        let info = file.query_info("standard::content-type",
-                                   0, null);
-        this._renderer = this._mimeHandler.getObject(info.get_content_type());        
+        /* create a temporary spinner renderer, that will timeout and show itself
+         * if the loading takes too long.
+         */
+        this._renderer = new SpinnerBox.SpinnerBox();
+        this._renderer.startTimeout();
+
+        file.query_info_async
+        (Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME + "," +
+         Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+         Gio.FileQueryInfoFlags.NONE,
+         GLib.PRIORITY_DEFAULT, null,
+         Lang.bind (this,
+                    function(obj, res) {
+                        try {
+                            this._fileInfo = obj.query_info_finish(res);
+                            this._titleLabel.set_text(this._fileInfo.get_display_name());
+
+                            /* now prepare the real renderer */
+                            this._pendingRenderer = this._mimeHandler.getObject(this._fileInfo.get_content_type());
+                            this._pendingRenderer.prepare(file, this, Lang.bind(this, this._onRendererPrepared));
+                        } catch(e) {
+                            /* FIXME: report the error */
+                        }}));
+    },
+
+    _onRendererPrepared : function() {
+        /* destroy the spinner renderer */
+        this._renderer.destroy();
+
+        this._renderer = this._pendingRenderer;
+        delete this._pendingRenderer;
+
+        /* generate the texture and toolbar for the new renderer */
+        this._createTexture();
+        this._createToolbar();
     },
 
-    _createTexture : function(file) {
+    _createTexture : function() {
         if (this._texture) {
             this._texture.destroy();
             delete this._texture;
         }
 
-        this._texture = this._renderer.render(file, this);
+        this._texture = this._renderer.render();
 
         this._textureXAlign = 
             new Clutter.AlignConstraint({ source: this._stage,
@@ -481,33 +514,17 @@ MainWindow.prototype = {
     },
 
 
-    _updateLabel : function(file) {
-	file.query_info_async(Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
-                              Gio.FileQueryInfoFlags.NONE,
-                              GLib.PRIORITY_DEFAULT, null,
-			      Lang.bind (this, 
-                                         function (obj, res) {
-				             try {
-				                 let info = obj.query_info_finish(res);
-				                 this._titleLabel.set_label(info.get_display_name());
-				             } catch (e) {
-				             }
-                                         }));
-    },
-
     /**************************************************************************
      ************************ titlebar helpers ********************************
      **************************************************************************/
-    _createTitle : function(file) {
+    _createTitle : function() {
         if (this._titleLabel) {
-            this._updateLabel(file);
             this._titleActor.raise_top();
             this._quitActor.raise_top();
             return;
         }
 
         this._titleLabel = new Gtk.Label({ label: "" });
-        this._updateLabel(file);
         this._titleLabel.get_style_context().add_class("np-decoration");
         
         this._titleLabel.show();
@@ -621,9 +638,9 @@ MainWindow.prototype = {
 	this.file = file;
         this._createAlphaBackground();
         this._createRenderer(file);
-        this._createTexture(file);
+        this._createTexture();
         this._createToolbar();
-        this._createTitle(file);
+        this._createTitle();
 
         if (!this._gtkWindow.get_visible()) {
             this._moveWindow();
diff --git a/src/js/ui/spinnerBox.js b/src/js/ui/spinnerBox.js
new file mode 100644
index 0000000..1eb24c6
--- /dev/null
+++ b/src/js/ui/spinnerBox.js
@@ -0,0 +1,81 @@
+let Clutter = imports.gi.Clutter;
+let Gtk = imports.gi.Gtk;
+
+let Tweener = imports.ui.tweener;
+let Mainloop = imports.mainloop;
+
+let SPINNER_SIZE = 48;
+let TIMEOUT = 500;
+
+function SpinnerBox(args) {
+    this._init(args);
+    this.canFullScreen = false;
+    this.moveOnClick = true;
+}
+
+SpinnerBox.prototype = {
+    _init : function(args) {
+        this._spinnerBox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 12);
+        this._spinnerBox.show();
+
+        this._spinner = Gtk.Spinner.new();
+        this._spinner.show();
+        this._spinner.set_size_request(SPINNER_SIZE, SPINNER_SIZE);
+        this._spinnerBox.pack_start(this._spinner, true, true, 0);
+
+        this._label = new Gtk.Label();
+        this._label.set_text(_("Loading..."));
+        this._label.show();
+        this._spinnerBox.pack_start(this._label, true, true, 0);
+
+        this.actor = new GtkClutter.Actor({ contents: this._spinnerBox });
+        this.actor.set_opacity(0);
+    },
+
+    render : function() {
+        return this.actor;
+    },
+
+    getSizeForAllocation : function() {
+        let spinnerSize = this._spinnerBox.get_preferred_size();
+        return [ spinnerSize[0].width,
+                 spinnerSize[0].height ];
+    },
+
+    startTimeout : function() {
+        if (this._timeoutId)
+            return;
+
+        this._spinner.start();
+        this._timeoutId = Mainloop.timeout_add(TIMEOUT,
+                                               Lang.bind(this,
+                                                         this._onTimeoutCompleted));
+    },
+
+    destroy : function() {
+        if (this._timeoutId) {
+            Mainloop.source_remove(this._timeoutId);
+            delete this._timeoutId;
+        }
+
+        Tweener.addTween(this.actor,
+                         { opacity: 0,
+                           time: 0.15,
+                           transition: 'easeOutQuad',
+                           onComplete: function() {
+                               this.actor.destroy();
+                           },
+                           onCompleteScope: this
+                         });
+    },
+
+    _onTimeoutCompleted : function() {
+        delete this._timeoutId;
+
+        Tweener.addTween(this.actor,
+                         { opacity: 255,
+                           time: 0.3,
+                           transition: 'easeOutQuad'
+                         });
+    },
+}
\ No newline at end of file



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