[gtk/gbsneto/filechooser-column-view: 98/161] filechooserwidget: Move file icon to column view




commit b4c14c38c79dd031ca99d9f0f3e9a6869da78116
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Oct 8 08:15:09 2022 -0300

    filechooserwidget: Move file icon to column view
    
    This commit moves the icon loading code into a new private
    widget called GtkFileThumbnail, which is bound to the GFileInfo
    of the model, and asynchronously loads the file icon from that.

 gtk/gtkfilechooserwidget.c     | 145 +----------------------
 gtk/gtkfilethumbnail.c         | 261 +++++++++++++++++++++++++++++++++++++++++
 gtk/gtkfilethumbnail.h         |  46 ++++++++
 gtk/meson.build                |   1 +
 gtk/ui/gtkfilechooserwidget.ui |  14 ++-
 5 files changed, 320 insertions(+), 147 deletions(-)
---
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 7714f2b7b9..711354a675 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -38,6 +38,7 @@
 #include "gtkfilechooserutils.h"
 #include "gtkfilechooser.h"
 #include "gtkfilesystemmodel.h"
+#include "gtkfilethumbnail.h"
 #include "gtkgrid.h"
 #include "gtkicontheme.h"
 #include "gtklabel.h"
@@ -275,7 +276,6 @@ struct _GtkFileChooserWidget
   GFile *renamed_file;
 
   GtkTreeViewColumn *list_name_column;
-  GtkCellRenderer *list_pixbuf_renderer;
   GtkTreeViewColumn *list_time_column;
   GtkCellRenderer *list_date_renderer;
   GtkCellRenderer *list_time_renderer;
