[gnome-documents] An an edit mode for google documents
- From: William Jon McCann <mccann src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-documents] An an edit mode for google documents
- Date: Wed, 23 Jan 2013 00:24:25 +0000 (UTC)
commit b8b207a1d0451db36fb8fa385cdf363e5aea9b5f
Author: William Jon McCann <jmccann redhat com>
Date: Sun Jan 20 09:41:11 2013 -0500
An an edit mode for google documents
https://bugzilla.gnome.org/show_bug.cgi?id=692102
configure.ac | 4 +
src/Makefile-js.am | 1 +
src/application.js | 4 +
src/documents.js | 17 +++
src/edit.js | 223 +++++++++++++++++++++++++++++++++++++++++
src/embed.js | 42 ++++++++-
src/mainWindow.js | 15 +++-
src/resources/preview-menu.ui | 4 +
src/windowMode.js | 14 ++-
9 files changed, 317 insertions(+), 7 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 70f6d75..3c53adf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,6 +50,7 @@ AC_CHECK_LIBM
AC_SUBST(LIBM)
EVINCE_MIN_VERSION=3.7.4
+WEBKITGTK_MIN_VERSION=1.10.0
GLIB_MIN_VERSION=2.35.1
GTK_MIN_VERSION=3.7.7
GOBJECT_INTROSPECTION_MIN_VERSION=1.31.6
@@ -59,16 +60,19 @@ CLUTTER_GTK_MIN_VERSION=1.4.2
CLUTTER_MIN_VERSION=1.10
TRACKER_MIN_VERSION=0.13.1
ZAPOJIT_MIN_VERSION=0.0.2
+SOUP_MIN_VERSION=2.41.3
PKG_CHECK_MODULES(DOCUMENTS,
clutter-gtk-1.0 >= $CLUTTER_GTK_MIN_VERSION
clutter-1.0 >= $CLUTTER_MIN_VERSION
evince-document-3.0 >= $EVINCE_MIN_VERSION
evince-view-3.0 >= $EVINCE_MIN_VERSION
+ webkitgtk-3.0 >= $WEBKITGTK_MIN_VERSION
gjs-1.0
glib-2.0 >= $GLIB_MIN_VERSION
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
gtk+-3.0 >= $GTK_MIN_VERSION
+ libsoup-2.4 >= $SOUP_MIN_VERSION
gnome-desktop-3.0
tracker-sparql-0.16 >= $TRACKER_MIN_VERSION
goa-1.0 >= $GOA_MIN_VERSION
diff --git a/src/Makefile-js.am b/src/Makefile-js.am
index d8eb073..3efdd44 100644
--- a/src/Makefile-js.am
+++ b/src/Makefile-js.am
@@ -3,6 +3,7 @@ dist_js_DATA = \
application.js \
changeMonitor.js \
documents.js \
+ edit.js \
embed.js \
main.js \
mainToolbar.js \
diff --git a/src/application.js b/src/application.js
index 7838a6e..4129ce2 100644
--- a/src/application.js
+++ b/src/application.js
@@ -372,6 +372,10 @@ const Application = new Lang.Class({
{ name: 'open-current',
callback: this._onActionOpenCurrent,
window_mode: WindowMode.WindowMode.PREVIEW },
+ { name: 'edit-current',
+ window_mode: WindowMode.WindowMode.PREVIEW },
+ { name: 'view-current',
+ window_mode: WindowMode.WindowMode.EDIT },
{ name: 'print-current', accel: '<Primary>p',
callback: this._onActionPrintCurrent,
window_mode: WindowMode.WindowMode.PREVIEW },
diff --git a/src/documents.js b/src/documents.js
index 14eaff4..bb6eee3 100644
--- a/src/documents.js
+++ b/src/documents.js
@@ -944,6 +944,23 @@ const DocumentManager = new Lang.Class({
this._connectMetadata(docModel);
},
+ reloadActiveItem: function() {
+ let doc = this.getActiveItem();
+
+ if (!doc)
+ return;
+
+ if (doc.collection)
+ return;
+
+ // cleanup any state we have for previously loaded model
+ this._clearActiveDocModel();
+
+ this._loaderCancellable = new Gio.Cancellable();
+ doc.load(this._loaderCancellable, Lang.bind(this, this._onDocumentLoaded));
+ this.emit('load-started', doc);
+ },
+
setActiveItem: function(doc) {
if (!this.parent(doc))
return;
diff --git a/src/edit.js b/src/edit.js
new file mode 100644
index 0000000..1fad4a6
--- /dev/null
+++ b/src/edit.js
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+const Clutter = imports.gi.Clutter;
+const WebKit = imports.gi.WebKit;
+const Soup = imports.gi.Soup;
+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 GtkClutter = imports.gi.GtkClutter;
+const _ = imports.gettext.gettext;
+
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Signals = imports.signals;
+
+const Application = imports.application;
+const Tweener = imports.util.tweener;
+const MainToolbar = imports.mainToolbar;
+const Searchbar = imports.searchbar;
+const Utils = imports.utils;
+const View = imports.view;
+const WindowMode = imports.windowMode;
+const Documents = imports.documents;
+
+const _BLANK_URI = "about:blank";
+
+const EditView = new Lang.Class({
+ Name: 'EditView',
+
+ _init: function(overlayLayout) {
+ this._uri = null;
+
+ this.widget = new Gtk.Overlay();
+
+ this._scrolledWindow = new Gtk.ScrolledWindow({ hexpand: true,
+ vexpand: true,
+ shadow_type: Gtk.ShadowType.IN });
+ this.widget.get_style_context().add_class('documents-scrolledwin');
+ this.widget.add(this._scrolledWindow);
+
+ this._session = WebKit.get_default_session ();
+ Soup.Session.prototype.add_feature.call(this._session, new Soup.ProxyResolverDefault());
+ Soup.Session.prototype.remove_feature.call(this._session, new Soup.CookieJar());
+ let jarfile = GLib.build_filenamev([GLib.get_user_cache_dir(), 'gnome-documents', 'cookies.sqlite'])
+ this._cookieJar = new Soup.CookieJarDB({ filename: jarfile, read_only: false });
+ Soup.Session.prototype.add_feature.call(this._session, this._cookieJar);
+
+ this._progressBar = new Gtk.ProgressBar({ halign: Gtk.Align.FILL,
+ valign: Gtk.Align.START });
+ this._progressBar.get_style_context().add_class('osd');
+ this.widget.add_overlay(this._progressBar);
+
+ this._createView();
+
+ this.widget.show_all();
+
+ this._editAction = Application.application.lookup_action('edit-current');
+ this._editAction.enabled = false;
+ this._editAction.connect('activate', Lang.bind(this,
+ function() {
+ let doc = Application.documentManager.getActiveItem();
+ if (!doc)
+ return;
+ Application.modeController.setWindowMode(WindowMode.WindowMode.EDIT);
+ this.setUri (doc.uri);
+ }));
+
+ this._viewAction = Application.application.lookup_action('view-current');
+ this._viewAction.enabled = false;
+ this._viewAction.connect('activate', Lang.bind(this,
+ function() {
+ Application.modeController.setWindowMode(WindowMode.WindowMode.PREVIEW);
+ }));
+
+ Application.documentManager.connect('load-started',
+ Lang.bind(this, this._onLoadStarted));
+ Application.documentManager.connect('load-finished',
+ Lang.bind(this, this._onLoadFinished));
+
+ },
+
+ _onLoadStarted: function() {
+ this._editAction.enabled = false;
+ this._viewAction.enabled = false;
+ },
+
+ _onLoadFinished: function(manager, doc, docModel) {
+ if (doc.uri) {
+ if (doc instanceof Documents.GoogleDocument)
+ this._editAction.enabled = true;
+ this._viewAction.enabled = true;
+ }
+ },
+
+ _createView: function() {
+ this.view = new WebKit.WebView();
+ this._scrolledWindow.add(this.view);
+ this.view.show();
+ this.view.connect('notify::progress', Lang.bind(this, this._onProgressChanged));
+ },
+
+ _isLoading: function() {
+ let status = this.view.load_status;
+ if ((status == WebKit.LoadStatus.finished
+ || status == WebKit.LoadStatus.failed)
+ && status != WebKit.LoadStatus.provisional)
+ return false;
+
+ return status != WebKit.LoadStatus.finished
+ && status != WebKit.LoadStatus.failed;
+ },
+
+ _onProgressChanged: function() {
+ if (!this.view.uri || this.view.uri == _BLANK_URI)
+ return;
+
+ let progress = this.view.progress;
+ let loading = this._isLoading();
+
+ if (progress == 1.0 || !loading) {
+ if (!this._timeoutId)
+ this._timeoutId = Mainloop.timeout_add(500, Lang.bind(this, this._onTimeoutExpired));
+ } else {
+ if (this._timeoutId) {
+ Mainloop.source_remove(this._timeoutId);
+ this._timeoutId = 0;
+ }
+ this._progressBar.show();
+ }
+ let value = 0.0
+ if (loading || progress == 1.0)
+ value = progress;
+ this._progressBar.fraction = value;
+ },
+
+ _onTimeoutExpired: function() {
+ this._timeoutId = 0;
+ this._progressBar.hide();
+ return false;
+ },
+
+ setUri: function(uri) {
+ if (this._uri == uri)
+ return;
+
+ if (!uri)
+ uri = _BLANK_URI;
+
+ this._uri = uri;
+ this.view.load_uri (uri);
+ },
+
+ getUri: function() {
+ return this._uri;
+ },
+});
+Signals.addSignalMethods(EditView.prototype);
+
+const EditToolbar = new Lang.Class({
+ Name: 'EditToolbar',
+ Extends: MainToolbar.MainToolbar,
+
+ _init: function(editView) {
+ this._editView = editView;
+
+ this.parent();
+
+ // back button, on the left of the toolbar
+ let iconName =
+ (this.widget.get_direction() == Gtk.TextDirection.RTL) ?
+ 'go-next-symbolic' : 'go-previous-symbolic';
+ let backButton =
+ this.widget.add_button(iconName, _("Back"), true);
+ backButton.connect('clicked', Lang.bind(this,
+ function() {
+ Application.documentManager.setActiveItem(null);
+ }));
+
+ let viewButton =
+ this.widget.add_button(null, _("View"), false);
+ viewButton.get_style_context().add_class('suggested-action');
+ viewButton.set_action_name('app.view-current');
+
+ this._setToolbarTitle();
+ this.widget.show_all();
+ },
+
+ createSearchbar: function() {
+ },
+
+ handleEvent: function(event) {
+ return false;
+ },
+
+ _setToolbarTitle: function() {
+ let primary = null;
+ let doc = Application.documentManager.getActiveItem();
+
+ if (doc)
+ primary = doc.name;
+
+ this.widget.set_labels(primary, null);
+ }
+});
diff --git a/src/embed.js b/src/embed.js
index b5a371d..489693c 100644
--- a/src/embed.js
+++ b/src/embed.js
@@ -27,9 +27,11 @@ const Application = imports.application;
const MainToolbar = imports.mainToolbar;
const Notifications = imports.notifications;
const Preview = imports.preview;
+const Edit = imports.edit;
const Selections = imports.selections;
const View = imports.view;
const WindowMode = imports.windowMode;
+const Documents = imports.documents;
const Clutter = imports.gi.Clutter;
const EvView = imports.gi.EvinceView;
@@ -377,6 +379,9 @@ const Embed = new Lang.Class({
this._preview = new Preview.PreviewView(this._overlayLayout);
this._previewPage = this._notebook.append_page(this._preview.widget, null);
+ this._edit = new Edit.EditView(this._overlayLayout);
+ this._editPage = this._notebook.append_page(this._edit.widget, null);
+
Application.modeController.connect('window-mode-changed',
Lang.bind(this, this._onWindowModeChanged));
@@ -458,10 +463,24 @@ const Embed = new Lang.Class({
},
_onWindowModeChanged: function(object, newMode, oldMode) {
- if (newMode == WindowMode.WindowMode.OVERVIEW)
+ switch (newMode) {
+ case WindowMode.WindowMode.OVERVIEW:
this._prepareForOverview();
- else
+ break;
+ case WindowMode.WindowMode.PREVIEW:
+ if (oldMode == WindowMode.WindowMode.EDIT)
+ Application.documentManager.reloadActiveItem();
this._prepareForPreview();
+ break;
+ case WindowMode.WindowMode.EDIT:
+ this._prepareForEdit();
+ break;
+ case WindowMode.WindowMode.NONE:
+ break;
+ default:
+ throw(new Error('Not handled'))
+ break;
+ }
},
_onActiveItemChanged: function(manager, doc) {
@@ -500,6 +519,8 @@ const Embed = new Lang.Class({
_prepareForOverview: function() {
if (this._preview)
this._preview.setModel(null);
+ if (this._edit)
+ this._edit.setUri(null);
if (this._toolbar)
this._toolbar.actor.destroy();
@@ -517,6 +538,8 @@ const Embed = new Lang.Class({
},
_prepareForPreview: function() {
+ if (this._edit)
+ this._edit.setUri(null);
if (this._toolbar)
this._toolbar.actor.destroy();
@@ -529,6 +552,21 @@ const Embed = new Lang.Class({
this._notebook.set_current_page(this._previewPage);
},
+ _prepareForEdit: function() {
+ if (this._preview)
+ this._preview.setModel(null);
+ if (this._toolbar)
+ this._toolbar.actor.destroy();
+
+ // pack the toolbar
+ this._toolbar = new Edit.EditToolbar(this._preview);
+ this._contentsLayout.pack_start = true;
+ this._contentsActor.add_actor(this._toolbar.actor);
+ this._contentsLayout.set_fill(this._toolbar.actor, true, false);
+
+ this._notebook.set_current_page(this._editPage);
+ },
+
_setError: function(primary, secondary) {
this._errorBox.update(primary, secondary);
this._errorBox.moveIn();
diff --git a/src/mainWindow.js b/src/mainWindow.js
index e3ff560..c6a510a 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -149,10 +149,21 @@ const MainWindow = new Lang.Class({
if (toolbar.handleEvent(event))
return true;
- if (Application.modeController.getWindowMode() == WindowMode.WindowMode.PREVIEW)
+ switch (Application.modeController.getWindowMode()) {
+ case WindowMode.WindowMode.NONE:
+ return false;
+ case WindowMode.WindowMode.PREVIEW:
return this._handleKeyPreview(event);
- else
+ case WindowMode.WindowMode.OVERVIEW:
return this._handleKeyOverview(event);
+ case WindowMode.WindowMode.EDIT:
+ return false;
+ default:
+ throw(new Error('Not handled'))
+ break;
+ }
+
+ return false;
},
_handleKeyPreview: function(event) {
diff --git a/src/resources/preview-menu.ui b/src/resources/preview-menu.ui
index d9bf848..27590f5 100644
--- a/src/resources/preview-menu.ui
+++ b/src/resources/preview-menu.ui
@@ -6,6 +6,10 @@
<attribute name="label" translatable="yes">Open</attribute>
</item>
<item>
+ <attribute name="action">app.edit-current</attribute>
+ <attribute name="label" translatable="yes">Edit</attribute>
+ </item>
+ <item>
<attribute name="action">app.print-current</attribute>
<attribute name="label" translatable="yes">Printâ</attribute>
<attribute name="accel"><Primary>p</attribute>
diff --git a/src/windowMode.js b/src/windowMode.js
index c60eec0..4a09235 100644
--- a/src/windowMode.js
+++ b/src/windowMode.js
@@ -29,7 +29,8 @@ const Application = imports.application;
const WindowMode = {
NONE: 0,
OVERVIEW: 1,
- PREVIEW: 2
+ PREVIEW: 2,
+ EDIT: 3
};
const ModeController = new Lang.Class({
@@ -47,7 +48,13 @@ const ModeController = new Lang.Class({
if (oldMode == mode)
return;
- this.setCanFullscreen(mode == WindowMode.PREVIEW);
+ if (mode == WindowMode.PREVIEW
+ || mode == WindowMode.EDIT) {
+ this.setCanFullscreen(true);
+ } else {
+ this.setCanFullscreen(false);
+ }
+
this._mode = mode;
this.emit('window-mode-changed', this._mode, oldMode);
@@ -80,7 +87,8 @@ const ModeController = new Lang.Class({
},
setFullscreen: function(fullscreen) {
- if (this._mode != WindowMode.PREVIEW)
+ if (this._mode != WindowMode.PREVIEW
+ && this._mode != WindowMode.EDIT)
return;
if (this._fullscreen == fullscreen)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]