Compare commits

...

33 Commits

Author SHA1 Message Date
Federico Mena Quintero
56ed4f574b Don't pass volumes as if they were a GFile
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-14 12:38:08 -05:00
Federico Mena Quintero
1358953103 Don't bring up the completion window after typing a folder name that is outside the roots
We were not clearing the completion store in the case where we couldn't
even start loading the 'new' current folder.  This includes the case
where the proposed folder is not inside the roots.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-14 12:38:03 -05:00
Matthias Clasen
44ef4e8bb9 Make it build 2010-10-07 07:04:24 -04:00
Federico Mena Quintero
2ac688681c Mark multiroot API additions as being available since 3.0
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:44:53 -05:00
Federico Mena Quintero
52472eaf9a testfilechooser - Add test buttons for rooting the file chooser
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:39:18 -05:00
Federico Mena Quintero
a174fba992 Add a missing break in a switch()
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:20 -05:00
Federico Mena Quintero
b2e19e0056 Don't use _gtk_file_chooser_is_file_in_roots() when we already know the roots strv
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:20 -05:00
Federico Mena Quintero
00592c3d4a Make _gtk_file_chooser_is_uri_in_roots() private
It is no longer used by the derived classes

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:20 -05:00
Federico Mena Quintero
da2e50ba63 Use the fast-path _gtk_file_chooser_uri_is_in_roots_list() instead of the slow _gtk_file_chooser_is_file_in_roots()
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:19 -05:00
Federico Mena Quintero
68f25e54d8 Use a boxed G_TYPE_STRV for the 'root-uris' property, not a pointer to a list
That should be friendlier to language bindings, and it makes our memory management correct.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:19 -05:00
Federico Mena Quintero
aabe7d0086 Oops, fix typo 2010-10-06 13:26:19 -05:00
Federico Mena Quintero
c3524bab42 Don't use gtktreeprivate in the file chooser
We were using TREE_VIEW_HEADER_HEIGHT() to factor out the Y position
during drag-and-drop; now we use the public function
gtk_tree_view_get_dest_row_at_pos().

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:19 -05:00
Federico Mena Quintero
8e164cc477 Don't leak a file_path; don't unref a null file_info
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:19 -05:00
Federico Mena Quintero
bad39dda20 const GSList doesn't make sense
Except to annoy us non-C++ programmers :)

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:19 -05:00
Federico Mena Quintero
57f4b48391 Remove _gtk_file_chooser_entry_get_root_uris()
There is no need for that getter.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:19 -05:00
Federico Mena Quintero
1abc6ef78c Don't filter the completion results for the roots
We don't even initiate the load-a-folder-to-do-completion procedure if the
folder is not in the roots.  By the time we get to populate_completion_store(),
we know that the current folder *is* allowed to be viewed.  See
start_loading_current_folder().

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:19 -05:00
Federico Mena Quintero
2738786c6f Remove superfluous NULL check
Now that _gtk_file_chooser_uri_has_prefix() deals with NULL prefix lists,
we can remove all such checks.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:18 -05:00
Federico Mena Quintero
9b1bd76a9b Don't use C++ style comments
We like it here in the 1990s, thank you very much.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:18 -05:00
Federico Mena Quintero
d8e078b7a3 s/in_root/in_roots everywhere, as we support multiple roots
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:18 -05:00
Federico Mena Quintero
b997b7f7f1 Allow NULL prefixes in _gtk_file_chooser_uri_has_prefix()
This allows us to just call that function with whatever root_uris we
have, instead of manually comparing the root_uris for NULL every time.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:18 -05:00
Federico Mena Quintero
5cbaf53d9b Do uri_has_prefix() without allocations
Signed-off-by: Federico Mena Quintero <federico@novell.com>
2010-10-06 13:26:18 -05:00
Christian Hammond
90670ccda5 Show the roots in the sidebar.
Roots will be shown only if:

1) They're not the user's Desktop or Home directories (which would already
   be listed otherwise).
2) It's not the URI of an existing volume.
3) The parent volume isn't already a root.
4) The root actually does exist (preventing non-browseable roots, like "ftp:")
2010-10-06 13:26:18 -05:00
Christian Hammond
3cbcb110e0 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.
2010-10-06 13:26:17 -05:00
Christian Hammond
d73dfd118e Validate the results in gtk_file_chooser_get_files. 2010-10-06 13:26:17 -05:00
Christian Hammond
a07db264a4 Display an icon for the virtual root button. 2010-10-06 13:26:17 -05:00
Christian Hammond
93a91f91d8 Prevent access to old locations when using a non-existant root URI. 2010-10-06 13:26:17 -05:00
Christian Hammond
b11da2d25b Make GtkFileChooserButton work with root URI.
GtkFileChooserButton now understands root URIs and only displays entries
in the list that would be shown in the file chooser.
2010-10-06 13:26:17 -05:00
Christian Hammond
9289e75934 Filter the path bar and auto-completion results.
This changes the path bar to only show those folders accessible within
the root URI. If a particular folder has been set as the root URI, it will
appear as the top-most button in the path bar, much like the File System
does.

This also hides the scroll buttons in the Path Bar when no buttons are set
(in the case of an invalid root URI) and hides the left scroll button if the
first shown folder is the very first folder in the path bar.
2010-10-06 13:24:54 -05:00
Christian Hammond
7056f9a39b Keep the list of custom shortcuts in a list and rebuild it on root_uri change.
The old custom shortcut code assumed that the entry would be added to the
sidebar and never removed programatically within that instance of the file
chooser. That, clearly, doesn't work when dynamically changing the root URIs.

We now maintain a list of added custom shortcuts and add/remove these based
on the root URI whenever the root changes.
2010-10-06 13:24:12 -05:00
Christian Hammond
2d8588a2e3 Make the local_only property wrap root_uri.
Root URI and Local Only properties are very similar, so this change combines
them into one concept. A root URI of "file://" is now the same as the old
Local Only. The old Local Only property remains, and we may even want to keep
it around indefinitely, but it just simply wraps a root URI of "file://".

