diff options
-rw-r--r-- | libnautilus-private/nautilus-canvas-container.c | 41 | ||||
-rw-r--r-- | libnautilus-private/nautilus-canvas-container.h | 1 | ||||
-rw-r--r-- | libnautilus-private/nautilus-directory.c | 22 | ||||
-rw-r--r-- | libnautilus-private/nautilus-directory.h | 2 | ||||
-rw-r--r-- | src/nautilus-canvas-view.c | 18 | ||||
-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.c | 42 | ||||
-rw-r--r-- | src/nautilus-rename-file-popover.ui | 66 | ||||
-rw-r--r-- | src/nautilus-view.c | 436 | ||||
-rw-r--r-- | src/nautilus-view.h | 2 | ||||
-rw-r--r-- | src/nautilus.gresource.xml | 3 |
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> |