summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Soriano <csoriano@gnome.org>2015-08-15 17:20:21 +0200
committerCarlos Soriano <csoriano@gnome.org>2015-08-16 14:53:54 +0200
commit328348c6f76bc72823c1a8464937b7f4208674d9 (patch)
treed901e2155586dd3d14d7e3d3f56f24b0fde2649c
parentedaa65f4ee7d6219c0c6ca1cecdf84be2bc2a63d (diff)
downloadnautilus-328348c6f76bc72823c1a8464937b7f4208674d9.tar.gz
nautilus-view: use popover for renaming
Some users felt it quite disruptive to us a dialog, even if the attention has to be on the name entry. Also it's the way that GtkFileChooser implemented it and it actually feels less disruptive and desigerns agreed it works better. So continue to use a dialog for the new folder creation, but use a popover for renaming.
-rw-r--r--libnautilus-private/nautilus-canvas-container.c41
-rw-r--r--libnautilus-private/nautilus-canvas-container.h1
-rw-r--r--libnautilus-private/nautilus-directory.c22
-rw-r--r--libnautilus-private/nautilus-directory.h2
-rw-r--r--src/nautilus-canvas-view.c18
-rw-r--r--src/nautilus-create-folder-dialog.ui (renamed from src/nautilus-file-name-dialog.ui)6
-rw-r--r--src/nautilus-list-view.c42
-rw-r--r--src/nautilus-rename-file-popover.ui66
-rw-r--r--src/nautilus-view.c436
-rw-r--r--src/nautilus-view.h2
-rw-r--r--src/nautilus.gresource.xml3
11 files changed, 430 insertions, 209 deletions
diff --git a/libnautilus-private/nautilus-canvas-container.c b/libnautilus-private/nautilus-canvas-container.c
index a2620dc81..d40b77abb 100644
--- a/libnautilus-private/nautilus-canvas-container.c
+++ b/libnautilus-private/nautilus-canvas-container.c
@@ -6380,6 +6380,47 @@ nautilus_canvas_container_get_icon_locations (NautilusCanvasContainer *container
return result;
}
+/* Returns an array of GdkRectangles of the icons. */
+static GArray *
+nautilus_canvas_container_get_icons_bounding_box (NautilusCanvasContainer *container,
+ GList *icons)
+{
+ GArray *result;
+ GList *node;
+ int index;
+ int x1, x2, y1, y2;
+
+ result = g_array_new (FALSE, TRUE, sizeof (GdkRectangle));
+ result = g_array_set_size (result, g_list_length (icons));
+
+ for (index = 0, node = icons; node != NULL; index++, node = node->next) {
+ icon_get_bounding_box ((NautilusCanvasIcon *)node->data,
+ &x1, &y1, &x2, &y2,
+ BOUNDS_USAGE_FOR_ENTIRE_ITEM);
+ g_array_index (result, GdkRectangle, index).x = x1;
+ g_array_index (result, GdkRectangle, index).width = x2 - x1;
+ g_array_index (result, GdkRectangle, index).y = y1;
+ g_array_index (result, GdkRectangle, index).height = y2 - y1;
+ }
+
+ return result;
+}
+
+GArray *
+nautilus_canvas_container_get_selected_icons_bounding_box (NautilusCanvasContainer *container)
+{
+ GArray *result;
+ GList *icons;
+
+ g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), NULL);
+
+ icons = nautilus_canvas_container_get_selected_icons (container);
+ result = nautilus_canvas_container_get_icons_bounding_box (container, icons);
+ g_list_free (icons);
+
+ return result;
+}
+
/**
* nautilus_canvas_container_get_selected_icon_locations:
* @container: An canvas container widget.
diff --git a/libnautilus-private/nautilus-canvas-container.h b/libnautilus-private/nautilus-canvas-container.h
index 9519b4abe..711b3ea4b 100644
--- a/libnautilus-private/nautilus-canvas-container.h
+++ b/libnautilus-private/nautilus-canvas-container.h
@@ -270,6 +270,7 @@ void nautilus_canvas_container_invert_selection (NautilusCanvasContainer
void nautilus_canvas_container_set_selection (NautilusCanvasContainer *view,
GList *selection);
GArray * nautilus_canvas_container_get_selected_icon_locations (NautilusCanvasContainer *view);
+GArray * nautilus_canvas_container_get_selected_icons_bounding_box (NautilusCanvasContainer *container);
gboolean nautilus_canvas_container_has_stretch_handles (NautilusCanvasContainer *container);
gboolean nautilus_canvas_container_is_stretched (NautilusCanvasContainer *container);
void nautilus_canvas_container_show_stretch_handles (NautilusCanvasContainer *container);
diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c
index 4f408080a..e150e8106 100644
--- a/libnautilus-private/nautilus-directory.c
+++ b/libnautilus-private/nautilus-directory.c
@@ -1447,6 +1447,28 @@ nautilus_directory_contains_file (NautilusDirectory *directory,
return NAUTILUS_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->contains_file (directory, file);
}
+NautilusFile*
+nautilus_directory_get_file_by_name (NautilusDirectory *directory,
+ const gchar *name)
+{
+ GList *files;
+ GList *l;
+ NautilusFile *result = NULL;
+
+ files = nautilus_directory_get_file_list (directory);
+
+ for (l = files; l != NULL; l = l->next) {
+ if (nautilus_file_compare_display_name (l->data, name) == 0) {
+ result = nautilus_file_ref (l->data);
+ break;
+ }
+ }
+
+ nautilus_file_list_free (files);
+
+ return result;
+}
+
void
nautilus_directory_call_when_ready (NautilusDirectory *directory,
NautilusFileAttributes file_attributes,
diff --git a/libnautilus-private/nautilus-directory.h b/libnautilus-private/nautilus-directory.h
index 46040d7d1..5f6c0cdd8 100644
--- a/libnautilus-private/nautilus-directory.h
+++ b/libnautilus-private/nautilus-directory.h
@@ -167,6 +167,8 @@ GFile * nautilus_directory_get_location (NautilusDirector
gboolean nautilus_directory_contains_file (NautilusDirectory *directory,
NautilusFile *file);
+NautilusFile* nautilus_directory_get_file_by_name (NautilusDirectory *directory,
+ const gchar *name);
/* Get (and ref) a NautilusFile object for this directory. */
NautilusFile * nautilus_directory_get_corresponding_file (NautilusDirectory *directory);
diff --git a/src/nautilus-canvas-view.c b/src/nautilus-canvas-view.c
index 53e37d9d5..8d42d6f83 100644
--- a/src/nautilus-canvas-view.c
+++ b/src/nautilus-canvas-view.c
@@ -1172,6 +1172,23 @@ nautilus_canvas_view_reveal_selection (NautilusView *view)
nautilus_file_list_free (selection);
}
+static GdkRectangle*
+nautilus_canvas_view_compute_rename_popover_relative_to (NautilusView *view)
+{
+ GArray *bounding_boxes;
+ GdkRectangle *bounding_box;
+ NautilusCanvasContainer *canvas_container;
+
+ canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
+ bounding_boxes = nautilus_canvas_container_get_selected_icons_bounding_box (canvas_container);
+ /* We only allow renaming one item at once */
+ bounding_box = &g_array_index (bounding_boxes, GdkRectangle, 0);
+
+ g_array_free (bounding_boxes, FALSE);
+
+ return bounding_box;
+}
+
static GArray *
nautilus_canvas_view_get_selected_icon_locations (NautilusView *view)
{
@@ -1877,6 +1894,7 @@ nautilus_canvas_view_class_init (NautilusCanvasViewClass *klass)
nautilus_view_class->end_loading = nautilus_canvas_view_end_loading;
nautilus_view_class->file_changed = nautilus_canvas_view_file_changed;
nautilus_view_class->get_selected_icon_locations = nautilus_canvas_view_get_selected_icon_locations;
+ nautilus_view_class->compute_rename_popover_relative_to = nautilus_canvas_view_compute_rename_popover_relative_to;
nautilus_view_class->get_selection = nautilus_canvas_view_get_selection;
nautilus_view_class->get_selection_for_file_transfer = nautilus_canvas_view_get_selection;
nautilus_view_class->is_empty = nautilus_canvas_view_is_empty;
diff --git a/src/nautilus-file-name-dialog.ui b/src/nautilus-create-folder-dialog.ui
index 4e2c4c770..21bf6b2ad 100644
--- a/src/nautilus-file-name-dialog.ui
+++ b/src/nautilus-create-folder-dialog.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.14"/>
- <object class="GtkDialog" id="file_name_dialog">
+ <object class="GtkDialog" id="create_folder_dialog">
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
@@ -32,8 +32,8 @@
<object class="GtkEntry" id="name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <signal name="notify::text" handler="nautilus_view_file_name_dialog_entry_on_validate" swapped="no" />
- <signal name="activate" handler="nautilus_view_file_name_dialog_entry_on_activate" swapped="no" />
+ <signal name="changed" handler="create_folder_dialog_entry_on_changed" swapped="no" />
+ <signal name="activate" handler="create_folder_dialog_entry_on_activate" swapped="no" />
</object>
<packing>
<property name="expand">False</property>
diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c
index 20a4882c4..35a7472f6 100644
--- a/src/nautilus-list-view.c
+++ b/src/nautilus-list-view.c
@@ -59,6 +59,12 @@
#define DEBUG_FLAG NAUTILUS_DEBUG_LIST_VIEW
#include <libnautilus-private/nautilus-debug.h>
+/* We use a rectangle to make the popover point to the right column. In an
+ * ideal world with GtkListBox we would just point to the GtkListBoxRow. In our case, we
+ * need to use a rectangle and we provide some width to not make the popover arrow pointy
+ * in the edges if the window is small */
+#define RENAME_POPOVER_RELATIVE_TO_RECTANGLE_WIDTH 40
+
struct NautilusListViewDetails {
GtkTreeView *tree_view;
NautilusListModel *model;
@@ -3240,6 +3246,41 @@ nautilus_list_view_get_id (NautilusView *view)
return NAUTILUS_LIST_VIEW_ID;
}
+static GdkRectangle*
+nautilus_list_view_compute_rename_popover_relative_to (NautilusView *view)
+{
+ GtkTreeSelection *selection;
+ GtkTreePath *path;
+ GdkRectangle *rect;
+ GtkTreeModel *model;
+ GtkTreeView *tree_view;
+ GList *list;
+ NautilusListView *list_view;
+
+ rect = g_malloc0 (sizeof(GdkRectangle));
+ list_view = NAUTILUS_LIST_VIEW (view);
+ tree_view = list_view->details->tree_view;
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view->details->tree_view));
+ model = GTK_TREE_MODEL (list_view->details->model);
+ list = gtk_tree_selection_get_selected_rows (selection, &model);
+ path = list->data;
+ gtk_tree_view_get_cell_area (tree_view, path, NULL, rect);
+ gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+ rect->x, rect->y,
+ &rect->x, &rect->y);
+
+ rect->x = CLAMP (gtk_widget_get_allocated_width (GTK_WIDGET (tree_view)) * 0.5 -
+ RENAME_POPOVER_RELATIVE_TO_RECTANGLE_WIDTH * 0.5,
+ 0,
+ gtk_widget_get_allocated_width (GTK_WIDGET (tree_view)) -
+ RENAME_POPOVER_RELATIVE_TO_RECTANGLE_WIDTH);
+ rect->width = RENAME_POPOVER_RELATIVE_TO_RECTANGLE_WIDTH;
+
+ g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
+
+ return rect;
+}
+
static void
nautilus_list_view_class_init (NautilusListViewClass *class)
{
@@ -3277,6 +3318,7 @@ nautilus_list_view_class_init (NautilusListViewClass *class)
nautilus_view_class->get_view_id = nautilus_list_view_get_id;
nautilus_view_class->get_first_visible_file = nautilus_list_view_get_first_visible_file;
nautilus_view_class->scroll_to_file = list_view_scroll_to_file;
+ nautilus_view_class->compute_rename_popover_relative_to = nautilus_list_view_compute_rename_popover_relative_to;
}
static void
diff --git a/src/nautilus-rename-file-popover.ui b/src/nautilus-rename-file-popover.ui
new file mode 100644
index 000000000..5214857c2
--- /dev/null
+++ b/src/nautilus-rename-file-popover.ui
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <object class="GtkPopover" id="rename_file_popover">
+ <property name="position">bottom</property>
+ <signal name="closed" handler="rename_file_popover_on_closed"/>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="margin">10</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="name_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Name</property>
+ <property name="halign">start</property>
+ <property name="mnemonic_widget">name_entry</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="name_entry">
+ <property name="visible">True</property>
+ <property name="activates-default">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="rename_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">_Rename</property>
+ <property name="use_underline">True</property>
+ <property name="can_default">True</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="error_label">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/src/nautilus-view.c b/src/nautilus-view.c
index 073bacc0e..d5ec6a121 100644
--- a/src/nautilus-view.c
+++ b/src/nautilus-view.c
@@ -116,8 +116,8 @@
#define MAX_MENU_LEVELS 5
#define TEMPLATE_LIMIT 30
-/* Time to show the duplicated folder label */
-#define DIALOG_DUPLICATED_NAME_ERROR_LABEL_TIMEOUT 500
+/* Delay to show the duplicated label when creating a folder */
+#define CREATE_FOLDER_DUPLICATED_LABEL_TIMEOUT 500
/* Delay to show the Loading... floating bar */
#define FLOATING_BAR_LOADING_DELAY 500 /* ms */
@@ -159,7 +159,8 @@ struct NautilusViewDetails
NautilusFile *directory_as_file;
guint dir_merge_id;
- gint dialog_duplicated_name_label_timeout_id;
+ gint create_folder_duplicated_label_timeout_id;
+ GtkWidget *rename_file_popover;
gboolean supports_zooming;
@@ -1699,16 +1700,18 @@ context_menu_to_file_operation_position (NautilusView *view)
typedef struct {
NautilusView *view;
- GtkWidget *dialog;
+ GtkWidget *widget;
GtkWidget *error_label;
GtkWidget *name_entry;
gboolean target_is_folder;
NautilusFile *target_file;
+ GtkWidget *activate_button;
gboolean duplicated_is_folder;
-} FileNameDialogData;
+} FileNameWidgetData;
typedef struct {
NautilusView *view;
+ GtkWidget *widget;
GtkWidget *name_entry;
NautilusFile *target_file;
} RenameDialogData;
@@ -1720,143 +1723,152 @@ typedef struct {
} NewFolderDialogData;
static gboolean
-duplicated_file_label_show (FileNameDialogData *data)
+duplicated_file_label_show (FileNameWidgetData *data)
{
if (data->duplicated_is_folder)
gtk_label_set_label (GTK_LABEL (data->error_label), _("A folder with that name already exists."));
else
gtk_label_set_label (GTK_LABEL (data->error_label), _("A file with that name already exists."));
- data->view->details->dialog_duplicated_name_label_timeout_id = 0;
- return FALSE;
+ data->view->details->create_folder_duplicated_label_timeout_id = 0;
+
+ return G_SOURCE_REMOVE;
}
-static void
-nautilus_view_file_name_dialog_validate_name (FileNameDialogData *data)
+static gchar*
+validate_file_name (const gchar *name,
+ gboolean is_folder)
{
- gboolean duplicated_name;
- gboolean valid_name;
- gchar *name;
- GList *files;
- GList *node;
- NautilusFile *file;
-
- g_assert (data != NULL);
- g_assert (GTK_IS_ENTRY (data->name_entry));
- g_assert (GTK_IS_LABEL (data->error_label));
- g_assert (GTK_IS_DIALOG (data->dialog));
- g_assert (NAUTILUS_IS_VIEW (data->view));
+ gchar *error_message = NULL;
- name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry))));
- duplicated_name = FALSE;
- valid_name = FALSE;
- files = nautilus_directory_get_file_list (data->view->details->model);
-
- for (node = files; node != NULL; node = node->next) {
- file = node->data;
-
- if (nautilus_file_compare_display_name (file, name) == 0) {
- /* If we are renaming, we don't want to block the user to
- * rename the file with the current file name */
- if (data->target_file == NULL ||
- nautilus_file_compare_display_name (data->target_file, name) != 0) {
- duplicated_name = TRUE;
- data->duplicated_is_folder = nautilus_file_is_directory (file);
- break;
- }
- }
- }
-
- nautilus_file_list_free (files);
-
- /* Remove any sources left behind by
- * previous calls of this function.
- */
- if (data->view->details->dialog_duplicated_name_label_timeout_id > 0) {
- g_source_remove (data->view->details->dialog_duplicated_name_label_timeout_id);
- data->view->details->dialog_duplicated_name_label_timeout_id = 0;
- }
-
- if (duplicated_name) {
- data->view->details->dialog_duplicated_name_label_timeout_id =
- g_timeout_add (DIALOG_DUPLICATED_NAME_ERROR_LABEL_TIMEOUT,
- (GSourceFunc)duplicated_file_label_show,
- data);
- } else if (strstr (name, "/") != NULL) {
- if (data->target_is_folder)
- gtk_label_set_label (GTK_LABEL (data->error_label), _("Folder names cannot contain “/”."));
+ if (strstr (name, "/") != NULL) {
+ if (is_folder)
+ error_message = _("Folder names cannot contain “/”.");
else
- gtk_label_set_label (GTK_LABEL (data->error_label), _("Files names cannot contain “/”."));
+ error_message = _("Files names cannot contain “/”.");
} else if (strcmp (name, ".") == 0){
- if (data->target_is_folder)
- gtk_label_set_label (GTK_LABEL (data->error_label), _("A folder can not be called “.”."));
+ if (is_folder)
+ error_message = _("A folder can not be called “.”.");
else
- gtk_label_set_label (GTK_LABEL (data->error_label), _("A file can not be called “.”."));
+ error_message = _("A file can not be called “.”.");
} else if (strcmp (name, "..") == 0){
- if (data->target_is_folder)
- gtk_label_set_label (GTK_LABEL (data->error_label), _("A folder can not be called “..”."));
+ if (is_folder)
+ error_message = _("A folder can not be called “..”.");
else
- gtk_label_set_label (GTK_LABEL (data->error_label), _("A file can not be called “..”."));
- } else {
- /* No errors detected, empty the label */
- gtk_label_set_label (GTK_LABEL (data->error_label), NULL);
- valid_name = strlen (name) > 0;
+ error_message = _("A file can not be called “..”.");
}
- gtk_dialog_set_response_sensitive (GTK_DIALOG (data->dialog),
- GTK_RESPONSE_OK,
- valid_name);
- g_free (name);
+ return error_message;
}
static void
-nautilus_view_file_name_dialog_entry_on_validate (GObject *object,
- GParamSpec *params,
- gpointer user_data)
+create_folder_dialog_entry_on_changed (GtkEntry *entry,
+ gpointer user_data)
{
- FileNameDialogData *data;
+ FileNameWidgetData *data;
+ NautilusFile *existing_file;
+ gchar *name;
+ gchar *error_message;
+ gboolean valid_name;
+ gboolean can_create_folder;
+
+ data = (FileNameWidgetData *) user_data;
+ name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry))));
+ error_message = validate_file_name (name, TRUE);
+ gtk_label_set_label (GTK_LABEL (data->error_label), error_message);
+
+ existing_file = nautilus_directory_get_file_by_name (data->view->details->model, name);
+
+ valid_name = strlen (name) > 0 && error_message == NULL;
+ can_create_folder = existing_file == NULL && valid_name;
+ gtk_widget_set_sensitive (data->activate_button, can_create_folder);
- data = (FileNameDialogData *) user_data;
+ if (data->view->details->create_folder_duplicated_label_timeout_id > 0) {
+ g_source_remove (data->view->details->create_folder_duplicated_label_timeout_id);
+ data->view->details->create_folder_duplicated_label_timeout_id = 0;
+ }
+
+ /* Report duplicated file only if not other message shown (for instance,
+ * folders like "." or ".." will always exists, but we consider it as an
+ * error, not as a duplicated file) */
+ if (existing_file != NULL && valid_name) {
+ data->duplicated_is_folder = nautilus_file_is_directory (existing_file);
+ data->view->details->create_folder_duplicated_label_timeout_id =
+ g_timeout_add (CREATE_FOLDER_DUPLICATED_LABEL_TIMEOUT,
+ (GSourceFunc)duplicated_file_label_show,
+ data);
+ }
- nautilus_view_file_name_dialog_validate_name (data);
+ if (existing_file != NULL)
+ nautilus_file_unref (existing_file);
}
static void
-nautilus_view_file_name_dialog_entry_on_activate (GtkWidget *entry,
- gpointer user_data)
+rename_file_popover_entry_on_changed (GtkEntry *entry,
+ gpointer user_data)
{
- FileNameDialogData *data;
- GtkWidget *create_button;
+ FileNameWidgetData *data;
+ gboolean valid_name;
+ gchar *name;
+ gchar *error_message;
- data = (FileNameDialogData *) user_data;
- create_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog),
- GTK_RESPONSE_OK);
+ data = (FileNameWidgetData *) user_data;
+ name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry))));
+ error_message = validate_file_name (name, nautilus_file_is_directory (data->target_file));
+ gtk_label_set_label (GTK_LABEL (data->error_label), error_message);
- /* nautilus_view_new_folder_dialog_validate_name performs
- * all the necessary validation, and it's not needed to check
- * it all again. Checking if the "Create" button is sensitive
- * is enough.
- */
- if (gtk_widget_get_sensitive (create_button)) {
- gtk_dialog_response (GTK_DIALOG (data->dialog),
+ valid_name = strlen (name) > 0 && error_message == NULL;
+ gtk_widget_set_sensitive (data->activate_button, valid_name);
+
+ g_free (name);
+}
+
+static void
+create_folder_dialog_entry_on_activate (GtkWidget *entry,
+ gpointer user_data)
+{
+ FileNameWidgetData *data;
+ NautilusFile *existing_file;
+ gchar *name;
+ gchar *error_message;
+ gboolean valid_name;
+ gboolean can_create_folder;
+
+ data = (FileNameWidgetData *) user_data;
+ name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry))));
+ existing_file = nautilus_directory_get_file_by_name (data->view->details->model, name);
+ error_message = validate_file_name (name, TRUE);
+ valid_name = strlen (name) > 0 && error_message == NULL;
+ can_create_folder = existing_file == NULL && valid_name;
+
+ if (data->view->details->create_folder_duplicated_label_timeout_id > 0) {
+ g_source_remove (data->view->details->create_folder_duplicated_label_timeout_id);
+ data->view->details->create_folder_duplicated_label_timeout_id = 0;
+ }
+
+ if (can_create_folder) {
+ gtk_dialog_response (GTK_DIALOG (data->widget),
GTK_RESPONSE_OK);
- } else {
- NautilusView *view = data->view;
+ } else {
+ /* Report duplicated file only if not other message shown (for instance,
+ * folders like "." or ".." will always exists, but we consider it as an
+ * error, not as a duplicated file) */
+ if (existing_file != NULL && valid_name) {
+ data->duplicated_is_folder = nautilus_file_is_directory (existing_file);
+ /* Show it inmediatily since the user tried to trigger the action */
+ duplicated_file_label_show (data);
+ }
+ }
- /* Since typos are immediately shown, only
- * handle name collisions here.
- */
- if (view->details->dialog_duplicated_name_label_timeout_id > 0) {
- g_source_remove (view->details->dialog_duplicated_name_label_timeout_id);
- duplicated_file_label_show (data);
- }
- }
+ if (existing_file != NULL)
+ nautilus_file_unref (existing_file);
+
+ g_free (name);
}
static void
-nautilus_view_rename_dialog_on_response (GtkDialog *dialog,
- gint response_id,
- gpointer user_data)
+rename_file_popover_rename_button_on_clicked (GtkButton *entry,
+ gpointer *user_data)
{
RenameDialogData *rename_data;
gchar *name;
@@ -1867,96 +1879,113 @@ nautilus_view_rename_dialog_on_response (GtkDialog *dialog,
g_assert (GTK_IS_ENTRY (rename_data->name_entry));
g_assert (NAUTILUS_IS_FILE (rename_data->target_file));
- if (response_id == GTK_RESPONSE_OK) {
- name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (rename_data->name_entry))));
- nautilus_rename_file (rename_data->target_file, name, NULL, NULL);
- g_free (name);
- }
+ name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (rename_data->name_entry))));
+ nautilus_rename_file (rename_data->target_file, name, NULL, NULL);
+ g_free (name);
+
nautilus_view_select_file (rename_data->view, rename_data->target_file);
nautilus_view_reveal_selection (rename_data->view);
- /* If there's any resources left from the delayed
- * message, it should be removed before it gets
- * triggered.
- */
- if (rename_data->view->details->dialog_duplicated_name_label_timeout_id > 0) {
- g_source_remove (rename_data->view->details->dialog_duplicated_name_label_timeout_id);
- rename_data->view->details->dialog_duplicated_name_label_timeout_id = 0;
- }
+ gtk_widget_hide (rename_data->widget);
- g_free (user_data);
- gtk_widget_destroy (GTK_WIDGET (dialog));
+ g_free (rename_data);
+}
+
+static void
+rename_file_popover_on_closed (GtkPopover *popover,
+ gpointer user_data)
+{
+ FileNameWidgetData *widget_data;
+
+ widget_data = (FileNameWidgetData *) user_data;
+ widget_data->view->details->rename_file_popover = NULL;
+ g_free (widget_data);
+}
+
+static GdkRectangle*
+nautilus_view_compute_rename_popover_relative_to (NautilusView *view)
+{
+ return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compute_rename_popover_relative_to (view);
}
static void
-nautilus_view_rename_dialog_new (NautilusView *view,
- NautilusFile *target_file)
+nautilus_view_rename_file_popover_new (NautilusView *view,
+ NautilusFile *target_file)
{
- FileNameDialogData *dialog_data;
- RenameDialogData *user_data;
- GtkWidget *button_ok;
+ FileNameWidgetData *widget_data;
+ RenameDialogData *rename_data;
GtkWidget *label_file_name;
GtkBuilder *builder;
gint start_offset, end_offset;
- gchar *file_name;
- gchar *title;
+ GdkRectangle *relative_to;
- builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-file-name-dialog.ui");
- button_ok = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
- label_file_name = GTK_WIDGET (gtk_builder_get_object (builder, "name_label"));
+ if (view->details->rename_file_popover != NULL)
+ return;
- dialog_data = g_new (FileNameDialogData, 1);
- dialog_data->view = view;
- dialog_data->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "file_name_dialog"));
- dialog_data->error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
- dialog_data->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry"));
- dialog_data->target_is_folder = nautilus_file_is_directory (target_file);
- dialog_data->target_file = target_file;
+ builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-rename-file-popover.ui");
+ label_file_name = GTK_WIDGET (gtk_builder_get_object (builder, "name_label"));
- user_data = g_new (RenameDialogData, 1);
- user_data->view = view;
- user_data->target_file = target_file;
- user_data->name_entry = dialog_data->name_entry;
+ widget_data = g_new (FileNameWidgetData, 1);
+ widget_data->view = view;
+ widget_data->widget = GTK_WIDGET (gtk_builder_get_object (builder, "rename_file_popover"));
+ widget_data->activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "rename_button"));
+ widget_data->error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
+ widget_data->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry"));
+ widget_data->target_is_folder = nautilus_file_is_directory (target_file);
+ widget_data->target_file = target_file;
- gtk_window_set_transient_for (GTK_WINDOW (dialog_data->dialog),
- GTK_WINDOW (nautilus_view_get_window (view)));
+ view->details->rename_file_popover = widget_data->widget;
- /* Connect signals */
- gtk_builder_add_callback_symbols (builder,
- "nautilus_view_file_name_dialog_entry_on_validate",
- G_CALLBACK (nautilus_view_file_name_dialog_entry_on_validate),
- "nautilus_view_file_name_dialog_entry_on_activate",
- G_CALLBACK (nautilus_view_file_name_dialog_entry_on_activate),
- NULL);
+ rename_data = g_new (RenameDialogData, 1);
+ rename_data->view = view;
+ rename_data->widget = widget_data->widget;
+ rename_data->target_file = target_file;
+ rename_data->name_entry = widget_data->name_entry;
- dialog_data->target_is_folder = nautilus_file_is_directory (target_file);
- gtk_button_set_label (GTK_BUTTON (button_ok), _("Rename"));
- file_name = nautilus_file_get_display_name (target_file);
- title = g_strdup_printf (_("Rename “%s”"), file_name);
- gtk_window_set_title (GTK_WINDOW (dialog_data->dialog), title);
- g_free (file_name);
- g_free (title);
- if (dialog_data->target_is_folder)
+ if (widget_data->target_is_folder)
gtk_label_set_text (GTK_LABEL (label_file_name), _("Folder name"));
else
gtk_label_set_text (GTK_LABEL (label_file_name), _("File name"));
- gtk_entry_set_text (GTK_ENTRY (dialog_data->name_entry), nautilus_file_get_name (target_file));
- gtk_builder_connect_signals (builder, dialog_data);
-
- g_signal_connect (dialog_data->dialog,
- "response",
- G_CALLBACK (nautilus_view_rename_dialog_on_response),
- user_data);
+ gtk_entry_set_text (GTK_ENTRY (widget_data->name_entry), nautilus_file_get_name (target_file));
+
+ g_signal_connect (widget_data->activate_button,
+ "clicked",
+ G_CALLBACK (rename_file_popover_rename_button_on_clicked),
+ rename_data);
+
+ g_signal_connect (widget_data->name_entry,
+ "changed",
+ G_CALLBACK (rename_file_popover_entry_on_changed),
+ widget_data);
+
+ g_signal_connect (GTK_POPOVER (widget_data->widget),
+ "closed",
+ G_CALLBACK (rename_file_popover_on_closed),
+ widget_data);
+
+ g_signal_connect (GTK_POPOVER (widget_data->widget),
+ "unmap",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ relative_to = nautilus_view_compute_rename_popover_relative_to (view);
+ gtk_popover_set_default_widget (GTK_POPOVER (widget_data->widget),
+ widget_data->activate_button);
+ gtk_popover_set_pointing_to (GTK_POPOVER (widget_data->widget), relative_to);
+ gtk_popover_set_relative_to (GTK_POPOVER (widget_data->widget),
+ GTK_WIDGET (view));
+ gtk_widget_show (widget_data->widget);
- gtk_widget_show_all (dialog_data->dialog);
/* Select the name part withouth the file extension */
eel_filename_get_rename_region (nautilus_file_get_name (target_file),
&start_offset, &end_offset);
- gtk_editable_select_region (GTK_EDITABLE (dialog_data->name_entry),
+ gtk_editable_select_region (GTK_EDITABLE (widget_data->name_entry),
start_offset, end_offset);
- /* Update the ok button status */
- nautilus_view_file_name_dialog_validate_name (dialog_data);
+ /* Update the rename button status */
+ rename_file_popover_entry_on_changed (GTK_ENTRY (widget_data->name_entry),
+ widget_data);
+
g_object_unref (builder);
}
@@ -2000,70 +2029,67 @@ nautilus_view_new_folder_dialog_on_response (GtkDialog *dialog,
g_free (name);
}
- /* If there's any resources left from the delayed
- * message, it should be removed before it gets
- * triggered.
- */
- if (new_folder_data->view->details->dialog_duplicated_name_label_timeout_id > 0) {
- g_source_remove (new_folder_data->view->details->dialog_duplicated_name_label_timeout_id);
- new_folder_data->view->details->dialog_duplicated_name_label_timeout_id = 0;
- }
+ if (new_folder_data->view->details->create_folder_duplicated_label_timeout_id > 0) {
+ g_source_remove (new_folder_data->view->details->create_folder_duplicated_label_timeout_id);
+ new_folder_data->view->details->create_folder_duplicated_label_timeout_id = 0;
+ }
- g_free (user_data);
gtk_widget_destroy (GTK_WIDGET (dialog));
+ g_free (user_data);
}
static void
nautilus_view_new_folder_dialog_new (NautilusView *view,
gboolean with_selection)
{
- FileNameDialogData *dialog_data;
+ FileNameWidgetData *widget_data;
NewFolderDialogData *user_data;
- GtkWidget *button_ok;
GtkWidget *label_file_name;
GtkBuilder *builder;
- builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-file-name-dialog.ui");
- button_ok = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
+ builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-create-folder-dialog.ui");
label_file_name = GTK_WIDGET (gtk_builder_get_object (builder, "name_label"));
- dialog_data = g_new (FileNameDialogData, 1);
- dialog_data->view = view;
- dialog_data->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "file_name_dialog"));
- dialog_data->error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
- dialog_data->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry"));
- dialog_data->target_is_folder = TRUE;
- dialog_data->target_file = NULL;
+ widget_data = g_new (FileNameWidgetData, 1);
+ widget_data->view = view;
+ widget_data->widget = GTK_WIDGET (gtk_builder_get_object (builder, "create_folder_dialog"));
+ widget_data->activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
+ widget_data->error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
+ widget_data->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry"));
+ widget_data->target_is_folder = TRUE;
+ widget_data->target_file = NULL;
user_data = g_new (NewFolderDialogData, 1);
user_data->view = view;
user_data->with_selection = with_selection;
- user_data->name_entry = dialog_data->name_entry;
+ user_data->name_entry = widget_data->name_entry;
- gtk_window_set_transient_for (GTK_WINDOW (dialog_data->dialog),
+ gtk_window_set_transient_for (GTK_WINDOW (widget_data->widget),
GTK_WINDOW (nautilus_view_get_window (view)));
/* Connect signals */
gtk_builder_add_callback_symbols (builder,
- "nautilus_view_file_name_dialog_entry_on_validate",
- G_CALLBACK (nautilus_view_file_name_dialog_entry_on_validate),
- "nautilus_view_file_name_dialog_entry_on_activate",
- G_CALLBACK (nautilus_view_file_name_dialog_entry_on_activate),
+ "create_folder_dialog_entry_on_changed",
+ G_CALLBACK (create_folder_dialog_entry_on_changed),
+ "create_folder_dialog_entry_on_activate",
+ G_CALLBACK (create_folder_dialog_entry_on_activate),
NULL);
- gtk_builder_connect_signals (builder, dialog_data);
- gtk_button_set_label (GTK_BUTTON (button_ok), _("Create"));
+ gtk_builder_connect_signals (builder, widget_data);
+ gtk_button_set_label (GTK_BUTTON (widget_data->activate_button),
+ _("Create"));
gtk_label_set_text (GTK_LABEL (label_file_name), _("Folder name"));
- gtk_window_set_title (GTK_WINDOW (dialog_data->dialog), _("New Folder"));
+ gtk_window_set_title (GTK_WINDOW (widget_data->widget), _("New Folder"));
- g_signal_connect (dialog_data->dialog,
+ g_signal_connect (widget_data->widget,
"response",
G_CALLBACK (nautilus_view_new_folder_dialog_on_response),
user_data);
- gtk_widget_show_all (dialog_data->dialog);
+ gtk_widget_show_all (widget_data->widget);
/* Update the ok button status */
- nautilus_view_file_name_dialog_validate_name (dialog_data);
+ create_folder_dialog_entry_on_changed (GTK_ENTRY (widget_data->name_entry),
+ widget_data);
g_object_unref (builder);
}
@@ -5488,7 +5514,7 @@ real_action_rename (NautilusView *view,
* they are always pre-selected as a whole */
select_all = nautilus_file_is_directory (file);
}
- nautilus_view_rename_dialog_new (view, file);
+ nautilus_view_rename_file_popover_new (view, file);
}
}
diff --git a/src/nautilus-view.h b/src/nautilus-view.h
index 93fbc894d..3cc87dab0 100644
--- a/src/nautilus-view.h
+++ b/src/nautilus-view.h
@@ -276,6 +276,8 @@ struct NautilusViewClass {
const char *uri);
NautilusWindow * (*get_window) (NautilusView *view);
+
+ GdkRectangle * (*compute_rename_popover_relative_to) (NautilusView *view);
};
/* GObject support */
diff --git a/src/nautilus.gresource.xml b/src/nautilus.gresource.xml
index acab5ff41..c80a529d4 100644
--- a/src/nautilus.gresource.xml
+++ b/src/nautilus.gresource.xml
@@ -8,7 +8,8 @@
<file>nautilus-toolbar-ui.xml</file>
<file>nautilus-toolbar-view-menu.xml</file>
<file>nautilus-toolbar-action-menu.xml</file>
- <file>nautilus-file-name-dialog.ui</file>
+ <file>nautilus-create-folder-dialog.ui</file>
+ <file>nautilus-rename-file-popover.ui</file>
<file>nautilus-view-context-menus.xml</file>
<file>nautilus-progress-info-widget.xml</file>
<file>nautilus-move-to-trash-shortcut-changed.ui</file>