[network-manager-applet: 5/7] editor: change JSON Team/TeamPort config widget from GEntry to GTextView



commit 697f7f49f25fd9867810959e23cff2ee1a982980
Author: Jiří Klimeš <jklimes redhat com>
Date:   Tue Sep 17 16:43:54 2013 +0200

    editor: change JSON Team/TeamPort config widget from GEntry to GTextView
    
    and allow importing the config from a file.
    
    libteam configuration is a string that can be quite long, and simple GEntry is
    not much appropriate for it. This commit uses GTextView instead, so that
    structured multiline JSON config can be typed. In addition to that, the import
    button allows selecting a file whose content will be imported as the config
    text.

 src/connection-editor/ce-page-team-port.ui |   38 +++++++++--
 src/connection-editor/ce-page-team.ui      |   42 +++++++++++--
 src/connection-editor/page-team-port.c     |   89 +++++++++++++++++++++++----
 src/connection-editor/page-team.c          |   92 +++++++++++++++++++++++-----
 4 files changed, 220 insertions(+), 41 deletions(-)
---
diff --git a/src/connection-editor/ce-page-team-port.ui b/src/connection-editor/ce-page-team-port.ui
index 382e9c1..10422f4 100644
--- a/src/connection-editor/ce-page-team-port.ui
+++ b/src/connection-editor/ce-page-team-port.ui
@@ -1,14 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 3.0 -->
-  <object class="GtkTable" id="TeamPortPage">
+  <object class="GtkGrid" id="TeamPortPage">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="border_width">12</property>
-    <property name="n_rows">3</property>
-    <property name="n_columns">2</property>
     <property name="column_spacing">12</property>
     <property name="row_spacing">6</property>
+    <property name="column_homogeneous">True</property>
     <child>
       <object class="GtkLabel" id="team_port_json_config_label">
         <property name="visible">True</property>
@@ -20,18 +19,43 @@
       </object>
       <packing>
         <property name="left_attach">0</property>
-        <property name="top_attach">2</property>
+        <property name="top_attach">0</property>
       </packing>
     </child>
     <child>
-      <object class="GtkEntry" id="team_port_json_config">
+      <object class="GtkScrolledWindow" id="scrolledwindow1">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
-        <property name="invisible_char">●</property>
+        <property name="shadow_type">in</property>
+        <property name="min_content_height">100</property>
+        <child>
+          <object class="GtkTextView" id="team_port_json_config">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+          </object>
+        </child>
       </object>
       <packing>
-        <property name="left_attach">1</property>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+        <property name="width">2</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="import_config_button">
+        <property name="label" translatable="yes">_Import team configuration from a file...</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="use_underline">True</property>
+        <property name="hexpand">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
         <property name="top_attach">2</property>
+        <property name="width">2</property>
+        <property name="height">1</property>
       </packing>
     </child>
   </object>
diff --git a/src/connection-editor/ce-page-team.ui b/src/connection-editor/ce-page-team.ui
index 135d043..a751fdb 100644
--- a/src/connection-editor/ce-page-team.ui
+++ b/src/connection-editor/ce-page-team.ui
@@ -12,9 +12,10 @@
   <object class="GtkGrid" id="TeamPage">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
+    <property name="hexpand">True</property>
     <property name="border_width">12</property>
     <property name="column_spacing">12</property>
-    <property name="row_spacing">6</property>
+    <property name="row_spacing">8</property>
     <child>
       <object class="GtkLabel" id="master_connections_label">
         <property name="visible">True</property>
@@ -41,24 +42,52 @@
       </object>
       <packing>
         <property name="left_attach">0</property>
-        <property name="top_attach">8</property>
+        <property name="top_attach">3</property>
+        <property name="width">2</property>
+        <property name="height">1</property>
       </packing>
     </child>
     <child>
-      <object class="GtkEntry" id="team_json_config">
+      <object class="GtkScrolledWindow" id="scrolledwindow2">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
-        <property name="invisible_char">●</property>
+        <property name="shadow_type">in</property>
+        <property name="min_content_height">100</property>
+        <child>
+          <object class="GtkTextView" id="team_json_config">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+          </object>
+        </child>
       </object>
       <packing>
-        <property name="left_attach">1</property>
-        <property name="top_attach">8</property>
+        <property name="left_attach">0</property>
+        <property name="top_attach">4</property>
+        <property name="width">2</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="import_config_button">
+        <property name="label" translatable="yes">I_mport team configuration from a file...</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="use_underline">True</property>
+        <property name="hexpand">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">5</property>
+        <property name="width">2</property>
+        <property name="height">1</property>
       </packing>
     </child>
     <child>
       <object class="GtkHBox" id="hbox2">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
         <property name="spacing">10</property>
         <child>
           <object class="GtkScrolledWindow" id="scrolledwindow1">
@@ -174,6 +203,7 @@
       <object class="GtkEntry" id="master_interface">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
+        <property name="hexpand">True</property>
         <property name="invisible_char">●</property>
       </object>
       <packing>
