[gnome-builder/editor-layout] start on save and save as for tabs



commit 3e36864a202fc5c95ec38eda957dfd3e31b99efb
Author: Christian Hergert <christian hergert me>
Date:   Sun Nov 30 02:02:13 2014 -0800

    start on save and save as for tabs

 src/editor/gb-editor-document.c   |   78 ++++++++++++
 src/editor/gb-editor-document.h   |   20 +++-
 src/editor/gb-editor-tab.c        |  251 +++++++++++++++++++++++++++++++------
 src/editor/gb-editor-tab.h        |    4 +
 src/editor/gb-editor-workspace.c  |   28 ++++
 src/resources/ui/gb-editor-tab.ui |   33 ++++--
 6 files changed, 363 insertions(+), 51 deletions(-)
---
diff --git a/src/editor/gb-editor-document.c b/src/editor/gb-editor-document.c
index 531d89f..7debd2f 100644
--- a/src/editor/gb-editor-document.c
+++ b/src/editor/gb-editor-document.c
@@ -332,6 +332,84 @@ gb_editor_document_code_assistant_changed (GbEditorDocument      *document,
 }
 
 static void
+gb_editor_document_save_cb (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
+{
+  GtkSourceFileSaver *saver = (GtkSourceFileSaver *)object;
+  GError *error = NULL;
+  GTask *task = user_data;
+
+  ENTRY;
+
+  g_return_if_fail (GTK_SOURCE_IS_FILE_SAVER (saver));
+  g_return_if_fail (G_IS_ASYNC_RESULT (result));
+  g_return_if_fail (G_IS_TASK (task));
+
+  if (!gtk_source_file_saver_save_finish (saver, result, &error))
+    {
+      g_task_return_error (task, error);
+      GOTO (cleanup);
+    }
+
+  g_task_return_boolean (task, TRUE);
+
+cleanup:
+  g_object_unref (task);
+
+  EXIT;
+}
+
+void
+gb_editor_document_save_async (GbEditorDocument      *document,
+                               GCancellable          *cancellable,
+                               GFileProgressCallback  progress_callback,
+                               gpointer               progress_data,
+                               GDestroyNotify         progress_data_notify,
+                               GAsyncReadyCallback    callback,
+                               gpointer               user_data)
+{
+  GtkSourceFileSaver *saver;
+  GTask *task;
+
+  ENTRY;
+
+  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (document, cancellable, callback, user_data);
+
+  saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (document),
+                                     document->priv->file);
+
+  gtk_source_file_saver_save_async (saver,
+                                    G_PRIORITY_DEFAULT,
+                                    cancellable,
+                                    progress_callback,
+                                    progress_data,
+                                    progress_data_notify,
+                                    gb_editor_document_save_cb,
+                                    task);
+
+  g_object_unref (saver);
+
+  EXIT;
+}
+
+gboolean
+gb_editor_document_save_finish (GbEditorDocument  *document,
+                                GAsyncResult      *result,
+                                GError           **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (GB_IS_EDITOR_DOCUMENT (document), FALSE);
+  g_return_val_if_fail (G_IS_TASK (task), FALSE);
+
+  return g_task_propagate_boolean (task, error);
+}
+
+static void
 gb_editor_document_finalize (GObject *object)
 {
   GbEditorDocumentPrivate *priv = GB_EDITOR_DOCUMENT (object)->priv;
diff --git a/src/editor/gb-editor-document.h b/src/editor/gb-editor-document.h
index 2c6f902..a2d51e5 100644
--- a/src/editor/gb-editor-document.h
+++ b/src/editor/gb-editor-document.h
@@ -55,11 +55,21 @@ struct _GbEditorDocumentClass
 
 GbEditorDocument      *gb_editor_document_new                (void);
 GType                  gb_editor_document_get_type           (void) G_GNUC_CONST;
-GtkSourceFile         *gb_editor_document_get_file           (GbEditorDocument *document);
-void                   gb_editor_document_set_file           (GbEditorDocument *document,
-                                                              GtkSourceFile    *file);
-GbSourceChangeMonitor *gb_editor_document_get_change_monitor (GbEditorDocument *document);
-GbSourceCodeAssistant *gb_editor_document_get_code_assistant (GbEditorDocument *document);
+GtkSourceFile         *gb_editor_document_get_file           (GbEditorDocument       *document);
+void                   gb_editor_document_set_file           (GbEditorDocument       *document,
+                                                              GtkSourceFile          *file);
+GbSourceChangeMonitor *gb_editor_document_get_change_monitor (GbEditorDocument       *document);
+GbSourceCodeAssistant *gb_editor_document_get_code_assistant (GbEditorDocument       *document);
+void                   gb_editor_document_save_async         (GbEditorDocument       *document,
+                                                              GCancellable           *cancellable,
+                                                              GFileProgressCallback   progress_callback,
+                                                              gpointer                progress_data,
+                                                              GDestroyNotify          progress_data_notify,
+                                                              GAsyncReadyCallback     callback,
+                                                              gpointer                user_data);
+gboolean               gb_editor_document_save_finish        (GbEditorDocument       *document,
+                                                              GAsyncResult           *result,
+                                                              GError                **error);
 
 G_END_DECLS
 
diff --git a/src/editor/gb-editor-tab.c b/src/editor/gb-editor-tab.c
index f9fabf4..df8d7fa 100644
--- a/src/editor/gb-editor-tab.c
+++ b/src/editor/gb-editor-tab.c
@@ -16,35 +16,202 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "editor-tab"
+
 #include <glib/gi18n.h>
+#include <gtksourceview/gtksource.h>
 
+#include "gb-animation.h"
 #include "gb-editor-document.h"
 #include "gb-editor-frame.h"
 #include "gb-editor-tab.h"
+#include "gb-log.h"
+#include "gb-widget.h"
 
 struct _GbEditorTabPrivate
 {
   /* Widgets owned by GtkBuilder */
   GbEditorFrame    *frame;
   GtkPaned         *paned;
+  GtkProgressBar   *progress_bar;
   GtkToggleButton  *split_button;
 
   /* Weak references */
   GbEditorFrame    *last_frame;
+  GbAnimation      *progress_animation;
 
   /* Objects owned by GbEditorTab */
   GbEditorDocument *document;
 };
 
-enum
+G_DEFINE_TYPE_WITH_PRIVATE (GbEditorTab, gb_editor_tab, GB_TYPE_TAB)
+
+static void
+gb_editor_tab_progress_cb (goffset  current_num_bytes,
+                           goffset  total_num_bytes,
+                           gpointer user_data)
 {
-  PROP_0,
-  LAST_PROP
-};
+  GbEditorTabPrivate *priv;
+  GbEditorTab *tab = user_data;
+  gdouble fraction;
 
-G_DEFINE_TYPE_WITH_PRIVATE (GbEditorTab, gb_editor_tab, GB_TYPE_TAB)
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+
+  priv = tab->priv;
+
+  if (priv->progress_animation)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (priv->progress_animation),
+                                    (gpointer *)&priv->progress_animation);
+      gb_animation_stop (priv->progress_animation);
+      priv->progress_animation = NULL;
+    }
+
+  fraction = total_num_bytes
+           ? ((gdouble)current_num_bytes / (gdouble)total_num_bytes)
+           : 1.0;
+
+  priv->progress_animation =
+    gb_object_animate (priv->progress_bar,
+                       GB_ANIMATION_LINEAR,
+                       250,
+                       NULL,
+                       "fraction", fraction,
+                       NULL);
+  g_object_add_weak_pointer (G_OBJECT (priv->progress_animation),
+                             (gpointer *)&priv->progress_animation);
+}
+
+static void
+gb_editor_tab_save_cb (GObject      *source_object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
+{
+  GbEditorTab *tab = user_data;
+  GbEditorDocument *document = (GbEditorDocument *)source_object;
+  GError *error = NULL;
+
+  ENTRY;
+
+  g_return_if_fail (GB_IS_EDITOR_DOCUMENT (document));
+  g_return_if_fail (G_IS_ASYNC_RESULT (result));
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+
+  if (!gb_editor_document_save_finish (document, result, &error))
+    {
+      g_print ("%s", error->message);
+      //gb_editor_tab_set_error (tab, error);
+      g_clear_error (&error);
+    }
 
-static GParamSpec *gParamSpecs [LAST_PROP];
+  gb_widget_fade_hide (GTK_WIDGET (tab->priv->progress_bar));
+
+  g_object_unref (tab);
+
+  EXIT;
+}
+
+static void
+gb_editor_tab_do_save (GbEditorTab *tab)
+{
+  ENTRY;
+
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+
+  gtk_progress_bar_set_fraction (tab->priv->progress_bar, 0.0);
+  gtk_widget_show (GTK_WIDGET (tab->priv->progress_bar));
+
+  gb_editor_document_save_async (tab->priv->document,
+                                 NULL, /* cancellable */
+                                 gb_editor_tab_progress_cb,
+                                 tab,
+                                 NULL,
+                                 gb_editor_tab_save_cb,
+                                 g_object_ref (tab));
+
+  EXIT;
+}
+
+void
+gb_editor_tab_save_as (GbEditorTab *tab)
+{
+  GtkWidget *toplevel;
+  GtkDialog *dialog;
+  GtkWidget *suggested;
+  GFile *chosen_file;
+  guint response;
+
+  ENTRY;
+
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
+  dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
+                         "action", GTK_FILE_CHOOSER_ACTION_SAVE,
+                         "do-overwrite-confirmation", TRUE,
+                         "local-only", FALSE,
+                         "select-multiple", FALSE,
+                         "show-hidden", FALSE,
+                         "transient-for", toplevel,
+                         "title", _("Save Document As"),
+                         NULL);
+
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                          _("Cancel"), GTK_RESPONSE_CANCEL,
+                          _("Save"), GTK_RESPONSE_OK,
+                          NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+  suggested = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog),
+                                                  GTK_RESPONSE_OK);
+  gtk_style_context_add_class (gtk_widget_get_style_context (suggested),
+                               GTK_STYLE_CLASS_SUGGESTED_ACTION);
+
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_hide (GTK_WIDGET (dialog));
+
+  if (response == GTK_RESPONSE_OK)
+    {
+      GtkSourceFile *sfile;
+
+      sfile = gb_editor_document_get_file (tab->priv->document);
+      chosen_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+      gtk_source_file_set_location (sfile, chosen_file);
+      gb_editor_tab_do_save (tab);
+      g_clear_object (&chosen_file);
+    }
+
+  gtk_widget_destroy (GTK_WIDGET (dialog));
+
+  EXIT;
+}
+
+void
+gb_editor_tab_save (GbEditorTab *tab)
+{
+  GtkSourceFile *file;
+  gboolean has_location;
+
+  ENTRY;
+
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+
+  file = gb_editor_document_get_file (tab->priv->document);
+  has_location = !!gtk_source_file_get_location (file);
+
+  if (has_location)
+    gb_editor_tab_do_save (tab);
+  else
+    gb_editor_tab_save_as (tab);
+
+  EXIT;
+}
+
+void
+gb_editor_tab_open (GbEditorTab *tab)
+{
+}
 
 static void
 gb_editor_tab_on_frame_focused (GbEditorTab   *tab,
@@ -133,10 +300,28 @@ gb_editor_tab_grab_focus (GtkWidget *widget)
 }
 
 static void
