[gtk/gbsneto/filechooser-column-view: 54/74] filechooser: Bring back sorting




commit c0c3d75062bd46dc6dd85290edc52488ab0ec3c9
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Oct 11 11:02:07 2022 -0400

    filechooser: Bring back sorting
    
    Add a sort model between the filter model and the
    file system model, and set it up to sort according
    to the circumstances.

 gtk/gtkfilechooserwidget.c | 283 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 251 insertions(+), 32 deletions(-)
---
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 079f404b9f..11c193feb7 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -95,6 +95,8 @@
 #include "gtkstringlist.h"
 #include "gtkfilterlistmodel.h"
 #include "gtkcustomfilter.h"
+#include "gtkcustomsorter.h"
+#include "gtkmultisorter.h"
 
 #ifndef G_OS_WIN32
 #include "gopenuriportal.h"
@@ -200,6 +202,7 @@ struct _GtkFileChooserWidget
    * selection model.
    */
   GtkSelectionModel *selection_model;
+  GtkSortListModel *sort_model;
   GtkFilterListModel *filter_model;
 
   /* The file browsing widgets */
@@ -284,6 +287,7 @@ struct _GtkFileChooserWidget
   GFile *current_folder;
   GFile *renamed_file;
 
+  GtkColumnViewColumn *column_view_name_column;
   GtkColumnViewColumn *column_view_location_column;
   GtkColumnViewColumn *column_view_size_column;
   GtkColumnViewColumn *column_view_time_column;
@@ -600,6 +604,7 @@ gtk_file_chooser_widget_finalize (GObject *object)
   g_clear_object (&impl->model_for_search);
 
   g_clear_object (&impl->selection_model);
+  g_clear_object (&impl->sort_model);
   g_clear_object (&impl->filter_model);
 
   /* stopping the load above should have cleared this */
@@ -621,6 +626,8 @@ get_toplevel (GtkWidget *widget)
     return NULL;
 }
 
