[gtk+/multiroot-filechooser: 11/15] Add support for multiple roots.



commit 4ab090b831876fbc84c45a721591550e233630f2
Author: Christian Hammond <chipx86 chipx86 com>
Date:   Tue Mar 16 17:05:34 2010 -0700

    Add support for multiple roots.
    
    This introduces support for multiple roots on the file chooser. Instead
    of rooting to a single URI, there can now be several roots, which will be
    taken into account when selecting files, typing custom file paths, or showing
    parts of the UI.
    
    This makes it possible to, for example, limit the file chooser to the user's
    home directory and memory stick.

 gtk/gtkfilechooser.c        |  129 ++++++++++--------
 gtk/gtkfilechooser.h        |    6 +-
 gtk/gtkfilechooserbutton.c  |   29 +++--
 gtk/gtkfilechooserdefault.c |  302 ++++++++++++++++++++++++-------------------
 gtk/gtkfilechooserentry.c   |   30 ++---
 gtk/gtkfilechooserentry.h   |    6 +-
 gtk/gtkfilechooserprivate.h |    6 +-
 gtk/gtkfilechooserutils.c   |    4 +-
 gtk/gtkfilechooserutils.h   |    4 +-
 gtk/gtkpathbar.c            |   26 ++--
 gtk/gtkpathbar.h            |    6 +-
 11 files changed, 297 insertions(+), 251 deletions(-)
---
diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c
index db02215..4306151 100644
--- a/gtk/gtkfilechooser.c
+++ b/gtk/gtkfilechooser.c
@@ -851,23 +851,22 @@ gtk_file_chooser_class_init (gpointer g_iface)
 							     GTK_PARAM_READWRITE));
 
   /**
-   * GtkFileChooser:root-uri:
+   * GtkFileChooser:root-uris:
    *
-   * The absolute root URI that can be accessed in the file chooser.
+   * The absolute root URIs that can be accessed in the file chooser.
    * Any shortcuts (special or user-defined) or volumes not within
-   * this URI will be filtered out for this dialog.
+   * these URIs will be filtered out for this dialog.
    *
-   * The default is an empty string or NULL, which provides the
-   * default level of access for the file chooser.
+   * The default is NULL, which provides the default level of access
+   * for the file chooser.
    *
    * Since: 2.18
    */
   g_object_interface_install_property (g_iface,
-				       g_param_spec_string ("root-uri",
-							     P_("Root URI"),
-							     P_("The URI, if any, to use as the root for all access in the file chooser."),
-							     NULL,
-							     GTK_PARAM_READWRITE));
+				       g_param_spec_pointer ("root-uris",
+							   P_("Root URIs"),
+							   P_("The URIs, if any, to use as the root for all access in the file chooser."),
+							   GTK_PARAM_READWRITE));
 }
 
 /**
@@ -945,8 +944,8 @@ gtk_file_chooser_get_action (GtkFileChooser *chooser)
  * rather than the URI functions like
  * gtk_file_chooser_get_uri(),
  *
- * This implies a root URI of "file://". See
- * gtk_file_chooser_set_root_uri().
+ * This implies a single root URI of "file://". See
+ * gtk_file_chooser_set_root_uris().
  *
  * Since: 2.4
  **/
@@ -967,7 +966,7 @@ gtk_file_chooser_set_local_only (GtkFileChooser *chooser,
  * file selector. See gtk_file_chooser_set_local_only()
  *
  * This is %TRUE when the root URI of the file chooser is
- * "file://". See gtk_file_chooser_get_root_uri().
+ * "file://". See gtk_file_chooser_get_root_uris().
  * 
  * Return value: %TRUE if only local files can be selected.
  *
@@ -986,12 +985,12 @@ gtk_file_chooser_get_local_only (GtkFileChooser *chooser)
 }
 
 /**
- * gtk_file_chooser_set_root_uri:
+ * gtk_file_chooser_set_root_uris:
  * @chooser: a #GtkFileChooser
  * @root_uri: The root URI, or %NULL to allow access to everything.
  *
- * Sets the URI that will be the root of the file chooser. The file
- * chooser will not display or allow access to files outside of this URI.
+ * Sets the URIs that will be the roots of the file chooser. The file
+ * chooser will not display or allow access to files outside of these URIs.
  *
  * If this is set to %NULL, then the file chooser will have access to all
  * local and remote volumes and files.
@@ -1000,25 +999,29 @@ gtk_file_chooser_get_local_only (GtkFileChooser *chooser)
  * directory and its subdirectories, to a particular storage device, or to a
  * remote server.
  *
- * See gtk_file_chooser_get_root_uri()
+ * If more than one root URI is provided for the same filesystem or protocol
+ * (for example, "file:///home" and "file:///"), then the most permissive will
+ * be used (in this case, "file:///").
+ *
+ * See gtk_file_chooser_get_root_uris()
  *
  * Since: 2.18
  **/
 void