+gb_editor_tab_on_notify_location (GbEditorTab   *tab,
+                                  GParamSpec    *pspec,
+                                  GtkSourceFile *file)
+{
+  gchar *title;
+  GFile *location;
+
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+  g_return_if_fail (GTK_SOURCE_IS_FILE (file));
+
+  location = gtk_source_file_get_location (file);
+  title = g_file_get_basename (location);
+  gb_tab_set_title (GB_TAB (tab), title);
+  g_free (title);
+}
+
+static void
 gb_editor_tab_constructed (GObject *object)
 {
   GbEditorTabPrivate *priv;
   GbEditorTab *tab = (GbEditorTab *)object;
+  GtkSourceFile *file;
 
   g_return_if_fail (GB_IS_EDITOR_TAB (tab));
 
@@ -148,6 +333,13 @@ gb_editor_tab_constructed (GObject *object)
                                  NULL);
   gb_editor_frame_set_document (priv->frame, priv->document);
 
+  file = gb_editor_document_get_file (priv->document);
+  g_signal_connect_object (file,
+                           "notify::location",
+                           G_CALLBACK (gb_editor_tab_on_notify_location),
+                           tab,
+                           G_CONNECT_SWAPPED);
+
   g_signal_connect_object (priv->frame,
                            "focused",
                            G_CALLBACK (gb_editor_tab_on_frame_focused),
@@ -168,43 +360,27 @@ gb_editor_tab_dispose (GObject *object)
 
   g_clear_object (&priv->document);
 
-  G_OBJECT_CLASS (gb_editor_tab_parent_class)->dispose (object);
-}
-
-static void
-gb_editor_tab_finalize (GObject *object)
-{
-  G_OBJECT_CLASS (gb_editor_tab_parent_class)->finalize (object);
-}
-
-static void
-gb_editor_tab_get_property (GObject    *object,
-                            guint       prop_id,
-                            GValue     *value,
-                            GParamSpec *pspec)
-{
-  GbEditorTab *self = GB_EDITOR_TAB (object);
+  if (priv->last_frame)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (priv->last_frame),
+                                    (gpointer *)&priv->last_frame);
+      priv->last_frame = NULL;
+    }
 
