[file-roller/wip/gtk4: 34/54] new archive: added a custom location button




commit 365e93f6de970a257cb899f081bc94e4ea7080e1
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sat Oct 1 21:56:11 2022 +0200

    new archive: added a custom location button

 src/fr-location-button.c     | 266 +++++++++++++++++++++++++++++++++++++++++++
 src/fr-location-button.h     |  50 ++++++++
 src/fr-new-archive-dialog.c  |   9 +-
 src/meson.build              |   2 +
 src/ui/new-archive-dialog.ui |  69 +++++------
 5 files changed, 362 insertions(+), 34 deletions(-)
---
diff --git a/src/fr-location-button.c b/src/fr-location-button.c
new file mode 100644
index 00000000..4b609413
--- /dev/null
+++ b/src/fr-location-button.c
@@ -0,0 +1,266 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  File-Roller
+ *
+ *  Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ *  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 2 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/>.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include "gtk-utils.h"
+#include "glib-utils.h"
+#include "fr-location-button.h"
+
+
+enum {
+       PROP_0,
+       PROP_TITLE,
+};
+
+
+enum {
+       CHANGED,
+       LAST_SIGNAL
+};
+
+
+static guint fr_location_button_signals[LAST_SIGNAL] = { 0 };
+
+
+typedef struct {
+       GFile *location;
+       GtkWidget *label;
+       GtkWidget *icon;
+       GtkFileChooserNative *chooser;
+       char *title;
+} FrLocationButtonPrivate;
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (FrLocationButton, fr_location_button, GTK_TYPE_BUTTON)
+
+
+static void
+fr_location_button_finalize (GObject *object)
+{
+       FrLocationButton *self = FR_LOCATION_BUTTON (object);
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+
+       _g_object_unref (private->chooser);
+       g_free (private->title);
+
+       G_OBJECT_CLASS (fr_location_button_parent_class)->finalize (object);
+}
+
+
+static void
+gth_location_button_set_property (GObject      *object,
+                                 guint         property_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+       FrLocationButton *self = FR_LOCATION_BUTTON (object);
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+
+       switch (property_id) {
+       case PROP_TITLE:
+               g_free (private->title);
+               private->title = g_value_dup_string (value);
+               break;
+
+       default:
+               break;
+       }
+}
+
+
+static void
+gth_location_button_get_property (GObject    *object,
+                                 guint       property_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+       FrLocationButton *self = FR_LOCATION_BUTTON (object);
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+
+       switch (property_id) {
+       case PROP_TITLE:
+               g_value_set_string (value, private->title);
+               break;
+
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+               break;
+       }
+}
+
+
+static void
+fr_location_button_class_init (FrLocationButtonClass *klass)
+{
+       GObjectClass *object_class;
+
+       fr_location_button_parent_class = g_type_class_peek_parent (klass);
+
+       object_class = (GObjectClass*) klass;
+       object_class->set_property = gth_location_button_set_property;
+       object_class->get_property = gth_location_button_get_property;
+       object_class->finalize = fr_location_button_finalize;
+
+       fr_location_button_signals[CHANGED] =
+               g_signal_newv ("changed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              /* class_closure = */ NULL,
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0, NULL);
+
+       g_object_class_install_property (object_class,
+                                        PROP_TITLE,
+                                        g_param_spec_string ("title",
+                                                             "Title",
+                                                             "The file chooser title",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+
+}
+
+
+static void
+location_changed (FrLocationButton *self) {
+       g_signal_emit (self, fr_location_button_signals[CHANGED], 0, NULL);
+}
+
+
+static void
+file_chooser_response_cb (GtkNativeDialog *native,
+                         int              response,
+                         gpointer         user_data)
+{
+       FrLocationButton *self = user_data;
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+
+       if (response == GTK_RESPONSE_ACCEPT) {
+               GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (private->chooser));
+               if (file != NULL) {
+                       fr_location_button_set_location (self, file);
+                       location_changed (self);
+                       g_object_unref (file);
+               }
+       }
+
+       g_object_unref (private->chooser);
+       private->chooser = NULL;
+}
+
+
+static void
+clicked_cb (GtkButton *button,
+           gpointer   user_data)
+{
+       FrLocationButton *self = user_data;
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+
+       if (private->chooser != NULL)
+               return;
+
+       private->chooser = gtk_file_chooser_native_new (private->title,
+                                                       GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
+                                                       GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                                                       _GTK_LABEL_OPEN,
+                                                       _GTK_LABEL_CANCEL);
+       gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (private->chooser), TRUE);
+       if (private->location != NULL)
+               gtk_file_chooser_set_file (GTK_FILE_CHOOSER (private->chooser), private->location, NULL);
+       g_signal_connect (private->chooser,
+                         "response",
+                         G_CALLBACK (file_chooser_response_cb),
+                         self);
+       gtk_native_dialog_show (GTK_NATIVE_DIALOG (private->chooser));
+}
+
+
+static void
+fr_location_button_init (FrLocationButton *self)
+{
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+
+       private->chooser = NULL;
+       private->title = NULL;
+
+       gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
+
+       GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
+       gtk_button_set_child (GTK_BUTTON (self), box);
+
+       private->icon = gtk_image_new ();
+       gtk_box_append (GTK_BOX (box), private->icon);
+
+       private->label = gtk_label_new (private->title);
+       gtk_box_append (GTK_BOX (box), private->label);
+
+       g_signal_connect (self,
+                         "clicked",
+                         G_CALLBACK (clicked_cb),
+                         self);
+}
+
+
+GtkWidget *
+fr_location_button_new (const char *title)
+{
+       return g_object_new (FR_TYPE_LOCATION_BUTTON,
+                            "title", title,
+                            NULL);
+}
+
+
+GFile *
+fr_location_button_get_location (FrLocationButton *self)
+{
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+       return _g_object_ref (private->location);
+}
+
+
+void
+fr_location_button_set_location (FrLocationButton *self,
+                                GFile            *location)
+{
+       FrLocationButtonPrivate *private = fr_location_button_get_instance_private (self);
+
+       _g_object_unref (private->location);
+       private->location = g_object_ref (location);
+
+       GFileInfo *info = g_file_query_info (private->location,
+                                            "standard::display-name,standard::icon,standard::symbolic-icon",
+                                            G_FILE_QUERY_INFO_NONE,
+                                            NULL,
+                                            NULL);
+       if (info != NULL) {
+               gtk_label_set_text (GTK_LABEL (private->label), g_file_info_get_display_name (info));
+               gtk_image_set_from_gicon (GTK_IMAGE (private->icon), g_file_info_get_symbolic_icon (info));
+               g_object_unref (info);
+       }
+       else {
+               char *name = g_file_get_uri (private->location);
+               gtk_label_set_text (GTK_LABEL (private->label), name);
+               gtk_image_set_from_icon_name (GTK_IMAGE (private->icon), "folder-symbolic");
+               g_free (name);
+       }
+}
diff --git a/src/fr-location-button.h b/src/fr-location-button.h
new file mode 100644
index 00000000..e7f253a9
--- /dev/null
+++ b/src/fr-location-button.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  File-Roller
+ *
+ *  Copyright (C) 2022 The Free Software Foundation, Inc.
+ *
+ *  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 2 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/>.
+ */
+
+#ifndef FR_LOCATION_BUTTON_H
+#define FR_LOCATION_BUTTON_H
+
+#include <gtk/gtk.h>
+
+#define FR_TYPE_LOCATION_BUTTON (fr_location_button_get_type ())
+G_DECLARE_FINAL_TYPE (FrLocationButton, fr_location_button, FR, LOCATION_BUTTON, GtkButton)
+
+struct _FrLocationButton {
+       GtkButton parent_class;
+};
+
+struct _FrLocationButtonClass {
+       GtkButtonClass parent_class;
+       void (* changed) (FrLocationButton *location_button);
+};
+
+GtkWidget * fr_location_button_new (const char *title);
+
+/**
+ * fr_location_button_get_location:
+ * Returns: (transfer full)
+ */
+GFile * fr_location_button_get_location (FrLocationButton *dialog);
+
+void    fr_location_button_set_location (FrLocationButton *dialog,
+                                        GFile            *location);
+
+#endif /* FR_LOCATION_BUTTON_H */
diff --git a/src/fr-new-archive-dialog.c b/src/fr-new-archive-dialog.c
index ae2867b9..428cd131 100644
--- a/src/fr-new-archive-dialog.c
+++ b/src/fr-new-archive-dialog.c
@@ -26,6 +26,7 @@
 #include <gio/gio.h>
 #include "file-utils.h"
 #include "fr-init.h"
