ui: Improve preferences dialog, bug 663631
authorDavid King <amigadave@amigadave.com>
Tue, 8 Nov 2011 14:34:10 +0000 (15:34 +0100)
committerJens Georg <mail@jensge.org>
Mon, 6 Feb 2012 19:09:53 +0000 (20:09 +0100)
Add tooltips to the widgets in the preferences dialog. Add +/-
ToolButtons for adding and removing shared directories. Update the
sensitivity of the remove toolbutton, based on whether a row in the URI
model is selected, or if the model is empty. Remove the GtkAlignments
and use padding on containers. Set the correct response ID on the close
button. Set the entry text column in the GtkBuilder file.

TODO
data/rygel-preferences.ui
src/ui/rygel-media-pref-section.vala
src/ui/rygel-network-pref-section.vala

diff --git a/TODO b/TODO
index 992c026..07e15b5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -54,7 +54,6 @@
 
   * UI
     * Make sure we restart rygel when configuration changes.
-    * Fix tooltips.
     * Get interfaces directly from NM.
     * Show available APs for Wifi interface.
 
index 7a2780d..3a2aaac 100644 (file)
@@ -1,11 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-requires gtk+ 3.0 -->
   <object class="GtkAdjustment" id="adjustment1">
     <property name="upper">65525</property>
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
+  <object class="GtkSizeGroup" id="general-labels-sizegroup">
+    <property name="mode">both</property>
+  </object>
   <object class="GtkListStore" id="iface-liststore">
     <columns>
       <!-- column-name interface -->
@@ -18,7 +21,7 @@
     <property name="can_focus">False</property>
     <property name="hexpand">True</property>
     <property name="vexpand">True</property>
-    <property name="border_width">5</property>
+    <property name="border_width">6</property>
     <property name="title" translatable="yes">Rygel Preferences</property>
     <property name="default_height">400</property>
     <property name="type_hint">dialog</property>
         <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
         <property name="spacing">12</property>
-        <child internal-child="action_area">
-          <object class="GtkButtonBox" id="dialog-action_area1">
+        <child>
+          <object class="GtkGrid" id="grid1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="layout_style">end</property>
+            <property name="row_spacing">12</property>
+            <property name="column_spacing">12</property>
             <child>
-              <object class="GtkButton" id="button3">
-                <property name="label">gtk-close</property>
+              <object class="GtkCheckButton" id="upnp-checkbutton">
+                <property name="label" translatable="yes">_Share media through DLNA</property>
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
-                <property name="has_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="has_tooltip">True</property>
+                <property name="tooltip_markup" translatable="yes">Enable sharing of media, such as photos, videos and music, with DLNA</property>
+                <property name="tooltip_text" translatable="yes">Enable sharing of media, such as photos, videos and music, with DLNA</property>
                 <property name="use_action_appearance">False</property>
-                <property name="use_stock">True</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
               </object>
               <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
               </packing>
             </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAlignment" id="alignment1">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="top_padding">12</property>
-            <property name="bottom_padding">12</property>
-            <property name="left_padding">12</property>
-            <property name="right_padding">12</property>
             <child>
-              <object class="GtkVBox" id="vbox1">
+              <object class="GtkGrid" id="grid2">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="spacing">12</property>
+                <property name="margin_left">12</property>
                 <child>
-                  <object class="GtkCheckButton" id="upnp-checkbutton">
-                    <property name="label" translatable="yes">_Share media through DLNA</property>
+                  <object class="GtkScrolledWindow" id="scrolledwindow1">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="xalign">0</property>
-                    <property name="draw_indicator">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkAlignment" id="alignment2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="left_padding">12</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="shadow_type">in</property>
                     <child>