@@ -363,7 +363,6 @@ enum {
   MODEL_COL_NAME_COLLATED,
   MODEL_COL_IS_FOLDER,
   MODEL_COL_IS_SENSITIVE,
-  MODEL_COL_ICON,
   MODEL_COL_SIZE_TEXT,
   MODEL_COL_DATE_TEXT,
   MODEL_COL_TIME_TEXT,
@@ -383,7 +382,6 @@ enum {
         G_TYPE_STRING,            /* MODEL_COL_NAME_COLLATED */ \
         G_TYPE_BOOLEAN,           /* MODEL_COL_IS_FOLDER */     \
         G_TYPE_BOOLEAN,           /* MODEL_COL_IS_SENSITIVE */  \
-        G_TYPE_ICON,              /* MODEL_COL_ICON */          \
         G_TYPE_STRING,            /* MODEL_COL_SIZE_TEXT */     \
         G_TYPE_STRING,            /* MODEL_COL_DATE_TEXT */     \
         G_TYPE_STRING,            /* MODEL_COL_TIME_TEXT */     \
@@ -2207,17 +2205,6 @@ file_list_query_tooltip_cb (GtkWidget  *widget,
   return TRUE;
 }
 
-static void
-set_icon_cell_renderer_fixed_size (GtkFileChooserWidget *impl)
-{
-  int xpad, ypad;
-
-  gtk_cell_renderer_get_padding (impl->list_pixbuf_renderer, &xpad, &ypad);
-  gtk_cell_renderer_set_fixed_size (impl->list_pixbuf_renderer,
-                                    xpad * 2 + ICON_SIZE,
-                                    ypad * 2 + ICON_SIZE);
-}
-
 static GtkWidget *
 get_accept_action_widget (GtkDialog *dialog,
                           gboolean   sensitive_only)
@@ -3274,10 +3261,6 @@ gtk_file_chooser_widget_unroot (GtkWidget *widget)
 static void
 change_icon_theme (GtkFileChooserWidget *impl)
 {
-  /* the first cell in the first column is the icon column, and we have a fixed size there */
-  set_icon_cell_renderer_fixed_size (impl);
-
-  clear_model_cache (impl, MODEL_COL_ICON);
   gtk_widget_queue_resize (impl->browse_files_tree_view);
 }
 
@@ -4346,53 +4329,6 @@ my_g_format_time_for_display (GtkFileChooserWidget *impl,
   return date_str;
 }
 
-static void
-copy_attribute (GFileInfo   *to,
-                GFileInfo   *from,
-                const char *attribute)
-{
-  GFileAttributeType type;
-  gpointer value;
-
-  if (g_file_info_get_attribute_data (from, attribute, &type, &value, NULL))
-    g_file_info_set_attribute (to, attribute, type, value);
-}
-
-static void
-file_system_model_got_thumbnail (GObject      *object,
-                                 GAsyncResult *res,
-                                 gpointer      data)
-{
-  GtkFileSystemModel *model = data; /* might be unreffed if operation was cancelled */
-  GFile *file = G_FILE (object);
-  GFileInfo *queried, *info;
-  GtkTreeIter iter;
-
-  queried = g_file_query_info_finish (file, res, NULL);
-  if (queried == NULL)
-    return;
-
-  /* now we know model is valid */
-
-  /* file was deleted */
-  if (!_gtk_file_system_model_get_iter_for_file (model, &iter, file))
-    {
-      g_object_unref (queried);
-      return;
-    }
-
-  info = g_file_info_dup (_gtk_file_system_model_get_info (model, &iter));
-
-  copy_attribute (info, queried, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
-  copy_attribute (info, queried, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
-  copy_attribute (info, queried, G_FILE_ATTRIBUTE_STANDARD_ICON);
-
-  _gtk_file_system_model_update_file (model, file, info);
-
-  g_object_unref (info);
-  g_object_unref (queried);
-}
-
 /* Copied from src/nautilus_file.c:get_description() */
 struct {
   const char *icon_name;
@@ -4542,71 +4478,6 @@ file_system_model_set (GtkFileSystemModel *model,
       else
         g_value_set_boolean (value, TRUE);
       break;
-    case MODEL_COL_ICON:
-      if (info)
-        {
-          if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_ICON))
-            {
-              int scale;
-              GtkIconTheme *icon_theme;
-
-              scale = gtk_widget_get_scale_factor (GTK_WIDGET (impl));
-              icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (impl)));
-
-              g_value_take_object (value, _gtk_file_info_get_icon (info, ICON_SIZE, scale, icon_theme));
-            }
-          else
-            {
-              GtkTreeModel *tree_model;
-              GtkTreePath *start, *end;
-              GtkTreeIter iter;
-              gboolean visible;
-
-              if (impl->browse_files_tree_view == NULL ||
-                  g_file_info_has_attribute (info, "filechooser::queried"))
-                return FALSE;
-
-              tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
-              if (tree_model != GTK_TREE_MODEL (model))
-                return FALSE;
-
-              if (!_gtk_file_system_model_get_iter_for_file (model, &iter, file))
-                g_assert_not_reached ();
-
-              if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (impl->browse_files_tree_view), &start, 
&end))
-                {
-                  GtkTreePath *path;
-
-                  gtk_tree_path_prev (start);
-                  gtk_tree_path_next (end);
-                  path = gtk_tree_model_get_path (tree_model, &iter);
-                  visible = gtk_tree_path_compare (start, path) != 1 &&
-                            gtk_tree_path_compare (path, end) != 1;
-                  gtk_tree_path_free (path);
-                  gtk_tree_path_free (start);
-                  gtk_tree_path_free (end);
-                }
-              else
-                visible = TRUE;
-              if (visible)
-                {
-                  g_file_info_set_attribute_boolean (info, "filechooser::queried", TRUE);
-                  g_file_query_info_async (file,
-                                           G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
-                                           G_FILE_ATTRIBUTE_THUMBNAILING_FAILED ","
-                                           G_FILE_ATTRIBUTE_STANDARD_ICON,
-                                           G_FILE_QUERY_INFO_NONE,
-                                           G_PRIORITY_DEFAULT,
-                                           _gtk_file_system_model_get_cancellable (model),
-                                           file_system_model_got_thumbnail,
-                                           model);
-                }
-              return FALSE;
-            }
-        }
-      else
-        g_value_set_boxed (value, NULL);
-      break;
     case MODEL_COL_SIZE:
       g_value_set_int64 (value, info ? g_file_info_get_size (info) : 0);
       break;