diff --git a/src/connection-editor/page-team-port.c b/src/connection-editor/page-team-port.c
index ca7936c..280cf4e 100644
--- a/src/connection-editor/page-team-port.c
+++ b/src/connection-editor/page-team-port.c
@@ -37,8 +37,8 @@ G_DEFINE_TYPE (CEPageTeamPort, ce_page_team_port, CE_TYPE_PAGE)
 typedef struct {
        NMSettingTeamPort *setting;
 
-       GtkEntry *json_config;
-
+       GtkTextView *json_config_widget;
+       GtkWidget *import_config_button;
 } CEPageTeamPortPrivate;
 
 static void
@@ -49,13 +49,68 @@ team_port_private_init (CEPageTeamPort *self)
 
        builder = CE_PAGE (self)->builder;
 
-       priv->json_config = GTK_ENTRY (gtk_builder_get_object (builder, "team_port_json_config"));
+       priv->json_config_widget = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "team_port_json_config"));
+       priv->import_config_button = GTK_WIDGET (gtk_builder_get_object (builder, "import_config_button"));
+}
+
+static void
+json_config_changed (GObject *object, CEPageTeamPort *self)
+{
+       ce_page_changed (CE_PAGE (self));
 }
 
 static void
-stuff_changed (GtkWidget *w, gpointer user_data)
+import_config_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
 {
-       ce_page_changed (CE_PAGE (user_data));
+       CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (user_data);
+       GtkTextBuffer *buffer;
+       char *filename;
+       char *buf = NULL;
+       gsize buf_len;
+
+       if (response != GTK_RESPONSE_ACCEPT)
+               goto out;
+
+       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+       if (!filename) {
+               g_warning ("%s: didn't get a filename back from the chooser!", __func__);
+               goto out;
+       }
+
+       /* Put the file content into JSON config text view. */
+       // FIXME: do a cleverer file validity check
+       g_file_get_contents (filename, &buf, &buf_len, NULL);
+       if (buf_len > 100000) {
+               g_free (buf);
+               buf = g_strdup (_("Error: file doesn't contain a valid JSON configuration"));
+       }
+
+       buffer = gtk_text_view_get_buffer (priv->json_config_widget);
+       gtk_text_buffer_set_text (buffer, buf ? buf : "", -1);
+
+       g_free (filename);
+       g_free (buf);
+
+out:
+       gtk_widget_hide (dialog);
+       gtk_widget_destroy (dialog);
+}
+
+static void
+import_button_clicked_cb (GtkWidget *widget, CEPageTeamPort *self)
+{
+       GtkWidget *dialog;
+
+       dialog = gtk_file_chooser_dialog_new (_("Select file to import"),
+                                             NULL,
+                                             GTK_FILE_CHOOSER_ACTION_OPEN,
+                                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                             NULL);
+
+       g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (import_config_from_file_cb), self);
+       gtk_widget_show_all (dialog);
+       gtk_window_present (GTK_WINDOW (dialog));
 }
 
 static void
@@ -63,23 +118,24 @@ populate_ui (CEPageTeamPort *self)
 {
        CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
        NMSettingTeamPort *s_port = priv->setting;
+       GtkTextBuffer *buffer;
        const char *json_config;
 
+       buffer = gtk_text_view_get_buffer (priv->json_config_widget);
        json_config = nm_setting_team_port_get_config (s_port);
-       gtk_entry_set_text (priv->json_config, json_config ? json_config : "");
+       gtk_text_buffer_set_text (buffer, json_config ? json_config : "", -1);
+
+       g_signal_connect (buffer, "changed", G_CALLBACK (json_config_changed), self);
+       g_signal_connect (priv->import_config_button, "clicked", G_CALLBACK (import_button_clicked_cb), self);
 }
 
 static void
 finish_setup (CEPageTeamPort *self, gpointer unused, GError *error, gpointer user_data)
 {
-       CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
-
        if (error)
                return;
 
        populate_ui (self);
-
-       g_signal_connect (priv->json_config, "changed", G_CALLBACK (stuff_changed), self);
 }
 
 CEPage *
@@ -127,14 +183,21 @@ static void
 ui_to_setting (CEPageTeamPort *self)
 {
        CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
-       const char *json_config;
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       char *json_config;
+
+       buffer = gtk_text_view_get_buffer (priv->json_config_widget);
+       gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
+       gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
+       json_config = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
 
-       json_config = gtk_entry_get_text (priv->json_config);
-       if (!g_strcmp0(json_config, ""))
+       if (g_strcmp0 (json_config, "") == 0)
                json_config = NULL;
        g_object_set (priv->setting,
                      NM_SETTING_TEAM_PORT_CONFIG, json_config,
                      NULL);
+       g_free (json_config);
 }
 
 static gboolean
diff --git a/src/connection-editor/page-team.c b/src/connection-editor/page-team.c
index 1b19507..a02041f 100644
--- a/src/connection-editor/page-team.c
+++ b/src/connection-editor/page-team.c
@@ -39,8 +39,8 @@ typedef struct {
 
        GtkWindow *toplevel;
 
-       GtkEntry *json_config;
-       GtkWidget *json_config_label;
+       GtkTextView *json_config_widget;
+       GtkWidget *import_config_button;
 } CEPageTeamPrivate;
 
 static void