-                      <object class="GtkHBox" id="hbox2">
+                      <object class="GtkTreeView" id="uris-treeview">
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="spacing">12</property>
-                        <child>
-                          <object class="GtkScrolledWindow" id="scrolledwindow1">
-                            <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="uris-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">uris-liststore</property>
-                                <property name="headers_visible">False</property>
-                                <property name="search_column">0</property>
-                                <property name="fixed_height_mode">True</property>
-                                <child internal-child="selection">
-                                  <object class="GtkTreeSelection" id="treeview-selection"/>
-                                </child>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkVButtonBox" id="vbuttonbox1">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="spacing">5</property>
-                            <property name="layout_style">start</property>
-                            <child>
-                              <object class="GtkButton" id="add-button">
-                                <property name="label">gtk-add</property>
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="use_action_appearance">False</property>
-                                <property name="use_underline">True</property>
-                                <property name="use_stock">True</property>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">True</property>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkButton" id="remove-button">
-                                <property name="label">gtk-remove</property>
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="use_action_appearance">False</property>
-                                <property name="use_stock">True</property>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">True</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkButton" id="clear-button">
-                                <property name="label">gtk-clear</property>
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="use_action_appearance">False</property>
-                                <property name="use_underline">True</property>
-                                <property name="use_stock">True</property>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">True</property>
-                                <property name="position">2</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="model">uris-liststore</property>
+                        <property name="headers_visible">False</property>
+                        <property name="search_column">0</property>
+                        <property name="fixed_height_mode">True</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection" id="treeview-selection"/>
                         </child>
                       </object>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
+                    <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="GtkAlignment" id="alignment3">
+                  <object class="GtkToolbar" id="toolbar1">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="left_padding">12</property>
                     <child>
-                      <object class="GtkHBox" id="hbox1">
+                      <object class="GtkToolButton" id="add-button">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
-                        <child>
-                          <object class="GtkLabel" id="iface-label">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes" comments="Network Interface">_Network</property>
-                            <property name="use_underline">True</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkComboBoxText" id="iface-entry">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <items>
-                              <item translatable="yes">Any</item>
-                            </items>
-                          </object>
-                          <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
+                        <property name="tooltip_text" translatable="yes">Add a directory to the list of shared directories</property>
+                        <property name="use_action_appearance">False</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="remove-button">
+                        <property name="use_action_appearance">False</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="tooltip_text" translatable="yes">Remove a directory from the list of shared directories</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="label" translatable="yes">Remove 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>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">2</property>
+                    <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">1</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </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>
           </object>
           <packing>
             <property name="position">0</property>
           </packing>
         </child>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button3">
+                <property name="label">gtk-close</property>
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="has_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
       </object>
     </child>
     <action-widgets>
-      <action-widget response="0">button3</action-widget>
+      <action-widget response="-7">button3</action-widget>
     </action-widgets>
   </object>
+  <object class="GtkSizeGroup" id="plugin-labels-sizegroup"/>
   <object class="GtkFileChooserDialog" id="uris-dialog">
     <property name="can_focus">False</property>
     <property name="can_default">True</property>
             <child>
               <object class="GtkButton" id="button4">
                 <property name="label">gtk-cancel</property>
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="can_default">True</property>
             <child>
               <object class="GtkButton" id="button5">
                 <property name="label">gtk-open</property>
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="can_default">True</property>
               </packing>
             </child>
           </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
         </child>
         <child>
           <placeholder/>
       <action-widget response="-5">button5</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkSizeGroup" id="general-labels-sizegroup">
-    <property name="mode">both</property>
-  </object>
-  <object class="GtkSizeGroup" id="plugin-labels-sizegroup"/>
   <object class="GtkListStore" id="uris-liststore">
     <columns>
       <!-- column-name path -->
