summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgnacy Kuchciński <ignacykuchcinski@gmail.com>2022-08-01 02:51:26 +0200
committerIgnacy Kuchciński <ignacykuchcinski@gmail.com>2022-09-11 00:03:53 +0200
commit72f4d3f21826f6edbc6d0b39e90d8514dbddddc2 (patch)
tree6ab219e51b588f1ac286e01aa222d8b0d5a764a0
parent389b44833661c4393829ea58e916b305e3c2d2d0 (diff)
downloadnautilus-72f4d3f21826f6edbc6d0b39e90d8514dbddddc2.tar.gz
new-file-dialog: Add basic dialog structure
Related: https://gitlab.gnome.org/GNOME/nautilus/-/issues/2205
-rw-r--r--po/POTFILES.in2
-rw-r--r--src/meson.build2
-rw-r--r--src/nautilus-new-file-dialog-controller.c298
-rw-r--r--src/nautilus-new-file-dialog-controller.h45
-rw-r--r--src/resources/nautilus.gresource.xml1
-rw-r--r--src/resources/ui/nautilus-create-file-dialog.ui130
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>