+#include "fr-location-button.h"
 #include "fr-new-archive-dialog.h"
 #include "glib-utils.h"
 #include "gtk-utils.h"
@@ -48,6 +49,7 @@ struct _FrNewArchiveDialog {
        gboolean    can_create_volumes;
        GFile      *original_file;
        GList      *files_to_add;
+       GtkWidget  *location_button;
 };
 
 
@@ -211,6 +213,9 @@ _fr_new_archive_dialog_construct (FrNewArchiveDialog *self,
        _g_object_unref (self->original_file);
        self->original_file = _g_object_ref (original_file);
 
+       self->location_button = fr_location_button_new (_("Location"));
+       gtk_box_append (GTK_BOX (GET_WIDGET ("parent_filechooserbutton_container")), self->location_button);
+       gtk_label_set_mnemonic_widget (GTK_LABEL (GET_WIDGET ("location_label")), self->location_button);
        gtk_box_append (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), GET_WIDGET ("content"));
 
        gtk_dialog_add_button (GTK_DIALOG (self), _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL);
@@ -247,7 +252,7 @@ _fr_new_archive_dialog_construct (FrNewArchiveDialog *self,
 
        if (folder == NULL)
                folder = _g_file_get_home ();
-       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (GET_WIDGET ("parent_filechooserbutton")), 
folder, NULL);
+       fr_location_button_set_location (FR_LOCATION_BUTTON (self->location_button), folder);
 
        gtk_expander_set_expanded (GTK_EXPANDER (GET_WIDGET ("other_options_expander")),
                                      g_settings_get_boolean (self->settings, PREF_NEW_EXPAND_OPTIONS));