index a3d1a9e..e05234b 100644 (file)
@@ -31,13 +31,15 @@ public class Rygel.MediaPrefSection : PreferencesSection {
     const string URIS_DIALOG = URIS_KEY + "-dialog";
     const string ADD_BUTTON = "add-button";
     const string REMOVE_BUTTON = "remove-button";
-    const string CLEAR_BUTTON = "clear-button";
+    const string TREE_SELECTION = "treeview-selection";
 
     private ArrayList<Widget> widgets; // All widgets in this section
 
     private TreeView treeview;
     private ListStore liststore;
+    private TreeSelection tree_selection;
     private FileChooserDialog dialog;
+    private ToolButton remove_button;
 
     public MediaPrefSection (Builder            builder,
                              WritableUserConfig config) {
@@ -49,6 +51,9 @@ public class Rygel.MediaPrefSection : PreferencesSection {
         assert (this.treeview != null);
         this.liststore = (ListStore) builder.get_object (URIS_LISTSTORE);
         assert (this.liststore != null);
+        this.tree_selection = builder.get_object (TREE_SELECTION)
+                                                  as TreeSelection;
+        assert (this.tree_selection != null);
         this.dialog = (FileChooserDialog) builder.get_object (URIS_DIALOG);
         assert (this.dialog != null);
 
@@ -74,17 +79,17 @@ public class Rygel.MediaPrefSection : PreferencesSection {
         this.dialog.set_current_folder (Environment.get_home_dir ());
         this.dialog.show_hidden = false;
 
-        var button = (Button) builder.get_object (ADD_BUTTON);
-        button.clicked.connect (this.on_add_button_clicked);
-        this.widgets.add (button);
+        var add_button = builder.get_object (ADD_BUTTON) as ToolButton;
+        add_button.clicked.connect (this.on_add_button_clicked);
+        this.widgets.add (add_button);
 
-        button = (Button) builder.get_object (REMOVE_BUTTON);
-        button.clicked.connect (this.on_remove_button_clicked);
-        this.widgets.add (button);
+        remove_button = builder.get_object (REMOVE_BUTTON) as ToolButton;
+        remove_button.clicked.connect (this.on_remove_button_clicked);
+        this.widgets.add (remove_button);
 
-        button = (Button) builder.get_object (CLEAR_BUTTON);
-        button.clicked.connect (this.on_clear_button_clicked);
-        this.widgets.add (button);
+        // Update the sensitivity of the remove button
+        this.on_tree_selection_changed ();
+        this.tree_selection.changed.connect (this.on_tree_selection_changed);
     }
 
     public override void save () {
@@ -108,9 +113,14 @@ public class Rygel.MediaPrefSection : PreferencesSection {
         foreach (var widget in this.widgets) {
             widget.sensitive = sensitivity;
         }
+
+        // Force an update of the remove button.
+        if (sensitivity) {
+            this.on_tree_selection_changed ();
+        }
     }
 
-    private void on_add_button_clicked (Button button) {
+    private void on_add_button_clicked (ToolButton button) {
         if (this.dialog.run () == ResponseType.OK) {
             TreeIter iter;
 
@@ -131,7 +141,7 @@ public class Rygel.MediaPrefSection : PreferencesSection {
         this.dialog.hide ();
     }
 
-    private void on_remove_button_clicked (Button button) {
+    private void on_remove_button_clicked (ToolButton button) {
         var selection = this.treeview.get_selection ();
         var rows = selection.get_selected_rows (null);
 
@@ -152,10 +162,6 @@ public class Rygel.MediaPrefSection : PreferencesSection {
         }
     }
 
-    private void on_clear_button_clicked (Button button) {
-        this.liststore.clear ();
-    }
-
     private string get_real_uri (string uri) {
         switch (uri) {
         case "@MUSIC@":
@@ -182,4 +188,13 @@ public class Rygel.MediaPrefSection : PreferencesSection {
             return uri;
         }
     }
+
+    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);
+        }
+    }
 }
index 4997f14..0e6c8bc 100644 (file)
@@ -25,7 +25,6 @@ using GUPnP;
 
 public class Rygel.NetworkPrefSection : PreferencesSection {
     const string IFACE_ENTRY = "iface-entry";
-    const string ANY_NETWORK = "Any";
 
     private ComboBoxText iface_entry;
 
@@ -40,10 +39,9 @@ public class Rygel.NetworkPrefSection : PreferencesSection {
 
         this.context_manager = new ContextManager (null, 0);
 
-        // Apparently glade/GtkBuilder is unable to do this for us
-        this.iface_entry.set_entry_text_column (0);
         try {
             this.iface_entry.append_text (config.get_interface ());
+            // TODO: Set the current interface to be active.
             this.iface_entry.set_active (0);
         } catch (GLib.Error err) {
             // No problem if we fail to read the config, the default values
@@ -59,7 +57,8 @@ public class Rygel.NetworkPrefSection : PreferencesSection {
     public override void save () {
         var iface = this.iface_entry.get_active_text ();
 
-        if (iface == ANY_NETWORK) {
+        // The zeroth item is "Any" network. -1 represents no active item.
+        if (this.iface_entry.active <= 0 ) {
             iface = "";
         }