Compare commits
33 Commits
matthiasc/
...
multiroot-
Author | SHA1 | Date | |
---|---|---|---|
|
56ed4f574b | ||
|
1358953103 | ||
|
44ef4e8bb9 | ||
|
2ac688681c | ||
|
52472eaf9a | ||
|
a174fba992 | ||
|
b2e19e0056 | ||
|
00592c3d4a | ||
|
da2e50ba63 | ||
|
68f25e54d8 | ||
|
aabe7d0086 | ||
|
c3524bab42 | ||
|
8e164cc477 | ||
|
bad39dda20 | ||
|
57f4b48391 | ||
|
1abc6ef78c | ||
|
2738786c6f | ||
|
9b1bd76a9b | ||
|
d8e078b7a3 | ||
|
b997b7f7f1 | ||
|
5cbaf53d9b | ||
|
90670ccda5 | ||
|
3cbcb110e0 | ||
|
d73dfd118e | ||
|
a07db264a4 | ||
|
93a91f91d8 | ||
|
b11da2d25b | ||
|
9289e75934 | ||
|
7056f9a39b | ||
|
2d8588a2e3 | ||
|
5673ef9463 | ||
|
40669f960a | ||
|
c3abc8a89d |
@@ -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 */
|
||||
|
@@ -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);
|
||||
|
@@ -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
@@ -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 */
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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);
|
||||
|
123
gtk/gtkpathbar.c
123
gtk/gtkpathbar.c
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user