[nautilus/wip/antoniof/new-list-view-without-expanders: 15/27] view-icon-controller: Abstract sharable code
- From: António Fernandes <antoniof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/antoniof/new-list-view-without-expanders: 15/27] view-icon-controller: Abstract sharable code
- Date: Tue, 21 Jun 2022 18:55:19 +0000 (UTC)
commit b28e2d545dca3177cf91b3c2bc1855abace719f0
Author: António Fernandes <antoniof gnome org>
Date: Mon Jun 6 11:31:12 2022 +0100
view-icon-controller: Abstract sharable code
The new list view is going to be GtkColumnView-based, so it's going to
share some code with the GtkGridView-based view.
In order to avoid code duplication and still keep the NautilusFilesView
class agnostic of the widgets used by final classes, create an abstract
NautilusListBase class.
But this abstract class needs to interact with the item widgets, which
are going to be different between views. To resolve this, an abstract
NautilusViewCell class is created for the item widgets, which is also
going to be used for the new list view column cells.
Also, bump GLib version requirement now that we use GSignalGroup.
meson.build | 2 +-
src/meson.build | 4 +
src/nautilus-list-base-private.h | 33 +
src/nautilus-list-base.c | 1321 ++++++++++++++++++++++++
src/nautilus-list-base.h | 27 +
src/nautilus-types.h | 3 +-
src/nautilus-view-cell.c | 189 ++++
src/nautilus-view-cell.h | 31 +
src/nautilus-view-icon-controller.c | 1271 ++---------------------
src/nautilus-view-icon-controller.h | 5 +-
src/nautilus-view-icon-item-ui.c | 197 +---
src/nautilus-view-icon-item-ui.h | 10 +-
src/nautilus-view-model.c | 8 +-
src/nautilus-view-model.h | 1 +
src/resources/ui/nautilus-view-icon-item-ui.ui | 2 +-
15 files changed, 1727 insertions(+), 1377 deletions(-)
---
diff --git a/meson.build b/meson.build
index 154c7b763..7af5a3ef0 100644
--- a/meson.build
+++ b/meson.build
@@ -92,7 +92,7 @@ pkgconfig = import('pkgconfig')
################
# Dependencies #
################
-glib_ver = '>= 2.67.1'
+glib_ver = '>= 2.72.0'
libm = cc.find_library('m')
diff --git a/src/meson.build b/src/meson.build
index 35a0dce98..3525c2f7c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -83,6 +83,8 @@ libnautilus_sources = [
'nautilus-floating-bar.h',
'nautilus-freedesktop-dbus.c',
'nautilus-freedesktop-dbus.h',
+ 'nautilus-list-base.c',
+ 'nautilus-list-base.h',
'nautilus-list-model.c',
'nautilus-list-model.h',
'nautilus-list-view.c',
@@ -122,6 +124,8 @@ libnautilus_sources = [
'nautilus-trash-bar.h',
'nautilus-view.c',
'nautilus-view.h',
+ 'nautilus-view-cell.c',
+ 'nautilus-view-cell.h',
'nautilus-view-icon-controller.c',
'nautilus-view-icon-controller.h',
'nautilus-view-icon-item-ui.c',
diff --git a/src/nautilus-list-base-private.h b/src/nautilus-list-base-private.h
new file mode 100644
index 000000000..96944d52e
--- /dev/null
+++ b/src/nautilus-list-base-private.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "nautilus-list-base.h"
+#include "nautilus-view-model.h"
+#include "nautilus-view-cell.h"
+
+/*
+ * Private header to be included only by subclasses.
+ */
+
+G_BEGIN_DECLS
+
+/* Methods */
+NautilusViewModel *nautilus_list_base_get_model (NautilusListBase *self);
+void nautilus_list_base_set_icon_size (NautilusListBase *self,
+ gint icon_size);
+void nautilus_list_base_setup_gestures (NautilusListBase *self);
+
+/* Shareable helpers */
+void set_directory_sort_metadata (NautilusFile *file,
+ const gchar *metadata_name,
+ gboolean reversed);
+const NautilusFileSortType get_sorts_type_from_metadata_text (const char *metadata_name);
+void setup_cell_common (GtkListItem *listitem,
+ NautilusViewCell *cell);
+
+G_END_DECLS
diff --git a/src/nautilus-list-base.c b/src/nautilus-list-base.c
new file mode 100644
index 000000000..4d35df869
--- /dev/null
+++ b/src/nautilus-list-base.c
@@ -0,0 +1,1321 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "nautilus-list-base-private.h"
+
+#include "nautilus-clipboard.h"
+#include "nautilus-view-cell.h"
+#include "nautilus-view-item-model.h"
+#include "nautilus-view-model.h"
+#include "nautilus-files-view.h"
+#include "nautilus-file.h"
+#include "nautilus-metadata.h"
+#include "nautilus-global-preferences.h"
+#include "nautilus-thumbnails.h"
+
+/**
+ * NautilusListBase:
+ *
+ * Abstract class containing shared code for #NautilusFilesView implementations
+ * using a #GtkListBase-derived widget (e.g. GtkGridView, GtkColumnView) which
+ * takes a #NautilusViewModel instance as its model and and a #NautilusViewCell
+ * instance as #GtkListItem:child.
+ *
+ * It has been has been created to avoid code duplication in implementations,
+ * while keeping #NautilusFilesView implementation-agnostic (should the need for
+ * non-#GtkListBase views arise).
+ */
+
+typedef struct _NautilusListBasePrivate NautilusListBasePrivate;
+struct _NautilusListBasePrivate
+{
+ NautilusViewModel *model;
+
+ GList *cut_files;
+
+ guint scroll_to_file_handle_id;
+ guint prioritize_thumbnailing_handle_id;
+ GtkAdjustment *vadjustment;
+
+ gboolean single_click_mode;
+ gboolean activate_on_release;
+ gboolean deny_background_click;
+};
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (NautilusListBase, nautilus_list_base, NAUTILUS_TYPE_FILES_VIEW)
+
+typedef struct
+{
+ const NautilusFileSortType sort_type;
+ const gchar *metadata_name;
+} SortConstants;
+
+static const SortConstants sorts_constants[] =
+{
+ {
+ NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
+ "name",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_SIZE,
+ "size",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_TYPE,
+ "type",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_MTIME,
+ "modification date",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_ATIME,
+ "access date",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_BTIME,
+ "creation date",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
+ "trashed",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
+ "search_relevance",
+ },
+ {
+ NAUTILUS_FILE_SORT_BY_RECENCY,
+ "recency",
+ },
+};
+
+static inline NautilusViewItemModel *
+get_view_item (GListModel *model,
+ guint position)
+{
+ return NAUTILUS_VIEW_ITEM_MODEL (g_list_model_get_item (model, position));
+}
+
+static const SortConstants *
+get_sorts_constants_from_sort_type (NautilusFileSortType sort_type)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (sorts_constants); i++)
+ {
+ if (sort_type == sorts_constants[i].sort_type)
+ {
+ return &sorts_constants[i];
+ }
+ }
+
+ return &sorts_constants[0];
+}
+
+static const SortConstants *
+get_sorts_constants_from_metadata_text (const char *metadata_name)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (sorts_constants); i++)
+ {
+ if (g_strcmp0 (sorts_constants[i].metadata_name, metadata_name) == 0)
+ {
+ return &sorts_constants[i];
+ }
+ }
+
+ return &sorts_constants[0];
+}
+
+const NautilusFileSortType
+get_sorts_type_from_metadata_text (const char *metadata_name)
+{
+ return get_sorts_constants_from_metadata_text (metadata_name)->sort_type;
+}
+
+static const SortConstants *
+get_default_sort_order (NautilusFile *file,
+ gboolean *reversed)
+{
+ NautilusFileSortType sort_type;
+
+ sort_type = nautilus_file_get_default_sort_type (file, reversed);
+
+ return get_sorts_constants_from_sort_type (sort_type);
+}
+
+static const SortConstants *
+get_directory_sort_by (NautilusFile *file,
+ gboolean *reversed)
+{
+ const SortConstants *default_sort;
+ g_autofree char *sort_by = NULL;
+
+ default_sort = get_default_sort_order (file, reversed);
+ g_return_val_if_fail (default_sort != NULL, NULL);
+
+ sort_by = nautilus_file_get_metadata (file,
+ NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
+ default_sort->metadata_name);
+
+ *reversed = nautilus_file_get_boolean_metadata (file,
+ NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
+ *reversed);
+
+ return get_sorts_constants_from_metadata_text (sort_by);
+}
+
+void
+set_directory_sort_metadata (NautilusFile *file,
+ const gchar *metadata_name,
+ gboolean reversed)
+{
+ const SortConstants *default_sort;
+ gboolean default_reversed;
+
+ default_sort = get_default_sort_order (file, &default_reversed);
+
+ nautilus_file_set_metadata (file,
+ NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
+ default_sort->metadata_name,
+ metadata_name);
+ nautilus_file_set_boolean_metadata (file,
+ NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
+ default_reversed,
+ reversed);
+}
+
+static void
+update_sort_order_from_metadata_and_preferences (NautilusListBase *self)
+{
+ const SortConstants *default_directory_sort;
+ GActionGroup *view_action_group;
+ gboolean reversed;
+
+ default_directory_sort = get_directory_sort_by (nautilus_files_view_get_directory_as_file
(NAUTILUS_FILES_VIEW (self)),
+ &reversed);
+ view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self));
+ g_action_group_change_action_state (view_action_group,
+ "sort",
+ g_variant_new ("(sb)",
+ default_directory_sort->metadata_name,
+ reversed));
+}
+
+void
+nautilus_list_base_set_icon_size (NautilusListBase *self,
+ gint icon_size)
+{
+ GListModel *model;
+ guint n_items;
+
+ model = G_LIST_MODEL (nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self)));
+
+ n_items = g_list_model_get_n_items (model);
+ for (guint i = 0; i < n_items; i++)
+ {
+ g_autoptr (NautilusViewItemModel) current_item_model = NULL;
+
+ current_item_model = get_view_item (model, i);
+ nautilus_view_item_model_set_icon_size (current_item_model, icon_size);
+ }
+}
+
+/* GtkListBase changes selection only with the primary button, and only after
+ * release. But we need to antecipate selection earlier if we are to activate it
+ * or open its context menu. This helper should be used in these situations if
+ * it's desirable to act on a multi-item selection, because it preserves it. */
+static void
+select_single_item_if_not_selected (NautilusListBase *self,
+ NautilusViewItemModel *item)
+{
+ NautilusViewModel *model;
+ guint position;
+
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
+ position = nautilus_view_model_get_index (model, item);
+ if (!gtk_selection_model_is_selected (GTK_SELECTION_MODEL (model), position))
+ {
+ gtk_selection_model_select_item (GTK_SELECTION_MODEL (model), position, TRUE);
+ }
+}
+
+static void
+activate_selection_on_click (NautilusListBase *self,
+ gboolean open_in_new_tab)
+{
+ g_autolist (NautilusFile) selection = NULL;
+ NautilusOpenFlags flags = 0;
+ NautilusFilesView *files_view = NAUTILUS_FILES_VIEW (self);
+
+ selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
+ if (open_in_new_tab)
+ {
+ flags |= NAUTILUS_OPEN_FLAG_NEW_TAB;
+ flags |= NAUTILUS_OPEN_FLAG_DONT_MAKE_ACTIVE;
+ }
+ nautilus_files_view_activate_files (files_view, selection, flags, TRUE);
+}
+
+static void
+on_item_click_pressed (GtkGestureClick *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
+ NautilusViewCell *cell = user_data;
+ NautilusListBase *self = NAUTILUS_LIST_BASE (nautilus_view_cell_get_view (cell));
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ NautilusViewItemModel *item;
+ guint button;
+ GdkModifierType modifiers;
+ gboolean selection_mode;
+
+ item = nautilus_view_cell_get_item (cell);
+ g_return_if_fail (item != NULL);
+ button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+ modifiers = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (gesture));
+ selection_mode = (modifiers & (GDK_CONTROL_MASK | GDK_SHIFT_MASK));
+
+ /* Before anything else, store event state to be read by other handlers. */
+ priv->deny_background_click = TRUE;
+ priv->activate_on_release = (priv->single_click_mode &&
+ button == GDK_BUTTON_PRIMARY &&
+ n_press == 1 &&
+ !selection_mode);
+
+ /* It's safe to claim event sequence on press in the following cases because
+ * they don't interfere with touch scrolling. */
+ if (button == GDK_BUTTON_PRIMARY && n_press == 2 && !priv->single_click_mode)
+ {
+ activate_selection_on_click (self, modifiers & GDK_SHIFT_MASK);
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+ }
+ else if (button == GDK_BUTTON_MIDDLE && n_press == 1)
+ {
+ /* Antecipate selection, if necessary, to activate it. */
+ select_single_item_if_not_selected (self, item);
+ activate_selection_on_click (self, TRUE);
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+ }
+ else if (button == GDK_BUTTON_SECONDARY && n_press == 1)
+ {
+ gdouble view_x, view_y;
+
+ /* Antecipate selection, if necessary, for the context menu. */
+ select_single_item_if_not_selected (self, item);
+
+ gtk_widget_translate_coordinates (GTK_WIDGET (cell), GTK_WIDGET (self),
+ x, y,
+ &view_x, &view_y);
+ nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (self),
+ view_x, view_y);
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+ }
+}
+
+static void
+on_item_click_released (GtkGestureClick *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
+ NautilusViewCell *cell = user_data;
+ NautilusListBase *self = NAUTILUS_LIST_BASE (nautilus_view_cell_get_view (cell));
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ if (priv->activate_on_release)
+ {
+ NautilusViewModel *model;
+ NautilusViewItemModel *item;
+ guint i;
+
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
+ item = nautilus_view_cell_get_item (cell);
+ g_return_if_fail (item != NULL);
+ i = nautilus_view_model_get_index (model, item);
+
+ /* Antecipate selection, enforcing single selection of target item. */
+ gtk_selection_model_select_item (GTK_SELECTION_MODEL (model), i, TRUE);
+
+ activate_selection_on_click (self, FALSE);
+ }
+
+ priv->activate_on_release = FALSE;
+ priv->deny_background_click = FALSE;
+}
+
+static void
+on_item_click_stopped (GtkGestureClick *gesture,
+ gpointer user_data)
+{
+ NautilusViewCell *cell = user_data;
+ NautilusListBase *self = NAUTILUS_LIST_BASE (nautilus_view_cell_get_view (cell));
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ priv->activate_on_release = FALSE;
+ priv->deny_background_click = FALSE;
+}
+
+static void
+on_view_click_pressed (GtkGestureClick *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
+ NautilusListBase *self = user_data;
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ guint button;
+ GdkModifierType modifiers;
+ gboolean selection_mode;
+
+ if (priv->deny_background_click)
+ {
+ /* Item was clicked. */
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+ return;
+ }
+
+ /* Don't interfere with GtkListBase default selection handling when
+ * holding Ctrl and Shift. */
+ modifiers = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (gesture));
+ selection_mode = (modifiers & (GDK_CONTROL_MASK | GDK_SHIFT_MASK));
+ if (!selection_mode)
+ {
+ nautilus_view_set_selection (NAUTILUS_VIEW (self), NULL);
+ }
+
+ button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+ if (button == GDK_BUTTON_SECONDARY)
+ {
+ GtkWidget *event_widget;
+ gdouble view_x;
+ gdouble view_y;
+
+ event_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
+ gtk_widget_translate_coordinates (event_widget, GTK_WIDGET (self),
+ x, y,
+ &view_x, &view_y);
+ nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (self),
+ view_x, view_y);
+ }
+}
+
+static void
+on_item_longpress_pressed (GtkGestureLongPress *gesture,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
+ NautilusViewCell *cell = user_data;
+ NautilusListBase *self = NAUTILUS_LIST_BASE (nautilus_view_cell_get_view (cell));
+ GtkWidget *event_widget;
+ gdouble view_x;
+ gdouble view_y;
+
+ event_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
+
+ gtk_widget_translate_coordinates (event_widget,
+ GTK_WIDGET (self),
+ x, y, &view_x, &view_y);
+
+ nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (self),
+ view_x, view_y);
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static void
+on_view_longpress_pressed (GtkGestureLongPress *gesture,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (user_data);
+ GtkWidget *event_widget;
+ gdouble view_x;
+ gdouble view_y;
+
+ event_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
+
+ gtk_widget_translate_coordinates (event_widget,
+ GTK_WIDGET (self),
+ x, y, &view_x, &view_y);
+
+ nautilus_view_set_selection (NAUTILUS_VIEW (self), NULL);
+ nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (self),
+ view_x, view_y);
+}
+
+void
+setup_cell_common (GtkListItem *listitem,
+ NautilusViewCell *cell)
+{
+ GtkEventController *controller;
+
+ g_object_bind_property (listitem, "item",
+ cell, "item",
+ G_BINDING_SYNC_CREATE);
+ gtk_list_item_set_child (listitem, GTK_WIDGET (cell));
+
+ controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
+ gtk_widget_add_controller (GTK_WIDGET (cell), controller);
+ gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
+ gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
+ g_signal_connect (controller, "pressed", G_CALLBACK (on_item_click_pressed), cell);
+ g_signal_connect (controller, "stopped", G_CALLBACK (on_item_click_stopped), cell);
+ g_signal_connect (controller, "released", G_CALLBACK (on_item_click_released), cell);
+
+ controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
+ gtk_widget_add_controller (GTK_WIDGET (cell), controller);
+ gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (controller), TRUE);
+ g_signal_connect (controller, "pressed", G_CALLBACK (on_item_longpress_pressed), cell);
+}
+
+static void
+nautilus_list_base_scroll_to_item (NautilusListBase *self,
+ guint position)
+{
+ NAUTILUS_LIST_BASE_CLASS (G_OBJECT_GET_CLASS (self))->scroll_to_item (self, position);
+}
+
+static guint
+nautilus_list_base_get_icon_size (NautilusListBase *self)
+{
+ return NAUTILUS_LIST_BASE_CLASS (G_OBJECT_GET_CLASS (self))->get_icon_size (self);
+}
+
+static GtkWidget *
+nautilus_list_base_get_view_ui (NautilusListBase *self)
+{
+ return NAUTILUS_LIST_BASE_CLASS (G_OBJECT_GET_CLASS (self))->get_view_ui (self);
+}
+
+typedef struct
+{
+ NautilusListBase *self;
+ GQuark attribute_q;
+} NautilusListBaseSortData;
+
+static void
+real_begin_loading (NautilusFilesView *files_view)
+{
+ /*TODO move this to the files view class begin_loading and hook up? */
+
+
+ /* TODO: This calls sort once, and update_context_menus calls update_actions
+ * which calls the action again
+ */
+ update_sort_order_from_metadata_and_preferences (NAUTILUS_LIST_BASE (files_view));
+
+ /* We could have changed to the trash directory or to searching, and then
+ * we need to update the menus */
+ nautilus_files_view_update_context_menus (files_view);
+ nautilus_files_view_update_toolbar_menus (files_view);
+}
+
+static void
+real_clear (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ nautilus_view_model_remove_all_items (priv->model);
+}
+
+static void
+set_click_mode_from_settings (NautilusListBase *self)
+{
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ int click_policy;
+
+ click_policy = g_settings_get_enum (nautilus_preferences,
+ NAUTILUS_PREFERENCES_CLICK_POLICY);
+
+ priv->single_click_mode = (click_policy == NAUTILUS_CLICK_POLICY_SINGLE);
+}
+
+static void
+real_click_policy_changed (NautilusFilesView *files_view)
+{
+ set_click_mode_from_settings (NAUTILUS_LIST_BASE (files_view));
+}
+
+static void
+real_file_changed (NautilusFilesView *files_view,
+ NautilusFile *file,
+ NautilusDirectory *directory)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ NautilusViewItemModel *item_model;
+
+ item_model = nautilus_view_model_get_item_from_file (priv->model, file);
+ nautilus_view_item_model_file_changed (item_model);
+}
+
+static GList *
+real_get_selection (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autoptr (GtkSelectionFilterModel) selection = NULL;
+ guint n_selected;
+ GList *selected_files = NULL;
+
+ selection = gtk_selection_filter_model_new (GTK_SELECTION_MODEL (priv->model));
+ n_selected = g_list_model_get_n_items (G_LIST_MODEL (selection));
+ for (guint i = 0; i < n_selected; i++)
+ {
+ g_autoptr (NautilusViewItemModel) item_model = NULL;
+
+ item_model = get_view_item (G_LIST_MODEL (selection), i);
+ selected_files = g_list_prepend (selected_files,
+ g_object_ref (nautilus_view_item_model_get_file (item_model)));
+ }
+
+ return selected_files;
+}
+
+static gboolean
+real_is_empty (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ return g_list_model_get_n_items (G_LIST_MODEL (priv->model)) == 0;
+}
+
+static void
+real_end_file_changes (NautilusFilesView *files_view)
+{
+}
+
+static void
+real_remove_file (NautilusFilesView *files_view,
+ NautilusFile *file,
+ NautilusDirectory *directory)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ NautilusViewItemModel *item_model;
+
+ item_model = nautilus_view_model_get_item_from_file (priv->model, file);
+ if (item_model != NULL)
+ {
+ nautilus_view_model_remove_item (priv->model, item_model);
+ }
+}
+
+static GQueue *
+convert_glist_to_queue (GList *list)
+{
+ GList *l;
+ GQueue *queue;
+
+ queue = g_queue_new ();
+ for (l = list; l != NULL; l = l->next)
+ {
+ g_queue_push_tail (queue, l->data);
+ }
+
+ return queue;
+}
+
+static GQueue *
+convert_files_to_item_models (NautilusListBase *self,
+ GQueue *files)
+{
+ GList *l;
+ GQueue *models;
+
+ models = g_queue_new ();
+ for (l = g_queue_peek_head_link (files); l != NULL; l = l->next)
+ {
+ NautilusViewItemModel *item_model;
+
+ item_model = nautilus_view_item_model_new (NAUTILUS_FILE (l->data),
+ nautilus_list_base_get_icon_size (self));
+ g_queue_push_tail (models, item_model);
+ }
+
+ return models;
+}
+
+static void
+real_set_selection (NautilusFilesView *files_view,
+ GList *selection)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autoptr (GQueue) selection_files = NULL;
+ g_autoptr (GQueue) selection_item_models = NULL;
+ g_autoptr (GtkBitset) update_set = NULL;
+ g_autoptr (GtkBitset) selection_set = NULL;
+
+ update_set = gtk_selection_model_get_selection (GTK_SELECTION_MODEL (priv->model));
+ selection_set = gtk_bitset_new_empty ();
+
+ /* Convert file list into set of model indices */
+ selection_files = convert_glist_to_queue (selection);
+ selection_item_models = nautilus_view_model_get_items_from_files (priv->model, selection_files);
+ for (GList *l = g_queue_peek_head_link (selection_item_models); l != NULL; l = l->next)
+ {
+ gtk_bitset_add (selection_set,
+ nautilus_view_model_get_index (priv->model, l->data));
+ }
+
+ gtk_bitset_union (update_set, selection_set);
+ gtk_selection_model_set_selection (GTK_SELECTION_MODEL (priv->model),
+ selection_set,
+ update_set);
+}
+
+static void
+real_select_all (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ gtk_selection_model_select_all (GTK_SELECTION_MODEL (priv->model));
+}
+
+static void
+real_invert_selection (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ GtkSelectionModel *selection_model = GTK_SELECTION_MODEL (priv->model);
+ g_autoptr (GtkBitset) selected = NULL;
+ g_autoptr (GtkBitset) all = NULL;
+ g_autoptr (GtkBitset) new_selected = NULL;
+
+ selected = gtk_selection_model_get_selection (selection_model);
+
+ /* We are going to flip the selection state of every item in the model. */
+ all = gtk_bitset_new_range (0, g_list_model_get_n_items (G_LIST_MODEL (priv->model)));
+
+ /* The new selection is all items minus the ones currently selected. */
+ new_selected = gtk_bitset_copy (all);
+ gtk_bitset_subtract (new_selected, selected);
+
+ gtk_selection_model_set_selection (selection_model, new_selected, all);
+}
+
+static guint
+get_first_selected_item (NautilusListBase *self)
+{
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autolist (NautilusFile) selection = NULL;
+ NautilusFile *file;
+ NautilusViewItemModel *item_model;
+
+ selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
+ if (selection == NULL)
+ {
+ return G_MAXUINT;
+ }
+
+ file = NAUTILUS_FILE (selection->data);
+ item_model = nautilus_view_model_get_item_from_file (priv->model, file);
+
+ return nautilus_view_model_get_index (priv->model, item_model);
+}
+
+static void
+real_reveal_selection (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+
+ nautilus_list_base_scroll_to_item (self, get_first_selected_item (self));
+}
+
+static gboolean
+showing_recent_directory (NautilusFilesView *view)
+{
+ NautilusFile *file;
+
+ file = nautilus_files_view_get_directory_as_file (view);
+ if (file != NULL)
+ {
+ return nautilus_file_is_in_recent (file);
+ }
+ return FALSE;
+}
+
+static gboolean
+showing_search_directory (NautilusFilesView *view)
+{
+ NautilusFile *file;
+
+ file = nautilus_files_view_get_directory_as_file (view);
+ if (file != NULL)
+ {
+ return nautilus_file_is_in_search (file);
+ }
+ return FALSE;
+}
+
+static void
+real_update_actions_state (NautilusFilesView *files_view)
+{
+ GAction *action;
+ GActionGroup *view_action_group;
+
+ NAUTILUS_FILES_VIEW_CLASS (nautilus_list_base_parent_class)->update_actions_state (files_view);
+
+ view_action_group = nautilus_files_view_get_action_group (files_view);
+ action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "sort");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ !showing_recent_directory (files_view) &&
+ !showing_search_directory (files_view));
+}
+
+
+static int
+real_compare_files (NautilusFilesView *files_view,
+ NautilusFile *file1,
+ NautilusFile *file2)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ GtkSorter *sorter;
+ g_autoptr (NautilusViewItemModel) item1 = NULL;
+ g_autoptr (NautilusViewItemModel) item2 = NULL;
+
+ sorter = nautilus_view_model_get_sorter (priv->model);
+ if (sorter == NULL)
+ {
+ return 0;
+ }
+
+ /* Generate fake model items for sorter use only. */
+ item1 = nautilus_view_item_model_new (file1, NAUTILUS_GRID_ICON_SIZE_SMALL);
+ item2 = nautilus_view_item_model_new (file2, NAUTILUS_GRID_ICON_SIZE_SMALL);
+
+ return gtk_sorter_compare (sorter, item1, item2);
+}
+
+static void
+on_clipboard_contents_received (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ NautilusFilesView *files_view = NAUTILUS_FILES_VIEW (source_object);
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ NautilusClipboard *clip;
+ NautilusViewItemModel *item;
+
+ for (GList *l = priv->cut_files; l != NULL; l = l->next)
+ {
+ item = nautilus_view_model_get_item_from_file (priv->model, l->data);
+ if (item != NULL)
+ {
+ nautilus_view_item_model_set_cut (item, FALSE);
+ }
+ }
+ g_clear_list (&priv->cut_files, g_object_unref);
+
+ clip = nautilus_files_view_get_clipboard_finish (files_view, res, NULL);
+ if (clip != NULL && nautilus_clipboard_is_cut (clip))
+ {
+ priv->cut_files = g_list_copy_deep (nautilus_clipboard_peek_files (clip),
+ (GCopyFunc) g_object_ref,
+ NULL);
+ }
+
+ for (GList *l = priv->cut_files; l != NULL; l = l->next)
+ {
+ item = nautilus_view_model_get_item_from_file (priv->model, l->data);
+ if (item != NULL)
+ {
+ nautilus_view_item_model_set_cut (item, TRUE);
+ }
+ }
+}
+
+static void
+update_clipboard_status (NautilusFilesView *view)
+{
+ nautilus_files_view_get_clipboard_async (view,
+ on_clipboard_contents_received,
+ NULL);
+}
+
+static void
+on_clipboard_owner_changed (GdkClipboard *clipboard,
+ gpointer user_data)
+{
+ update_clipboard_status (NAUTILUS_FILES_VIEW (user_data));
+}
+
+static void
+real_end_loading (NautilusFilesView *files_view,
+ gboolean all_files_seen)
+{
+ update_clipboard_status (files_view);
+}
+
+static guint
+get_first_visible_item (NautilusListBase *self)
+{
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ guint n_items;
+ gdouble scrolled_y;
+ GtkWidget *view_ui;
+
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (priv->model));
+ scrolled_y = gtk_adjustment_get_value (priv->vadjustment);
+ view_ui = nautilus_list_base_get_view_ui (self);
+ for (guint i = 0; i < n_items; i++)
+ {
+ g_autoptr (NautilusViewItemModel) item = NULL;
+ GtkWidget *item_ui;
+
+ item = get_view_item (G_LIST_MODEL (priv->model), i);
+ item_ui = nautilus_view_item_model_get_item_ui (item);
+ if (item_ui != NULL)
+ {
+ gdouble y;
+
+ gtk_widget_translate_coordinates (item_ui, view_ui,
+ 0, 0, NULL, &y);
+ if (gtk_widget_is_visible (item_ui) && y >= scrolled_y)
+ {
+ return i;
+ }
+ }
+ }
+
+ return G_MAXUINT;
+}
+
+static char *
+real_get_first_visible_file (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ guint i;
+ g_autoptr (NautilusViewItemModel) item = NULL;
+ gchar *uri = NULL;
+
+ i = get_first_visible_item (self);
+ if (i < G_MAXUINT)
+ {
+ item = get_view_item (G_LIST_MODEL (priv->model), i);
+ uri = nautilus_file_get_uri (nautilus_view_item_model_get_file (item));
+ }
+ return uri;
+}
+
+typedef struct
+{
+ NautilusListBase *view;
+ char *uri;
+} ScrollToFileData;
+
+static void
+scroll_to_file_data_free (ScrollToFileData *data)
+{
+ g_free (data->uri);
+ g_free (data);
+}
+
+static gboolean
+scroll_to_file_on_idle (ScrollToFileData *data)
+{
+ NautilusListBase *self = data->view;
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autoptr (NautilusFile) file = NULL;
+ NautilusViewItemModel *item;
+ guint i;
+
+ file = nautilus_file_get_existing_by_uri (data->uri);
+ item = nautilus_view_model_get_item_from_file (priv->model, file);
+ i = nautilus_view_model_get_index (priv->model, item);
+
+ nautilus_list_base_scroll_to_item (self, i);
+
+ priv->scroll_to_file_handle_id = 0;
+ return G_SOURCE_REMOVE;
+}
+
+static void
+real_scroll_to_file (NautilusFilesView *files_view,
+ const char *uri)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ ScrollToFileData *data;
+ guint handle_id;
+
+ data = g_new (ScrollToFileData, 1);
+ data->view = self;
+ data->uri = g_strdup (uri);
+ handle_id = g_idle_add_full (G_PRIORITY_LOW,
+ (GSourceFunc) scroll_to_file_on_idle,
+ data,
+ (GDestroyNotify) scroll_to_file_data_free);
+ priv->scroll_to_file_handle_id = handle_id;
+}
+
+static void
+real_add_files (NautilusFilesView *files_view,
+ GList *files)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autoptr (GQueue) files_queue = NULL;
+ g_autoptr (GQueue) item_models = NULL;
+ gdouble adjustment_value;
+
+ files_queue = convert_glist_to_queue (files);
+ item_models = convert_files_to_item_models (self, files_queue);
+ nautilus_view_model_add_items (priv->model, item_models);
+
+ /* GtkListBase anchoring doesn't cope well with our lazy loading.
+ * Assuming that GtkListBase|list.scroll-to-item resets the anchor to 0, use
+ * that as a workaround to prevent scrolling while we are at the top. */
+ adjustment_value = gtk_adjustment_get_value (priv->vadjustment);
+ if (G_APPROX_VALUE (adjustment_value, 0.0, DBL_EPSILON))
+ {
+ nautilus_list_base_scroll_to_item (self, 0);
+ }
+}
+
+static void
+real_select_first (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autoptr (NautilusViewItemModel) item = NULL;
+ NautilusFile *file;
+ g_autoptr (GList) selection = NULL;
+
+ item = get_view_item (G_LIST_MODEL (priv->model), 0);
+ if (item == NULL)
+ {
+ return;
+ }
+ file = nautilus_view_item_model_get_file (item);
+ selection = g_list_prepend (selection, file);
+ nautilus_view_set_selection (NAUTILUS_VIEW (files_view), selection);
+}
+
+static GdkRectangle *
+get_rectangle_for_item_ui (NautilusListBase *self,
+ GtkWidget *item_ui)
+{
+ GdkRectangle *rectangle;
+ GtkWidget *content_widget;
+ gdouble view_x;
+ gdouble view_y;
+
+ rectangle = g_new0 (GdkRectangle, 1);
+ gtk_widget_get_allocation (item_ui, rectangle);
+
+ content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (self));
+ gtk_widget_translate_coordinates (item_ui, content_widget,
+ rectangle->x, rectangle->y,
+ &view_x, &view_y);
+ rectangle->x = view_x;
+ rectangle->y = view_y;
+
+ return rectangle;
+}
+
+static GdkRectangle *
+real_compute_rename_popover_pointing_to (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autoptr (NautilusViewItemModel) item = NULL;
+ GtkWidget *item_ui;
+
+ /* We only allow one item to be renamed with a popover */
+ item = get_view_item (G_LIST_MODEL (priv->model), get_first_selected_item (self));
+ item_ui = nautilus_view_item_model_get_item_ui (item);
+ g_return_val_if_fail (item_ui != NULL, NULL);
+
+ return get_rectangle_for_item_ui (self, item_ui);
+}
+
+static GdkRectangle *
+real_reveal_for_selection_context_menu (NautilusFilesView *files_view)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ g_autoptr (GtkSelectionFilterModel) selection = NULL;
+ guint n_selected;
+ GtkWidget *focus_child;
+ guint i;
+ GtkWidget *item_ui;
+
+ selection = gtk_selection_filter_model_new (GTK_SELECTION_MODEL (priv->model));
+ n_selected = g_list_model_get_n_items (G_LIST_MODEL (selection));
+ g_return_val_if_fail (n_selected > 0, NULL);
+
+ /* Get the focused item_ui, if selected.
+ * Otherwise, get the selected item_ui which is sorted the lowest.*/
+ focus_child = gtk_widget_get_focus_child (nautilus_list_base_get_view_ui (self));
+ for (i = 0; i < n_selected; i++)
+ {
+ g_autoptr (NautilusViewItemModel) item = NULL;
+
+ item = get_view_item (G_LIST_MODEL (selection), i);
+ item_ui = nautilus_view_item_model_get_item_ui (item);
+ if (item_ui != NULL && gtk_widget_get_parent (item_ui) == focus_child)
+ {
+ break;
+ }
+ }
+ nautilus_list_base_scroll_to_item (self, i);
+
+ return get_rectangle_for_item_ui (self, item_ui);
+}
+
+static void
+real_preview_selection_event (NautilusFilesView *files_view,
+ GtkDirectionType direction)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (files_view);
+ GtkMovementStep step;
+ gint count;
+ gboolean handled;
+
+ step = (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN) ?
+ GTK_MOVEMENT_DISPLAY_LINES : GTK_MOVEMENT_VISUAL_POSITIONS;
+ count = (direction == GTK_DIR_RIGHT || direction == GTK_DIR_DOWN) ?
+ 1 : -1;
+
+ g_signal_emit_by_name (nautilus_list_base_get_view_ui (self),
+ "move-cursor", step, count, &handled);
+}
+
+static void
+default_sort_order_changed_callback (NautilusListBase *self)
+{
+ update_sort_order_from_metadata_and_preferences (self);
+}
+
+static void
+nautilus_list_base_dispose (GObject *object)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (object);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ g_clear_handle_id (&priv->scroll_to_file_handle_id, g_source_remove);
+ g_clear_handle_id (&priv->prioritize_thumbnailing_handle_id, g_source_remove);
+
+ G_OBJECT_CLASS (nautilus_list_base_parent_class)->dispose (object);
+}
+
+static void
+nautilus_list_base_finalize (GObject *object)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (object);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ g_clear_list (&priv->cut_files, g_object_unref);
+
+ G_OBJECT_CLASS (nautilus_list_base_parent_class)->finalize (object);
+}
+
+static gboolean
+prioritize_thumbnailing_on_idle (NautilusListBase *self)
+{
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ gdouble page_size;
+ GtkWidget *first_visible_child;
+ GtkWidget *next_child;
+ guint first_index;
+ guint next_index;
+ gdouble y;
+ guint last_index;
+ g_autoptr (NautilusViewItemModel) first_item = NULL;
+ NautilusFile *file;
+
+ priv->prioritize_thumbnailing_handle_id = 0;
+
+ page_size = gtk_adjustment_get_page_size (priv->vadjustment);
+ first_index = get_first_visible_item (self);
+ if (first_index == G_MAXUINT)
+ {
+ return G_SOURCE_REMOVE;
+ }
+
+ first_item = get_view_item (G_LIST_MODEL (priv->model), first_index);
+
+ first_visible_child = nautilus_view_item_model_get_item_ui (first_item);
+
+ for (next_index = first_index + 1; next_index < g_list_model_get_n_items (G_LIST_MODEL (priv->model));
next_index++)
+ {
+ g_autoptr (NautilusViewItemModel) next_item = NULL;
+
+ next_item = get_view_item (G_LIST_MODEL (priv->model), next_index);
+ next_child = nautilus_view_item_model_get_item_ui (next_item);
+ if (next_child == NULL)
+ {
+ break;
+ }
+ if (gtk_widget_translate_coordinates (next_child, first_visible_child,
+ 0, 0, NULL, &y))
+ {
+ if (y > page_size)
+ {
+ break;
+ }
+ }
+ }
+ last_index = next_index - 1;
+
+ /* Do the iteration in reverse to give higher priority to the top */
+ for (gint i = 0; i <= last_index - first_index; i++)
+ {
+ g_autoptr (NautilusViewItemModel) item = NULL;
+
+ item = get_view_item (G_LIST_MODEL (priv->model), last_index - i);
+ g_return_val_if_fail (item != NULL, G_SOURCE_REMOVE);
+
+ file = nautilus_view_item_model_get_file (NAUTILUS_VIEW_ITEM_MODEL (item));
+ if (file != NULL && nautilus_file_is_thumbnailing (file))
+ {
+ g_autofree gchar *uri = nautilus_file_get_uri (file);
+ nautilus_thumbnail_prioritize (uri);
+ }
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+on_vadjustment_changed (GtkAdjustment *adjustment,
+ gpointer user_data)
+{
+ NautilusListBase *self = NAUTILUS_LIST_BASE (user_data);
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ guint handle_id;
+
+ /* Schedule on idle to rate limit and to avoid delaying scrolling. */
+ if (priv->prioritize_thumbnailing_handle_id == 0)
+ {
+ handle_id = g_idle_add ((GSourceFunc) prioritize_thumbnailing_on_idle, self);
+ priv->prioritize_thumbnailing_handle_id = handle_id;
+ }
+}
+
+static void
+nautilus_list_base_class_init (NautilusListBaseClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ NautilusFilesViewClass *files_view_class = NAUTILUS_FILES_VIEW_CLASS (klass);
+
+ object_class->dispose = nautilus_list_base_dispose;
+ object_class->finalize = nautilus_list_base_finalize;
+
+ files_view_class->add_files = real_add_files;
+ files_view_class->begin_loading = real_begin_loading;
+ files_view_class->clear = real_clear;
+ files_view_class->click_policy_changed = real_click_policy_changed;
+ files_view_class->file_changed = real_file_changed;
+ files_view_class->get_selection = real_get_selection;
+ /* TODO: remove this get_selection_for_file_transfer, this doesn't even
+ * take into account we could us the view for recursive search :/
+ * CanvasView has the same issue. */
+ files_view_class->get_selection_for_file_transfer = real_get_selection;
+ files_view_class->is_empty = real_is_empty;
+ files_view_class->remove_file = real_remove_file;
+ files_view_class->select_all = real_select_all;
+ files_view_class->set_selection = real_set_selection;
+ files_view_class->invert_selection = real_invert_selection;
+ files_view_class->compare_files = real_compare_files;
+ files_view_class->end_file_changes = real_end_file_changes;
+ files_view_class->end_loading = real_end_loading;
+ files_view_class->get_first_visible_file = real_get_first_visible_file;
+ files_view_class->reveal_selection = real_reveal_selection;
+ files_view_class->update_actions_state = real_update_actions_state;
+ files_view_class->scroll_to_file = real_scroll_to_file;
+ files_view_class->select_first = real_select_first;
+ files_view_class->compute_rename_popover_pointing_to = real_compute_rename_popover_pointing_to;
+ files_view_class->reveal_for_selection_context_menu = real_reveal_for_selection_context_menu;
+ files_view_class->preview_selection_event = real_preview_selection_event;
+}
+
+static void
+nautilus_list_base_init (NautilusListBase *self)
+{
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+ GtkWidget *content_widget;
+ GtkAdjustment *vadjustment;
+
+ gtk_widget_add_css_class (GTK_WIDGET (self), "view");
+
+ g_signal_connect_object (nautilus_preferences,
+ "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
+ G_CALLBACK (default_sort_order_changed_callback),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (nautilus_preferences,
+ "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
+ G_CALLBACK (default_sort_order_changed_callback),
+ self,
+ G_CONNECT_SWAPPED);
+
+ /* React to clipboard changes */
+ g_signal_connect_object (gdk_display_get_clipboard (gdk_display_get_default ()),
+ "changed",
+ G_CALLBACK (on_clipboard_owner_changed), self, 0);
+
+ content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (self));
+ vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (content_widget));
+
+ priv->vadjustment = vadjustment;
+ g_signal_connect (vadjustment, "changed", (GCallback) on_vadjustment_changed, self);
+ g_signal_connect (vadjustment, "value-changed", (GCallback) on_vadjustment_changed, self);
+
+ priv->model = nautilus_view_model_new ();
+
+ g_signal_connect_object (GTK_SELECTION_MODEL (priv->model),
+ "selection-changed",
+ G_CALLBACK (nautilus_files_view_notify_selection_changed),
+ NAUTILUS_FILES_VIEW (self),
+ G_CONNECT_SWAPPED);
+
+ set_click_mode_from_settings (self);
+}
+
+NautilusViewModel *
+nautilus_list_base_get_model (NautilusListBase *self)
+{
+ NautilusListBasePrivate *priv = nautilus_list_base_get_instance_private (self);
+
+ return priv->model;
+}
+
+void
+nautilus_list_base_setup_gestures (NautilusListBase *self)
+{
+ GtkWidget *view_ui = nautilus_list_base_get_view_ui (self);
+ GtkEventController *controller;
+
+ controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
+ gtk_widget_add_controller (view_ui, controller);
+ gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
+ g_signal_connect (controller, "pressed",
+ G_CALLBACK (on_view_click_pressed), self);
+
+ controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
+ gtk_widget_add_controller (view_ui, controller);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (controller), TRUE);
+ g_signal_connect (controller, "pressed",
+ G_CALLBACK (on_view_longpress_pressed), self);
+}
diff --git a/src/nautilus-list-base.h b/src/nautilus-list-base.h
new file mode 100644
index 000000000..007ab07a6
--- /dev/null
+++ b/src/nautilus-list-base.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "nautilus-files-view.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_LIST_BASE (nautilus_list_base_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (NautilusListBase, nautilus_list_base, NAUTILUS, LIST_BASE, NautilusFilesView)
+
+struct _NautilusListBaseClass
+{
+ NautilusFilesViewClass parent_class;
+
+ guint (*get_icon_size) (NautilusListBase *self);
+ GtkWidget *(*get_view_ui) (NautilusListBase *self);
+ void (*scroll_to_item) (NautilusListBase *self,
+ guint position);
+};
+
+G_END_DECLS
diff --git a/src/nautilus-types.h b/src/nautilus-types.h
index 073a1576d..1fe935449 100644
--- a/src/nautilus-types.h
+++ b/src/nautilus-types.h
@@ -36,8 +36,9 @@ typedef struct _NautilusClipboard NautilusClipboard;
typedef struct _NautilusDirectory NautilusDirectory;
typedef struct NautilusFile NautilusFile;
typedef struct NautilusFileQueue NautilusFileQueue;
-typedef struct _NautilusFilesView NautilusFilesView;
+typedef struct _NautilusFilesModelView NautilusFilesModelView;
typedef struct _NautilusIconInfo NautilusIconInfo;
+typedef struct _NautilusListBase NautilusListBase;
typedef struct NautilusMonitor NautilusMonitor;
typedef struct _NautilusQuery NautilusQuery;
typedef struct _NautilusQueryEditor NautilusQueryEditor;
diff --git a/src/nautilus-view-cell.c b/src/nautilus-view-cell.c
new file mode 100644
index 000000000..0a184f0d0
--- /dev/null
+++ b/src/nautilus-view-cell.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 2022 António Fernandes <antoniof gnome org>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "nautilus-view-cell.h"
+#include "nautilus-list-base.h"
+
+/**
+ * NautilusViewCell:
+ *
+ * Abstract class of widgets tailored to be set as #GtkListItem:child in a view
+ * which subclasses #NautilusListBase.
+ *
+ * Subclass constructors should take a pointer to the #NautilusListBase view.
+ *
+ * The view is responsible for setting #NautilusViewCell:item. This can be done
+ * using a GBinding from #GtkListItem:item to #NautilusViewCell:item.
+ */
+
+typedef struct _NautilusViewCellPrivate NautilusViewCellPrivate;
+struct _NautilusViewCellPrivate
+{
+ AdwBin parent_instance;
+
+ NautilusListBase *view; /* Unowned */
+ NautilusViewItemModel *item; /* Owned reference */
+
+ gboolean called_once;
+};
+
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (NautilusViewCell, nautilus_view_cell, ADW_TYPE_BIN)
+
+enum
+{
+ PROP_0,
+ PROP_VIEW,
+ PROP_ITEM,
+ N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+nautilus_view_cell_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusViewCell *self = NAUTILUS_VIEW_CELL (object);
+ NautilusViewCellPrivate *priv = nautilus_view_cell_get_instance_private (self);
+
+ switch (prop_id)
+ {
+ case PROP_VIEW:
+ {
+ g_value_set_object (value, priv->view);
+ }
+ break;
+
+ case PROP_ITEM:
+ {
+ g_value_set_object (value, priv->item);
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+ }
+}
+
+static void
+nautilus_view_cell_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusViewCell *self = NAUTILUS_VIEW_CELL (object);
+ NautilusViewCellPrivate *priv = nautilus_view_cell_get_instance_private (self);
+
+ switch (prop_id)
+ {
+ case PROP_VIEW:
+ {
+ priv->view = g_value_get_object (value);
+ }
+ break;
+
+ case PROP_ITEM:
+ {
+ g_set_object (&priv->item, g_value_get_object (value));
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+ }
+}
+
+static void
+nautilus_view_cell_init (NautilusViewCell *self)
+{
+}
+
+static void
+nautilus_view_cell_finalize (GObject *object)
+{
+ NautilusViewCell *self = NAUTILUS_VIEW_CELL (object);
+ NautilusViewCellPrivate *priv = nautilus_view_cell_get_instance_private (self);
+
+ g_clear_object (&priv->item);
+
+ G_OBJECT_CLASS (nautilus_view_cell_parent_class)->finalize (object);
+}
+
+static void
+nautilus_view_cell_class_init (NautilusViewCellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = nautilus_view_cell_finalize;
+ object_class->get_property = nautilus_view_cell_get_property;
+ object_class->set_property = nautilus_view_cell_set_property;
+
+ properties[PROP_VIEW] = g_param_spec_object ("view",
+ "", "",
+ NAUTILUS_TYPE_LIST_BASE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
+ properties[PROP_ITEM] = g_param_spec_object ("item",
+ "", "",
+ NAUTILUS_TYPE_VIEW_ITEM_MODEL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+gboolean
+nautilus_view_cell_once (NautilusViewCell *self)
+{
+ NautilusViewCellPrivate *priv = nautilus_view_cell_get_instance_private (self);
+
+ if (priv->called_once)
+ {
+ return FALSE;
+ }
+ priv->called_once = TRUE;
+
+ return TRUE;
+}
+
+NautilusListBase *
+nautilus_view_cell_get_view (NautilusViewCell *self)
+{
+ NautilusListBase *view;
+
+ g_return_val_if_fail (NAUTILUS_IS_VIEW_CELL (self), NULL);
+
+ g_object_get (self, "view", &view, NULL);
+
+ return view;
+}
+
+void
+nautilus_view_cell_set_item (NautilusViewCell *self,
+ NautilusViewItemModel *item)
+{
+ g_return_if_fail (NAUTILUS_IS_VIEW_CELL (self));
+ g_return_if_fail (item == NULL || NAUTILUS_IS_VIEW_ITEM_MODEL (item));
+
+ g_object_set (self, "item", item, NULL);
+}
+
+NautilusViewItemModel *
+nautilus_view_cell_get_item (NautilusViewCell *self)
+{
+ NautilusViewItemModel *item;
+
+ g_return_val_if_fail (NAUTILUS_IS_VIEW_CELL (self), NULL);
+
+ g_object_get (self, "item", &item, NULL);
+
+ return item;
+}
diff --git a/src/nautilus-view-cell.h b/src/nautilus-view-cell.h
new file mode 100644
index 000000000..6093752eb
--- /dev/null
+++ b/src/nautilus-view-cell.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 António Fernandes <antoniof gnome org>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libadwaita-1/adwaita.h>
+
+#include "nautilus-types.h"
+#include "nautilus-view-item-model.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_VIEW_CELL (nautilus_view_cell_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (NautilusViewCell, nautilus_view_cell, NAUTILUS, VIEW_CELL, AdwBin)
+
+struct _NautilusViewCellClass
+{
+ AdwBinClass parent_class;
+};
+
+NautilusListBase *nautilus_view_cell_get_view (NautilusViewCell *self);
+void nautilus_view_cell_set_item (NautilusViewCell *self,
+ NautilusViewItemModel *item);
+NautilusViewItemModel *nautilus_view_cell_get_item (NautilusViewCell *self);
+gboolean nautilus_view_cell_once (NautilusViewCell *self);
+
+G_END_DECLS
diff --git a/src/nautilus-view-icon-controller.c b/src/nautilus-view-icon-controller.c
index f21cb681f..b4006f1e9 100644
--- a/src/nautilus-view-icon-controller.c
+++ b/src/nautilus-view-icon-controller.c
@@ -1,193 +1,31 @@
+#include "nautilus-list-base-private.h"
#include "nautilus-view-icon-controller.h"
#include "nautilus-view-item-model.h"
#include "nautilus-view-icon-item-ui.h"
-#include "nautilus-view-model.h"
-#include "nautilus-files-view.h"
#include "nautilus-file.h"
-#include "nautilus-metadata.h"
-#include "nautilus-window-slot.h"
-#include "nautilus-directory.h"
-#include "nautilus-clipboard.h"
#include "nautilus-global-preferences.h"
-#include "nautilus-thumbnails.h"
struct _NautilusViewIconController
{
- NautilusFilesView parent_instance;
+ NautilusListBase parent_instance;
GtkGridView *view_ui;
- NautilusViewModel *model;
-
- GList *cut_files;
GActionGroup *action_group;
gint zoom_level;
- GQuark caption_attributes[NAUTILUS_VIEW_ICON_N_CAPTIONS];
- gboolean single_click_mode;
- gboolean activate_on_release;
- gboolean deny_background_click;
+ gboolean directories_first;
- guint scroll_to_file_handle_id;
- guint prioritize_thumbnailing_handle_id;
- GtkAdjustment *vadjustment;
+ GQuark caption_attributes[NAUTILUS_VIEW_ICON_N_CAPTIONS];
NautilusFileSortType sort_type;
- gboolean directories_first;
gboolean reversed;
};
-G_DEFINE_TYPE (NautilusViewIconController, nautilus_view_icon_controller, NAUTILUS_TYPE_FILES_VIEW)
-
-typedef struct
-{
- const NautilusFileSortType sort_type;
- const gchar *metadata_name;
-} SortConstants;
-
-static const SortConstants sorts_constants[] =
-{
- {
- NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
- "name",
- },
- {
- NAUTILUS_FILE_SORT_BY_SIZE,
- "size",
- },
- {
- NAUTILUS_FILE_SORT_BY_TYPE,
- "type",
- },
- {
- NAUTILUS_FILE_SORT_BY_MTIME,
- "modification date",
- },
- {
- NAUTILUS_FILE_SORT_BY_ATIME,
- "access date",
- },
- {
- NAUTILUS_FILE_SORT_BY_BTIME,
- "creation date",
- },
- {
- NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
- "trashed",
- },
- {
- NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
- "search_relevance",
- },
- {
- NAUTILUS_FILE_SORT_BY_RECENCY,
- "recency",
- },
-};
+G_DEFINE_TYPE (NautilusViewIconController, nautilus_view_icon_controller, NAUTILUS_TYPE_LIST_BASE)
static guint get_icon_size_for_zoom_level (NautilusGridZoomLevel zoom_level);
-static const SortConstants *
-get_sorts_constants_from_sort_type (NautilusFileSortType sort_type)
-{
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS (sorts_constants); i++)
- {
- if (sort_type == sorts_constants[i].sort_type)
- {
- return &sorts_constants[i];
- }
- }
-
- return &sorts_constants[0];
-}
-
-static const SortConstants *
-get_sorts_constants_from_metadata_text (const char *metadata_name)
-{
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS (sorts_constants); i++)
- {
- if (g_strcmp0 (sorts_constants[i].metadata_name, metadata_name) == 0)
- {
- return &sorts_constants[i];
- }
- }
-
- return &sorts_constants[0];
-}
-
-static const SortConstants *
-get_default_sort_order (NautilusFile *file,
- gboolean *reversed)
-{
- NautilusFileSortType sort_type;
-
- sort_type = nautilus_file_get_default_sort_type (file, reversed);
-
- return get_sorts_constants_from_sort_type (sort_type);
-}
-
-static const SortConstants *
-get_directory_sort_by (NautilusFile *file,
- gboolean *reversed)
-{
- const SortConstants *default_sort;
- g_autofree char *sort_by = NULL;
-
- default_sort = get_default_sort_order (file, reversed);
- g_return_val_if_fail (default_sort != NULL, NULL);
-
- sort_by = nautilus_file_get_metadata (file,
- NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
- default_sort->metadata_name);
-
- *reversed = nautilus_file_get_boolean_metadata (file,
- NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
- *reversed);
-
- return get_sorts_constants_from_metadata_text (sort_by);
-}
-
-static void
-set_directory_sort_metadata (NautilusFile *file,
- const SortConstants *sort,
- gboolean reversed)
-{
- const SortConstants *default_sort;
- gboolean default_reversed;
-
- default_sort = get_default_sort_order (file, &default_reversed);
-
- nautilus_file_set_metadata (file,
- NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
- default_sort->metadata_name,
- sort->metadata_name);
- nautilus_file_set_boolean_metadata (file,
- NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
- default_reversed,
- reversed);
-}
-
-static void
-update_sort_order_from_metadata_and_preferences (NautilusViewIconController *self)
-{
- const SortConstants *default_directory_sort;
- GActionGroup *view_action_group;
- gboolean reversed;
-
- default_directory_sort = get_directory_sort_by (nautilus_files_view_get_directory_as_file
(NAUTILUS_FILES_VIEW (self)),
- &reversed);
- view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self));
- g_action_group_change_action_state (view_action_group,
- "sort",
- g_variant_new ("(sb)",
- default_directory_sort->metadata_name,
- reversed));
-}
-
static gint
nautilus_view_icon_controller_sort (gconstpointer a,
gconstpointer b,
@@ -206,258 +44,6 @@ nautilus_view_icon_controller_sort (gconstpointer a,
self->reversed);
}
-static void
-real_begin_loading (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
-
- /* TODO: This calls sort once, and update_context_menus calls update_actions which calls
- * the action again
- */
- update_sort_order_from_metadata_and_preferences (self);
-
- /*TODO move this to the files view class begin_loading and hook up? */
-
- /* We could have changed to the trash directory or to searching, and then
- * we need to update the menus */
- nautilus_files_view_update_context_menus (files_view);
- nautilus_files_view_update_toolbar_menus (files_view);
-}
-
-static void
-real_clear (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
-
- nautilus_view_model_remove_all_items (self->model);
-}
-
-static void
-real_file_changed (NautilusFilesView *files_view,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- NautilusViewIconController *self;
- NautilusViewItemModel *item_model;
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- item_model = nautilus_view_model_get_item_from_file (self->model, file);
- nautilus_view_item_model_file_changed (item_model);
-}
-
-static GList *
-real_get_selection (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self;
- g_autoptr (GtkSelectionFilterModel) selection = NULL;
- guint n_selected;
- GList *selected_files = NULL;
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- selection = gtk_selection_filter_model_new (GTK_SELECTION_MODEL (self->model));
- n_selected = g_list_model_get_n_items (G_LIST_MODEL (selection));
- for (guint i = 0; i < n_selected; i++)
- {
- g_autoptr (NautilusViewItemModel) item_model = NULL;
-
- item_model = g_list_model_get_item (G_LIST_MODEL (selection), i);
- selected_files = g_list_prepend (selected_files,
- g_object_ref (nautilus_view_item_model_get_file (item_model)));
- }
-
- return selected_files;
-}
-
-static gboolean
-real_is_empty (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
-
- return g_list_model_get_n_items (G_LIST_MODEL (self->model)) == 0;
-}
-
-static void
-real_end_file_changes (NautilusFilesView *files_view)
-{
-}
-
-static void
-real_remove_file (NautilusFilesView *files_view,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- NautilusViewItemModel *item_model;
-
- item_model = nautilus_view_model_get_item_from_file (self->model, file);
- if (item_model != NULL)
- {
- nautilus_view_model_remove_item (self->model, item_model);
- }
-}
-
-static GQueue *
-convert_glist_to_queue (GList *list)
-{
- GList *l;
- GQueue *queue;
-
- queue = g_queue_new ();
- for (l = list; l != NULL; l = l->next)
- {
- g_queue_push_tail (queue, l->data);
- }
-
- return queue;
-}
-
-static GQueue *
-convert_files_to_item_models (NautilusViewIconController *self,
- GQueue *files)
-{
- GList *l;
- GQueue *models;
-
- models = g_queue_new ();
- for (l = g_queue_peek_head_link (files); l != NULL; l = l->next)
- {
- NautilusViewItemModel *item_model;
-
- item_model = nautilus_view_item_model_new (NAUTILUS_FILE (l->data),
- get_icon_size_for_zoom_level (self->zoom_level));
- g_queue_push_tail (models, item_model);
- }
-
- return models;
-}
-
-static void
-real_set_selection (NautilusFilesView *files_view,
- GList *selection)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- g_autoptr (GQueue) selection_files = NULL;
- g_autoptr (GQueue) selection_item_models = NULL;
- g_autoptr (GtkBitset) update_set = NULL;
- g_autoptr (GtkBitset) selection_set = NULL;
-
- update_set = gtk_selection_model_get_selection (GTK_SELECTION_MODEL (self->model));
- selection_set = gtk_bitset_new_empty ();
-
- /* Convert file list into set of model indices */
- selection_files = convert_glist_to_queue (selection);
- selection_item_models = nautilus_view_model_get_items_from_files (self->model, selection_files);
- for (GList *l = g_queue_peek_head_link (selection_item_models); l != NULL ; l = l->next)
- {
- gtk_bitset_add (selection_set,
- nautilus_view_model_get_index (self->model, l->data));
- }
-
- gtk_bitset_union (update_set, selection_set);
- gtk_selection_model_set_selection (GTK_SELECTION_MODEL (self->model),
- selection_set,
- update_set);
-}
-
-static void
-real_select_all (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- gtk_selection_model_select_all (GTK_SELECTION_MODEL (self->model));
-}
-
-static void
-real_invert_selection (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- GtkSelectionModel *selection_model = GTK_SELECTION_MODEL (self->model);
- g_autoptr (GtkBitset) selected = NULL;
- g_autoptr (GtkBitset) all = NULL;
- g_autoptr (GtkBitset) new_selected = NULL;
-
- selected = gtk_selection_model_get_selection (selection_model);
-
- /* We are going to flip the selection state of every item in the model. */
- all = gtk_bitset_new_range (0, g_list_model_get_n_items (G_LIST_MODEL (self->model)));
-
- /* The new selection is all items minus the ones currently selected. */
- new_selected = gtk_bitset_copy (all);
- gtk_bitset_subtract (new_selected, selected);
-
- gtk_selection_model_set_selection (selection_model, new_selected, all);
-}
-
-static guint
-get_first_selected_item (NautilusViewIconController *self)
-{
- g_autolist (NautilusFile) selection = NULL;
- NautilusFile *file;
- NautilusViewItemModel *item_model;
-
- selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
- if (selection == NULL)
- {
- return G_MAXUINT;
- }
-
- file = NAUTILUS_FILE (selection->data);
- item_model = nautilus_view_model_get_item_from_file (self->model, file);
-
- return nautilus_view_model_get_index (self->model, item_model);
-}
-
-static void
-real_reveal_selection (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
-
- gtk_widget_activate_action (GTK_WIDGET (self->view_ui),
- "list.scroll-to-item",
- "u",
- get_first_selected_item (self));
-}
-
-static gboolean
-showing_recent_directory (NautilusFilesView *view)
-{
- NautilusFile *file;
-
- file = nautilus_files_view_get_directory_as_file (view);
- if (file != NULL)
- {
- return nautilus_file_is_in_recent (file);
- }
- return FALSE;
-}
-
-static gboolean
-showing_search_directory (NautilusFilesView *view)
-{
- NautilusFile *file;
-
- file = nautilus_files_view_get_directory_as_file (view);
- if (file != NULL)
- {
- return nautilus_file_is_in_search (file);
- }
- return FALSE;
-}
-
-static void
-real_update_actions_state (NautilusFilesView *files_view)
-{
- GAction *action;
- GActionGroup *view_action_group;
-
- NAUTILUS_FILES_VIEW_CLASS (nautilus_view_icon_controller_parent_class)->update_actions_state
(files_view);
-
- view_action_group = nautilus_files_view_get_action_group (files_view);
- action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "sort");
- g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
- !showing_recent_directory (files_view) &&
- !showing_search_directory (files_view));
-}
-
static void
real_bump_zoom_level (NautilusFilesView *files_view,
int zoom_increment)
@@ -556,23 +142,6 @@ set_captions_from_preferences (NautilusViewIconController *self)
}
}
-static void
-set_icon_size (NautilusViewIconController *self,
- gint icon_size)
-{
- guint n_items;
-
- n_items = g_list_model_get_n_items (G_LIST_MODEL (self->model));
- for (guint i = 0; i < n_items; i++)
- {
- g_autoptr (NautilusViewItemModel) current_item_model = NULL;
-
- current_item_model = g_list_model_get_item (G_LIST_MODEL (self->model), i);
- nautilus_view_item_model_set_icon_size (current_item_model,
- get_icon_size_for_zoom_level (self->zoom_level));
- }
-}
-
static void
set_zoom_level (NautilusViewIconController *self,
guint new_level)
@@ -584,7 +153,8 @@ set_zoom_level (NautilusViewIconController *self,
* updates captions whenever the icon size is set*/
set_captions_from_preferences (self);
- set_icon_size (self, get_icon_size_for_zoom_level (new_level));
+ nautilus_list_base_set_icon_size (NAUTILUS_LIST_BASE (self),
+ get_icon_size_for_zoom_level (new_level));
nautilus_files_view_update_toolbar_menus (NAUTILUS_FILES_VIEW (self));
}
@@ -628,134 +198,6 @@ real_can_zoom_out (NautilusFilesView *files_view)
return self->zoom_level > NAUTILUS_GRID_ZOOM_LEVEL_SMALL;
}
-static GdkRectangle *
-get_rectangle_for_item_ui (NautilusViewIconController *self,
- GtkWidget *item_ui)
-{
- GdkRectangle *rectangle;
- GtkWidget *content_widget;
- gdouble view_x;
- gdouble view_y;
-
- rectangle = g_new0 (GdkRectangle, 1);
- gtk_widget_get_allocation (item_ui, rectangle);
-
- content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (self));
- gtk_widget_translate_coordinates (item_ui, content_widget,
- rectangle->x, rectangle->y,
- &view_x, &view_y);
- rectangle->x = view_x;
- rectangle->y = view_y;
-
- return rectangle;
-}
-
-static GdkRectangle *
-real_compute_rename_popover_pointing_to (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- g_autoptr (NautilusViewItemModel) item = NULL;
- GtkWidget *item_ui;
-
- /* We only allow one item to be renamed with a popover */
- item = g_list_model_get_item (G_LIST_MODEL (self->model),
- get_first_selected_item (self));
- item_ui = nautilus_view_item_model_get_item_ui (item);
- g_return_val_if_fail (item_ui != NULL, NULL);
-
- return get_rectangle_for_item_ui (self, item_ui);
-}
-
-static GdkRectangle *
-real_reveal_for_selection_context_menu (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- g_autoptr (GtkSelectionFilterModel) selection = NULL;
- guint n_selected;
- GtkWidget *focus_child;
- guint i;
- GtkWidget *item_ui;
-
- selection = gtk_selection_filter_model_new (GTK_SELECTION_MODEL (self->model));
- n_selected = g_list_model_get_n_items (G_LIST_MODEL (selection));
- g_return_val_if_fail (n_selected > 0, NULL);
-
- /* Get the focused item_ui, if selected.
- * Otherwise, get the selected item_ui which is sorted the lowest.*/
- focus_child = gtk_widget_get_focus_child (GTK_WIDGET (self->view_ui));
- for (i = 0; i < n_selected; i++)
- {
- g_autoptr (NautilusViewItemModel) item = NULL;
-
- item = g_list_model_get_item (G_LIST_MODEL (selection), i);
- item_ui = nautilus_view_item_model_get_item_ui (item);
- if (item_ui != NULL && gtk_widget_get_parent (item_ui) == focus_child)
- {
- break;
- }
- }
-
- gtk_widget_activate_action (GTK_WIDGET (self->view_ui),
- "list.scroll-to-item",
- "u",
- i);
-
- return get_rectangle_for_item_ui (self, item_ui);
-}
-
-static void
-set_click_mode_from_settings (NautilusViewIconController *self)
-{
- int click_policy;
-
- click_policy = g_settings_get_enum (nautilus_preferences,
- NAUTILUS_PREFERENCES_CLICK_POLICY);
-
- self->single_click_mode = (click_policy == NAUTILUS_CLICK_POLICY_SINGLE);
-}
-
-static void
-real_click_policy_changed (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- set_click_mode_from_settings (self);
-}
-
-/* GtkListBase changes selection only with the primary button, and only after
- * release. But we need to antecipate selection earlier if we are to activate it
- * or open its context menu. This helper should be used in these situations if
- * it's desirable to act on a multi-item selection, because it preserves it. */
-static void
-select_single_item_if_not_selected (NautilusViewIconController *self,
- NautilusViewItemModel *item)
-{
- GtkSelectionModel *selection_model = GTK_SELECTION_MODEL (self->model);
- guint position;
-
- position = nautilus_view_model_get_index (self->model, item);
- if (!gtk_selection_model_is_selected (selection_model, position))
- {
- gtk_selection_model_select_item (selection_model, position, TRUE);
- }
-}
-
-static void
-activate_selection_on_click (NautilusViewIconController *self,
- gboolean open_in_new_tab)
-{
- g_autolist (NautilusFile) selection = NULL;
- NautilusOpenFlags flags = 0;
- NautilusFilesView *files_view = NAUTILUS_FILES_VIEW (self);
-
- selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
- if (open_in_new_tab)
- {
- flags |= NAUTILUS_OPEN_FLAG_NEW_TAB;
- flags |= NAUTILUS_OPEN_FLAG_DONT_MAKE_ACTIVE;
- }
- nautilus_files_view_activate_files (files_view, selection, flags, TRUE);
-}
-
/* We only care about the keyboard activation part that GtkGridView provides,
* but we don't need any special filtering here. Indeed, we ask GtkGridView
* to not activate on single click, and we get to handle double clicks before
@@ -774,378 +216,47 @@ on_grid_view_item_activated (GtkGridView *grid_view,
nautilus_files_view_activate_selection (NAUTILUS_FILES_VIEW (self));
}
-static void
-on_item_click_pressed (GtkGestureClick *gesture,
- gint n_press,
- gdouble x,
- gdouble y,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
- GtkWidget *event_widget;
- NautilusViewItemModel *item_model;
- guint button;
- GdkModifierType modifiers;
- gboolean selection_mode;
-
- event_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
- item_model = nautilus_view_icon_item_ui_get_model (NAUTILUS_VIEW_ICON_ITEM_UI (event_widget));
- button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
- modifiers = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (gesture));
- selection_mode = (modifiers & (GDK_CONTROL_MASK | GDK_SHIFT_MASK));
-
- /* Before anything else, store event state to be read by other handlers. */
- self->deny_background_click = TRUE;
- self->activate_on_release = (self->single_click_mode &&
- button == GDK_BUTTON_PRIMARY &&
- n_press == 1 &&
- !selection_mode);
-
- /* It's safe to claim event sequence on press in the following cases because
- * they don't interfere with touch scrolling. */
- if (button == GDK_BUTTON_PRIMARY && n_press == 2 && !self->single_click_mode)
- {
- activate_selection_on_click (self, modifiers & GDK_SHIFT_MASK);
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
- }
- else if (button == GDK_BUTTON_MIDDLE && n_press == 1)
- {
- /* Antecipate selection, if necessary, to activate it. */
- select_single_item_if_not_selected (self, item_model);
- activate_selection_on_click (self, TRUE);
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
- }
- else if (button == GDK_BUTTON_SECONDARY && n_press == 1)
- {
- gdouble view_x, view_y;
-
- /* Antecipate selection, if necessary, for the context menu. */
- select_single_item_if_not_selected (self, item_model);
-
- gtk_widget_translate_coordinates (event_widget, GTK_WIDGET (self),
- x, y,
- &view_x, &view_y);
- nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (self),
- view_x, view_y);
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
- }
-}
-
-static void
-on_item_click_released (GtkGestureClick *gesture,
- gint n_press,
- gdouble x,
- gdouble y,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
-
- if (self->activate_on_release)
- {
- GtkWidget *event_widget;
- NautilusViewItemModel *item_model;
- guint i;
-
- event_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
- item_model = nautilus_view_icon_item_ui_get_model (NAUTILUS_VIEW_ICON_ITEM_UI (event_widget));
- i = nautilus_view_model_get_index (self->model, item_model);
-
- /* Antecipate selection, enforcing single selection of target item. */
- gtk_selection_model_select_item (GTK_SELECTION_MODEL (self->model), i, TRUE);
-
- activate_selection_on_click (self, FALSE);
- }
-
- self->activate_on_release = FALSE;
- self->deny_background_click = FALSE;
-}
-
-static void
-on_item_click_stopped (GtkGestureClick *gesture,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
-
- self->activate_on_release = FALSE;
- self->deny_background_click = FALSE;
-}
-
-static void
-on_view_click_pressed (GtkGestureClick *gesture,
- gint n_press,
- gdouble x,
- gdouble y,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
- guint button;
- GdkModifierType modifiers;
- gboolean selection_mode;
-
- if (self->deny_background_click)
- {
- /* Item was clicked. */
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
- return;
- }
-
- /* Don't interfere with GtkGridView default selection handling when
- * holding Ctrl and Shift. */
- modifiers = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (gesture));
- selection_mode = (modifiers & (GDK_CONTROL_MASK | GDK_SHIFT_MASK));
- if (!selection_mode)
- {
- nautilus_view_set_selection (NAUTILUS_VIEW (self), NULL);
- }
-
- button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
- if (button == GDK_BUTTON_SECONDARY)
- {
- GtkWidget *event_widget;
- gdouble view_x;
- gdouble view_y;
-
- event_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
- gtk_widget_translate_coordinates (event_widget, GTK_WIDGET (self),
- x, y,
- &view_x, &view_y);
- nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (self),
- view_x, view_y);
- }
-}
-
-static void
-on_longpress_gesture_pressed_callback (GtkGestureLongPress *gesture,
- gdouble x,
- gdouble y,
- gpointer user_data)
-{
- NautilusViewIconController *self;
- GtkWidget *event_widget;
- gdouble view_x;
- gdouble view_y;
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
- event_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
-
- gtk_widget_translate_coordinates (event_widget,
- GTK_WIDGET (self),
- x, y, &view_x, &view_y);
- if (NAUTILUS_IS_VIEW_ICON_ITEM_UI (event_widget))
- {
- nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (self),
- view_x, view_y);
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
- }
- else
- {
- nautilus_view_set_selection (NAUTILUS_VIEW (self), NULL);
- nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (self),
- view_x, view_y);
- }
-}
-
-static int
-real_compare_files (NautilusFilesView *files_view,
- NautilusFile *file1,
- NautilusFile *file2)
-{
- GActionGroup *view_action_group;
- GAction *action;
- const gchar *target_name;
- gboolean reversed;
- const SortConstants *sort_constants;
- gboolean directories_first;
-
- view_action_group = nautilus_files_view_get_action_group (files_view);
- action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "sort");
- g_variant_get (g_action_get_state (action), "(&sb)", &target_name, &reversed);
- sort_constants = get_sorts_constants_from_metadata_text (target_name);
- directories_first = nautilus_files_view_should_sort_directories_first (files_view);
-
- return nautilus_file_compare_for_sort (file1, file2,
- sort_constants->sort_type,
- directories_first,
- reversed);
-}
-
-static void
-on_clipboard_contents_received (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- NautilusFilesView *files_view = NAUTILUS_FILES_VIEW (source_object);
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- NautilusClipboard *clip;
- NautilusViewItemModel *item;
-
- for (GList *l = self->cut_files; l != NULL; l = l->next)
- {
- item = nautilus_view_model_get_item_from_file (self->model, l->data);
- if (item != NULL)
- {
- nautilus_view_item_model_set_cut (item, FALSE);
- }
- }
- g_clear_list (&self->cut_files, g_object_unref);
-
- clip = nautilus_files_view_get_clipboard_finish (files_view, res, NULL);
- if (clip != NULL && nautilus_clipboard_is_cut (clip))
- {
- self->cut_files = g_list_copy_deep (nautilus_clipboard_peek_files (clip),
- (GCopyFunc) g_object_ref,
- NULL);
- }
-
- for (GList *l = self->cut_files; l != NULL; l = l->next)
- {
- item = nautilus_view_model_get_item_from_file (self->model, l->data);
- if (item != NULL)
- {
- nautilus_view_item_model_set_cut (item, TRUE);
- }
- }
-}
-
-static void
-update_clipboard_status (NautilusFilesView *files_view)
-{
- nautilus_files_view_get_clipboard_async (files_view,
- on_clipboard_contents_received,
- NULL);
-}
-
-static void
-on_clipboard_owner_changed (GdkClipboard *clipboard,
- gpointer user_data)
-{
- update_clipboard_status (NAUTILUS_FILES_VIEW (user_data));
-}
-
-
-static void
-real_end_loading (NautilusFilesView *files_view,
- gboolean all_files_seen)
-{
- update_clipboard_status (files_view);
-}
-
static guint
-get_first_visible_item (NautilusViewIconController *self)
+real_get_icon_size (NautilusListBase *files_model_view)
{
- guint n_items;
- gdouble scrolled_y;
-
- n_items = g_list_model_get_n_items (G_LIST_MODEL (self->model));
- scrolled_y = gtk_adjustment_get_value (self->vadjustment);
- for (guint i = 0; i < n_items; i++)
- {
- g_autoptr (NautilusViewItemModel) item = NULL;
- GtkWidget *item_ui;
-
- item = g_list_model_get_item (G_LIST_MODEL (self->model), i);
- item_ui = nautilus_view_item_model_get_item_ui (item);
- if (item_ui != NULL)
- {
- gdouble y;
-
- gtk_widget_translate_coordinates (item_ui, GTK_WIDGET (self->view_ui),
- 0, 0, NULL, &y);
- if (gtk_widget_is_visible (item_ui) && y >= scrolled_y)
- {
- return i;
- }
- }
- }
+ NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_model_view);
- return G_MAXUINT;
+ return get_icon_size_for_zoom_level (self->zoom_level);
}
-static char *
-real_get_first_visible_file (NautilusFilesView *files_view)
+static GtkWidget *
+real_get_view_ui (NautilusListBase *files_model_view)
{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- guint i;
- g_autoptr (NautilusViewItemModel) item = NULL;
- gchar *uri = NULL;
+ NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_model_view);
- i = get_first_visible_item (self);
- if (i < G_MAXUINT)
- {
- item = g_list_model_get_item (G_LIST_MODEL (self->model), i);
- uri = nautilus_file_get_uri (nautilus_view_item_model_get_file (item));
- }
- return uri;
+ return GTK_WIDGET (self->view_ui);
}
-typedef struct
-{
- NautilusViewIconController *view;
- char *uri;
-} ScrollToFileData;
-
static void
-scroll_to_file_data_free (ScrollToFileData *data)
+real_scroll_to_item (NautilusListBase *files_model_view,
+ guint position)
{
- g_free (data->uri);
- g_free (data);
-}
-
-static gboolean
-scroll_to_file_on_idle (ScrollToFileData *data)
-{
- NautilusViewIconController *self = data->view;
- g_autoptr (NautilusFile) file = NULL;
- NautilusViewItemModel *item;
- guint i;
-
- file = nautilus_file_get_existing_by_uri (data->uri);
- item = nautilus_view_model_get_item_from_file (self->model, file);
- i = nautilus_view_model_get_index (self->model, item);
+ NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_model_view);
gtk_widget_activate_action (GTK_WIDGET (self->view_ui),
"list.scroll-to-item",
"u",
- i);
-
- self->scroll_to_file_handle_id = 0;
- return G_SOURCE_REMOVE;
-}
-
-static void
-real_scroll_to_file (NautilusFilesView *files_view,
- const char *uri)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- ScrollToFileData *data;
- guint handle_id;
-
- /* Not exactly sure why, but the child widgets are not yet realized when
- * this is usually called (which is when view finishes loading. Maybe
- * because GtkFlowBox only generates children at the next GMainContext
- * iteration? Anyway, doing it on idle as low priority works. */
-
- data = g_new (ScrollToFileData, 1);
- data->view = self;
- data->uri = g_strdup (uri);
- handle_id = g_idle_add_full (G_PRIORITY_LOW,
- (GSourceFunc) scroll_to_file_on_idle,
- data,
- (GDestroyNotify) scroll_to_file_data_free);
- self->scroll_to_file_handle_id = handle_id;
+ position);
}
static void
real_sort_directories_first_changed (NautilusFilesView *files_view)
{
NautilusViewIconController *self;
+ NautilusViewModel *model;
g_autoptr (GtkCustomSorter) sorter = NULL;
self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
self->directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self));
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
sorter = gtk_custom_sorter_new (nautilus_view_icon_controller_sort, self, NULL);
- nautilus_view_model_set_sorter (self->model, GTK_SORTER (sorter));
+ nautilus_view_model_set_sorter (model, GTK_SORTER (sorter));
}
static void
@@ -1154,8 +265,8 @@ action_sort_order_changed (GSimpleAction *action,
gpointer user_data)
{
const gchar *target_name;
- const SortConstants *sort_constants;
- NautilusViewIconController *self;
+ NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
+ NautilusViewModel *model;
g_autoptr (GtkCustomSorter) sorter = NULL;
/* Don't resort if the action is in the same state as before */
@@ -1164,86 +275,25 @@ action_sort_order_changed (GSimpleAction *action,
return;
}
- self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
g_variant_get (value, "(&sb)", &target_name, &self->reversed);
- sort_constants = get_sorts_constants_from_metadata_text (target_name);
- self->sort_type = sort_constants->sort_type;
- self->directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self));
+ self->sort_type = get_sorts_type_from_metadata_text (target_name);
sorter = gtk_custom_sorter_new (nautilus_view_icon_controller_sort, self, NULL);
- nautilus_view_model_set_sorter (self->model, GTK_SORTER (sorter));
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
+ nautilus_view_model_set_sorter (model, GTK_SORTER (sorter));
set_directory_sort_metadata (nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self)),
- sort_constants,
+ target_name,
self->reversed);
g_simple_action_set_state (action, value);
}
-static void
-real_add_files (NautilusFilesView *files_view,
- GList *files)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- g_autoptr (GQueue) files_queue = NULL;
- g_autoptr (GQueue) item_models = NULL;
- gdouble adjustment_value;
-
- files_queue = convert_glist_to_queue (files);
- item_models = convert_files_to_item_models (self, files_queue);
- nautilus_view_model_add_items (self->model, item_models);
-
- /* GtkListBase anchoring doesn't cope well with our lazy loading.
- * Assuming that GtkListBase|list.scroll-to-item resets the anchor to 0, use
- * that as a workaround to prevent scrolling while we are at the top. */
- adjustment_value = gtk_adjustment_get_value (self->vadjustment);
- if (G_APPROX_VALUE (adjustment_value, 0.0, DBL_EPSILON))
- {
- gtk_widget_activate_action (GTK_WIDGET (self->view_ui), "list.scroll-to-item", "u", 0);
- }
-}
-
-
static guint
real_get_view_id (NautilusFilesView *files_view)
{
return NAUTILUS_VIEW_GRID_ID;
}
-static void
-real_select_first (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- g_autoptr (NautilusViewItemModel) item = NULL;
- NautilusFile *file;
- g_autoptr (GList) selection = NULL;
-
- item = NAUTILUS_VIEW_ITEM_MODEL (g_list_model_get_item (G_LIST_MODEL (self->model), 0));
- if (item == NULL)
- {
- return;
- }
- file = nautilus_view_item_model_get_file (item);
- selection = g_list_prepend (selection, file);
- nautilus_view_set_selection (NAUTILUS_VIEW (files_view), selection);
-}
-
-static void
-real_preview_selection_event (NautilusFilesView *files_view,
- GtkDirectionType direction)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- GtkMovementStep step;
- gint count;
- gboolean handled;
-
- step = (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN) ?
- GTK_MOVEMENT_DISPLAY_LINES : GTK_MOVEMENT_VISUAL_POSITIONS;
- count = (direction == GTK_DIR_RIGHT || direction == GTK_DIR_DOWN) ?
- 1 : -1;
-
- g_signal_emit_by_name (self->view_ui, "move-cursor", step, count, &handled);
-}
-
static void
action_zoom_to_level (GSimpleAction *action,
GVariant *state,
@@ -1272,119 +322,22 @@ on_captions_preferences_changed (NautilusViewIconController *self)
/* Hack: this relies on the assumption that NautilusViewIconItemUi updates
* captions whenever the icon size is set (even if it's the same value). */
- set_icon_size (self, get_icon_size_for_zoom_level (self->zoom_level));
-}
-
-static void
-on_default_sort_order_changed (NautilusViewIconController *self)
-{
- update_sort_order_from_metadata_and_preferences (self);
+ nautilus_list_base_set_icon_size (NAUTILUS_LIST_BASE (self),
+ get_icon_size_for_zoom_level (self->zoom_level));
}
static void
dispose (GObject *object)
{
- NautilusViewIconController *self;
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (object);
-
- g_clear_handle_id (&self->scroll_to_file_handle_id, g_source_remove);
- g_clear_handle_id (&self->prioritize_thumbnailing_handle_id, g_source_remove);
-
G_OBJECT_CLASS (nautilus_view_icon_controller_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (object);
-
- g_clear_list (&self->cut_files, g_object_unref);
-
G_OBJECT_CLASS (nautilus_view_icon_controller_parent_class)->finalize (object);
}
-static gboolean
-prioritize_thumbnailing_on_idle (NautilusViewIconController *self)
-{
- gdouble page_size;
- GtkWidget *first_visible_child;
- GtkWidget *next_child;
- guint first_index;
- guint next_index;
- gdouble y;
- guint last_index;
- g_autoptr (NautilusViewItemModel) first_item = NULL;
- NautilusFile *file;
-
- self->prioritize_thumbnailing_handle_id = 0;
-
- page_size = gtk_adjustment_get_page_size (self->vadjustment);
- first_index = get_first_visible_item (self);
- if (first_index == G_MAXUINT)
- {
- return G_SOURCE_REMOVE;
- }
-
- first_item = g_list_model_get_item (G_LIST_MODEL (self->model), first_index);
-
- first_visible_child = nautilus_view_item_model_get_item_ui (first_item);
-
- for (next_index = first_index + 1; next_index < g_list_model_get_n_items (G_LIST_MODEL (self->model));
next_index++)
- {
- g_autoptr (NautilusViewItemModel) next_item = NULL;
-
- next_item = g_list_model_get_item (G_LIST_MODEL (self->model), next_index);
- next_child = nautilus_view_item_model_get_item_ui (next_item);
- if (next_child == NULL)
- {
- break;
- }
- if (gtk_widget_translate_coordinates (next_child, first_visible_child,
- 0, 0, NULL, &y))
- {
- if (y > page_size)
- {
- break;
- }
- }
- }
- last_index = next_index - 1;
-
- /* Do the iteration in reverse to give higher priority to the top */
- for (gint i = 0; i <= last_index - first_index; i++)
- {
- g_autoptr (NautilusViewItemModel) item = NULL;
-
- item = g_list_model_get_item (G_LIST_MODEL (self->model), last_index - i);
- g_return_val_if_fail (item != NULL, G_SOURCE_REMOVE);
-
- file = nautilus_view_item_model_get_file (NAUTILUS_VIEW_ITEM_MODEL (item));
- if (file != NULL && nautilus_file_is_thumbnailing (file))
- {
- g_autofree gchar *uri = nautilus_file_get_uri (file);
- nautilus_thumbnail_prioritize (uri);
- }
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-on_vadjustment_changed (GtkAdjustment *adjustment,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
- guint handle_id;
-
- /* Schedule on idle to rate limit and to avoid delaying scrolling. */
- if (self->prioritize_thumbnailing_handle_id == 0)
- {
- handle_id = g_idle_add ((GSourceFunc) prioritize_thumbnailing_on_idle, self);
- self->prioritize_thumbnailing_handle_id = handle_id;
- }
-}
-
static void
bind_item_ui (GtkSignalListItemFactory *factory,
GtkListItem *listitem,
@@ -1396,11 +349,9 @@ bind_item_ui (GtkSignalListItemFactory *factory,
item_ui = gtk_list_item_get_child (listitem);
item_model = NAUTILUS_VIEW_ITEM_MODEL (gtk_list_item_get_item (listitem));
- nautilus_view_icon_item_ui_set_model (NAUTILUS_VIEW_ICON_ITEM_UI (item_ui),
- item_model);
nautilus_view_item_model_set_item_ui (item_model, item_ui);
- if (nautilus_view_icon_item_ui_once (NAUTILUS_VIEW_ICON_ITEM_UI (item_ui)))
+ if (nautilus_view_cell_once (NAUTILUS_VIEW_CELL (item_ui)))
{
GtkWidget *parent;
@@ -1422,13 +373,10 @@ unbind_item_ui (GtkSignalListItemFactory *factory,
GtkListItem *listitem,
gpointer user_data)
{
- NautilusViewIconItemUi *item_ui;
NautilusViewItemModel *item_model;
- item_ui = NAUTILUS_VIEW_ICON_ITEM_UI (gtk_list_item_get_child (listitem));
item_model = NAUTILUS_VIEW_ITEM_MODEL (gtk_list_item_get_item (listitem));
- nautilus_view_icon_item_ui_set_model (item_ui, NULL);
nautilus_view_item_model_set_item_ui (item_model, NULL);
}
@@ -1439,39 +387,28 @@ setup_item_ui (GtkSignalListItemFactory *factory,
{
NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
NautilusViewIconItemUi *item_ui;
- GtkEventController *controller;
- item_ui = nautilus_view_icon_item_ui_new ();
+ item_ui = nautilus_view_icon_item_ui_new (NAUTILUS_LIST_BASE (self));
+ setup_cell_common (listitem, NAUTILUS_VIEW_CELL (item_ui));
+
nautilus_view_item_ui_set_caption_attributes (item_ui, self->caption_attributes);
- gtk_list_item_set_child (listitem, GTK_WIDGET (item_ui));
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
- gtk_widget_add_controller (GTK_WIDGET (item_ui), controller);
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
- gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
- g_signal_connect (controller, "pressed", G_CALLBACK (on_item_click_pressed), self);
- g_signal_connect (controller, "released", G_CALLBACK (on_item_click_released), self);
- g_signal_connect (controller, "stopped", G_CALLBACK (on_item_click_stopped), self);
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
- gtk_widget_add_controller (GTK_WIDGET (item_ui), controller);
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
- gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (controller), TRUE);
- g_signal_connect (controller, "pressed", G_CALLBACK (on_longpress_gesture_pressed_callback), self);
}
static GtkGridView *
create_view_ui (NautilusViewIconController *self)
{
+ NautilusViewModel *model;
GtkListItemFactory *factory;
GtkWidget *widget;
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
+
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_item_ui), self);
g_signal_connect (factory, "bind", G_CALLBACK (bind_item_ui), self);
g_signal_connect (factory, "unbind", G_CALLBACK (unbind_item_ui), self);
- widget = gtk_grid_view_new (GTK_SELECTION_MODEL (self->model), factory);
+ widget = gtk_grid_view_new (GTK_SELECTION_MODEL (model), factory);
gtk_widget_set_focusable (widget, TRUE);
gtk_widget_set_valign (widget, GTK_ALIGN_START);
@@ -1499,130 +436,35 @@ const GActionEntry view_icon_actions[] =
{ "zoom-to-level", NULL, NULL, "100", action_zoom_to_level }
};
-static void
-constructed (GObject *object)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (object);
- GtkWidget *content_widget;
- GtkAdjustment *vadjustment;
- GActionGroup *view_action_group;
- GtkEventController *controller;
-
- content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (self));
- vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (content_widget));
-
- self->vadjustment = vadjustment;
- g_signal_connect (vadjustment, "changed", (GCallback) on_vadjustment_changed, self);
- g_signal_connect (vadjustment, "value-changed", (GCallback) on_vadjustment_changed, self);
-
- self->model = nautilus_view_model_new ();
-
- self->view_ui = create_view_ui (self);
- gtk_widget_show (GTK_WIDGET (self->view_ui));
-
- g_signal_connect_swapped (GTK_SELECTION_MODEL (self->model),
- "selection-changed",
- G_CALLBACK (nautilus_files_view_notify_selection_changed),
- NAUTILUS_FILES_VIEW (self));
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
- gtk_widget_add_controller (GTK_WIDGET (content_widget), controller);
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
- gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
- g_signal_connect (controller, "pressed",
- G_CALLBACK (on_view_click_pressed), self);
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
- gtk_widget_add_controller (GTK_WIDGET (self->view_ui), controller);
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
- gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (controller), TRUE);
- g_signal_connect (controller, "pressed",
- (GCallback) on_longpress_gesture_pressed_callback, self);
-
- gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (content_widget),
- GTK_WIDGET (self->view_ui));
-
- self->action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self));
- g_action_map_add_action_entries (G_ACTION_MAP (self->action_group),
- view_icon_actions,
- G_N_ELEMENTS (view_icon_actions),
- self);
-
- gtk_widget_show (GTK_WIDGET (self));
-
- view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self));
- g_action_map_add_action_entries (G_ACTION_MAP (view_action_group),
- view_icon_actions,
- G_N_ELEMENTS (view_icon_actions),
- self);
- self->zoom_level = get_default_zoom_level ();
- /* Keep the action synced with the actual value, so the toolbar can poll it */
- g_action_group_change_action_state (nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self)),
- "zoom-to-level", g_variant_new_int32 (self->zoom_level));
-}
-
static void
nautilus_view_icon_controller_class_init (NautilusViewIconControllerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NautilusFilesViewClass *files_view_class = NAUTILUS_FILES_VIEW_CLASS (klass);
+ NautilusListBaseClass *files_model_view_class = NAUTILUS_LIST_BASE_CLASS (klass);
object_class->dispose = dispose;
object_class->finalize = finalize;
- object_class->constructed = constructed;
- files_view_class->add_files = real_add_files;
- files_view_class->begin_loading = real_begin_loading;
files_view_class->bump_zoom_level = real_bump_zoom_level;
files_view_class->can_zoom_in = real_can_zoom_in;
files_view_class->can_zoom_out = real_can_zoom_out;
- files_view_class->click_policy_changed = real_click_policy_changed;
- files_view_class->clear = real_clear;
- files_view_class->file_changed = real_file_changed;
- files_view_class->get_selection = real_get_selection;
- /* TODO: remove this get_selection_for_file_transfer, this doesn't even
- * take into account we could us the view for recursive search :/
- * CanvasView has the same issue. */
- files_view_class->get_selection_for_file_transfer = real_get_selection;
- files_view_class->is_empty = real_is_empty;
- files_view_class->remove_file = real_remove_file;
- files_view_class->update_actions_state = real_update_actions_state;
- files_view_class->reveal_selection = real_reveal_selection;
- files_view_class->select_all = real_select_all;
- files_view_class->invert_selection = real_invert_selection;
- files_view_class->set_selection = real_set_selection;
- files_view_class->compare_files = real_compare_files;
files_view_class->sort_directories_first_changed = real_sort_directories_first_changed;
- files_view_class->end_file_changes = real_end_file_changes;
- files_view_class->end_loading = real_end_loading;
files_view_class->get_view_id = real_get_view_id;
- files_view_class->get_first_visible_file = real_get_first_visible_file;
- files_view_class->scroll_to_file = real_scroll_to_file;
- files_view_class->select_first = real_select_first;
files_view_class->restore_standard_zoom_level = real_restore_standard_zoom_level;
files_view_class->is_zoom_level_default = real_is_zoom_level_default;
- files_view_class->compute_rename_popover_pointing_to = real_compute_rename_popover_pointing_to;
- files_view_class->reveal_for_selection_context_menu = real_reveal_for_selection_context_menu;
- files_view_class->preview_selection_event = real_preview_selection_event;
+
+ files_model_view_class->get_icon_size = real_get_icon_size;
+ files_model_view_class->get_view_ui = real_get_view_ui;
+ files_model_view_class->scroll_to_item = real_scroll_to_item;
}
static void
nautilus_view_icon_controller_init (NautilusViewIconController *self)
{
- gtk_widget_add_css_class (GTK_WIDGET (self), "view");
- gtk_widget_add_css_class (GTK_WIDGET (self), "nautilus-grid-view");
- set_click_mode_from_settings (self);
+ GtkWidget *content_widget;
- g_signal_connect_object (nautilus_preferences,
- "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
- G_CALLBACK (on_default_sort_order_changed),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (nautilus_preferences,
- "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
- G_CALLBACK (on_default_sort_order_changed),
- self,
- G_CONNECT_SWAPPED);
+ gtk_widget_add_css_class (GTK_WIDGET (self), "nautilus-grid-view");
set_captions_from_preferences (self);
g_signal_connect_object (nautilus_icon_view_preferences,
@@ -1631,11 +473,26 @@ nautilus_view_icon_controller_init (NautilusViewIconController *self)
self,
G_CONNECT_SWAPPED);
- g_signal_connect_object (gdk_display_get_clipboard (gdk_display_get_default ()),
- "changed",
- G_CALLBACK (on_clipboard_owner_changed),
- self,
- 0);
+ content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (self));
+
+ self->view_ui = create_view_ui (self);
+ nautilus_list_base_setup_gestures (NAUTILUS_LIST_BASE (self));
+
+ gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (content_widget),
+ GTK_WIDGET (self->view_ui));
+
+ self->action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self));
+ g_action_map_add_action_entries (G_ACTION_MAP (self->action_group),
+ view_icon_actions,
+ G_N_ELEMENTS (view_icon_actions),
+ self);
+
+ self->directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self));
+
+ self->zoom_level = get_default_zoom_level ();
+ /* Keep the action synced with the actual value, so the toolbar can poll it */
+ g_action_group_change_action_state (nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self)),
+ "zoom-to-level", g_variant_new_int32 (self->zoom_level));
}
NautilusViewIconController *
diff --git a/src/nautilus-view-icon-controller.h b/src/nautilus-view-icon-controller.h
index be70c94bd..0dfa878e0 100644
--- a/src/nautilus-view-icon-controller.h
+++ b/src/nautilus-view-icon-controller.h
@@ -3,15 +3,14 @@
#include <glib.h>
#include <gtk/gtk.h>
-#include "nautilus-files-view.h"
+#include "nautilus-list-base.h"
#include "nautilus-window-slot.h"
-#include "nautilus-view-model.h"
G_BEGIN_DECLS
#define NAUTILUS_TYPE_VIEW_ICON_CONTROLLER (nautilus_view_icon_controller_get_type())
-G_DECLARE_FINAL_TYPE (NautilusViewIconController, nautilus_view_icon_controller, NAUTILUS,
VIEW_ICON_CONTROLLER, NautilusFilesView)
+G_DECLARE_FINAL_TYPE (NautilusViewIconController, nautilus_view_icon_controller, NAUTILUS,
VIEW_ICON_CONTROLLER, NautilusListBase)
NautilusViewIconController *nautilus_view_icon_controller_new (NautilusWindowSlot *slot);
diff --git a/src/nautilus-view-icon-item-ui.c b/src/nautilus-view-icon-item-ui.c
index d0ebff7b4..4c5897a89 100644
--- a/src/nautilus-view-icon-item-ui.c
+++ b/src/nautilus-view-icon-item-ui.c
@@ -1,13 +1,11 @@
#include "nautilus-view-icon-item-ui.h"
-#include "nautilus-view-item-model.h"
-#include "nautilus-file.h"
-#include "nautilus-thumbnails.h"
struct _NautilusViewIconItemUi
{
- GtkBox parent_instance;
+ NautilusViewCell parent_instance;
+
+ GSignalGroup *item_signal_group;
- NautilusViewItemModel *model;
GQuark *caption_attributes;
GtkWidget *fixed_height_box;
@@ -16,24 +14,16 @@ struct _NautilusViewIconItemUi
GtkWidget *first_caption;
GtkWidget *second_caption;
GtkWidget *third_caption;
-
- gboolean called_once;
};
-G_DEFINE_TYPE (NautilusViewIconItemUi, nautilus_view_icon_item_ui, GTK_TYPE_BOX)
-
-enum
-{
- PROP_0,
- PROP_MODEL,
- N_PROPS
-};
+G_DEFINE_TYPE (NautilusViewIconItemUi, nautilus_view_icon_item_ui, NAUTILUS_TYPE_VIEW_CELL)
#define EXTRA_WIDTH_FOR_TEXT 36
static void
update_icon (NautilusViewIconItemUi *self)
{
+ NautilusViewItemModel *item;
NautilusFileIconFlags flags;
g_autoptr (GdkPaintable) icon_paintable = NULL;
GtkStyleContext *style_context;
@@ -41,8 +31,10 @@ update_icon (NautilusViewIconItemUi *self)
guint icon_size;
g_autofree gchar *thumbnail_path = NULL;
- file = nautilus_view_item_model_get_file (self->model);
- icon_size = nautilus_view_item_model_get_icon_size (self->model);
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_model_get_file (item);
+ icon_size = nautilus_view_item_model_get_icon_size (item);
flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE |
NAUTILUS_FILE_ICON_FLAGS_USE_EMBLEMS |
@@ -76,6 +68,7 @@ update_icon (NautilusViewIconItemUi *self)
static void
update_captions (NautilusViewIconItemUi *self)
{
+ NautilusViewItemModel *item;
NautilusFile *file;
GtkWidget * const caption_labels[] =
{
@@ -85,7 +78,9 @@ update_captions (NautilusViewIconItemUi *self)
};
G_STATIC_ASSERT (G_N_ELEMENTS (caption_labels) == NAUTILUS_VIEW_ICON_N_CAPTIONS);
- file = nautilus_view_item_model_get_file (self->model);
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_model_get_file (item);
for (guint i = 0; i < NAUTILUS_VIEW_ICON_N_CAPTIONS; i++)
{
GQuark attribute_q = self->caption_attributes[i];
@@ -105,9 +100,12 @@ update_captions (NautilusViewIconItemUi *self)
static void
on_file_changed (NautilusViewIconItemUi *self)
{
+ NautilusViewItemModel *item;
NautilusFile *file;
- file = nautilus_view_item_model_get_file (self->model);
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_model_get_file (item);
update_icon (self);
@@ -117,25 +115,18 @@ on_file_changed (NautilusViewIconItemUi *self)
}
static void
-on_view_item_size_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+on_item_size_changed (NautilusViewIconItemUi *self)
{
- NautilusViewIconItemUi *self = NAUTILUS_VIEW_ICON_ITEM_UI (user_data);
-
update_icon (self);
update_captions (self);
}
static void
-on_view_item_is_cut_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+on_item_is_cut_changed (NautilusViewIconItemUi *self)
{
- NautilusViewIconItemUi *self = NAUTILUS_VIEW_ICON_ITEM_UI (user_data);
gboolean is_cut;
- g_object_get (object, "is-cut", &is_cut, NULL);
+ g_object_get (self, "is-cut", &is_cut, NULL);
if (is_cut)
{
gtk_widget_add_css_class (self->icon, "cut");
@@ -146,100 +137,15 @@ on_view_item_is_cut_changed (GObject *object,
}
}
-static void
-set_model (NautilusViewIconItemUi *self,
- NautilusViewItemModel *model);
-
static void
finalize (GObject *object)
{
NautilusViewIconItemUi *self = (NautilusViewIconItemUi *) object;
- set_model (self, NULL);
+ g_object_unref (self->item_signal_group);
G_OBJECT_CLASS (nautilus_view_icon_item_ui_parent_class)->finalize (object);
}
-static void
-get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- NautilusViewIconItemUi *self = NAUTILUS_VIEW_ICON_ITEM_UI (object);
-
- switch (prop_id)
- {
- case PROP_MODEL:
- {
- g_value_set_object (value, self->model);
- }
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-set_model (NautilusViewIconItemUi *self,
- NautilusViewItemModel *model)
-{
- NautilusFile *file;
-
- if (self->model == model)
- {
- return;
- }
-
- if (self->model != NULL)
- {
- g_signal_handlers_disconnect_by_data (self->model, self);
- g_clear_object (&self->model);
- }
-
- if (model == NULL)
- {
- return;
- }
-
- self->model = g_object_ref (model);
-
- file = nautilus_view_item_model_get_file (self->model);
-
- update_icon (self);
- gtk_label_set_text (GTK_LABEL (self->label),
- nautilus_file_get_display_name (file));
- update_captions (self);
-
- g_signal_connect (self->model, "notify::icon-size",
- (GCallback) on_view_item_size_changed, self);
- g_signal_connect (self->model, "notify::is-cut",
- (GCallback) on_view_item_is_cut_changed, self);
- g_signal_connect_swapped (self->model, "file-changed",
- (GCallback) on_file_changed, self);
-}
-
-static void
-set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- NautilusViewIconItemUi *self = NAUTILUS_VIEW_ICON_ITEM_UI (object);
-
- switch (prop_id)
- {
- case PROP_MODEL:
- {
- set_model (self, g_value_get_object (value));
- }
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
static void
nautilus_view_icon_item_ui_class_init (NautilusViewIconItemUiClass *klass)
{
@@ -247,16 +153,6 @@ nautilus_view_icon_item_ui_class_init (NautilusViewIconItemUiClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = finalize;
- object_class->get_property = get_property;
- object_class->set_property = set_property;
-
- g_object_class_install_property (object_class,
- PROP_MODEL,
- g_param_spec_object ("model",
- "Item model",
- "The item model that this UI reprensents",
- NAUTILUS_TYPE_VIEW_ITEM_MODEL,
- G_PARAM_READWRITE));
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/nautilus/ui/nautilus-view-icon-item-ui.ui");
@@ -273,6 +169,22 @@ nautilus_view_icon_item_ui_init (NautilusViewIconItemUi *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
+ /* Connect automatically to an item. */
+ self->item_signal_group = g_signal_group_new (NAUTILUS_TYPE_VIEW_ITEM_MODEL);
+ g_signal_group_connect_swapped (self->item_signal_group, "notify::icon-size",
+ (GCallback) on_item_size_changed, self);
+ g_signal_group_connect_swapped (self->item_signal_group, "notify::is-cut",
+ (GCallback) on_item_is_cut_changed, self);
+ g_signal_group_connect_swapped (self->item_signal_group, "file-changed",
+ (GCallback) on_file_changed, self);
+ g_signal_connect_object (self->item_signal_group, "bind",
+ (GCallback) on_file_changed, self,
+ G_CONNECT_SWAPPED);
+
+ g_object_bind_property (self, "item",
+ self->item_signal_group, "target",
+ G_BINDING_SYNC_CREATE);
+
#if PANGO_VERSION_CHECK (1, 44, 4)
{
PangoAttrList *attr_list;
@@ -288,26 +200,11 @@ nautilus_view_icon_item_ui_init (NautilusViewIconItemUi *self)
}
NautilusViewIconItemUi *
-nautilus_view_icon_item_ui_new (void)
-{
- return g_object_new (NAUTILUS_TYPE_VIEW_ICON_ITEM_UI, NULL);
-}
-
-void
-nautilus_view_icon_item_ui_set_model (NautilusViewIconItemUi *self,
- NautilusViewItemModel *model)
-{
- g_object_set (self, "model", model, NULL);
-}
-
-NautilusViewItemModel *
-nautilus_view_icon_item_ui_get_model (NautilusViewIconItemUi *self)
+nautilus_view_icon_item_ui_new (NautilusListBase *view)
{
- NautilusViewItemModel *model = NULL;
-
- g_object_get (self, "model", &model, NULL);
-
- return model;
+ return g_object_new (NAUTILUS_TYPE_VIEW_ICON_ITEM_UI,
+ "view", view,
+ NULL);
}
void
@@ -316,15 +213,3 @@ nautilus_view_item_ui_set_caption_attributes (NautilusViewIconItemUi *self,
{
self->caption_attributes = attrs;
}
-
-gboolean
-nautilus_view_icon_item_ui_once (NautilusViewIconItemUi *self)
-{
- if (self->called_once)
- {
- return FALSE;
- }
-
- self->called_once = TRUE;
- return TRUE;
-}
diff --git a/src/nautilus-view-icon-item-ui.h b/src/nautilus-view-icon-item-ui.h
index edae77dc8..5f6d1ad93 100644
--- a/src/nautilus-view-icon-item-ui.h
+++ b/src/nautilus-view-icon-item-ui.h
@@ -3,7 +3,7 @@
#include <glib.h>
#include <gtk/gtk.h>
-#include "nautilus-view-item-model.h"
+#include "nautilus-view-cell.h"
G_BEGIN_DECLS
@@ -17,14 +17,10 @@ enum
#define NAUTILUS_TYPE_VIEW_ICON_ITEM_UI (nautilus_view_icon_item_ui_get_type())
-G_DECLARE_FINAL_TYPE (NautilusViewIconItemUi, nautilus_view_icon_item_ui, NAUTILUS, VIEW_ICON_ITEM_UI,
GtkBox)
+G_DECLARE_FINAL_TYPE (NautilusViewIconItemUi, nautilus_view_icon_item_ui, NAUTILUS, VIEW_ICON_ITEM_UI,
NautilusViewCell)
-NautilusViewIconItemUi * nautilus_view_icon_item_ui_new (void);
-void nautilus_view_icon_item_ui_set_model (NautilusViewIconItemUi *self,
- NautilusViewItemModel *model);
-NautilusViewItemModel *nautilus_view_icon_item_ui_get_model (NautilusViewIconItemUi *self);
+NautilusViewIconItemUi * nautilus_view_icon_item_ui_new (NautilusListBase *view);
void nautilus_view_item_ui_set_caption_attributes (NautilusViewIconItemUi *self,
GQuark *attrs);
-gboolean nautilus_view_icon_item_ui_once (NautilusViewIconItemUi *self);
G_END_DECLS
diff --git a/src/nautilus-view-model.c b/src/nautilus-view-model.c
index 595d24c0f..3b7c793cd 100644
--- a/src/nautilus-view-model.c
+++ b/src/nautilus-view-model.c
@@ -174,7 +174,7 @@ get_property (GObject *object,
{
case PROP_SORTER:
{
- g_value_set_object (value, self->sorter);
+ g_value_set_object (value, nautilus_view_model_get_sorter (self));
}
break;
@@ -278,6 +278,12 @@ nautilus_view_model_new ()
return g_object_new (NAUTILUS_TYPE_VIEW_MODEL, NULL);
}
+GtkSorter *
+nautilus_view_model_get_sorter (NautilusViewModel *self)
+{
+ return self->sorter;
+}
+
void
nautilus_view_model_set_sorter (NautilusViewModel *self,
GtkSorter *sorter)
diff --git a/src/nautilus-view-model.h b/src/nautilus-view-model.h
index 1771cd6e2..d76c3987d 100644
--- a/src/nautilus-view-model.h
+++ b/src/nautilus-view-model.h
@@ -12,6 +12,7 @@ G_DECLARE_FINAL_TYPE (NautilusViewModel, nautilus_view_model, NAUTILUS, VIEW_MOD
NautilusViewModel * nautilus_view_model_new (void);
+GtkSorter *nautilus_view_model_get_sorter (NautilusViewModel *self);
void nautilus_view_model_set_sorter (NautilusViewModel *self,
GtkSorter *sorter);
NautilusViewItemModel * nautilus_view_model_get_item_from_file (NautilusViewModel *self,
diff --git a/src/resources/ui/nautilus-view-icon-item-ui.ui b/src/resources/ui/nautilus-view-icon-item-ui.ui
index 0b0f18d26..e614c538f 100644
--- a/src/resources/ui/nautilus-view-icon-item-ui.ui
+++ b/src/resources/ui/nautilus-view-icon-item-ui.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
- <template class="NautilusViewIconItemUi" parent="GtkBox">
+ <template class="NautilusViewIconItemUi" parent="NautilusViewCell">
<child>
<object class="AdwClamp">
<property name="maximum-size">0</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]