The set_local_only and set_root_uri functions have been merged, and improved
logic for setting the current folder on root URI/local-only property changes
has been added.
2010-10-06 13:24:12 -05:00
Christian Hammond
5673ef9463 Filter and restore the Recently Used list on root URI switching.
The Recently Used list only shows matches that are within the root URI.
The entry in the sidebar is available at all times, as recently used items
can be on remote URIs.
2010-10-06 13:24:12 -05:00
Christian Hammond
40669f960a Update the sidebar entries based on the root URI.
The sidebar generation code has been made more flexible so that it can be
run more than once, instead of assuming it will only ever be run once.

Various sidebar entries are now dependent on the type of root. Search, for
example, only shows up with a file:-based root.

When deciding whether a volume can be added, the root URI is checked to make
sure the volume resides within that root.
2010-10-06 13:24:12 -05:00
Christian Hammond
c3abc8a89d Add the concept of rooting the filechooser to a specific URI.
The only UI elements (shortcuts, bookmarks, special folders, etc.) that will
show up are ones within the root URI.

At this point, we have the UI filtering out the special sidebar entries
that are not within the root URI, and we have some API calls set up for
specifying the root URI.

Future changes will limit browsing within the root URI, limit search
results, and other such fixes.
2010-10-06 13:24:11 -05:00
12 changed files with 1438 additions and 224 deletions

View File