@@ -7140,12 +7011,6 @@ path_bar_clicked (GtkPathBar           *path_bar,
 static void
 update_cell_renderer_attributes (GtkFileChooserWidget *impl)
 {
-  gtk_tree_view_column_set_attributes (impl->list_name_column,
-                                       impl->list_pixbuf_renderer,
-                                       "gicon", MODEL_COL_ICON,
-                                       "sensitive", MODEL_COL_IS_SENSITIVE,
-                                       NULL);
-
   gtk_tree_view_column_set_attributes (impl->list_size_column,
                                        impl->list_size_renderer,
                                        "text", MODEL_COL_SIZE_TEXT,
@@ -7368,6 +7233,8 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
   widget_class->grab_focus = gtk_widget_grab_focus_child;
   widget_class->focus = gtk_widget_focus_child;
 
+  g_type_ensure (GTK_TYPE_FILE_THUMBNAIL);
+
   /*
    * Signals
    */
@@ -7766,7 +7633,6 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, search_entry);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, search_spinner);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, list_name_column);
-  gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, list_pixbuf_renderer);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, list_time_column);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, list_date_renderer);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, list_time_renderer);
@@ -7888,11 +7754,6 @@ post_process_ui (GtkFileChooserWidget *impl)
   _gtk_path_bar_set_file (GTK_PATH_BAR (impl->browse_path_bar), file, FALSE);
   g_object_unref (file);
 
-  /* Set the fixed size icon renderer, this requires
-   * that impl->icon_size be already setup.
-   */
-  set_icon_cell_renderer_fixed_size (impl);
-
   gtk_popover_set_default_widget (GTK_POPOVER (impl->new_folder_popover), impl->new_folder_create_button);
   gtk_popover_set_default_widget (GTK_POPOVER (impl->rename_file_popover), impl->rename_file_rename_button);
 