@@ -51,17 +51,71 @@ team_private_init (CEPageTeam *self)
 
        builder = CE_PAGE (self)->builder;
 
-       priv->json_config = GTK_ENTRY (gtk_builder_get_object (builder, "team_json_config"));
-       priv->json_config_label = GTK_WIDGET (gtk_builder_get_object (builder, "team_json_config_label"));
+       priv->json_config_widget = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "team_json_config"));
+       priv->import_config_button = GTK_WIDGET (gtk_builder_get_object (builder, "import_config_button"));
 
-       priv->toplevel = GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (priv->json_config),
+       priv->toplevel = GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (priv->json_config_widget),
                                                              GTK_TYPE_WINDOW));
 }
 
 static void
-stuff_changed (GtkWidget *w, gpointer user_data)
+json_config_changed (GObject *object, CEPageTeam *self)
 {
-       ce_page_changed (CE_PAGE (user_data));
+       ce_page_changed (CE_PAGE (self));
+}
+
+static void
+import_config_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
+{
+       CEPageTeamPrivate *priv = CE_PAGE_TEAM_GET_PRIVATE (user_data);
+       GtkTextBuffer *buffer;
+       char *filename;
+       char *buf = NULL;
+       gsize buf_len;
+
+       if (response != GTK_RESPONSE_ACCEPT)
+               goto out;
+
+       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+       if (!filename) {
+               g_warning ("%s: didn't get a filename back from the chooser!", __func__);
+               goto out;
+       }
+
+       /* Put the file content into JSON config text view. */
+       // FIXME: do a cleverer file validity check
+       g_file_get_contents (filename, &buf, &buf_len, NULL);
+       if (buf_len > 100000) {
+               g_free (buf);
+               buf = g_strdup (_("Error: file doesn't contain a valid JSON configuration"));
+       }
+
+       buffer = gtk_text_view_get_buffer (priv->json_config_widget);
+       gtk_text_buffer_set_text (buffer, buf ? buf : "", -1);
+
+       g_free (filename);
+       g_free (buf);
+
+out:
+       gtk_widget_hide (dialog);
+       gtk_widget_destroy (dialog);
+}
+
+static void
+import_button_clicked_cb (GtkWidget *widget, CEPageTeam *self)
+{
+       GtkWidget *dialog;
+
+       dialog = gtk_file_chooser_dialog_new (_("Select file to import"),
+                                             NULL,
+                                             GTK_FILE_CHOOSER_ACTION_OPEN,
+                                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                             NULL);
+
+       g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (import_config_from_file_cb), self);
+       gtk_widget_show_all (dialog);
+       gtk_window_present (GTK_WINDOW (dialog));
 }
 
 static void
@@ -69,10 +123,15 @@ populate_ui (CEPageTeam *self)
 {
        CEPageTeamPrivate *priv = CE_PAGE_TEAM_GET_PRIVATE (self);
        NMSettingTeam *s_team = priv->setting;
+       GtkTextBuffer *buffer;
        const char *json_config;
 
+       buffer = gtk_text_view_get_buffer (priv->json_config_widget);
        json_config = nm_setting_team_get_config (s_team);
-       gtk_entry_set_text (priv->json_config, json_config ? json_config : "");
+       gtk_text_buffer_set_text (buffer, json_config ? json_config : "", -1);
+
+       g_signal_connect (buffer, "changed", G_CALLBACK (json_config_changed), self);
+       g_signal_connect (priv->import_config_button, "clicked", G_CALLBACK (import_button_clicked_cb), self);
 }
 
 static void
@@ -115,14 +174,10 @@ add_slave (CEPageMaster *master, NewConnectionResultFunc result_func)
 static void
 finish_setup (CEPageTeam *self, gpointer unused, GError *error, gpointer user_data)
 {
-       CEPageTeamPrivate *priv = CE_PAGE_TEAM_GET_PRIVATE (self);
-
        if (error)
                return;
 
        populate_ui (self);
-
-       g_signal_connect (priv->json_config, "changed", G_CALLBACK (stuff_changed), self);
 }
 
 CEPage *
@@ -168,14 +223,21 @@ static void
 ui_to_setting (CEPageTeam *self)
 {
        CEPageTeamPrivate *priv = CE_PAGE_TEAM_GET_PRIVATE (self);
-       const char *json_config;
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       char *json_config;
+
+       buffer = gtk_text_view_get_buffer (priv->json_config_widget);
+       gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
+       gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
+       json_config = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
 
-       json_config = gtk_entry_get_text (priv->json_config);
-       if (!g_strcmp0(json_config, ""))
+       if (g_strcmp0 (json_config, "") == 0)
                json_config = NULL;
        g_object_set (priv->setting,
                      NM_SETTING_TEAM_CONFIG, json_config,
                      NULL);
+       g_free (json_config);
 }
 
 static gboolean


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