-gtk_file_chooser_set_root_uri (GtkFileChooser *chooser,
-			       const gchar    *root_uri)
+gtk_file_chooser_set_root_uris (GtkFileChooser *chooser,
+			        GSList         *root_uris)
 {
   g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
 
-  g_object_set (chooser, "root-uri", root_uri, NULL);
+  g_object_set (chooser, "root-uris", root_uris, NULL);
 }
 
 /**
- * gtk_file_chooser_get_root_uri:
+ * gtk_file_chooser_get_root_uris:
  * @chooser: a #GtkFileChooser
  *
- * Gets the URI that is the root of the file chooser. The file chooser
- * will not display or allow access to files outside of this URI.
+ * Gets the URIs that are the roots of the file chooser. The file chooser
+ * will not display or allow access to files outside of these URIs.
  *
  * If this is %NULL, then the file chooser has access to all local and
  * remote volumes and files.
@@ -1027,22 +1030,26 @@ gtk_file_chooser_set_root_uri (GtkFileChooser *chooser,
  * directory and its subdirectories, to a particular storage device, or to a
  * remote server.
  *
- * See gtk_file_chooser_set_root_uri()
+ * If more than one root URI is provided for the same filesystem or protocol
+ * (for example, "file:///home" and "file:///"), then the most permissive will
+ * be used (in this case, "file:///").
+ *
+ * See gtk_file_chooser_set_root_uris()
  *
- * Return value: The root URI, or %NULL.
+ * Return value: The root URIs, or %NULL.
  *
  * Since: 2.18
  **/
-const gchar *
-gtk_file_chooser_get_root_uri (GtkFileChooser *chooser)
+GSList *
+gtk_file_chooser_get_root_uris (GtkFileChooser *chooser)
 {
-  const gchar *root_uri;
+  GSList *root_uris;
 
   g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
 
-  g_object_get (chooser, "root-uri", &root_uri, NULL);
+  g_object_get (chooser, "root-uris", &root_uris, NULL);
 
-  return root_uri;
+  return root_uris;
 }
 
 /**
@@ -2859,41 +2866,46 @@ gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser)
 #endif
 
 gboolean
-_gtk_file_chooser_uri_has_prefix (const char *uri,
-                                  const char *prefix)
+_gtk_file_chooser_uri_has_prefix (const char   *uri,
+                                  const GSList *prefixes)
 {
   int uri_len;
-  int prefix_len;
-  gboolean result;
-  char *new_prefix = NULL;
+  gboolean result = FALSE;
+  const GSList *l;
 
   g_return_val_if_fail (uri != NULL, FALSE);
-  g_return_val_if_fail (prefix != NULL, FALSE);
+  g_return_val_if_fail (prefixes != NULL, FALSE);
 
   uri_len = strlen (uri);
-  prefix_len = strlen (prefix);
 
-  if (prefix[prefix_len - 1] != '/')
+  for (l = prefixes; l != NULL && !result; l = l->next)
     {
-      new_prefix = g_strdup_printf ("%s/", prefix);
-      prefix = new_prefix;
-      prefix_len++;
+      char *new_prefix = NULL;
+      char *prefix = (char *)l->data;
+      int prefix_len = strlen (prefix);
+
+      if (prefix[prefix_len - 1] != '/')
+        {
+          new_prefix = g_strdup_printf ("%s/", prefix);
+          prefix = new_prefix;
+          prefix_len++;
+        }
+
+      if (prefix_len == uri_len + 1)
+        {
+          /*
+           * Special case. The prefix URI may contain a trailing slash while the
+           * URI we're comparing against may not (or vice-versa), despite the
+           * URIs being equal.
+           */
+          result = !strncmp (prefix, uri, uri_len);
+        }
+      else
+        result = (uri_len >= prefix_len && g_str_has_prefix (uri, prefix));
+
+      g_free (new_prefix);
     }
 
-  if (prefix_len == uri_len + 1)
-    {
-      /*
-       * Special case. The prefix URI may contain a trailing slash while the
-       * URI we're comparing against may not (or vice-versa), despite the
-       * URIs being equal.
-       */
-      result = !strncmp (prefix, uri, uri_len);
-    }
-  else
-    result = (uri_len >= prefix_len && g_str_has_prefix (uri, prefix));
-
-  g_free (new_prefix);
-
   return result;
 }
 
@@ -2901,14 +2913,15 @@ gboolean
 _gtk_file_chooser_is_uri_in_root (GtkFileChooser *chooser,
                                   const char     *uri)
 {
-  const char *root_uri;
+  GSList *root_uris;
 
   g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
   g_return_val_if_fail (uri != NULL, FALSE);
 
-  root_uri = gtk_file_chooser_get_root_uri (chooser);
+  root_uris = gtk_file_chooser_get_root_uris (chooser);
 
-  return root_uri == NULL || _gtk_file_chooser_uri_has_prefix (uri, root_uri);
+  return root_uris == NULL ||
+         _gtk_file_chooser_uri_has_prefix (uri, root_uris);
 }
 
 gboolean
