Commit a9515134 authored by Stefano Teso's avatar Stefano Teso Committed by Cosimo Cecchi

list-view: create folders in subdirectories when possible

Don't always choose the tree root as parent when creating a new folder,
but look at the current selection's directory.

https://bugzilla.gnome.org/show_bug.cgi?id=330644
parent 97b1ff2f
......@@ -2025,6 +2025,163 @@ nautilus_list_view_file_changed (NautilusView *view, NautilusFile *file, Nautilu
}
}
typedef struct {
GtkTreePath *path;
gboolean is_common;
gboolean is_root;
} HasCommonParentData;
static void
tree_selection_has_common_parent_foreach_func (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer user_data)
{
HasCommonParentData *data;
GtkTreePath *parent_path;
gboolean has_parent;
data = (HasCommonParentData *) user_data;
parent_path = gtk_tree_path_copy (path);
gtk_tree_path_up (parent_path);
has_parent = (gtk_tree_path_get_depth (parent_path) > 0) ? TRUE : FALSE;
if (!has_parent) {
data->is_root = TRUE;
}
if (data->is_common && !data->is_root) {
if (data->path == NULL) {
data->path = gtk_tree_path_copy (parent_path);
} else if (gtk_tree_path_compare (data->path, parent_path) != 0) {
data->is_common = FALSE;
}
}
gtk_tree_path_free (parent_path);
}
static void
tree_selection_has_common_parent (GtkTreeSelection *selection,
gboolean *is_common,
gboolean *is_root)
{
HasCommonParentData data;
g_assert (is_common != NULL);
g_assert (is_root != NULL);
data.path = NULL;
data.is_common = *is_common = TRUE;
data.is_root = *is_root = FALSE;
gtk_tree_selection_selected_foreach (selection,
tree_selection_has_common_parent_foreach_func,
&data);
*is_common = data.is_common;
*is_root = data.is_root;
if (data.path != NULL) {
gtk_tree_path_free (data.path);
}
}
static char *
nautilus_list_view_get_backing_uri (NautilusView *view)
{
NautilusListView *list_view;
NautilusListModel *list_model;
NautilusFile *file;
GtkTreeView *tree_view;
GtkTreeSelection *selection;
GtkTreePath *path;
GList *paths;
guint length;
char *uri;
g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NULL);
list_view = NAUTILUS_LIST_VIEW (view);
list_model = list_view->details->model;
tree_view = list_view->details->tree_view;
g_assert (list_model);
/* We currently handle three common cases here:
* (a) if the selection contains non-filesystem items (i.e., the
* "(Empty)" label), we return the uri of the parent.
* (b) if the selection consists of exactly one _expanded_ directory, we
* return its URI.
* (c) if the selection consists of either exactly one item which is not
* an expanded directory) or multiple items in the same directory,
* we return the URI of the common parent.
*/
uri = NULL;
selection = gtk_tree_view_get_selection (tree_view);
length = gtk_tree_selection_count_selected_rows (selection);
if (length == 1) {
paths = gtk_tree_selection_get_selected_rows (selection, NULL);
path = (GtkTreePath *) paths->data;
file = nautilus_list_model_file_for_path (list_model, path);
if (file == NULL) {
/* The selected item is a label, not a file */
gtk_tree_path_up (path);
file = nautilus_list_model_file_for_path (list_model, path);
}
if (file != NULL) {
if (nautilus_file_is_directory (file) &&
gtk_tree_view_row_expanded (tree_view, path)) {
uri = nautilus_file_get_uri (file);
}
nautilus_file_unref (file);
}
gtk_tree_path_free (path);
g_list_free (paths);
}
if (uri == NULL && length > 0) {
gboolean is_common, is_root;
/* Check that all the selected items belong to the same
* directory and that directory is not the root directory (which
* is handled by NautilusView::get_backing_directory.) */
tree_selection_has_common_parent (selection, &is_common, &is_root);
if (is_common && !is_root) {
paths = gtk_tree_selection_get_selected_rows (selection, NULL);
path = (GtkTreePath *) paths->data;
file = nautilus_list_model_file_for_path (list_model, path);
g_assert (file != NULL);
uri = nautilus_file_get_parent_uri (file);
nautilus_file_unref (file);
g_list_foreach (paths, (GFunc) gtk_tree_path_free, NULL);
g_list_free (paths);
}
}
if (uri != NULL) {
return uri;
}
return EEL_CALL_PARENT_WITH_RETURN_VALUE (NAUTILUS_VIEW_CLASS,
get_backing_uri, (view));
}
static void
nautilus_list_view_get_selection_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
......@@ -3100,6 +3257,7 @@ nautilus_list_view_class_init (NautilusListViewClass *class)
nautilus_view_class->click_policy_changed = nautilus_list_view_click_policy_changed;
nautilus_view_class->clear = nautilus_list_view_clear;
nautilus_view_class->file_changed = nautilus_list_view_file_changed;
nautilus_view_class->get_backing_uri = nautilus_list_view_get_backing_uri;
nautilus_view_class->get_selection = nautilus_list_view_get_selection;
nautilus_view_class->get_selection_for_file_transfer = nautilus_list_view_get_selection_for_file_transfer;
nautilus_view_class->get_item_count = nautilus_list_view_get_item_count;
......
......@@ -360,6 +360,51 @@ nautilus_view_unmerge_menus (NautilusView *view)
unmerge_menus, (view));
}
static char *
real_get_backing_uri (NautilusView *view)
{
NautilusDirectory *directory;
char *uri;
g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
if (view->details->model == NULL) {
return NULL;
}
directory = view->details->model;
if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) {
directory = nautilus_desktop_directory_get_real_directory (NAUTILUS_DESKTOP_DIRECTORY (directory));
} else {
nautilus_directory_ref (directory);
}
uri = nautilus_directory_get_uri (directory);
nautilus_directory_unref (directory);
return uri;
}
/**
*
* nautilus_view_get_backing_uri:
*
* Returns the URI for the target location of new directory, new file, new
* link, new launcher, and paste operations.
*/
char *
nautilus_view_get_backing_uri (NautilusView *view)
{
g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
return EEL_CALL_METHOD_WITH_RETURN_VALUE
(NAUTILUS_VIEW_CLASS, view,
get_backing_uri, (view));
}
/**
* nautilus_view_select_all:
*
......@@ -1287,34 +1332,6 @@ action_other_application_callback (GtkAction *action,
open_with_other_program (NAUTILUS_VIEW (callback_data));
}
/* Get the real directory where files will be stored and created */
char *
nautilus_view_get_backing_uri (NautilusView *view)
{
NautilusDirectory *directory;
char *uri;
g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
if (view->details->model == NULL) {
return NULL;
}
directory = view->details->model;
if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) {
directory = nautilus_desktop_directory_get_real_directory (NAUTILUS_DESKTOP_DIRECTORY (directory));
} else {
nautilus_directory_ref (directory);
}
uri = nautilus_directory_get_uri (directory);
nautilus_directory_unref (directory);
return uri;
}
static void
trash_or_delete_selected_files (NautilusView *view)
{
......@@ -9760,6 +9777,7 @@ nautilus_view_class_init (NautilusViewClass *klass)
klass->load_error = real_load_error;
klass->can_rename_file = can_rename_file;
klass->start_renaming_file = start_renaming_file;
klass->get_backing_uri = real_get_backing_uri;
klass->using_manual_layout = real_using_manual_layout;
klass->merge_menus = real_merge_menus;
klass->unmerge_menus = real_unmerge_menus;
......
......@@ -142,6 +142,14 @@ struct NautilusViewClass {
*/
void (* reset_to_defaults) (NautilusView *view);
/* get_backing uri is a function pointer for subclasses to
* override. Subclasses may replace it with a function that
* returns the URI for the location where to create new folders,
* files, links, launchers, and paste the clipboard to.
*/
char * (* get_backing_uri) (NautilusView *view);
/* get_selection is not a signal; it is just a function pointer for
* subclasses to replace (override). Subclasses must replace it
* with a function that returns a newly-allocated GList of
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment