diff options
author | Ignacy Kuchciński <ignacykuchcinski@gmail.com> | 2022-08-01 02:51:26 +0200 |
---|---|---|
committer | Ignacy Kuchciński <ignacykuchcinski@gmail.com> | 2022-09-11 00:03:53 +0200 |
commit | 72f4d3f21826f6edbc6d0b39e90d8514dbddddc2 (patch) | |
tree | 6ab219e51b588f1ac286e01aa222d8b0d5a764a0 | |
parent | 389b44833661c4393829ea58e916b305e3c2d2d0 (diff) | |
download | nautilus-72f4d3f21826f6edbc6d0b39e90d8514dbddddc2.tar.gz |
new-file-dialog: Add basic dialog structure
Related: https://gitlab.gnome.org/GNOME/nautilus/-/issues/2205
-rw-r--r-- | po/POTFILES.in | 2 | ||||
-rw-r--r-- | src/meson.build | 2 | ||||
-rw-r--r-- | src/nautilus-new-file-dialog-controller.c | 298 | ||||
-rw-r--r-- | src/nautilus-new-file-dialog-controller.h | 45 | ||||
-rw-r--r-- | src/resources/nautilus.gresource.xml | 1 | ||||
-rw-r--r-- | src/resources/ui/nautilus-create-file-dialog.ui | 130 |
6 files changed, 478 insertions, 0 deletions
diff --git a/po/POTFILES.in b/po/POTFILES.in index 6bea74b37..61c923940 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -39,6 +39,7 @@ src/nautilus-list-view.c src/nautilus-location-entry.c src/nautilus-main.c src/nautilus-mime-actions.c +src/nautilus-new-file-dialog-controller.c src/nautilus-new-folder-dialog-controller.c src/nautilus-operations-ui-manager.c src/nautilus-pathbar.c @@ -69,6 +70,7 @@ src/resources/ui/nautilus-app-chooser.ui src/resources/ui/nautilus-batch-rename-dialog.ui src/resources/ui/nautilus-column-chooser.ui src/resources/ui/nautilus-compress-dialog.ui +src/resources/ui/nautilus-create-file-dialog.ui src/resources/ui/nautilus-create-folder-dialog.ui src/resources/ui/nautilus-file-conflict-dialog.ui src/resources/ui/nautilus-file-properties-change-permissions.ui diff --git a/src/meson.build b/src/meson.build index e682b99ba..a866a2e9a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -178,6 +178,8 @@ libnautilus_sources = [ 'nautilus-rename-file-popover-controller.h', 'nautilus-templates-dialog.c', 'nautilus-templates-dialog.h', + 'nautilus-new-file-dialog-controller.c', + 'nautilus-new-file-dialog-controller.h', 'nautilus-new-folder-dialog-controller.c', 'nautilus-new-folder-dialog-controller.h', 'nautilus-compress-dialog-controller.c', diff --git a/src/nautilus-new-file-dialog-controller.c b/src/nautilus-new-file-dialog-controller.c new file mode 100644 index 000000000..e66d541e9 --- /dev/null +++ b/src/nautilus-new-file-dialog-controller.c @@ -0,0 +1,298 @@ +/* nautilus-new-file-dialog-controller.c + * + * Copyright 2022 Ignacy Kuchciński <ignacykuchcinski@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "nautilus-new-file-dialog-controller.h" + +#include <glib/gi18n.h> + +#include "nautilus-application.h" + +struct _NautilusNewFileDialogController +{ + NautilusFileNameWidgetController parent_instance; + + GtkDialog *new_file_dialog; + GtkLabel *extension_label; + + gchar *template_name; + gchar *extension; +}; + +G_DEFINE_TYPE (NautilusNewFileDialogController, nautilus_new_file_dialog_controller, NAUTILUS_TYPE_FILE_NAME_WIDGET_CONTROLLER) + +static gboolean +nautilus_new_file_dialog_controller_name_is_valid (NautilusFileNameWidgetController *self, + gchar *name, + gchar **error_message) +{ + gboolean is_valid; + + is_valid = TRUE; + if (strlen (name) == 0) + { + is_valid = FALSE; + } + else if (strstr (name, "/") != NULL) + { + is_valid = FALSE; + *error_message = _("File names cannot contain “/“."); + } + else if (strcmp (name, ".") == 0) + { + is_valid = FALSE; + *error_message = _("A file cannot be called “.“."); + } + else if (strcmp (name, "..") == 0) + { + is_valid = FALSE; + *error_message = _("A file cannot be called “..“."); + } + else if (nautilus_file_name_widget_controller_is_name_too_long (self, name)) + { + is_valid = FALSE; + *error_message = _("File name is too long."); + } + else if (g_str_has_prefix (name, ".")) + { + /* We must warn about the side effect */ + *error_message = _("Files with “.“ at the beginning of their name are hidden."); + } + + return is_valid; +} + +static gchar * +nautilus_new_file_dialog_controller_get_new_name (NautilusFileNameWidgetController *controller) +{ + NautilusNewFileDialogController *self; + g_autofree gchar *basename = NULL; + + self = NAUTILUS_NEW_FILE_DIALOG_CONTROLLER (controller); + + basename = NAUTILUS_FILE_NAME_WIDGET_CONTROLLER_CLASS (nautilus_new_file_dialog_controller_parent_class)->get_new_name (controller); + + if (g_str_has_suffix (basename, self->extension)) + { + return g_strdup (basename); + } + + return g_strconcat (basename, self->extension, NULL); +} + + +gchar * +nautilus_new_file_dialog_controller_get_template_name (NautilusNewFileDialogController *self) +{ + return self->template_name; +} + +static void +new_file_dialog_controller_on_response (GtkDialog *dialog, + int response, + NautilusNewFileDialogController *self) +{ + if (response != GTK_RESPONSE_OK) + { + g_signal_emit_by_name (self, "cancelled"); + } +} + +static void +text_action_row_on_activated (GtkCheckButton *check_button, + NautilusNewFileDialogController *self) +{ + self->template_name = NULL; + self->extension = ".txt"; + gtk_label_set_text (self->extension_label, ".txt"); +} + +static void +document_action_row_on_activated (GtkCheckButton *check_button, + NautilusNewFileDialogController *self) +{ + self->template_name = "document.odt"; + self->extension = ".odt"; + gtk_label_set_text (self->extension_label, ".odt"); +} + +static void +spreadsheet_action_row_on_activated (GtkCheckButton *check_button, + NautilusNewFileDialogController *self) +{ + self->template_name = "spreadsheet.ods"; + self->extension = ".ods"; + gtk_label_set_text (self->extension_label, ".ods"); +} + +static void +presentation_action_row_on_activated (GtkCheckButton *check_button, + NautilusNewFileDialogController *self) +{ + self->template_name = "presentation.odp"; + self->extension = ".odp"; + gtk_label_set_text (self->extension_label, ".odp"); +} + +NautilusNewFileDialogController * +nautilus_new_file_dialog_controller_new (GtkWindow *parent_window, + NautilusDirectory *destination_directory) +{ + NautilusNewFileDialogController *self; + g_autoptr (GtkBuilder) builder = NULL; + GtkDialog *new_file_dialog; + GtkLabel *extension_label; + GtkRevealer *error_revealer; + GtkLabel *error_label; + AdwEntryRow *name_entry; + GtkButton *activate_button; + GList *recommended_apps; + AdwActionRow *text_action_row; + AdwActionRow *document_action_row; + AdwActionRow *spreadsheet_action_row; + AdwActionRow *presentation_action_row; + gboolean not_sandboxed; + + builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-create-file-dialog.ui"); + new_file_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "create_file_dialog")); + extension_label = GTK_LABEL (gtk_builder_get_object (builder, "extension_label")); + error_revealer = GTK_REVEALER (gtk_builder_get_object (builder, "error_revealer")); + error_label = GTK_LABEL (gtk_builder_get_object (builder, "error_label")); + name_entry = ADW_ENTRY_ROW (gtk_builder_get_object (builder, "name_entry")); + activate_button = GTK_BUTTON (gtk_builder_get_object (builder, "ok_button")); + text_action_row = ADW_ACTION_ROW (gtk_builder_get_object (builder, "text_action_row")); + document_action_row = ADW_ACTION_ROW (gtk_builder_get_object (builder, "document_action_row")); + spreadsheet_action_row = ADW_ACTION_ROW (gtk_builder_get_object (builder, "spreadsheet_action_row")); + presentation_action_row = ADW_ACTION_ROW (gtk_builder_get_object (builder, "presentation_action_row")); + + gtk_window_set_transient_for (GTK_WINDOW (new_file_dialog), parent_window); + + self = g_object_new (NAUTILUS_TYPE_NEW_FILE_DIALOG_CONTROLLER, + "error-revealer", error_revealer, + "error-label", error_label, + "name-entry", name_entry, + "activate-button", activate_button, + "containing-directory", destination_directory, NULL); + + self->new_file_dialog = new_file_dialog; + self->extension_label = extension_label; + + g_signal_connect_object (new_file_dialog, + "response", + G_CALLBACK (new_file_dialog_controller_on_response), + self, + 0); + + g_signal_connect_object (text_action_row, + "activated", + G_CALLBACK (text_action_row_on_activated), + self, + 0); + + g_signal_connect_object (document_action_row, + "activated", + G_CALLBACK (document_action_row_on_activated), + self, + 0); + + g_signal_connect_object (spreadsheet_action_row, + "activated", + G_CALLBACK (spreadsheet_action_row_on_activated), + self, + 0); + + g_signal_connect_object (presentation_action_row, + "activated", + G_CALLBACK (presentation_action_row_on_activated), + self, + 0); + + recommended_apps = g_app_info_get_recommended_for_type ("application/vnd.oasis.opendocument.presentation"); + not_sandboxed = !nautilus_application_is_sandboxed (); + + if (recommended_apps == NULL && not_sandboxed) + { + gtk_widget_set_visible (GTK_WIDGET (presentation_action_row), FALSE); + } + else + { + g_list_free_full (recommended_apps, g_object_unref); + } + + recommended_apps = g_app_info_get_recommended_for_type ("application/vnd.oasis.opendocument.spreadsheet"); + + if (recommended_apps == NULL && not_sandboxed) + { + gtk_widget_set_visible (GTK_WIDGET (spreadsheet_action_row), FALSE); + } + else + { + g_list_free_full (recommended_apps, g_object_unref); + } + + recommended_apps = g_app_info_get_recommended_for_type ("application/vnd.oasis.opendocument.text"); + + if (recommended_apps == NULL && not_sandboxed) + { + gtk_widget_set_visible (GTK_WIDGET (document_action_row), FALSE); + } + else + { + g_list_free_full (recommended_apps, g_object_unref); + } + + adw_action_row_activate (text_action_row); + + gtk_widget_show (GTK_WIDGET (new_file_dialog)); + + return self; +} + +static void +nautilus_new_file_dialog_controller_init (NautilusNewFileDialogController *self) +{ +} + +static void +nautilus_new_file_dialog_controller_finalize (GObject *gobject) +{ + NautilusNewFileDialogController *self; + + self = NAUTILUS_NEW_FILE_DIALOG_CONTROLLER (gobject); + + if (self->new_file_dialog != NULL) + { + gtk_window_destroy (GTK_WINDOW (self->new_file_dialog)); + self->new_file_dialog = NULL; + } + + G_OBJECT_CLASS (nautilus_new_file_dialog_controller_parent_class)->finalize (gobject); +} + +static void +nautilus_new_file_dialog_controller_class_init (NautilusNewFileDialogControllerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NautilusFileNameWidgetControllerClass *parent_class = NAUTILUS_FILE_NAME_WIDGET_CONTROLLER_CLASS (klass); + + object_class->finalize = nautilus_new_file_dialog_controller_finalize; + + parent_class->name_is_valid = nautilus_new_file_dialog_controller_name_is_valid; + parent_class->get_new_name = nautilus_new_file_dialog_controller_get_new_name; +} diff --git a/src/nautilus-new-file-dialog-controller.h b/src/nautilus-new-file-dialog-controller.h new file mode 100644 index 000000000..f2153f198 --- /dev/null +++ b/src/nautilus-new-file-dialog-controller.h @@ -0,0 +1,45 @@ +/* nautilus-new-file-dialog-controller.h + * + * Copyright 2022 Ignacy Kuchciński <ignacykuchcinski@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include <adwaita.h> + +#include "nautilus-file-name-widget-controller.h" +#include "nautilus-directory.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_NEW_FILE_DIALOG_CONTROLLER (nautilus_new_file_dialog_controller_get_type ()) + +G_DECLARE_FINAL_TYPE (NautilusNewFileDialogController, nautilus_new_file_dialog_controller, NAUTILUS, NEW_FILE_DIALOG_CONTROLLER, NautilusFileNameWidgetController) + +NautilusNewFileDialogController * nautilus_new_file_dialog_controller_new (GtkWindow *parent_window, + NautilusDirectory *destination_directory); + +/** + * nautilus_new_file_dialog_controller_get_template_name: + * + * Returns: the filename of the chosen blank template, or NULL if the chosen + * file type is a text file + */ +gchar * nautilus_new_file_dialog_controller_get_template_name (NautilusNewFileDialogController *self); + +G_END_DECLS diff --git a/src/resources/nautilus.gresource.xml b/src/resources/nautilus.gresource.xml index 2866224ff..56b5697da 100644 --- a/src/resources/nautilus.gresource.xml +++ b/src/resources/nautilus.gresource.xml @@ -13,6 +13,7 @@ <file>ui/nautilus-column-chooser.ui</file> <file>ui/nautilus-list-view-column-editor.ui</file> <file>ui/nautilus-templates-dialog.ui</file> + <file>ui/nautilus-create-file-dialog.ui</file> <file>ui/nautilus-create-folder-dialog.ui</file> <file>ui/nautilus-compress-dialog.ui</file> <file>ui/nautilus-rename-file-popover.ui</file> diff --git a/src/resources/ui/nautilus-create-file-dialog.ui b/src/resources/ui/nautilus-create-file-dialog.ui new file mode 100644 index 000000000..af3a19972 --- /dev/null +++ b/src/resources/ui/nautilus-create-file-dialog.ui @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <object class="GtkDialog" id="create_file_dialog"> + <property name="title" translatable="yes">New File</property> + <property name="modal">True</property> + <property name="use-header-bar">1</property> + <property name="default-width">500</property> + <property name="default-height">450</property> + <child internal-child="content_area"> + <object class="GtkBox"> + <child> + <object class="AdwClamp"> + <property name="margin_top">18</property> + <property name="margin_bottom">18</property> + <property name="margin_start">18</property> + <property name="margin_end">18</property> + <property name="child"> + <object class="GtkBox"> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="AdwPreferencesGroup"> + <child> + <object class="AdwEntryRow" id="name_entry"> + <property name="title" translatable="yes">File Name</property> + <child> + <object class="GtkLabel" id="extension_label"> + <property name="label">.txt</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + <style> + <class name="dim-label"/> + </style> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkRevealer" id="error_revealer"> + <property name="child"> + <object class="GtkLabel" id="error_label"> + <property name="xalign">0</property> + </object> + </property> + </object> + </child> + <child> + <object class="AdwPreferencesGroup"> + <child> + <object class="AdwActionRow" id="text_action_row"> + <property name="icon-name">text-x-generic-symbolic</property> + <property name="title" translatable="yes">_Text File</property> + <property name="use-underline">true</property> + <child> + <object class="GtkCheckButton" id="text_check_button"> + <property name="active">True</property> + </object> + </child> + <property name="activatable_widget">text_check_button</property> + </object> + </child> + <child> + <object class="AdwActionRow" id="document_action_row"> + <property name="icon-name">x-office-document-symbolic</property> + <property name="title" translatable="yes">_Document</property> + <property name="use-underline">true</property> + <child> + <object class="GtkCheckButton" id="document_check_button"> + <property name="group">text_check_button</property> + </object> + </child> + <property name="activatable_widget">document_check_button</property> + </object> + </child> + <child> + <object class="AdwActionRow" id="spreadsheet_action_row"> + <property name="icon-name">x-office-spreadsheet-symbolic</property> + <property name="title" translatable="yes">_Spreadsheet</property> + <property name="use-underline">true</property> + <child> + <object class="GtkCheckButton" id="spreadsheet_check_button"> + <property name="group">text_check_button</property> + </object> + </child> + <property name="activatable_widget">spreadsheet_check_button</property> + </object> + </child> + <child> + <object class="AdwActionRow" id="presentation_action_row"> + <property name="icon-name">x-office-presentation-symbolic</property> + <property name="title" translatable="yes">_Presentation</property> + <property name="use-underline">true</property> + <child> + <object class="GtkCheckButton" id="presentation_check_button"> + <property name="group">text_check_button</property> + </object> + </child> + <property name="activatable_widget">presentation_check_button</property> + </object> + </child> + </object> + </child> + </object> + </property> + </object> + </child> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="cancel_button"> + <property name="label" translatable="yes">_Cancel</property> + <property name="use-underline">true</property> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="ok_button"> + <property name="label" translatable="yes">C_reate</property> + <property name="use-underline">true</property> + <property name="sensitive">False</property> + </object> + </child> + <action-widgets> + <action-widget response="ok" default="true">ok_button</action-widget> + <action-widget response="cancel">cancel_button</action-widget> + </action-widgets> + </object> +</interface> |