-  switch (prop_id)
+  if (priv->progress_animation)
     {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      g_object_remove_weak_pointer (G_OBJECT (priv->progress_animation),
+                                    (gpointer *)&priv->progress_animation);
+      priv->progress_animation = NULL;
     }
+
+  G_OBJECT_CLASS (gb_editor_tab_parent_class)->dispose (object);
 }
 
 static void
-gb_editor_tab_set_property (GObject      *object,
-                            guint         prop_id,
-                            const GValue *value,
-                            GParamSpec   *pspec)
+gb_editor_tab_finalize (GObject *object)
 {
-  GbEditorTab *self = GB_EDITOR_TAB (object);
-
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
+  G_OBJECT_CLASS (gb_editor_tab_parent_class)->finalize (object);
 }
 
 static void
@@ -216,8 +392,6 @@ gb_editor_tab_class_init (GbEditorTabClass *klass)
   object_class->constructed = gb_editor_tab_constructed;
   object_class->dispose = gb_editor_tab_dispose;
   object_class->finalize = gb_editor_tab_finalize;
-  object_class->get_property = gb_editor_tab_get_property;
-  object_class->set_property = gb_editor_tab_set_property;
 
   widget_class->grab_focus = gb_editor_tab_grab_focus;
 
@@ -225,6 +399,7 @@ gb_editor_tab_class_init (GbEditorTabClass *klass)
                                                "/org/gnome/builder/ui/gb-editor-tab.ui");
   gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, frame);
   gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, paned);