+static void setup_sorting (GtkFileChooserWidget *impl);
+
 static GListModel *
 get_current_model (GtkFileChooserWidget *self)
 {
@@ -634,6 +641,7 @@ set_current_model (GtkFileChooserWidget *self,
   gtk_filter_list_model_set_model (self->filter_model, model);
   gtk_filter_changed (gtk_filter_list_model_get_filter (self->filter_model),
                       GTK_FILTER_CHANGE_DIFFERENT);
+  setup_sorting (self);
 }
 
 /* Extracts the parent folders out of the supplied list of GtkRecentInfo* items, and returns
@@ -1555,6 +1563,9 @@ change_sort_directories_first_state (GSimpleAction *action,
 
   g_simple_action_set_state (action, state);
   impl->sort_directories_first = g_variant_get_boolean (state);
+
+  gtk_sorter_changed (gtk_sort_list_model_get_sorter (impl->sort_model),
+                      GTK_SORTER_CHANGE_DIFFERENT);
 }
 
 static void
@@ -2049,7 +2060,8 @@ column_view_get_file_date (GtkListItem *item,
 
   impl = GTK_FILE_CHOOSER_WIDGET (gtk_widget_get_ancestor (gtk_list_item_get_child (item),
                                                            GTK_TYPE_FILE_CHOOSER_WIDGET));
-  g_assert (impl != NULL);
+  if (!impl)
+    return NULL;
 
   if (impl->operation_mode == OPERATION_MODE_RECENT)
     time = (glong) g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
@@ -2084,7 +2096,8 @@ column_view_get_file_time (GtkListItem *item,
 
   impl = GTK_FILE_CHOOSER_WIDGET (gtk_widget_get_ancestor (gtk_list_item_get_child (item),
                                                            GTK_TYPE_FILE_CHOOSER_WIDGET));
-  g_assert (impl != NULL);
+  if (!impl)
+    return NULL;
 
   if (impl->operation_mode == OPERATION_MODE_RECENT)
     time = (glong) g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
@@ -2108,16 +2121,16 @@ column_view_get_file_type (GtkListItem *item,
 
   impl = GTK_FILE_CHOOSER_WIDGET (gtk_widget_get_ancestor (gtk_list_item_get_child (item),
                                                            GTK_TYPE_FILE_CHOOSER_WIDGET));
-  g_assert (impl != NULL);
+  if (!impl)
+    return NULL;
 
   return get_type_information (impl, info);
 }
 
 static char *
-column_view_get_location (GtkListItem *list_item,
-                          GFileInfo   *info)
+file_chooser_get_location (GtkFileChooserWidget *impl,
+                           GFileInfo            *info)
 {
-  GtkFileChooserWidget *impl;
   GFile *home_location;
   GFile *dir_location;
   GFile *file;
@@ -2145,11 +2158,6 @@ column_view_get_location (GtkListItem *list_item,
       dir_location = g_file_get_parent (target);
       g_clear_object (&target);
     }
-
-  impl = GTK_FILE_CHOOSER_WIDGET (gtk_widget_get_ancestor (gtk_list_item_get_child (list_item),
-                                                           GTK_TYPE_FILE_CHOOSER_WIDGET));
-  g_assert (impl != NULL);
-
   if (!dir_location)
     location = g_strdup ("/");
   else if (impl->current_folder && g_file_equal (impl->current_folder, dir_location))
@@ -2174,6 +2182,20 @@ column_view_get_location (GtkListItem *list_item,
   return g_steal_pointer (&location);
 }
 
+static char *
+column_view_get_location (GtkListItem *list_item,
+                          GFileInfo   *info)
+{
+  GtkFileChooserWidget *impl;
+
+  impl = GTK_FILE_CHOOSER_WIDGET (gtk_widget_get_ancestor (gtk_list_item_get_child (list_item),
+                                                           GTK_TYPE_FILE_CHOOSER_WIDGET));
+  if (!impl)
+    return NULL;
+
+  return file_chooser_get_location (impl, info);
+}
+
 static char *
 column_view_get_size (GtkListItem *item,
                       GFileInfo   *info)
@@ -2191,7 +2213,8 @@ column_view_get_time_visible (GtkListItem *item)
 
   impl = GTK_FILE_CHOOSER_WIDGET (gtk_widget_get_ancestor (gtk_list_item_get_child (item),
                                                            GTK_TYPE_FILE_CHOOSER_WIDGET));
-  g_assert (impl != NULL);
+  if (!impl)
+    return FALSE;
 
   return impl->show_time;
 }
@@ -2682,7 +2705,7 @@ set_select_multiple (GtkFileChooserWidget *impl,
   gtk_column_view_set_enable_rubberband (GTK_COLUMN_VIEW (impl->browse_files_column_view),
                                          select_multiple);
 
-  model = g_object_ref (G_LIST_MODEL (impl->filter_model));
+  model = g_object_ref (G_LIST_MODEL (impl->sort_model));
 
   g_clear_object (&impl->selection_model);
 
@@ -2696,11 +2719,6 @@ set_select_multiple (GtkFileChooserWidget *impl,
   g_signal_connect (impl->selection_model, "items-changed",
                     G_CALLBACK (list_items_changed), impl);
 
-  g_signal_connect (impl->selection_model,
-                    "items-changed",
-                    G_CALLBACK (list_items_changed),
-                    impl);
-
   gtk_column_view_set_model (GTK_COLUMN_VIEW (impl->browse_files_column_view),
                              GTK_SELECTION_MODEL (impl->selection_model));
 
@@ -7024,6 +7042,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, browse_new_folder_button);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, browse_path_bar_size_group);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, browse_path_bar);
+  gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_name_column);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_location_column);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_size_column);
   gtk_widget_class_bind_template_child (widget_class, GtkFileChooserWidget, column_view_time_column);
@@ -7217,14 +7236,218 @@ match_func (gpointer item, gpointer user_data)
   return g_file_info_get_attribute_boolean (G_FILE_INFO (item), "filechooser::visible");
 }
 
+static GtkOrdering
+directory_sort_func (gconstpointer a,
+                     gconstpointer b,
+                     gpointer      user_data)
+{
+  GtkFileChooserWidget *impl = user_data;
+
+  if (impl->sort_directories_first)
+    {
+      gboolean adir = _gtk_file_info_consider_as_directory ((GFileInfo *)a);
+      gboolean bdir = _gtk_file_info_consider_as_directory ((GFileInfo *)b);
+
+      if (adir && !bdir)
+        return GTK_ORDERING_SMALLER;
+      if (!adir && bdir)
+        return GTK_ORDERING_LARGER;
+    }
+
+  return GTK_ORDERING_EQUAL;
+}
+
+static GtkOrdering
+name_sort_func (gconstpointer a,
+                gconstpointer b,
+                gpointer      user_data)
+{
+  char *key_a, *key_b;
+  GtkOrdering result;
+
+  /* FIXME: use sortkeys for these */
+  key_a = g_utf8_collate_key_for_filename (g_file_info_get_display_name ((GFileInfo *)a), -1);
+  key_b = g_utf8_collate_key_for_filename (g_file_info_get_display_name ((GFileInfo *)b), -1);
+
+  result = g_strcmp0 (key_a, key_b);
+
+  g_free (key_a);
+  g_free (key_b);
+
+  return result;
+}
+
+static GtkOrdering
+location_sort_func (gconstpointer a,
+                    gconstpointer b,
+                    gpointer      user_data)
+{
+  GtkFileChooserWidget *impl = user_data;
+  char *key_a, *key_b;
+  GtkOrdering result;
+
+  /* FIXME: use sortkeys for these */
+  key_a = g_utf8_collate_key_for_filename (file_chooser_get_location (impl, (GFileInfo *)a), -1);
+  key_b = g_utf8_collate_key_for_filename (file_chooser_get_location (impl, (GFileInfo *)b), -1);
+
+  result = g_strcmp0 (key_a, key_b);
+
+  g_free (key_a);
+  g_free (key_b);
+
+  return result;
+}
+
+static GtkOrdering
+size_sort_func (gconstpointer a,
+                gconstpointer b,
+                gpointer      user_data)
+{
+  gint64 size_a, size_b;
+
+  size_a = g_file_info_get_size ((GFileInfo *)a);
+  size_b = g_file_info_get_size ((GFileInfo *)b);
+
+  if (size_a < size_b)
+    return GTK_ORDERING_SMALLER;
+  else if (size_a > size_b)
+    return GTK_ORDERING_LARGER;
+  else
+    return GTK_ORDERING_EQUAL;
+}
+
+static GtkOrdering
+type_sort_func (gconstpointer a,
+                gconstpointer b,
+                gpointer      user_data)
+{
+  GtkFileChooserWidget *impl = user_data;
+  char *key_a, *key_b;
+  GtkOrdering result;
+
+  /* FIXME: use sortkeys for these */
+  key_a = get_type_information (impl, (GFileInfo *)a);
+  key_b = get_type_information (impl, (GFileInfo *)b);
+
+  result = g_strcmp0 (key_a, key_b);
+
+  g_free (key_a);
+  g_free (key_b);
+
+  return result;
+}
+
+static GtkOrdering
+time_sort_func (gconstpointer a,
+                gconstpointer b,
+                gpointer      user_data)
+{
+  GtkFileChooserWidget *impl = user_data;
+  glong time_a, time_b;
+
+  if (impl->operation_mode == OPERATION_MODE_RECENT)
+    time_a = (glong) g_file_info_get_attribute_uint64 ((GFileInfo *)a, G_FILE_ATTRIBUTE_TIME_ACCESS);
+  else
+    time_b = (glong) g_file_info_get_attribute_uint64 ((GFileInfo *)b, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+  if (time_a < time_b)
+    return GTK_ORDERING_SMALLER;
+  else if (time_a > time_b)
+    return GTK_ORDERING_LARGER;
+  else
+    return GTK_ORDERING_EQUAL;
+}
+
+static GtkOrdering
+recent_sort_func (gconstpointer a,
+                  gconstpointer b,
+                  gpointer      user_data)
+{
+  GtkOrdering result;
+
+  result = time_sort_func (a, b, user_data);
+
+  if (result == GTK_ORDERING_EQUAL)
+    result = name_sort_func (a, b, user_data);
+
+  if (result == GTK_ORDERING_EQUAL)
+    result = location_sort_func (a, b, user_data);
+
+  return result;
+}
+
+static GtkOrdering
+search_sort_func (gconstpointer a,
+                  gconstpointer b,
+                  gpointer      user_data)
+{
+  GtkOrdering result;
+
+  result = location_sort_func (a, b, user_data);
+
+  if (result == GTK_ORDERING_EQUAL)
+    result = name_sort_func (a, b, user_data);
+
+  if (result == GTK_ORDERING_EQUAL)
+    result = time_sort_func (a, b, user_data);
+
+  return result;
+}
+
+static void
+setup_sorting (GtkFileChooserWidget *impl)
+{
+  GtkFileSystemModel *fsmodel;
+  GtkSorter *sorter = NULL;
+
+  fsmodel = GTK_FILE_SYSTEM_MODEL (get_current_model (impl));
+
+  gtk_column_view_column_set_sorter (impl->column_view_name_column, NULL);
+  gtk_column_view_column_set_sorter (impl->column_view_location_column, NULL);
+  gtk_column_view_column_set_sorter (impl->column_view_size_column, NULL);
+  gtk_column_view_column_set_sorter (impl->column_view_type_column, NULL);
+  gtk_column_view_column_set_sorter (impl->column_view_time_column, NULL);
+
+  if (fsmodel == impl->browse_files_model)
+    {
+      gtk_column_view_column_set_sorter (impl->column_view_name_column, GTK_SORTER (gtk_custom_sorter_new 
(name_sort_func, impl, NULL)));
+      gtk_column_view_column_set_sorter (impl->column_view_location_column, GTK_SORTER 
(gtk_custom_sorter_new (location_sort_func, impl, NULL)));
+      gtk_column_view_column_set_sorter (impl->column_view_size_column, GTK_SORTER (gtk_custom_sorter_new 
(size_sort_func, impl, NULL)));
+      gtk_column_view_column_set_sorter (impl->column_view_type_column, GTK_SORTER (gtk_custom_sorter_new 
(type_sort_func, impl, NULL)));
+      gtk_column_view_column_set_sorter (impl->column_view_time_column, GTK_SORTER (gtk_custom_sorter_new 
(time_sort_func, impl, NULL)));
+
+      sorter = GTK_SORTER (gtk_multi_sorter_new ());
+      gtk_multi_sorter_append (GTK_MULTI_SORTER (sorter), GTK_SORTER (gtk_custom_sorter_new 
(directory_sort_func, impl, NULL)));
+      gtk_multi_sorter_append (GTK_MULTI_SORTER (sorter), g_object_ref (gtk_column_view_get_sorter 
(GTK_COLUMN_VIEW (impl->browse_files_column_view))));
+    }
+  else if (fsmodel == impl->recent_model)
+    {
+      sorter = GTK_SORTER (gtk_custom_sorter_new (recent_sort_func, impl, NULL));
+    }
+  else if (fsmodel == impl->search_model)
+    {
+      sorter = GTK_SORTER (gtk_custom_sorter_new (search_sort_func, impl, NULL));
+    }
+
+  gtk_sort_list_model_set_sorter (impl->sort_model, sorter);
+  g_clear_object (&sorter);
+}
+
 static void
 gtk_file_chooser_widget_init (GtkFileChooserWidget *impl)
 {
   GtkExpression *expression;
 
-  impl->selection_model = GTK_SELECTION_MODEL (gtk_single_selection_new (NULL));
-  impl->filter_model = gtk_filter_list_model_new (NULL, GTK_FILTER (gtk_custom_filter_new (match_func, NULL, 
NULL)));
+  /* Ensure private types used by the template
+   * definition before calling gtk_widget_init_template()
+   */
+  g_type_ensure (GTK_TYPE_PATH_BAR);
+  g_type_ensure (GTK_TYPE_PLACES_VIEW);
+  g_type_ensure (GTK_TYPE_PLACES_SIDEBAR);
+  g_type_ensure (GTK_TYPE_FILE_CHOOSER_ERROR_STACK);
+
   impl->select_multiple = FALSE;
+  impl->sort_directories_first = FALSE;
   impl->show_hidden = FALSE;
   impl->show_size_column = TRUE;
   impl->show_type_column = TRUE;
@@ -7239,25 +7462,21 @@ gtk_file_chooser_widget_init (GtkFileChooserWidget *impl)
   impl->auto_selecting_first_row = FALSE;
   impl->renamed_file = NULL;
 
-  gtk_single_selection_set_model (GTK_SINGLE_SELECTION (impl->selection_model), G_LIST_MODEL 
(impl->filter_model));
+  gtk_widget_init_template (GTK_WIDGET (impl));
+
+  impl->selection_model = GTK_SELECTION_MODEL (gtk_single_selection_new (NULL));
+  impl->filter_model = gtk_filter_list_model_new (NULL, GTK_FILTER (gtk_custom_filter_new (match_func, NULL, 
NULL)));
+  impl->sort_model = gtk_sort_list_model_new (NULL, NULL);
 
   g_signal_connect (impl->selection_model, "selection-changed",
                     G_CALLBACK (list_selection_changed), impl);
   g_signal_connect (impl->selection_model, "items-changed",
                     G_CALLBACK (list_items_changed), impl);
 
-  /* Ensure private types used by the template
-   * definition before calling gtk_widget_init_template()
-   */
-  g_type_ensure (GTK_TYPE_PATH_BAR);
-  g_type_ensure (GTK_TYPE_PLACES_VIEW);
-  g_type_ensure (GTK_TYPE_PLACES_SIDEBAR);
-  g_type_ensure (GTK_TYPE_FILE_CHOOSER_ERROR_STACK);
-
-  gtk_widget_init_template (GTK_WIDGET (impl));
+  gtk_single_selection_set_model (GTK_SINGLE_SELECTION (impl->selection_model), G_LIST_MODEL 
(impl->sort_model));
+  gtk_sort_list_model_set_model (impl->sort_model, G_LIST_MODEL (impl->filter_model));
 
-  gtk_column_view_set_model (GTK_COLUMN_VIEW (impl->browse_files_column_view),
-                             impl->selection_model);
+  gtk_column_view_set_model (GTK_COLUMN_VIEW (impl->browse_files_column_view), impl->selection_model);
 
   g_signal_connect (impl, "notify::display,", G_CALLBACK (display_changed_cb), impl);
   check_icon_theme (impl);


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