@@ -419,7 +424,7 @@ fr_new_archive_dialog_get_file (FrNewArchiveDialog  *self,
        /* File */
 
        n_format = get_selected_format (self);
-       parent = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (GET_WIDGET ("parent_filechooserbutton")));
+       parent = fr_location_button_get_location (FR_LOCATION_BUTTON (self->location_button));
        if (parent == NULL) {
                GtkWidget *msg_dialog = _gtk_error_dialog_new (
                        GTK_WINDOW (self),
diff --git a/src/meson.build b/src/meson.build
index ca149be7..5cdb8fb2 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -40,6 +40,7 @@ source_files = files(
   'fr-file-selector-dialog.c',
   'fr-init.c',
   'fr-location-bar.c',
+  'fr-location-button.c',
   'fr-new-archive-dialog.c',
   'fr-process.c',
   'fr-window-actions-callbacks.c',
@@ -83,6 +84,7 @@ fr_headers = files(
   'fr-file-selector-dialog.h',
   'fr-init.h',
   'fr-location-bar.h',
+  'fr-location-button.h',
   'fr-new-archive-dialog.h',
   'fr-process.h',
   'fr-window-actions-callbacks.h',
diff --git a/src/ui/new-archive-dialog.ui b/src/ui/new-archive-dialog.ui
index 91d0ef62..f9380932 100644
--- a/src/ui/new-archive-dialog.ui
+++ b/src/ui/new-archive-dialog.ui
@@ -10,7 +10,7 @@
     <child>
       <object class="GtkBox" id="box1">
         <property name="orientation">vertical</property>
-        <property name="spacing">12</property>
+        <property name="spacing">24</property>
         <child>
           <object class="GtkBox" id="box7">
             <property name="orientation">vertical</property>
@@ -52,12 +52,11 @@
               <object class="GtkLabel" id="location_label">
                 <property name="label" translatable="1">_Location:</property>
                 <property name="use_underline">1</property>
-                <property name="mnemonic_widget">parent_filechooserbutton</property>
                 <property name="halign">start</property>
               </object>
             </child>
             <child>
-              <object class="GtkBox" id="parent_filechooserbutton">
+              <object class="GtkBox" id="parent_filechooserbutton_container">
               </object>
             </child>
           </object>
@@ -73,7 +72,7 @@
           <object class="GtkBox" id="box4">
             <property name="margin_top">6</property>
             <property name="orientation">vertical</property>
-            <property name="spacing">6</property>
+            <property name="spacing">12</property>
             <child>
               <object class="GtkBox" id="box5">
                 <property name="margin_top">12</property>
@@ -97,41 +96,47 @@
               </object>
             </child>
             <child>
-              <object class="GtkCheckButton" id="encrypt_header_checkbutton">
-                <property name="label" translatable="1">_Encrypt the file list too</property>
-                <property name="focusable">1</property>
-                <property name="use_underline">1</property>
-                <property name="halign">start</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkBox" id="volume_box">
+              <object class="GtkBox">
+                <property name="orientation">vertical</property>
                 <property name="spacing">6</property>
                 <child>
-                  <object class="GtkCheckButton" id="volume_checkbutton">
-                    <property name="label" translatable="1" comments="this is part of a sentence, for 
example &quot;split into volumes of 10.0 MB&quot;, where MB stands for megabyte.">Split into _volumes 
of</property>
+                  <object class="GtkCheckButton" id="encrypt_header_checkbutton">
+                    <property name="label" translatable="1">_Encrypt the file list too</property>
                     <property name="focusable">1</property>
                     <property name="use_underline">1</property>
-                    <property name="halign">center</property>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkSpinButton" id="volume_spinbutton">
-                    <property name="halign">center</property>
-                    <property name="focusable">1</property>
-                    <property name="width_chars">4</property>
-                    <property name="text" translatable="1">10,0</property>
-                    <property name="adjustment">volume_adjustment</property>
-                    <property name="climb_rate">1</property>
-                    <property name="digits">1</property>
-                    <property name="numeric">1</property>
-                    <property name="value">10</property>
+                    <property name="halign">start</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="label50">
-                    <property name="halign">center</property>
-                    <property name="label" translatable="1" comments="MB means megabytes">MB</property>
+                  <object class="GtkBox" id="volume_box">
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkCheckButton" id="volume_checkbutton">
+                        <property name="label" translatable="1" comments="this is part of a sentence, for 
example &quot;split into volumes of 10.0 MB&quot;, where MB stands for megabyte.">Split into _volumes 
of</property>
+                        <property name="focusable">1</property>
+                        <property name="use_underline">1</property>
+                        <property name="halign">center</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSpinButton" id="volume_spinbutton">
+                        <property name="halign">center</property>
+                        <property name="focusable">1</property>
+                        <property name="width_chars">4</property>
+                        <property name="text" translatable="1">10,0</property>
+                        <property name="adjustment">volume_adjustment</property>
+                        <property name="climb_rate">1</property>
+                        <property name="digits">1</property>
+                        <property name="numeric">1</property>
+                        <property name="value">10</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label50">
+                        <property name="halign">center</property>
+                        <property name="label" translatable="1" comments="MB means megabytes">MB</property>
+                      </object>
+                    </child>
                   </object>
                 </child>
               </object>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]