[rygel] ui: Support multiple network interfaces



commit eddc238a5d9c1f00d43f51eb630bee714808a671
Author: Jens Georg <jensg openismus com>
Date:   Sat May 11 00:36:10 2013 +0200

    ui: Support multiple network interfaces

 data/rygel-preferences.ui              |  173 ++++++++++++++++++++++++-------
 src/ui/rygel-network-pref-section.vala |  132 ++++++++++++++++++------
 2 files changed, 234 insertions(+), 71 deletions(-)
---
diff --git a/data/rygel-preferences.ui b/data/rygel-preferences.ui
index b53ecb3..349611f 100644
--- a/data/rygel-preferences.ui
+++ b/data/rygel-preferences.ui
@@ -7,6 +7,12 @@
       <column type="gchararray"/>
     </columns>
   </object>
+  <object class="GtkListStore" id="networks-liststore">
+    <columns>
+      <!-- column-name network-name -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
   <object class="GtkDialog" id="preferences-dialog">
     <property name="width_request">480</property>
     <property name="height_request">240</property>
@@ -15,7 +21,7 @@
     <property name="vexpand">True</property>
     <property name="border_width">6</property>
     <property name="title" translatable="yes">Rygel Preferences</property>
-    <property name="default_height">400</property>
+    <property name="default_height">600</property>
     <property name="type_hint">dialog</property>
     <child internal-child="vbox">
       <object class="GtkBox" id="dialog-vbox1">
@@ -128,44 +134,6 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="iface-label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="margin_left">12</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes" comments="Network Interface">_Network:</property>
-                <property name="use_underline">True</property>
-                <property name="mnemonic_widget">iface-entry</property>
-              </object>
-              <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">2</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkComboBoxText" id="iface-entry">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="has_tooltip">True</property>
-                <property name="tooltip_markup" translatable="yes">Select the network interface that DLNA 
media will be shared on, or share media on all interfaces</property>
-                <property name="tooltip_text" translatable="yes">Select the network interface that DLNA 
media will be shared on, or share media on all interfaces</property>
-                <property name="hexpand">True</property>
-                <property name="entry_text_column">0</property>
-                <property name="id_column">1</property>
-                <items>
-                  <item translatable="yes">Any</item>
-                </items>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">2</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
-              </packing>
-            </child>
-            <child>
               <object class="GtkGrid" id="grid3">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
@@ -207,6 +175,133 @@
                 <property name="height">1</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkGrid" id="grid4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_left">12</property>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTreeView" id="networks-treeview">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="model">networks-liststore</property>
+                        <property name="headers_visible">False</property>
+                        <property name="headers_clickable">False</property>
+                        <property name="search_column">0</property>
+                        <property name="fixed_height_mode">True</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection" id="networks-tree-selection"/>
+                        </child>
+                        <child>
+                          <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+                            <property name="sizing">fixed</property>
+                            <property name="title" translatable="yes">column</property>
+                            <child>
+                              <object class="GtkCellRendererCombo" id="cellrenderertext2">
+                                <property name="editable">True</property>
+                                <property name="model">iface-liststore</property>
+                                <property name="text_column">0</property>
+                              </object>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToolbar" id="toolbar2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="toolbar_style">icons</property>
+                    <property name="icon_size">1</property>
+                    <style>
+                      <class name="inline-toolbar"/>
+                    </style>
+                    <child>
+                      <object class="GtkToolButton" id="network-add-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="has_tooltip">True</property>
+                        <property name="tooltip_markup" translatable="yes">Add a directory to the list of 
shared directories</property>
+                        <property name="tooltip_text" translatable="yes">Add a directory to the list of 
shared directories</property>
+                        <property name="label" translatable="yes">Add shared directory</property>
+                        <property name="icon_name">list-add-symbolic</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="homogeneous">True</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkToolButton" id="network-remove-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="has_tooltip">True</property>
+                        <property name="tooltip_markup" translatable="yes">Remove a directory from the list 
of shared directories</property>
+                        <property name="tooltip_text" translatable="yes">Remove a directory from the list of 
shared directories</property>
+                        <property name="label" translatable="yes">Remove shared directory</property>
+                        <property name="icon_name">list-remove-symbolic</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="homogeneous">True</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">3</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Networks:</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">2</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
           </object>
           <packing>
             <property name="expand">False</property>
diff --git a/src/ui/rygel-network-pref-section.vala b/src/ui/rygel-network-pref-section.vala
index 0c4d8d5..b80924f 100644
--- a/src/ui/rygel-network-pref-section.vala
+++ b/src/ui/rygel-network-pref-section.vala
@@ -22,11 +22,20 @@
  */
 using Gtk;
 using GUPnP;
