- Disconnect signal connections when appropriate. - Listen to

Wed Apr  9 12:28:04 2003  Owen Taylor  <otaylor@redhat.com>

        * gtkfilesystemmodel.c:
        - Disconnect signal connections when appropriate.
        - Listen to ::roots-changed on the file system
        - When the last reference count on a child is
          removed, queue an idle to unload the parent.

        * gtkfilesystemgnomevfs.c
        - When URI's outside of file:/// are acessed,
          add toplevel URI's to the list of roots.
        - Improve display name computations

        * gtkfilechooserentry.c: Don't complete on empty
        file parts; free stored folder when base directory
        changes.

        * gtkfilechooser.c: Fill in some docs.
This commit is contained in:
Owen Taylor 2003-04-09 16:52:13 +00:00 committed by Owen Taylor
parent 1926dbc1f6
commit af6bc44d86
4 changed files with 330 additions and 52 deletions

View File

@ -152,27 +152,64 @@ gtk_file_chooser_get_action (GtkFileChooser *chooser)
return action;
}
/**
* gtk_file_chooser_set_folder_mode:
* @chooser: a #GtkFileChooser
* @folder_mode: %TRUE if the file chooser is used to select folders
* rather than files.
*
* Sets whether the file chooser is used to select folders
* rather than files. If in folder mode, only folders are displayed
* to the use, and not the individual files inside the folders
* and the user selects a single folder rather than one or
* more files.
**/
void
gtk_file_chooser_set_directory_mode (GtkFileChooser *chooser,
gboolean directory_mode)
gtk_file_chooser_set_folder_mode (GtkFileChooser *chooser,
gboolean folder_mode)
{
g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
g_object_set (chooser, "directory_mode", directory_mode, NULL);
g_object_set (chooser, "folder_mode", folder_mode, NULL);
}
/**
* gtk_file_chooser_get_folder_mode:
* @chooser: a #GtkFileChooser
*
* Gets whether the file chooser is used to select folders
* rather than files. See gtk_file_chooser_set_folder_mode()
*
* Return value: %TRUE if the file chooser is used to select
folders rather than files.
**/
gboolean
gtk_file_chooser_get_directory_mode (GtkFileChooser *chooser)
gtk_file_chooser_get_folder_mode (GtkFileChooser *chooser)
{
gboolean directory_mode;
gboolean folder_mode;
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
g_object_get (chooser, "directory_mode", &directory_mode, NULL);
g_object_get (chooser, "folder_mode", &folder_mode, NULL);
return directory_mode;
return folder_mode;
}
/**
* gtk_file_chooser_set_local_only:
* @chooser: a #GtkFileChooser
* @local_only: %TRUE if only local files can be selected
*
* Sets whether only local files can be selected in the
* file selector. If @local_only is %TRUE (the default),
* then the selected file are files are guaranteed to be
* accessible through the operating systems native file
* file system and therefore the application only
* needs to worry about the filename functions in
* #GtkFileChooser, like gtk_file_chooser_get_filename(),
* rather than the URI functions like
* gtk_file_chooser_get_uri(),
**/
void
gtk_file_chooser_set_local_only (GtkFileChooser *chooser,
gboolean local_only)
@ -182,6 +219,15 @@ gtk_file_chooser_set_local_only (GtkFileChooser *chooser,
g_object_set (chooser, "local_only", local_only, NULL);
}
/**
* gtk_file_chooser_get_local_only:
* @chooser: a #GtkFileChoosre
*
* Gets whether only local files can be selected in the
* file selector. See gtk_file_chooser_set_local_only()
*
* Return value: %TRUE if only local files can be selected.
**/
gboolean
gtk_file_chooser_get_local_only (GtkFileChooser *chooser)
{
@ -194,6 +240,16 @@ gtk_file_chooser_get_local_only (GtkFileChooser *chooser)
return local_only;
}
/**
* gtk_file_chooser_set_select_multiple:
* @chooser: a #GtkFileChooser
* @select_multiple: %TRUE if multiple files can be selected.
*
* Sets whether multiple files can be selected in the file
* selector. If the file selector if in folder mode (see
* gtk_file_selector_set_folder_mode()) then only one folder
* can be selected, without regard to this setting.
**/
void
gtk_file_chooser_set_select_multiple (GtkFileChooser *chooser,
gboolean select_multiple)
@ -203,6 +259,15 @@ gtk_file_chooser_set_select_multiple (GtkFileChooser *chooser,
g_object_set (chooser, "select_multiple", select_multiple, NULL);
}
/**
* gtk_file_chooser_get_select_multiple:
* @chooser: a #GtkFileChooser
*
* Gets whether multiple files can be selected in the file
* selector. See gtk_file_chooser_set_select_multiple().
*
* Return value: %TRUE if multiple files can be selected.
**/
gboolean
gtk_file_chooser_get_select_multiple (GtkFileChooser *chooser)
{
@ -215,6 +280,18 @@ gtk_file_chooser_get_select_multiple (GtkFileChooser *chooser)
return select_multiple;
}
/**
* gtk_file_chooser_get_filename:
* @chooser: a #GtkFileChooser
*
* Gets the filename for the currently selected file in
* the file selector. If multiple files are selected,
* one of the filenames will be returned at random.
*
* Return value: The currently selected filename, or %NULL
* if no file is selected, or the selected file can't
* be represented with a local filename.
**/
gchar *
gtk_file_chooser_get_filename (GtkFileChooser *chooser)
{

View File

@ -169,6 +169,9 @@ completion_idle_callback (GtkFileChooserEntry *chooser_entry)
chooser_entry->completion_idle = NULL;
if (strcmp (chooser_entry->file_part, "") == 0)
return FALSE;
if (!chooser_entry->current_folder &&
chooser_entry->file_system &&
chooser_entry->current_folder_path)
@ -425,6 +428,7 @@ _gtk_file_chooser_entry_set_base_folder (GtkFileChooserEntry *chooser_entry,
gtk_file_path_free (chooser_entry->base_folder);
chooser_entry->base_folder = gtk_file_path_copy (path);
gtk_file_chooser_entry_changed (GTK_EDITABLE (chooser_entry));
}
/**

View File

@ -46,7 +46,8 @@ typedef enum {
GTK_FILE_INFO_MIME_TYPE = 1 << 3,
GTK_FILE_INFO_MODIFICATION_TIME = 1 << 4,
GTK_FILE_INFO_SIZE = 1 << 5,
GTK_FILE_INFO_ICON = 1 << 6
GTK_FILE_INFO_ICON = 1 << 6,
GTK_FILE_INFO_ALL = (1 << 7) - 1
} GtkFileInfoType;
/* GError enumeration for GtkFileSystem

View File

@ -44,6 +44,9 @@ struct _GtkFileSystemModel
FileModelNode *roots;
GtkFileFolder *root_folder;
GSList *idle_clears;
GSource *idle_clear_source;
gushort max_depth;
guint show_hidden : 1;
@ -65,6 +68,7 @@ struct _FileModelNode
GtkFileSystemModel *model;
guint ref_count;
guint n_referenced_children;
gushort depth;
@ -72,6 +76,7 @@ struct _FileModelNode
guint is_dummy : 1;
guint is_visible : 1;
guint loaded : 1;
guint idle_clear : 1;
};
static void gtk_file_system_model_class_init (GtkFileSystemModelClass *class);
@ -120,6 +125,10 @@ static void file_model_node_ref (FileModelNode *node);
static void file_model_node_unref (GtkFileSystemModel *model,
FileModelNode *node);
static void file_model_node_idle_clear (FileModelNode *node);
static void file_model_node_idle_clear_cancel (FileModelNode *node);
static void file_model_node_child_unref (FileModelNode *parent);
static const GtkFileInfo *file_model_node_get_info (GtkFileSystemModel *model,
FileModelNode *node);
static gboolean file_model_node_is_visible (GtkFileSystemModel *model,
@ -129,6 +138,9 @@ static void file_model_node_clear (GtkFileSystemModel *mode
static FileModelNode * file_model_node_get_children (GtkFileSystemModel *model,
FileModelNode *node);
static void roots_changed_callback (GtkFileSystem *file_system,
GtkFileSystemModel *model);
static void deleted_callback (GtkFileFolder *folder,
FileModelNode *node);
static void files_added_callback (GtkFileFolder *folder,
@ -576,18 +588,22 @@ _gtk_file_system_model_new (GtkFileSystem *file_system,
{
roots = child_paths;
g_signal_connect (model->root_folder, "deleted",
G_CALLBACK (root_deleted_callback), model);
g_signal_connect (model->root_folder, "files_added",
G_CALLBACK (root_files_added_callback), model);
g_signal_connect (model->root_folder, "files_changed",
G_CALLBACK (root_files_changed_callback), model);
g_signal_connect (model->root_folder, "files_removed",
G_CALLBACK (root_files_removed_callback), model);
g_signal_connect_object (model->root_folder, "deleted",
G_CALLBACK (root_deleted_callback), model, 0);
g_signal_connect_object (model->root_folder, "files_added",
G_CALLBACK (root_files_added_callback), model, 0);
g_signal_connect_object (model->root_folder, "files_changed",
G_CALLBACK (root_files_changed_callback), model, 0);
g_signal_connect_object (model->root_folder, "files_removed",
G_CALLBACK (root_files_removed_callback), model, 0);
}
}
else
{
roots = gtk_file_system_list_roots (file_system);
g_signal_connect_object (file_system, "roots_changed",
G_CALLBACK (roots_changed_callback), model, 0);
}
roots = gtk_file_paths_sort (roots);
@ -830,7 +846,8 @@ find_child_node (GtkFileSystemModel *model,
static FileModelNode *
find_and_ref_path (GtkFileSystemModel *model,
const GtkFilePath *path)
const GtkFilePath *path,
GSList **cleanups)
{
GtkFilePath *parent_path;
FileModelNode *parent_node;
@ -842,7 +859,7 @@ find_and_ref_path (GtkFileSystemModel *model,
if (parent_path)
{
parent_node = find_and_ref_path (model, parent_path);
parent_node = find_and_ref_path (model, parent_path, cleanups);
gtk_file_path_free (parent_path);
if (!parent_node)
@ -862,6 +879,9 @@ find_and_ref_path (GtkFileSystemModel *model,
path,
model->types,
NULL); /* NULL-GError */
if (folder)
{
*cleanups = g_slist_prepend (*cleanups, folder);
child_node = find_child_node (model, parent_node, path);
if (child_node)
@ -869,11 +889,12 @@ find_and_ref_path (GtkFileSystemModel *model,
file_model_node_ref (child_node);
return child_node;
}
}
if (parent_node)
unref_node_and_parents (model, parent_node);
return FALSE;
return NULL;
}
/**
@ -908,7 +929,8 @@ _gtk_file_system_model_path_do (GtkFileSystemModel *model,
GtkFileSystemModelPathFunc func,
gpointer user_data)
{
FileModelNode *node = find_and_ref_path (model, path);
GSList *cleanups = NULL;
FileModelNode *node = find_and_ref_path (model, path, &cleanups);
if (node)
{
@ -922,11 +944,12 @@ _gtk_file_system_model_path_do (GtkFileSystemModel *model,
gtk_tree_path_free (path);
unref_node_and_parents (model, node);
return TRUE;
}
else
return FALSE;
g_slist_foreach (cleanups, (GFunc)g_object_unref, NULL);
g_slist_free (cleanups);
return node != NULL;
}
static FileModelNode *
@ -944,13 +967,7 @@ file_model_node_new (GtkFileSystemModel *model,
static void
file_model_node_free (FileModelNode *node)
{
if (node->children)
{
FileModelNode *children;
for (children = node->children; children; children = children->next)
file_model_node_free (children);
}
file_model_node_clear (node->model, node);
if (node->path)
gtk_file_path_free (node->path);
@ -958,9 +975,6 @@ file_model_node_free (FileModelNode *node)
if (node->info)
gtk_file_info_free (node->info);
if (node->folder)
g_object_unref (node->folder);
g_free (node);
}
@ -1021,11 +1035,7 @@ file_model_node_clear (GtkFileSystemModel *model,
{
FileModelNode *children;
if (node->folder)
{
g_object_unref (node->folder);
node->folder = NULL;
}
file_model_node_idle_clear_cancel (node);
children = node->children;
node->children = NULL;
@ -1035,19 +1045,90 @@ file_model_node_clear (GtkFileSystemModel *model,
{
FileModelNode *next = children->next;
file_model_node_clear (model, children);
file_model_node_free (children);
children = next;
}
node->ref_count = 0;
if (node->folder)
{
/* Unreffing node->folder may cause roots_changed,
* so we need to be careful about ordering.
*/
GtkFileFolder *folder = node->folder;
node->folder = NULL;
g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (deleted_callback), node);
g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_added_callback), node);
g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_changed_callback), node);
g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_removed_callback), node);
g_object_unref (folder);
}
}
static void
file_model_node_ref (FileModelNode *node)
{
node->ref_count++;
if (node->ref_count == 1 && node->parent)
node->parent->n_referenced_children++;
}
static gboolean
idle_clear_callback (GtkFileSystemModel *model)
{
while (model->idle_clears)
{
FileModelNode *node = model->idle_clears->data;
model->idle_clears = g_slist_delete_link (model->idle_clears, model->idle_clears);
node->idle_clear = FALSE;
file_model_node_clear (node->model, node);
}
return FALSE;
}
static void
file_model_node_idle_clear (FileModelNode *node)
{
if (!node->idle_clear)
{
GtkFileSystemModel *model = node->model;
node->idle_clear = TRUE;
if (!model->idle_clears)
{
model->idle_clear_source = g_idle_source_new ();
g_source_set_priority (model->idle_clear_source, G_PRIORITY_HIGH);
g_source_set_closure (model->idle_clear_source,
g_cclosure_new_object (G_CALLBACK (idle_clear_callback),
G_OBJECT (model)));
g_source_attach (model->idle_clear_source, NULL);
}
model->idle_clears = g_slist_prepend (model->idle_clears, node);
node->idle_clear = TRUE;
}
}
static void
file_model_node_idle_clear_cancel (FileModelNode *node)
{
if (node->idle_clear)
{
GtkFileSystemModel *model = node->model;
model->idle_clears = g_slist_remove (model->idle_clears, node);
if (!model->idle_clears)
{
g_source_destroy (model->idle_clear_source);
model->idle_clear_source = NULL;
}
node->idle_clear = FALSE;
}
}
static void
@ -1056,7 +1137,19 @@ file_model_node_unref (GtkFileSystemModel *model,
{
node->ref_count--;
if (node->ref_count == 0)
{
file_model_node_clear (model, node);
if (node->parent)
file_model_node_child_unref (node->parent);
}
}
static void
file_model_node_child_unref (FileModelNode *parent)
{
parent->n_referenced_children--;
if (parent->n_referenced_children == 0)
file_model_node_idle_clear (parent);
}
static FileModelNode *
@ -1072,6 +1165,8 @@ file_model_node_get_children (GtkFileSystemModel *model,
gboolean has_children = FALSE;
gboolean is_folder = node->depth < model->max_depth && gtk_file_info_get_is_folder (info);
file_model_node_idle_clear_cancel (node);
if (is_folder)
node->folder = gtk_file_system_get_folder (model->file_system,
node->path,
@ -1231,7 +1326,6 @@ do_files_added (GtkFileSystemModel *model,
parent_node->children = parent_node->children->next;
parent_node->has_dummy = FALSE;
file_model_node_free (dummy);
dummy_path = gtk_tree_path_copy (path);
gtk_tree_path_up (dummy_path);
@ -1239,6 +1333,10 @@ do_files_added (GtkFileSystemModel *model,
gtk_tree_model_row_deleted (tree_model, dummy_path);
gtk_tree_path_free (dummy_path);
if (dummy->ref_count)
file_model_node_child_unref (parent_node);
file_model_node_free (dummy);
}
gtk_tree_path_next (path);
@ -1409,6 +1507,9 @@ do_files_removed (GtkFileSystemModel *model,
else
model->roots = next;
if (parent_node && children->ref_count)
file_model_node_child_unref (parent_node);
if (children->is_visible)
gtk_tree_model_row_deleted (tree_model, path);
@ -1426,6 +1527,103 @@ do_files_removed (GtkFileSystemModel *model,
g_slist_free (sorted_paths);
}
static void
roots_changed_callback (GtkFileSystem *file_system,
GtkFileSystemModel *model)
{
GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
GSList *new_roots;
GSList *tmp_list;
FileModelNode *children;
FileModelNode *prev = NULL;
GtkTreePath *path;
new_roots = gtk_file_system_list_roots (file_system);
new_roots = gtk_file_paths_sort (new_roots);
children = model->roots;
tmp_list = new_roots;
path = gtk_tree_path_new ();
gtk_tree_path_down (path);
while (children || tmp_list)
{
FileModelNode *next = NULL;
int cmp;
if (tmp_list && children)
cmp = gtk_file_path_compare (children->path, tmp_list->data);
else if (children)
cmp = -1;
else
cmp = 1;
if (cmp < 0)
{
next = children->next;
if (prev)
prev->next = children->next;
else
model->roots = children->next;
if (children->is_visible)
gtk_tree_model_row_deleted (tree_model, path);
file_model_node_free (children);
}
else if (cmp == 0)
{
/* Already there
*/
next = children->next;
prev = children;
if (children->is_visible)
gtk_tree_path_next (path);
}
else
{
GtkTreeIter iter;
FileModelNode *node = file_model_node_new (model, tmp_list->data);
node->is_visible = file_model_node_is_visible (model, node);
node->next = children;
node->depth = 0;
if (prev)
prev->next = node;
else
model->roots = node;
if (node->is_visible)
{
iter.user_data = node;
gtk_tree_model_row_inserted (tree_model, path, &iter);
if (gtk_file_system_model_iter_has_child (tree_model, &iter))
gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
gtk_tree_path_next (path);
}
prev = node;
}
if (cmp <= 0)
{
children = next;
}
if (cmp >= 0)
{
gtk_file_path_free (tmp_list->data);
tmp_list = tmp_list->next;
}
}
g_slist_free (new_roots);
gtk_tree_path_free (path);
}
static void
deleted_callback (GtkFileFolder *folder,
FileModelNode *node)
@ -1485,5 +1683,3 @@ root_files_removed_callback (GtkFileFolder *folder,
{
do_files_removed (model, NULL, paths);
}