@@ -825,6 +825,25 @@ gtk_file_chooser_default_init (GtkFileChooserInterface *iface)
"will offer the user to create new folders."),
TRUE,
GTK_PARAM_READWRITE));
/**
* GtkFileChooser:root-uris:
*
* The absolute root URIs that can be accessed in the file chooser.
* Any shortcuts (special or user-defined) or volumes not within
* these URIs will be filtered out for this dialog.
*
* The default is NULL, which provides the default level of access
* for the file chooser.
*
* Since: 3.0
*/
g_object_interface_install_property (iface,
g_param_spec_boxed ("root-uris",
P_("Root URIs"),
P_("The URIs, if any, to use as the root for all access in the file chooser."),
G_TYPE_STRV,
GTK_PARAM_READWRITE));
}
/**
@@ -902,6 +921,9 @@ gtk_file_chooser_get_action (GtkFileChooser *chooser)
* rather than the URI functions like
* gtk_file_chooser_get_uri(),
*
* This implies a single root URI of "file://". See
* gtk_file_chooser_set_root_uris().
*
* Since: 2.4
**/
void
@@ -915,10 +937,13 @@ gtk_file_chooser_set_local_only (GtkFileChooser *chooser,
/**
* gtk_file_chooser_get_local_only:
* @chooser: a #GtkFileChoosre
* @chooser: a #GtkFileChooser
*
* Gets whether only local files can be selected in the
* 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_uris().
*
* Return value: %TRUE if only local files can be selected.
*
@@ -936,6 +961,76 @@ gtk_file_chooser_get_local_only (GtkFileChooser *chooser)
return local_only;
}
/**
* gtk_file_chooser_set_root_uris:
* @chooser: a #GtkFileChooser
* @root_uris: A %NULL-terminated array of strings with the root URIs, or %NULL to allow access to everything.
*
* 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.
*
* This is useful when needing to restrict the file chooser to a particular
* directory and its subdirectories, to a particular storage device, or to a
* remote server.
*
* 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: 3.0
**/
void
gtk_file_chooser_set_root_uris (GtkFileChooser *chooser,
const gchar **root_uris)
{
g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
g_object_set (chooser, "root-uris", root_uris, NULL);
}
/**
* gtk_file_chooser_get_root_uris:
* @chooser: a #GtkFileChooser
*
* 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.
*
* This is useful when needing to restrict the file chooser to a particular
* directory and its subdirectories, to a particular storage device, or to a
* remote server.
*
* 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: A %NULL-terminated array of strings with the URIs of the roots,
* or simply %NULL if there are no roots set for the @chooser. You should free
* this array with g_strfreev().
*
* Since: 3.0
**/
gchar **
gtk_file_chooser_get_root_uris (GtkFileChooser *chooser)
{
gchar **root_uris;
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
g_object_get (chooser, "root-uris", &root_uris, NULL);
return root_uris;
}
/**
* gtk_file_chooser_set_select_multiple:
* @chooser: a #GtkFileChooser
@@ -1705,9 +1800,21 @@ gtk_file_chooser_unselect_file (GtkFileChooser *chooser,
GSList *
gtk_file_chooser_get_files (GtkFileChooser *chooser)
{
GSList *files, *l;
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_files (chooser);
files = GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_files (chooser);
for (l = files; l != NULL; l = l->next)
{
GFile *file = (GFile *)l->data;
g_return_val_if_fail (_gtk_file_chooser_is_file_in_roots (chooser, file),
NULL);
}
return files;
}
/**
@@ -2567,3 +2674,347 @@ gtk_file_chooser_get_do_overwrite_confirmation (GtkFileChooser *chooser)
return do_overwrite_confirmation;
}
#if defined (G_OS_WIN32) && !defined (_WIN64)
/* DLL ABI stability backward compatibility versions */
#undef gtk_file_chooser_get_filename
gchar *
gtk_file_chooser_get_filename (GtkFileChooser *chooser)
{
gchar *utf8_filename = gtk_file_chooser_get_filename_utf8 (chooser);
gchar *retval = g_locale_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
g_free (utf8_filename);
return retval;
}
#undef gtk_file_chooser_set_filename
gboolean
gtk_file_chooser_set_filename (GtkFileChooser *chooser,
const gchar *filename)
{
gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
gboolean retval = gtk_file_chooser_set_filename_utf8 (chooser, utf8_filename);
g_free (utf8_filename);
return retval;
}
#undef gtk_file_chooser_select_filename
gboolean
gtk_file_chooser_select_filename (GtkFileChooser *chooser,
const gchar *filename)
{
gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
gboolean retval = gtk_file_chooser_select_filename_utf8 (chooser, utf8_filename);
g_free (utf8_filename);
return retval;
}
#undef gtk_file_chooser_unselect_filename
void
gtk_file_chooser_unselect_filename (GtkFileChooser *chooser,
const char *filename)
{
gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
gtk_file_chooser_unselect_filename_utf8 (chooser, utf8_filename);
g_free (utf8_filename);
}
#undef gtk_file_chooser_get_filenames
GSList *
gtk_file_chooser_get_filenames (GtkFileChooser *chooser)
{
GSList *list = gtk_file_chooser_get_filenames_utf8 (chooser);
GSList *rover = list;
while (rover)
{
gchar *tem = (gchar *) rover->data;
rover->data = g_locale_from_utf8 ((gchar *) rover->data, -1, NULL, NULL, NULL);
g_free (tem);
rover = rover->next;
}
return list;
}
#undef gtk_file_chooser_set_current_folder
gboolean
gtk_file_chooser_set_current_folder (GtkFileChooser *chooser,
const gchar *filename)
{
gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
gboolean retval = gtk_file_chooser_set_current_folder_utf8 (chooser, utf8_filename);
g_free (utf8_filename);
return retval;
}
#undef gtk_file_chooser_get_current_folder
gchar *
gtk_file_chooser_get_current_folder (GtkFileChooser *chooser)
{
gchar *utf8_folder = gtk_file_chooser_get_current_folder_utf8 (chooser);
gchar *retval = g_locale_from_utf8 (utf8_folder, -1, NULL, NULL, NULL);
g_free (utf8_folder);
return retval;
}
#undef gtk_file_chooser_get_preview_filename
char *
gtk_file_chooser_get_preview_filename (GtkFileChooser *chooser)
{
char *utf8_filename = gtk_file_chooser_get_preview_filename_utf8 (chooser);
char *retval = g_locale_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
g_free (utf8_filename);
return retval;
}
#undef gtk_file_chooser_add_shortcut_folder
gboolean
gtk_file_chooser_add_shortcut_folder (GtkFileChooser *chooser,
const char *folder,
GError **error)
{
char *utf8_folder = g_locale_to_utf8 (folder, -1, NULL, NULL, NULL);
gboolean retval =
gtk_file_chooser_add_shortcut_folder_utf8 (chooser, utf8_folder, error);
g_free (utf8_folder);
return retval;
}
#undef gtk_file_chooser_remove_shortcut_folder
gboolean
gtk_file_chooser_remove_shortcut_folder (GtkFileChooser *chooser,
const char *folder,
GError **error)
{
char *utf8_folder = g_locale_to_utf8 (folder, -1, NULL, NULL, NULL);
gboolean retval =
gtk_file_chooser_remove_shortcut_folder_utf8 (chooser, utf8_folder, error);
g_free (utf8_folder);
return retval;
}
#undef gtk_file_chooser_list_shortcut_folders
GSList *
gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser)
{
GSList *list = gtk_file_chooser_list_shortcut_folders_utf8 (chooser);
GSList *rover = list;
while (rover)
{
gchar *tem = (gchar *) rover->data;
rover->data = g_locale_from_utf8 ((gchar *) rover->data, -1, NULL, NULL, NULL);
g_free (tem);
rover = rover->next;
}
return list;
}
#endif
static gboolean
uri_has_prefix (const char *uri, const char *prefix)
{
int prefix_len;
const char *remainder;
prefix_len = strlen (prefix);
if (prefix_len > 0 && prefix[prefix_len - 1] == '/')
prefix_len--;
if (strncmp (uri, prefix, prefix_len) != 0)
return FALSE;
remainder = uri + prefix_len;
return (*remainder == '/') || (*remainder == '\0');
}
gboolean
_gtk_file_chooser_uri_is_in_roots_list (const char *uri, GSList *roots)
{
GSList *l;
g_return_val_if_fail (uri != NULL, FALSE);
if (roots == NULL)
return TRUE; /* No roots means all URIs are good */
for (l = roots; l; l = l->next)
{
const char *prefix = l->data;
if (uri_has_prefix (uri, prefix))
return TRUE;
}
return FALSE;
}
static gboolean
uri_is_in_roots_strv (const char *uri, gchar **roots)
{
gchar **r;
if (!roots)
return TRUE; /* No roots means all URIs are good */
for (r = roots; *r; r++)
if (uri_has_prefix (uri, *r))
return TRUE;
return FALSE;
}
static gboolean
is_uri_in_roots (GtkFileChooser *chooser,
const char *uri)
{
gchar **root_uris;
gboolean is_in_roots;
root_uris = gtk_file_chooser_get_root_uris (chooser);
is_in_roots = uri_is_in_roots_strv (uri, root_uris);
g_strfreev (root_uris);
return is_in_roots;
}
gboolean
_gtk_file_chooser_is_file_in_roots (GtkFileChooser *chooser,
GFile *file)
{
char *uri;
gboolean result;
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
g_return_val_if_fail (file != NULL, FALSE);
uri = g_file_get_uri (file);
result = is_uri_in_roots (chooser, uri);
g_free (uri);
return result;
}
GSList *
_gtk_file_chooser_get_visible_roots (GtkFileChooser *chooser)
{
GSList *results = NULL;
GtkFileSystem *file_system = _gtk_file_chooser_get_file_system (chooser);
gchar **root_uris;
gchar **r;
root_uris = gtk_file_chooser_get_root_uris (chooser);
for (r = root_uris; r && *r; r++)
{
GFile *file = g_file_new_for_uri (*r);
gboolean skip = FALSE;
GtkFileSystemVolume *volume;
GFileInfo *file_info;
char *file_path;
gboolean is_home_or_desktop;
if (file == NULL)
continue;
file_path = g_file_get_path (file);
/*
* See if this is the Desktop directory or Home directory, which will
* already be listed.
*/
is_home_or_desktop = (!g_strcmp0 (file_path,
g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) ||
!g_strcmp0 (file_path, g_get_home_dir()));
g_free (file_path);
if (is_home_or_desktop)
{
g_object_unref (file);
continue;
}
/* Make sure the file exists in some form. */
file_info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
G_FILE_QUERY_INFO_NONE,
NULL,
NULL);
if (file_info == NULL)
{
g_object_unref (file);
continue;
}
volume = _gtk_file_system_get_volume_for_file (file_system, file);
if (volume != NULL)
{
GFile *fs_root = _gtk_file_system_volume_get_root (volume);
if (fs_root != NULL)
{
char *fs_root_uri = g_file_get_uri (fs_root);
if (uri_is_in_roots_strv (fs_root_uri, root_uris))
{
/* This is going to be listed already. Ignore it for now. */
skip = TRUE;
}
g_free (fs_root_uri);
g_object_unref (fs_root);
}
}
if (skip)
{
g_object_unref (file);
continue;
}
results = g_slist_append (results, file);
}
g_strfreev (root_uris);
return results;
}
/* vim: et sw=2 cinoptions=(0,t0,f1s,n-1s,{1s,>2s,^-1s */