+using Gee;
 
 public class Rygel.NetworkPrefSection : PreferencesSection {
-    const string IFACE_ENTRY = "iface-entry";
-
-    private ComboBoxText iface_entry;
+    const string IFACE_STORE = "iface-liststore";
+    const string NETWORKS_STORE = "networks-liststore";
+    const string TREEVIEW = "networks-treeview";
+    const string TREE_SELECTION = "networks-tree-selection";
+
+    private ListStore iface_store;
+    private ListStore networks_store;
+    private TreeView treeview;
+    private TreeSelection tree_selection;
+    private Grid grid;
+    private ToolButton remove_button;
 
     private ContextManager context_manager;
 
@@ -34,19 +43,50 @@ public class Rygel.NetworkPrefSection : PreferencesSection {
                                WritableUserConfig config) throws Error {
         base (config, "general");
 
-        this.iface_entry = (ComboBoxText) builder.get_object (IFACE_ENTRY);
-        assert (this.iface_entry != null);
-
+        this.iface_store = builder.get_object (IFACE_STORE) as ListStore;
+        assert (this.iface_store != null);
+
+        this.networks_store = builder.get_object (NETWORKS_STORE) as ListStore;
+        assert (this.networks_store != null);
+
+        this.tree_selection = builder.get_object (TREE_SELECTION) as
+            TreeSelection;
+
+        var renderer = builder.get_object ("cellrenderertext2")
+                                        as CellRendererCombo;
+        renderer.edited.connect ( (path, new_) => {
+            TreeIter iter;
+            networks_store.get_iter_from_string (out iter, path);
+            networks_store.set (iter, 0, new_);
+        });
+
+        this.treeview = builder.get_object (TREEVIEW) as TreeView;
+
+        this.remove_button = builder.get_object ("network-remove-button")
+                                        as ToolButton;
+        remove_button.clicked.connect (this.on_remove_button_clicked);
+
+        var add_button = builder.get_object ("network-add-button")
+                                       as ToolButton;
+        add_button.clicked.connect ( () => {
+            TreeIter iter;
+            networks_store.append (out iter);
+            var path = networks_store.get_path (iter);
+            this.treeview.set_cursor (path,
+                                      this.treeview.get_column (0),
+                                      true);
+            this.treeview.grab_focus ();
+        });
+
+        this.grid = builder.get_object ("grid4") as Grid;
         this.context_manager = ContextManager.create (0);
 
         try {
             var interfaces = config.get_interfaces ();
-            if (interfaces != null) {
-                int num_items;
-
-                this.iface_entry.append_text (interfaces[0]);
-                num_items = this.count_items (this.iface_entry.model);
-                this.iface_entry.set_active (num_items - 1);
+            foreach (var iface in interfaces) {
+                TreeIter iter;
+                networks_store.append (out iter);
+                networks_store.set (iter, 0, iface);
             }
         } catch (GLib.Error err) {
             // No problem if we fail to read the config, the default values
@@ -57,21 +97,29 @@ public class Rygel.NetworkPrefSection : PreferencesSection {
                                         (this.on_context_available);
         this.context_manager.context_unavailable.connect
                                         (this.on_context_unavailable);
+
+        this.on_tree_selection_changed ();
+        this.tree_selection.changed.connect (this.on_tree_selection_changed);
     }
 
     public override void save () {
-        var iface = this.iface_entry.get_active_text ();
+        TreeIter iter;
+        var uri_list = new Gee.ArrayList<string> ();
+
+        if (this.networks_store.get_iter_first (out iter)) {
+            do {
+                string uri;
 
-        // The zeroth item is "Any" network. -1 represents no active item.
-        if (this.iface_entry.active <= 0 ) {
-            iface = "";
+                this.networks_store.get (iter, 0, out uri, -1);
+                uri_list.add (uri);
+            } while (this.networks_store.iter_next (ref iter));
         }
 
-        this.config.set_interface (iface);
+        this.config.set_string_list ("general", "interface", uri_list);
     }
 
     public override void set_sensitivity (bool sensitivity) {
-        iface_entry.sensitive = sensitivity;
+        this.grid.sensitive = sensitivity;
     }
 
     private void on_context_available (GUPnP.ContextManager manager,
@@ -79,7 +127,8 @@ public class Rygel.NetworkPrefSection : PreferencesSection {
         TreeIter iter;
 
         if (!this.find_interface (context.interface, out iter)) {
-            this.iface_entry.append_text (context.interface);
+            this.iface_store.append (out iter);
+            this.iface_store.set (iter, 0, context.interface);
         }
     }
 
@@ -88,14 +137,37 @@ public class Rygel.NetworkPrefSection : PreferencesSection {
         TreeIter iter;
 
         if (this.find_interface (context.interface, out iter)) {
-            var list_store = this.iface_entry.model as ListStore;
-            list_store.remove (iter);
+            this.iface_store.remove (iter);
+        }
+    }
+
+    private void on_remove_button_clicked (ToolButton button) {
+        var selection = this.treeview.get_selection ();
+        var rows = selection.get_selected_rows (null);
+
+        // First get permanent references to rows
+        var row_refs = new Gee.ArrayList<TreeRowReference> ();
+        foreach (var row in rows) {
+            row_refs.add (new TreeRowReference (this.networks_store, row));
+        }
+
+        // Now we can safely remove rows
+        foreach (var row_ref in row_refs) {
+           TreeIter iter;
+
+           var path = row_ref.get_path ();
+           this.networks_store.get_iter (out iter, path);
+
+           this.networks_store.remove (iter);
         }
     }
 
+
     private bool find_interface (string iface, out TreeIter iter) {
-        var model = this.iface_entry.model;
+        var model = this.iface_store;
         var more = model.get_iter_first (out iter);
+        string name = null;
+
         while (more) {
             model.get (iter, 0, &name, -1);
 
@@ -109,16 +181,12 @@ public class Rygel.NetworkPrefSection : PreferencesSection {
         return more;
     }
 
-    private int count_items (TreeModel model) {
-        TreeIter iter;
-        int count = 0;
-        var more = model.get_iter_first (out iter);
-
-        while (more) {
-            count++;
-            more = model.iter_next (ref iter);
+    private void on_tree_selection_changed () {
+        // Remove button cannot be sensitive if no row is selected
+        if (tree_selection.get_selected (null, null)) {
+            remove_button.set_sensitive (true);
+        } else {
+            remove_button.set_sensitive (false);
         }
-
-        return count;
     }
 }


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