+  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, progress_bar);
   gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, split_button);
 
   g_type_ensure (GB_TYPE_EDITOR_FRAME);
diff --git a/src/editor/gb-editor-tab.h b/src/editor/gb-editor-tab.h
index cc01f1c..31d9f65 100644
--- a/src/editor/gb-editor-tab.h
+++ b/src/editor/gb-editor-tab.h
@@ -19,6 +19,7 @@
 #ifndef GB_EDITOR_TAB_H
 #define GB_EDITOR_TAB_H
 
+#include <gio/gio.h>
 #include <gtk/gtk.h>
 
 #include "gb-tab.h"
@@ -51,6 +52,9 @@ struct _GbEditorTabClass
 };
 
 GType gb_editor_tab_get_type (void) G_GNUC_CONST;
+void  gb_editor_tab_save     (GbEditorTab *tab);
+void  gb_editor_tab_save_as  (GbEditorTab *tab);
+void  gb_editor_tab_open     (GbEditorTab *tab);
 
 G_END_DECLS
 
diff --git a/src/editor/gb-editor-workspace.c b/src/editor/gb-editor-workspace.c
index 604bd5e..46cd3c3 100644
--- a/src/editor/gb-editor-workspace.c
+++ b/src/editor/gb-editor-workspace.c
@@ -52,6 +52,32 @@ gb_editor_workspace_open (GbEditorWorkspace *workspace,
 }
 
 static void