diff --git a/gtk/gtkfilechooser.h b/gtk/gtkfilechooser.h
index 9ac4058..63ec0a1 100644
--- a/gtk/gtkfilechooser.h
+++ b/gtk/gtkfilechooser.h
@@ -123,9 +123,9 @@ GtkFileChooserAction gtk_file_chooser_get_action          (GtkFileChooser
 void                 gtk_file_chooser_set_local_only      (GtkFileChooser       *chooser,
 							   gboolean              local_only);
 gboolean             gtk_file_chooser_get_local_only      (GtkFileChooser       *chooser);
-void                 gtk_file_chooser_set_root_uri        (GtkFileChooser       *chooser,
-							   const gchar          *root_uri);
-const gchar         *gtk_file_chooser_get_root_uri        (GtkFileChooser       *chooser);
+void                 gtk_file_chooser_set_root_uris       (GtkFileChooser       *chooser,
+							   GSList               *root_uris);
+GSList              *gtk_file_chooser_get_root_uris       (GtkFileChooser       *chooser);
 void                 gtk_file_chooser_set_select_multiple (GtkFileChooser       *chooser,
 							   gboolean              select_multiple);
 gboolean             gtk_file_chooser_get_select_multiple (GtkFileChooser       *chooser);
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index 0d3c87f..ca4415e 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -876,14 +876,17 @@ gtk_file_chooser_button_set_property (GObject      *object,
       break;
 
     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
-    case GTK_FILE_CHOOSER_PROP_ROOT_URI:
+    case GTK_FILE_CHOOSER_PROP_ROOT_URIS:
       g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
 
       if (!_gtk_file_chooser_is_file_in_root (filechooser,
             gtk_file_chooser_get_current_folder_file (filechooser)))
         {
-          GFile *file = g_file_new_for_uri (
-            gtk_file_chooser_get_root_uri (filechooser));
+          GSList *root_uris = gtk_file_chooser_get_root_uris (filechooser);
+
+          GFile *file = g_file_new_for_uri (root_uris == NULL
+                                            ? "file:///"
+                                            : (char *)root_uris->data);
 
           gtk_file_chooser_set_current_folder_file (filechooser, file, NULL);
           model_update_current_folder (button, file);
@@ -943,7 +946,7 @@ gtk_file_chooser_button_get_property (GObject    *object,
     case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
     case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
     case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
-    case GTK_FILE_CHOOSER_PROP_ROOT_URI:
+    case GTK_FILE_CHOOSER_PROP_ROOT_URIS:
       g_object_get_property (G_OBJECT (priv->dialog), pspec->name, value);
       break;
 
@@ -1834,7 +1837,7 @@ model_add_volumes (GtkFileChooserButton *button,
   GtkListStore *store;
   gint pos;
   gboolean local_only;
-  const char *root_uri;
+  GSList *root_uris;
   GtkFileSystem *file_system;
   GtkFileChooser *filechooser;
   GSList *l;
@@ -1846,7 +1849,7 @@ model_add_volumes (GtkFileChooserButton *button,
   pos = model_get_type_position (button, ROW_TYPE_VOLUME);
   filechooser = GTK_FILE_CHOOSER (button->priv->dialog);
   local_only = gtk_file_chooser_get_local_only (filechooser);
-  root_uri = gtk_file_chooser_get_root_uri (filechooser);
+  root_uris = gtk_file_chooser_get_root_uris (filechooser);
   file_system = button->priv->fs;
 
   for (l = volumes; l; l = l->next)
@@ -1867,7 +1870,7 @@ model_add_volumes (GtkFileChooserButton *button,
           _gtk_file_system_volume_is_mounted (volume) &&
           !g_file_is_native (base_file))
         skip = TRUE;
-      else if (root_uri != NULL &&
+      else if (root_uris != NULL &&
                (base_file == NULL ||
                 !_gtk_file_chooser_is_file_in_root (filechooser, base_file)))
         skip = TRUE;
@@ -2152,7 +2155,7 @@ static inline gboolean
 test_if_file_is_visible (GtkFileSystem *fs,
 			 GFile         *file,
 			 gboolean       local_only,
-			 const char    *root_uri,
+			 GSList        *root_uris,
 			 gboolean       is_folder)
 {
   char *uri;
@@ -2165,8 +2168,8 @@ test_if_file_is_visible (GtkFileSystem *fs,
     return FALSE;
 
   uri = g_file_get_uri (file);
-  result = (root_uri == NULL ||
-			_gtk_file_chooser_uri_has_prefix (uri, root_uri));
+  result = (root_uris == NULL ||
+            _gtk_file_chooser_uri_has_prefix (uri, root_uris));
   g_free (uri);
 
   if (!result)
@@ -2188,12 +2191,12 @@ filter_model_visible_func (GtkTreeModel *model,
   gchar type;
   gpointer data;
   gboolean local_only, retval, is_folder;
-  const char *root_uri;
+  GSList *root_uris;
 
   type = ROW_TYPE_INVALID;
   data = NULL;
   local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (priv->dialog));
-  root_uri = gtk_file_chooser_get_root_uri (GTK_FILE_CHOOSER (priv->dialog));
+  root_uris = gtk_file_chooser_get_root_uris (GTK_FILE_CHOOSER (priv->dialog));
 
   gtk_tree_model_get (model, iter,
 		      TYPE_COLUMN, &type,
@@ -2209,7 +2212,7 @@ filter_model_visible_func (GtkTreeModel *model,
     case ROW_TYPE_SPECIAL:
     case ROW_TYPE_SHORTCUT:
     case ROW_TYPE_BOOKMARK:
-      retval = test_if_file_is_visible (priv->fs, data, local_only, root_uri,
+      retval = test_if_file_is_visible (priv->fs, data, local_only, root_uris,
 										is_folder);
       break;
     case ROW_TYPE_VOLUME:
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 72b55f9..d4b94ed 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -718,7 +718,7 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
 #ifdef PROFILE_FILE_CHOOSER
   access ("MARK: *** CREATE FILE CHOOSER", F_OK);
 #endif
-  impl->root_uri = g_strdup ("file://");
+  impl->root_uris = g_slist_append (NULL, g_strdup ("file://"));
   impl->preview_widget_active = TRUE;
   impl->use_preview_label = TRUE;
   impl->select_multiple = FALSE;
@@ -1776,11 +1776,26 @@ shortcuts_append_search (GtkFileChooserDefault *impl)
   gboolean old_changing_folders = impl->changing_folder;
   impl->changing_folder = TRUE;
   int start_row = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
+  gboolean can_search = (impl->root_uris == NULL);
 
   if (impl->has_search)
       shortcuts_remove_rows (impl, start_row, 1);
 
-  if (impl->root_uri == NULL || g_str_has_prefix (impl->root_uri, "file:"))
+  if (!can_search)
+    {
+      GSList *l;
+
+      for (l = impl->root_uris; l != NULL; l = l->next)
+        {
+          if (g_str_has_prefix ((char *)l->data, "file:"))
+            {
+              can_search = TRUE;
+              break;
+            }
+        }
+    }
+
+  if (can_search)
     {
       GtkTreeIter iter;
       GdkPixbuf *pixbuf = render_search_icon (impl);
@@ -2097,7 +2112,7 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
           _gtk_file_system_volume_is_mounted (volume) &&
           !g_file_is_native (base_file))
         skip = TRUE;
-      else if (impl->root_uri != NULL &&
+      else if (impl->root_uris != NULL &&
                (base_file == NULL ||
                 !_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl),
                                                     base_file)))
@@ -2274,7 +2289,7 @@ shortcuts_add_custom_folders (GtkFileChooserDefault *impl)
     {
       GFile *file = (GFile *)l->data;
 
-      if (impl->root_uri != NULL &&
+      if (impl->root_uris != NULL &&
           _gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl), file))
         {
           int pos = shortcuts_get_pos_for_shortcut_folder (impl,
@@ -4944,10 +4959,11 @@ save_widgets_create (GtkFileChooserDefault *impl)
   _gtk_file_chooser_entry_set_local_only (
      GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
      gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (impl)));
-  _gtk_file_chooser_entry_set_root_uri (
+  _gtk_file_chooser_entry_set_root_uris (
      GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
-     impl->root_uri);
-  _gtk_path_bar_set_root_uri (GTK_PATH_BAR (impl->browse_path_bar), impl->root_uri);
+     impl->root_uris);
+  _gtk_path_bar_set_root_uris (GTK_PATH_BAR (impl->browse_path_bar),
+                               impl->root_uris);
   gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
   gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
   gtk_table_attach (GTK_TABLE (table), impl->location_entry,
@@ -5105,9 +5121,9 @@ location_switch_to_filename_entry (GtkFileChooserDefault *impl)
   _gtk_file_chooser_entry_set_local_only (
      GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
      gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (impl)));
-  _gtk_file_chooser_entry_set_root_uri (
+  _gtk_file_chooser_entry_set_root_uris (
      GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
-     impl->root_uri);
+     impl->root_uris);
 
   /* Done */
 
@@ -5392,145 +5408,143 @@ set_extra_widget (GtkFileChooserDefault *impl,
 }
 
 static void
-set_root_uri (GtkFileChooserDefault *impl,
-              const gchar           *root_uri)
+set_root_uris (GtkFileChooserDefault *impl,
+               GSList                *root_uris)
 {
-  if (root_uri == NULL || *root_uri == '\0')
-    root_uri = NULL;
+  GtkTreeIter iter;
+  GFile *list_selected = NULL;
+  ShortcutType shortcut_type = -1;
+  gboolean local_only;
 
-  if (g_strcmp0 (root_uri, impl->root_uri))
-    {
-      GtkTreeIter iter;
-      GFile *list_selected = NULL;
-      ShortcutType shortcut_type = -1;
-      gboolean local_only;
+  if (root_uris == impl->root_uris)
+    return;
 
-      g_free (impl->root_uri);
-      impl->root_uri = (root_uri == NULL ? NULL : g_strdup (root_uri));
+  g_slist_foreach (impl->root_uris, (GFunc)g_free, NULL);
+  g_slist_free (impl->root_uris);
 
-      local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (impl));
+  impl->root_uris = root_uris;
 
-      if (impl->location_entry)
-        {
-          _gtk_file_chooser_entry_set_root_uri (
-            GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
-            impl->root_uri);
-          _gtk_file_chooser_entry_set_local_only (
-            GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
-            local_only);
-        }
+  local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (impl));
 
-      _gtk_path_bar_set_root_uri (GTK_PATH_BAR (impl->browse_path_bar),
-                                  impl->root_uri);
+  if (impl->location_entry)
+    {
+      _gtk_file_chooser_entry_set_root_uris (
+        GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+       impl->root_uris);
+      _gtk_file_chooser_entry_set_local_only (
+        GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+        local_only);
+    }
 
-      /* Attempt to preserve the sidebar selection if possible. */
-      if (shortcuts_get_selected (impl, &iter))
-        {
-          gpointer col_data = NULL;
+  _gtk_path_bar_set_root_uris (GTK_PATH_BAR (impl->browse_path_bar),
+                               impl->root_uris);
 
-          gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
-                              &iter,
-                              SHORTCUTS_COL_DATA, &col_data,
-                              SHORTCUTS_COL_TYPE, &shortcut_type,
-                              -1);
+  /* Attempt to preserve the sidebar selection if possible. */
+  if (shortcuts_get_selected (impl, &iter))
+    {
+      gpointer col_data = NULL;
 
-          if (col_data != NULL)
-            {
-              if (shortcut_type == SHORTCUT_TYPE_FILE)
-                list_selected = g_object_ref (col_data);
-              else if (shortcut_type == SHORTCUT_TYPE_VOLUME)
-                list_selected = col_data;
-            }
-        }
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
+                          &iter,
+                          SHORTCUTS_COL_DATA, &col_data,
+                          SHORTCUTS_COL_TYPE, &shortcut_type,
+                          -1);
 
-      if (impl->shortcuts_model && impl->file_system)
+      if (col_data != NULL)
         {
-          /* Update all the sidebar entries to filter the root URI. */
-          shortcuts_model_create (impl);
-          shortcuts_add_bookmarks (impl);
-          shortcuts_add_custom_folders (impl);
+          if (shortcut_type == SHORTCUT_TYPE_FILE)
+            list_selected = g_object_ref (col_data);
+          else if (shortcut_type == SHORTCUT_TYPE_VOLUME)
+            list_selected = col_data;
         }
+    }
 
-      if (impl->current_folder != NULL)
-        {
-          if (local_only && !g_file_is_native (impl->current_folder))
-            {
-              /* If we are pointing to a non-local folder, make an effort to
-               * change back to a local folder, but it's really up to the app
-               * to not cause such a situation, so we ignore errors.
-               */
-              const gchar *home = g_get_home_dir ();
-              GFile *home_file;
+  if (impl->shortcuts_model && impl->file_system)
+    {
+      /* Update all the sidebar entries to filter the root URI. */
+      shortcuts_model_create (impl);
+      shortcuts_add_bookmarks (impl);
+      shortcuts_add_custom_folders (impl);
+    }
 
-              if (home != NULL)
-                {
-                  home_file = g_file_new_for_path (home);
-                  gtk_file_chooser_set_current_folder_file (
-                    GTK_FILE_CHOOSER (impl),
-                    home_file, NULL);
+  if (impl->current_folder != NULL)
+    {
+      if (local_only && !g_file_is_native (impl->current_folder))
+        {
+          /* If we are pointing to a non-local folder, make an effort to
+           * change back to a local folder, but it's really up to the app
+           * to not cause such a situation, so we ignore errors.
+           */
+          const gchar *home = g_get_home_dir ();
+          GFile *home_file;
 
-                  g_object_unref (home_file);
-                }
-            }
-          else if (impl->root_uri != NULL &&
-                   !_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl),
-                                                       impl->current_folder))
+          if (home != NULL)
             {
-              /*
-               * If we are pointing to a folder outside of the root URI,
-               * set the folder to the root URI.
-               */
-
-              /*
-               * Clear the list first, in case we can't load this path.
-               * We don't want to show files they shouldn't be able to access.
-               */
-              if (impl->operation_mode == OPERATION_MODE_BROWSE)
-                stop_operation (impl, impl->operation_mode);
+              home_file = g_file_new_for_path (home);
+              gtk_file_chooser_set_current_folder_file (
+                GTK_FILE_CHOOSER (impl),
+                home_file, NULL);
 
-              gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (impl),
-                                                       impl->root_uri);
-            }
-          else
-            {
-              /* Re-set the current folder so we'll display it properly. */
-              gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (impl),
-                                                        impl->current_folder,
-                                                        NULL);
+              g_object_unref (home_file);
             }
         }
+      else if (impl->root_uris != NULL &&
+               !_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl),
+                                                   impl->current_folder))
+        {
+          /*
+           * If we are pointing to a folder outside of the root URI,
+           * set the folder to the root URI.
+           */
 
-      if (shortcut_type != -1)
+          /*
+           * Clear the list first, in case we can't load this path.
+           * We don't want to show files they shouldn't be able to access.
+           */
+          if (impl->operation_mode == OPERATION_MODE_BROWSE)
+            stop_operation (impl, impl->operation_mode);
+
+          gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (impl),
+                                                   (char *)impl->root_uris->data);
+        }
+      else
         {
-          if (list_selected != NULL)
-            {
-              shortcuts_find_folder (impl, list_selected);
+          /* Re-set the current folder so we'll display it properly. */
+          gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (impl),
+                                                    impl->current_folder,
+                                                    NULL);
+        }
+    }
 
-              if (shortcut_type == SHORTCUT_TYPE_FILE)
-                g_object_unref (list_selected);
-            }
-          else
-            {
-              int pos = -1;
+  if (shortcut_type != -1)
+    {
+      if (list_selected != NULL)
+        {
+          shortcuts_find_folder (impl, list_selected);
 
-              /*
-               * Switch the operation mode to browse, a good default.
-               * We'll go back to Search or Recent if that's what was
-               * selected. The advantage is that we'll reload the results
-               * as well.
-               */
-              stop_operation (impl, impl->operation_mode);
+          if (shortcut_type == SHORTCUT_TYPE_FILE)
+            g_object_unref (list_selected);
+        }
+      else
+        {
+          int pos = -1;
 
-              impl->operation_mode = OPERATION_MODE_BROWSE;
+          /*
+           * Switch the operation mode to browse, a good default.
+           * We'll go back to Search or Recent if that's what was
+           * selected. The advantage is that we'll reload the results
+           * as well.
+           */
+          stop_operation (impl, impl->operation_mode);
+          impl->operation_mode = OPERATION_MODE_BROWSE;
 
-              if (shortcut_type == SHORTCUT_TYPE_SEARCH)
-                pos = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
-              else if (shortcut_type == SHORTCUT_TYPE_RECENT)
-                pos = shortcuts_get_index (impl, SHORTCUTS_RECENT);
+          if (shortcut_type == SHORTCUT_TYPE_SEARCH)
+            pos = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
+          else if (shortcut_type == SHORTCUT_TYPE_RECENT)
+            pos = shortcuts_get_index (impl, SHORTCUTS_RECENT);
 
-              if (pos != -1)
-                shortcuts_find_pos (impl, pos);
-            }
+          if (pos != -1)
+            shortcuts_find_pos (impl, pos);
         }
     }
 }
@@ -5713,7 +5727,10 @@ gtk_file_chooser_default_set_property (GObject      *object,
       break;
 
     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
-      set_root_uri (impl, g_value_get_boolean (value) ? "file://" : NULL);
+      set_root_uris (impl,
+                     g_value_get_boolean (value)
+                     ? g_slist_append (NULL, g_strdup ("file://"))
+                     : NULL);
       break;
 
     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
@@ -5779,8 +5796,8 @@ gtk_file_chooser_default_set_property (GObject      *object,
       }
       break;
 
-    case GTK_FILE_CHOOSER_PROP_ROOT_URI:
-      set_root_uri (impl, g_value_get_string (value));
+    case GTK_FILE_CHOOSER_PROP_ROOT_URIS:
+      set_root_uris (impl, (GSList *)g_value_get_pointer (value));
       break;
 
     default:
@@ -5808,10 +5825,26 @@ gtk_file_chooser_default_get_property (GObject    *object,
       break;
 
     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
-      g_value_set_boolean (value,
-                           impl->root_uri != NULL &&
-                           g_str_has_prefix (impl->root_uri, "file://"));
-      break;
+      {
+        gboolean local_only = (impl->root_uris != NULL);
+
+        if (local_only)
+          {
+            GSList *l;
+
+            for (l = impl->root_uris; l != NULL; l = l->next)
+              {
+                if (!g_str_has_prefix ((char *)l->data, "file://"))
+                  {
+                    local_only = FALSE;
+                    break;
+                  }
+              }
+          }
+
+        g_value_set_boolean (value, local_only);
+        break;
+      }
 
     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
       g_value_set_object (value, impl->preview_widget);
@@ -5845,8 +5878,8 @@ gtk_file_chooser_default_get_property (GObject    *object,
       g_value_set_boolean (value, impl->create_folders);
       break;
 
-    case GTK_FILE_CHOOSER_PROP_ROOT_URI:
-      g_value_set_string (value, impl->root_uri);
+    case GTK_FILE_CHOOSER_PROP_ROOT_URIS:
+      g_value_set_pointer (value, impl->root_uris);
       break;
 
     default:
@@ -5883,8 +5916,9 @@ gtk_file_chooser_default_dispose (GObject *object)
       impl->extra_widget = NULL;
     }
 
-  g_free (impl->root_uri);
-  impl->root_uri = NULL;
+  g_slist_foreach (impl->root_uris, (GFunc)g_free, NULL);
+  g_slist_free (impl->root_uris);
+  impl->root_uris = NULL;
 
   pending_select_files_free (impl);
 
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index d077e47..e216cea 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -67,7 +67,7 @@ struct _GtkFileChooserEntry
   GtkFileChooserAction action;
 
   GtkFileSystem *file_system;
-  char *root_uri;
+  const GSList *root_uris;
   GFile *base_folder;
   GFile *current_folder_file;
   gchar *file_part;
@@ -208,7 +208,7 @@ _gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry)
   GtkCellRenderer *cell;
 
   chooser_entry->local_only = TRUE;
-  chooser_entry->root_uri = NULL;
+  chooser_entry->root_uris = NULL;
 
   g_object_set (chooser_entry, "truncate-multiline", TRUE, NULL);
 
@@ -297,9 +297,6 @@ gtk_file_chooser_entry_dispose (GObject *object)
   discard_current_folder (chooser_entry);
   discard_loading_and_current_folder_file (chooser_entry);
 
-  g_free (chooser_entry->root_uri);
-  chooser_entry->root_uri = NULL;
-
   if (chooser_entry->start_autocompletion_idle_id != 0)
     {
       g_source_remove (chooser_entry->start_autocompletion_idle_id);
@@ -457,9 +454,9 @@ is_file_in_root (GtkFileChooserEntry *chooser_entry,
                  GFile               *file)
 {
   char *uri = g_file_get_uri (file);
-  gboolean result = chooser_entry->root_uri == NULL ||
-                    _gtk_file_chooser_uri_has_prefix (uri,
-                                                      chooser_entry->root_uri);
+  gboolean result =
+    chooser_entry->root_uris == NULL ||
+    _gtk_file_chooser_uri_has_prefix (uri, chooser_entry->root_uris);
   g_free (uri);
 
   return result;
@@ -1488,7 +1485,7 @@ start_loading_current_folder (GtkFileChooserEntry *chooser_entry)
 
   if ((chooser_entry->local_only
        && !g_file_is_native (chooser_entry->current_folder_file)) ||
-      (chooser_entry->root_uri != NULL
+      (chooser_entry->root_uris != NULL
        && !is_file_in_root (chooser_entry,
                             chooser_entry->current_folder_file)))
     {
@@ -2028,19 +2025,18 @@ _gtk_file_chooser_entry_get_local_only (GtkFileChooserEntry *chooser_entry)
 }
 
 void
-_gtk_file_chooser_entry_set_root_uri (GtkFileChooserEntry *chooser_entry,
-                                      const char          *root_uri)
+_gtk_file_chooser_entry_set_root_uris (GtkFileChooserEntry *chooser_entry,
+                                       const GSList        *root_uris)
 {
-  g_free (chooser_entry->root_uri);
-
-  chooser_entry->root_uri = (root_uri == NULL ? NULL : g_strdup(root_uri));
+  /* This doesn't need its own copy. */
+  chooser_entry->root_uris = root_uris;
   clear_completions (chooser_entry);
 }
 
-const char *
-_gtk_file_chooser_entry_get_root_uri (GtkFileChooserEntry *chooser_entry)
+const GSList *
+_gtk_file_chooser_entry_get_root_uris (GtkFileChooserEntry *chooser_entry)
 {
-  return chooser_entry->root_uri;
+  return chooser_entry->root_uris;
 }
 
 // vim: et sw=2 cinoptions=(0,t0,f1s,n-1s,{1s,>2s,^-1s
diff --git a/gtk/gtkfilechooserentry.h b/gtk/gtkfilechooserentry.h
index 38e4ebb..ef392f9 100644
--- a/gtk/gtkfilechooserentry.h
+++ b/gtk/gtkfilechooserentry.h
@@ -51,9 +51,9 @@ void               _gtk_file_chooser_entry_select_filename    (GtkFileChooserEnt
 void               _gtk_file_chooser_entry_set_local_only     (GtkFileChooserEntry *chooser_entry,
                                                                gboolean             local_only);
 gboolean           _gtk_file_chooser_entry_get_local_only     (GtkFileChooserEntry *chooser_entry);
-void               _gtk_file_chooser_entry_set_root_uri     (GtkFileChooserEntry *chooser_entry,
-                                                             const char          *root_uri);
-const char        *_gtk_file_chooser_entry_get_root_uri     (GtkFileChooserEntry *chooser_entry);
+void               _gtk_file_chooser_entry_set_root_uris    (GtkFileChooserEntry *chooser_entry,
+                                                             const GSList        *root_uris);
+const GSList      *_gtk_file_chooser_entry_get_root_uris    (GtkFileChooserEntry *chooser_entry);
 
 G_END_DECLS
 
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index 92caf8d..dc339c7 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -111,8 +111,8 @@ gboolean       _gtk_file_chooser_is_uri_in_root (GtkFileChooser *chooser,
 gboolean       _gtk_file_chooser_is_file_in_root (GtkFileChooser *chooser,
                                                   GFile          *file);
 
-gboolean       _gtk_file_chooser_uri_has_prefix (const char *uri,
-                                                 const char *prefix);
+gboolean       _gtk_file_chooser_uri_has_prefix (const char   *uri,
+                                                 const GSList *prefixes);
 
 /* GtkFileChooserDialog private */
 
@@ -170,7 +170,7 @@ struct _GtkFileChooserDefault
   GtkFileChooserAction action;
 
   GtkFileSystem *file_system;
-  char *root_uri;
+  GSList *root_uris;
 
   /* Save mode widgets */
   GtkWidget *save_widgets;
diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c
index 8a881bf..f18c171 100644
--- a/gtk/gtkfilechooserutils.c
+++ b/gtk/gtkfilechooserutils.c
@@ -121,8 +121,8 @@ _gtk_file_chooser_install_properties (GObjectClass *klass)
 				    GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
 				    "create-folders");
   g_object_class_override_property (klass,
-				    GTK_FILE_CHOOSER_PROP_ROOT_URI,
-				    "root-uri");
+				    GTK_FILE_CHOOSER_PROP_ROOT_URIS,
+				    "root-uris");
 }
 
 /**
diff --git a/gtk/gtkfilechooserutils.h b/gtk/gtkfilechooserutils.h
index 53d6e83..770656f 100644
--- a/gtk/gtkfilechooserutils.h
+++ b/gtk/gtkfilechooserutils.h
@@ -42,8 +42,8 @@ typedef enum {
   GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN,
   GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION,
   GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
-  GTK_FILE_CHOOSER_PROP_ROOT_URI,
-  GTK_FILE_CHOOSER_PROP_LAST                   = GTK_FILE_CHOOSER_PROP_ROOT_URI
+  GTK_FILE_CHOOSER_PROP_ROOT_URIS,
+  GTK_FILE_CHOOSER_PROP_LAST                   = GTK_FILE_CHOOSER_PROP_ROOT_URIS
 } GtkFileChooserProp;
 
 void _gtk_file_chooser_install_properties (GObjectClass *klass);
diff --git a/gtk/gtkpathbar.c b/gtk/gtkpathbar.c
index d7e1319..0e14863 100644
--- a/gtk/gtkpathbar.c
+++ b/gtk/gtkpathbar.c
@@ -261,8 +261,6 @@ gtk_path_bar_finalize (GObject *object)
   g_list_free (path_bar->button_list);
   if (path_bar->root_file)
     g_object_unref (path_bar->root_file);
-  if (path_bar->root_uri)
-    g_free (path_bar->root_uri);
   if (path_bar->home_file)
     g_object_unref (path_bar->home_file);
   if (path_bar->desktop_file)
@@ -1457,6 +1455,8 @@ static ButtonType
 find_button_type (GtkPathBar  *path_bar,
 		  GFile       *file)
 {
+  const GSList *l;
+
   if (path_bar->root_file != NULL &&
       g_file_equal (file, path_bar->root_file))
     return ROOT_BUTTON;
@@ -1467,15 +1467,16 @@ find_button_type (GtkPathBar  *path_bar,
       g_file_equal (file, path_bar->desktop_file))
     return DESKTOP_BUTTON;
 
-  if (path_bar->root_uri != NULL)
+  for (l = path_bar->root_uris; l != NULL; l = l->next)
     {
+      char *root_uri = (char *)l->data;
       char *uri = g_file_get_uri (file);
-      int root_uri_len = strlen (path_bar->root_uri);
+      int root_uri_len = strlen (root_uri);
 
-      if (!strcmp (uri, path_bar->root_uri) ||
-          (path_bar->root_uri[root_uri_len - 1] == '/' &&
+      if (!strcmp (uri, root_uri) ||
+          (root_uri[root_uri_len - 1] == '/' &&
            root_uri_len == strlen (uri) + 1 &&
-           !strncmp (uri, path_bar->root_uri, root_uri_len - 1)))
+           !strncmp (uri, root_uri, root_uri_len - 1)))
         {
           return VIRTUAL_ROOT_BUTTON;
         }
@@ -1665,8 +1666,8 @@ is_file_in_root (GtkPathBar *path_bar,
                  GFile      *file)
 {
   char *uri = g_file_get_uri (file);
-  gboolean result = path_bar->root_uri == NULL ||
-                    _gtk_file_chooser_uri_has_prefix (uri, path_bar->root_uri);
+  gboolean result = path_bar->root_uris == NULL ||
+                    _gtk_file_chooser_uri_has_prefix (uri, path_bar->root_uris);
   g_free(uri);
 
   return result;
@@ -1857,13 +1858,12 @@ _gtk_path_bar_set_file_system (GtkPathBar    *path_bar,
 }
 
 void
-_gtk_path_bar_set_root_uri    (GtkPathBar         *path_bar,
-                               const char         *root_uri)
+_gtk_path_bar_set_root_uris   (GtkPathBar         *path_bar,
+                               const GSList       *root_uris)
 {
   g_return_if_fail (GTK_IS_PATH_BAR (path_bar));
 
-  g_free (path_bar->root_uri);
-  path_bar->root_uri = (root_uri == NULL ? NULL : g_strdup (root_uri));
+  path_bar->root_uris = root_uris;
 
   /*
    * We don't know if we can even query this URI, so clear the buttons as
diff --git a/gtk/gtkpathbar.h b/gtk/gtkpathbar.h
index 5aad390..b27ceec 100644
--- a/gtk/gtkpathbar.h
+++ b/gtk/gtkpathbar.h
@@ -45,7 +45,7 @@ struct _GtkPathBar
   GFile *home_file;
   GFile *desktop_file;
 
-  char *root_uri;
+  const GSList *root_uris;
 
   GCancellable *get_info_cancellable;
 
@@ -90,8 +90,8 @@ gboolean _gtk_path_bar_set_file        (GtkPathBar         *path_bar,
 					GFile              *file,
 					gboolean            keep_trail,
 					GError            **error);
-void     _gtk_path_bar_set_root_uri    (GtkPathBar         *path_bar,
-										const char         *root_uri);
+void     _gtk_path_bar_set_root_uris   (GtkPathBar         *path_bar,
+										const GSList       *root_uris);
 void     _gtk_path_bar_up              (GtkPathBar *path_bar);
 void     _gtk_path_bar_down            (GtkPathBar *path_bar);
 



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