View File

@@ -123,6 +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_uris (GtkFileChooser *chooser,
const gchar **root_uris);
gchar **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);

View File

@@ -103,6 +103,7 @@ enum
typedef enum
{
ROW_TYPE_SPECIAL,
ROW_TYPE_ROOT,
ROW_TYPE_VOLUME,
ROW_TYPE_SHORTCUT,
ROW_TYPE_BOOKMARK_SEPARATOR,
@@ -137,6 +138,8 @@ struct _GtkFileChooserButtonPrivate
GtkFileSystem *fs;
GFile *old_file;
GSList *shortcuts;
gulong combo_box_changed_id;
gulong dialog_file_activated_id;
gulong dialog_folder_changed_id;
@@ -151,6 +154,7 @@ struct _GtkFileChooserButtonPrivate
gint icon_size;
guint8 n_special;
guint8 n_roots;
guint8 n_volumes;
guint8 n_shortcuts;
guint8 n_bookmarks;
@@ -433,6 +437,8 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
priv->icon_size = FALLBACK_ICON_SIZE;
priv->focus_on_click = TRUE;
priv->shortcuts = NULL;
priv->n_shortcuts = 0;
gtk_widget_push_composite_child ();
@@ -525,6 +531,98 @@ gtk_file_chooser_button_file_chooser_iface_init (GtkFileChooserIface *iface)
iface->remove_shortcut_folder = gtk_file_chooser_button_remove_shortcut_folder;
}
static void
reload_roots (GtkFileChooserButton *button)
{
GtkFileChooser *filechooser;
GtkFileChooserButtonPrivate *priv = button->priv;
GSList *l, *roots;
gint start_pos;
start_pos = model_get_type_position (button, ROW_TYPE_ROOT);
model_remove_rows (button, start_pos, priv->n_roots);
priv->n_roots = 0;
filechooser = GTK_FILE_CHOOSER (button->priv->dialog);
roots = _gtk_file_chooser_get_visible_roots (GTK_FILE_CHOOSER (filechooser));
for (l = roots; l != NULL; l = l->next)
{
GFile *file = (GFile *)l->data;
gint pos = start_pos + priv->n_roots;
GtkTreeIter iter;
gtk_list_store_insert (GTK_LIST_STORE (priv->model), &iter, pos);
gtk_list_store_set (GTK_LIST_STORE (priv->model), &iter,
ICON_COLUMN, NULL,
DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME),
TYPE_COLUMN, ROW_TYPE_ROOT,
DATA_COLUMN, file,
IS_FOLDER_COLUMN, FALSE,
-1);
set_info_for_file_at_iter (button, file, &iter);
priv->n_roots++;
}
g_slist_free (roots);
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model));
update_label_and_image (button);
update_combo_box (button);
}
static void
add_shortcut_to_list (GtkFileChooserButton *button,
GFile *shortcut)
{
GtkFileChooserButtonPrivate *priv = button->priv;
gint pos = model_get_type_position (button, ROW_TYPE_SHORTCUT) +
priv->n_shortcuts;
GtkTreeIter iter;
gtk_list_store_insert (GTK_LIST_STORE (priv->model), &iter, pos);
gtk_list_store_set (GTK_LIST_STORE (priv->model), &iter,
ICON_COLUMN, NULL,
DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME),
TYPE_COLUMN, ROW_TYPE_SHORTCUT,
DATA_COLUMN, g_object_ref (shortcut),
IS_FOLDER_COLUMN, FALSE,
-1);
set_info_for_file_at_iter (button, shortcut, &iter);
priv->n_shortcuts++;
}
static void
reload_shortcuts (GtkFileChooserButton *button)
{
GtkFileChooser *filechooser;
GtkFileChooserButtonPrivate *priv = button->priv;
GSList *l;
model_remove_rows (button,
model_get_type_position (button, ROW_TYPE_SHORTCUT),
priv->n_shortcuts);
priv->n_shortcuts = 0;
filechooser = GTK_FILE_CHOOSER (button->priv->dialog);
for (l = priv->shortcuts; l != NULL; l = l->next)
{
GFile *shortcut = (GFile *)l->data;
if (_gtk_file_chooser_is_file_in_roots (filechooser, shortcut))
{
add_shortcut_to_list (button, shortcut);
}
}
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model));
update_label_and_image (button);
update_combo_box (button);
}
static gboolean
gtk_file_chooser_button_add_shortcut_folder (GtkFileChooser *chooser,
GFile *file,
@@ -541,24 +639,16 @@ gtk_file_chooser_button_add_shortcut_folder (GtkFileChooser *chooser,
{
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (chooser);
GtkFileChooserButtonPrivate *priv = button->priv;
GtkTreeIter iter;
gint pos;
pos = model_get_type_position (button, ROW_TYPE_SHORTCUT);
pos += priv->n_shortcuts;
g_object_ref (G_OBJECT (file));
priv->shortcuts = g_slist_append (priv->shortcuts, file);
gtk_list_store_insert (GTK_LIST_STORE (priv->model), &iter, pos);
gtk_list_store_set (GTK_LIST_STORE (priv->model), &iter,
ICON_COLUMN, NULL,
DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME),
TYPE_COLUMN, ROW_TYPE_SHORTCUT,
DATA_COLUMN, g_object_ref (file),
IS_FOLDER_COLUMN, FALSE,
-1);
set_info_for_file_at_iter (button, file, &iter);
priv->n_shortcuts++;
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model));
if (_gtk_file_chooser_is_file_in_roots (GTK_FILE_CHOOSER (priv->dialog),
file))
{
add_shortcut_to_list (button, file);
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model));
}
}
return retval;
@@ -584,6 +674,7 @@ gtk_file_chooser_button_remove_shortcut_folder (GtkFileChooser *chooser,
GtkTreeIter iter;
gint pos;
gchar type;
GSList *l;
pos = model_get_type_position (button, ROW_TYPE_SHORTCUT);
gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, pos);
@@ -610,6 +701,18 @@ gtk_file_chooser_button_remove_shortcut_folder (GtkFileChooser *chooser,
}
while (type == ROW_TYPE_SHORTCUT &&
gtk_tree_model_iter_next (priv->model, &iter));
for (l = priv->shortcuts; l != NULL; l = l->next)
{
GFile *shortcut = (GFile *)l->data;
if (g_file_equal (shortcut, file))
{
g_object_unref (G_OBJECT (shortcut));
priv->shortcuts = g_slist_remove_link (priv->shortcuts, l);
break;
}
}
}
return retval;
@@ -743,6 +846,7 @@ gtk_file_chooser_button_set_property (GObject *object,
{
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (object);
GtkFileChooserButtonPrivate *priv = button->priv;
GtkFileChooser *filechooser = GTK_FILE_CHOOSER (priv->dialog);
switch (param_id)
{
@@ -809,9 +913,28 @@ gtk_file_chooser_button_set_property (GObject *object,
break;
case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
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_roots (filechooser, gtk_file_chooser_get_current_folder_file (filechooser)))
{
char **root_uris = gtk_file_chooser_get_root_uris (filechooser);
GFile *file = g_file_new_for_uri ((root_uris == NULL || *root_uris == NULL)
? "file:///"
: root_uris[0]);
g_strfreev (root_uris);
gtk_file_chooser_set_current_folder_file (filechooser, file, NULL);
model_update_current_folder (button, file);
g_object_unref (G_OBJECT (file));
}
fs_volumes_changed_cb (priv->fs, button);
fs_bookmarks_changed_cb (priv->fs, button);
reload_roots (button);
reload_shortcuts (button);
break;
case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
@@ -856,6 +979,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_URIS:
g_object_get_property (G_OBJECT (priv->dialog), pspec->name, value);
break;
@@ -874,6 +998,13 @@ gtk_file_chooser_button_finalize (GObject *object)
if (priv->old_file)
g_object_unref (priv->old_file);
if (priv->shortcuts)
{
g_slist_foreach (priv->shortcuts, (GFunc)g_object_unref, NULL);
g_slist_free (priv->shortcuts);
priv->shortcuts = NULL;
}
G_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->finalize (object);
}
@@ -1502,6 +1633,11 @@ model_get_type_position (GtkFileChooserButton *button,
retval += button->priv->n_special;
if (row_type == ROW_TYPE_ROOT)
return retval;
retval += button->priv->n_roots;
if (row_type == ROW_TYPE_VOLUME)
return retval;
@@ -1735,6 +1871,7 @@ model_add_volumes (GtkFileChooserButton *button,
gint pos;
gboolean local_only;
GtkFileSystem *file_system;
GtkFileChooser *filechooser;
GSList *l;
if (!volumes)
@@ -1742,7 +1879,8 @@ model_add_volumes (GtkFileChooserButton *button,
store = GTK_LIST_STORE (button->priv->model);
pos = model_get_type_position (button, ROW_TYPE_VOLUME);
local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (button->priv->dialog));
filechooser = GTK_FILE_CHOOSER (button->priv->dialog);
local_only = gtk_file_chooser_get_local_only (filechooser);
file_system = button->priv->fs;
for (l = volumes; l; l = l->next)
@@ -1751,28 +1889,30 @@ model_add_volumes (GtkFileChooserButton *button,
GtkTreeIter iter;
GdkPixbuf *pixbuf;
gchar *display_name;
GFile *base_file;
gboolean skip = FALSE;
volume = l->data;
if (local_only)
{
if (_gtk_file_system_volume_is_mounted (volume))
{
GFile *base_file;
base_file = _gtk_file_system_volume_get_root (volume);
base_file = _gtk_file_system_volume_get_root (volume);
if (base_file != NULL)
{
if (!g_file_is_native (base_file))
{
g_object_unref (base_file);
continue;
}
else
g_object_unref (base_file);
}
}
}
if (local_only &&
base_file != NULL &&
_gtk_file_system_volume_is_mounted (volume) &&
!g_file_is_native (base_file))
skip = TRUE;
else if (base_file == NULL ||
!_gtk_file_chooser_is_file_in_roots (filechooser, base_file))
skip = TRUE;
if (base_file != NULL)
g_object_unref (base_file);
if (skip)
{
_gtk_file_system_volume_unref (volume);
continue;
}
pixbuf = _gtk_file_system_volume_render_icon (volume,
GTK_WIDGET (button),
@@ -1809,13 +1949,15 @@ model_add_bookmarks (GtkFileChooserButton *button,
gint pos;
gboolean local_only;
GSList *l;
GtkFileChooser *filechooser;
if (!bookmarks)
return;
store = GTK_LIST_STORE (button->priv->model);
pos = model_get_type_position (button, ROW_TYPE_BOOKMARK);
local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (button->priv->dialog));
filechooser = GTK_FILE_CHOOSER (button->priv->dialog);
local_only = gtk_file_chooser_get_local_only (filechooser);
for (l = bookmarks; l; l = l->next)
{
@@ -1823,6 +1965,9 @@ model_add_bookmarks (GtkFileChooserButton *button,
file = l->data;
if (!_gtk_file_chooser_is_file_in_roots (filechooser, file))
continue;
if (g_file_is_native (file))
{
gtk_list_store_insert (store, &iter, pos);
@@ -2037,17 +2182,24 @@ model_remove_rows (GtkFileChooserButton *button,
/* Filter Model */
static inline gboolean
test_if_file_is_visible (GtkFileSystem *fs,
test_if_file_is_visible (GtkFileChooserButton *button,
GFile *file,
gboolean local_only,
gboolean is_folder)
{
gboolean result;
if (!file)
return FALSE;
if (local_only && !g_file_is_native (file))
return FALSE;
result = _gtk_file_chooser_is_file_in_roots (GTK_FILE_CHOOSER (button), file);
if (!result)
return FALSE;
if (!is_folder)
return FALSE;
@@ -2083,7 +2235,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, is_folder);
retval = test_if_file_is_visible (button, data, local_only, is_folder);
break;
case ROW_TYPE_VOLUME:
{
@@ -2501,6 +2653,7 @@ combo_box_changed_cb (GtkComboBox *combo_box,
switch (type)
{
case ROW_TYPE_SPECIAL:
case ROW_TYPE_ROOT:
case ROW_TYPE_SHORTCUT:
case ROW_TYPE_BOOKMARK:
case ROW_TYPE_CURRENT_FOLDER:

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,8 @@
#include "gtkcelllayout.h"
#include "gtkcellrenderertext.h"
#include "gtkentry.h"
#include "gtkfilechooserentry.h"
#include "gtkfilechooserprivate.h"
#include "gtklabel.h"
#include "gtkmain.h"
#include "gtksizerequest.h"
@@ -70,6 +72,7 @@ struct _GtkFileChooserEntry
GtkFileChooserAction action;
GtkFileSystem *file_system;
GSList *root_uris;
GFile *base_folder;
GFile *current_folder_file;
gchar *file_part;
@@ -210,6 +213,7 @@ _gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry)
GtkCellRenderer *cell;
chooser_entry->local_only = TRUE;
chooser_entry->root_uris = NULL;
g_object_set (chooser_entry, "truncate-multiline", TRUE, NULL);
@@ -450,6 +454,17 @@ beep (GtkFileChooserEntry *chooser_entry)
gtk_widget_error_bell (GTK_WIDGET (chooser_entry));
}
static gboolean
is_file_in_roots (GtkFileChooserEntry *chooser_entry,
GFile *file)
{
char *uri = g_file_get_uri (file);
gboolean result = _gtk_file_chooser_uri_is_in_roots_list (uri, chooser_entry->root_uris);
g_free (uri);
return result;
}
/* This function will append a directory separator to paths to
* display_name iff the path associated with it is a directory.
* maybe_append_separator_to_file will g_free the display_name and
@@ -1469,8 +1484,9 @@ start_loading_current_folder (GtkFileChooserEntry *chooser_entry)
g_assert (chooser_entry->current_folder == NULL);
g_assert (chooser_entry->load_folder_cancellable == NULL);
if (chooser_entry->local_only
&& !g_file_is_native (chooser_entry->current_folder_file))
if ((chooser_entry->local_only
&& !g_file_is_native (chooser_entry->current_folder_file))
|| !is_file_in_roots (chooser_entry, chooser_entry->current_folder_file))
{
g_object_unref (chooser_entry->current_folder_file);
chooser_entry->current_folder_file = NULL;
@@ -1618,6 +1634,12 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry,
if (folder_file)
g_object_unref (folder_file);
if (result != REFRESH_OK)
{
clear_completions (chooser_entry);
discard_completion_store (chooser_entry);
}
g_assert (/* we are OK and we have a current folder file and (loading process or folder handle)... */
((result == REFRESH_OK)
&& (chooser_entry->current_folder_file != NULL)
@@ -2006,3 +2028,14 @@ _gtk_file_chooser_entry_get_local_only (GtkFileChooserEntry *chooser_entry)
{
return chooser_entry->local_only;
}
void
_gtk_file_chooser_entry_set_root_uris (GtkFileChooserEntry *chooser_entry,
GSList *root_uris)
{
/* This doesn't need its own copy. */
chooser_entry->root_uris = root_uris;
clear_completions (chooser_entry);
}
/* vim: et sw=2 cinoptions=(0,t0,f1s,n-1s,{1s,>2s,^-1s */

View File

@@ -51,6 +51,8 @@ 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_uris (GtkFileChooserEntry *chooser_entry,
GSList *root_uris);
G_END_DECLS

View File

@@ -104,6 +104,14 @@ gboolean _gtk_file_chooser_remove_shortcut_folder (GtkFileChooser *cho
GError **error);
GSList * _gtk_file_chooser_list_shortcut_folder_files (GtkFileChooser *chooser);
GSList * _gtk_file_chooser_list_shortcut_folder_files (GtkFileChooser *chooser);
gboolean _gtk_file_chooser_is_file_in_roots (GtkFileChooser *chooser,
GFile *file);
GSList * _gtk_file_chooser_get_visible_roots (GtkFileChooser *chooser);
gboolean _gtk_file_chooser_uri_is_in_roots_list (const char *uri, GSList *roots);
/* GtkFileChooserDialog private */
struct _GtkFileChooserDialogPrivate
@@ -159,6 +167,7 @@ struct _GtkFileChooserDefault
GtkFileChooserAction action;
GtkFileSystem *file_system;
GSList *root_uris;
/* Save mode widgets */
GtkWidget *save_widgets;
@@ -229,6 +238,7 @@ struct _GtkFileChooserDefault
/* Handles */
GSList *loading_shortcuts;
GSList *shortcuts;
GSList *reload_icon_cancellables;
GCancellable *file_list_drag_data_received_cancellable;
GCancellable *update_current_folder_cancellable;
@@ -249,6 +259,7 @@ struct _GtkFileChooserDefault
GtkFileFilter *current_filter;
GSList *filters;
int num_roots;
int num_volumes;
int num_shortcuts;
int num_bookmarks;
@@ -285,7 +296,6 @@ struct _GtkFileChooserDefault
/* Flags */
guint local_only : 1;
guint preview_widget_active : 1;
guint use_preview_label : 1;
guint select_multiple : 1;

View File

@@ -117,6 +117,9 @@ _gtk_file_chooser_install_properties (GObjectClass *klass)
g_object_class_override_property (klass,
GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
"create-folders");
g_object_class_override_property (klass,
GTK_FILE_CHOOSER_PROP_ROOT_URIS,
"root-uris");
}
/**

View File

@@ -41,7 +41,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_LAST = GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS
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);

View File

@@ -28,6 +28,7 @@
#include "gtkalignment.h"
#include "gtkarrow.h"
#include "gtkdnd.h"
#include "gtkfilechooserprivate.h"
#include "gtkimage.h"
#include "gtkintl.h"
#include "gtkicontheme.h"
@@ -46,6 +47,7 @@ enum {
typedef enum {
NORMAL_BUTTON,
ROOT_BUTTON,
VIRTUAL_ROOT_BUTTON,
HOME_BUTTON,
DESKTOP_BUTTON
} ButtonType;
@@ -464,7 +466,7 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
GtkPathBar *path_bar = GTK_PATH_BAR (widget);
GtkTextDirection direction;
GtkAllocation child_allocation;
GList *list, *first_button;
GList *list, *first_button, *root_button;
gint width;
gint allocation_width;
guint border_width;
@@ -481,7 +483,11 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
/* No path is set; we don't have to allocate anything. */
if (path_bar->button_list == NULL)
return;
{
gtk_widget_set_child_visible (path_bar->up_slider_button, FALSE);
gtk_widget_set_child_visible (path_bar->down_slider_button, FALSE);
return;
}
direction = gtk_widget_get_direction (widget);
border_width = gtk_container_get_border_width (GTK_CONTAINER (path_bar));
@@ -501,15 +507,17 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
width += child_requisition.width + path_bar->spacing;
if (list == path_bar->fake_root)
break;
break;
}
root_button = g_list_last (path_bar->button_list);
if (width <= allocation_width)
{
if (path_bar->fake_root)
first_button = path_bar->fake_root;
else
first_button = g_list_last (path_bar->button_list);
first_button = root_button;
}
else
{
@@ -578,7 +586,8 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
if (direction == GTK_TEXT_DIR_RTL)
{
child_allocation.x = allocation->x + allocation->width - border_width;
if (need_sliders || path_bar->fake_root)
if (need_sliders ||
(path_bar->fake_root && path_bar->fake_root != root_button))
{
child_allocation.x -= (path_bar->spacing + path_bar->slider_width);
up_slider_offset = allocation->width - border_width - path_bar->slider_width;
@@ -587,7 +596,8 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
else
{
child_allocation.x = allocation->x + border_width;
if (need_sliders || path_bar->fake_root)
if (need_sliders ||
(path_bar->fake_root && path_bar->fake_root != root_button))
{
up_slider_offset = border_width;
child_allocation.x += (path_bar->spacing + path_bar->slider_width);
@@ -652,7 +662,8 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
gtk_widget_set_child_visible (BUTTON_DATA (list->data)->button, FALSE);
}
if (need_sliders || path_bar->fake_root)
if (need_sliders ||
(path_bar->fake_root && path_bar->fake_root != root_button))
{
child_allocation.width = path_bar->slider_width;
child_allocation.x = up_slider_offset + allocation->x;
@@ -1241,6 +1252,13 @@ set_button_image_get_info_cb (GCancellable *cancellable,
switch (data->button_data->type)
{
case VIRTUAL_ROOT_BUTTON:
if (data->path_bar->root_icon != NULL)
g_object_unref (data->path_bar->root_icon);
else
data->path_bar->root_icon = pixbuf;
break;
case HOME_BUTTON:
if (data->path_bar->home_icon)
g_object_unref (pixbuf);
@@ -1294,6 +1312,38 @@ set_button_image (GtkPathBar *path_bar,
gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->root_icon);
break;
case VIRTUAL_ROOT_BUTTON:
/*
* This is the first button, meaning that it's the root of the
* file chooser. Give it a special icon.
*
* We're reusing the root_icon variable, which in this particular
* case will actually represent this root. This is reset every time
* the icon theme or root URI changes.
*/
if (path_bar->root_icon != NULL)
{
gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image),
path_bar->root_icon);
}
else
{
data = g_new0 (struct SetButtonImageData, 1);
data->path_bar = path_bar;
data->button_data = button_data;
if (button_data->cancellable)
g_cancellable_cancel (button_data->cancellable);
button_data->cancellable =
_gtk_file_system_get_info (path_bar->file_system,
button_data->file,
"standard::icon",
set_button_image_get_info_cb,
data);
}
break;
case HOME_BUTTON:
if (path_bar->home_icon != NULL)
{
@@ -1337,6 +1387,7 @@ set_button_image (GtkPathBar *path_bar,
set_button_image_get_info_cb,
data);
break;
default:
break;
}
@@ -1432,6 +1483,8 @@ static ButtonType
find_button_type (GtkPathBar *path_bar,
GFile *file)
{
GSList *l;
if (path_bar->root_file != NULL &&
g_file_equal (file, path_bar->root_file))
return ROOT_BUTTON;
@@ -1442,6 +1495,21 @@ find_button_type (GtkPathBar *path_bar,
g_file_equal (file, path_bar->desktop_file))
return DESKTOP_BUTTON;
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 (root_uri);
if (!strcmp (uri, root_uri) ||
(root_uri[root_uri_len - 1] == '/' &&
root_uri_len == strlen (uri) + 1 &&
!strncmp (uri, root_uri, root_uri_len - 1)))
{
return VIRTUAL_ROOT_BUTTON;
}
}
return NORMAL_BUTTON;
}
@@ -1498,6 +1566,7 @@ make_directory_button (GtkPathBar *path_bar,
break;
case HOME_BUTTON:
case DESKTOP_BUTTON:
case VIRTUAL_ROOT_BUTTON:
button_data->image = gtk_image_new ();
button_data->label = gtk_label_new (NULL);
label_alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
@@ -1620,6 +1689,17 @@ struct SetFileInfo
gboolean first_directory;
};
static gboolean
is_file_in_roots (GtkPathBar *path_bar,
GFile *file)
{
char *uri = g_file_get_uri (file);
gboolean result = _gtk_file_chooser_uri_is_in_roots_list (uri, path_bar->root_uris);
g_free(uri);
return result;
}
static void
gtk_path_bar_set_file_finish (struct SetFileInfo *info,
gboolean result)
@@ -1691,6 +1771,12 @@ gtk_path_bar_get_info_callback (GCancellable *cancellable,
display_name = g_file_info_get_display_name (info);
is_hidden = g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info);
if (!is_file_in_roots (file_info->path_bar, file_info->file))
{
gtk_path_bar_set_file_finish (file_info, TRUE);
return;
}
gtk_widget_push_composite_child ();
button_data = make_directory_button (file_info->path_bar, display_name,
file_info->file,
@@ -1798,6 +1884,29 @@ _gtk_path_bar_set_file_system (GtkPathBar *path_bar,
path_bar->root_file = g_file_new_for_path ("/");
}
void
_gtk_path_bar_set_root_uris (GtkPathBar *path_bar,
GSList *root_uris)
{
g_return_if_fail (GTK_IS_PATH_BAR (path_bar));
path_bar->root_uris = root_uris;
/*
* We don't know if we can even query this URI, so clear the buttons as
* a precaution. Otherwise the user could jump to folders outside the root
* URI and break things.
*/
gtk_path_bar_clear_buttons (path_bar);
/* Also clear the root icon, as we'll be using this for the root URI button. */
if (path_bar->root_icon)
{
g_object_unref (path_bar->root_icon);
path_bar->root_icon = NULL;
}
}
/**
* _gtk_path_bar_up:
* @path_bar: a #GtkPathBar

View File

@@ -45,6 +45,8 @@ struct _GtkPathBar
GFile *home_file;
GFile *desktop_file;
GSList *root_uris;
GCancellable *get_info_cancellable;
GdkPixbuf *root_icon;
@@ -88,6 +90,8 @@ gboolean _gtk_path_bar_set_file (GtkPathBar *path_bar,
GFile *file,
gboolean keep_trail,
GError **error);
void _gtk_path_bar_set_root_uris (GtkPathBar *path_bar,
GSList *root_uris);
void _gtk_path_bar_up (GtkPathBar *path_bar);
void _gtk_path_bar_down (GtkPathBar *path_bar);

View File

@@ -406,6 +406,26 @@ unmap_and_remap_cb (GtkButton *button,
gtk_widget_show (GTK_WIDGET (chooser));
}
static void
root_to_home_and_tmp_cb (GtkButton *button,
GtkFileChooser *chooser)
{
char *root_uris[] = { "",
"file:///tmp",
NULL };
root_uris[0] = g_strconcat ("file://", g_get_home_dir (), NULL);
gtk_file_chooser_set_root_uris (chooser, (const char **) root_uris);
g_free (root_uris[0]);
}
static void
unroot_cb (GtkButton *button,
GtkFileChooser *chooser)
{
gtk_file_chooser_set_root_uris (chooser, NULL);
}
static void
kill_dependent (GtkWindow *win, GtkWidget *dep)
{
@@ -474,6 +494,16 @@ confirm_overwrite_cb (GtkFileChooser *chooser,
return conf;
}
static void
add_test_button (GtkWidget *container, const char *label_text, GCallback callback, gpointer data)
{
GtkWidget *button;
button = gtk_button_new_with_label (label_text);
gtk_container_add (GTK_CONTAINER (container), button);
g_signal_connect (button, "clicked", callback, data);
}
int
main (int argc, char **argv)
{
@@ -660,30 +690,13 @@ main (int argc, char **argv)
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_file_chooser_unselect_all), dialog);
button = gtk_button_new_with_label ("set_current_folder (\"/nonexistent\")");
gtk_container_add (GTK_CONTAINER (vbbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (set_folder_nonexistent_cb), dialog);
button = gtk_button_new_with_label ("set_current_folder (\"/usr/nonexistent\")");
gtk_container_add (GTK_CONTAINER (vbbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (set_folder_existing_nonexistent_cb), dialog);
button = gtk_button_new_with_label ("set_filename (\"/nonexistent\")");
gtk_container_add (GTK_CONTAINER (vbbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (set_filename_nonexistent_cb), dialog);
button = gtk_button_new_with_label ("set_filename (\"/usr/nonexistent\")");
gtk_container_add (GTK_CONTAINER (vbbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (set_filename_existing_nonexistent_cb), dialog);
button = gtk_button_new_with_label ("Unmap and remap");
gtk_container_add (GTK_CONTAINER (vbbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (unmap_and_remap_cb), dialog);
add_test_button (vbbox, "set_current_folder (\"/nonexistent\")", G_CALLBACK (set_folder_nonexistent_cb), dialog);
add_test_button (vbbox, "set_current_folder (\"/usr/nonexistent\")", G_CALLBACK (set_folder_existing_nonexistent_cb), dialog);
add_test_button (vbbox, "set_filename (\"/nonexistent\")", G_CALLBACK (set_filename_nonexistent_cb), dialog);
add_test_button (vbbox, "set_filename (\"/usr/nonexistent\")", G_CALLBACK (set_filename_existing_nonexistent_cb), dialog);
add_test_button (vbbox, "Unmap and remap", G_CALLBACK (unmap_and_remap_cb), dialog);
add_test_button (vbbox, "Root to $HOME and /tmp", G_CALLBACK (root_to_home_and_tmp_cb), dialog);
add_test_button (vbbox, "Unroot", G_CALLBACK (unroot_cb), dialog);
gtk_widget_show_all (control_window);