+save_tab (GSimpleAction *action,
+          GVariant      *parameter,
+          gpointer       user_data)
+{
+  GbEditorWorkspace *workspace = user_data;
+  GbTab *tab;
+
+  tab = gb_tab_grid_get_active (workspace->priv->tab_grid);
+  if (GB_IS_EDITOR_TAB (tab))
+    gb_editor_tab_save (GB_EDITOR_TAB (tab));
+}
+
+static void
+save_as_tab (GSimpleAction *action,
+             GVariant      *parameter,
+             gpointer       user_data)
+{
+  GbEditorWorkspace *workspace = user_data;
+  GbTab *tab;
+
+  tab = gb_tab_grid_get_active (workspace->priv->tab_grid);
+  if (GB_IS_EDITOR_TAB (tab))
+    gb_editor_tab_save_as (GB_EDITOR_TAB (tab));
+}
+
+static void
 new_tab (GSimpleAction *action,
          GVariant      *parameter,
          gpointer       user_data)
@@ -122,6 +148,8 @@ gb_editor_workspace_init (GbEditorWorkspace *workspace)
 {
     const GActionEntry entries[] = {
       { "new-tab", new_tab },
+      { "save", save_tab },
+      { "save-as", save_as_tab },
     };
 
   workspace->priv = gb_editor_workspace_get_instance_private (workspace);
diff --git a/src/resources/ui/gb-editor-tab.ui b/src/resources/ui/gb-editor-tab.ui
index 5ede5b1..3f9476c 100644
--- a/src/resources/ui/gb-editor-tab.ui
+++ b/src/resources/ui/gb-editor-tab.ui
@@ -42,19 +42,36 @@
     <child internal-child="content">
       <object class="GtkBox" id="content">
         <child>
-          <object class="GtkPaned" id="paned">
+          <object class="GtkOverlay">
             <property name="visible">true</property>
-            <property name="orientation">vertical</property>
-            <property name="vexpand">true</property>
+            <child type="overlay">
+              <object class="GtkProgressBar" id="progress_bar">
+                <property name="visible">false</property>
+                <property name="fraction">0.0</property>
+                <property name="valign">start</property>
+                <property name="halign">fill</property>
+                <property name="vexpand">false</property>
+                <style>
+                  <class name="osd"/>
+                </style>
+              </object>
+            </child>
             <child>
-              <object class="GbEditorFrame" id="frame">
+              <object class="GtkPaned" id="paned">
                 <property name="visible">true</property>
+                <property name="orientation">vertical</property>
                 <property name="vexpand">true</property>
+                <child>
+                  <object class="GbEditorFrame" id="frame">
+                    <property name="visible">true</property>
+                    <property name="vexpand">true</property>
+                  </object>
+                  <packing>
+                    <property name="resize">true</property>
+                    <property name="shrink">false</property>
+                  </packing>
+                </child>
               </object>
-              <packing>
-                <property name="resize">true</property>
-                <property name="shrink">false</property>
-              </packing>
             </child>
           </object>
         </child>


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