diff --git a/gtk/gtkfilethumbnail.c b/gtk/gtkfilethumbnail.c
new file mode 100644
index 0000000000..633b6be912
--- /dev/null
+++ b/gtk/gtkfilethumbnail.c
@@ -0,0 +1,261 @@
+/* gtkfilethumbnail.c
+ *
+ * Copyright 2022 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include "gtkfilethumbnail.h"
+
+#include "gtkbinlayout.h"
+#include "gtkfilechooserutils.h"
+#include "gtkimage.h"
+#include "gtkprivate.h"
+#include "gtkwidget.h"
+
+#define ICON_SIZE 16
+
+struct _GtkFileThumbnail
+{
+  GtkWidget parent;
+
+  GtkWidget *image;
+
+  GtkFileSystemItem *item;
+  GCancellable *cancellable;
+};
+
+typedef struct
+{
+  GtkWidgetClass parent;
+} GtkFileThumbnailClass;
+
+G_DEFINE_FINAL_TYPE (GtkFileThumbnail, _gtk_file_thumbnail, GTK_TYPE_WIDGET)
+
+enum {
+  PROP_0,
+  PROP_ITEM,
+  N_PROPS,
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+copy_attribute (GFileInfo  *to,
+                GFileInfo  *from,
+                const char *attribute)
+{
+  GFileAttributeType type;
+  gpointer value;
+
+  if (g_file_info_get_attribute_data (from, attribute, &type, &value, NULL))
+    g_file_info_set_attribute (to, attribute, type, value);
+}
+
+static gboolean
+update_image (GtkFileThumbnail *self)
+{
+  GtkIconTheme *icon_theme;
+  GFileInfo *info;
+  GIcon *icon;
+  int scale;
+
+  info = _gtk_file_system_item_get_file_info (self->item);
+  if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_ICON))
+    return FALSE;
+
+  scale = gtk_widget_get_scale_factor (GTK_WIDGET (self));
+  icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (self)));
+
+  icon = _gtk_file_info_get_icon (info, ICON_SIZE, scale, icon_theme);
+
+  gtk_image_set_from_gicon (GTK_IMAGE (self->image), icon);
+
+  g_object_unref (icon);
+
+  return TRUE;
+
+}
+
+static void
+thumbnail_queried_cb (GObject      *object,
+                      GAsyncResult *result,
+                      gpointer      user_data)
+{
+  GtkFileThumbnail *self = user_data; /* might be unreffed if operation was cancelled */
+  GFile *file = G_FILE (object);
+  GFileInfo *queried;
+  GFileInfo *info;
+
+  queried = g_file_query_info_finish (file, result, NULL);
+  if (queried == NULL)
+    return;
+
+  info = _gtk_file_system_item_get_file_info (self->item);
+  copy_attribute (info, queried, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
+  copy_attribute (info, queried, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
+  copy_attribute (info, queried, G_FILE_ATTRIBUTE_STANDARD_ICON);
+
+  update_image (self);
+
+  g_clear_object (&queried);
+
+  g_clear_object (&self->cancellable);
+}
+
+static void
+cancel_thumbnail (GtkFileThumbnail *self)
+{
+  g_cancellable_cancel (self->cancellable);
+  g_clear_object (&self->cancellable);
+}
+
+static void
+get_thumbnail (GtkFileThumbnail *self)
+{
+  if (!self->item)
+    return;
+
+  if (!update_image (self))
+    {
+      GFileInfo *info;
+      GFile *file;
+
+      info = _gtk_file_system_item_get_file_info (self->item);
+      if (g_file_info_has_attribute (info, "filechooser::queried"))
+        return;
+
+      g_assert (self->cancellable == NULL);
+      self->cancellable = g_cancellable_new ();
+
+      file = _gtk_file_system_item_get_file (self->item);
+      g_file_info_set_attribute_boolean (info, "filechooser::queried", TRUE);
+      g_file_query_info_async (file,
+                               G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
+                               G_FILE_ATTRIBUTE_THUMBNAILING_FAILED ","
+                               G_FILE_ATTRIBUTE_STANDARD_ICON,
+                               G_FILE_QUERY_INFO_NONE,
+                               G_PRIORITY_DEFAULT,
+                               self->cancellable,
+                               thumbnail_queried_cb,
+                               self);
+    }
+}
+
+static void
+_gtk_file_thumbnail_dispose (GObject *object)
+{
+  GtkFileThumbnail *self = (GtkFileThumbnail *)object;
+
+  _gtk_file_thumbnail_set_item (self, NULL);
+
+  g_clear_pointer (&self->image, gtk_widget_unparent);
+
+  G_OBJECT_CLASS (_gtk_file_thumbnail_parent_class)->dispose (object);
+}
+
+static void
+_gtk_file_thumbnail_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  GtkFileThumbnail *self = GTK_FILE_THUMBNAIL (object);
+
+  switch (prop_id)
+    {
+    case PROP_ITEM:
+      g_value_set_object (value, self->item);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+_gtk_file_thumbnail_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  GtkFileThumbnail *self = GTK_FILE_THUMBNAIL (object);
+
+  switch (prop_id)
+    {
+    case PROP_ITEM:
+      _gtk_file_thumbnail_set_item (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+_gtk_file_thumbnail_class_init (GtkFileThumbnailClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = _gtk_file_thumbnail_dispose;
+  object_class->get_property = _gtk_file_thumbnail_get_property;
+  object_class->set_property = _gtk_file_thumbnail_set_property;
+
+  properties[PROP_ITEM] =
+    g_param_spec_object ("item", NULL, NULL,
+                         GTK_TYPE_FILE_SYSTEM_ITEM,
+                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_set_css_name (widget_class, I_("filethumbnail"));
+
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+}
+
+static void
+_gtk_file_thumbnail_init (GtkFileThumbnail *self)
+{
+  self->image = gtk_image_new ();
+  gtk_widget_set_parent (self->image, GTK_WIDGET (self));
+}
+
+GtkFileSystemItem *
+_gtk_file_thumbnail_get_item (GtkFileThumbnail *self)
+{
+  g_assert (GTK_IS_FILE_THUMBNAIL (self));
+
+  return self->item;
+}
+
+void
+_gtk_file_thumbnail_set_item (GtkFileThumbnail  *self,
+                              GtkFileSystemItem *item)
+{
+  g_assert (GTK_IS_FILE_THUMBNAIL (self));
+  g_assert (item == NULL || GTK_IS_FILE_SYSTEM_ITEM (item));
+
+  if (g_set_object (&self->item, item))
+    {
+      cancel_thumbnail (self);
+      get_thumbnail (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
+    }
+}
+
diff --git a/gtk/gtkfilethumbnail.h b/gtk/gtkfilethumbnail.h
new file mode 100644
index 0000000000..12ffadefb0
--- /dev/null
+++ b/gtk/gtkfilethumbnail.h
@@ -0,0 +1,46 @@
+/* gtkfilethumbnail.h
+ *
+ * Copyright 2022 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+
+#ifndef __GTK_FILE_THUMBNAIL_H__
+#define __GTK_FILE_THUMBNAIL_H__
+
+#include <gio/gio.h>
+
+#include "gtkfilesystemmodel.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_FILE_THUMBNAIL    (_gtk_file_thumbnail_get_type ())
+#define GTK_FILE_THUMBNAIL(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_THUMBNAIL, 
GtkFileThumbnail))
+#define GTK_IS_FILE_THUMBNAIL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_THUMBNAIL))
+
+typedef struct _GtkFileThumbnail      GtkFileThumbnail;
+
+GType _gtk_file_thumbnail_get_type (void) G_GNUC_CONST;
+
+GtkFileSystemItem *_gtk_file_thumbnail_get_item (GtkFileThumbnail *self);
+void _gtk_file_thumbnail_set_item (GtkFileThumbnail  *self,
+                                   GtkFileSystemItem *item);
+
+G_END_DECLS
+
+#endif /* __GTK_FILE_THUMBNAIL_H__ */
+
diff --git a/gtk/meson.build b/gtk/meson.build
index 5ce0ae81e3..db856250e4 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -109,6 +109,7 @@ gtk_private_sources = files([
   'gtkfilechoosernativeportal.c',
   'gtkfilechooserutils.c',
   'gtkfilesystemmodel.c',
+  'gtkfilethumbnail.c',
   'gtkgizmo.c',
   'gtkiconcache.c',
   'gtkiconcachevalidator.c',
diff --git a/gtk/ui/gtkfilechooserwidget.ui b/gtk/ui/gtkfilechooserwidget.ui
index 4e0090f9f7..09fb17af36 100644
--- a/gtk/ui/gtkfilechooserwidget.ui
+++ b/gtk/ui/gtkfilechooserwidget.ui
@@ -155,6 +155,15 @@
   <template class="GtkListItem">
     <property name="child">
       <object class="GtkBox">
+        <child>
+          <object class="GtkFileThumbnail">
+            <property name="margin-start">6</property>
+            <property name="margin-end">6</property>
+            <binding name="item">
+              <lookup name="item">GtkListItem</lookup>
+            </binding>
+          </object>
+        </child>
         <child>
           <object class="GtkInscription">
             <property name="hexpand">1</property>
@@ -234,11 +243,6 @@
                                                 <property name="title" translatable="yes">Name</property>
                                                 <property name="resizable">1</property>
                                                 <property name="expand">1</property>
-                                                <child>
-                                                  <object class="GtkCellRendererPixbuf" 
id="list_pixbuf_renderer">
-                                                    <property name="xpad">6</property>
-                                                  </object>
-                                                </child>
                                               </object>
                                             </child>
                                             <child>


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