diff --git a/data/org.gnome.nautilus.gschema.xml b/data/org.gnome.nautilus.gschema.xml
index 90f63c488d2fd292fa69be8c1956f8fdc4f0340c..39a8ed753a256b412eec8f3e3d4e08f16183c91b 100644
--- a/data/org.gnome.nautilus.gschema.xml
+++ b/data/org.gnome.nautilus.gschema.xml
@@ -226,7 +226,7 @@
Default list view zoom level
- [ 'name', 'size', 'date_modified', 'starred' ]
+ [ 'name', 'size', 'date_modified' ]
Columns visible in list view
diff --git a/meson.build b/meson.build
index 154c7b76326d45b2e9be22e58f6e0b6acd54503c..7af5a3ef0bfc288ca6f8174f68f028b95c4173f2 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/po/POTFILES.in b/po/POTFILES.in
index cea948da64cc60f6ce270f4028d519fdca6088fb..19a277eebbe20e93ef836ff09db45ef0e53c316c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -61,7 +61,6 @@ src/nautilus-shell-search-provider.c
src/nautilus-special-location-bar.c
src/nautilus-toolbar.c
src/nautilus-trash-bar.c
-src/nautilus-tree-view-drag-dest.c
src/nautilus-ui-utilities.c
src/nautilus-vfs-file.c
src/nautilus-view.c
@@ -91,7 +90,7 @@ src/resources/ui/nautilus-starred-is-empty.ui
src/resources/ui/nautilus-toolbar.ui
src/resources/ui/nautilus-toolbar-view-menu.ui
src/resources/ui/nautilus-trash-is-empty.ui
-src/resources/ui/nautilus-view-icon-item-ui.ui
+src/resources/ui/nautilus-grid-cell.ui
src/resources/ui/nautilus-window.ui
src/gtk/nautilusgtkplacesview.c
src/gtk/nautilusgtkplacesviewrow.c
diff --git a/src/meson.build b/src/meson.build
index 35a0dce98e426b75cbdcf4e07d0af0c959819d7c..edcfe0d91f842870e7acd96ddfcce10056bfc8e7 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -83,17 +83,22 @@ libnautilus_sources = [
'nautilus-floating-bar.h',
'nautilus-freedesktop-dbus.c',
'nautilus-freedesktop-dbus.h',
- 'nautilus-list-model.c',
- 'nautilus-list-model.h',
+ 'nautilus-grid-cell.c',
+ 'nautilus-grid-cell.h',
+ 'nautilus-grid-view.c',
+ 'nautilus-grid-view.h',
+ 'nautilus-label-cell.c',
+ 'nautilus-label-cell.h',
+ 'nautilus-list-base.c',
+ 'nautilus-list-base.h',
'nautilus-list-view.c',
'nautilus-list-view.h',
- 'nautilus-list-view-private.h',
- 'nautilus-list-view-dnd.c',
- 'nautilus-list-view-dnd.h',
'nautilus-location-entry.c',
'nautilus-location-entry.h',
'nautilus-mime-actions.c',
'nautilus-mime-actions.h',
+ 'nautilus-name-cell.c',
+ 'nautilus-name-cell.h',
'nautilus-notebook.c',
'nautilus-notebook.h',
'nautilus-pathbar.c',
@@ -115,6 +120,8 @@ libnautilus_sources = [
'nautilus-self-check-functions.h',
'nautilus-shell-search-provider.c',
'nautilus-special-location-bar.c',
+ 'nautilus-star-cell.c',
+ 'nautilus-star-cell.h',
'nautilus-toolbar.c',
'nautilus-toolbar.h',
'nautilus-toolbar-menu-sections.h',
@@ -122,12 +129,10 @@ libnautilus_sources = [
'nautilus-trash-bar.h',
'nautilus-view.c',
'nautilus-view.h',
- 'nautilus-view-icon-controller.c',
- 'nautilus-view-icon-controller.h',
- 'nautilus-view-icon-item-ui.c',
- 'nautilus-view-icon-item-ui.h',
- 'nautilus-view-item-model.c',
- 'nautilus-view-item-model.h',
+ 'nautilus-view-cell.c',
+ 'nautilus-view-cell.h',
+ 'nautilus-view-item.c',
+ 'nautilus-view-item.h',
'nautilus-view-model.c',
'nautilus-view-model.h',
'nautilus-window-slot.c',
@@ -227,8 +232,6 @@ libnautilus_sources = [
'nautilus-thumbnails.h',
'nautilus-trash-monitor.c',
'nautilus-trash-monitor.h',
- 'nautilus-tree-view-drag-dest.c',
- 'nautilus-tree-view-drag-dest.h',
'nautilus-ui-utilities.c',
'nautilus-ui-utilities.h',
'nautilus-video-mime-types.h',
diff --git a/src/nautilus-column-chooser.c b/src/nautilus-column-chooser.c
index 3412fb1bdfa5594ce5409dfa386ff537aa0dd5d4..23aa5af5c5bab14f07ccb36d4ea0f73fc337d223 100644
--- a/src/nautilus-column-chooser.c
+++ b/src/nautilus-column-chooser.c
@@ -298,6 +298,12 @@ populate_tree (NautilusColumnChooser *chooser)
visible = TRUE;
sensitive = FALSE;
}
+ if (strcmp (name, "starred") == 0)
+ {
+ g_free (name);
+ g_free (label);
+ continue;
+ }
gtk_list_store_append (chooser->store, &iter);
gtk_list_store_set (chooser->store, &iter,
diff --git a/src/nautilus-directory-async.c b/src/nautilus-directory-async.c
index 5fa29ae91c2f1b1218f22d91ba260fda208a3dde..4899ea7b627e5a84ba9c016efd1e31b3aa41e167 100644
--- a/src/nautilus-directory-async.c
+++ b/src/nautilus-directory-async.c
@@ -3704,7 +3704,7 @@ thumbnail_loader_size_prepared (GdkPixbufLoader *loader,
aspect_ratio = ((double) width) / height;
/* cf. nautilus_file_get_icon() */
- max_thumbnail_size = NAUTILUS_GRID_ICON_SIZE_LARGEST * NAUTILUS_GRID_ICON_SIZE_STANDARD / NAUTILUS_GRID_ICON_SIZE_SMALL;
+ max_thumbnail_size = NAUTILUS_GRID_ICON_SIZE_EXTRA_LARGE * NAUTILUS_GRID_ICON_SIZE_MEDIUM / NAUTILUS_GRID_ICON_SIZE_SMALL;
if (MAX (width, height) > max_thumbnail_size)
{
if (width > height)
diff --git a/src/nautilus-dnd.c b/src/nautilus-dnd.c
index a1e9ff128d983ef50fd28d940fe330b049371542..b43e758b827d50c30528340e460adb6c3a12c022 100644
--- a/src/nautilus-dnd.c
+++ b/src/nautilus-dnd.c
@@ -33,7 +33,6 @@
#include
#include
#include "nautilus-file-utilities.h"
-#include
#include
#include
diff --git a/src/nautilus-enums.h b/src/nautilus-enums.h
index 4145ed3869b9122a946cdbc5318043882e52f9ae..2cb9b4c80f0e63d33e65a5e317dac2319ce1c4f3 100644
--- a/src/nautilus-enums.h
+++ b/src/nautilus-enums.h
@@ -30,36 +30,32 @@
typedef enum
{
- NAUTILUS_GRID_ICON_SIZE_SMALL = 48,
- NAUTILUS_GRID_ICON_SIZE_STANDARD = 64,
- NAUTILUS_GRID_ICON_SIZE_LARGE = 96,
- NAUTILUS_GRID_ICON_SIZE_LARGER = 128,
- NAUTILUS_GRID_ICON_SIZE_LARGEST = 256,
+ NAUTILUS_GRID_ICON_SIZE_SMALL = 48,
+ NAUTILUS_GRID_ICON_SIZE_MEDIUM = 96,
+ NAUTILUS_GRID_ICON_SIZE_LARGE = 168,
+ NAUTILUS_GRID_ICON_SIZE_EXTRA_LARGE = 256,
} NautilusGridIconSize;
typedef enum
{
NAUTILUS_GRID_ZOOM_LEVEL_SMALL,
- NAUTILUS_GRID_ZOOM_LEVEL_STANDARD,
+ NAUTILUS_GRID_ZOOM_LEVEL_MEDIUM,
NAUTILUS_GRID_ZOOM_LEVEL_LARGE,
- NAUTILUS_GRID_ZOOM_LEVEL_LARGER,
- NAUTILUS_GRID_ZOOM_LEVEL_LARGEST,
+ NAUTILUS_GRID_ZOOM_LEVEL_EXTRA_LARGE,
} NautilusGridZoomLevel;
typedef enum
{
- NAUTILUS_LIST_ICON_SIZE_SMALL = 16,
- NAUTILUS_LIST_ICON_SIZE_STANDARD = 32,
- NAUTILUS_LIST_ICON_SIZE_LARGE = 48,
- NAUTILUS_LIST_ICON_SIZE_LARGER = 64,
+ NAUTILUS_LIST_ICON_SIZE_SMALL = 16,
+ NAUTILUS_LIST_ICON_SIZE_MEDIUM = 32,
+ NAUTILUS_LIST_ICON_SIZE_LARGE = 64,
} NautilusListIconSize;
typedef enum
{
NAUTILUS_LIST_ZOOM_LEVEL_SMALL,
- NAUTILUS_LIST_ZOOM_LEVEL_STANDARD,
+ NAUTILUS_LIST_ZOOM_LEVEL_MEDIUM,
NAUTILUS_LIST_ZOOM_LEVEL_LARGE,
- NAUTILUS_LIST_ZOOM_LEVEL_LARGER,
} NautilusListZoomLevel;
typedef enum
diff --git a/src/nautilus-file.c b/src/nautilus-file.c
index 4d3d4a74bd1e4f1ffd2542adb3457a6fcafa53f6..5bdc0e125f73292b2f7ffe5b1adf9c2c05d6d8b5 100644
--- a/src/nautilus-file.c
+++ b/src/nautilus-file.c
@@ -5216,7 +5216,7 @@ nautilus_file_get_thumbnail_icon (NautilusFile *file,
}
else
{
- modified_size = size * scale * NAUTILUS_GRID_ICON_SIZE_STANDARD / NAUTILUS_GRID_ICON_SIZE_SMALL;
+ modified_size = size * scale * NAUTILUS_GRID_ICON_SIZE_MEDIUM / NAUTILUS_GRID_ICON_SIZE_SMALL;
}
if (file->details->thumbnail)
@@ -5226,7 +5226,7 @@ nautilus_file_get_thumbnail_icon (NautilusFile *file,
s = MAX (w, h);
/* Don't scale up small thumbnails in the standard view */
- if (s <= NAUTILUS_GRID_ICON_SIZE_STANDARD)
+ if (s <= NAUTILUS_GRID_ICON_SIZE_MEDIUM)
{
thumb_scale = (double) size / NAUTILUS_GRID_ICON_SIZE_SMALL;
}
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index ba08f22546f440eb45869da6689170b14714df27..5c8729c307e0f7bba0bdb669801d5f4949050ebe 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -86,7 +86,7 @@
#include "nautilus-trash-monitor.h"
#include "nautilus-ui-utilities.h"
#include "nautilus-view.h"
-#include "nautilus-view-icon-controller.h"
+#include "nautilus-grid-view.h"
#include "nautilus-window.h"
#include "nautilus-tracker-utilities.h"
@@ -3718,7 +3718,7 @@ done_loading (NautilusFilesView *view,
if (do_reveal)
{
- if (NAUTILUS_IS_LIST_VIEW (view) || NAUTILUS_IS_VIEW_ICON_CONTROLLER (view))
+ if (NAUTILUS_IS_LIST_VIEW (view) || NAUTILUS_IS_GRID_VIEW (view))
{
/* HACK: We should be able to directly call reveal_selection here,
* but at this point the GtkTreeView hasn't allocated the new nodes
@@ -8052,20 +8052,26 @@ nautilus_files_view_reset_view_menu (NautilusFilesView *view)
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
NautilusFile *file;
GMenuModel *sort_section = priv->toolbar_menu_sections->sort_section;
- const gchar *trashed_action;
+ const gchar *action;
gint i;
file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (view));
- /* When not in Trash, set an inexistant action to hide the menu item. This
- * works under the assumptiont that the menu item has its "hidden-when"
- * attribute set to "action-disabled", and that an inexistant action is
- * treated as a disabled action. */
- trashed_action = nautilus_file_is_in_trash (file) ? "view.sort" : "doesnt-exist";
- i = nautilus_g_menu_model_find_by_string (sort_section, "target", "trash-time");
- g_return_if_fail (i != -1);
- nautilus_g_menu_replace_string_in_item (G_MENU (sort_section), i,
- "action", trashed_action);
+ /* When not in the special location, set an inexistant action to hide the
+ * menu item. This works under the assumptiont that the menu item has its
+ * "hidden-when" attribute set to "action-disabled", and that an inexistant
+ * action is treated as a disabled action. */
+ action = nautilus_file_is_in_trash (file) ? "view.sort" : "doesnt-exist";
+ i = nautilus_g_menu_model_find_by_string (sort_section, "nautilus-menu-item", "last_trashed");
+ nautilus_g_menu_replace_string_in_item (G_MENU (sort_section), i, "action", action);
+
+ action = nautilus_file_is_in_recent (file) ? "view.sort" : "doesnt-exist";
+ i = nautilus_g_menu_model_find_by_string (sort_section, "nautilus-menu-item", "recency");
+ nautilus_g_menu_replace_string_in_item (G_MENU (sort_section), i, "action", action);
+
+ action = nautilus_file_is_in_search (file) ? "view.sort" : "doesnt-exist";
+ i = nautilus_g_menu_model_find_by_string (sort_section, "nautilus-menu-item", "relevance");
+ nautilus_g_menu_replace_string_in_item (G_MENU (sort_section), i, "action", action);
}
/* Convenience function to reset the menus owned by the view but managed on
@@ -9605,13 +9611,13 @@ nautilus_files_view_new (guint id,
{
case NAUTILUS_VIEW_GRID_ID:
{
- view = NAUTILUS_FILES_VIEW (nautilus_view_icon_controller_new (slot));
+ view = NAUTILUS_FILES_VIEW (nautilus_grid_view_new (slot));
}
break;
case NAUTILUS_VIEW_LIST_ID:
{
- view = nautilus_list_view_new (slot);
+ view = NAUTILUS_FILES_VIEW (nautilus_list_view_new (slot));
}
break;
}
diff --git a/src/nautilus-grid-cell.c b/src/nautilus-grid-cell.c
new file mode 100644
index 0000000000000000000000000000000000000000..426a2c2a8459a88ed2fc4c626ee1bd2583138839
--- /dev/null
+++ b/src/nautilus-grid-cell.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "nautilus-grid-cell.h"
+
+struct _NautilusGridCell
+{
+ NautilusViewCell parent_instance;
+
+ GSignalGroup *item_signal_group;
+
+ GQuark *caption_attributes;
+
+ GtkWidget *fixed_height_box;
+ GtkWidget *icon;
+ GtkWidget *label;
+ GtkWidget *first_caption;
+ GtkWidget *second_caption;
+ GtkWidget *third_caption;
+};
+
+G_DEFINE_TYPE (NautilusGridCell, nautilus_grid_cell, NAUTILUS_TYPE_VIEW_CELL)
+
+#define EXTRA_WIDTH_FOR_TEXT 36
+
+static void
+update_icon (NautilusGridCell *self)
+{
+ NautilusViewItem *item;
+ NautilusFileIconFlags flags;
+ g_autoptr (GdkPaintable) icon_paintable = NULL;
+ GtkStyleContext *style_context;
+ NautilusFile *file;
+ guint icon_size;
+ g_autofree gchar *thumbnail_path = NULL;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_get_file (item);
+ icon_size = nautilus_view_item_get_icon_size (item);
+ flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
+ NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE |
+ NAUTILUS_FILE_ICON_FLAGS_USE_EMBLEMS |
+ NAUTILUS_FILE_ICON_FLAGS_USE_ONE_EMBLEM;
+
+ icon_paintable = nautilus_file_get_icon_paintable (file, icon_size, 1, flags);
+ gtk_picture_set_paintable (GTK_PICTURE (self->icon), icon_paintable);
+
+ /* Set the same height and width for all icons regardless of aspect ratio.
+ */
+ gtk_widget_set_size_request (self->fixed_height_box, icon_size, icon_size);
+ if (icon_size < NAUTILUS_GRID_ICON_SIZE_EXTRA_LARGE)
+ {
+ int extra_margins = 0.5 * EXTRA_WIDTH_FOR_TEXT;
+ gtk_widget_set_margin_start (self->fixed_height_box, extra_margins);
+ gtk_widget_set_margin_end (self->fixed_height_box, extra_margins);
+ }
+ style_context = gtk_widget_get_style_context (self->icon);
+ thumbnail_path = nautilus_file_get_thumbnail_path (file);
+ if (thumbnail_path != NULL &&
+ nautilus_file_should_show_thumbnail (file))
+ {
+ gtk_style_context_add_class (style_context, "thumbnail");
+ }
+ else
+ {
+ gtk_style_context_remove_class (style_context, "thumbnail");
+ }
+}
+
+static void
+update_captions (NautilusGridCell *self)
+{
+ NautilusViewItem *item;
+ NautilusFile *file;
+ GtkWidget * const caption_labels[] =
+ {
+ self->first_caption,
+ self->second_caption,
+ self->third_caption
+ };
+ G_STATIC_ASSERT (G_N_ELEMENTS (caption_labels) == NAUTILUS_GRID_CELL_N_CAPTIONS);
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_get_file (item);
+ for (guint i = 0; i < NAUTILUS_GRID_CELL_N_CAPTIONS; i++)
+ {
+ GQuark attribute_q = self->caption_attributes[i];
+ gboolean show_caption;
+
+ show_caption = (attribute_q != 0);
+ gtk_widget_set_visible (caption_labels[i], show_caption);
+ if (show_caption)
+ {
+ g_autofree gchar *string = NULL;
+ string = nautilus_file_get_string_attribute_q (file, attribute_q);
+ gtk_label_set_text (GTK_LABEL (caption_labels[i]), string);
+ }
+ }
+}
+
+static void
+on_file_changed (NautilusGridCell *self)
+{
+ NautilusViewItem *item;
+ NautilusFile *file;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_get_file (item);
+
+ update_icon (self);
+
+ gtk_label_set_text (GTK_LABEL (self->label),
+ nautilus_file_get_display_name (file));
+ update_captions (self);
+}
+
+static void
+on_item_size_changed (NautilusGridCell *self)
+{
+ update_icon (self);
+ update_captions (self);
+}
+
+static void
+on_item_is_cut_changed (NautilusGridCell *self)
+{
+ gboolean is_cut;
+
+ g_object_get (nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self)),
+ "is-cut", &is_cut,
+ NULL);
+ if (is_cut)
+ {
+ gtk_widget_add_css_class (self->icon, "cut");
+ }
+ else
+ {
+ gtk_widget_remove_css_class (self->icon, "cut");
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ NautilusGridCell *self = (NautilusGridCell *) object;
+
+ g_object_unref (self->item_signal_group);
+ G_OBJECT_CLASS (nautilus_grid_cell_parent_class)->finalize (object);
+}
+
+static void
+nautilus_grid_cell_class_init (NautilusGridCellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = finalize;
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/ui/nautilus-grid-cell.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, NautilusGridCell, fixed_height_box);
+ gtk_widget_class_bind_template_child (widget_class, NautilusGridCell, icon);
+ gtk_widget_class_bind_template_child (widget_class, NautilusGridCell, label);
+ gtk_widget_class_bind_template_child (widget_class, NautilusGridCell, first_caption);
+ gtk_widget_class_bind_template_child (widget_class, NautilusGridCell, second_caption);
+ gtk_widget_class_bind_template_child (widget_class, NautilusGridCell, third_caption);
+}
+
+static void
+nautilus_grid_cell_init (NautilusGridCell *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);
+ 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;
+
+ /* GTK4 TODO: This attribute is set in the UI file but GTK 3 ignores it.
+ * Remove this block after the switch to GTK 4. */
+ attr_list = pango_attr_list_new ();
+ pango_attr_list_insert (attr_list, pango_attr_insert_hyphens_new (FALSE));
+ gtk_label_set_attributes (GTK_LABEL (self->label), attr_list);
+ pango_attr_list_unref (attr_list);
+ }
+#endif
+}
+
+NautilusGridCell *
+nautilus_grid_cell_new (NautilusListBase *view)
+{
+ return g_object_new (NAUTILUS_TYPE_GRID_CELL,
+ "view", view,
+ NULL);
+}
+
+void
+nautilus_grid_cell_set_caption_attributes (NautilusGridCell *self,
+ GQuark *attrs)
+{
+ self->caption_attributes = attrs;
+}
diff --git a/src/nautilus-grid-cell.h b/src/nautilus-grid-cell.h
new file mode 100644
index 0000000000000000000000000000000000000000..52da1f81c38e533ed6f8bb65ba4bac2548edf217
--- /dev/null
+++ b/src/nautilus-grid-cell.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "nautilus-view-cell.h"
+
+G_BEGIN_DECLS
+
+enum
+{
+ NAUTILUS_GRID_CELL_FIRST_CAPTION,
+ NAUTILUS_GRID_CELL_SECOND_CAPTION,
+ NAUTILUS_GRID_CELL_THIRD_CAPTION,
+ NAUTILUS_GRID_CELL_N_CAPTIONS
+};
+
+#define NAUTILUS_TYPE_GRID_CELL (nautilus_grid_cell_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusGridCell, nautilus_grid_cell, NAUTILUS, GRID_CELL, NautilusViewCell)
+
+NautilusGridCell * nautilus_grid_cell_new (NautilusListBase *view);
+void nautilus_grid_cell_set_caption_attributes (NautilusGridCell *self,
+ GQuark *attrs);
+
+G_END_DECLS
diff --git a/src/nautilus-grid-view.c b/src/nautilus-grid-view.c
new file mode 100644
index 0000000000000000000000000000000000000000..926f5042e3c35c9039743b211573d4a7ec1178b5
--- /dev/null
+++ b/src/nautilus-grid-view.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "nautilus-list-base-private.h"
+#include "nautilus-grid-view.h"
+
+#include "nautilus-grid-cell.h"
+#include "nautilus-global-preferences.h"
+
+struct _NautilusGridView
+{
+ NautilusListBase parent_instance;
+
+ GtkGridView *view_ui;
+
+ GActionGroup *action_group;
+ gint zoom_level;
+
+ gboolean directories_first;
+
+ GQuark caption_attributes[NAUTILUS_GRID_CELL_N_CAPTIONS];
+
+ NautilusFileSortType sort_type;
+ gboolean reversed;
+};
+
+G_DEFINE_TYPE (NautilusGridView, nautilus_grid_view, NAUTILUS_TYPE_LIST_BASE)
+
+static guint get_icon_size_for_zoom_level (NautilusGridZoomLevel zoom_level);
+
+static gint
+nautilus_grid_view_sort (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
+{
+ NautilusGridView *self = user_data;
+ NautilusFile *file_a;
+ NautilusFile *file_b;
+
+ file_a = nautilus_view_item_get_file (NAUTILUS_VIEW_ITEM ((gpointer) a));
+ file_b = nautilus_view_item_get_file (NAUTILUS_VIEW_ITEM ((gpointer) b));
+
+ return nautilus_file_compare_for_sort (file_a, file_b,
+ self->sort_type,
+ self->directories_first,
+ self->reversed);
+}
+
+static void
+real_bump_zoom_level (NautilusFilesView *files_view,
+ int zoom_increment)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (files_view);
+ NautilusGridZoomLevel new_level;
+
+ new_level = self->zoom_level + zoom_increment;
+
+ if (new_level >= NAUTILUS_GRID_ZOOM_LEVEL_SMALL &&
+ new_level <= NAUTILUS_GRID_ZOOM_LEVEL_EXTRA_LARGE)
+ {
+ g_action_group_change_action_state (self->action_group,
+ "zoom-to-level",
+ g_variant_new_int32 (new_level));
+ }
+}
+
+static guint
+get_icon_size_for_zoom_level (NautilusGridZoomLevel zoom_level)
+{
+ switch (zoom_level)
+ {
+ case NAUTILUS_GRID_ZOOM_LEVEL_SMALL:
+ {
+ return NAUTILUS_GRID_ICON_SIZE_SMALL;
+ }
+ break;
+
+ case NAUTILUS_GRID_ZOOM_LEVEL_MEDIUM:
+ {
+ return NAUTILUS_GRID_ICON_SIZE_MEDIUM;
+ }
+ break;
+
+ case NAUTILUS_GRID_ZOOM_LEVEL_LARGE:
+ {
+ return NAUTILUS_GRID_ICON_SIZE_LARGE;
+ }
+ break;
+
+ case NAUTILUS_GRID_ZOOM_LEVEL_EXTRA_LARGE:
+ {
+ return NAUTILUS_GRID_ICON_SIZE_EXTRA_LARGE;
+ }
+ break;
+ }
+ g_return_val_if_reached (NAUTILUS_GRID_ICON_SIZE_MEDIUM);
+}
+
+static gint
+get_default_zoom_level (void)
+{
+ NautilusGridZoomLevel default_zoom_level;
+
+ default_zoom_level = g_settings_get_enum (nautilus_icon_view_preferences,
+ NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL);
+
+ /* Sanitize preference value */
+ return CLAMP (default_zoom_level,
+ NAUTILUS_GRID_ZOOM_LEVEL_SMALL,
+ NAUTILUS_GRID_ZOOM_LEVEL_EXTRA_LARGE);
+}
+
+static void
+set_captions_from_preferences (NautilusGridView *self)
+{
+ g_auto (GStrv) value = NULL;
+ gint n_captions_for_zoom_level;
+
+ value = g_settings_get_strv (nautilus_icon_view_preferences,
+ NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS);
+
+ /* Set a celling on the number of captions depending on the zoom level. */
+ n_captions_for_zoom_level = MIN (self->zoom_level,
+ G_N_ELEMENTS (self->caption_attributes));
+
+ /* Reset array to zeros beforehand, as we may not refill all elements. */
+ memset (&self->caption_attributes, 0, sizeof (self->caption_attributes));
+ for (gint i = 0, quark_i = 0;
+ value[i] != NULL && quark_i < n_captions_for_zoom_level;
+ i++)
+ {
+ if (g_strcmp0 (value[i], "none") == 0)
+ {
+ continue;
+ }
+
+ /* Convert to quarks in advance, otherwise each NautilusFile attribute
+ * getter would call g_quark_from_string() once for each file. */
+ self->caption_attributes[quark_i] = g_quark_from_string (value[i]);
+ quark_i++;
+ }
+}
+
+static void
+set_zoom_level (NautilusGridView *self,
+ guint new_level)
+{
+ self->zoom_level = new_level;
+
+ /* The zoom level may change how many captions are allowed. Update it before
+ * setting the icon size, under the assumption that NautilusGridCell
+ * updates captions whenever the icon size is set*/
+ set_captions_from_preferences (self);
+
+ 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));
+}
+
+static void
+real_restore_standard_zoom_level (NautilusFilesView *files_view)
+{
+ NautilusGridView *self;
+
+ self = NAUTILUS_GRID_VIEW (files_view);
+ g_action_group_change_action_state (self->action_group,
+ "zoom-to-level",
+ g_variant_new_int32 (NAUTILUS_GRID_ZOOM_LEVEL_MEDIUM));
+}
+
+static gboolean
+real_is_zoom_level_default (NautilusFilesView *files_view)
+{
+ NautilusGridView *self;
+ guint icon_size;
+
+ self = NAUTILUS_GRID_VIEW (files_view);
+ icon_size = get_icon_size_for_zoom_level (self->zoom_level);
+
+ return icon_size == NAUTILUS_GRID_ICON_SIZE_MEDIUM;
+}
+
+static gboolean
+real_can_zoom_in (NautilusFilesView *files_view)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (files_view);
+
+ return self->zoom_level < NAUTILUS_GRID_ZOOM_LEVEL_EXTRA_LARGE;
+}
+
+static gboolean
+real_can_zoom_out (NautilusFilesView *files_view)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (files_view);
+
+ return self->zoom_level > NAUTILUS_GRID_ZOOM_LEVEL_SMALL;
+}
+
+/* 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
+ * GtkGridView does (as one of widget subclassing's goal is to modify the parent
+ * class's behavior), while claiming the click gestures, so it means GtkGridView
+ * will never react to a click event to emit this signal. So we should be pretty
+ * safe here with regards to our custom item click handling.
+ */
+static void
+on_grid_view_item_activated (GtkGridView *grid_view,
+ guint position,
+ gpointer user_data)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (user_data);
+
+ nautilus_files_view_activate_selection (NAUTILUS_FILES_VIEW (self));
+}
+
+static guint
+real_get_icon_size (NautilusListBase *files_model_view)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (files_model_view);
+
+ return get_icon_size_for_zoom_level (self->zoom_level);
+}
+
+static GtkWidget *
+real_get_view_ui (NautilusListBase *files_model_view)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (files_model_view);
+
+ return GTK_WIDGET (self->view_ui);
+}
+
+static void
+real_scroll_to_item (NautilusListBase *files_model_view,
+ guint position)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (files_model_view);
+
+ gtk_widget_activate_action (GTK_WIDGET (self->view_ui),
+ "list.scroll-to-item",
+ "u",
+ position);
+}
+
+static void
+real_sort_directories_first_changed (NautilusFilesView *files_view)
+{
+ NautilusGridView *self;
+ NautilusViewModel *model;
+ g_autoptr (GtkCustomSorter) sorter = NULL;
+
+ self = NAUTILUS_GRID_VIEW (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_grid_view_sort, self, NULL);
+ nautilus_view_model_set_sorter (model, GTK_SORTER (sorter));
+}
+
+static void
+action_sort_order_changed (GSimpleAction *action,
+ GVariant *value,
+ gpointer user_data)
+{
+ const gchar *target_name;
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (user_data);
+ NautilusViewModel *model;
+ g_autoptr (GtkCustomSorter) sorter = NULL;
+
+ /* Don't resort if the action is in the same state as before */
+ if (g_variant_equal (value, g_action_get_state (G_ACTION (action))))
+ {
+ return;
+ }
+
+ g_variant_get (value, "(&sb)", &target_name, &self->reversed);
+ self->sort_type = get_sorts_type_from_metadata_text (target_name);
+
+ sorter = gtk_custom_sorter_new (nautilus_grid_view_sort, self, NULL);
+ 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)),
+ target_name,
+ self->reversed);
+
+ g_simple_action_set_state (action, value);
+}
+
+static guint
+real_get_view_id (NautilusFilesView *files_view)
+{
+ return NAUTILUS_VIEW_GRID_ID;
+}
+
+static void
+action_zoom_to_level (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (user_data);
+ int zoom_level;
+
+ zoom_level = g_variant_get_int32 (state);
+ set_zoom_level (self, zoom_level);
+ g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
+
+ if (g_settings_get_enum (nautilus_icon_view_preferences,
+ NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL) != zoom_level)
+ {
+ g_settings_set_enum (nautilus_icon_view_preferences,
+ NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
+ zoom_level);
+ }
+}
+
+static void
+on_captions_preferences_changed (NautilusGridView *self)
+{
+ set_captions_from_preferences (self);
+
+ /* Hack: this relies on the assumption that NautilusGridCell updates
+ * captions whenever the icon size is set (even if it's the same value). */
+ nautilus_list_base_set_icon_size (NAUTILUS_LIST_BASE (self),
+ get_icon_size_for_zoom_level (self->zoom_level));
+}
+
+static void
+dispose (GObject *object)
+{
+ G_OBJECT_CLASS (nautilus_grid_view_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+ G_OBJECT_CLASS (nautilus_grid_view_parent_class)->finalize (object);
+}
+
+static void
+bind_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
+{
+ GtkWidget *cell;
+ NautilusViewItem *item;
+
+ cell = gtk_list_item_get_child (listitem);
+ item = NAUTILUS_VIEW_ITEM (gtk_list_item_get_item (listitem));
+
+ nautilus_view_item_set_item_ui (item, cell);
+
+ if (nautilus_view_cell_once (NAUTILUS_VIEW_CELL (cell)))
+ {
+ GtkWidget *parent;
+
+ /* At the time of ::setup emission, the item ui has got no parent yet,
+ * that's why we need to complete the widget setup process here, on the
+ * first time ::bind is emitted. */
+ parent = gtk_widget_get_parent (cell);
+ gtk_widget_set_halign (parent, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign (parent, GTK_ALIGN_START);
+ gtk_widget_set_margin_top (parent, 3);
+ gtk_widget_set_margin_bottom (parent, 3);
+ gtk_widget_set_margin_start (parent, 3);
+ gtk_widget_set_margin_end (parent, 3);
+ }
+}
+
+static void
+unbind_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
+{
+ NautilusViewItem *item;
+
+ item = NAUTILUS_VIEW_ITEM (gtk_list_item_get_item (listitem));
+
+ nautilus_view_item_set_item_ui (item, NULL);
+}
+
+static void
+setup_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
+{
+ NautilusGridView *self = NAUTILUS_GRID_VIEW (user_data);
+ NautilusGridCell *cell;
+
+ cell = nautilus_grid_cell_new (NAUTILUS_LIST_BASE (self));
+ setup_cell_common (listitem, NAUTILUS_VIEW_CELL (cell));
+
+ nautilus_grid_cell_set_caption_attributes (cell, self->caption_attributes);
+}
+
+static GtkGridView *
+create_view_ui (NautilusGridView *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_cell), self);
+ g_signal_connect (factory, "bind", G_CALLBACK (bind_cell), self);
+ g_signal_connect (factory, "unbind", G_CALLBACK (unbind_cell), self);
+
+ widget = gtk_grid_view_new (GTK_SELECTION_MODEL (model), factory);
+ gtk_widget_set_focusable (widget, TRUE);
+ gtk_widget_set_valign (widget, GTK_ALIGN_START);
+
+ /* We don't use the built-in child activation feature for clicks because it
+ * doesn't fill all our needs nor does it match our expected behavior.
+ * Instead, we roll our own event handling and double/single click mode.
+ * However, GtkGridView:single-click-activate has other effects besides
+ * activation, as it affects the selection behavior as well (e.g. selects on
+ * hover). Setting it to FALSE gives us the expected behavior. */
+ gtk_grid_view_set_single_click_activate (GTK_GRID_VIEW (widget), FALSE);
+ gtk_grid_view_set_max_columns (GTK_GRID_VIEW (widget), 20);
+ gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (widget), TRUE);
+
+ /* While we don't want to use GTK's click activation, we'll let it handle
+ * the key activation part (with Enter).
+ */
+ g_signal_connect (widget, "activate", G_CALLBACK (on_grid_view_item_activated), self);
+
+ return GTK_GRID_VIEW (widget);
+}
+
+const GActionEntry view_icon_actions[] =
+{
+ { "sort", NULL, "(sb)", "('invalid',false)", action_sort_order_changed },
+ { "zoom-to-level", NULL, NULL, "100", action_zoom_to_level }
+};
+
+static void
+nautilus_grid_view_class_init (NautilusGridViewClass *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;
+
+ 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->sort_directories_first_changed = real_sort_directories_first_changed;
+ files_view_class->get_view_id = real_get_view_id;
+ 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_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_grid_view_init (NautilusGridView *self)
+{
+ GtkWidget *content_widget;
+
+ gtk_widget_add_css_class (GTK_WIDGET (self), "nautilus-grid-view");
+
+ set_captions_from_preferences (self);
+ g_signal_connect_object (nautilus_icon_view_preferences,
+ "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS,
+ G_CALLBACK (on_captions_preferences_changed),
+ self,
+ G_CONNECT_SWAPPED);
+
+ 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));
+}
+
+NautilusGridView *
+nautilus_grid_view_new (NautilusWindowSlot *slot)
+{
+ return g_object_new (NAUTILUS_TYPE_GRID_VIEW,
+ "window-slot", slot,
+ NULL);
+}
diff --git a/src/nautilus-grid-view.h b/src/nautilus-grid-view.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c8835fcb1a7516aa571a1447a98713362917091
--- /dev/null
+++ b/src/nautilus-grid-view.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "nautilus-list-base.h"
+#include "nautilus-window-slot.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_GRID_VIEW (nautilus_grid_view_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusGridView, nautilus_grid_view, NAUTILUS, GRID_VIEW, NautilusListBase)
+
+NautilusGridView *nautilus_grid_view_new (NautilusWindowSlot *slot);
+
+G_END_DECLS
diff --git a/src/nautilus-icon-info.h b/src/nautilus-icon-info.h
index e5fab7a6bf0f9db30d4ee5215240d20542c437f9..074789fda864d5c43e28eb24a6e8b0bdc1b9dea6 100644
--- a/src/nautilus-icon-info.h
+++ b/src/nautilus-icon-info.h
@@ -8,9 +8,6 @@
G_BEGIN_DECLS
-#define NAUTILUS_LIST_ZOOM_LEVEL_N_ENTRIES (NAUTILUS_LIST_ZOOM_LEVEL_LARGER + 1)
-#define NAUTILUS_GRID_ZOOM_LEVEL_N_ENTRIES (NAUTILUS_GRID_ZOOM_LEVEL_LARGEST + 1)
-
/* Maximum size of an icon that the icon factory will ever produce */
#define NAUTILUS_ICON_MAXIMUM_SIZE 320
diff --git a/src/nautilus-label-cell.c b/src/nautilus-label-cell.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d3319dba11d971ae6e87cf1646b530f240cdc96
--- /dev/null
+++ b/src/nautilus-label-cell.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 António Fernandes
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/* Needed for NautilusColumn (full GType). */
+#include
+
+#include "nautilus-label-cell.h"
+
+struct _NautilusLabelCell
+{
+ NautilusViewCell parent_instance;
+
+ GSignalGroup *item_signal_group;
+
+ NautilusColumn *column;
+ GQuark attribute_q;
+
+ GtkLabel *label;
+
+ gboolean show_snippet;
+};
+
+G_DEFINE_TYPE (NautilusLabelCell, nautilus_label_cell, NAUTILUS_TYPE_VIEW_CELL)
+
+enum
+{
+ PROP_0,
+ PROP_COLUMN,
+ N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+on_file_changed (NautilusLabelCell *self)
+{
+ NautilusViewItem *item;
+ NautilusFile *file;
+ g_autofree gchar *string = NULL;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_get_file (item);
+
+ string = nautilus_file_get_string_attribute_q (file, self->attribute_q);
+ gtk_label_set_text (self->label, string);
+}
+
+static void
+nautilus_label_cell_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusLabelCell *self = NAUTILUS_LABEL_CELL (object);
+
+ switch (prop_id)
+ {
+ case PROP_COLUMN:
+ {
+ self->column = g_value_get_object (value);
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+ }
+}
+
+static void
+nautilus_label_cell_init (NautilusLabelCell *self)
+{
+ GtkWidget *child;
+
+ child = gtk_label_new (NULL);
+ adw_bin_set_child (ADW_BIN (self), child);
+ gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
+ gtk_widget_add_css_class (child, "dim-label");
+ self->label = GTK_LABEL (child);
+
+ /* Connect automatically to an item. */
+ self->item_signal_group = g_signal_group_new (NAUTILUS_TYPE_VIEW_ITEM);
+ 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);
+}
+
+static void
+nautilus_label_cell_constructed (GObject *object)
+{
+ NautilusLabelCell *self = NAUTILUS_LABEL_CELL (object);
+ g_autofree gchar *column_name = NULL;
+ gfloat xalign;
+
+ G_OBJECT_CLASS (nautilus_label_cell_parent_class)->constructed (object);
+
+ g_object_get (self->column,
+ "attribute_q", &self->attribute_q,
+ "name", &column_name,
+ "xalign", &xalign,
+ NULL);
+ gtk_label_set_xalign (self->label, xalign);
+
+ if (g_strcmp0 (column_name, "permissions") == 0)
+ {
+ gtk_widget_add_css_class (GTK_WIDGET (self->label), "monospace");
+ }
+ else
+ {
+ gtk_widget_add_css_class (GTK_WIDGET (self->label), "numeric");
+ }
+}
+
+static void
+nautilus_label_cell_finalize (GObject *object)
+{
+ NautilusLabelCell *self = (NautilusLabelCell *) object;
+
+ g_object_unref (self->item_signal_group);
+ G_OBJECT_CLASS (nautilus_label_cell_parent_class)->finalize (object);
+}
+
+static void
+nautilus_label_cell_class_init (NautilusLabelCellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = nautilus_label_cell_set_property;
+ object_class->constructed = nautilus_label_cell_constructed;
+ object_class->finalize = nautilus_label_cell_finalize;
+
+ properties[PROP_COLUMN] = g_param_spec_object ("column",
+ "", "",
+ NAUTILUS_TYPE_COLUMN,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+NautilusViewCell *
+nautilus_label_cell_new (NautilusListBase *view,
+ NautilusColumn *column)
+{
+ return NAUTILUS_VIEW_CELL (g_object_new (NAUTILUS_TYPE_LABEL_CELL,
+ "view", view,
+ "column", column,
+ NULL));
+}
diff --git a/src/nautilus-label-cell.h b/src/nautilus-label-cell.h
new file mode 100644
index 0000000000000000000000000000000000000000..b476ef9a0bddb03f3aa79c1b1488cbe11afffdba
--- /dev/null
+++ b/src/nautilus-label-cell.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 António Fernandes
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+/* Needed for NautilusColumn (typedef only). */
+#include "nautilus-types.h"
+
+#include "nautilus-view-cell.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_LABEL_CELL (nautilus_label_cell_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusLabelCell, nautilus_label_cell, NAUTILUS, LABEL_CELL, NautilusViewCell)
+
+NautilusViewCell * nautilus_label_cell_new (NautilusListBase *view,
+ NautilusColumn *column);
+
+G_END_DECLS
diff --git a/src/nautilus-list-base-private.h b/src/nautilus-list-base-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..96944d52e96251559181b08c151d8ea0491a500a
--- /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 0000000000000000000000000000000000000000..355961e94297978dd4ebddac6ec70b99a528b768
--- /dev/null
+++ b/src/nautilus-list-base.c
@@ -0,0 +1,1291 @@
+/*
+ * 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.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 NautilusViewItem *
+get_view_item (GListModel *model,
+ guint position)
+{
+ return NAUTILUS_VIEW_ITEM (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 (NautilusViewItem) current_item = NULL;
+
+ current_item = get_view_item (model, i);
+ nautilus_view_item_set_icon_size (current_item, 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,
+ NautilusViewItem *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);
+ NautilusViewItem *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;
+ NautilusViewItem *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);
+ NautilusViewItem *item;
+
+ item = nautilus_view_model_get_item_from_file (priv->model, file);
+ nautilus_view_item_file_changed (item);
+}
+
+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 (NautilusViewItem) item = NULL;
+
+ item = get_view_item (G_LIST_MODEL (selection), i);
+ selected_files = g_list_prepend (selected_files,
+ g_object_ref (nautilus_view_item_get_file (item)));
+ }
+
+ 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);
+ NautilusViewItem *item;
+
+ item = nautilus_view_model_get_item_from_file (priv->model, file);
+ if (item != NULL)
+ {
+ nautilus_view_model_remove_item (priv->model, item);
+ }
+}
+
+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_items (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)
+ {
+ NautilusViewItem *item;
+
+ item = nautilus_view_item_new (NAUTILUS_FILE (l->data),
+ nautilus_list_base_get_icon_size (self));
+ g_queue_push_tail (models, item);
+ }
+
+ 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_items = 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_items = nautilus_view_model_get_items_from_files (priv->model, selection_files);
+ for (GList *l = g_queue_peek_head_link (selection_items); l != NULL; l = l->next)
+ {
+ gtk_bitset_add (selection_set,
+ nautilus_view_model_get_index (priv->model, l->data));
+ }
+
+ /* Set focus on the first selected row. */
+ if (!g_queue_is_empty (selection_items))
+ {
+ NautilusViewItem *item = g_queue_peek_head (selection_items);
+ GtkWidget *parent = gtk_widget_get_parent (nautilus_view_item_get_item_ui (item));
+
+ if (!gtk_widget_grab_focus (parent))
+ {
+ /* In GtkColumnView, the parent is a cell; its parent is the row. */
+ gtk_widget_grab_focus (gtk_widget_get_parent (parent));
+ }
+ }
+
+ 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;
+ NautilusViewItem *item;
+
+ selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
+ if (selection == NULL)
+ {
+ return G_MAXUINT;
+ }
+
+ file = NAUTILUS_FILE (selection->data);
+ item = nautilus_view_model_get_item_from_file (priv->model, file);
+
+ return nautilus_view_model_get_index (priv->model, item);
+}
+
+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 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 (NautilusViewItem) item1 = NULL;
+ g_autoptr (NautilusViewItem) 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_new (file1, NAUTILUS_GRID_ICON_SIZE_SMALL);
+ item2 = nautilus_view_item_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;
+ NautilusViewItem *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_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_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 (NautilusViewItem) item = NULL;
+ GtkWidget *item_ui;
+
+ item = get_view_item (G_LIST_MODEL (priv->model), i);
+ item_ui = nautilus_view_item_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 (NautilusViewItem) 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_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;
+ NautilusViewItem *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) items = NULL;
+ gdouble adjustment_value;
+
+ files_queue = convert_glist_to_queue (files);
+ items = convert_files_to_items (self, files_queue);
+ nautilus_view_model_add_items (priv->model, items);
+
+ /* 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 (NautilusViewItem) 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_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 (NautilusViewItem) 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_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 (NautilusViewItem) item = NULL;
+
+ item = get_view_item (G_LIST_MODEL (selection), i);
+ item_ui = nautilus_view_item_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 (NautilusViewItem) 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_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 (NautilusViewItem) next_item = NULL;
+
+ next_item = get_view_item (G_LIST_MODEL (priv->model), next_index);
+ next_child = nautilus_view_item_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 (NautilusViewItem) 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_get_file (NAUTILUS_VIEW_ITEM (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->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 0000000000000000000000000000000000000000..007ab07a621c59c062f3de07c3ea931e19c0b7e7
--- /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-list-model.c b/src/nautilus-list-model.c
deleted file mode 100644
index dba6b99e4c6dff1cbefc6649c4f707f9a6042b0a..0000000000000000000000000000000000000000
--- a/src/nautilus-list-model.c
+++ /dev/null
@@ -1,1883 +0,0 @@
-/* fm-list-model.h - a GtkTreeModel for file lists.
- *
- * Copyright (C) 2001, 2002 Anders Carlsson
- * Copyright (C) 2003, Soeren Sandmann
- * Copyright (C) 2004, Novell, Inc.
- *
- * The Gnome Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * The Gnome Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with the Gnome Library; see the file COPYING.LIB. If not,
- * see .
- *
- * Authors: Anders Carlsson , Soeren Sandmann (sandmann@daimi.au.dk), Dave Camp
- */
-
-#include
-
-#include "nautilus-list-model.h"
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include "nautilus-dnd.h"
-
-enum
-{
- SUBDIRECTORY_UNLOADED,
- GET_ICON_SCALE,
- LAST_SIGNAL
-};
-
-static GQuark attribute_name_q,
- attribute_modification_date_q,
- attribute_date_modified_q;
-
-/* msec delay after Loading... dummy row turns into (empty) */
-#define LOADING_TO_EMPTY_DELAY 100
-
-static guint list_model_signals[LAST_SIGNAL] = { 0 };
-
-static int nautilus_list_model_file_entry_compare_func (gconstpointer a,
- gconstpointer b,
- gpointer user_data);
-static void nautilus_list_model_tree_model_init (GtkTreeModelIface *iface);
-static void nautilus_list_model_sortable_init (GtkTreeSortableIface *iface);
-
-typedef struct
-{
- GSequence *files;
- GHashTable *directory_reverse_map; /* map from directory to GSequenceIter's */
- GHashTable *top_reverse_map; /* map from files in top dir to GSequenceIter's */
-
- int stamp;
-
- GQuark sort_attribute;
- GtkSortType order;
-
- gboolean sort_directories_first;
-
- GtkTreeView *drag_view;
- int drag_begin_x;
- int drag_begin_y;
-
- GPtrArray *columns;
-
- GList *highlight_files;
-} NautilusListModelPrivate;
-
-typedef struct
-{
- NautilusListModel *model;
-
- GList *path_list;
-} DragDataGetInfo;
-
-typedef struct FileEntry FileEntry;
-
-struct FileEntry
-{
- NautilusFile *file;
- GHashTable *reverse_map; /* map from files to GSequenceIter's */
- NautilusDirectory *subdirectory;
- FileEntry *parent;
- GSequence *files;
- GSequenceIter *ptr;
- guint loaded : 1;
-};
-
-G_DEFINE_TYPE_WITH_CODE (NautilusListModel, nautilus_list_model, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
- nautilus_list_model_tree_model_init)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
- nautilus_list_model_sortable_init)
- G_ADD_PRIVATE (NautilusListModel));
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-static const GtkTargetEntry drag_types [] =
-{
- { NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST },
- { NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST },
-};
-#endif
-
-static void
-file_entry_free (FileEntry *file_entry)
-{
- nautilus_file_unref (file_entry->file);
- if (file_entry->reverse_map)
- {
- g_hash_table_destroy (file_entry->reverse_map);
- file_entry->reverse_map = NULL;
- }
- if (file_entry->subdirectory != NULL)
- {
- nautilus_directory_unref (file_entry->subdirectory);
- }
- if (file_entry->files != NULL)
- {
- g_sequence_free (file_entry->files);
- }
- g_free (file_entry);
-}
-
-static GtkTreeModelFlags
-nautilus_list_model_get_flags (GtkTreeModel *tree_model)
-{
- return GTK_TREE_MODEL_ITERS_PERSIST;
-}
-
-static int
-nautilus_list_model_get_n_columns (GtkTreeModel *tree_model)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (NAUTILUS_LIST_MODEL (tree_model));
-
- return NAUTILUS_LIST_MODEL_NUM_COLUMNS + priv->columns->len;
-}
-
-static GType
-nautilus_list_model_get_column_type (GtkTreeModel *tree_model,
- int index)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- switch (index)
- {
- case NAUTILUS_LIST_MODEL_FILE_COLUMN:
- {
- return NAUTILUS_TYPE_FILE;
- }
-
- case NAUTILUS_LIST_MODEL_SUBDIRECTORY_COLUMN:
- {
- return NAUTILUS_TYPE_DIRECTORY;
- }
-
- case NAUTILUS_LIST_MODEL_SMALL_ICON_COLUMN:
- case NAUTILUS_LIST_MODEL_STANDARD_ICON_COLUMN:
- case NAUTILUS_LIST_MODEL_LARGE_ICON_COLUMN:
- case NAUTILUS_LIST_MODEL_LARGER_ICON_COLUMN:
- {
- return GDK_TYPE_TEXTURE;
- }
-
- case NAUTILUS_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN:
- {
- return G_TYPE_BOOLEAN;
- }
-
- default:
- {
- if (index < NAUTILUS_LIST_MODEL_NUM_COLUMNS + priv->columns->len)
- {
- return G_TYPE_STRING;
- }
- else
- {
- return G_TYPE_INVALID;
- }
- }
- }
-}
-
-static void
-nautilus_list_model_ptr_to_iter (NautilusListModel *model,
- GSequenceIter *ptr,
- GtkTreeIter *iter)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- g_assert (!g_sequence_iter_is_end (ptr));
-
- if (iter != NULL)
- {
- iter->stamp = priv->stamp;
- iter->user_data = ptr;
- }
-}
-
-static gboolean
-nautilus_list_model_get_iter (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreePath *path)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- GSequence *files;
- GSequenceIter *ptr;
- FileEntry *file_entry;
- int i, d;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
- ptr = NULL;
-
- files = priv->files;
- for (d = 0; d < gtk_tree_path_get_depth (path); d++)
- {
- i = gtk_tree_path_get_indices (path)[d];
-
- if (files == NULL || i >= g_sequence_get_length (files))
- {
- return FALSE;
- }
-
- ptr = g_sequence_get_iter_at_pos (files, i);
- file_entry = g_sequence_get (ptr);
- files = file_entry->files;
- }
-
- nautilus_list_model_ptr_to_iter (model, ptr, iter);
-
- return TRUE;
-}
-
-static GtkTreePath *
-nautilus_list_model_get_path (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- GtkTreePath *path;
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- GSequenceIter *ptr;
- FileEntry *file_entry;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
-
- if (g_sequence_iter_is_end (iter->user_data))
- {
- /* FIXME is this right? */
- return NULL;
- }
-
- path = gtk_tree_path_new ();
- ptr = iter->user_data;
- while (ptr != NULL)
- {
- gtk_tree_path_prepend_index (path, g_sequence_iter_get_position (ptr));
- file_entry = g_sequence_get (ptr);
- if (file_entry->parent != NULL)
- {
- ptr = file_entry->parent->ptr;
- }
- else
- {
- ptr = NULL;
- }
- }
-
- return path;
-}
-
-static gint
-nautilus_list_model_get_icon_scale (NautilusListModel *model)
-{
- gint retval = -1;
-
- g_signal_emit (model, list_model_signals[GET_ICON_SCALE], 0,
- &retval);
-
- if (retval == -1)
- {
- retval = gdk_monitor_get_scale_factor (g_list_model_get_item (gdk_display_get_monitors (gdk_display_get_default ()), 0));
- }
-
- /* FIXME: Temporary regression: HiDPI icons not supported, ignore scale. */
- retval = 1;
-
- return retval;
-}
-
-guint
-nautilus_list_model_get_icon_size_for_zoom_level (NautilusListZoomLevel zoom_level)
-{
- switch (zoom_level)
- {
- case NAUTILUS_LIST_ZOOM_LEVEL_SMALL:
- {
- return NAUTILUS_LIST_ICON_SIZE_SMALL;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_STANDARD:
- {
- return NAUTILUS_LIST_ICON_SIZE_STANDARD;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_LARGE:
- {
- return NAUTILUS_LIST_ICON_SIZE_LARGE;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_LARGER:
- {
- return NAUTILUS_LIST_ICON_SIZE_LARGER;
- }
- }
- g_return_val_if_reached (NAUTILUS_LIST_ICON_SIZE_STANDARD);
-}
-
-static void
-nautilus_list_model_get_value (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- int column,
- GValue *value)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- FileEntry *file_entry;
- NautilusFile *file;
- char *str;
- GdkTexture *icon;
- int icon_size, icon_scale;
- NautilusListZoomLevel zoom_level;
- NautilusFileIconFlags flags;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- g_return_if_fail (priv->stamp == iter->stamp);
- g_return_if_fail (!g_sequence_iter_is_end (iter->user_data));
-
- file_entry = g_sequence_get (iter->user_data);
- file = file_entry->file;
-
- switch (column)
- {
- case NAUTILUS_LIST_MODEL_FILE_COLUMN:
- {
- g_value_init (value, NAUTILUS_TYPE_FILE);
-
- g_value_set_object (value, file);
- }
- break;
-
- case NAUTILUS_LIST_MODEL_SUBDIRECTORY_COLUMN:
- {
- g_value_init (value, NAUTILUS_TYPE_DIRECTORY);
-
- g_value_set_object (value, file_entry->subdirectory);
- }
- break;
-
- case NAUTILUS_LIST_MODEL_SMALL_ICON_COLUMN:
- case NAUTILUS_LIST_MODEL_STANDARD_ICON_COLUMN:
- case NAUTILUS_LIST_MODEL_LARGE_ICON_COLUMN:
- case NAUTILUS_LIST_MODEL_LARGER_ICON_COLUMN:
- {
- g_value_init (value, GDK_TYPE_TEXTURE);
-
- if (file != NULL)
- {
- zoom_level = nautilus_list_model_get_zoom_level_from_column_id (column);
- icon_size = nautilus_list_model_get_icon_size_for_zoom_level (zoom_level);
- icon_scale = nautilus_list_model_get_icon_scale (model);
-
- flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
- NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE |
- NAUTILUS_FILE_ICON_FLAGS_USE_EMBLEMS |
- NAUTILUS_FILE_ICON_FLAGS_USE_ONE_EMBLEM;
-
- if (priv->drag_view != NULL)
- {
- GtkTreePath *path_a, *path_b;
-
- gtk_tree_view_get_drag_dest_row (priv->drag_view,
- &path_a,
- NULL);
- if (path_a != NULL)
- {
- path_b = gtk_tree_model_get_path (tree_model, iter);
-
- if (gtk_tree_path_compare (path_a, path_b) == 0)
- {
- flags |= NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT;
- }
-
- gtk_tree_path_free (path_a);
- gtk_tree_path_free (path_b);
- }
- }
-
- icon = nautilus_file_get_icon_texture (file, icon_size, icon_scale, flags);
-
-#if 0 && NAUTILUS_CLIPBOARD_NEEDS_GTK4_REIMPLEMENTATION
- if (priv->highlight_files != NULL &&
- g_list_find_custom (priv->highlight_files,
- file, (GCompareFunc) nautilus_file_compare_location))
- {
- rendered_icon = eel_create_spotlight_pixbuf (icon);
-
- if (rendered_icon != NULL)
- {
- g_object_unref (icon);
- icon = rendered_icon;
- }
- }
-#endif
-
- g_value_set_object (value, icon);
- g_object_unref (icon);
- }
- }
- break;
-
- case NAUTILUS_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN:
- {
- g_value_init (value, G_TYPE_BOOLEAN);
-
- g_value_set_boolean (value, file != NULL && nautilus_file_can_rename (file));
- }
- break;
-
- default:
- {
- if (column >= NAUTILUS_LIST_MODEL_NUM_COLUMNS && column < NAUTILUS_LIST_MODEL_NUM_COLUMNS + priv->columns->len)
- {
- NautilusColumn *nautilus_column;
- GQuark attribute;
- nautilus_column = priv->columns->pdata[column - NAUTILUS_LIST_MODEL_NUM_COLUMNS];
-
- g_value_init (value, G_TYPE_STRING);
- g_object_get (nautilus_column,
- "attribute_q", &attribute,
- NULL);
- if (file != NULL)
- {
- str = nautilus_file_get_string_attribute_with_default_q (file,
- attribute);
- g_value_take_string (value, str);
- }
- else if (attribute == attribute_name_q)
- {
- if (file_entry->parent->loaded)
- {
- g_value_set_string (value, _("(Empty)"));
- }
- else
- {
- g_value_set_string (value, _("Loading…"));
- }
- }
- }
- else
- {
- g_assert_not_reached ();
- }
- }
- }
-}
-
-static gboolean
-nautilus_list_model_iter_next (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
-
- iter->user_data = g_sequence_iter_next (iter->user_data);
-
- return !g_sequence_iter_is_end (iter->user_data);
-}
-
-static gboolean
-nautilus_list_model_iter_children (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- GSequence *files;
- FileEntry *file_entry;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- if (parent == NULL)
- {
- files = priv->files;
- }
- else
- {
- file_entry = g_sequence_get (parent->user_data);
- files = file_entry->files;
- }
-
- if (files == NULL || g_sequence_get_length (files) == 0)
- {
- return FALSE;
- }
-
- iter->stamp = priv->stamp;
- iter->user_data = g_sequence_get_begin_iter (files);
-
- return TRUE;
-}
-
-static gboolean
-nautilus_list_model_iter_has_child (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- FileEntry *file_entry;
-
- if (iter == NULL)
- {
- return !nautilus_list_model_is_empty (NAUTILUS_LIST_MODEL (tree_model));
- }
-
- file_entry = g_sequence_get (iter->user_data);
-
- return (file_entry->files != NULL && g_sequence_get_length (file_entry->files) > 0);
-}
-
-static int
-nautilus_list_model_iter_n_children (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- GSequence *files;
- FileEntry *file_entry;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- if (iter == NULL)
- {
- files = priv->files;
- }
- else
- {
- file_entry = g_sequence_get (iter->user_data);
- files = file_entry->files;
- }
-
- return g_sequence_get_length (files);
-}
-
-static gboolean
-nautilus_list_model_iter_nth_child (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- int n)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- GSequenceIter *child;
- GSequence *files;
- FileEntry *file_entry;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- if (parent != NULL)
- {
- file_entry = g_sequence_get (parent->user_data);
- files = file_entry->files;
- }
- else
- {
- files = priv->files;
- }
-
- child = g_sequence_get_iter_at_pos (files, n);
-
- if (g_sequence_iter_is_end (child))
- {
- return FALSE;
- }
-
- iter->stamp = priv->stamp;
- iter->user_data = child;
-
- return TRUE;
-}
-
-static gboolean
-nautilus_list_model_iter_parent (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *child)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- FileEntry *file_entry;
-
- model = NAUTILUS_LIST_MODEL (tree_model);
- priv = nautilus_list_model_get_instance_private (model);
-
- file_entry = g_sequence_get (child->user_data);
-
- if (file_entry->parent == NULL)
- {
- return FALSE;
- }
-
- iter->stamp = priv->stamp;
- iter->user_data = file_entry->parent->ptr;
-
- return TRUE;
-}
-
-static GSequenceIter *
-lookup_file (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- NautilusListModelPrivate *priv;
- FileEntry *file_entry;
- GSequenceIter *ptr, *parent_ptr;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- parent_ptr = NULL;
- if (directory)
- {
- parent_ptr = g_hash_table_lookup (priv->directory_reverse_map,
- directory);
- }
-
- if (parent_ptr)
- {
- file_entry = g_sequence_get (parent_ptr);
- ptr = g_hash_table_lookup (file_entry->reverse_map, file);
- }
- else
- {
- ptr = g_hash_table_lookup (priv->top_reverse_map, file);
- }
-
- if (ptr)
- {
- g_assert (((FileEntry *) g_sequence_get (ptr))->file == file);
- }
-
- return ptr;
-}
-
-
-struct GetIters
-{
- NautilusListModel *model;
- NautilusFile *file;
- GList *iters;
-};
-
-static void
-dir_to_iters (struct GetIters *data,
- GHashTable *reverse_map)
-{
- GSequenceIter *ptr;
-
- ptr = g_hash_table_lookup (reverse_map, data->file);
- if (ptr)
- {
- GtkTreeIter *iter;
- iter = g_new0 (GtkTreeIter, 1);
- nautilus_list_model_ptr_to_iter (data->model, ptr, iter);
- data->iters = g_list_prepend (data->iters, iter);
- }
-}
-
-static void
-file_to_iter_cb (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- struct GetIters *data;
- FileEntry *dir_file_entry;
-
- data = user_data;
- dir_file_entry = g_sequence_get ((GSequenceIter *) value);
- dir_to_iters (data, dir_file_entry->reverse_map);
-}
-
-GList *
-nautilus_list_model_get_all_iters_for_file (NautilusListModel *model,
- NautilusFile *file)
-{
- struct GetIters data;
- NautilusListModelPrivate *priv;
- data.file = file;
- data.model = model;
- data.iters = NULL;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- dir_to_iters (&data, priv->top_reverse_map);
- g_hash_table_foreach (priv->directory_reverse_map,
- file_to_iter_cb, &data);
-
- return g_list_reverse (data.iters);
-}
-
-gboolean
-nautilus_list_model_get_first_iter_for_file (NautilusListModel *model,
- NautilusFile *file,
- GtkTreeIter *iter)
-{
- GList *list;
- gboolean res;
-
- res = FALSE;
-
- list = nautilus_list_model_get_all_iters_for_file (model, file);
- if (list != NULL)
- {
- res = TRUE;
- *iter = *(GtkTreeIter *) list->data;
- }
- g_list_free_full (list, g_free);
-
- return res;
-}
-
-
-gboolean
-nautilus_list_model_get_tree_iter_from_file (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory,
- GtkTreeIter *iter)
-{
- GSequenceIter *ptr;
-
- ptr = lookup_file (model, file, directory);
- if (!ptr)
- {
- return FALSE;
- }
-
- nautilus_list_model_ptr_to_iter (model, ptr, iter);
-
- return TRUE;
-}
-
-static int
-nautilus_list_model_file_entry_compare_func (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- FileEntry *file_entry1;
- FileEntry *file_entry2;
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- int result;
-
- model = NAUTILUS_LIST_MODEL (user_data);
- priv = nautilus_list_model_get_instance_private (model);
-
- file_entry1 = (FileEntry *) a;
- file_entry2 = (FileEntry *) b;
-
- if (file_entry1->file != NULL && file_entry2->file != NULL)
- {
- result = nautilus_file_compare_for_sort_by_attribute_q (file_entry1->file, file_entry2->file,
- priv->sort_attribute,
- priv->sort_directories_first,
- (priv->order == GTK_SORT_DESCENDING));
- }
- else if (file_entry1->file == NULL)
- {
- return -1;
- }
- else
- {
- return 1;
- }
-
- return result;
-}
-
-int
-nautilus_list_model_compare_func (NautilusListModel *model,
- NautilusFile *file1,
- NautilusFile *file2)
-{
- NautilusListModelPrivate *priv;
- int result;
-
- priv = nautilus_list_model_get_instance_private (model);
- result = nautilus_file_compare_for_sort_by_attribute_q (file1, file2,
- priv->sort_attribute,
- priv->sort_directories_first,
- (priv->order == GTK_SORT_DESCENDING));
-
- return result;
-}
-
-static void
-nautilus_list_model_sort_file_entries (NautilusListModel *model,
- GSequence *files,
- GtkTreePath *path)
-{
- GSequenceIter **old_order;
- GtkTreeIter iter;
- int *new_order;
- int length;
- int i;
- FileEntry *file_entry;
- gboolean has_iter;
-
- length = g_sequence_get_length (files);
-
- if (length <= 1)
- {
- return;
- }
-
- /* generate old order of GSequenceIter's */
- old_order = g_new (GSequenceIter *, length);
- for (i = 0; i < length; ++i)
- {
- GSequenceIter *ptr = g_sequence_get_iter_at_pos (files, i);
-
- file_entry = g_sequence_get (ptr);
- if (file_entry->files != NULL)
- {
- gtk_tree_path_append_index (path, i);
- nautilus_list_model_sort_file_entries (model, file_entry->files, path);
- gtk_tree_path_up (path);
- }
-
- old_order[i] = ptr;
- }
-
- /* sort */
- g_sequence_sort (files, nautilus_list_model_file_entry_compare_func, model);
-
- /* generate new order */
- new_order = g_new (int, length);
- /* Note: new_order[newpos] = oldpos */
- for (i = 0; i < length; ++i)
- {
- new_order[g_sequence_iter_get_position (old_order[i])] = i;
- }
-
- /* Let the world know about our new order */
-
- g_assert (new_order != NULL);
-
- has_iter = FALSE;
- if (gtk_tree_path_get_depth (path) != 0)
- {
- gboolean get_iter_result;
- has_iter = TRUE;
- get_iter_result = gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
- g_assert (get_iter_result);
- }
-
- gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
- path, has_iter ? &iter : NULL, new_order);
-
- g_free (old_order);
- g_free (new_order);
-}
-
-static void
-nautilus_list_model_sort (NautilusListModel *model)
-{
- GtkTreePath *path;
- NautilusListModelPrivate *priv;
-
- path = gtk_tree_path_new ();
- priv = nautilus_list_model_get_instance_private (model);
-
- nautilus_list_model_sort_file_entries (model, priv->files, path);
-
- gtk_tree_path_free (path);
-}
-
-static gboolean
-nautilus_list_model_get_sort_column_id (GtkTreeSortable *sortable,
- gint *sort_column_id,
- GtkSortType *order)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- int id;
-
- model = NAUTILUS_LIST_MODEL (sortable);
- priv = nautilus_list_model_get_instance_private (model);
- id = nautilus_list_model_get_sort_column_id_from_attribute (model, priv->sort_attribute);
-
- if (id == -1)
- {
- return FALSE;
- }
-
- if (sort_column_id != NULL)
- {
- *sort_column_id = id;
- }
-
- if (order != NULL)
- {
- *order = priv->order;
- }
-
- return TRUE;
-}
-
-static void
-nautilus_list_model_set_sort_column_id (GtkTreeSortable *sortable,
- gint sort_column_id,
- GtkSortType order)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
-
- model = NAUTILUS_LIST_MODEL (sortable);
- priv = nautilus_list_model_get_instance_private (model);
-
- priv->sort_attribute = nautilus_list_model_get_attribute_from_sort_column_id (model, sort_column_id);
-
- priv->order = order;
-
- nautilus_list_model_sort (model);
- gtk_tree_sortable_sort_column_changed (sortable);
-}
-
-static gboolean
-nautilus_list_model_has_default_sort_func (GtkTreeSortable *sortable)
-{
- return FALSE;
-}
-
-static void
-add_dummy_row (NautilusListModel *model,
- FileEntry *parent_entry)
-{
- NautilusListModelPrivate *priv;
- FileEntry *dummy_file_entry;
- GtkTreeIter iter;
- GtkTreePath *path;
-
- priv = nautilus_list_model_get_instance_private (model);
- dummy_file_entry = g_new0 (FileEntry, 1);
- dummy_file_entry->parent = parent_entry;
- dummy_file_entry->ptr = g_sequence_insert_sorted (parent_entry->files, dummy_file_entry,
- nautilus_list_model_file_entry_compare_func, model);
- iter.stamp = priv->stamp;
- iter.user_data = dummy_file_entry->ptr;
-
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
- gtk_tree_path_free (path);
-}
-
-gboolean
-nautilus_list_model_add_file (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- NautilusListModelPrivate *priv;
- GtkTreeIter iter;
- GtkTreePath *path;
- FileEntry *file_entry;
- GSequenceIter *ptr, *parent_ptr;
- GSequence *files;
- gboolean replace_dummy;
- GHashTable *parent_hash;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- parent_ptr = g_hash_table_lookup (priv->directory_reverse_map,
- directory);
- if (parent_ptr)
- {
- file_entry = g_sequence_get (parent_ptr);
- ptr = g_hash_table_lookup (file_entry->reverse_map, file);
- }
- else
- {
- file_entry = NULL;
- ptr = g_hash_table_lookup (priv->top_reverse_map, file);
- }
-
- if (ptr != NULL)
- {
- g_warning ("file already in tree (parent_ptr: %p)!!!\n", parent_ptr);
- return FALSE;
- }
-
- file_entry = g_new0 (FileEntry, 1);
- file_entry->file = nautilus_file_ref (file);
- file_entry->parent = NULL;
- file_entry->subdirectory = NULL;
- file_entry->files = NULL;
-
- files = priv->files;
- parent_hash = priv->top_reverse_map;
-
- replace_dummy = FALSE;
-
- if (parent_ptr != NULL)
- {
- file_entry->parent = g_sequence_get (parent_ptr);
- /* At this point we set loaded. Either we saw
- * "done" and ignored it waiting for this, or we do this
- * earlier, but then we replace the dummy row anyway,
- * so it doesn't matter */
- file_entry->parent->loaded = 1;
- parent_hash = file_entry->parent->reverse_map;
- files = file_entry->parent->files;
- if (g_sequence_get_length (files) == 1)
- {
- GSequenceIter *dummy_ptr = g_sequence_get_iter_at_pos (files, 0);
- FileEntry *dummy_entry = g_sequence_get (dummy_ptr);
- if (dummy_entry->file == NULL)
- {
- /* replace the dummy loading entry */
- priv->stamp++;
- g_sequence_remove (dummy_ptr);
-
- replace_dummy = TRUE;
- }
- }
- }
-
-
- file_entry->ptr = g_sequence_insert_sorted (files, file_entry,
- nautilus_list_model_file_entry_compare_func, model);
-
- g_hash_table_insert (parent_hash, file, file_entry->ptr);
-
- iter.stamp = priv->stamp;
- iter.user_data = file_entry->ptr;
-
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
- if (replace_dummy)
- {
- gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
- }
- else
- {
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
- }
-
- if (nautilus_file_is_directory (file))
- {
- file_entry->files = g_sequence_new ((GDestroyNotify) file_entry_free);
-
- add_dummy_row (model, file_entry);
-
- gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model),
- path, &iter);
- }
- gtk_tree_path_free (path);
-
- return TRUE;
-}
-
-void
-nautilus_list_model_file_changed (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- NautilusListModelPrivate *priv;
- FileEntry *parent_file_entry;
- GtkTreeIter iter;
- GtkTreePath *path, *parent_path;
- GSequenceIter *ptr;
- int pos_before, pos_after, length, i, old;
- int *new_order;
- gboolean has_iter;
- GSequence *files;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- ptr = lookup_file (model, file, directory);
- if (!ptr)
- {
- return;
- }
-
-
- pos_before = g_sequence_iter_get_position (ptr);
-
- g_sequence_sort_changed (ptr, nautilus_list_model_file_entry_compare_func, model);
-
- pos_after = g_sequence_iter_get_position (ptr);
-
- if (pos_before != pos_after)
- {
- /* The file moved, we need to send rows_reordered */
-
- parent_file_entry = ((FileEntry *) g_sequence_get (ptr))->parent;
-
- if (parent_file_entry == NULL)
- {
- has_iter = FALSE;
- parent_path = gtk_tree_path_new ();
- files = priv->files;
- }
- else
- {
- has_iter = TRUE;
- nautilus_list_model_ptr_to_iter (model, parent_file_entry->ptr, &iter);
- parent_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
- files = parent_file_entry->files;
- }
-
- length = g_sequence_get_length (files);
- new_order = g_new (int, length);
- /* Note: new_order[newpos] = oldpos */
- for (i = 0, old = 0; i < length; ++i)
- {
- if (i == pos_after)
- {
- new_order[i] = pos_before;
- }
- else
- {
- if (old == pos_before)
- {
- old++;
- }
- new_order[i] = old++;
- }
- }
-
- gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
- parent_path, has_iter ? &iter : NULL, new_order);
-
- gtk_tree_path_free (parent_path);
- g_free (new_order);
- }
-
- nautilus_list_model_ptr_to_iter (model, ptr, &iter);
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
- gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
- gtk_tree_path_free (path);
-}
-
-gboolean
-nautilus_list_model_is_empty (NautilusListModel *model)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- return (g_sequence_get_length (priv->files) == 0);
-}
-
-static void
-nautilus_list_model_remove (NautilusListModel *model,
- GtkTreeIter *iter)
-{
- NautilusListModelPrivate *priv;
- GSequenceIter *ptr, *child_ptr;
- FileEntry *file_entry, *child_file_entry, *parent_file_entry;
- GtkTreePath *path;
- GtkTreeIter parent_iter;
-
- priv = nautilus_list_model_get_instance_private (model);
- ptr = iter->user_data;
- file_entry = g_sequence_get (ptr);
-
- if (file_entry->files != NULL)
- {
- while (g_sequence_get_length (file_entry->files) > 0)
- {
- child_ptr = g_sequence_get_begin_iter (file_entry->files);
- child_file_entry = g_sequence_get (child_ptr);
- if (child_file_entry->file != NULL)
- {
- nautilus_list_model_remove_file (model,
- child_file_entry->file,
- file_entry->subdirectory);
- }
- else
- {
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
- gtk_tree_path_append_index (path, 0);
- priv->stamp++;
- g_sequence_remove (child_ptr);
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
- gtk_tree_path_free (path);
- }
-
- /* the parent iter didn't actually change */
- iter->stamp = priv->stamp;
- }
- }
-
- if (file_entry->file != NULL) /* Don't try to remove dummy row */
- {
- if (file_entry->parent != NULL)
- {
- g_hash_table_remove (file_entry->parent->reverse_map, file_entry->file);
- }
- else
- {
- g_hash_table_remove (priv->top_reverse_map, file_entry->file);
- }
- }
-
- parent_file_entry = file_entry->parent;
- if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 1 &&
- file_entry->file != NULL)
- {
- /* this is the last non-dummy child, add a dummy node */
- /* We need to do this before removing the last file to avoid
- * collapsing the row.
- */
- add_dummy_row (model, parent_file_entry);
- }
-
- if (file_entry->subdirectory != NULL)
- {
- g_signal_emit (model,
- list_model_signals[SUBDIRECTORY_UNLOADED], 0,
- file_entry->subdirectory);
- g_hash_table_remove (priv->directory_reverse_map,
- file_entry->subdirectory);
- }
-
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
-
- g_sequence_remove (ptr);
- priv->stamp++;
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
-
- gtk_tree_path_free (path);
-
- if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 0)
- {
- parent_iter.stamp = priv->stamp;
- parent_iter.user_data = parent_file_entry->ptr;
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &parent_iter);
- gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model),
- path, &parent_iter);
- gtk_tree_path_free (path);
- }
-}
-
-void
-nautilus_list_model_remove_file (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- GtkTreeIter iter;
-
- if (nautilus_list_model_get_tree_iter_from_file (model, file, directory, &iter))
- {
- nautilus_list_model_remove (model, &iter);
- }
-}
-
-static void
-nautilus_list_model_clear_directory (NautilusListModel *model,
- GSequence *files)
-{
- NautilusListModelPrivate *priv;
- GtkTreeIter iter;
- FileEntry *file_entry;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- while (g_sequence_get_length (files) > 0)
- {
- iter.user_data = g_sequence_get_begin_iter (files);
-
- file_entry = g_sequence_get (iter.user_data);
- if (file_entry->files != NULL)
- {
- nautilus_list_model_clear_directory (model, file_entry->files);
- }
-
- iter.stamp = priv->stamp;
- nautilus_list_model_remove (model, &iter);
- }
-}
-
-void
-nautilus_list_model_clear (NautilusListModel *model)
-{
- NautilusListModelPrivate *priv;
-
- g_return_if_fail (model != NULL);
-
- priv = nautilus_list_model_get_instance_private (model);
-
- nautilus_list_model_clear_directory (model, priv->files);
-}
-
-NautilusFile *
-nautilus_list_model_file_for_path (NautilusListModel *model,
- GtkTreePath *path)
-{
- NautilusFile *file;
- GtkTreeIter iter;
-
- file = NULL;
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model),
- &iter, path))
- {
- gtk_tree_model_get (GTK_TREE_MODEL (model),
- &iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
- }
- return file;
-}
-
-gboolean
-nautilus_list_model_load_subdirectory (NautilusListModel *model,
- GtkTreePath *path,
- NautilusDirectory **directory)
-{
- NautilusListModelPrivate *priv;
- GtkTreeIter iter;
- FileEntry *file_entry;
- NautilusDirectory *subdirectory;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
- {
- return FALSE;
- }
-
- file_entry = g_sequence_get (iter.user_data);
- if (file_entry->file == NULL ||
- file_entry->subdirectory != NULL)
- {
- return FALSE;
- }
-
- subdirectory = nautilus_directory_get_for_file (file_entry->file);
-
- if (g_hash_table_lookup (priv->directory_reverse_map, subdirectory) != NULL)
- {
- nautilus_directory_unref (subdirectory);
- g_warning ("Already in directory_reverse_map, failing\n");
- return FALSE;
- }
-
- file_entry->subdirectory = subdirectory,
- g_hash_table_insert (priv->directory_reverse_map,
- subdirectory, file_entry->ptr);
- file_entry->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
-
- /* Return a ref too */
- nautilus_directory_ref (subdirectory);
- *directory = subdirectory;
-
- return TRUE;
-}
-
-/* removes all children of the subfolder and unloads the subdirectory */
-void
-nautilus_list_model_unload_subdirectory (NautilusListModel *model,
- GtkTreeIter *iter)
-{
- NautilusListModelPrivate *priv;
- GSequenceIter *child_ptr;
- FileEntry *file_entry, *child_file_entry;
- GtkTreeIter child_iter;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- file_entry = g_sequence_get (iter->user_data);
- if (file_entry->file == NULL ||
- file_entry->subdirectory == NULL)
- {
- return;
- }
-
- file_entry->loaded = 0;
-
- /* Remove all children */
- while (g_sequence_get_length (file_entry->files) > 0)
- {
- child_ptr = g_sequence_get_begin_iter (file_entry->files);
- child_file_entry = g_sequence_get (child_ptr);
- if (child_file_entry->file == NULL)
- {
- /* Don't delete the dummy node */
- break;
- }
- else
- {
- nautilus_list_model_ptr_to_iter (model, child_ptr, &child_iter);
- nautilus_list_model_remove (model, &child_iter);
- }
- }
-
- /* Emit unload signal */
- g_signal_emit (model,
- list_model_signals[SUBDIRECTORY_UNLOADED], 0,
- file_entry->subdirectory);
-
- /* actually unload */
- g_hash_table_remove (priv->directory_reverse_map,
- file_entry->subdirectory);
- nautilus_directory_unref (file_entry->subdirectory);
- file_entry->subdirectory = NULL;
-
- g_assert (g_hash_table_size (file_entry->reverse_map) == 0);
- g_hash_table_destroy (file_entry->reverse_map);
- file_entry->reverse_map = NULL;
-}
-
-
-
-void
-nautilus_list_model_set_should_sort_directories_first (NautilusListModel *model,
- gboolean sort_directories_first)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- if (priv->sort_directories_first == sort_directories_first)
- {
- return;
- }
-
- priv->sort_directories_first = sort_directories_first;
- nautilus_list_model_sort (model);
-}
-
-int
-nautilus_list_model_get_sort_column_id_from_attribute (NautilusListModel *model,
- GQuark attribute)
-{
- NautilusListModelPrivate *priv;
- guint i;
-
- if (attribute == 0)
- {
- return -1;
- }
-
- priv = nautilus_list_model_get_instance_private (model);
-
- /* Hack - the preferences dialog sets modification_date for some
- * rather than date_modified for some reason. Make sure that
- * works. */
- if (attribute == attribute_modification_date_q)
- {
- attribute = attribute_date_modified_q;
- }
-
- for (i = 0; i < priv->columns->len; i++)
- {
- NautilusColumn *column;
- GQuark column_attribute;
-
- column = NAUTILUS_COLUMN (priv->columns->pdata[i]);
- g_object_get (G_OBJECT (column),
- "attribute_q", &column_attribute,
- NULL);
- if (column_attribute == attribute)
- {
- return NAUTILUS_LIST_MODEL_NUM_COLUMNS + i;
- }
- }
-
- return -1;
-}
-
-GQuark
-nautilus_list_model_get_attribute_from_sort_column_id (NautilusListModel *model,
- int sort_column_id)
-{
- NautilusListModelPrivate *priv;
- NautilusColumn *column;
- int index;
- GQuark attribute;
-
- priv = nautilus_list_model_get_instance_private (model);
- index = sort_column_id - NAUTILUS_LIST_MODEL_NUM_COLUMNS;
-
- if (index < 0 || index >= priv->columns->len)
- {
- g_warning ("unknown sort column id: %d", sort_column_id);
- return 0;
- }
-
- column = NAUTILUS_COLUMN (priv->columns->pdata[index]);
- g_object_get (G_OBJECT (column), "attribute_q", &attribute, NULL);
-
- return attribute;
-}
-
-NautilusListZoomLevel
-nautilus_list_model_get_zoom_level_from_column_id (int column)
-{
- switch (column)
- {
- case NAUTILUS_LIST_MODEL_SMALL_ICON_COLUMN:
- {
- return NAUTILUS_LIST_ZOOM_LEVEL_SMALL;
- }
-
- case NAUTILUS_LIST_MODEL_STANDARD_ICON_COLUMN:
- {
- return NAUTILUS_LIST_ZOOM_LEVEL_STANDARD;
- }
-
- case NAUTILUS_LIST_MODEL_LARGE_ICON_COLUMN:
- {
- return NAUTILUS_LIST_ZOOM_LEVEL_LARGE;
- }
-
- case NAUTILUS_LIST_MODEL_LARGER_ICON_COLUMN:
- {
- return NAUTILUS_LIST_ZOOM_LEVEL_LARGER;
- }
- }
-
- g_return_val_if_reached (NAUTILUS_LIST_ZOOM_LEVEL_STANDARD);
-}
-
-int
-nautilus_list_model_get_column_id_from_zoom_level (NautilusListZoomLevel zoom_level)
-{
- switch (zoom_level)
- {
- case NAUTILUS_LIST_ZOOM_LEVEL_SMALL:
- {
- return NAUTILUS_LIST_MODEL_SMALL_ICON_COLUMN;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_STANDARD:
- {
- return NAUTILUS_LIST_MODEL_STANDARD_ICON_COLUMN;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_LARGE:
- {
- return NAUTILUS_LIST_MODEL_LARGE_ICON_COLUMN;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_LARGER:
- {
- return NAUTILUS_LIST_MODEL_LARGER_ICON_COLUMN;
- }
- }
-
- g_return_val_if_reached (NAUTILUS_LIST_MODEL_STANDARD_ICON_COLUMN);
-}
-
-void
-nautilus_list_model_set_drag_view (NautilusListModel *model,
- GtkTreeView *view,
- int drag_begin_x,
- int drag_begin_y)
-{
- NautilusListModelPrivate *priv;
-
- g_return_if_fail (model != NULL);
- g_return_if_fail (NAUTILUS_IS_LIST_MODEL (model));
- g_return_if_fail (!view || GTK_IS_TREE_VIEW (view));
-
- priv = nautilus_list_model_get_instance_private (model);
-
- priv->drag_view = view;
- priv->drag_begin_x = drag_begin_x;
- priv->drag_begin_y = drag_begin_y;
-}
-
-GtkTreeView *
-nautilus_list_model_get_drag_view (NautilusListModel *model,
- int *drag_begin_x,
- int *drag_begin_y)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- if (drag_begin_x != NULL)
- {
- *drag_begin_x = priv->drag_begin_x;
- }
-
- if (drag_begin_y != NULL)
- {
- *drag_begin_y = priv->drag_begin_y;
- }
-
- return priv->drag_view;
-}
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-GtkTargetList *
-nautilus_list_model_get_drag_target_list ()
-{
- GtkTargetList *target_list;
-
- target_list = gtk_target_list_new (drag_types, G_N_ELEMENTS (drag_types));
- gtk_target_list_add_text_targets (target_list, NAUTILUS_ICON_DND_TEXT);
-
- return target_list;
-}
-#endif
-
-int
-nautilus_list_model_add_column (NautilusListModel *model,
- NautilusColumn *column)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- g_ptr_array_add (priv->columns, column);
- g_object_ref (column);
-
- return NAUTILUS_LIST_MODEL_NUM_COLUMNS + (priv->columns->len - 1);
-}
-
-static void
-nautilus_list_model_dispose (GObject *object)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
- int i;
-
- model = NAUTILUS_LIST_MODEL (object);
- priv = nautilus_list_model_get_instance_private (model);
-
- if (priv->columns)
- {
- for (i = 0; i < priv->columns->len; i++)
- {
- g_object_unref (priv->columns->pdata[i]);
- }
- g_ptr_array_free (priv->columns, TRUE);
- priv->columns = NULL;
- }
-
- if (priv->files)
- {
- g_sequence_free (priv->files);
- priv->files = NULL;
- }
-
- if (priv->top_reverse_map)
- {
- g_hash_table_destroy (priv->top_reverse_map);
- priv->top_reverse_map = NULL;
- }
- if (priv->directory_reverse_map)
- {
- g_hash_table_destroy (priv->directory_reverse_map);
- priv->directory_reverse_map = NULL;
- }
-
- G_OBJECT_CLASS (nautilus_list_model_parent_class)->dispose (object);
-}
-
-static void
-nautilus_list_model_finalize (GObject *object)
-{
- NautilusListModel *model;
- NautilusListModelPrivate *priv;
-
- model = NAUTILUS_LIST_MODEL (object);
- priv = nautilus_list_model_get_instance_private (model);
-
- if (priv->highlight_files != NULL)
- {
- nautilus_file_list_free (priv->highlight_files);
- priv->highlight_files = NULL;
- }
-
- G_OBJECT_CLASS (nautilus_list_model_parent_class)->finalize (object);
-}
-
-static void
-nautilus_list_model_init (NautilusListModel *model)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- priv->files = g_sequence_new ((GDestroyNotify) file_entry_free);
- priv->top_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
- priv->directory_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
- priv->stamp = g_random_int ();
- priv->sort_attribute = 0;
- priv->columns = g_ptr_array_new ();
-}
-
-static void
-nautilus_list_model_class_init (NautilusListModelClass *klass)
-{
- GObjectClass *object_class;
-
- attribute_name_q = g_quark_from_static_string ("name");
- attribute_modification_date_q = g_quark_from_static_string ("modification_date");
- attribute_date_modified_q = g_quark_from_static_string ("date_modified");
-
- object_class = (GObjectClass *) klass;
- object_class->finalize = nautilus_list_model_finalize;
- object_class->dispose = nautilus_list_model_dispose;
-
- list_model_signals[SUBDIRECTORY_UNLOADED] =
- g_signal_new ("subdirectory-unloaded",
- NAUTILUS_TYPE_LIST_MODEL,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (NautilusListModelClass, subdirectory_unloaded),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1,
- NAUTILUS_TYPE_DIRECTORY);
-
- list_model_signals[GET_ICON_SCALE] =
- g_signal_new ("get-icon-scale",
- NAUTILUS_TYPE_LIST_MODEL,
- G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- NULL,
- G_TYPE_INT, 0);
-}
-
-static void
-nautilus_list_model_tree_model_init (GtkTreeModelIface *iface)
-{
- iface->get_flags = nautilus_list_model_get_flags;
- iface->get_n_columns = nautilus_list_model_get_n_columns;
- iface->get_column_type = nautilus_list_model_get_column_type;
- iface->get_iter = nautilus_list_model_get_iter;
- iface->get_path = nautilus_list_model_get_path;
- iface->get_value = nautilus_list_model_get_value;
- iface->iter_next = nautilus_list_model_iter_next;
- iface->iter_children = nautilus_list_model_iter_children;
- iface->iter_has_child = nautilus_list_model_iter_has_child;
- iface->iter_n_children = nautilus_list_model_iter_n_children;
- iface->iter_nth_child = nautilus_list_model_iter_nth_child;
- iface->iter_parent = nautilus_list_model_iter_parent;
-}
-
-static void
-nautilus_list_model_sortable_init (GtkTreeSortableIface *iface)
-{
- iface->get_sort_column_id = nautilus_list_model_get_sort_column_id;
- iface->set_sort_column_id = nautilus_list_model_set_sort_column_id;
- iface->has_default_sort_func = nautilus_list_model_has_default_sort_func;
-}
-
-void
-nautilus_list_model_subdirectory_done_loading (NautilusListModel *model,
- NautilusDirectory *directory)
-{
- NautilusListModelPrivate *priv;
- GtkTreeIter iter;
- GtkTreePath *path;
- FileEntry *file_entry, *dummy_entry;
- GSequenceIter *parent_ptr, *dummy_ptr;
- GSequence *files;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- if (model == NULL || priv->directory_reverse_map == NULL)
- {
- return;
- }
- parent_ptr = g_hash_table_lookup (priv->directory_reverse_map,
- directory);
- if (parent_ptr == NULL)
- {
- return;
- }
-
- file_entry = g_sequence_get (parent_ptr);
- files = file_entry->files;
-
- /* Only swap loading -> empty if we saw no files yet at "done",
- * otherwise, toggle loading at first added file to the model.
- */
- if (!nautilus_directory_is_not_empty (directory) &&
- g_sequence_get_length (files) == 1)
- {
- dummy_ptr = g_sequence_get_iter_at_pos (file_entry->files, 0);
- dummy_entry = g_sequence_get (dummy_ptr);
- if (dummy_entry->file == NULL)
- {
- /* was the dummy file */
- file_entry->loaded = 1;
-
- iter.stamp = priv->stamp;
- iter.user_data = dummy_ptr;
-
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
- gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
- gtk_tree_path_free (path);
- }
- }
-}
-
-static void
-refresh_row (gpointer data,
- gpointer user_data)
-{
- NautilusFile *file;
- NautilusListModel *model;
- GList *iters, *l;
- GtkTreePath *path;
-
- model = user_data;
- file = data;
-
- iters = nautilus_list_model_get_all_iters_for_file (model, file);
- for (l = iters; l != NULL; l = l->next)
- {
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), l->data);
- gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, l->data);
-
- gtk_tree_path_free (path);
- }
-
- g_list_free_full (iters, g_free);
-}
-
-void
-nautilus_list_model_set_highlight_for_files (NautilusListModel *model,
- GList *files)
-{
- NautilusListModelPrivate *priv;
-
- priv = nautilus_list_model_get_instance_private (model);
-
- if (priv->highlight_files != NULL)
- {
- g_list_foreach (priv->highlight_files, refresh_row, model);
- nautilus_file_list_free (priv->highlight_files);
- priv->highlight_files = NULL;
- }
-
- if (files != NULL)
- {
- priv->highlight_files = nautilus_file_list_copy (files);
- g_list_foreach (priv->highlight_files, refresh_row, model);
- }
-}
diff --git a/src/nautilus-list-model.h b/src/nautilus-list-model.h
deleted file mode 100644
index cb430cfc1cacebbdc7926288ae22ce178f3d6d41..0000000000000000000000000000000000000000
--- a/src/nautilus-list-model.h
+++ /dev/null
@@ -1,115 +0,0 @@
-
-/* fm-list-model.h - a GtkTreeModel for file lists.
-
- Copyright (C) 2001, 2002 Anders Carlsson
-
- The Gnome Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- The Gnome Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the Gnome Library; see the file COPYING.LIB. If not,
- see .
-
- Authors: Anders Carlsson
-*/
-
-#pragma once
-
-#include
-#include
-#include "nautilus-file.h"
-#include "nautilus-directory.h"
-#include
-
-#define NAUTILUS_TYPE_LIST_MODEL nautilus_list_model_get_type()
-G_DECLARE_DERIVABLE_TYPE (NautilusListModel, nautilus_list_model, NAUTILUS, LIST_MODEL, GObject);
-
-enum {
- NAUTILUS_LIST_MODEL_FILE_COLUMN,
- NAUTILUS_LIST_MODEL_SUBDIRECTORY_COLUMN,
- NAUTILUS_LIST_MODEL_SMALL_ICON_COLUMN,
- NAUTILUS_LIST_MODEL_STANDARD_ICON_COLUMN,
- NAUTILUS_LIST_MODEL_LARGE_ICON_COLUMN,
- NAUTILUS_LIST_MODEL_LARGER_ICON_COLUMN,
- NAUTILUS_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN,
- NAUTILUS_LIST_MODEL_NUM_COLUMNS
-};
-
-struct _NautilusListModelClass
-{
- GObjectClass parent_class;
-
- void (* subdirectory_unloaded)(NautilusListModel *model,
- NautilusDirectory *subdirectory);
-};
-
-gboolean nautilus_list_model_add_file (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory);
-void nautilus_list_model_file_changed (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory);
-gboolean nautilus_list_model_is_empty (NautilusListModel *model);
-void nautilus_list_model_remove_file (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory);
-void nautilus_list_model_clear (NautilusListModel *model);
-gboolean nautilus_list_model_get_tree_iter_from_file (NautilusListModel *model,
- NautilusFile *file,
- NautilusDirectory *directory,
- GtkTreeIter *iter);
-GList * nautilus_list_model_get_all_iters_for_file (NautilusListModel *model,
- NautilusFile *file);
-gboolean nautilus_list_model_get_first_iter_for_file (NautilusListModel *model,
- NautilusFile *file,
- GtkTreeIter *iter);
-void nautilus_list_model_set_should_sort_directories_first (NautilusListModel *model,
- gboolean sort_directories_first);
-
-int nautilus_list_model_get_sort_column_id_from_attribute (NautilusListModel *model,
- GQuark attribute);
-GQuark nautilus_list_model_get_attribute_from_sort_column_id (NautilusListModel *model,
- int sort_column_id);
-void nautilus_list_model_sort_files (NautilusListModel *model,
- GList **files);
-
-NautilusListZoomLevel nautilus_list_model_get_zoom_level_from_column_id (int column);
-int nautilus_list_model_get_column_id_from_zoom_level (NautilusListZoomLevel zoom_level);
-guint nautilus_list_model_get_icon_size_for_zoom_level (NautilusListZoomLevel zoom_level);
-
-NautilusFile * nautilus_list_model_file_for_path (NautilusListModel *model, GtkTreePath *path);
-gboolean nautilus_list_model_load_subdirectory (NautilusListModel *model, GtkTreePath *path, NautilusDirectory **directory);
-void nautilus_list_model_unload_subdirectory (NautilusListModel *model, GtkTreeIter *iter);
-
-void nautilus_list_model_set_drag_view (NautilusListModel *model,
- GtkTreeView *view,
- int begin_x,
- int begin_y);
-GtkTreeView * nautilus_list_model_get_drag_view (NautilusListModel *model,
- int *drag_begin_x,
- int *drag_begin_y);
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-GtkTargetList * nautilus_list_model_get_drag_target_list (void);
-#endif
-
-int nautilus_list_model_compare_func (NautilusListModel *model,
- NautilusFile *file1,
- NautilusFile *file2);
-
-
-int nautilus_list_model_add_column (NautilusListModel *model,
- NautilusColumn *column);
-
-void nautilus_list_model_subdirectory_done_loading (NautilusListModel *model,
- NautilusDirectory *directory);
-
-void nautilus_list_model_set_highlight_for_files (NautilusListModel *model,
- GList *files);
diff --git a/src/nautilus-list-view-dnd.c b/src/nautilus-list-view-dnd.c
deleted file mode 100644
index cef6192c50b580e810e9ea0b6636b43eecf611e9..0000000000000000000000000000000000000000
--- a/src/nautilus-list-view-dnd.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* nautilus-list-view-dnd.c
- *
- * Copyright (C) 2015 Carlos Soriano
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-#include
-
-#include "nautilus-list-view-dnd.h"
-#include "nautilus-list-view-private.h"
-
-static GtkTargetList *source_target_list = NULL;
-
-static void
-drag_info_data_free (NautilusListView *list_view);
-
-static void
-drag_data_get_callback (GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- gpointer user_data)
-{
- GtkTreeView *tree_view;
- GtkTreeModel *model;
- NautilusListView *list_view;
-
- tree_view = GTK_TREE_VIEW (widget);
- list_view = NAUTILUS_LIST_VIEW (user_data);
-
- model = gtk_tree_view_get_model (tree_view);
-
- if (model == NULL)
- {
- return;
- }
-
- if (list_view->details->drag_source_info == NULL ||
- list_view->details->drag_source_info->selection_cache == NULL)
- {
- return;
- }
-
- nautilus_drag_drag_data_get_from_cache (list_view->details->drag_source_info->selection_cache,
- context, selection_data, info, time);
-}
-
-static cairo_surface_t *
-get_drag_surface (NautilusListView *view)
-{
- GtkTreeModel *model;
- GtkTreePath *path;
- GtkTreeIter iter;
- cairo_surface_t *ret;
- GdkRectangle cell_area;
-
- ret = NULL;
-
- if (gtk_tree_view_get_path_at_pos (view->details->tree_view,
- view->details->drag_x,
- view->details->drag_y,
- &path, NULL, NULL, NULL))
- {
- model = gtk_tree_view_get_model (view->details->tree_view);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_model_get (model, &iter,
- nautilus_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
- &ret,
- -1);
- }
-
- gtk_tree_view_get_cell_area (view->details->tree_view,
- path,
- view->details->file_name_column,
- &cell_area);
-
- gtk_tree_path_free (path);
-
- return ret;
-}
-
-/* iteration glue struct */
-typedef struct
-{
- NautilusListView *view;
- NautilusDragEachSelectedItemDataGet iteratee;
- gpointer iteratee_data;
-} ListGetDataBinderContext;
-
-static void
-item_get_data_binder (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- ListGetDataBinderContext *context = data;
- NautilusFile *file;
- GtkTreeView *treeview;
- GtkTreeViewColumn *column;
- GdkRectangle cell_area;
- int drag_begin_y = 0;
- char *uri;
-
- treeview = nautilus_list_model_get_drag_view (context->view->details->model,
- NULL,
- &drag_begin_y);
- column = gtk_tree_view_get_column (treeview, 0);
-
- file = nautilus_list_model_file_for_path (NAUTILUS_LIST_MODEL (model), path);
- if (file == NULL)
- {
- return;
- }
-
- gtk_tree_view_get_cell_area (treeview,
- path,
- column,
- &cell_area);
-
- uri = nautilus_file_get_activation_uri (file);
-
- nautilus_file_unref (file);
-
- /* pass the uri, mouse-relative x/y and icon width/height */
- context->iteratee (uri,
- 0,
- cell_area.y - drag_begin_y,
- cell_area.width,
- cell_area.height,
- context->iteratee_data);
-
- g_free (uri);
-}
-
-static void
-each_item_get_data_binder (NautilusDragEachSelectedItemDataGet iteratee,
- gpointer iterator_context,
- gpointer data)
-{
- NautilusListView *view = NAUTILUS_LIST_VIEW (iterator_context);
- ListGetDataBinderContext context;
- GtkTreeSelection *selection;
-
- context.view = view;
- context.iteratee = iteratee;
- context.iteratee_data = data;
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_view));
- gtk_tree_selection_selected_foreach (selection, item_get_data_binder, &context);
-}
-
-static void
-drag_begin_callback (GtkWidget *widget,
- GdkDragContext *context,
- NautilusListView *view)
-{
- cairo_surface_t *surface;
- NautilusWindow *window;
- GList *dragged_files;
-
- window = nautilus_files_view_get_window (NAUTILUS_FILES_VIEW (view));
- surface = get_drag_surface (view);
- if (surface)
- {
- gtk_drag_set_icon_surface (context, surface);
- cairo_surface_destroy (surface);
- }
- else
- {
- gtk_drag_set_icon_default (context);
- }
-
- view->details->drag_button = 0;
- view->details->drag_started = TRUE;
-
- view->details->drag_source_info->selection_cache = nautilus_drag_create_selection_cache (view,
- each_item_get_data_binder);
-
- dragged_files = nautilus_drag_file_list_from_selection_list (view->details->drag_source_info->selection_cache);
- if (nautilus_file_list_are_all_folders (dragged_files))
- {
- nautilus_window_start_dnd (window, context);
- }
- g_list_free_full (dragged_files, g_object_unref);
-}
-
-static void
-drag_end_callback (GtkWidget *widget,
- GdkDragContext *context,
- NautilusListView *list_view)
-{
- NautilusWindow *window;
-
- window = nautilus_files_view_get_window (NAUTILUS_FILES_VIEW (list_view));
-
- nautilus_window_end_dnd (window, context);
-
- drag_info_data_free (list_view);
-}
-
-static void
-drag_info_data_free (NautilusListView *list_view)
-{
- nautilus_drag_destroy_selection_list (list_view->details->drag_source_info->selection_cache);
- list_view->details->drag_source_info->selection_cache = NULL;
-
- g_free (list_view->details->drag_source_info);
- list_view->details->drag_source_info = NULL;
-
- g_signal_handlers_disconnect_by_func (list_view->details->tree_view, drag_begin_callback, list_view);
- g_signal_handlers_disconnect_by_func (list_view->details->tree_view, drag_data_get_callback, list_view);
- g_signal_handlers_disconnect_by_func (list_view->details->tree_view, drag_end_callback, list_view);
-}
-
-NautilusDragInfo *
-nautilus_list_view_dnd_get_drag_source_data (NautilusListView *list_view,
- GdkDragContext *context)
-{
- GtkTreeView *tree_view;
- GtkTreeModel *model;
-
- tree_view = GTK_TREE_VIEW (list_view->details->tree_view);
-
- model = gtk_tree_view_get_model (tree_view);
-
- if (model == NULL)
- {
- return NULL;
- }
-
- if (list_view->details->drag_source_info == NULL ||
- list_view->details->drag_source_info->selection_cache == NULL)
- {
- return NULL;
- }
-
- return list_view->details->drag_source_info;
-}
-
-void
-nautilus_list_view_dnd_init (NautilusListView *list_view)
-{
- if (list_view->details->drag_source_info != NULL)
- {
- return;
- }
-
- list_view->details->drag_source_info = g_new0 (NautilusDragInfo, 1);
-
- g_signal_connect_object (list_view->details->tree_view, "drag-begin",
- G_CALLBACK (drag_begin_callback), list_view, 0);
- g_signal_connect_object (list_view->details->tree_view, "drag-end",
- G_CALLBACK (drag_end_callback), list_view, 0);
- g_signal_connect_object (list_view->details->tree_view, "drag-data-get",
- G_CALLBACK (drag_data_get_callback), list_view, 0);
-}
-
-void
-nautilus_list_view_dnd_drag_begin (NautilusListView *list_view,
- gdouble offset_x,
- gdouble offset_y,
- GdkEvent *event)
-{
- if (list_view->details->drag_button == 0)
- {
- return;
- }
-
- if (!source_target_list)
- {
- source_target_list = nautilus_list_model_get_drag_target_list ();
- }
-
- if (gtk_drag_check_threshold (GTK_WIDGET (list_view->details->tree_view),
- list_view->details->drag_x,
- list_view->details->drag_y,
- list_view->details->drag_x + offset_x,
- list_view->details->drag_y + offset_y))
- {
- guint32 actions;
-
- actions = GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK;
- list_view->details->drag_source_info->source_actions = actions;
- gtk_drag_begin_with_coordinates (GTK_WIDGET (list_view->details->tree_view),
- source_target_list,
- actions,
- list_view->details->drag_button,
- (GdkEvent *) event,
- -1,
- -1);
- }
-}
-#endif
diff --git a/src/nautilus-list-view-dnd.h b/src/nautilus-list-view-dnd.h
deleted file mode 100644
index 88ade6770de5cba8baaeae49fa117e6d9e42bf11..0000000000000000000000000000000000000000
--- a/src/nautilus-list-view-dnd.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* nautilus-list-view-dnd.h
- *
- * Copyright (C) 2015 Carlos Soriano
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-
-#include
-
-#include "nautilus-list-view.h"
-
-#include "nautilus-dnd.h"
-
-void nautilus_list_view_dnd_init (NautilusListView *list_view);
-void nautilus_list_view_dnd_drag_begin (NautilusListView *list_view,
- gdouble offset_x,
- gdouble offset_y,
- GdkEvent *event);
-NautilusDragInfo *
-nautilus_list_view_dnd_get_drag_source_data (NautilusListView *list_view,
- GdkDragContext *context);
-#endif
diff --git a/src/nautilus-list-view-private.h b/src/nautilus-list-view-private.h
deleted file mode 100644
index 4c0e3e1c86a5bf2747aed220036fd64fe8228eb9..0000000000000000000000000000000000000000
--- a/src/nautilus-list-view-private.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* nautilus-list-view-private.h
- *
- * Copyright (C) 2015 Carlos Soriano
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-/* Data and functions shared between list view and list view dnd */
-
-#pragma once
-
-#include "nautilus-list-model.h"
-#include "nautilus-tree-view-drag-dest.h"
-#include "nautilus-dnd.h"
-#include "nautilus-tag-manager.h"
-
-struct NautilusListViewDetails {
- GtkTreeView *tree_view;
- NautilusListModel *model;
-
- GtkTreeViewColumn *file_name_column;
- int file_name_column_num;
-
- GtkCellRendererPixbuf *pixbuf_cell;
- GtkCellRendererText *file_name_cell;
- GList *cells;
-
- NautilusListZoomLevel zoom_level;
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
- NautilusTreeViewDragDest *drag_dest;
-#endif
-
- GtkTreePath *first_click_path; /* Both clicks in a double click need to be on the same row */
-
- GtkTreePath *new_selection_path; /* Path of the new selection after removing a file */
-
- GtkTreePath *hover_path;
-
- gint last_event_button_x;
- gint last_event_button_y;
-
- guint drag_button;
- int drag_x;
- int drag_y;
-
- gboolean drag_started;
- gboolean row_selected_on_button_down;
- gboolean active;
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
- NautilusDragInfo *drag_source_info;
-#endif
-
- GHashTable *columns;
- GtkWidget *column_editor;
- GtkWidget *columns_popover;
- GtkWidget *columns_popover_box;
-
- char *original_name;
-
- gulong clipboard_handler_id;
-
- GQuark last_sort_attr;
-
- GRegex *regex;
-
- GCancellable *starred_cancellable;
-};
-
diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c
index 0aeb4b14645689b2afb3df78ab6cf2679773eb9c..ab13aaae42cf8501bca5538c8fb9bec9870f8d69 100644
--- a/src/nautilus-list-view.c
+++ b/src/nautilus-list-view.c
@@ -1,3107 +1,447 @@
-/* fm-list-view.c - implementation of list view of directory.
- *
- * Copyright (C) 2000 Eazel, Inc.
- * Copyright (C) 2001, 2002 Anders Carlsson
- *
- * The Gnome Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * The Gnome Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with the Gnome Library; see the file COPYING.LIB. If not,
- * see .
+/*
+ * Copyright (C) 2000 Eazel, Inc.
+ * Copyright (C) 2001, 2002 Anders Carlsson
+ * Copyright (C) 2022 GNOME project contributors
*
- * Authors: John Sullivan
- * Anders Carlsson
- * David Emory Watson
+ * SPDX-License-Identifier: GPL-3.0-or-later
*/
-#include "nautilus-list-view.h"
-#include "nautilus-list-view-private.h"
-
-#include
-#include
-#include
#include
-#include
-#include
-#define DEBUG_FLAG NAUTILUS_DEBUG_LIST_VIEW
-#include "nautilus-debug.h"
+/* Needed for NautilusColumn. */
+#include
+
+#include "nautilus-list-base-private.h"
+#include "nautilus-list-view.h"
-#include "nautilus-clipboard.h"
#include "nautilus-column-chooser.h"
#include "nautilus-column-utilities.h"
-#include "nautilus-dnd.h"
-#include "nautilus-enums.h"
-#include "nautilus-error-reporting.h"
+#include "nautilus-directory.h"
+#include "nautilus-file.h"
#include "nautilus-file-utilities.h"
-#include "nautilus-files-view-dnd.h"
#include "nautilus-global-preferences.h"
-#include "nautilus-list-model.h"
-#include "nautilus-list-view-dnd.h"
+#include "nautilus-label-cell.h"
#include "nautilus-metadata.h"
+#include "nautilus-name-cell.h"
#include "nautilus-search-directory.h"
+#include "nautilus-star-cell.h"
#include "nautilus-tag-manager.h"
-#include "nautilus-toolbar.h"
-#include "nautilus-tree-view-drag-dest.h"
-#include "nautilus-ui-utilities.h"
-#include "nautilus-view.h"
-#include "nautilus-tracker-utilities.h"
-struct SelectionForeachData
+struct _NautilusListView
{
- GList *list;
- GtkTreeSelection *selection;
-};
+ NautilusListBase parent_instance;
-/*
- * The row height should be large enough to not clip emblems.
- * Computing this would be costly, so we just choose a number
- * that works well with the set of emblems we've designed.
- */
-#define LIST_VIEW_MINIMUM_ROW_HEIGHT 28
+ GtkColumnView *view_ui;
-/* The star icon itself is 16px, which leaves an empty 16px gutter on each side,
- * which is necessary to avoid the overlay scrollbar.
- */
-#define STAR_COLUMN_WIDTH 48
-
-/* We wait two seconds after row is collapsed to unload the subdirectory */
-#define COLLAPSE_TO_UNLOAD_DELAY 2
-
-/* According to Pango docs, alpha is a guint16 value between 0 and 65535. */
-#define ALPHA_55_PERCENT ((guint16) (0.55 * 0xffff))
-
-static GdkCursor *hand_cursor = NULL;
-
-static GList *nautilus_list_view_get_selection (NautilusFilesView *view);
-static GList *nautilus_list_view_get_selection_for_file_transfer (NautilusFilesView *view);
-static void nautilus_list_view_set_zoom_level (NautilusListView *view,
- NautilusListZoomLevel new_level);
-static void nautilus_list_view_scroll_to_file (NautilusListView *view,
- NautilusFile *file);
-static void nautilus_list_view_sort_directories_first_changed (NautilusFilesView *view);
-
-static void apply_columns_settings (NautilusListView *list_view,
- char **column_order,
- char **visible_columns);
-static char **get_visible_columns (NautilusListView *list_view);
-static char **get_default_visible_columns (NautilusListView *list_view);
-static char **get_column_order (NautilusListView *list_view);
-static char **get_default_column_order (NautilusListView *list_view);
-static void popup_column_header_menu (NautilusListView *list_view,
- gdouble x,
- gdouble y);
-
-G_DEFINE_TYPE (NautilusListView, nautilus_list_view, NAUTILUS_TYPE_FILES_VIEW);
-
-static const char *default_search_visible_columns[] =
-{
- "name", "size", "where", NULL
-};
+ GActionGroup *action_group;
+ gint zoom_level;
-static const char *default_search_columns_order[] =
-{
- "name", "size", "where", NULL
-};
+ gboolean directories_first;
-static const char *default_recent_visible_columns[] =
-{
- "name", "where", "recency", NULL
-};
+ GQuark path_attribute_q;
+ GFile *file_path_base_location;
-static const char *default_recent_columns_order[] =
-{
- "name", "where", "recency", NULL
+ GtkColumnViewColumn *star_column;
+ GtkWidget *column_editor;
+ GHashTable *factory_to_column_map;
};
-static const char *default_trash_visible_columns[] =
+G_DEFINE_TYPE (NautilusListView, nautilus_list_view, NAUTILUS_TYPE_LIST_BASE)
+
+
+static void on_sorter_changed (GtkSorter *sorter,
+ GtkSorterChange change,
+ gpointer user_data);
+
+static const char *default_columns_for_recent[] =
{
- "name", "size", "trash_orig_path", "trashed_on", NULL
+ "name", "size", "recency", NULL
};
-static const char *default_trash_columns_order[] =
+static const char *default_columns_for_trash[] =
{
- "name", "size", "trash_orig_path", "trashed_on", NULL
+ "name", "size", "trashed_on", NULL
};
-static const gchar *
-get_default_sort_order (NautilusFile *file,
- gboolean *reversed)
+static guint
+get_icon_size_for_zoom_level (NautilusListZoomLevel zoom_level)
{
- NautilusFileSortType sort_type;
-
- /* This array makes the #NautilusFileSortType values correspond to the
- * respective column attribute.
- */
- const char *attributes[] =
+ switch (zoom_level)
{
- "name",
- "size",
- "type",
- "date_modified",
- "date_accessed",
- "date_created",
- "starred",
- "trashed_on",
- "search_relevance",
- "recency",
- NULL
- };
+ case NAUTILUS_LIST_ZOOM_LEVEL_SMALL:
+ {
+ return NAUTILUS_LIST_ICON_SIZE_SMALL;
+ }
+ break;
- sort_type = nautilus_file_get_default_sort_type (file, reversed);
+ case NAUTILUS_LIST_ZOOM_LEVEL_MEDIUM:
+ {
+ return NAUTILUS_LIST_ICON_SIZE_MEDIUM;
+ }
+ break;
- return attributes[sort_type];
+ case NAUTILUS_LIST_ZOOM_LEVEL_LARGE:
+ {
+ return NAUTILUS_LIST_ICON_SIZE_LARGE;
+ }
+ break;
+ }
+ g_return_val_if_reached (NAUTILUS_LIST_ICON_SIZE_MEDIUM);
}
-static void
-list_selection_changed_callback (GtkTreeSelection *selection,
- gpointer user_data)
+static guint
+real_get_icon_size (NautilusListBase *files_model_view)
{
- NautilusFilesView *view;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_model_view);
- view = NAUTILUS_FILES_VIEW (user_data);
-
- nautilus_files_view_notify_selection_changed (view);
+ return get_icon_size_for_zoom_level (self->zoom_level);
}
-static void
-activate_selected_items (NautilusListView *view)
+static GtkWidget *
+real_get_view_ui (NautilusListBase *files_model_view)
{
- GList *file_list;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_model_view);
- file_list = nautilus_list_view_get_selection (NAUTILUS_FILES_VIEW (view));
- if (file_list != NULL)
- {
- nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (view),
- file_list,
- 0, TRUE);
- nautilus_file_list_free (file_list);
- }
+ return GTK_WIDGET (self->view_ui);
}
static void
-activate_selected_items_alternate (NautilusListView *view,
- NautilusFile *file,
- gboolean open_in_tab)
+apply_columns_settings (NautilusListView *self,
+ char **column_order,
+ char **visible_columns)
{
- GList *file_list;
- NautilusOpenFlags flags;
-
- flags = 0;
-
- if (open_in_tab)
+ g_autolist (NautilusColumn) all_columns = NULL;
+ NautilusFile *file;
+ NautilusDirectory *directory;
+ g_autoptr (GFile) location = NULL;
+ g_autoptr (GList) view_columns = NULL;
+ GListModel *old_view_columns;
+ g_autoptr (GHashTable) visible_columns_hash = NULL;
+ g_autoptr (GHashTable) old_view_columns_hash = NULL;
+ int column_i = 0;
+
+ file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self));
+ directory = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (self));
+ if (NAUTILUS_IS_SEARCH_DIRECTORY (directory))
{
- flags |= NAUTILUS_OPEN_FLAG_NEW_TAB;
- flags |= NAUTILUS_OPEN_FLAG_DONT_MAKE_ACTIVE;
+ g_autoptr (NautilusQuery) query = NULL;
+
+ query = nautilus_search_directory_get_query (NAUTILUS_SEARCH_DIRECTORY (directory));
+ location = nautilus_query_get_location (query);
}
else
{
- flags |= NAUTILUS_OPEN_FLAG_NEW_WINDOW;
+ location = nautilus_file_get_location (file);
}
- if (file != NULL)
+ all_columns = nautilus_get_columns_for_file (file);
+ all_columns = nautilus_sort_columns (all_columns, column_order);
+
+ /* hash table to lookup if a given column should be visible */
+ visible_columns_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+ /* always show name column */
+ g_hash_table_insert (visible_columns_hash, g_strdup ("name"), g_strdup ("name"));
+
+ /* always show star column if supported */
+ if (nautilus_tag_manager_can_star_contents (nautilus_tag_manager_get (), location) ||
+ nautilus_is_starred_directory (location))
{
- nautilus_file_ref (file);
- file_list = g_list_prepend (NULL, file);
+ g_hash_table_insert (visible_columns_hash, g_strdup ("starred"), g_strdup ("starred"));
}
- else
+
+ if (visible_columns != NULL)
{
- file_list = nautilus_list_view_get_selection (NAUTILUS_FILES_VIEW (view));
+ for (int i = 0; visible_columns[i] != NULL; ++i)
+ {
+ g_hash_table_insert (visible_columns_hash,
+ g_ascii_strdown (visible_columns[i], -1),
+ g_ascii_strdown (visible_columns[i], -1));
+ }
}
- nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (view),
- file_list,
- flags,
- TRUE);
- nautilus_file_list_free (file_list);
-}
-static gboolean
-button_event_modifies_selection (GdkEvent *event)
-{
- GdkModifierType state;
+ old_view_columns_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ NULL);
+ old_view_columns = gtk_column_view_get_columns (self->view_ui);
+ for (guint i = 0; i < g_list_model_get_n_items (old_view_columns); i++)
+ {
+ g_autoptr (GtkColumnViewColumn) view_column = NULL;
+ GtkListItemFactory *factory;
+ NautilusColumn *nautilus_column;
+ gchar *name;
- state = gdk_event_get_modifier_state (event);
+ view_column = g_list_model_get_item (old_view_columns, i);
+ factory = gtk_column_view_column_get_factory (view_column);
+ nautilus_column = g_hash_table_lookup (self->factory_to_column_map, factory);
+ g_object_get (nautilus_column, "name", &name, NULL);
+ g_hash_table_insert (old_view_columns_hash, name, view_column);
+ }
- return (state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
-}
+ for (GList *l = all_columns; l != NULL; l = l->next)
+ {
+ g_autofree char *name = NULL;
+ g_autofree char *lowercase = NULL;
-static int
-get_click_policy (void)
-{
- return g_settings_get_enum (nautilus_preferences,
- NAUTILUS_PREFERENCES_CLICK_POLICY);
-}
+ g_object_get (G_OBJECT (l->data), "name", &name, NULL);
+ lowercase = g_ascii_strdown (name, -1);
-static void
-on_event_controller_motion_motion (GtkEventControllerMotion *controller,
- double x,
- double y,
- gpointer user_data)
-{
- NautilusListView *view;
- GtkWidget *widget;
- GtkTreePath *old_hover_path;
- int x_in_bin;
- int y_in_bin;
+ if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL)
+ {
+ GtkColumnViewColumn *view_column;
- if (get_click_policy () != NAUTILUS_CLICK_POLICY_SINGLE)
- {
- return;
+ view_column = g_hash_table_lookup (old_view_columns_hash, name);
+ if (view_column != NULL)
+ {
+ view_columns = g_list_prepend (view_columns, view_column);
+ }
+ }
}
- view = user_data;
- widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (controller));
- old_hover_path = view->details->hover_path;
-
- gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (widget),
- x, y,
- &x_in_bin, &y_in_bin);
- gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
- x_in_bin, y_in_bin,
- &view->details->hover_path,
- NULL, NULL, NULL);
+ view_columns = g_list_reverse (view_columns);
- if ((old_hover_path != NULL) != (view->details->hover_path != NULL))
+ /* hide columns that are not present in the configuration */
+ for (guint i = 0; i < g_list_model_get_n_items (old_view_columns); i++)
{
- if (view->details->hover_path != NULL)
+ g_autoptr (GtkColumnViewColumn) view_column = NULL;
+
+ view_column = g_list_model_get_item (old_view_columns, i);
+ if (g_list_find (view_columns, view_column) == NULL)
{
- gtk_widget_set_cursor (widget, hand_cursor);
+ gtk_column_view_column_set_visible (view_column, FALSE);
}
else
{
- gtk_widget_set_cursor (widget, NULL);
+ gtk_column_view_column_set_visible (view_column, TRUE);
}
}
- if (old_hover_path != NULL)
- {
- gtk_tree_path_free (old_hover_path);
- }
-}
-
-static void
-on_event_controller_motion_leave (GtkEventControllerMotion *controller,
- gpointer user_data)
-{
- NautilusListView *view;
-
- view = user_data;
-
- if (get_click_policy () != NAUTILUS_CLICK_POLICY_SINGLE ||
- view->details->hover_path == NULL)
+ /* place columns in the correct order */
+ for (GList *l = view_columns; l != NULL; l = l->next, column_i++)
{
- return;
+ gtk_column_view_insert_column (self->view_ui, column_i, l->data);
}
-
- gtk_tree_path_free (view->details->hover_path);
- view->details->hover_path = NULL;
}
static void
-on_event_controller_motion_enter (GtkEventControllerMotion *controller,
- double x,
- double y,
- gpointer user_data)
+real_scroll_to_item (NautilusListBase *files_model_view,
+ guint position)
{
- NautilusListView *view;
- GtkWidget *widget;
- int x_in_bin;
- int y_in_bin;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_model_view);
+ GtkWidget *child;
- if (get_click_policy () != NAUTILUS_CLICK_POLICY_SINGLE)
- {
- return;
- }
+ child = gtk_widget_get_last_child (GTK_WIDGET (self->view_ui));
- view = user_data;
- if (view->details->hover_path != NULL)
+ while (child != NULL && !GTK_IS_LIST_VIEW (child))
{
- gtk_tree_path_free (view->details->hover_path);
+ child = gtk_widget_get_prev_sibling (child);
}
- widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (controller));
- gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (widget),
- x, y,
- &x_in_bin, &y_in_bin);
- gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
- x_in_bin, y_in_bin,
- &view->details->hover_path,
- NULL, NULL, NULL);
-
- if (view->details->hover_path != NULL)
+ if (child != NULL)
{
- gtk_widget_set_cursor (widget, hand_cursor);
+ gtk_widget_activate_action (child, "list.scroll-to-item", "u", position);
}
}
-static void
-row_activated_callback (GtkTreeView *treeview,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- NautilusListView *view)
+static gint
+nautilus_list_view_sort (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
{
- activate_selected_items (view);
+ GQuark attribute_q = GPOINTER_TO_UINT (user_data);
+ NautilusFile *file_a = nautilus_view_item_get_file (NAUTILUS_VIEW_ITEM ((gpointer) a));
+ NautilusFile *file_b = nautilus_view_item_get_file (NAUTILUS_VIEW_ITEM ((gpointer) b));
+
+ /* The reversed argument is FALSE because the columnview sorter handles that
+ * itself and if we don't want to reverse the reverse. The directories_first
+ * argument is also FALSE for the same reason: we don't want the columnview
+ * sorter to reverse it (it would display directories last!); instead we
+ * handle directories_first in a separate sorter. */
+ return nautilus_file_compare_for_sort_by_attribute_q (file_a, file_b,
+ attribute_q,
+ FALSE /* directories_first */,
+ FALSE /* reversed */);
}
-static gboolean
-check_starred_status (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
+static gint
+sort_directories_func (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
{
- NautilusFile *file;
- GList *l;
- GList *changed_files;
-
- changed_files = data;
+ gboolean *directories_first = user_data;
- gtk_tree_model_get (GTK_TREE_MODEL (model),
- iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- if (!file)
+ if (*directories_first)
{
- return FALSE;
- }
+ NautilusFile *file_a = nautilus_view_item_get_file (NAUTILUS_VIEW_ITEM ((gpointer) a));
+ NautilusFile *file_b = nautilus_view_item_get_file (NAUTILUS_VIEW_ITEM ((gpointer) b));
+ gboolean a_is_directory = nautilus_file_is_directory (file_a);
+ gboolean b_is_directory = nautilus_file_is_directory (file_b);
- for (l = changed_files; l != NULL; l = l->next)
- {
- if (nautilus_file_compare_location (NAUTILUS_FILE (l->data), file) == 0)
+ if (a_is_directory && !b_is_directory)
+ {
+ return GTK_ORDERING_SMALLER;
+ }
+ if (b_is_directory && !a_is_directory)
{
- gtk_tree_model_row_changed (model, path, iter);
+ return GTK_ORDERING_LARGER;
}
}
-
- nautilus_file_unref (file);
-
- return FALSE;
-}
-
-static void
-on_starred_files_changed (NautilusTagManager *tag_manager,
- GList *changed_files,
- gpointer user_data)
-{
- NautilusListView *list_view;
-
- list_view = NAUTILUS_LIST_VIEW (user_data);
-
- gtk_tree_model_foreach (GTK_TREE_MODEL (list_view->details->model),
- check_starred_status,
- changed_files);
+ return GTK_ORDERING_EQUAL;
}
-static void
-on_star_cell_renderer_clicked (GtkTreePath *path,
- NautilusListView *list_view)
+static char **
+get_default_visible_columns (NautilusListView *self)
{
- NautilusListModel *list_model;
NautilusFile *file;
- g_autofree gchar *uri = NULL;
- GList *selection;
- NautilusTagManager *tag_manager = nautilus_tag_manager_get ();
-
- list_model = list_view->details->model;
- file = nautilus_list_model_file_for_path (list_model, path);
+ file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self));
- if (file == NULL)
+ if (nautilus_file_is_in_trash (file))
{
- /* This row is a label, not a file */
- return;
+ return g_strdupv ((gchar **) default_columns_for_trash);
}
- uri = nautilus_file_get_uri (file);
- selection = g_list_prepend (NULL, file);
-
- if (nautilus_tag_manager_file_is_starred (tag_manager, uri))
- {
- nautilus_tag_manager_unstar_files (tag_manager,
- G_OBJECT (list_view),
- selection,
- NULL,
- list_view->details->starred_cancellable);
- }
- else
+ if (nautilus_file_is_in_recent (file))
{
- nautilus_tag_manager_star_files (tag_manager,
- G_OBJECT (list_view),
- selection,
- NULL,
- list_view->details->starred_cancellable);
+ return g_strdupv ((gchar **) default_columns_for_recent);
}
- nautilus_file_list_free (selection);
+ return g_settings_get_strv (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
}
-static void
-on_tree_view_click_gesture_pressed (GtkGestureClick *gesture,
- gint n_press,
- gdouble x,
- gdouble y,
- gpointer callback_data)
+static char **
+get_visible_columns (NautilusListView *self)
{
- NautilusListView *view;
- GtkWidget *widget;
- GtkTreeView *tree_view;
- g_autoptr (GtkTreePath) path = NULL;
- GtkTreeViewColumn *column;
- GtkTreeSelection *selection;
- guint button;
- gint bin_x;
- gint bin_y;
- GdkEventSequence *sequence;
- GdkEvent *event;
- gboolean on_expander, show_expanders;
- gboolean is_simple_click, path_selected;
NautilusFile *file;
- gboolean on_star;
-
- view = NAUTILUS_LIST_VIEW (callback_data);
- widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
- tree_view = GTK_TREE_VIEW (widget);
- selection = gtk_tree_view_get_selection (tree_view);
- button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
-
- gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &bin_x, &bin_y);
+ g_autofree gchar **visible_columns = NULL;
- view->details->last_event_button_x = bin_x;
- view->details->last_event_button_y = bin_y;
+ file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self));
- /* Don't handle extra mouse buttons here */
- if (button > 5)
+ visible_columns = nautilus_file_get_metadata_list (file,
+ NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS);
+ if (visible_columns == NULL || visible_columns[0] == NULL)
{
- return;
+ return get_default_visible_columns (self);
}
- sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
- event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+ return g_steal_pointer (&visible_columns);
+}
- /* Column headers lie above bin_window, hence negative y coordinate. */
- if (bin_y < 0)
- {
- if (button == GDK_BUTTON_SECONDARY)
- {
- popup_column_header_menu (view, x, y);
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
- }
- else
- {
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
- }
- return;
- }
+static char **
+get_default_column_order (NautilusListView *self)
+{
+ NautilusFile *file;
- nautilus_list_model_set_drag_view
- (NAUTILUS_LIST_MODEL (gtk_tree_view_get_model (tree_view)),
- tree_view,
- bin_x, bin_y);
+ file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self));
- /* Ignore double click if we are in single click mode */
- if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE && n_press >= 2)
+ if (nautilus_file_is_in_trash (file))
{
- return;
+ return g_strdupv ((gchar **) default_columns_for_trash);
}
- is_simple_click = ((button == GDK_BUTTON_PRIMARY || button == GDK_BUTTON_MIDDLE) && (n_press == 1));
-
- /* No item at this position */
- if (!gtk_tree_view_get_path_at_pos (tree_view, bin_x, bin_y,
- &path, &column, NULL, NULL))
+ if (nautilus_file_is_in_recent (file))
{
- if (is_simple_click)
- {
- g_clear_pointer (&view->details->first_click_path, gtk_tree_path_free);
- }
+ return g_strdupv ((gchar **) default_columns_for_recent);
+ }
- gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (tree_view));
+ return g_settings_get_strv (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
+}
- if (button == GDK_BUTTON_SECONDARY)
- {
- nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (view),
- x, y);
- }
+static char **
+get_column_order (NautilusListView *self)
+{
+ NautilusFile *file;
+ g_autofree gchar **column_order = NULL;
- return;
- }
+ file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self));
- on_expander = FALSE;
- path_selected = gtk_tree_selection_path_is_selected (selection, path);
- show_expanders = g_settings_get_boolean (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE);
+ column_order = nautilus_file_get_metadata_list (file,
+ NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER);
- if (show_expanders)
+ if (column_order != NULL && column_order[0] != NULL)
{
- GdkRectangle cell_area;
+ return g_steal_pointer (&column_order);
+ }
- gtk_tree_view_get_cell_area (tree_view, path, column, &cell_area);
+ return get_default_column_order (self);
+}
+static void
+update_columns_settings_from_metadata_and_preferences (NautilusListView *self)
+{
+ g_auto (GStrv) column_order = get_column_order (self);
+ g_auto (GStrv) visible_columns = get_visible_columns (self);
- /* We assume that the cell area excludes the expander itself.
- * Explanatory link for future reference:
- * https://gitlab.gnome.org/GNOME/nautilus/merge_requests/97#note_58649 */
+ apply_columns_settings (self, column_order, visible_columns);
+}
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- {
- on_expander = bin_x > (cell_area.x + cell_area.width);
- }
- else
- {
- on_expander = bin_x < cell_area.x;
- }
- }
+static GFile *
+get_base_location (NautilusListView *self)
+{
+ NautilusDirectory *directory;
+ GFile *base_location = NULL;
- /* Keep track of path of last click so double clicks only happen
- * on the same item */
- if (is_simple_click)
+ directory = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (self));
+ if (NAUTILUS_IS_SEARCH_DIRECTORY (directory))
{
- g_clear_pointer (&view->details->first_click_path, gtk_tree_path_free);
- view->details->first_click_path = gtk_tree_path_copy (path);
- }
+ g_autoptr (NautilusQuery) query = NULL;
+ g_autoptr (GFile) location = NULL;
- on_star = (g_hash_table_lookup (view->details->columns, "starred") == column &&
- !gtk_tree_view_is_blank_at_pos (tree_view,
- bin_x,
- bin_y,
- NULL,
- NULL,
- NULL,
- NULL));
-
- if (is_simple_click && on_star)
- {
- on_star_cell_renderer_clicked (path, view);
- }
- else if (n_press == 2 && !on_star)
- {
- /* Double clicking does not trigger a D&D action. */
- view->details->drag_button = 0;
+ query = nautilus_search_directory_get_query (NAUTILUS_SEARCH_DIRECTORY (directory));
+ location = nautilus_query_get_location (query);
- /* NOTE: Activation can actually destroy the view if we're switching */
- if (!on_expander &&
- view->details->first_click_path &&
- gtk_tree_path_compare (path, view->details->first_click_path) == 0)
+ if (!nautilus_is_recent_directory (location) &&
+ !nautilus_is_starred_directory (location) &&
+ !nautilus_is_trash_directory (location))
{
- if ((button == GDK_BUTTON_PRIMARY) && button_event_modifies_selection (event))
- {
- file = nautilus_list_model_file_for_path (view->details->model, path);
- if (file != NULL)
- {
- activate_selected_items_alternate (view, file, TRUE);
- nautilus_file_unref (file);
- }
- }
- else if ((button == GDK_BUTTON_PRIMARY || button == GDK_BUTTON_SECONDARY))
- {
- activate_selected_items (view);
- }
- }
- else
- {
- return;
+ base_location = g_steal_pointer (&location);
}
}
- else
- {
- GdkModifierType state;
- g_autoptr (GtkTreePath) cursor = NULL;
- GList *selected_rows = NULL;
-
- state = gdk_event_get_modifier_state (event);
-
- /* We cannot easily match the expected behavior of Shift+click, so we
- * must fall back to GtkTreeView's default event handling.
- *
- * If Shift and Ctrl are held simultateously, GtkTreeView ignores Shift,
- * so we implement a more useful behavior ourselves.
- */
- if ((state & GDK_SHIFT_MASK) != 0 && (state & GDK_CONTROL_MASK) == 0)
- {
- return;
- }
- /* Let GtkTreeView handle tree expanding/collapsing. */
- if (is_simple_click && on_expander)
- {
- return;
- }
+ return base_location;
+}
- /* As we don't let GtkTreeView default event handling go through, so we
- * must grab the focus ourselves. */
- gtk_widget_grab_focus (widget);
+static void
+on_column_view_item_activated (GtkGridView *grid_view,
+ guint position,
+ gpointer user_data)
+{
+ NautilusListView *self = NAUTILUS_LIST_VIEW (user_data);
- if (!path_selected)
- {
- if ((state & GDK_CONTROL_MASK) != 0)
- {
- if ((state & GDK_SHIFT_MASK) != 0)
- {
- gtk_tree_view_get_cursor (tree_view, &cursor, NULL);
- if (cursor != NULL)
- {
- gtk_tree_selection_select_range (selection, cursor, path);
- }
- else
- {
- gtk_tree_selection_select_path (selection, path);
- }
- }
- else
- {
- gtk_tree_selection_select_path (selection, path);
- }
- selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
-
- /* This unselects everything */
- gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
-
- /* So select it again */
- for (GList *l = selected_rows; l != NULL; l = l->next)
- {
- gtk_tree_selection_select_path (selection, l->data);
- }
- g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
- }
- else
- {
- gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
- }
- }
+ nautilus_files_view_activate_selection (NAUTILUS_FILES_VIEW (self));
+}
- if (is_simple_click)
- {
- view->details->drag_started = FALSE;
- view->details->drag_button = button;
- view->details->drag_x = bin_x;
- view->details->drag_y = bin_y;
- view->details->row_selected_on_button_down = path_selected;
- }
+static GtkColumnView *
+create_view_ui (NautilusListView *self)
+{
+ NautilusViewModel *model;
+ GtkWidget *widget;
- if (button == GDK_BUTTON_SECONDARY)
- {
- nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (view),
- x, y);
- }
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
+ widget = gtk_column_view_new (GTK_SELECTION_MODEL (model));
- /* Don't open a new tab if we are in single click mode (this would open 2 tabs),
- * or if CTRL or SHIFT is pressed.
- */
- if (button == GDK_BUTTON_MIDDLE &&
- get_click_policy () != NAUTILUS_CLICK_POLICY_SINGLE &&
- !button_event_modifies_selection (event))
- {
- gtk_tree_selection_unselect_all (selection);
- gtk_tree_selection_select_path (selection, path);
+ gtk_widget_set_hexpand (widget, TRUE);
- activate_selected_items_alternate (view, NULL, TRUE);
- }
- }
- gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
-}
-
-static void
-on_tree_view_click_gesture_released (GtkGestureClick *gesture,
- gint n_press,
- gdouble x,
- gdouble y,
- gpointer callback_data)
-{
- NautilusListView *view;
- guint button;
- GdkEventSequence *sequence;
- GdkEvent *event;
- GtkTreeView *tree_view;
- GtkTreeSelection *selection;
- gint x_in_bin;
- gint y_in_bin;
- GtkTreePath *path;
- GdkModifierType state;
-
- view = NAUTILUS_LIST_VIEW (callback_data);
- button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
- if (button != view->details->drag_button)
- {
- return;
- }
-
- view->details->drag_button = 0;
-
- if (view->details->drag_started)
- {
- return;
- }
-
- /* Did not drag. */
-
- sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
- event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
- /* Typically will only happen with GTK+ <= 3.22.30 and <= 3.93.0,
- * where ::released is emitted after ::cancel, but can’t hurt to guard
- * against it anyway.
- */
- if (event == NULL)
- {
- return;
- }
-
- tree_view = view->details->tree_view;
- selection = gtk_tree_view_get_selection (tree_view);
-
-
- gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
- x, y,
- &x_in_bin, &y_in_bin);
-
- if (!gtk_tree_view_get_path_at_pos (tree_view, x_in_bin, y_in_bin, &path, NULL, NULL, NULL))
- {
- return;
- }
-
- state = gdk_event_get_modifier_state (event);
-
- if ((button == GDK_BUTTON_PRIMARY || button == GDK_BUTTON_MIDDLE)
- && ((state & GDK_CONTROL_MASK) != 0 ||
- (state & GDK_SHIFT_MASK) == 0)
- && view->details->row_selected_on_button_down)
- {
- if (!button_event_modifies_selection (event))
- {
- gtk_tree_selection_unselect_all (selection);
- gtk_tree_selection_select_path (selection, path);
- }
- else
- {
- gtk_tree_selection_unselect_path (selection, path);
- }
- }
-
- if ((get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE)
- && !button_event_modifies_selection (event))
- {
- if (button == GDK_BUTTON_PRIMARY)
- {
- activate_selected_items (view);
- }
- else if (button == GDK_BUTTON_MIDDLE)
- {
- activate_selected_items_alternate (view, NULL, TRUE);
- }
- }
- gtk_tree_path_free (path);
-}
-
-static gboolean
-on_event_controller_key_key_pressed (GtkEventControllerKey *controller,
- unsigned int keyval,
- unsigned int keycode,
- GdkModifierType state,
- gpointer user_data)
-{
- GtkWidget *widget;
- NautilusFilesView *view;
- GtkTreeView *tree_view;
-
- widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (controller));
- view = NAUTILUS_FILES_VIEW (user_data);
- tree_view = GTK_TREE_VIEW (widget);
-
- NAUTILUS_LIST_VIEW (view)->details->last_event_button_x = -1;
- NAUTILUS_LIST_VIEW (view)->details->last_event_button_y = -1;
-
- if (keyval == GDK_KEY_Right)
- {
- g_autoptr (GtkTreePath) path = NULL;
-
- gtk_tree_view_get_cursor (tree_view, &path, NULL);
-
- if (path != NULL)
- {
- gtk_tree_view_expand_row (tree_view, path, FALSE);
- }
-
- return GDK_EVENT_STOP;
- }
-
- if (keyval == GDK_KEY_Left)
- {
- g_autoptr (GtkTreePath) path = NULL;
-
- gtk_tree_view_get_cursor (tree_view, &path, NULL);
-
- if (path != NULL && !gtk_tree_view_collapse_row (tree_view, path))
- {
- /* if the row is already collapsed or doesn't have any children,
- * jump to the parent row instead.
- */
- if ((gtk_tree_path_get_depth (path) > 1) && gtk_tree_path_up (path))
- {
- gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
- }
- }
-
- return GDK_EVENT_STOP;
- }
-
- if (keyval == GDK_KEY_space)
- {
- if ((state & GDK_CONTROL_MASK) != 0)
- {
- return GDK_EVENT_PROPAGATE;
- }
-
- if (!gtk_widget_has_focus (GTK_WIDGET (NAUTILUS_LIST_VIEW (view)->details->tree_view)))
- {
- return GDK_EVENT_PROPAGATE;
- }
-
- if ((state & GDK_SHIFT_MASK) != 0)
- {
- activate_selected_items_alternate (NAUTILUS_LIST_VIEW (view), NULL, TRUE);
- }
-
- return GDK_EVENT_STOP;
- }
-
- if (keyval == GDK_KEY_v)
- {
- /* Eat Control + v to not enable type ahead */
- if ((state & GDK_CONTROL_MASK) != 0)
- {
- return GDK_EVENT_STOP;
- }
- }
-
- return GDK_EVENT_PROPAGATE;
-}
-
-static void
-subdirectory_done_loading_callback (NautilusDirectory *directory,
- NautilusListView *view)
-{
- nautilus_list_model_subdirectory_done_loading (view->details->model, directory);
-}
-
-static void
-row_expanded_callback (GtkTreeView *treeview,
- GtkTreeIter *iter,
- GtkTreePath *path,
- gpointer callback_data)
-{
- NautilusListView *view;
- NautilusDirectory *directory;
- char *uri;
-
- view = NAUTILUS_LIST_VIEW (callback_data);
-
- if (!nautilus_list_model_load_subdirectory (view->details->model, path, &directory))
- {
- return;
- }
-
- uri = nautilus_directory_get_uri (directory);
- DEBUG ("Row expanded callback for URI %s", uri);
- g_free (uri);
-
- nautilus_files_view_add_subdirectory (NAUTILUS_FILES_VIEW (view), directory);
-
- if (nautilus_directory_are_all_files_seen (directory))
- {
- nautilus_list_model_subdirectory_done_loading (view->details->model,
- directory);
- }
- else
- {
- g_signal_connect_object (directory, "done-loading",
- G_CALLBACK (subdirectory_done_loading_callback),
- view, 0);
- }
-
- nautilus_directory_unref (directory);
-}
-
-typedef struct
-{
- NautilusFile *file;
- NautilusDirectory *directory;
- NautilusListView *view;
-} UnloadDelayData;
-
-static void
-unload_delay_data_free (UnloadDelayData *unload_data)
-{
- if (unload_data->view != NULL)
- {
- g_object_remove_weak_pointer (G_OBJECT (unload_data->view),
- (gpointer *) &unload_data->view);
- }
-
- nautilus_directory_unref (unload_data->directory);
- nautilus_file_unref (unload_data->file);
-
- g_slice_free (UnloadDelayData, unload_data);
-}
-
-static UnloadDelayData *
-unload_delay_data_new (NautilusFile *file,
- NautilusDirectory *parent_directory,
- NautilusListView *view)
-{
- UnloadDelayData *unload_data;
-
- unload_data = g_slice_new0 (UnloadDelayData);
- unload_data->view = view;
- unload_data->file = nautilus_file_ref (file);
- unload_data->directory = nautilus_directory_ref (parent_directory);
-
- g_object_add_weak_pointer (G_OBJECT (unload_data->view),
- (gpointer *) &unload_data->view);
-
- return unload_data;
-}
-
-static gboolean
-unload_file_timeout (gpointer data)
-{
- UnloadDelayData *unload_data = data;
- GtkTreeIter iter;
- NautilusListModel *model;
- GtkTreePath *path;
-
- if (unload_data->view == NULL)
- {
- goto out;
- }
-
- model = unload_data->view->details->model;
- if (nautilus_list_model_get_tree_iter_from_file (model,
- unload_data->file,
- unload_data->directory,
- &iter))
- {
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
- if (!gtk_tree_view_row_expanded (unload_data->view->details->tree_view,
- path))
- {
- nautilus_list_model_unload_subdirectory (model, &iter);
- }
- gtk_tree_path_free (path);
- }
-
-out:
- unload_delay_data_free (unload_data);
- return FALSE;
-}
-
-static void
-row_collapsed_callback (GtkTreeView *treeview,
- GtkTreeIter *iter,
- GtkTreePath *path,
- gpointer callback_data)
-{
- NautilusListView *view;
- NautilusFile *file;
- NautilusDirectory *directory;
- GtkTreeIter parent;
- UnloadDelayData *unload_data;
- GtkTreeModel *model;
- char *uri;
-
- view = NAUTILUS_LIST_VIEW (callback_data);
- model = GTK_TREE_MODEL (view->details->model);
-
- gtk_tree_model_get (model, iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- uri = nautilus_file_get_uri (file);
- DEBUG ("Row collapsed callback for uri %s", uri);
- g_free (uri);
-
- directory = NULL;
- if (gtk_tree_model_iter_parent (model, &parent, iter))
- {
- gtk_tree_model_get (model, &parent,
- NAUTILUS_LIST_MODEL_SUBDIRECTORY_COLUMN, &directory,
- -1);
- }
-
- unload_data = unload_delay_data_new (file, directory, view);
- g_timeout_add_seconds (COLLAPSE_TO_UNLOAD_DELAY,
- unload_file_timeout,
- unload_data);
-
- nautilus_file_unref (file);
- nautilus_directory_unref (directory);
-}
-
-static void
-subdirectory_unloaded_callback (NautilusListModel *model,
- NautilusDirectory *directory,
- gpointer callback_data)
-{
- NautilusListView *view;
-
- g_return_if_fail (NAUTILUS_IS_LIST_MODEL (model));
- g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
-
- view = NAUTILUS_LIST_VIEW (callback_data);
-
- g_signal_handlers_disconnect_by_func (directory,
- G_CALLBACK (subdirectory_done_loading_callback),
- view);
- nautilus_files_view_remove_subdirectory (NAUTILUS_FILES_VIEW (view), directory);
-}
-
-static gboolean
-test_expand_row_callback (GtkTreeView *tree_view,
- GtkTreeIter *iter,
- GtkTreePath *path,
- gboolean user_data)
-{
- return !g_settings_get_boolean (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE);
-}
-
-static void
-nautilus_list_view_reveal_selection (NautilusFilesView *view)
-{
- g_autolist (NautilusFile) selection = NULL;
-
- g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
-
- selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
-
- /* Make sure at least one of the selected items is scrolled into view */
- if (selection != NULL)
- {
- NautilusListView *list_view;
- NautilusFile *file;
- GtkTreeIter iter;
- GtkTreePath *path;
-
- list_view = NAUTILUS_LIST_VIEW (view);
- file = selection->data;
- if (nautilus_list_model_get_first_iter_for_file (list_view->details->model, file, &iter))
- {
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
-
- gtk_tree_view_scroll_to_cell (list_view->details->tree_view, path, NULL, FALSE, 0.0, 0.0);
-
- gtk_tree_path_free (path);
- }
- }
-}
-
-static gboolean
-sort_criterion_changes_due_to_user (GtkTreeView *tree_view)
-{
- GList *columns, *p;
- GtkTreeViewColumn *column;
- GSignalInvocationHint *ihint;
- gboolean ret;
-
- ret = FALSE;
-
- columns = gtk_tree_view_get_columns (tree_view);
- for (p = columns; p != NULL; p = p->next)
- {
- column = p->data;
- ihint = g_signal_get_invocation_hint (column);
- if (ihint != NULL)
- {
- ret = TRUE;
- break;
- }
- }
- g_list_free (columns);
-
- return ret;
-}
-
-static void
-sort_column_changed_callback (GtkTreeSortable *sortable,
- NautilusListView *view)
-{
- NautilusFile *file;
- gint sort_column_id, default_sort_column_id;
- GtkSortType reversed;
- GQuark sort_attr, default_sort_attr;
- char *reversed_attr, *default_reversed_attr;
- gboolean default_sort_reversed;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (view));
-
- gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &reversed);
- sort_attr = nautilus_list_model_get_attribute_from_sort_column_id (view->details->model, sort_column_id);
-
- default_sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (view->details->model,
- g_quark_from_string (get_default_sort_order (file, &default_sort_reversed)));
- default_sort_attr = nautilus_list_model_get_attribute_from_sort_column_id (view->details->model, default_sort_column_id);
- nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN,
- g_quark_to_string (default_sort_attr), g_quark_to_string (sort_attr));
-
- default_reversed_attr = (default_sort_reversed ? "true" : "false");
-
- if (view->details->last_sort_attr != sort_attr &&
- sort_criterion_changes_due_to_user (view->details->tree_view))
- {
- /* at this point, the sort order is always GTK_SORT_ASCENDING, if the sort column ID
- * switched. Invert the sort order, if it's the default criterion with a reversed preference,
- * or if it makes sense for the attribute (i.e. date). */
- if (sort_attr == default_sort_attr)
- {
- /* use value from preferences */
- reversed = g_settings_get_boolean (nautilus_preferences,
- NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER);
- }
- else
- {
- reversed = nautilus_file_is_date_sort_attribute_q (sort_attr);
- }
-
- if (reversed)
- {
- g_signal_handlers_block_by_func (sortable, sort_column_changed_callback, view);
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view->details->model),
- sort_column_id,
- GTK_SORT_DESCENDING);
- g_signal_handlers_unblock_by_func (sortable, sort_column_changed_callback, view);
- }
- }
-
-
- reversed_attr = (reversed ? "true" : "false");
- nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED,
- default_reversed_attr, reversed_attr);
-
- /* Make sure selected item(s) is visible after sort */
- nautilus_list_view_reveal_selection (NAUTILUS_FILES_VIEW (view));
-
- view->details->last_sort_attr = sort_attr;
-}
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-static char *
-get_root_uri_callback (NautilusTreeViewDragDest *dest,
- gpointer user_data)
-{
- NautilusListView *view;
-
- view = NAUTILUS_LIST_VIEW (user_data);
-
- return nautilus_files_view_get_uri (NAUTILUS_FILES_VIEW (view));
-}
-
-static NautilusFile *
-get_file_for_path_callback (NautilusTreeViewDragDest *dest,
- GtkTreePath *path,
- gpointer user_data)
-{
- NautilusListView *view;
-
- view = NAUTILUS_LIST_VIEW (user_data);
-
- return nautilus_list_model_file_for_path (view->details->model, path);
-}
-
-
-static void
-list_view_handle_uri_list (NautilusTreeViewDragDest *dest,
- const char *item_uris,
- const char *target_uri,
- GdkDragAction action,
- NautilusListView *view)
-{
- nautilus_files_view_handle_uri_list_drop (NAUTILUS_FILES_VIEW (view),
- item_uris, target_uri, action);
-}
-
-static void
-list_view_handle_text (NautilusTreeViewDragDest *dest,
- const char *text,
- const char *target_uri,
- GdkDragAction action,
- NautilusListView *view)
-{
- nautilus_files_view_handle_text_drop (NAUTILUS_FILES_VIEW (view),
- text, target_uri, action);
-}
-
-static void
-list_view_handle_raw (NautilusTreeViewDragDest *dest,
- const char *raw_data,
- int length,
- const char *target_uri,
- const char *direct_save_uri,
- GdkDragAction action,
- NautilusListView *view)
-{
- nautilus_files_view_handle_raw_drop (NAUTILUS_FILES_VIEW (view),
- raw_data, length, target_uri, direct_save_uri,
- action);
-}
-
-static void
-list_view_handle_hover (NautilusTreeViewDragDest *dest,
- const char *target_uri,
- NautilusListView *view)
-{
- nautilus_files_view_handle_hover (NAUTILUS_FILES_VIEW (view), target_uri);
-}
-
-static void
-move_copy_items_callback (NautilusTreeViewDragDest *dest,
- const GList *item_uris,
- const char *target_uri,
- guint action,
- gpointer user_data)
-{
- NautilusFilesView *view = user_data;
-
- nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
- item_uris);
- nautilus_files_view_move_copy_items (view,
- item_uris,
- target_uri,
- action);
-}
-#endif
-
-static void
-column_header_menu_toggled (GtkCheckButton *menu_item,
- NautilusListView *list_view)
-{
- NautilusFile *file;
- char **visible_columns;
- char **column_order;
- const char *column;
- gboolean active;
- GPtrArray *ptr_array;
- int i;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
- visible_columns = get_visible_columns (list_view);
- column_order = get_column_order (list_view);
- column = g_object_get_data (G_OBJECT (menu_item), "column-name");
- active = gtk_check_button_get_active (menu_item);
-
- /* Rebuild visible_columns to add or remove the toggled column. */
- ptr_array = g_ptr_array_sized_new (g_strv_length (visible_columns));
- for (i = 0; visible_columns[i] != NULL; ++i)
- {
- if (!active && g_strcmp0 (visible_columns[i], column))
- {
- continue;
- }
- g_ptr_array_add (ptr_array, visible_columns[i]);
- }
-
- if (active)
- {
- g_ptr_array_add (ptr_array, g_strdup (column));
- }
- g_ptr_array_add (ptr_array, NULL);
-
- g_free (visible_columns);
- visible_columns = (gchar **) g_ptr_array_free (ptr_array, FALSE);
-
- nautilus_file_set_metadata_list (file,
- NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS,
- visible_columns);
-
- /* set view values ourselves, as new metadata could not have been
- * updated yet.
- */
- apply_columns_settings (list_view, column_order, visible_columns);
-
- g_strfreev (column_order);
- g_strfreev (visible_columns);
-}
-
-static void
-column_header_menu_use_default (GtkButton *menu_item,
- NautilusListView *list_view)
-{
- NautilusFile *file;
- char **default_columns;
- char **default_order;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
-
- nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NULL);
- nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NULL);
-
- default_columns = get_default_visible_columns (list_view);
- default_order = get_default_column_order (list_view);
-
- /* set view values ourselves, as new metadata could not have been
- * updated yet.
- */
- apply_columns_settings (list_view, default_order, default_columns);
- /* Popdown the popover because the checkboxes are not updated. */
- gtk_popover_popdown (GTK_POPOVER (list_view->details->columns_popover));
-
- g_strfreev (default_columns);
- g_strfreev (default_order);
-}
-
-static void
-popup_column_header_menu (NautilusListView *list_view,
- gdouble x,
- gdouble y)
-{
- NautilusFile *file;
- char **visible_columns;
- char **column_order;
- GList *all_columns;
- GHashTable *visible_columns_hash;
- int i;
- GList *l;
- GtkPopover *popover;
- GtkWidget *menu;
- GtkWidget *menu_item;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
-
- visible_columns = get_visible_columns (list_view);
- column_order = get_column_order (list_view);
-
- all_columns = nautilus_get_columns_for_file (file);
- all_columns = nautilus_sort_columns (all_columns, column_order);
-
- /* hash table to lookup if a given column should be visible */
- visible_columns_hash = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) g_free);
- /* always show name column */
- g_hash_table_insert (visible_columns_hash, g_strdup ("name"), g_strdup ("name"));
- if (visible_columns != NULL)
- {
- for (i = 0; visible_columns[i] != NULL; ++i)
- {
- g_hash_table_insert (visible_columns_hash,
- g_ascii_strdown (visible_columns[i], -1),
- g_ascii_strdown (visible_columns[i], -1));
- }
- }
-
- popover = GTK_POPOVER (list_view->details->columns_popover);
- menu = list_view->details->columns_popover_box;
- /* Remove all old items before repopulating. */
- while ((menu_item = gtk_widget_get_first_child (menu)) != NULL)
- {
- gtk_box_remove (GTK_BOX (menu), menu_item);
- }
-
- for (l = all_columns; l != NULL; l = l->next)
- {
- char *name;
- char *label;
- char *lowercase;
-
- g_object_get (G_OBJECT (l->data),
- "name", &name,
- "label", &label,
- NULL);
- lowercase = g_ascii_strdown (name, -1);
-
- menu_item = gtk_check_button_new_with_label (label);
- gtk_box_append (GTK_BOX (menu), menu_item);
-
- g_object_set_data_full (G_OBJECT (menu_item),
- "column-name", name, g_free);
-
- /* name is always visible */
- if (strcmp (lowercase, "name") == 0)
- {
- gtk_widget_set_sensitive (menu_item, FALSE);
- }
-
- if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL)
- {
- gtk_check_button_set_active (GTK_CHECK_BUTTON (menu_item), TRUE);
- }
-
- g_signal_connect (menu_item,
- "toggled",
- G_CALLBACK (column_header_menu_toggled),
- list_view);
-
- g_free (lowercase);
- g_free (label);
- }
-
- menu_item = gtk_button_new_with_label (_("Use Default"));
- gtk_box_append (GTK_BOX (menu), menu_item);
-
- g_signal_connect (menu_item,
- "clicked",
- G_CALLBACK (column_header_menu_use_default),
- list_view);
-
- gtk_widget_show (menu);
- gtk_popover_set_pointing_to (popover, &(GdkRectangle){x, y, 0, 0});
- gtk_popover_popup (popover);
-
- g_hash_table_destroy (visible_columns_hash);
- nautilus_column_list_free (all_columns);
- g_strfreev (column_order);
- g_strfreev (visible_columns);
-}
-
-static void
-apply_columns_settings (NautilusListView *list_view,
- char **column_order,
- char **visible_columns)
-{
- GList *all_columns;
- NautilusFile *file;
- GList *old_view_columns, *view_columns;
- GHashTable *visible_columns_hash;
- GtkTreeViewColumn *prev_view_column;
- GList *l;
- int i;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
-
- /* prepare ordered list of view columns using column_order and visible_columns */
- view_columns = NULL;
-
- all_columns = nautilus_get_columns_for_file (file);
- all_columns = nautilus_sort_columns (all_columns, column_order);
-
- /* hash table to lookup if a given column should be visible */
- visible_columns_hash = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) g_free);
- /* always show name column */
- g_hash_table_insert (visible_columns_hash, g_strdup ("name"), g_strdup ("name"));
- if (visible_columns != NULL)
- {
- for (i = 0; visible_columns[i] != NULL; ++i)
- {
- g_hash_table_insert (visible_columns_hash,
- g_ascii_strdown (visible_columns[i], -1),
- g_ascii_strdown (visible_columns[i], -1));
- }
- }
-
- for (l = all_columns; l != NULL; l = l->next)
- {
- char *name;
- char *lowercase;
-
- g_object_get (G_OBJECT (l->data), "name", &name, NULL);
- lowercase = g_ascii_strdown (name, -1);
-
- if (g_hash_table_lookup (visible_columns_hash, lowercase) != NULL)
- {
- GtkTreeViewColumn *view_column;
-
- view_column = g_hash_table_lookup (list_view->details->columns, name);
- if (view_column != NULL)
- {
- view_columns = g_list_prepend (view_columns, view_column);
- }
- }
-
- g_free (name);
- g_free (lowercase);
- }
-
- g_hash_table_destroy (visible_columns_hash);
- nautilus_column_list_free (all_columns);
-
- view_columns = g_list_reverse (view_columns);
-
- /* hide columns that are not present in the configuration */
- old_view_columns = gtk_tree_view_get_columns (list_view->details->tree_view);
- for (l = old_view_columns; l != NULL; l = l->next)
- {
- if (g_list_find (view_columns, l->data) == NULL)
- {
- gtk_tree_view_column_set_visible (l->data, FALSE);
- }
- }
- g_list_free (old_view_columns);
-
- /* show new columns from the configuration */
- for (l = view_columns; l != NULL; l = l->next)
- {
- gtk_tree_view_column_set_visible (l->data, TRUE);
- }
-
- /* place columns in the correct order */
- prev_view_column = NULL;
- for (l = view_columns; l != NULL; l = l->next)
- {
- gtk_tree_view_move_column_after (list_view->details->tree_view, l->data, prev_view_column);
- prev_view_column = l->data;
- }
- g_list_free (view_columns);
-}
-
-static void
-starred_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- NautilusListView *view)
-{
- g_autofree gchar *text = NULL;
- g_autofree gchar *uri = NULL;
- NautilusFile *file;
-
- gtk_tree_model_get (model, iter,
- view->details->file_name_column_num, &text,
- -1);
-
- gtk_tree_model_get (GTK_TREE_MODEL (model),
- iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- if (file == NULL)
- {
- /* This row is a label, not a file */
- g_object_set (renderer,
- "icon-name", NULL,
- "mode", GTK_CELL_RENDERER_MODE_INERT,
- NULL);
- return;
- }
-
- uri = nautilus_file_get_uri (file);
-
- if (nautilus_tag_manager_file_is_starred (nautilus_tag_manager_get (), uri))
- {
- g_object_set (renderer,
- "icon-name", "starred-symbolic",
- NULL);
- }
- else
- {
- g_object_set (renderer,
- "icon-name", "non-starred-symbolic",
- NULL);
- }
-
- nautilus_file_unref (file);
-}
-
-static void
-filename_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- NautilusListView *view)
-{
- char *text;
- g_autofree gchar *escaped_text = NULL;
- g_autofree gchar *escaped_name = NULL;
- g_autofree gchar *replaced_text = NULL;
- GtkTreePath *path;
- PangoUnderline underline;
- GString *display_text;
- NautilusDirectory *directory;
- NautilusQuery *query = NULL;
- NautilusFile *file;
- const gchar *snippet;
-
- gtk_tree_model_get (model, iter,
- view->details->file_name_column_num, &text,
- -1);
-
- escaped_name = g_markup_escape_text (text, -1);
- display_text = g_string_new (escaped_name);
-
- directory = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (view));
-
- if (NAUTILUS_IS_SEARCH_DIRECTORY (directory))
- {
- query = nautilus_search_directory_get_query (NAUTILUS_SEARCH_DIRECTORY (directory));
- }
-
- if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE)
- {
- path = gtk_tree_model_get_path (model, iter);
-
- if (view->details->hover_path == NULL ||
- gtk_tree_path_compare (path, view->details->hover_path))
- {
- underline = PANGO_UNDERLINE_NONE;
- }
- else
- {
- underline = PANGO_UNDERLINE_SINGLE;
- }
-
- gtk_tree_path_free (path);
- }
- else
- {
- underline = PANGO_UNDERLINE_NONE;
- }
-
- if (query &&
- nautilus_query_get_search_content (query) == NAUTILUS_QUERY_SEARCH_CONTENT_FULL_TEXT)
- {
- gtk_tree_model_get (model, iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- /* Rule out dummy row */
- if (file != NULL)
- {
- snippet = nautilus_file_get_search_fts_snippet (file);
- if (snippet)
- {
- replaced_text = g_regex_replace (view->details->regex,
- snippet,
- -1,
- 0,
- " ",
- G_REGEX_MATCH_NEWLINE_ANY,
- NULL);
-
- escaped_text = g_markup_escape_text (replaced_text, -1);
-
- g_string_append_printf (display_text,
- " %s",
- escaped_text);
- }
- }
- nautilus_file_unref (file);
- }
-
- g_object_set (G_OBJECT (renderer),
- "markup", display_text->str,
- "underline", underline,
- NULL);
-
- g_free (text);
- g_string_free (display_text, TRUE);
-}
-
-static void
-location_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- NautilusListView *view,
- gboolean show_trash_orig)
-{
- NautilusDirectory *directory;
- GFile *home_location;
- NautilusFile *file;
- GFile *dir_location;
- GFile *base_location;
- gchar *where = NULL;
-
- directory = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (view));
-
- home_location = g_file_new_for_path (g_get_home_dir ());
-
- gtk_tree_model_get (model, iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- /* The file might be NULL if we just toggled an expander
- * and we're still loading the subdirectory.
- */
- if (file == NULL)
- {
- return;
- }
-
- if (show_trash_orig && nautilus_file_is_in_trash (file))
- {
- NautilusFile *orig_file;
-
- orig_file = nautilus_file_get_trash_original_file (file);
-
- if (orig_file != NULL)
- {
- nautilus_file_unref (file);
- file = orig_file;
- }
- }
-
- if (!nautilus_file_is_in_recent (file))
- {
- dir_location = nautilus_file_get_parent_location (file);
- }
- else
- {
- GFile *activation_location;
-
- activation_location = nautilus_file_get_activation_location (file);
- dir_location = g_file_get_parent (activation_location);
-
- g_object_unref (activation_location);
- }
-
- if (!NAUTILUS_IS_SEARCH_DIRECTORY (directory))
- {
- base_location = g_object_ref (home_location);
- }
- else
- {
- NautilusQuery *query;
- NautilusFile *base;
- GFile *location;
-
- query = nautilus_search_directory_get_query (NAUTILUS_SEARCH_DIRECTORY (directory));
- location = nautilus_query_get_location (query);
- base = nautilus_file_get (location);
-
- if (!nautilus_file_is_in_recent (base))
- {
- base_location = nautilus_file_get_location (base);
- }
- else
- {
- base_location = g_object_ref (home_location);
- }
-
- nautilus_file_unref (base);
- g_object_unref (location);
- g_object_unref (query);
- }
-
- if (g_file_equal (base_location, dir_location))
- {
- /* Only occurs when search result is
- * a direct child of the base location
- */
- where = g_strdup ("");
- }
- else if (g_file_equal (home_location, dir_location))
- {
- where = g_strdup (_("Home"));
- }
- else if (g_file_has_prefix (dir_location, base_location))
- {
- gchar *relative_path;
-
- relative_path = g_file_get_relative_path (base_location, dir_location);
- where = g_filename_display_name (relative_path);
-
- g_free (relative_path);
- }
- else
- {
- where = g_file_get_path (dir_location);
- }
-
- g_object_set (G_OBJECT (renderer),
- "text", where,
- NULL);
-
- g_free (where);
-
- g_object_unref (base_location);
- g_object_unref (dir_location);
- nautilus_file_unref (file);
- g_object_unref (home_location);
-}
-
-
-static void
-where_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- NautilusListView *view)
-{
- location_cell_data_func (column, renderer, model, iter, view, FALSE);
-}
-
-static void
-trash_orig_path_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- NautilusListView *view)
-{
- location_cell_data_func (column, renderer, model, iter, view, TRUE);
-}
-
-#define SMALL_ZOOM_ICON_PADDING 0
-#define STANDARD_ZOOM_ICON_PADDING 6
-#define LARGE_ZOOM_ICON_PADDING 6
-#define LARGER_ZOOM_ICON_PADDING 6
-
-static gint
-nautilus_list_view_get_icon_padding_for_zoom_level (NautilusListZoomLevel zoom_level)
-{
- switch (zoom_level)
- {
- case NAUTILUS_LIST_ZOOM_LEVEL_SMALL:
- {
- return SMALL_ZOOM_ICON_PADDING;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_STANDARD:
- {
- return STANDARD_ZOOM_ICON_PADDING;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_LARGE:
- {
- return LARGE_ZOOM_ICON_PADDING;
- }
-
- case NAUTILUS_LIST_ZOOM_LEVEL_LARGER:
- {
- return LARGER_ZOOM_ICON_PADDING;
- }
-
- default:
- {
- g_assert_not_reached ();
- }
- }
-}
-
-static void
-set_up_pixbuf_size (NautilusListView *view)
-{
- int icon_size, icon_padding;
-
- /* Make all rows the same size. */
- icon_size = nautilus_list_model_get_icon_size_for_zoom_level (view->details->zoom_level);
- icon_padding = nautilus_list_view_get_icon_padding_for_zoom_level (view->details->zoom_level);
- gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (view->details->pixbuf_cell),
- -1, icon_size + 2 * icon_padding);
-
- /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=641518 */
- gtk_tree_view_columns_autosize (view->details->tree_view);
-}
-
-static gint
-get_icon_scale_callback (NautilusListModel *model,
- NautilusListView *view)
-{
- /* FIXME: Temporary regression: HiDPI icons not supported, ignore scale. */
- return 1;
-}
-
-static void
-on_longpress_gesture_pressed_event (GtkGestureLongPress *gesture,
- gdouble x,
- gdouble y,
- gpointer user_data)
-{
- NautilusListView *view = user_data;
- g_autolist (NautilusFile) selection = NULL;
-
- selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
- if (selection != NULL)
- {
- nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (view), x, y);
- }
- else
- {
- nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (view), x, y);
- }
-}
-
-static void
-on_tree_view_drag_gesture_drag_begin (GtkGestureDrag *gesture,
- gdouble start_x,
- gdouble start_y,
- gpointer user_data)
-{
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
- nautilus_list_view_dnd_init (NAUTILUS_LIST_VIEW (user_data));
-#endif
-}
-
-static void
-on_tree_view_drag_gesture_drag_update (GtkGestureDrag *gesture,
- gdouble offset_x,
- gdouble offset_y,
- gpointer user_data)
-{
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
- GdkEventSequence *sequence;
- GdkEvent *event;
- NautilusListView *list_view;
-
- sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
- event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
- list_view = NAUTILUS_LIST_VIEW (user_data);
-
- nautilus_list_view_dnd_drag_begin (list_view, offset_x, offset_y, event);
-#endif
-}
-
-static void
-list_view_use_tree_changed_callback (gpointer callback_data)
-{
- GtkTreeView *tree_view;
-
- tree_view = GTK_TREE_VIEW (callback_data);
-
- gtk_tree_view_collapse_all (tree_view);
-}
-
-
-static void
-create_and_set_up_tree_view (NautilusListView *view)
-{
- GtkCellRenderer *cell;
- GtkTreeViewColumn *column;
-#if 0 && NAUTILUS_A11Y_NEEDS_GTK4_REIMPLEMENTATION
- AtkObject *atk_obj;
-#endif
- GList *nautilus_columns;
- GList *l;
- gchar **default_column_order, **default_visible_columns;
- GtkWidget *content_widget;
- GtkEventController *controller;
-
- content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (view));
- view->details->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
- view->details->columns = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- (GDestroyNotify) g_free,
- NULL);
- gtk_tree_view_set_enable_search (view->details->tree_view, FALSE);
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
- view->details->drag_dest =
- nautilus_tree_view_drag_dest_new (view->details->tree_view);
-#endif
-
- /* Stop the tree view from performing select-all actions.
- * It is desireable that the action is disabled while directory
- * is loading.
- */
- g_signal_connect (view->details->tree_view, "select-all",
- G_CALLBACK (g_signal_stop_emission_by_name), "select-all");
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
- g_signal_connect_object (view->details->drag_dest,
- "get-root-uri",
- G_CALLBACK (get_root_uri_callback),
- view, 0);
- g_signal_connect_object (view->details->drag_dest,
- "get-file-for-path",
- G_CALLBACK (get_file_for_path_callback),
- view, 0);
- g_signal_connect_object (view->details->drag_dest,
- "move-copy-items",
- G_CALLBACK (move_copy_items_callback),
- view, 0);
- g_signal_connect_object (view->details->drag_dest, "handle-uri-list",
- G_CALLBACK (list_view_handle_uri_list), view, 0);
- g_signal_connect_object (view->details->drag_dest, "handle-text",
- G_CALLBACK (list_view_handle_text), view, 0);
- g_signal_connect_object (view->details->drag_dest, "handle-raw",
- G_CALLBACK (list_view_handle_raw), view, 0);
- g_signal_connect_object (view->details->drag_dest, "handle-hover",
- G_CALLBACK (list_view_handle_hover), view, 0);
-#endif
-
- g_signal_connect_object (gtk_tree_view_get_selection (view->details->tree_view),
- "changed",
- G_CALLBACK (list_selection_changed_callback), view, 0);
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
- gtk_widget_add_controller (GTK_WIDGET (view->details->tree_view), controller);
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
- gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
-
- g_signal_connect (controller, "drag-begin",
- G_CALLBACK (on_tree_view_drag_gesture_drag_begin), view);
- g_signal_connect (controller, "drag-update",
- G_CALLBACK (on_tree_view_drag_gesture_drag_update), view);
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
- gtk_widget_add_controller (GTK_WIDGET (view->details->tree_view), controller);
-
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
- gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
-
- g_signal_connect (controller, "pressed",
- G_CALLBACK (on_tree_view_click_gesture_pressed), view);
- g_signal_connect (controller, "released",
- G_CALLBACK (on_tree_view_click_gesture_released), view);
-
- controller = gtk_event_controller_motion_new ();
- gtk_widget_add_controller (GTK_WIDGET (view->details->tree_view), controller);
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
-
- g_signal_connect (controller, "enter",
- G_CALLBACK (on_event_controller_motion_enter), view);
- g_signal_connect (controller, "leave",
- G_CALLBACK (on_event_controller_motion_leave), view);
- g_signal_connect (controller, "motion",
- G_CALLBACK (on_event_controller_motion_motion), view);
-
- controller = gtk_event_controller_key_new ();
- gtk_widget_add_controller (GTK_WIDGET (view->details->tree_view), controller);
-
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
-
- g_signal_connect (controller, "key-pressed",
- G_CALLBACK (on_event_controller_key_key_pressed), view);
-
- g_signal_connect_object (view->details->tree_view, "test-expand-row",
- G_CALLBACK (test_expand_row_callback), view, 0);
- g_signal_connect_object (view->details->tree_view, "row-expanded",
- G_CALLBACK (row_expanded_callback), view, 0);
- g_signal_connect_object (view->details->tree_view, "row-collapsed",
- G_CALLBACK (row_collapsed_callback), view, 0);
- g_signal_connect_object (view->details->tree_view, "row-activated",
- G_CALLBACK (row_activated_callback), view, 0);
-
- g_signal_connect_object (nautilus_list_view_preferences,
- "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE,
- G_CALLBACK (list_view_use_tree_changed_callback),
- view->details->tree_view,
- G_CONNECT_SWAPPED);
-
- view->details->model = g_object_new (NAUTILUS_TYPE_LIST_MODEL, NULL);
- gtk_tree_view_set_model (view->details->tree_view, GTK_TREE_MODEL (view->details->model));
- /* Need the model for the dnd drop icon "accept" change */
- nautilus_list_model_set_drag_view (NAUTILUS_LIST_MODEL (view->details->model),
- view->details->tree_view, 0, 0);
-
- g_signal_connect_object (view->details->model, "sort-column-changed",
- G_CALLBACK (sort_column_changed_callback), view, 0);
-
- g_signal_connect_object (view->details->model, "subdirectory-unloaded",
- G_CALLBACK (subdirectory_unloaded_callback), view, 0);
-
- g_signal_connect_object (view->details->model, "get-icon-scale",
- G_CALLBACK (get_icon_scale_callback), view, 0);
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
- gtk_widget_add_controller (GTK_WIDGET (content_widget), controller);
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
- gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (controller), TRUE);
- g_signal_connect (controller, "pressed",
- (GCallback) on_longpress_gesture_pressed_event, view);
-
- gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view->details->tree_view), GTK_SELECTION_MULTIPLE);
-
- g_settings_bind (nautilus_list_view_preferences, NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE,
- view->details->tree_view, "show-expanders",
- G_SETTINGS_BIND_DEFAULT);
-
- nautilus_columns = nautilus_get_all_columns ();
-
- for (l = nautilus_columns; l != NULL; l = l->next)
- {
- NautilusColumn *nautilus_column;
- int column_num;
- char *name;
- char *label;
- float xalign;
- GtkSortType sort_order;
-
- nautilus_column = NAUTILUS_COLUMN (l->data);
-
- g_object_get (nautilus_column,
- "name", &name,
- "label", &label,
- "xalign", &xalign,
- "default-sort-order", &sort_order,
- NULL);
-
- column_num = nautilus_list_model_add_column (view->details->model,
- nautilus_column);
-
- /* Created the name column specially, because it
- * has the icon in it.*/
- if (!strcmp (name, "name"))
- {
- /* Create the file name column */
- view->details->file_name_column = gtk_tree_view_column_new ();
- gtk_tree_view_append_column (view->details->tree_view,
- view->details->file_name_column);
- view->details->file_name_column_num = column_num;
-
- g_hash_table_insert (view->details->columns,
- g_strdup ("name"),
- view->details->file_name_column);
-
- gtk_tree_view_set_search_column (view->details->tree_view, column_num);
-
- gtk_tree_view_column_set_sort_column_id (view->details->file_name_column, column_num);
- gtk_tree_view_column_set_title (view->details->file_name_column, _("Name"));
- gtk_tree_view_column_set_resizable (view->details->file_name_column, TRUE);
- gtk_tree_view_column_set_expand (view->details->file_name_column, TRUE);
-
- /* Initial padding */
- cell = gtk_cell_renderer_text_new ();
- gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE);
- g_object_set (cell, "xpad", 6, NULL);
- g_settings_bind (nautilus_list_view_preferences, NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE,
- cell, "visible",
- G_SETTINGS_BIND_INVERT_BOOLEAN | G_SETTINGS_BIND_GET);
-
- /* File icon */
- cell = gtk_cell_renderer_pixbuf_new ();
- view->details->pixbuf_cell = (GtkCellRendererPixbuf *) cell;
- set_up_pixbuf_size (view);
-
- gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE);
- gtk_tree_view_column_set_attributes (view->details->file_name_column,
- cell,
- "texture", nautilus_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
- NULL);
-
- cell = gtk_cell_renderer_text_new ();
- view->details->file_name_cell = (GtkCellRendererText *) cell;
- g_object_set (cell,
- "ellipsize", PANGO_ELLIPSIZE_END,
- "single-paragraph-mode", FALSE,
- "width-chars", 30,
- "xpad", 5,
- NULL);
-
- gtk_tree_view_column_pack_start (view->details->file_name_column, cell, TRUE);
- gtk_tree_view_column_set_cell_data_func (view->details->file_name_column, cell,
- (GtkTreeCellDataFunc) filename_cell_data_func,
- view, NULL);
- }
- else
- {
- if (g_strcmp0 (name, "starred") == 0)
- {
- cell = gtk_cell_renderer_pixbuf_new ();
- g_object_set (cell,
- "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
- NULL);
-
- column = gtk_tree_view_column_new_with_attributes ("",
- cell,
- NULL);
- gtk_tree_view_column_set_fixed_width (column, STAR_COLUMN_WIDTH);
- }
- else
- {
- PangoAttrList *attr_list = pango_attr_list_new ();
-
- cell = gtk_cell_renderer_text_new ();
-
- column = gtk_tree_view_column_new_with_attributes (label,
- cell,
- "text", column_num,
- NULL);
-
- pango_attr_list_insert (attr_list, pango_attr_foreground_alpha_new (ALPHA_55_PERCENT));
- g_object_set (cell, "attributes", attr_list, NULL);
- pango_attr_list_unref (attr_list);
- }
-
- gtk_tree_view_column_set_alignment (column, xalign);
- g_object_set (cell,
- "xalign", xalign,
- "xpad", 5,
- NULL);
- if (!strcmp (name, "permissions"))
- {
- g_object_set (cell,
- "family", "Monospace",
- NULL);
- }
- view->details->cells = g_list_append (view->details->cells,
- cell);
-
- gtk_tree_view_append_column (view->details->tree_view, column);
- gtk_tree_view_column_set_sort_column_id (column, column_num);
- g_hash_table_insert (view->details->columns,
- g_strdup (name),
- column);
-
- gtk_tree_view_column_set_resizable (column, TRUE);
- gtk_tree_view_column_set_sort_order (column, sort_order);
-
- if (!strcmp (name, "where"))
- {
- gtk_tree_view_column_set_cell_data_func (column, cell,
- (GtkTreeCellDataFunc) where_cell_data_func,
- view, NULL);
- }
- else if (!strcmp (name, "trash_orig_path"))
- {
- gtk_tree_view_column_set_cell_data_func (column, cell,
- (GtkTreeCellDataFunc) trash_orig_path_cell_data_func,
- view, NULL);
- }
- else if (!strcmp (name, "starred"))
- {
- gtk_tree_view_column_set_cell_data_func (column, cell,
- (GtkTreeCellDataFunc) starred_cell_data_func,
- view, NULL);
- }
- }
- g_free (name);
- g_free (label);
- }
- nautilus_column_list_free (nautilus_columns);
-
- default_visible_columns = g_settings_get_strv (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
- default_column_order = g_settings_get_strv (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
-
- /* Apply the default column order and visible columns, to get it
- * right most of the time. The metadata will be checked when a
- * folder is loaded */
- apply_columns_settings (view,
- default_column_order,
- default_visible_columns);
-
- gtk_widget_show (GTK_WIDGET (view->details->tree_view));
- gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (content_widget),
- GTK_WIDGET (view->details->tree_view));
-
-#if 0 && NAUTILUS_A11Y_NEEDS_GTK4_REIMPLEMENTATION
- atk_obj = gtk_widget_get_accessible (GTK_WIDGET (view->details->tree_view));
- atk_object_set_name (atk_obj, _("List View"));
-#endif
-
- g_strfreev (default_visible_columns);
- g_strfreev (default_column_order);
-}
-
-static void
-nautilus_list_view_add_files (NautilusFilesView *view,
- GList *files)
-{
- NautilusListModel *model;
- GList *l;
-
- model = NAUTILUS_LIST_VIEW (view)->details->model;
- for (l = files; l != NULL; l = l->next)
- {
- NautilusFile *parent;
- NautilusDirectory *directory;
-
- parent = nautilus_file_get_parent (NAUTILUS_FILE (l->data));
- directory = nautilus_directory_get_for_file (parent);
- nautilus_list_model_add_file (model, NAUTILUS_FILE (l->data), directory);
-
- nautilus_file_unref (parent);
- nautilus_directory_unref (directory);
- }
-}
-
-static char **
-get_default_visible_columns (NautilusListView *list_view)
-{
- NautilusFile *file;
- NautilusDirectory *directory;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
-
- if (nautilus_file_is_in_trash (file))
- {
- return g_strdupv ((gchar **) default_trash_visible_columns);
- }
-
- if (nautilus_file_is_in_recent (file))
- {
- return g_strdupv ((gchar **) default_recent_visible_columns);
- }
-
- directory = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (list_view));
- if (NAUTILUS_IS_SEARCH_DIRECTORY (directory))
- {
- return g_strdupv ((gchar **) default_search_visible_columns);
- }
-
- return g_settings_get_strv (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
-}
-
-static char **
-get_visible_columns (NautilusListView *list_view)
-{
- NautilusFile *file;
- g_autofree gchar **visible_columns = NULL;
- g_autoptr (GFile) location = NULL;
- GPtrArray *res;
- g_autofree gchar *uri = NULL;
- gboolean can_star_current_directory;
- gboolean is_starred;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
- uri = nautilus_file_get_uri (file);
-
- location = g_file_new_for_uri (uri);
- can_star_current_directory = nautilus_tag_manager_can_star_contents (nautilus_tag_manager_get (),
- location);
- is_starred = eel_uri_is_starred (uri);
-
- visible_columns = nautilus_file_get_metadata_list (file,
- NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS);
- if (visible_columns == NULL)
- {
- visible_columns = get_default_visible_columns (list_view);
- }
-
- res = g_ptr_array_new ();
- for (gint i = 0; visible_columns[i] != NULL; i++)
- {
- if (g_strcmp0 (visible_columns[i], "starred") != 0 ||
- (g_strcmp0 (visible_columns[i], "starred") == 0 && (can_star_current_directory || is_starred)))
- {
- g_ptr_array_add (res, visible_columns[i]);
- }
- }
-
- g_ptr_array_add (res, NULL);
-
- return (char **) g_ptr_array_free (res, FALSE);
-}
-
-static char **
-get_default_column_order (NautilusListView *list_view)
-{
- NautilusFile *file;
- NautilusDirectory *directory;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
-
- if (nautilus_file_is_in_trash (file))
- {
- return g_strdupv ((gchar **) default_trash_columns_order);
- }
-
- if (nautilus_file_is_in_recent (file))
- {
- return g_strdupv ((gchar **) default_recent_columns_order);
- }
-
- directory = nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (list_view));
- if (NAUTILUS_IS_SEARCH_DIRECTORY (directory))
- {
- return g_strdupv ((gchar **) default_search_columns_order);
- }
-
- return g_settings_get_strv (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER);
-}
-
-static char **
-get_column_order (NautilusListView *list_view)
-{
- NautilusFile *file;
- gchar **column_order;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
-
- column_order = nautilus_file_get_metadata_list
- (file,
- NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER);
-
- if (column_order != NULL)
- {
- return column_order;
- }
-
- return get_default_column_order (list_view);
-}
-
-static void
-check_allow_sort (NautilusListView *list_view)
-{
- GList *column_names;
- GList *l;
- NautilusFile *file;
- GtkTreeViewColumn *column;
- gboolean allow_sorting;
- int sort_column_id;
-
- column_names = g_hash_table_get_keys (list_view->details->columns);
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
- allow_sorting = !(nautilus_file_is_in_recent (file) || nautilus_file_is_in_search (file));
-
- for (l = column_names; l != NULL; l = l->next)
- {
- column = g_hash_table_lookup (list_view->details->columns, l->data);
- if (allow_sorting)
- {
- sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
- g_quark_from_string (l->data));
- /* Restore its original sorting id. We rely on that the keys of the hashmap
- * use the same string than the sort criterias */
- gtk_tree_view_column_set_sort_column_id (column, sort_column_id);
- }
- else
- {
- /* This disables the header and any sorting capability (like shortcuts),
- * but leaving them interactionable so the user can still resize them */
- gtk_tree_view_column_set_sort_column_id (column, -1);
- }
- }
-
- g_list_free (column_names);
-}
-
-static void
-set_columns_settings_from_metadata_and_preferences (NautilusListView *list_view)
-{
- char **column_order;
- char **visible_columns;
-
- column_order = get_column_order (list_view);
- visible_columns = get_visible_columns (list_view);
+ /* We don't use the built-in child activation feature for click because it
+ * doesn't fill all our needs nor does it match our expected behavior.
+ * Instead, we roll our own event handling and double/single click mode.
+ * However, GtkColumnView:single-click-activate has other effects besides
+ * activation, as it affects the selection behavior as well (e.g. selects on
+ * hover). Setting it to FALSE gives us the expected behavior. */
+ gtk_column_view_set_single_click_activate (GTK_COLUMN_VIEW (widget), FALSE);
+ gtk_column_view_set_enable_rubberband (GTK_COLUMN_VIEW (widget), TRUE);
- apply_columns_settings (list_view, column_order, visible_columns);
-
- g_strfreev (column_order);
- g_strfreev (visible_columns);
-}
-
-static void
-set_sort_order_from_metadata_and_preferences (NautilusListView *list_view)
-{
- char *sort_attribute;
- int sort_column_id;
- NautilusFile *file;
- gboolean sort_reversed, default_sort_reversed;
- const gchar *default_sort_order;
-
- file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (list_view));
- default_sort_order = get_default_sort_order (file, &default_sort_reversed);
- if (!(nautilus_file_is_in_recent (file) || nautilus_file_is_in_search (file)))
- {
- sort_attribute = nautilus_file_get_metadata (file,
- NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN,
- NULL);
- sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
- g_quark_from_string (sort_attribute));
- g_free (sort_attribute);
-
- if (sort_column_id == -1)
- {
- sort_column_id =
- nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
- g_quark_from_string (default_sort_order));
- }
-
- sort_reversed = nautilus_file_get_boolean_metadata (file,
- NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED,
- default_sort_reversed);
- }
- else
- {
- /* Make sure we use the default one and not one that the user used previously
- * of the change to not allow sorting on search and recent, or the
- * case that the user or some app modified directly the metadata */
- sort_column_id = nautilus_list_model_get_sort_column_id_from_attribute (list_view->details->model,
- g_quark_from_string (default_sort_order));
- sort_reversed = default_sort_reversed;
- }
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_view->details->model),
- sort_column_id,
- sort_reversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING);
-}
-
-static NautilusListZoomLevel
-get_default_zoom_level (void)
-{
- NautilusListZoomLevel default_zoom_level;
-
- default_zoom_level = g_settings_get_enum (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL);
-
- if (default_zoom_level < NAUTILUS_LIST_ZOOM_LEVEL_SMALL
- || default_zoom_level > NAUTILUS_LIST_ZOOM_LEVEL_LARGER)
- {
- default_zoom_level = NAUTILUS_LIST_ZOOM_LEVEL_STANDARD;
- }
-
- return default_zoom_level;
-}
-
-static void
-nautilus_list_view_begin_loading (NautilusFilesView *view)
-{
- NautilusListView *list_view;
-
- list_view = NAUTILUS_LIST_VIEW (view);
-
- nautilus_list_view_sort_directories_first_changed (NAUTILUS_FILES_VIEW (list_view));
- set_sort_order_from_metadata_and_preferences (list_view);
- set_columns_settings_from_metadata_and_preferences (list_view);
- check_allow_sort (list_view);
-}
-
-static void
-nautilus_list_view_clear (NautilusFilesView *view)
-{
- NautilusListView *list_view;
- GtkTreeView *tree_view;
- GtkTreeSelection *tree_selection;
- GtkTreePath *path;
-
- list_view = NAUTILUS_LIST_VIEW (view);
-
- if (list_view->details->model != NULL)
- {
- tree_view = list_view->details->tree_view;
-
- /* When the current cursor's row gets deleted, GTK will move the cursor to
- * the next row, and when setting the cursor it also selects the new
- * cursor's row, thereby triggering selection signals. The new cursor will
- * soon be deleted again and the loop repeats.
- *
- * Since clear() removes all entries, those selections are useless but they
- * take up most of the time in clear(). For example, when a search returns
- * a large list, exiting from the search view would make nautilus hang.
- *
- * At the time the code is written simply removing the cursor solves the
- * problem, but to be future-proof in case GTK does anything fancy with
- * the current selection, we also remove the selection.
- *
- * Because GTK internally seeking the cursor takes time, only blocking the
- * selection signal like everywhere else will not remove that overhead.
- */
-
- /* Clear the current selection */
- tree_selection = gtk_tree_view_get_selection (tree_view);
- gtk_tree_selection_unselect_all (tree_selection);
-
- /* Clear the current cursor */
- path = gtk_tree_path_new ();
- gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
- gtk_tree_path_free (path);
-
- nautilus_list_model_clear (list_view->details->model);
- }
-}
-
-static void
-nautilus_list_view_file_changed (NautilusFilesView *view,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- NautilusListView *listview;
-
- listview = NAUTILUS_LIST_VIEW (view);
-
- nautilus_list_model_file_changed (listview->details->model, file, directory);
-}
-
-typedef struct
-{
- GtkTreePath *path;
- gboolean is_common;
- gboolean is_root;
-} HasCommonParentData;
-
-static void
-tree_selection_has_common_parent_foreach_func (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- HasCommonParentData *data;
- GtkTreePath *parent_path;
- gboolean has_parent;
-
- data = (HasCommonParentData *) user_data;
-
- parent_path = gtk_tree_path_copy (path);
- gtk_tree_path_up (parent_path);
-
- has_parent = (gtk_tree_path_get_depth (parent_path) > 0) ? TRUE : FALSE;
-
- if (!has_parent)
- {
- data->is_root = TRUE;
- }
-
- if (data->is_common && !data->is_root)
- {
- if (data->path == NULL)
- {
- data->path = gtk_tree_path_copy (parent_path);
- }
- else if (gtk_tree_path_compare (data->path, parent_path) != 0)
- {
- data->is_common = FALSE;
- }
- }
-
- gtk_tree_path_free (parent_path);
-}
-
-static void
-tree_selection_has_common_parent (GtkTreeSelection *selection,
- gboolean *is_common,
- gboolean *is_root)
-{
- HasCommonParentData data;
-
- g_assert (is_common != NULL);
- g_assert (is_root != NULL);
-
- data.path = NULL;
- data.is_common = *is_common = TRUE;
- data.is_root = *is_root = FALSE;
-
- gtk_tree_selection_selected_foreach (selection,
- tree_selection_has_common_parent_foreach_func,
- &data);
-
- *is_common = data.is_common;
- *is_root = data.is_root;
-
- if (data.path != NULL)
- {
- gtk_tree_path_free (data.path);
- }
-}
-
-static char *
-nautilus_list_view_get_backing_uri (NautilusFilesView *view)
-{
- NautilusListView *list_view;
- NautilusListModel *list_model;
- NautilusFile *file;
- GtkTreeView *tree_view;
- GtkTreeSelection *selection;
- GtkTreePath *path;
- GList *paths;
- guint length;
- char *uri;
-
- g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NULL);
-
- list_view = NAUTILUS_LIST_VIEW (view);
- list_model = list_view->details->model;
- tree_view = list_view->details->tree_view;
-
- g_assert (list_model);
-
- /* We currently handle three common cases here:
- * (a) if the selection contains non-filesystem items (i.e., the
- * "(Empty)" label), we return the uri of the parent.
- * (b) if the selection consists of exactly one _expanded_ directory, we
- * return its URI.
- * (c) if the selection consists of either exactly one item which is not
- * an expanded directory) or multiple items in the same directory,
- * we return the URI of the common parent.
+ /* While we don't want to use GTK's click activation, we'll let it handle
+ * the key activation part (with Enter).
*/
+ g_signal_connect (widget, "activate", G_CALLBACK (on_column_view_item_activated), self);
- uri = NULL;
-
- selection = gtk_tree_view_get_selection (tree_view);
- length = gtk_tree_selection_count_selected_rows (selection);
-
- if (length == 1)
- {
- paths = gtk_tree_selection_get_selected_rows (selection, NULL);
- path = (GtkTreePath *) paths->data;
-
- file = nautilus_list_model_file_for_path (list_model, path);
- if (file == NULL)
- {
- /* The selected item is a label, not a file */
- gtk_tree_path_up (path);
- file = nautilus_list_model_file_for_path (list_model, path);
- }
-
- if (file != NULL)
- {
- if (nautilus_file_is_directory (file) &&
- gtk_tree_view_row_expanded (tree_view, path))
- {
- uri = nautilus_file_get_uri (file);
- }
- nautilus_file_unref (file);
- }
-
- gtk_tree_path_free (path);
- g_list_free (paths);
- }
-
- if (uri == NULL && length > 0)
- {
- gboolean is_common, is_root;
-
- /* Check that all the selected items belong to the same
- * directory and that directory is not the root directory (which
- * is handled by NautilusFilesView::get_backing_directory.) */
-
- tree_selection_has_common_parent (selection, &is_common, &is_root);
-
- if (is_common && !is_root)
- {
- paths = gtk_tree_selection_get_selected_rows (selection, NULL);
- path = (GtkTreePath *) paths->data;
-
- file = nautilus_list_model_file_for_path (list_model, path);
- g_assert (file != NULL);
- uri = nautilus_file_get_parent_uri (file);
- nautilus_file_unref (file);
-
- g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
- }
- }
-
- if (uri != NULL)
- {
- return uri;
- }
-
- return NAUTILUS_FILES_VIEW_CLASS (nautilus_list_view_parent_class)->get_backing_uri (view);
-}
-
-static void
-nautilus_list_view_get_selection_foreach_func (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- GList **list;
- NautilusFile *file;
-
- list = data;
-
- gtk_tree_model_get (model, iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- if (file != NULL)
- {
- (*list) = g_list_prepend ((*list), file);
- }
-}
-
-static GList *
-nautilus_list_view_get_selection (NautilusFilesView *view)
-{
- GList *list;
-
- list = NULL;
-
- gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view),
- nautilus_list_view_get_selection_foreach_func, &list);
-
- return g_list_reverse (list);
-}
-
-static void
-nautilus_list_view_get_selection_for_file_transfer_foreach_func (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- NautilusFile *file;
- struct SelectionForeachData *selection_data;
- GtkTreeIter parent, child;
-
- selection_data = data;
-
- gtk_tree_model_get (model, iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- if (file != NULL)
- {
- /* If the parent folder is also selected, don't include this file in the
- * file operation, since that would copy it to the toplevel target instead
- * of keeping it as a child of the copied folder
- */
- child = *iter;
- while (gtk_tree_model_iter_parent (model, &parent, &child))
- {
- if (gtk_tree_selection_iter_is_selected (selection_data->selection,
- &parent))
- {
- return;
- }
- child = parent;
- }
-
- nautilus_file_ref (file);
- selection_data->list = g_list_prepend (selection_data->list, file);
- }
-}
-
-
-static GList *
-nautilus_list_view_get_selection_for_file_transfer (NautilusFilesView *view)
-{
- struct SelectionForeachData selection_data;
-
- selection_data.list = NULL;
- selection_data.selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
-
- gtk_tree_selection_selected_foreach (selection_data.selection,
- nautilus_list_view_get_selection_for_file_transfer_foreach_func, &selection_data);
-
- return g_list_reverse (selection_data.list);
-}
-
-static gboolean
-nautilus_list_view_is_empty (NautilusFilesView *view)
-{
- return nautilus_list_model_is_empty (NAUTILUS_LIST_VIEW (view)->details->model);
-}
-
-static void
-nautilus_list_view_end_file_changes (NautilusFilesView *view)
-{
- NautilusListView *list_view;
-
- list_view = NAUTILUS_LIST_VIEW (view);
-
- if (list_view->details->new_selection_path)
- {
- gtk_tree_view_set_cursor (list_view->details->tree_view,
- list_view->details->new_selection_path,
- NULL, FALSE);
- gtk_tree_path_free (list_view->details->new_selection_path);
- list_view->details->new_selection_path = NULL;
- }
-}
-
-static void
-nautilus_list_view_remove_file (NautilusFilesView *view,
- NautilusFile *file,
- NautilusDirectory *directory)
-{
- GtkTreePath *path;
- GtkTreePath *file_path;
- GtkTreeIter iter;
- GtkTreeIter temp_iter;
- GtkTreeRowReference *row_reference;
- NautilusListView *list_view;
- GtkTreeModel *tree_model;
- GtkTreeSelection *selection;
-
- path = NULL;
- row_reference = NULL;
- list_view = NAUTILUS_LIST_VIEW (view);
- tree_model = GTK_TREE_MODEL (list_view->details->model);
-
- if (nautilus_list_model_get_tree_iter_from_file (list_view->details->model, file, directory, &iter))
- {
- selection = gtk_tree_view_get_selection (list_view->details->tree_view);
- file_path = gtk_tree_model_get_path (tree_model, &iter);
-
- if (gtk_tree_selection_path_is_selected (selection, file_path))
- {
- /* get reference for next element in the list view. If the element to be deleted is the
- * last one, get reference to previous element. If there is only one element in view
- * no need to select anything.
- */
- temp_iter = iter;
-
- if (gtk_tree_model_iter_next (tree_model, &iter))
- {
- path = gtk_tree_model_get_path (tree_model, &iter);
- row_reference = gtk_tree_row_reference_new (tree_model, path);
- }
- else
- {
- path = gtk_tree_model_get_path (tree_model, &temp_iter);
- if (gtk_tree_path_prev (path))
- {
- row_reference = gtk_tree_row_reference_new (tree_model, path);
- }
- }
- gtk_tree_path_free (path);
- }
-
- gtk_tree_path_free (file_path);
-
- nautilus_list_model_remove_file (list_view->details->model, file, directory);
-
- if (gtk_tree_row_reference_valid (row_reference))
- {
- if (list_view->details->new_selection_path)
- {
- gtk_tree_path_free (list_view->details->new_selection_path);
- }
- list_view->details->new_selection_path = gtk_tree_row_reference_get_path (row_reference);
- }
-
- if (row_reference)
- {
- gtk_tree_row_reference_free (row_reference);
- }
- }
-}
-
-static void
-nautilus_list_view_set_selection (NautilusFilesView *view,
- GList *selection)
-{
- NautilusListView *list_view;
- NautilusListModel *model;
- GtkTreeView *tree_view;
- GtkTreeSelection *tree_selection;
- GList *node;
- gboolean cursor_is_set_on_selection = FALSE;
- GList *iters, *l;
- NautilusFile *file;
-
- list_view = NAUTILUS_LIST_VIEW (view);
- model = list_view->details->model;
- tree_view = list_view->details->tree_view;
- tree_selection = gtk_tree_view_get_selection (tree_view);
-
- g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
-
- gtk_tree_selection_unselect_all (tree_selection);
- for (node = selection; node != NULL; node = node->next)
- {
- file = node->data;
- iters = nautilus_list_model_get_all_iters_for_file (model, file);
-
- for (l = iters; l != NULL; l = l->next)
- {
- if (!cursor_is_set_on_selection)
- {
- GtkTreePath *path;
-
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model),
- (GtkTreeIter *) l->data);
- gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
- gtk_tree_path_free (path);
-
- cursor_is_set_on_selection = TRUE;
- continue;
- }
-
- gtk_tree_selection_select_iter (tree_selection,
- (GtkTreeIter *) l->data);
- }
- g_list_free_full (iters, g_free);
- }
-
- g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
- nautilus_files_view_notify_selection_changed (view);
-}
-
-static void
-nautilus_list_view_invert_selection (NautilusFilesView *view)
-{
- NautilusListView *list_view;
- GtkTreeSelection *tree_selection;
- GList *node;
- GList *iters, *l;
- NautilusFile *file;
- GList *selection = NULL;
-
- list_view = NAUTILUS_LIST_VIEW (view);
- tree_selection = gtk_tree_view_get_selection (list_view->details->tree_view);
-
- g_signal_handlers_block_by_func (tree_selection, list_selection_changed_callback, view);
-
- gtk_tree_selection_selected_foreach (tree_selection,
- nautilus_list_view_get_selection_foreach_func, &selection);
-
- gtk_tree_selection_select_all (tree_selection);
-
- for (node = selection; node != NULL; node = node->next)
- {
- file = node->data;
- iters = nautilus_list_model_get_all_iters_for_file (list_view->details->model, file);
-
- for (l = iters; l != NULL; l = l->next)
- {
- gtk_tree_selection_unselect_iter (tree_selection,
- (GtkTreeIter *) l->data);
- }
- g_list_free_full (iters, g_free);
- }
-
- g_list_free (selection);
-
- g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
- nautilus_files_view_notify_selection_changed (view);
-}
-
-static void
-nautilus_list_view_select_all (NautilusFilesView *view)
-{
- gtk_tree_selection_select_all (gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view));
-}
-
-static void
-nautilus_list_view_select_first (NautilusFilesView *view)
-{
- GtkTreeSelection *selection;
- GtkTreeIter iter;
-
- if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (NAUTILUS_LIST_VIEW (view)->details->model), &iter))
- {
- return;
- }
- selection = gtk_tree_view_get_selection (NAUTILUS_LIST_VIEW (view)->details->tree_view);
- gtk_tree_selection_unselect_all (selection);
- gtk_tree_selection_select_iter (selection, &iter);
-}
-
-static void
-nautilus_list_view_zoom_to_level (NautilusFilesView *view,
- gint zoom_level)
-{
- NautilusListView *list_view;
-
- g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
-
- list_view = NAUTILUS_LIST_VIEW (view);
-
- if (list_view->details->zoom_level == zoom_level)
- {
- return;
- }
-
- nautilus_list_view_set_zoom_level (list_view, zoom_level);
- g_action_group_change_action_state (nautilus_files_view_get_action_group (view),
- "zoom-to-level", g_variant_new_int32 (zoom_level));
-
- nautilus_files_view_update_toolbar_menus (view);
-}
-
-static void
-action_zoom_to_level (GSimpleAction *action,
- GVariant *state,
- gpointer user_data)
-{
- NautilusFilesView *view;
- NautilusListZoomLevel zoom_level;
-
- g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
-
- view = NAUTILUS_FILES_VIEW (user_data);
- zoom_level = g_variant_get_int32 (state);
- nautilus_list_view_zoom_to_level (view, zoom_level);
-
- g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
- if (g_settings_get_enum (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL) != zoom_level)
- {
- g_settings_set_enum (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL,
- zoom_level);
- }
+ return GTK_COLUMN_VIEW (widget);
}
static void
@@ -3241,708 +581,585 @@ action_visible_columns (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
- NautilusListView *list_view;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (user_data);
- list_view = NAUTILUS_LIST_VIEW (user_data);
-
- if (list_view->details->column_editor)
+ if (self->column_editor)
{
- gtk_window_present (GTK_WINDOW (list_view->details->column_editor));
+ gtk_widget_show (self->column_editor);
}
else
{
- list_view->details->column_editor = create_column_editor (list_view);
- g_object_add_weak_pointer (G_OBJECT (list_view->details->column_editor),
- (gpointer *) &list_view->details->column_editor);
+ self->column_editor = create_column_editor (self);
+ g_object_add_weak_pointer (G_OBJECT (self->column_editor),
+ (gpointer *) &self->column_editor);
- gtk_widget_show (list_view->details->column_editor);
+ gtk_widget_show (self->column_editor);
}
}
-const GActionEntry list_view_entries[] =
-{
- { "visible-columns", action_visible_columns },
- { "zoom-to-level", NULL, NULL, "1", action_zoom_to_level }
-};
-
static void
-nautilus_list_view_set_zoom_level (NautilusListView *view,
- NautilusListZoomLevel new_level)
+action_sort_order_changed (GSimpleAction *action,
+ GVariant *value,
+ gpointer user_data)
{
- int column;
+ const gchar *target_name;
+ gboolean reversed;
+ NautilusFileSortType sort_type;
+ NautilusListView *self;
+ GListModel *view_columns;
+ g_autoptr (GtkColumnViewColumn) sort_column = NULL;
+ GtkSorter *sorter;
- g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
- g_return_if_fail (new_level >= NAUTILUS_LIST_ZOOM_LEVEL_SMALL &&
- new_level <= NAUTILUS_LIST_ZOOM_LEVEL_LARGER);
+ /* This array makes the #NautilusFileSortType values correspond to the
+ * respective column attribute.
+ */
+ const char *attributes[] =
+ {
+ "name",
+ "size",
+ "type",
+ "date_modified",
+ "date_accessed",
+ "date_created",
+ "starred",
+ "trashed_on",
+ "search_relevance",
+ "recency",
+ NULL
+ };
- if (view->details->zoom_level == new_level)
+ /* Don't resort if the action is in the same state as before */
+ if (g_variant_equal (value, g_action_get_state (G_ACTION (action))))
{
return;
}
- view->details->zoom_level = new_level;
-
- /* Select correctly scaled icons. */
- column = nautilus_list_model_get_column_id_from_zoom_level (new_level);
- gtk_tree_view_column_set_attributes (view->details->file_name_column,
- GTK_CELL_RENDERER (view->details->pixbuf_cell),
- "texture", column,
- NULL);
- set_up_pixbuf_size (view);
-}
-
-static void
-nautilus_list_view_bump_zoom_level (NautilusFilesView *view,
- int zoom_increment)
-{
- NautilusListView *list_view;
- gint new_level;
+ self = NAUTILUS_LIST_VIEW (user_data);
+ g_variant_get (value, "(&sb)", &target_name, &reversed);
- g_return_if_fail (NAUTILUS_IS_LIST_VIEW (view));
+ if (g_strcmp0 (target_name, "unknown") == 0)
+ {
+ /* Sort order has been changed without using this action. */
+ g_simple_action_set_state (action, value);
+ return;
+ }
- list_view = NAUTILUS_LIST_VIEW (view);
- new_level = list_view->details->zoom_level + zoom_increment;
+ sort_type = get_sorts_type_from_metadata_text (target_name);
- if (new_level >= NAUTILUS_LIST_ZOOM_LEVEL_SMALL &&
- new_level <= NAUTILUS_LIST_ZOOM_LEVEL_LARGER)
+ view_columns = gtk_column_view_get_columns (self->view_ui);
+ for (guint i = 0; i < g_list_model_get_n_items (view_columns); i++)
{
- nautilus_list_view_zoom_to_level (view, new_level);
- }
-}
+ g_autoptr (GtkColumnViewColumn) view_column = NULL;
+ GtkListItemFactory *factory;
+ NautilusColumn *nautilus_column;
+ gchar *attribute;
-static void
-nautilus_list_view_restore_standard_zoom_level (NautilusFilesView *view)
-{
- nautilus_list_view_zoom_to_level (view, NAUTILUS_LIST_ZOOM_LEVEL_STANDARD);
-}
+ view_column = g_list_model_get_item (view_columns, i);
+ factory = gtk_column_view_column_get_factory (view_column);
+ nautilus_column = g_hash_table_lookup (self->factory_to_column_map, factory);
+ if (nautilus_column == NULL)
+ {
+ continue;
+ }
+ g_object_get (nautilus_column, "attribute", &attribute, NULL);
+ if (g_strcmp0 (attributes[sort_type], attribute) == 0)
+ {
+ sort_column = g_steal_pointer (&view_column);
+ break;
+ }
+ }
-static gboolean
-nautilus_list_view_can_zoom_in (NautilusFilesView *view)
-{
- g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
+ sorter = gtk_column_view_get_sorter (self->view_ui);
- return NAUTILUS_LIST_VIEW (view)->details->zoom_level < NAUTILUS_LIST_ZOOM_LEVEL_LARGER;
-}
+ g_signal_handlers_block_by_func (sorter, on_sorter_changed, self);
+ /* FIXME: Set NULL to stop drawing the arrow on previous sort column
+ * to workaround https://gitlab.gnome.org/GNOME/gtk/-/issues/4696 */
+ gtk_column_view_sort_by_column (self->view_ui, NULL, FALSE);
+ gtk_column_view_sort_by_column (self->view_ui, sort_column, reversed);
+ g_signal_handlers_unblock_by_func (sorter, on_sorter_changed, self);
-static gboolean
-nautilus_list_view_can_zoom_out (NautilusFilesView *view)
-{
- g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), FALSE);
+ set_directory_sort_metadata (nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self)),
+ target_name,
+ reversed);
- return NAUTILUS_LIST_VIEW (view)->details->zoom_level > NAUTILUS_LIST_ZOOM_LEVEL_SMALL;
+ g_simple_action_set_state (action, value);
}
-static gboolean
-nautilus_list_view_is_zoom_level_default (NautilusFilesView *view)
+static void
+set_zoom_level (NautilusListView *self,
+ guint new_level)
{
- NautilusListView *list_view;
- guint icon_size;
+ self->zoom_level = new_level;
+
+ nautilus_list_base_set_icon_size (NAUTILUS_LIST_BASE (self),
+ get_icon_size_for_zoom_level (new_level));
- list_view = NAUTILUS_LIST_VIEW (view);
- icon_size = nautilus_list_model_get_icon_size_for_zoom_level (list_view->details->zoom_level);
+ if (self->zoom_level == NAUTILUS_LIST_ZOOM_LEVEL_SMALL)
+ {
+ gtk_widget_add_css_class (GTK_WIDGET (self), "compact");
+ }
+ else
+ {
+ gtk_widget_remove_css_class (GTK_WIDGET (self), "compact");
+ }
- return icon_size == NAUTILUS_LIST_ICON_SIZE_STANDARD;
+ nautilus_files_view_update_toolbar_menus (NAUTILUS_FILES_VIEW (self));
}
static void
-nautilus_list_view_click_policy_changed (NautilusFilesView *directory_view)
+action_zoom_to_level (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
{
- GdkDisplay *display;
- NautilusListView *view;
- GtkTreeIter iter;
- GtkTreeView *tree;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (user_data);
+ int zoom_level;
- view = NAUTILUS_LIST_VIEW (directory_view);
- display = gtk_widget_get_display (GTK_WIDGET (view));
+ zoom_level = g_variant_get_int32 (state);
+ set_zoom_level (self, zoom_level);
+ g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
- /* ensure that we unset the hand cursor and refresh underlined rows */
- if (get_click_policy () == NAUTILUS_CLICK_POLICY_DOUBLE)
+ if (g_settings_get_enum (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL) != zoom_level)
{
- if (view->details->hover_path != NULL)
- {
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
- &iter, view->details->hover_path))
- {
- gtk_tree_model_row_changed (GTK_TREE_MODEL (view->details->model),
- view->details->hover_path, &iter);
- }
+ g_settings_set_enum (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL,
+ zoom_level);
+ }
+}
- gtk_tree_path_free (view->details->hover_path);
- view->details->hover_path = NULL;
- }
+const GActionEntry list_view_entries[] =
+{
+ { "visible-columns", action_visible_columns },
+ { "sort", NULL, "(sb)", "('invalid',false)", action_sort_order_changed },
+ { "zoom-to-level", NULL, NULL, "1", action_zoom_to_level }
+};
- tree = view->details->tree_view;
- if (gtk_widget_get_realized (GTK_WIDGET (tree)))
- {
- gtk_widget_set_cursor (GTK_WIDGET (tree), NULL);
+static void
+real_begin_loading (NautilusFilesView *files_view)
+{
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_view);
+ NautilusFile *file;
- if (display != NULL)
- {
- gdk_display_flush (display);
- }
- }
+ NAUTILUS_FILES_VIEW_CLASS (nautilus_list_view_parent_class)->begin_loading (files_view);
+
+ update_columns_settings_from_metadata_and_preferences (self);
- g_clear_object (&hand_cursor);
+ self->path_attribute_q = 0;
+ g_clear_object (&self->file_path_base_location);
+ file = nautilus_files_view_get_directory_as_file (files_view);
+ if (nautilus_file_is_in_trash (file))
+ {
+ self->path_attribute_q = g_quark_from_string ("trash_orig_path");
+ self->file_path_base_location = get_base_location (self);
}
- else if (get_click_policy () == NAUTILUS_CLICK_POLICY_SINGLE)
+ else if (nautilus_file_is_in_search (file) ||
+ nautilus_file_is_in_recent (file) ||
+ nautilus_file_is_in_starred (file))
{
- if (hand_cursor == NULL)
- {
- hand_cursor = gdk_cursor_new_from_name ("pointer", NULL);
- }
+ self->path_attribute_q = g_quark_from_string ("where");
+ self->file_path_base_location = get_base_location (self);
}
}
static void
-default_sort_order_changed_callback (gpointer callback_data)
+real_bump_zoom_level (NautilusFilesView *files_view,
+ int zoom_increment)
{
- NautilusListView *list_view;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_view);
+ NautilusListZoomLevel new_level;
- list_view = NAUTILUS_LIST_VIEW (callback_data);
+ new_level = self->zoom_level + zoom_increment;
- set_sort_order_from_metadata_and_preferences (list_view);
+ if (new_level >= NAUTILUS_LIST_ZOOM_LEVEL_SMALL &&
+ new_level <= NAUTILUS_LIST_ZOOM_LEVEL_LARGE)
+ {
+ g_action_group_change_action_state (self->action_group,
+ "zoom-to-level",
+ g_variant_new_int32 (new_level));
+ }
}
-static void
-default_visible_columns_changed_callback (gpointer callback_data)
+static gint
+get_default_zoom_level (void)
{
- NautilusListView *list_view;
+ NautilusListZoomLevel default_zoom_level;
- list_view = NAUTILUS_LIST_VIEW (callback_data);
+ default_zoom_level = g_settings_get_enum (nautilus_list_view_preferences,
+ NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL);
- set_columns_settings_from_metadata_and_preferences (list_view);
+ /* Sanitize preference value. */
+ return CLAMP (default_zoom_level,
+ NAUTILUS_LIST_ZOOM_LEVEL_SMALL,
+ NAUTILUS_LIST_ZOOM_LEVEL_LARGE);
}
static void
-default_column_order_changed_callback (gpointer callback_data)
+real_restore_standard_zoom_level (NautilusFilesView *files_view)
{
- NautilusListView *list_view;
-
- list_view = NAUTILUS_LIST_VIEW (callback_data);
+ NautilusListView *self;
- set_columns_settings_from_metadata_and_preferences (list_view);
+ self = NAUTILUS_LIST_VIEW (files_view);
+ g_action_group_change_action_state (self->action_group,
+ "zoom-to-level",
+ g_variant_new_int32 (NAUTILUS_LIST_ZOOM_LEVEL_MEDIUM));
}
-static void
-nautilus_list_view_sort_directories_first_changed (NautilusFilesView *view)
+static gboolean
+real_can_zoom_in (NautilusFilesView *files_view)
{
- NautilusListView *list_view;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_view);
- list_view = NAUTILUS_LIST_VIEW (view);
-
- nautilus_list_model_set_should_sort_directories_first (list_view->details->model,
- nautilus_files_view_should_sort_directories_first (view));
+ return self->zoom_level < NAUTILUS_LIST_ZOOM_LEVEL_LARGE;
}
-static int
-nautilus_list_view_compare_files (NautilusFilesView *view,
- NautilusFile *file1,
- NautilusFile *file2)
+static gboolean
+real_can_zoom_out (NautilusFilesView *files_view)
{
- NautilusListView *list_view;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_view);
- list_view = NAUTILUS_LIST_VIEW (view);
- return nautilus_list_model_compare_func (list_view->details->model, file1, file2);
+ return self->zoom_level > NAUTILUS_LIST_ZOOM_LEVEL_SMALL;
}
-static void
-nautilus_list_view_dispose (GObject *object)
+static gboolean
+real_is_zoom_level_default (NautilusFilesView *files_view)
{
- NautilusListView *list_view;
-
- list_view = NAUTILUS_LIST_VIEW (object);
-
- if (list_view->details->model)
- {
- g_object_unref (list_view->details->model);
- list_view->details->model = NULL;
- }
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
- if (list_view->details->drag_dest)
- {
- g_object_unref (list_view->details->drag_dest);
- list_view->details->drag_dest = NULL;
- }
-#endif
-
- g_signal_handlers_disconnect_by_func (nautilus_preferences,
- default_sort_order_changed_callback,
- list_view);
- g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
- default_visible_columns_changed_callback,
- list_view);
- g_signal_handlers_disconnect_by_func (nautilus_list_view_preferences,
- default_column_order_changed_callback,
- list_view);
+ NautilusListView *self;
+ guint icon_size;
- g_clear_pointer (&list_view->details->columns_popover, gtk_widget_unparent);
+ self = NAUTILUS_LIST_VIEW (files_view);
+ icon_size = get_icon_size_for_zoom_level (self->zoom_level);
- G_OBJECT_CLASS (nautilus_list_view_parent_class)->dispose (object);
+ return icon_size == NAUTILUS_LIST_ICON_SIZE_MEDIUM;
}
static void
-nautilus_list_view_finalize (GObject *object)
+real_sort_directories_first_changed (NautilusFilesView *files_view)
{
- NautilusListView *list_view;
-
- list_view = NAUTILUS_LIST_VIEW (object);
-
- g_free (list_view->details->original_name);
- list_view->details->original_name = NULL;
-
- if (list_view->details->first_click_path)
- {
- gtk_tree_path_free (list_view->details->first_click_path);
- }
- if (list_view->details->new_selection_path)
- {
- gtk_tree_path_free (list_view->details->new_selection_path);
- }
-
- g_list_free (list_view->details->cells);
- g_hash_table_destroy (list_view->details->columns);
-
- if (list_view->details->hover_path != NULL)
- {
- gtk_tree_path_free (list_view->details->hover_path);
- }
-
- if (list_view->details->column_editor != NULL)
- {
- gtk_window_destroy (GTK_WINDOW (list_view->details->column_editor));
- }
+ NautilusListView *self = NAUTILUS_LIST_VIEW (files_view);
+ NautilusViewModel *model;
- g_regex_unref (list_view->details->regex);
+ self->directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self));
- g_cancellable_cancel (list_view->details->starred_cancellable);
- g_clear_object (&list_view->details->starred_cancellable);
-
- g_signal_handlers_disconnect_by_func (nautilus_tag_manager_get (),
- on_starred_files_changed,
- list_view);
-
- g_free (list_view->details);
-
- G_OBJECT_CLASS (nautilus_list_view_parent_class)->finalize (object);
+ /* Reset the sorter to trigger ressorting */
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
+ nautilus_view_model_set_sorter (model, nautilus_view_model_get_sorter (model));
}
-static char *
-nautilus_list_view_get_first_visible_file (NautilusFilesView *view)
+static void
+on_sorter_changed (GtkSorter *sorter,
+ GtkSorterChange change,
+ gpointer user_data)
{
- NautilusFile *file;
- GtkTreePath *path;
- GtkTreeIter iter;
- NautilusListView *list_view;
-
- list_view = NAUTILUS_LIST_VIEW (view);
-
- if (gtk_tree_view_get_path_at_pos (list_view->details->tree_view,
- 0, 0,
- &path, NULL, NULL, NULL))
- {
- gtk_tree_model_get_iter (GTK_TREE_MODEL (list_view->details->model),
- &iter, path);
-
- gtk_tree_path_free (path);
-
- gtk_tree_model_get (GTK_TREE_MODEL (list_view->details->model),
- &iter,
- NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
- -1);
- if (file)
- {
- char *uri;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (user_data);
- uri = nautilus_file_get_uri (file);
-
- nautilus_file_unref (file);
-
- return uri;
- }
- }
+ /* When user clicks a header to change sort order, we don't know what the
+ * new sort order is. Make sure the sort menu doesn't indicate a outdated
+ * action state. */
+ g_action_group_change_action_state (nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (self)),
+ "sort", g_variant_new ("(sb)", "unknown", FALSE));
+}
- return NULL;
+static guint
+real_get_view_id (NautilusFilesView *files_view)
+{
+ return NAUTILUS_VIEW_LIST_ID;
}
static void
-nautilus_list_view_scroll_to_file (NautilusListView *view,
- NautilusFile *file)
+on_item_click_released_workaround (GtkGestureClick *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
{
- GtkTreePath *path;
- GtkTreeIter iter;
+ NautilusViewCell *cell = user_data;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (nautilus_view_cell_get_view (cell));
+ GdkModifierType modifiers;
- if (!nautilus_list_model_get_first_iter_for_file (view->details->model, file, &iter))
+ modifiers = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (gesture));
+ if (n_press == 1 &&
+ modifiers & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
{
- return;
- }
+ NautilusViewModel *model;
+ NautilusViewItem *item;
+ guint i;
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->model), &iter);
+ 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);
- gtk_tree_view_scroll_to_cell (view->details->tree_view,
- path, NULL,
- TRUE, 0.0, 0.0);
-
- gtk_tree_path_free (path);
+ gtk_widget_activate_action (GTK_WIDGET (cell),
+ "list.select-item",
+ "(ubb)",
+ i,
+ modifiers & GDK_CONTROL_MASK,
+ modifiers & GDK_SHIFT_MASK);
+ }
}
+/* This whole event handler is a workaround to a GtkColumnView bug: it
+ * activates the list|select-item action twice, which may cause the
+ * second activation to reverse the effects of the first:
+ * https://gitlab.gnome.org/GNOME/gtk/-/issues/4819
+ *
+ * As a workaround, we are going to activate the action a 3rd time.
+ * The third time is the charm, as the saying goes. */
static void
-list_view_scroll_to_file (NautilusFilesView *view,
- const char *uri)
+setup_selection_click_workaround (NautilusViewCell *cell)
{
- NautilusFile *file;
+ GtkEventController *controller;
- if (uri != NULL)
- {
- /* Only if existing, since we don't want to add the file to
- * the directory if it has been removed since then */
- file = nautilus_file_get_existing_by_uri (uri);
- if (file != NULL)
- {
- nautilus_list_view_scroll_to_file (NAUTILUS_LIST_VIEW (view), file);
- nautilus_file_unref (file);
- }
- }
+ 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), GDK_BUTTON_PRIMARY);
+ g_signal_connect (controller, "released", G_CALLBACK (on_item_click_released_workaround), cell);
}
static void
-on_clipboard_contents_received (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
+setup_name_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
{
- NautilusFilesView *files_view = NAUTILUS_FILES_VIEW (source_object);
- NautilusListViewDetails *details = NAUTILUS_LIST_VIEW (files_view)->details;
- NautilusClipboard *clip;
+ NautilusListView *self = NAUTILUS_LIST_VIEW (user_data);
+ NautilusViewCell *cell;
- clip = nautilus_files_view_get_clipboard_finish (files_view, res, NULL);
- if (clip != NULL && nautilus_clipboard_is_cut (clip))
- {
- GList *files;
+ cell = nautilus_name_cell_new (NAUTILUS_LIST_BASE (self));
+ setup_cell_common (listitem, cell);
- files = nautilus_clipboard_peek_files (clip);
- nautilus_list_model_set_highlight_for_files (details->model, files);
- }
- else
+ nautilus_name_cell_set_path (NAUTILUS_NAME_CELL (cell),
+ self->path_attribute_q,
+ self->file_path_base_location);
+ if (NAUTILUS_IS_SEARCH_DIRECTORY (nautilus_files_view_get_model (NAUTILUS_FILES_VIEW (self))))
{
- nautilus_list_model_set_highlight_for_files (details->model, NULL);
+ nautilus_name_cell_show_snippet (NAUTILUS_NAME_CELL (cell));
}
+
+ gtk_list_item_set_child (listitem, GTK_WIDGET (cell));
+
+ setup_selection_click_workaround (cell);
}
static void
-update_clipboard_status (NautilusFilesView *view)
+bind_name_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
{
- nautilus_files_view_get_clipboard_async (view,
- on_clipboard_contents_received,
- NULL);
+ NautilusViewItem *item;
+
+ item = NAUTILUS_VIEW_ITEM (gtk_list_item_get_item (listitem));
+
+ nautilus_view_item_set_item_ui (item, gtk_list_item_get_child (listitem));
}
static void
-on_clipboard_owner_changed (GdkClipboard *clipboard,
- gpointer user_data)
+unbind_name_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
{
- update_clipboard_status (NAUTILUS_FILES_VIEW (user_data));
+ NautilusViewItem *item;
+
+ item = NAUTILUS_VIEW_ITEM (gtk_list_item_get_item (listitem));
+ g_return_if_fail (NAUTILUS_IS_VIEW_ITEM (item));
+
+ nautilus_view_item_set_item_ui (item, NULL);
}
static void
-nautilus_list_view_end_loading (NautilusFilesView *view,
- gboolean all_files_seen)
+setup_star_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
{
- update_clipboard_status (view);
-}
+ NautilusViewCell *cell;
-static guint
-nautilus_list_view_get_id (NautilusFilesView *view)
-{
- return NAUTILUS_VIEW_LIST_ID;
+ cell = nautilus_star_cell_new (NAUTILUS_LIST_BASE (user_data));
+ setup_cell_common (listitem, cell);
+ setup_selection_click_workaround (cell);
}
-static GdkRectangle *
-get_rectangle_for_path (NautilusListView *list_view,
- GtkTreePath *path)
+static void
+setup_label_cell (GtkSignalListItemFactory *factory,
+ GtkListItem *listitem,
+ gpointer user_data)
{
- GtkTreeView *tree_view = list_view->details->tree_view;
- GdkRectangle *rect = g_malloc0 (sizeof (GdkRectangle));
- int header_height;
-
- gtk_tree_view_get_cell_area (tree_view,
- path,
- list_view->details->file_name_column,
- rect);
- gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
- rect->x, rect->y,
- &rect->x, &rect->y);
-
- /* FIXME Due to smooth scrolling, we may get the cell area while the view is
- * still scrolling (and still outside the view), not at the final position
- * of the cell after scrolling.
- * https://bugzilla.gnome.org/show_bug.cgi?id=746773
- * The following workaround guesses the final "y" coordinate by clamping it
- * to the widget edge. Note that the top edge has got columns header, which
- * is private, so first guess the header height from the difference between
- * widget coordinates and bin cooridinates.
- */
- gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
- 0, 0,
- NULL, &header_height);
+ NautilusListView *self = user_data;
+ NautilusColumn *nautilus_column;
+ NautilusViewCell *cell;
- rect->y = CLAMP (rect->y,
- header_height,
- gtk_widget_get_allocated_height (GTK_WIDGET (list_view)) - rect->height);
- /* End of workaround */
+ nautilus_column = g_hash_table_lookup (self->factory_to_column_map, factory);
- return rect;
+ cell = nautilus_label_cell_new (NAUTILUS_LIST_BASE (user_data), nautilus_column);
+ setup_cell_common (listitem, cell);
+ setup_selection_click_workaround (cell);
}
-static GdkRectangle *
-nautilus_list_view_compute_rename_popover_pointing_to (NautilusFilesView *view)
+static void
+setup_view_columns (NautilusListView *self)
{
- NautilusListView *list_view;
- GtkTreeView *tree_view;
- GtkTreeSelection *selection;
- GList *list;
- GtkTreePath *path;
- GdkRectangle *rect;
-
- list_view = NAUTILUS_LIST_VIEW (view);
- tree_view = list_view->details->tree_view;
- selection = gtk_tree_view_get_selection (tree_view);
- list = gtk_tree_selection_get_selected_rows (selection, NULL);
- path = list->data;
- rect = get_rectangle_for_path (list_view, path);
-
- if (list_view->details->last_event_button_x > 0)
- {
- /* Point to the position in the row where it was clicked. */
- rect->x = list_view->details->last_event_button_x;
- /* Make it zero width to point exactly at rect->x.*/
- rect->width = 0;
- }
+ GtkListItemFactory *factory;
+ g_autolist (NautilusColumn) nautilus_columns = NULL;
- g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
+ nautilus_columns = nautilus_get_all_columns ();
- return rect;
-}
+ self->factory_to_column_map = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
-static GdkRectangle *
-nautilus_list_view_reveal_for_selection_context_menu (NautilusFilesView *view)
-{
- NautilusListView *list_view;
- GtkTreeView *tree_view;
- GtkTreeSelection *tree_selection;
- GtkTreePath *path;
- GdkRectangle *rect;
+ for (GList *l = nautilus_columns; l != NULL; l = l->next)
+ {
+ NautilusColumn *nautilus_column = NAUTILUS_COLUMN (l->data);
+ g_autofree gchar *name = NULL;
+ g_autofree gchar *label = NULL;
+ GQuark attribute_q = 0;
+ GtkSortType sort_order;
+ g_autoptr (GtkCustomSorter) sorter = NULL;
+ g_autoptr (GtkColumnViewColumn) view_column = NULL;
- g_return_val_if_fail (NAUTILUS_IS_LIST_VIEW (view), NULL);
+ g_object_get (nautilus_column,
+ "name", &name,
+ "label", &label,
+ "attribute_q", &attribute_q,
+ "default-sort-order", &sort_order,
+ NULL);
- list_view = NAUTILUS_LIST_VIEW (view);
- tree_view = list_view->details->tree_view;
- tree_selection = gtk_tree_view_get_selection (tree_view);
- g_return_val_if_fail (tree_selection != NULL, NULL);
+ sorter = gtk_custom_sorter_new (nautilus_list_view_sort,
+ GUINT_TO_POINTER (attribute_q),
+ NULL);
- /* Get the path to the last focused item, if selected. Otherwise, get
- * the path to the selected item which is sorted the lowest.
- */
- gtk_tree_view_get_cursor (tree_view, &path, NULL);
- if (path == NULL || !gtk_tree_selection_path_is_selected (tree_selection, path))
- {
- GList *list;
+ factory = gtk_signal_list_item_factory_new ();
+ view_column = gtk_column_view_column_new (NULL, factory);
+ gtk_column_view_column_set_expand (view_column, FALSE);
+ gtk_column_view_column_set_resizable (view_column, TRUE);
+ gtk_column_view_column_set_title (view_column, label);
+ gtk_column_view_column_set_sorter (view_column, GTK_SORTER (sorter));
- list = gtk_tree_selection_get_selected_rows (tree_selection, NULL);
- list = g_list_last (list);
- path = g_steal_pointer (&list->data);
+ if (!strcmp (name, "name"))
+ {
+ g_signal_connect (factory, "setup", G_CALLBACK (setup_name_cell), self);
+ g_signal_connect (factory, "bind", G_CALLBACK (bind_name_cell), self);
+ g_signal_connect (factory, "unbind", G_CALLBACK (unbind_name_cell), self);
- g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
- }
+ gtk_column_view_column_set_expand (view_column, TRUE);
+ }
+ else if (g_strcmp0 (name, "starred") == 0)
+ {
+ g_signal_connect (factory, "setup", G_CALLBACK (setup_star_cell), self);
- gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
+ gtk_column_view_column_set_title (view_column, "");
+ gtk_column_view_column_set_resizable (view_column, FALSE);
- rect = get_rectangle_for_path (list_view, path);
- rect->width = rect->height;
+ self->star_column = view_column;
+ }
+ else
+ {
+ g_signal_connect (factory, "setup", G_CALLBACK (setup_label_cell), self);
+ }
- gtk_tree_path_free (path);
+ gtk_column_view_append_column (self->view_ui, view_column);
- return rect;
+ g_hash_table_insert (self->factory_to_column_map,
+ factory,
+ g_object_ref (nautilus_column));
+ }
}
static void
-nautilus_list_view_preview_selection_event (NautilusFilesView *view,
- GtkDirectionType direction)
+nautilus_list_view_init (NautilusListView *self)
{
- NautilusListView *list_view;
- GtkTreeView *tree_view;
- GtkTreeSelection *selection;
- GList *list;
- GtkTreeIter iter;
- GtkTreePath *path;
- GtkTreeModel *tree_model;
- gboolean moved;
-
- /* We only support up and down movements for the list view */
- if (direction != GTK_DIR_UP && direction != GTK_DIR_DOWN)
- {
- return;
- }
+ NautilusViewModel *model;
+ GtkWidget *content_widget;
+ g_autoptr (GtkCustomSorter) directories_sorter = NULL;
+ g_autoptr (GtkMultiSorter) sorter = NULL;
- list_view = NAUTILUS_LIST_VIEW (view);
- tree_view = list_view->details->tree_view;
- selection = gtk_tree_view_get_selection (tree_view);
- list = gtk_tree_selection_get_selected_rows (selection, &tree_model);
+ gtk_widget_add_css_class (GTK_WIDGET (self), "nautilus-list-view");
- if (list == NULL)
- {
- return;
- }
+ g_signal_connect_object (nautilus_list_view_preferences,
+ "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS,
+ G_CALLBACK (update_columns_settings_from_metadata_and_preferences),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (nautilus_list_view_preferences,
+ "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER,
+ G_CALLBACK (update_columns_settings_from_metadata_and_preferences),
+ self,
+ G_CONNECT_SWAPPED);
- /* Advance the first selected item, since that's what we use for
- * the previewer */
- path = list->data;
- moved = FALSE;
- if (gtk_tree_model_get_iter (tree_model, &iter, path))
- {
- if (direction == GTK_DIR_UP)
- {
- moved = gtk_tree_model_iter_previous (tree_model, &iter);
- }
- else
- {
- moved = gtk_tree_model_iter_next (tree_model, &iter);
- }
- }
+ content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (self));
- if (moved)
- {
- g_signal_handlers_block_by_func (selection, list_selection_changed_callback, view);
+ self->view_ui = create_view_ui (self);
+ nautilus_list_base_setup_gestures (NAUTILUS_LIST_BASE (self));
- gtk_tree_selection_unselect_all (selection);
- gtk_tree_selection_select_iter (selection, &iter);
+ setup_view_columns (self);
- g_signal_handlers_unblock_by_func (selection, list_selection_changed_callback, view);
- nautilus_files_view_notify_selection_changed (view);
- }
+ self->directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self));
+ directories_sorter = gtk_custom_sorter_new (sort_directories_func, &self->directories_first, NULL);
+
+ sorter = gtk_multi_sorter_new ();
+ gtk_multi_sorter_append (sorter, g_object_ref (GTK_SORTER (directories_sorter)));
+ gtk_multi_sorter_append (sorter, g_object_ref (gtk_column_view_get_sorter (self->view_ui)));
+ g_signal_connect_object (sorter, "changed", G_CALLBACK (on_sorter_changed), self, 0);
+
+ model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
+ nautilus_view_model_set_sorter (model, GTK_SORTER (sorter));
+
+ 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),
+ list_view_entries,
+ G_N_ELEMENTS (list_view_entries),
+ self);
+
+ self->zoom_level = get_default_zoom_level ();
+ 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_list_view_dispose (GObject *object)
+{
+ NautilusListView *self = NAUTILUS_LIST_VIEW (object);
- g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
+ g_clear_object (&self->file_path_base_location);
+ g_clear_pointer (&self->factory_to_column_map, g_hash_table_destroy);
+
+ G_OBJECT_CLASS (nautilus_list_view_parent_class)->dispose (object);
}
static void
-nautilus_list_view_class_init (NautilusListViewClass *class)
+nautilus_list_view_finalize (GObject *object)
{
- NautilusFilesViewClass *nautilus_files_view_class;
-
- nautilus_files_view_class = NAUTILUS_FILES_VIEW_CLASS (class);
-
- G_OBJECT_CLASS (class)->dispose = nautilus_list_view_dispose;
- G_OBJECT_CLASS (class)->finalize = nautilus_list_view_finalize;
-
- nautilus_files_view_class->add_files = nautilus_list_view_add_files;
- nautilus_files_view_class->begin_loading = nautilus_list_view_begin_loading;
- nautilus_files_view_class->end_loading = nautilus_list_view_end_loading;
- nautilus_files_view_class->bump_zoom_level = nautilus_list_view_bump_zoom_level;
- nautilus_files_view_class->can_zoom_in = nautilus_list_view_can_zoom_in;
- nautilus_files_view_class->can_zoom_out = nautilus_list_view_can_zoom_out;
- nautilus_files_view_class->is_zoom_level_default = nautilus_list_view_is_zoom_level_default;
- nautilus_files_view_class->click_policy_changed = nautilus_list_view_click_policy_changed;
- nautilus_files_view_class->clear = nautilus_list_view_clear;
- nautilus_files_view_class->file_changed = nautilus_list_view_file_changed;
- nautilus_files_view_class->get_backing_uri = nautilus_list_view_get_backing_uri;
- nautilus_files_view_class->get_selection = nautilus_list_view_get_selection;
- nautilus_files_view_class->get_selection_for_file_transfer = nautilus_list_view_get_selection_for_file_transfer;
- nautilus_files_view_class->is_empty = nautilus_list_view_is_empty;
- nautilus_files_view_class->remove_file = nautilus_list_view_remove_file;
- nautilus_files_view_class->restore_standard_zoom_level = nautilus_list_view_restore_standard_zoom_level;
- nautilus_files_view_class->reveal_selection = nautilus_list_view_reveal_selection;
- nautilus_files_view_class->select_all = nautilus_list_view_select_all;
- nautilus_files_view_class->select_first = nautilus_list_view_select_first;
- nautilus_files_view_class->set_selection = nautilus_list_view_set_selection;
- nautilus_files_view_class->invert_selection = nautilus_list_view_invert_selection;
- nautilus_files_view_class->compare_files = nautilus_list_view_compare_files;
- nautilus_files_view_class->sort_directories_first_changed = nautilus_list_view_sort_directories_first_changed;
- nautilus_files_view_class->end_file_changes = nautilus_list_view_end_file_changes;
- nautilus_files_view_class->get_view_id = nautilus_list_view_get_id;
- nautilus_files_view_class->get_first_visible_file = nautilus_list_view_get_first_visible_file;
- nautilus_files_view_class->scroll_to_file = list_view_scroll_to_file;
- nautilus_files_view_class->compute_rename_popover_pointing_to = nautilus_list_view_compute_rename_popover_pointing_to;
- nautilus_files_view_class->reveal_for_selection_context_menu = nautilus_list_view_reveal_for_selection_context_menu;
- nautilus_files_view_class->preview_selection_event = nautilus_list_view_preview_selection_event;
+ G_OBJECT_CLASS (nautilus_list_view_parent_class)->finalize (object);
}
static void
-nautilus_list_view_init (NautilusListView *list_view)
+nautilus_list_view_class_init (NautilusListViewClass *klass)
{
- GActionGroup *view_action_group;
- GdkClipboard *clipboard;
-
- list_view->details = g_new0 (NautilusListViewDetails, 1);
-
- /* ensure that the zoom level is always set before settings up the tree view columns */
- list_view->details->zoom_level = get_default_zoom_level ();
-
- create_and_set_up_tree_view (list_view);
-
- gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (list_view)),
- "nautilus-list-view");
-
- list_view->details->columns_popover = gtk_popover_new ();
- gtk_widget_set_parent (list_view->details->columns_popover,
- GTK_WIDGET (list_view));
- g_signal_connect (list_view->details->columns_popover, "destroy", G_CALLBACK (gtk_widget_unparent), NULL);
-
- list_view->details->columns_popover_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
- gtk_widget_set_margin_top (list_view->details->columns_popover_box, 6);
- gtk_widget_set_margin_bottom (list_view->details->columns_popover_box, 6);
- gtk_widget_set_margin_start (list_view->details->columns_popover_box, 6);
- gtk_widget_set_margin_end (list_view->details->columns_popover_box, 6);
- gtk_popover_set_child (GTK_POPOVER (list_view->details->columns_popover),
- list_view->details->columns_popover_box);
-
- g_signal_connect_swapped (nautilus_preferences,
- "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
- G_CALLBACK (default_sort_order_changed_callback),
- list_view);
- g_signal_connect_swapped (nautilus_preferences,
- "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
- G_CALLBACK (default_sort_order_changed_callback),
- list_view);
- g_signal_connect_swapped (nautilus_list_view_preferences,
- "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS,
- G_CALLBACK (default_visible_columns_changed_callback),
- list_view);
- g_signal_connect_swapped (nautilus_list_view_preferences,
- "changed::" NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER,
- G_CALLBACK (default_column_order_changed_callback),
- list_view);
-
- /* React to clipboard changes */
- clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
- g_signal_connect_object (clipboard, "changed",
- G_CALLBACK (on_clipboard_owner_changed), list_view,
- 0);
-
- nautilus_list_view_click_policy_changed (NAUTILUS_FILES_VIEW (list_view));
-
- nautilus_list_view_set_zoom_level (list_view, get_default_zoom_level ());
-
- list_view->details->hover_path = NULL;
-
- view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (list_view));
- g_action_map_add_action_entries (G_ACTION_MAP (view_action_group),
- list_view_entries,
- G_N_ELEMENTS (list_view_entries),
- list_view);
- /* 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 (list_view)),
- "zoom-to-level", g_variant_new_int32 (get_default_zoom_level ()));
+ 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);
- list_view->details->regex = g_regex_new ("\\R+", 0, G_REGEX_MATCH_NEWLINE_ANY, NULL);
+ object_class->dispose = nautilus_list_view_dispose;
+ object_class->finalize = nautilus_list_view_finalize;
- list_view->details->starred_cancellable = g_cancellable_new ();
+ 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->sort_directories_first_changed = real_sort_directories_first_changed;
+ files_view_class->get_view_id = real_get_view_id;
+ files_view_class->restore_standard_zoom_level = real_restore_standard_zoom_level;
+ files_view_class->is_zoom_level_default = real_is_zoom_level_default;
- g_signal_connect (nautilus_tag_manager_get (),
- "starred-changed",
- (GCallback) on_starred_files_changed,
- list_view);
+ 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;
}
-NautilusFilesView *
+NautilusListView *
nautilus_list_view_new (NautilusWindowSlot *slot)
{
return g_object_new (NAUTILUS_TYPE_LIST_VIEW,
diff --git a/src/nautilus-list-view.h b/src/nautilus-list-view.h
index 7e19621e81d41f856210bb8e2ab4708d27c0b9db..8c2133648ed8625ce20b85e2f9fa24c9738ff732 100644
--- a/src/nautilus-list-view.h
+++ b/src/nautilus-list-view.h
@@ -1,40 +1,22 @@
-
-/* fm-list-view.h - interface for list view of directory.
-
- Copyright (C) 2000 Eazel, Inc.
- Copyright (C) 2001 Anders Carlsson
-
- The Gnome Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- The Gnome Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the Gnome Library; see the file COPYING.LIB. If not,
- see .
-
- Authors: John Sullivan
- Anders Carlsson
-*/
+/*
+ * Copyright (C) 2000 Eazel, Inc.
+ * Copyright (C) 2001, 2002 Anders Carlsson
+ * Copyright (C) 2022 GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
#pragma once
-#include "nautilus-files-view.h"
+#include "nautilus-list-base.h"
+#include "nautilus-window-slot.h"
+
+G_BEGIN_DECLS
-#define NAUTILUS_TYPE_LIST_VIEW (nautilus_list_view_get_type ())
-G_DECLARE_FINAL_TYPE (NautilusListView, nautilus_list_view, NAUTILUS, LIST_VIEW, NautilusFilesView)
+#define NAUTILUS_TYPE_LIST_VIEW (nautilus_list_view_get_type())
-typedef struct NautilusListViewDetails NautilusListViewDetails;
+G_DECLARE_FINAL_TYPE (NautilusListView, nautilus_list_view, NAUTILUS, LIST_VIEW, NautilusListBase)
-struct _NautilusListView
-{
- NautilusFilesView parent_instance;
- NautilusListViewDetails *details;
-};
+NautilusListView *nautilus_list_view_new (NautilusWindowSlot *slot);
-NautilusFilesView * nautilus_list_view_new (NautilusWindowSlot *slot);
\ No newline at end of file
+G_END_DECLS
diff --git a/src/nautilus-name-cell.c b/src/nautilus-name-cell.c
new file mode 100644
index 0000000000000000000000000000000000000000..daa6308a7deaf8df1e46412d29f9321c1ecdcebf
--- /dev/null
+++ b/src/nautilus-name-cell.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "nautilus-name-cell.h"
+#include "nautilus-file-utilities.h"
+
+struct _NautilusNameCell
+{
+ NautilusViewCell parent_instance;
+
+ GSignalGroup *item_signal_group;
+
+ GQuark path_attribute_q;
+ GFile *file_path_base_location;
+
+ GtkWidget *fixed_height_box;
+ GtkWidget *icon;
+ GtkWidget *label;
+ GtkWidget *snippet;
+ GtkWidget *path;
+
+ gboolean show_snippet;
+};
+
+G_DEFINE_TYPE (NautilusNameCell, nautilus_name_cell, NAUTILUS_TYPE_VIEW_CELL)
+
+static gchar *
+get_path_text (NautilusFile *file,
+ GQuark path_attribute_q,
+ GFile *base_location)
+{
+ g_autofree gchar *path = NULL;
+ g_autoptr (GFile) dir_location = NULL;
+ g_autoptr (GFile) home_location = g_file_new_for_path (g_get_home_dir ());
+ GFile *relative_location_base;
+
+ if (path_attribute_q == 0)
+ {
+ return NULL;
+ }
+
+ path = nautilus_file_get_string_attribute_q (file, path_attribute_q);
+ dir_location = g_file_new_for_commandline_arg (path);
+
+ if (base_location != NULL && g_file_equal (base_location, dir_location))
+ {
+ /* Only occurs when search result is
+ * a direct child of the base location
+ */
+ return NULL;
+ }
+
+ if (g_file_equal (dir_location, home_location))
+ {
+ return nautilus_compute_title_for_location (home_location);
+ }
+
+ relative_location_base = base_location;
+ if (relative_location_base == NULL)
+ {
+ /* Only occurs in Recent, Starred and Trash. */
+ relative_location_base = home_location;
+ }
+
+ if (g_file_has_prefix (dir_location, relative_location_base))
+ {
+ g_autofree gchar *relative_path = NULL;
+
+ relative_path = g_file_get_relative_path (relative_location_base, dir_location);
+ return g_filename_display_name (relative_path);
+ }
+
+ return g_file_get_path (dir_location);
+}
+
+static gchar *
+get_fts_snippet (NautilusFile *file)
+{
+ const gchar *snippet;
+ g_autoptr (GRegex) regex = NULL;
+
+ snippet = nautilus_file_get_search_fts_snippet (file);
+ if (snippet == NULL)
+ {
+ return NULL;
+ }
+
+ /* Flatten the text by replacing new lines with spaces */
+ regex = g_regex_new ("\\R+", 0, G_REGEX_MATCH_NEWLINE_ANY, NULL);
+ return g_regex_replace (regex,
+ snippet,
+ -1,
+ 0,
+ " ",
+ G_REGEX_MATCH_NEWLINE_ANY,
+ NULL);
+}
+
+static void
+update_labels (NautilusNameCell *self)
+{
+ NautilusViewItem *item;
+ NautilusFile *file;
+ g_autofree gchar *display_name = NULL;
+ g_autofree gchar *path_text = NULL;
+ g_autofree gchar *fts_snippet = NULL;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_get_file (item);
+
+ display_name = nautilus_file_get_display_name (file);
+ path_text = get_path_text (file,
+ self->path_attribute_q,
+ self->file_path_base_location);
+ if (self->show_snippet)
+ {
+ fts_snippet = get_fts_snippet (file);
+ }
+
+ gtk_label_set_text (GTK_LABEL (self->label), display_name);
+ gtk_label_set_text (GTK_LABEL (self->path), path_text);
+ gtk_label_set_text (GTK_LABEL (self->snippet), fts_snippet);
+
+ gtk_widget_set_visible (self->path, (path_text != NULL));
+ gtk_widget_set_visible (self->snippet, (fts_snippet != NULL));
+}
+
+static void
+update_icon (NautilusNameCell *self)
+{
+ NautilusFileIconFlags flags;
+ g_autoptr (GdkPaintable) icon_paintable = NULL;
+ GtkStyleContext *style_context;
+ NautilusViewItem *item;
+ NautilusFile *file;
+ guint icon_size;
+ int icon_height;
+ int extra_margin;
+ g_autofree gchar *thumbnail_path = NULL;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+
+ file = nautilus_view_item_get_file (item);
+ icon_size = nautilus_view_item_get_icon_size (item);
+ flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
+ NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE |
+ NAUTILUS_FILE_ICON_FLAGS_USE_EMBLEMS |
+ NAUTILUS_FILE_ICON_FLAGS_USE_ONE_EMBLEM;
+
+ icon_paintable = nautilus_file_get_icon_paintable (file, icon_size, 1, flags);
+ gtk_picture_set_paintable (GTK_PICTURE (self->icon), icon_paintable);
+
+ /* Set the same width for all icons regardless of aspect ratio.
+ * Don't set the width here because it would get GtkPicture w4h confused.
+ */
+ gtk_widget_set_size_request (self->fixed_height_box, icon_size, -1);
+
+ /* Give all items the same minimum width. This cannot be done by setting the
+ * width request directly, as above, because it would get mess up with
+ * height for width calculations.
+ *
+ * Instead we must add margins on both sides of the icon which, summed up
+ * with the icon's actual width, equal the desired item width. */
+ icon_height = gdk_paintable_get_intrinsic_height (icon_paintable);
+ extra_margin = (icon_size - icon_height) / 2;
+ gtk_widget_set_margin_top (self->fixed_height_box, extra_margin);
+ gtk_widget_set_margin_bottom (self->fixed_height_box, extra_margin);
+
+ style_context = gtk_widget_get_style_context (self->icon);
+ thumbnail_path = nautilus_file_get_thumbnail_path (file);
+ if (icon_size >= NAUTILUS_THUMBNAIL_MINIMUM_ICON_SIZE &&
+ thumbnail_path != NULL &&
+ nautilus_file_should_show_thumbnail (file))
+ {
+ gtk_style_context_add_class (style_context, "thumbnail");
+ }
+ else
+ {
+ gtk_style_context_remove_class (style_context, "thumbnail");
+ }
+}
+
+static void
+on_file_changed (NautilusNameCell *self)
+{
+ update_icon (self);
+ update_labels (self);
+}
+
+static void
+on_item_size_changed (NautilusNameCell *self)
+{
+ update_icon (self);
+}
+
+static void
+on_item_is_cut_changed (NautilusNameCell *self)
+{
+ gboolean is_cut;
+
+ g_object_get (nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self)),
+ "is-cut", &is_cut,
+ NULL);
+ if (is_cut)
+ {
+ gtk_widget_add_css_class (self->icon, "cut");
+ }
+ else
+ {
+ gtk_widget_remove_css_class (self->icon, "cut");
+ }
+}
+
+static void
+nautilus_name_cell_init (NautilusNameCell *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);
+ 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);
+}
+
+static void
+nautilus_name_cell_finalize (GObject *object)
+{
+ NautilusNameCell *self = (NautilusNameCell *) object;
+
+ g_clear_object (&self->item_signal_group);
+ g_clear_object (&self->file_path_base_location);
+ G_OBJECT_CLASS (nautilus_name_cell_parent_class)->finalize (object);
+}
+
+static void
+nautilus_name_cell_class_init (NautilusNameCellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = nautilus_name_cell_finalize;
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/ui/nautilus-name-cell.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, NautilusNameCell, fixed_height_box);
+ gtk_widget_class_bind_template_child (widget_class, NautilusNameCell, icon);
+ gtk_widget_class_bind_template_child (widget_class, NautilusNameCell, label);
+ gtk_widget_class_bind_template_child (widget_class, NautilusNameCell, snippet);
+ gtk_widget_class_bind_template_child (widget_class, NautilusNameCell, path);
+}
+
+NautilusViewCell *
+nautilus_name_cell_new (NautilusListBase *view)
+{
+ return NAUTILUS_VIEW_CELL (g_object_new (NAUTILUS_TYPE_NAME_CELL,
+ "view", view,
+ NULL));
+}
+
+void
+nautilus_name_cell_set_path (NautilusNameCell *self,
+ GQuark path_attribute_q,
+ GFile *base_location)
+{
+ self->path_attribute_q = path_attribute_q;
+ g_set_object (&self->file_path_base_location, base_location);
+}
+
+void
+nautilus_name_cell_show_snippet (NautilusNameCell *self)
+{
+ self->show_snippet = TRUE;
+}
diff --git a/src/nautilus-name-cell.h b/src/nautilus-name-cell.h
new file mode 100644
index 0000000000000000000000000000000000000000..62862cdf564c774671ae9ab9c0963d4f531f83e5
--- /dev/null
+++ b/src/nautilus-name-cell.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 António Fernandes
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "nautilus-view-cell.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_NAME_CELL (nautilus_name_cell_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusNameCell, nautilus_name_cell, NAUTILUS, NAME_CELL, NautilusViewCell)
+
+NautilusViewCell * nautilus_name_cell_new (NautilusListBase *view);
+void nautilus_name_cell_set_path (NautilusNameCell *self,
+ GQuark path_attribute_q,
+ GFile *base_location);
+void nautilus_name_cell_show_snippet (NautilusNameCell *self);
+
+G_END_DECLS
diff --git a/src/nautilus-properties-window.c b/src/nautilus-properties-window.c
index 6050683f2816a79ed4751d3d488b79125893d063..b3bfa1991dd5ab7aeddf0b4e7f9c9261fb822511 100644
--- a/src/nautilus-properties-window.c
+++ b/src/nautilus-properties-window.c
@@ -414,13 +414,13 @@ get_image_for_properties_window (NautilusPropertiesWindow *self,
if (!icon)
{
- icon = nautilus_file_get_icon (file, NAUTILUS_GRID_ICON_SIZE_STANDARD, icon_scale,
+ icon = nautilus_file_get_icon (file, NAUTILUS_GRID_ICON_SIZE_MEDIUM, icon_scale,
NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
NAUTILUS_FILE_ICON_FLAGS_IGNORE_VISITING);
}
else
{
- new_icon = nautilus_file_get_icon (file, NAUTILUS_GRID_ICON_SIZE_STANDARD, icon_scale,
+ new_icon = nautilus_file_get_icon (file, NAUTILUS_GRID_ICON_SIZE_MEDIUM, icon_scale,
NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
NAUTILUS_FILE_ICON_FLAGS_IGNORE_VISITING);
if (!new_icon || new_icon != icon)
@@ -436,7 +436,7 @@ get_image_for_properties_window (NautilusPropertiesWindow *self,
{
g_autoptr (GIcon) gicon = g_themed_icon_new ("text-x-generic");
- icon = nautilus_icon_info_lookup (gicon, NAUTILUS_GRID_ICON_SIZE_STANDARD, icon_scale);
+ icon = nautilus_icon_info_lookup (gicon, NAUTILUS_GRID_ICON_SIZE_MEDIUM, icon_scale);
}
if (icon_name != NULL)
diff --git a/src/nautilus-star-cell.c b/src/nautilus-star-cell.c
new file mode 100644
index 0000000000000000000000000000000000000000..a47a6b2ffeb9d2350331170b0aa652c2727e18d8
--- /dev/null
+++ b/src/nautilus-star-cell.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2022 António Fernandes
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "nautilus-star-cell.h"
+#include "nautilus-tag-manager.h"
+
+struct _NautilusStarCell
+{
+ NautilusViewCell parent_instance;
+
+ GSignalGroup *item_signal_group;
+
+ GtkImage *star;
+};
+
+G_DEFINE_TYPE (NautilusStarCell, nautilus_star_cell, NAUTILUS_TYPE_VIEW_CELL)
+
+static void
+on_star_click_released (GtkGestureClick *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
+ NautilusStarCell *self = user_data;
+ NautilusTagManager *tag_manager = nautilus_tag_manager_get ();
+ NautilusViewItem *item;
+ NautilusFile *file;
+ g_autofree gchar *uri = NULL;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_get_file (item);
+ uri = nautilus_file_get_uri (file);
+
+ if (nautilus_tag_manager_file_is_starred (tag_manager, uri))
+ {
+ nautilus_tag_manager_unstar_files (tag_manager,
+ G_OBJECT (item),
+ &(GList){ file, NULL },
+ NULL,
+ NULL);
+ gtk_widget_remove_css_class (GTK_WIDGET (self->star), "added");
+ }
+ else
+ {
+ nautilus_tag_manager_star_files (tag_manager,
+ G_OBJECT (item),
+ &(GList){ file, NULL },
+ NULL,
+ NULL);
+ gtk_widget_add_css_class (GTK_WIDGET (self->star), "added");
+ }
+
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static void
+update_star (GtkImage *star,
+ NautilusFile *file)
+{
+ gboolean is_starred;
+ g_autofree gchar *file_uri = NULL;
+
+ g_return_if_fail (NAUTILUS_IS_FILE (file));
+
+ file_uri = nautilus_file_get_uri (file);
+ is_starred = nautilus_tag_manager_file_is_starred (nautilus_tag_manager_get (),
+ file_uri);
+
+ gtk_image_set_from_icon_name (star, is_starred ? "starred-symbolic" : "non-starred-symbolic");
+}
+
+static void
+on_file_changed (NautilusStarCell *self)
+{
+ NautilusViewItem *item;
+ NautilusFile *file;
+ g_autofree gchar *string = NULL;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ g_return_if_fail (item != NULL);
+ file = nautilus_view_item_get_file (item);
+
+ update_star (self->star, file);
+}
+
+static void
+on_starred_changed (NautilusTagManager *tag_manager,
+ GList *changed_files,
+ gpointer user_data)
+{
+ NautilusStarCell *self = user_data;
+ NautilusViewItem *item;
+ NautilusFile *file;
+
+ item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
+ if (item == NULL)
+ {
+ return;
+ }
+
+ file = nautilus_view_item_get_file (item);
+ if (g_list_find (changed_files, file))
+ {
+ update_star (self->star, file);
+ }
+}
+
+static void
+nautilus_star_cell_init (NautilusStarCell *self)
+{
+ GtkWidget *star;
+ GtkGesture *gesture;
+
+ /* Create star icon */
+ star = gtk_image_new ();
+ gtk_widget_set_halign (star, GTK_ALIGN_END);
+ gtk_widget_set_valign (star, GTK_ALIGN_CENTER);
+ gtk_widget_add_css_class (star, "dim-label");
+ gtk_widget_add_css_class (star, "star");
+ adw_bin_set_child (ADW_BIN (self), star);
+ self->star = GTK_IMAGE (star);
+
+ /* Make it clickable */
+ gesture = gtk_gesture_click_new ();
+ gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_PRIMARY);
+ g_signal_connect (gesture, "released", G_CALLBACK (on_star_click_released), self);
+ gtk_widget_add_controller (star, GTK_EVENT_CONTROLLER (gesture));
+
+ /* Update on tag changes */
+ g_signal_connect_object (nautilus_tag_manager_get (), "starred-changed",
+ G_CALLBACK (on_starred_changed), self, 0);
+
+ /* Connect automatically to an item. */
+ self->item_signal_group = g_signal_group_new (NAUTILUS_TYPE_VIEW_ITEM);
+ 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);
+}
+
+static void
+nautilus_star_cell_finalize (GObject *object)
+{
+ NautilusStarCell *self = (NautilusStarCell *) object;
+
+ g_object_unref (self->item_signal_group);
+ G_OBJECT_CLASS (nautilus_star_cell_parent_class)->finalize (object);
+}
+
+static void
+nautilus_star_cell_class_init (NautilusStarCellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = nautilus_star_cell_finalize;
+}
+
+NautilusViewCell *
+nautilus_star_cell_new (NautilusListBase *view)
+{
+ return NAUTILUS_VIEW_CELL (g_object_new (NAUTILUS_TYPE_STAR_CELL,
+ "view", view,
+ NULL));
+}
diff --git a/src/nautilus-star-cell.h b/src/nautilus-star-cell.h
new file mode 100644
index 0000000000000000000000000000000000000000..415a745143fc1ad723e36d599133af3d8ec482b9
--- /dev/null
+++ b/src/nautilus-star-cell.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 António Fernandes
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "nautilus-view-cell.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_STAR_CELL (nautilus_star_cell_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusStarCell, nautilus_star_cell, NAUTILUS, STAR_CELL, NautilusViewCell)
+
+NautilusViewCell * nautilus_star_cell_new (NautilusListBase *view);
+
+G_END_DECLS
diff --git a/src/nautilus-tree-view-drag-dest.c b/src/nautilus-tree-view-drag-dest.c
deleted file mode 100644
index ffe89748008ffe5a627316f22db83d4b447bd7d6..0000000000000000000000000000000000000000
--- a/src/nautilus-tree-view-drag-dest.c
+++ /dev/null
@@ -1,1305 +0,0 @@
-/*
- * Nautilus
- *
- * Copyright (C) 2002 Sun Microsystems, Inc.
- *
- * Nautilus is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * Nautilus is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, see .
- *
- * Author: Dave Camp
- * XDS support: Benedikt Meurer (adapted by Amos Brocco )
- */
-
-/* nautilus-tree-view-drag-dest.c: Handles drag and drop for treeviews which
- * contain a hierarchy of files
- */
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-#include
-
-#include "nautilus-tree-view-drag-dest.h"
-
-#include "nautilus-dnd.h"
-#include "nautilus-file-changes-queue.h"
-#include "nautilus-global-preferences.h"
-
-#include
-
-#include
-#include
-
-#define DEBUG_FLAG NAUTILUS_DEBUG_LIST_VIEW
-#include "nautilus-debug.h"
-
-#define AUTO_SCROLL_MARGIN 20
-#define HOVER_EXPAND_TIMEOUT 1
-
-struct _NautilusTreeViewDragDestDetails
-{
- GtkTreeView *tree_view;
-
- gboolean drop_occurred;
-
- gboolean have_drag_data;
- guint drag_type;
- GtkSelectionData *drag_data;
- GList *drag_list;
-
- guint hover_id;
- gulong highlight_id;
- guint scroll_id;
- guint expand_id;
-
- char *direct_save_uri;
- char *target_uri;
-};
-
-enum
-{
- GET_ROOT_URI,
- GET_FILE_FOR_PATH,
- MOVE_COPY_ITEMS,
- HANDLE_NETSCAPE_URL,
- HANDLE_URI_LIST,
- HANDLE_TEXT,
- HANDLE_RAW,
- HANDLE_HOVER,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL];
-
-G_DEFINE_TYPE (NautilusTreeViewDragDest, nautilus_tree_view_drag_dest,
- G_TYPE_OBJECT);
-
-static const GtkTargetEntry drag_types [] =
-{
- { NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST },
- /* prefer "_NETSCAPE_URL" over "text/uri-list" to satisfy web browsers. */
- { NAUTILUS_ICON_DND_NETSCAPE_URL_TYPE, 0, NAUTILUS_ICON_DND_NETSCAPE_URL },
- { NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST },
- { NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, 0, NAUTILUS_ICON_DND_XDNDDIRECTSAVE }, /* XDS Protocol Type */
- { NAUTILUS_ICON_DND_RAW_TYPE, 0, NAUTILUS_ICON_DND_RAW }
-};
-
-
-static void
-gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
-{
- GdkRectangle visible_rect;
- GtkAdjustment *vadjustment;
- GdkDisplay *display;
- GdkSeat *seat;
- GdkDevice *pointer;
- GdkWindow *window;
- int y;
- int offset;
- float value;
-
- window = gtk_tree_view_get_bin_window (tree_view);
- vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
-
- display = gtk_widget_get_display (GTK_WIDGET (tree_view));
- seat = gdk_display_get_default_seat (display);
- pointer = gdk_seat_get_pointer (seat);
- gdk_window_get_device_position (window, pointer,
- NULL, &y, NULL);
-
- y += gtk_adjustment_get_value (vadjustment);
-
- gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
-
- offset = y - (visible_rect.y + 2 * AUTO_SCROLL_MARGIN);
- if (offset > 0)
- {
- offset = y - (visible_rect.y + visible_rect.height - 2 * AUTO_SCROLL_MARGIN);
- if (offset < 0)
- {
- return;
- }
- }
-
- value = CLAMP (gtk_adjustment_get_value (vadjustment) + offset, 0.0,
- gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
- gtk_adjustment_set_value (vadjustment, value);
-}
-
-static int
-scroll_timeout (gpointer data)
-{
- GtkTreeView *tree_view = GTK_TREE_VIEW (data);
-
- gtk_tree_view_vertical_autoscroll (tree_view);
-
- return TRUE;
-}
-
-static void
-remove_scroll_timeout (NautilusTreeViewDragDest *dest)
-{
- if (dest->details->scroll_id)
- {
- g_source_remove (dest->details->scroll_id);
- dest->details->scroll_id = 0;
- }
-}
-
-static int
-expand_timeout (gpointer data)
-{
- GtkTreeView *tree_view;
- GtkTreePath *drop_path;
-
- tree_view = GTK_TREE_VIEW (data);
-
- gtk_tree_view_get_drag_dest_row (tree_view, &drop_path, NULL);
-
- if (drop_path)
- {
- gtk_tree_view_expand_row (tree_view, drop_path, FALSE);
- gtk_tree_path_free (drop_path);
- }
-
- return FALSE;
-}
-
-static void
-remove_expand_timer (NautilusTreeViewDragDest *dest)
-{
- if (dest->details->expand_id)
- {
- g_source_remove (dest->details->expand_id);
- dest->details->expand_id = 0;
- }
-}
-
-static void
-set_drag_dest_row (NautilusTreeViewDragDest *dest,
- GtkTreePath *path)
-{
- if (path)
- {
- gtk_tree_view_set_drag_dest_row
- (dest->details->tree_view,
- path,
- GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
- }
- else
- {
- gtk_tree_view_set_drag_dest_row (dest->details->tree_view,
- NULL,
- 0);
- }
-}
-
-static void
-clear_drag_dest_row (NautilusTreeViewDragDest *dest)
-{
- gtk_tree_view_set_drag_dest_row (dest->details->tree_view, NULL, 0);
-}
-
-static gboolean
-get_drag_data (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- guint32 time)
-{
- GdkAtom target;
-
- target = gtk_drag_dest_find_target (GTK_WIDGET (dest->details->tree_view),
- context,
- NULL);
-
- if (target == GDK_NONE)
- {
- return FALSE;
- }
-
- if (target == gdk_atom_intern (NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE) &&
- !dest->details->drop_occurred)
- {
- dest->details->drag_type = NAUTILUS_ICON_DND_XDNDDIRECTSAVE;
- dest->details->have_drag_data = TRUE;
- return TRUE;
- }
-
- gtk_drag_get_data (GTK_WIDGET (dest->details->tree_view),
- context, target, time);
-
- return TRUE;
-}
-
-static void
-remove_hover_timer (NautilusTreeViewDragDest *dest)
-{
- if (dest->details->hover_id != 0)
- {
- g_source_remove (dest->details->hover_id);
- dest->details->hover_id = 0;
- }
-}
-
-static void
-free_drag_data (NautilusTreeViewDragDest *dest)
-{
- dest->details->have_drag_data = FALSE;
-
- if (dest->details->drag_data)
- {
- gtk_selection_data_free (dest->details->drag_data);
- dest->details->drag_data = NULL;
- }
-
- if (dest->details->drag_list)
- {
- nautilus_drag_destroy_selection_list (dest->details->drag_list);
- dest->details->drag_list = NULL;
- }
-
- g_free (dest->details->direct_save_uri);
- dest->details->direct_save_uri = NULL;
-
- g_free (dest->details->target_uri);
- dest->details->target_uri = NULL;
-
- remove_hover_timer (dest);
- remove_expand_timer (dest);
-}
-
-static gboolean
-hover_timer (gpointer user_data)
-{
- NautilusTreeViewDragDest *dest = user_data;
-
- dest->details->hover_id = 0;
-
- g_signal_emit (dest, signals[HANDLE_HOVER], 0, dest->details->target_uri);
-
- return FALSE;
-}
-
-static void
-check_hover_timer (NautilusTreeViewDragDest *dest,
- const char *uri)
-{
- if (g_strcmp0 (uri, dest->details->target_uri) == 0)
- {
- return;
- }
- remove_hover_timer (dest);
-
- g_clear_pointer (&dest->details->target_uri, g_free);
-
- if (uri != NULL)
- {
- dest->details->target_uri = g_strdup (uri);
- dest->details->hover_id = g_timeout_add (HOVER_TIMEOUT, hover_timer, dest);
- }
-}
-
-static void
-check_expand_timer (NautilusTreeViewDragDest *dest,
- GtkTreePath *drop_path,
- GtkTreePath *old_drop_path)
-{
- GtkTreeModel *model;
- GtkTreeIter drop_iter;
-
- model = gtk_tree_view_get_model (dest->details->tree_view);
-
- if (drop_path == NULL ||
- (old_drop_path != NULL && gtk_tree_path_compare (old_drop_path, drop_path) != 0))
- {
- remove_expand_timer (dest);
- }
-
- if (dest->details->expand_id == 0 &&
- drop_path != NULL)
- {
- gtk_tree_model_get_iter (model, &drop_iter, drop_path);
- if (gtk_tree_model_iter_has_child (model, &drop_iter))
- {
- dest->details->expand_id =
- g_timeout_add_seconds (HOVER_EXPAND_TIMEOUT,
- expand_timeout,
- dest->details->tree_view);
- }
- }
-}
-
-static char *
-get_root_uri (NautilusTreeViewDragDest *dest)
-{
- char *uri;
-
- g_signal_emit (dest, signals[GET_ROOT_URI], 0, &uri);
-
- return uri;
-}
-
-static NautilusFile *
-file_for_path (NautilusTreeViewDragDest *dest,
- GtkTreePath *path)
-{
- NautilusFile *file;
- char *uri;
-
- if (path)
- {
- g_signal_emit (dest, signals[GET_FILE_FOR_PATH], 0, path, &file);
- }
- else
- {
- uri = get_root_uri (dest);
-
- file = NULL;
- if (uri != NULL)
- {
- file = nautilus_file_get_by_uri (uri);
- }
-
- g_free (uri);
- }
-
- return file;
-}
-
-static char *
-get_drop_target_uri_for_path (NautilusTreeViewDragDest *dest,
- GtkTreePath *path)
-{
- NautilusFile *file;
- char *target = NULL;
- gboolean can;
-
- file = file_for_path (dest, path);
- if (file == NULL)
- {
- return NULL;
- }
- can = nautilus_drag_can_accept_info (file,
- dest->details->drag_type,
- dest->details->drag_list);
- if (can)
- {
- target = nautilus_file_get_uri (file);
- }
- nautilus_file_unref (file);
-
- return target;
-}
-
-static void
-check_hover_expand_timer (NautilusTreeViewDragDest *dest,
- GtkTreePath *path,
- GtkTreePath *drop_path,
- GtkTreePath *old_drop_path)
-{
- gboolean use_tree = g_settings_get_boolean (nautilus_list_view_preferences,
- NAUTILUS_PREFERENCES_LIST_VIEW_USE_TREE);
-
- if (use_tree)
- {
- check_expand_timer (dest, drop_path, old_drop_path);
- }
- else
- {
- char *uri;
- uri = get_drop_target_uri_for_path (dest, path);
- check_hover_timer (dest, uri);
- g_free (uri);
- }
-}
-
-static GtkTreePath *
-get_drop_path (NautilusTreeViewDragDest *dest,
- GtkTreePath *path)
-{
- NautilusFile *file;
- GtkTreePath *ret;
-
- if (!path || !dest->details->have_drag_data)
- {
- return NULL;
- }
-
- ret = gtk_tree_path_copy (path);
- file = file_for_path (dest, ret);
-
- /* Go up the tree until we find a file that can accept a drop */
- while (file == NULL /* dummy row */ ||
- !nautilus_drag_can_accept_info (file,
- dest->details->drag_type,
- dest->details->drag_list))
- {
- if (gtk_tree_path_get_depth (ret) == 1)
- {
- gtk_tree_path_free (ret);
- ret = NULL;
- break;
- }
- else
- {
- gtk_tree_path_up (ret);
-
- nautilus_file_unref (file);
- file = file_for_path (dest, ret);
- }
- }
- nautilus_file_unref (file);
-
- return ret;
-}
-
-static guint
-get_drop_action (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- GtkTreePath *path)
-{
- char *drop_target;
- int action;
-
- if (!dest->details->have_drag_data ||
- (dest->details->drag_type == NAUTILUS_ICON_DND_GNOME_ICON_LIST &&
- dest->details->drag_list == NULL))
- {
- return 0;
- }
-
- drop_target = get_drop_target_uri_for_path (dest, path);
- if (drop_target == NULL)
- {
- return 0;
- }
-
- action = 0;
- switch (dest->details->drag_type)
- {
- case NAUTILUS_ICON_DND_GNOME_ICON_LIST:
- {
- nautilus_drag_default_drop_action_for_icons
- (context,
- drop_target,
- dest->details->drag_list,
- 0,
- &action);
- }
- break;
-
- case NAUTILUS_ICON_DND_NETSCAPE_URL:
- {
- action = nautilus_drag_default_drop_action_for_netscape_url (context);
- }
- break;
-
- case NAUTILUS_ICON_DND_URI_LIST:
- {
- action = gdk_drag_context_get_suggested_action (context);
- }
- break;
-
- case NAUTILUS_ICON_DND_TEXT:
- case NAUTILUS_ICON_DND_RAW:
- case NAUTILUS_ICON_DND_XDNDDIRECTSAVE:
- {
- action = GDK_ACTION_COPY;
- }
- break;
- }
-
- g_free (drop_target);
-
- return action;
-}
-
-static gboolean
-drag_motion_callback (GtkWidget *widget,
- GdkDragContext *context,
- int x,
- int y,
- guint32 time,
- gpointer data)
-{
- NautilusTreeViewDragDest *dest;
- GtkTreePath *path;
- GtkTreePath *drop_path, *old_drop_path;
- GtkTreeViewDropPosition pos;
- int bin_y;
- guint action;
- gboolean res = TRUE;
-
- dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data);
-
- gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
- x, y, &path, &pos);
- if (pos == GTK_TREE_VIEW_DROP_BEFORE ||
- pos == GTK_TREE_VIEW_DROP_AFTER)
- {
- gtk_tree_path_free (path);
- path = NULL;
- }
-
- if (!dest->details->have_drag_data)
- {
- res = get_drag_data (dest, context, time);
- }
-
- if (!res)
- {
- return FALSE;
- }
-
- drop_path = get_drop_path (dest, path);
-
- action = 0;
- gtk_tree_view_convert_bin_window_to_widget_coords (GTK_TREE_VIEW (widget),
- 0, 0,
- NULL, &bin_y);
- if (bin_y <= y)
- {
- /* ignore drags on the header */
- action = get_drop_action (dest, context, drop_path);
- }
-
- gtk_tree_view_get_drag_dest_row (GTK_TREE_VIEW (widget), &old_drop_path,
- NULL);
-
- if (action)
- {
- set_drag_dest_row (dest, drop_path);
- check_hover_expand_timer (dest, path, drop_path, old_drop_path);
- }
- else
- {
- clear_drag_dest_row (dest);
- remove_hover_timer (dest);
- remove_expand_timer (dest);
- }
-
- if (path)
- {
- gtk_tree_path_free (path);
- }
-
- if (drop_path)
- {
- gtk_tree_path_free (drop_path);
- }
-
- if (old_drop_path)
- {
- gtk_tree_path_free (old_drop_path);
- }
-
- if (dest->details->scroll_id == 0)
- {
- dest->details->scroll_id =
- g_timeout_add (150,
- scroll_timeout,
- dest->details->tree_view);
- }
-
- gdk_drag_status (context, action, time);
-
- return TRUE;
-}
-
-static void
-drag_leave_callback (GtkWidget *widget,
- GdkDragContext *context,
- guint32 time,
- gpointer data)
-{
- NautilusTreeViewDragDest *dest;
-
- dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data);
-
- clear_drag_dest_row (dest);
-
- free_drag_data (dest);
-
- remove_scroll_timeout (dest);
-}
-
-static char *
-get_drop_target_uri_at_pos (NautilusTreeViewDragDest *dest,
- int x,
- int y)
-{
- char *drop_target = NULL;
- GtkTreePath *path;
- GtkTreePath *drop_path;
- GtkTreeViewDropPosition pos;
-
- gtk_tree_view_get_dest_row_at_pos (dest->details->tree_view, x, y,
- &path, &pos);
- if (pos == GTK_TREE_VIEW_DROP_BEFORE ||
- pos == GTK_TREE_VIEW_DROP_AFTER)
- {
- gtk_tree_path_free (path);
- path = NULL;
- }
-
- drop_path = get_drop_path (dest, path);
-
- drop_target = get_drop_target_uri_for_path (dest, drop_path);
-
- if (path != NULL)
- {
- gtk_tree_path_free (path);
- }
-
- if (drop_path != NULL)
- {
- gtk_tree_path_free (drop_path);
- }
-
- return drop_target;
-}
-
-static void
-receive_uris (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- GList *source_uris,
- int x,
- int y)
-{
- char *drop_target;
- GdkDragAction action, real_action;
-
- drop_target = get_drop_target_uri_at_pos (dest, x, y);
- g_assert (drop_target != NULL);
-
- real_action = gdk_drag_context_get_selected_action (context);
-
- if (real_action == GDK_ACTION_ASK)
- {
- action = GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK;
- real_action = nautilus_drag_drop_action_ask (GTK_WIDGET (dest->details->tree_view), action);
- }
-
- /* We only want to copy external uris */
- if (dest->details->drag_type == NAUTILUS_ICON_DND_URI_LIST)
- {
- real_action = GDK_ACTION_COPY;
- }
-
- if (real_action > 0)
- {
- if (!nautilus_drag_uris_local (drop_target, source_uris)
- || real_action != GDK_ACTION_MOVE)
- {
- g_signal_emit (dest, signals[MOVE_COPY_ITEMS], 0,
- source_uris,
- drop_target,
- real_action,
- x, y);
- }
- }
-
- g_free (drop_target);
-}
-
-static void
-receive_dropped_icons (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- int x,
- int y)
-{
- GList *source_uris;
- GList *l;
-
- /* FIXME: ignore local only moves */
-
- if (!dest->details->drag_list)
- {
- return;
- }
-
- source_uris = NULL;
- for (l = dest->details->drag_list; l != NULL; l = l->next)
- {
- source_uris = g_list_prepend (source_uris,
- ((NautilusDragSelectionItem *) l->data)->uri);
- }
-
- source_uris = g_list_reverse (source_uris);
-
- receive_uris (dest, context, source_uris, x, y);
-
- g_list_free (source_uris);
-}
-
-static void
-receive_dropped_uri_list (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- int x,
- int y)
-{
- char *drop_target;
-
- if (!dest->details->drag_data)
- {
- return;
- }
-
- drop_target = get_drop_target_uri_at_pos (dest, x, y);
- g_assert (drop_target != NULL);
-
- g_signal_emit (dest, signals[HANDLE_URI_LIST], 0,
- (char *) gtk_selection_data_get_data (dest->details->drag_data),
- drop_target,
- gdk_drag_context_get_selected_action (context),
- x, y);
-
- g_free (drop_target);
-}
-
-static void
-receive_dropped_text (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- int x,
- int y)
-{
- char *drop_target;
- guchar *text;
-
- if (!dest->details->drag_data)
- {
- return;
- }
-
- drop_target = get_drop_target_uri_at_pos (dest, x, y);
- g_assert (drop_target != NULL);
-
- text = gtk_selection_data_get_text (dest->details->drag_data);
- g_signal_emit (dest, signals[HANDLE_TEXT], 0,
- (char *) text, drop_target,
- gdk_drag_context_get_selected_action (context),
- x, y);
-
- g_free (text);
- g_free (drop_target);
-}
-
-static void
-receive_dropped_raw (NautilusTreeViewDragDest *dest,
- const char *raw_data,
- int length,
- GdkDragContext *context,
- int x,
- int y)
-{
- char *drop_target;
-
- if (!dest->details->drag_data)
- {
- return;
- }
-
- drop_target = get_drop_target_uri_at_pos (dest, x, y);
- g_assert (drop_target != NULL);
-
- g_signal_emit (dest, signals[HANDLE_RAW], 0,
- raw_data, length, drop_target,
- dest->details->direct_save_uri,
- gdk_drag_context_get_selected_action (context));
-
- g_free (drop_target);
-}
-
-static void
-receive_dropped_netscape_url (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- int x,
- int y)
-{
- char *drop_target;
-
- if (!dest->details->drag_data)
- {
- return;
- }
-
- drop_target = get_drop_target_uri_at_pos (dest, x, y);
- g_assert (drop_target != NULL);
-
- g_signal_emit (dest, signals[HANDLE_NETSCAPE_URL], 0,
- (char *) gtk_selection_data_get_data (dest->details->drag_data),
- drop_target,
- gdk_drag_context_get_selected_action (context),
- x, y);
-
- g_free (drop_target);
-}
-
-static gboolean
-receive_xds (NautilusTreeViewDragDest *dest,
- GtkWidget *widget,
- guint32 time,
- GdkDragContext *context,
- int x,
- int y)
-{
- GFile *location;
- const guchar *selection_data;
- gint selection_format;
- gint selection_length;
-
- selection_data = gtk_selection_data_get_data (dest->details->drag_data);
- selection_format = gtk_selection_data_get_format (dest->details->drag_data);
- selection_length = gtk_selection_data_get_length (dest->details->drag_data);
-
- if (selection_format == 8
- && selection_length == 1
- && selection_data[0] == 'F')
- {
- gtk_drag_get_data (widget, context,
- gdk_atom_intern (NAUTILUS_ICON_DND_RAW_TYPE,
- FALSE),
- time);
- return FALSE;
- }
- else if (selection_format == 8
- && selection_length == 1
- && selection_data[0] == 'S')
- {
- g_assert (dest->details->direct_save_uri != NULL);
- location = g_file_new_for_uri (dest->details->direct_save_uri);
-
- nautilus_file_changes_queue_file_added (location);
- nautilus_file_changes_consume_changes (TRUE);
-
- g_object_unref (location);
- }
- return TRUE;
-}
-
-
-static gboolean
-drag_data_received_callback (GtkWidget *widget,
- GdkDragContext *context,
- int x,
- int y,
- GtkSelectionData *selection_data,
- guint info,
- guint32 time,
- gpointer data)
-{
- NautilusTreeViewDragDest *dest;
- const gchar *tmp;
- int length;
- gboolean success, finished;
-
- dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data);
-
- if (!dest->details->have_drag_data)
- {
- dest->details->have_drag_data = TRUE;
- dest->details->drag_type = info;
- dest->details->drag_data =
- gtk_selection_data_copy (selection_data);
- if (info == NAUTILUS_ICON_DND_GNOME_ICON_LIST)
- {
- dest->details->drag_list =
- nautilus_drag_build_selection_list (selection_data);
- }
- }
-
- if (dest->details->drop_occurred)
- {
- success = FALSE;
- finished = TRUE;
- switch (info)
- {
- case NAUTILUS_ICON_DND_GNOME_ICON_LIST:
- {
- receive_dropped_icons (dest, context, x, y);
- success = TRUE;
- }
- break;
-
- case NAUTILUS_ICON_DND_NETSCAPE_URL:
- {
- receive_dropped_netscape_url (dest, context, x, y);
- success = TRUE;
- }
- break;
-
- case NAUTILUS_ICON_DND_URI_LIST:
- {
- receive_dropped_uri_list (dest, context, x, y);
- success = TRUE;
- }
- break;
-
- case NAUTILUS_ICON_DND_TEXT:
- {
- receive_dropped_text (dest, context, x, y);
- success = TRUE;
- }
- break;
-
- case NAUTILUS_ICON_DND_RAW:
- {
- length = gtk_selection_data_get_length (selection_data);
- tmp = (const gchar *) gtk_selection_data_get_data (selection_data);
- receive_dropped_raw (dest, tmp, length, context, x, y);
- success = TRUE;
- }
- break;
-
- case NAUTILUS_ICON_DND_XDNDDIRECTSAVE:
- {
- finished = receive_xds (dest, widget, time, context, x, y);
- success = TRUE;
- }
- break;
- }
-
- if (finished)
- {
- dest->details->drop_occurred = FALSE;
- free_drag_data (dest);
- gtk_drag_finish (context, success, FALSE, time);
- }
- }
-
- /* appease GtkTreeView by preventing its drag_data_receive
- * from being called */
- g_signal_stop_emission_by_name (dest->details->tree_view,
- "drag-data-received");
-
- return TRUE;
-}
-
-static char *
-get_direct_save_filename (GdkDragContext *context)
-{
- guchar *prop_text;
- gint prop_len;
-
- if (!gdk_property_get (gdk_drag_context_get_source_window (context), gdk_atom_intern (NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE),
- gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL,
- &prop_len, &prop_text))
- {
- return NULL;
- }
-
- /* Zero-terminate the string */
- prop_text = g_realloc (prop_text, prop_len + 1);
- prop_text[prop_len] = '\0';
-
- /* Verify that the file name provided by the source is valid */
- if (*prop_text == '\0' ||
- strchr ((const gchar *) prop_text, G_DIR_SEPARATOR) != NULL)
- {
- DEBUG ("Invalid filename provided by XDS drag site");
- g_free (prop_text);
- return NULL;
- }
-
- return (gchar *) prop_text;
-}
-
-static gboolean
-set_direct_save_uri (NautilusTreeViewDragDest *dest,
- GdkDragContext *context,
- int x,
- int y)
-{
- GFile *base, *child;
- char *drop_uri;
- char *filename, *uri;
-
- g_assert (dest->details->direct_save_uri == NULL);
-
- uri = NULL;
-
- drop_uri = get_drop_target_uri_at_pos (dest, x, y);
- if (drop_uri != NULL)
- {
- filename = get_direct_save_filename (context);
- if (filename != NULL)
- {
- /* Resolve relative path */
- base = g_file_new_for_uri (drop_uri);
- child = g_file_get_child (base, filename);
- uri = g_file_get_uri (child);
-
- g_object_unref (base);
- g_object_unref (child);
-
- /* Change the property */
- gdk_property_change (gdk_drag_context_get_source_window (context),
- gdk_atom_intern (NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE),
- gdk_atom_intern ("text/plain", FALSE), 8,
- GDK_PROP_MODE_REPLACE, (const guchar *) uri,
- strlen (uri));
-
- dest->details->direct_save_uri = uri;
- }
- else
- {
- DEBUG ("Invalid filename provided by XDS drag site");
- }
- }
- else
- {
- DEBUG ("Could not retrieve XDS drop destination");
- }
-
- return uri != NULL;
-}
-
-static gboolean
-drag_drop_callback (GtkWidget *widget,
- GdkDragContext *context,
- int x,
- int y,
- guint32 time,
- gpointer data)
-{
- NautilusTreeViewDragDest *dest;
- guint info;
- GdkAtom target;
-
- dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data);
-
- target = gtk_drag_dest_find_target (GTK_WIDGET (dest->details->tree_view),
- context,
- NULL);
- if (target == GDK_NONE)
- {
- return FALSE;
- }
-
- info = dest->details->drag_type;
-
- if (info == NAUTILUS_ICON_DND_XDNDDIRECTSAVE)
- {
- /* We need to set this or get_drop_path will fail, and it
- * was unset by drag_leave_callback */
- dest->details->have_drag_data = TRUE;
- if (!set_direct_save_uri (dest, context, x, y))
- {
- return FALSE;
- }
- dest->details->have_drag_data = FALSE;
- }
-
- dest->details->drop_occurred = TRUE;
-
- get_drag_data (dest, context, time);
- remove_scroll_timeout (dest);
- clear_drag_dest_row (dest);
-
- return TRUE;
-}
-
-static void
-tree_view_weak_notify (gpointer user_data,
- GObject *object)
-{
- NautilusTreeViewDragDest *dest;
-
- dest = NAUTILUS_TREE_VIEW_DRAG_DEST (user_data);
-
- remove_scroll_timeout (dest);
-
- dest->details->tree_view = NULL;
-}
-
-static void
-nautilus_tree_view_drag_dest_dispose (GObject *object)
-{
- NautilusTreeViewDragDest *dest;
-
- dest = NAUTILUS_TREE_VIEW_DRAG_DEST (object);
-
- if (dest->details->tree_view)
- {
- g_object_weak_unref (G_OBJECT (dest->details->tree_view),
- tree_view_weak_notify,
- dest);
- }
-
- remove_scroll_timeout (dest);
-
- G_OBJECT_CLASS (nautilus_tree_view_drag_dest_parent_class)->dispose (object);
-}
-
-static void
-nautilus_tree_view_drag_dest_finalize (GObject *object)
-{
- NautilusTreeViewDragDest *dest;
-
- dest = NAUTILUS_TREE_VIEW_DRAG_DEST (object);
- free_drag_data (dest);
-
- G_OBJECT_CLASS (nautilus_tree_view_drag_dest_parent_class)->finalize (object);
-}
-
-static void
-nautilus_tree_view_drag_dest_init (NautilusTreeViewDragDest *dest)
-{
- dest->details = G_TYPE_INSTANCE_GET_PRIVATE (dest, NAUTILUS_TYPE_TREE_VIEW_DRAG_DEST,
- NautilusTreeViewDragDestDetails);
-}
-
-static void
-nautilus_tree_view_drag_dest_class_init (NautilusTreeViewDragDestClass *class)
-{
- GObjectClass *gobject_class;
-
- gobject_class = G_OBJECT_CLASS (class);
-
- gobject_class->dispose = nautilus_tree_view_drag_dest_dispose;
- gobject_class->finalize = nautilus_tree_view_drag_dest_finalize;
-
- g_type_class_add_private (class, sizeof (NautilusTreeViewDragDestDetails));
-
- signals[GET_ROOT_URI] =
- g_signal_new ("get-root-uri",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- get_root_uri),
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_STRING, 0);
- signals[GET_FILE_FOR_PATH] =
- g_signal_new ("get-file-for-path",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- get_file_for_path),
- NULL, NULL,
- g_cclosure_marshal_generic,
- NAUTILUS_TYPE_FILE, 1,
- GTK_TYPE_TREE_PATH);
- signals[MOVE_COPY_ITEMS] =
- g_signal_new ("move-copy-items",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- move_copy_items),
- NULL, NULL,
-
- g_cclosure_marshal_generic,
- G_TYPE_NONE, 3,
- G_TYPE_POINTER,
- G_TYPE_STRING,
- GDK_TYPE_DRAG_ACTION);
- signals[HANDLE_NETSCAPE_URL] =
- g_signal_new ("handle-netscape-url",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- handle_netscape_url),
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_NONE, 3,
- G_TYPE_STRING,
- G_TYPE_STRING,
- GDK_TYPE_DRAG_ACTION);
- signals[HANDLE_URI_LIST] =
- g_signal_new ("handle-uri-list",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- handle_uri_list),
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_NONE, 3,
- G_TYPE_STRING,
- G_TYPE_STRING,
- GDK_TYPE_DRAG_ACTION);
- signals[HANDLE_TEXT] =
- g_signal_new ("handle-text",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- handle_text),
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_NONE, 3,
- G_TYPE_STRING,
- G_TYPE_STRING,
- GDK_TYPE_DRAG_ACTION);
- signals[HANDLE_RAW] =
- g_signal_new ("handle-raw",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- handle_raw),
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_NONE, 5,
- G_TYPE_POINTER,
- G_TYPE_INT,
- G_TYPE_STRING,
- G_TYPE_STRING,
- GDK_TYPE_DRAG_ACTION);
- signals[HANDLE_HOVER] =
- g_signal_new ("handle-hover",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NautilusTreeViewDragDestClass,
- handle_hover),
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_NONE, 1,
- G_TYPE_STRING);
-}
-
-
-
-NautilusTreeViewDragDest *
-nautilus_tree_view_drag_dest_new (GtkTreeView *tree_view)
-{
- NautilusTreeViewDragDest *dest;
- GtkTargetList *targets;
-
- dest = g_object_new (NAUTILUS_TYPE_TREE_VIEW_DRAG_DEST, NULL);
-
- dest->details->tree_view = tree_view;
- g_object_weak_ref (G_OBJECT (dest->details->tree_view),
- tree_view_weak_notify, dest);
-
- gtk_drag_dest_set (GTK_WIDGET (tree_view),
- 0, drag_types, G_N_ELEMENTS (drag_types),
- GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK);
-
- targets = gtk_drag_dest_get_target_list (GTK_WIDGET (tree_view));
- gtk_target_list_add_text_targets (targets, NAUTILUS_ICON_DND_TEXT);
-
- g_signal_connect_object (tree_view,
- "drag-motion",
- G_CALLBACK (drag_motion_callback),
- dest, 0);
- g_signal_connect_object (tree_view,
- "drag-leave",
- G_CALLBACK (drag_leave_callback),
- dest, 0);
- g_signal_connect_object (tree_view,
- "drag-drop",
- G_CALLBACK (drag_drop_callback),
- dest, 0);
- g_signal_connect_object (tree_view,
- "drag-data-received",
- G_CALLBACK (drag_data_received_callback),
- dest, 0);
-
- return dest;
-}
-#endif
diff --git a/src/nautilus-tree-view-drag-dest.h b/src/nautilus-tree-view-drag-dest.h
deleted file mode 100644
index 288eec34836ce66b5dda58d9828de3343127f57c..0000000000000000000000000000000000000000
--- a/src/nautilus-tree-view-drag-dest.h
+++ /dev/null
@@ -1,98 +0,0 @@
-
-/*
- * Nautilus
- *
- * Copyright (C) 2002 Sun Microsystems, Inc.
- *
- * Nautilus is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * Nautilus is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, see .
- *
- * Author: Dave Camp
- */
-
-/* nautilus-tree-view-drag-dest.h: Handles drag and drop for treeviews which
- * contain a hierarchy of files
- */
-
-#pragma once
-
-#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
-#include
-
-#include "nautilus-file.h"
-
-G_BEGIN_DECLS
-
-#define NAUTILUS_TYPE_TREE_VIEW_DRAG_DEST (nautilus_tree_view_drag_dest_get_type ())
-#define NAUTILUS_TREE_VIEW_DRAG_DEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_TREE_VIEW_DRAG_DEST, NautilusTreeViewDragDest))
-#define NAUTILUS_TREE_VIEW_DRAG_DEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_TREE_VIEW_DRAG_DEST, NautilusTreeViewDragDestClass))
-#define NAUTILUS_IS_TREE_VIEW_DRAG_DEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_TREE_VIEW_DRAG_DEST))
-#define NAUTILUS_IS_TREE_VIEW_DRAG_DEST_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_TREE_VIEW_DRAG_DEST))
-
-typedef struct _NautilusTreeViewDragDest NautilusTreeViewDragDest;
-typedef struct _NautilusTreeViewDragDestClass NautilusTreeViewDragDestClass;
-typedef struct _NautilusTreeViewDragDestDetails NautilusTreeViewDragDestDetails;
-
-struct _NautilusTreeViewDragDest {
- GObject parent;
-
- NautilusTreeViewDragDestDetails *details;
-};
-
-struct _NautilusTreeViewDragDestClass {
- GObjectClass parent;
-
- char *(*get_root_uri) (NautilusTreeViewDragDest *dest);
- NautilusFile *(*get_file_for_path) (NautilusTreeViewDragDest *dest,
- GtkTreePath *path);
- void (*move_copy_items) (NautilusTreeViewDragDest *dest,
- const GList *item_uris,
- const char *target_uri,
- GdkDragAction action,
- int x,
- int y);
- void (* handle_netscape_url) (NautilusTreeViewDragDest *dest,
- const char *url,
- const char *target_uri,
- GdkDragAction action,
- int x,
- int y);
- void (* handle_uri_list) (NautilusTreeViewDragDest *dest,
- const char *uri_list,
- const char *target_uri,
- GdkDragAction action,
- int x,
- int y);
- void (* handle_text) (NautilusTreeViewDragDest *dest,
- const char *text,
- const char *target_uri,
- GdkDragAction action,
- int x,
- int y);
- void (* handle_raw) (NautilusTreeViewDragDest *dest,
- char *raw_data,
- int length,
- const char *target_uri,
- const char *direct_save_uri,
- GdkDragAction action,
- int x,
- int y);
- void (* handle_hover) (NautilusTreeViewDragDest *dest,
- const char *target_uri);
-};
-
-GType nautilus_tree_view_drag_dest_get_type (void);
-NautilusTreeViewDragDest *nautilus_tree_view_drag_dest_new (GtkTreeView *tree_view);
-
-G_END_DECLS
-#endif
diff --git a/src/nautilus-types.h b/src/nautilus-types.h
index 073a1576d5c781a609709760e8ff198715b8b4e5..1fe93544916ba1de1f17225ab2b3e6f29c712d8d 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-ui-utilities.c b/src/nautilus-ui-utilities.c
index 1498488df5535d5816923bd31cdc36a93171dc2f..8e5933ee84c1c99882a3d4445603615845278879 100644
--- a/src/nautilus-ui-utilities.c
+++ b/src/nautilus-ui-utilities.c
@@ -127,7 +127,9 @@ nautilus_g_menu_replace_string_in_item (GMenu *menu,
{
g_autoptr (GMenuItem) item = NULL;
+ g_return_if_fail (i != -1);
item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i);
+ g_return_if_fail (item != NULL);
g_menu_item_set_attribute (item, attribute, "s", string);
g_menu_remove (menu, i);
g_menu_insert_item (menu, i, item);
diff --git a/src/nautilus-view-cell.c b/src/nautilus-view-cell.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f28fd8ff70f20ada9065913244bfc78f6f24a9a
--- /dev/null
+++ b/src/nautilus-view-cell.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 2022 António Fernandes
+ *
+ * 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 */
+ NautilusViewItem *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)
+{
+ gtk_widget_set_name (GTK_WIDGET (self), "NautilusViewCell");
+}
+
+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,
+ 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,
+ NautilusViewItem *item)
+{
+ g_return_if_fail (NAUTILUS_IS_VIEW_CELL (self));
+ g_return_if_fail (item == NULL || NAUTILUS_IS_VIEW_ITEM (item));
+
+ g_object_set (self, "item", item, NULL);
+}
+
+NautilusViewItem *
+nautilus_view_cell_get_item (NautilusViewCell *self)
+{
+ NautilusViewItem *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 0000000000000000000000000000000000000000..78297b82d22c09d15874af53102da72c0881fb3b
--- /dev/null
+++ b/src/nautilus-view-cell.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 António Fernandes
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include
+
+#include "nautilus-types.h"
+#include "nautilus-view-item.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,
+ NautilusViewItem *item);
+NautilusViewItem *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
deleted file mode 100644
index 94feef1bc4e025aa409be27a2fa0654968c7f8f0..0000000000000000000000000000000000000000
--- a/src/nautilus-view-icon-controller.c
+++ /dev/null
@@ -1,1677 +0,0 @@
-#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;
-
- 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;
-
- guint scroll_to_file_handle_id;
- guint prioritize_thumbnailing_handle_id;
- GtkAdjustment *vadjustment;
-};
-
-G_DEFINE_TYPE (NautilusViewIconController, nautilus_view_icon_controller, NAUTILUS_TYPE_FILES_VIEW)
-
-typedef struct
-{
- const NautilusFileSortType sort_type;
- const gchar *metadata_name;
- const gchar *action_target_name;
- gboolean reversed;
-} SortConstants;
-
-static const SortConstants sorts_constants[] =
-{
- {
- NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
- "name",
- "name",
- FALSE,
- },
- {
- NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
- "name",
- "name-desc",
- TRUE,
- },
- {
- NAUTILUS_FILE_SORT_BY_SIZE,
- "size",
- "size",
- TRUE,
- },
- {
- NAUTILUS_FILE_SORT_BY_TYPE,
- "type",
- "type",
- FALSE,
- },
- {
- NAUTILUS_FILE_SORT_BY_MTIME,
- "modification date",
- "modification-date",
- FALSE,
- },
- {
- NAUTILUS_FILE_SORT_BY_MTIME,
- "modification date",
- "modification-date-desc",
- TRUE,
- },
- {
- NAUTILUS_FILE_SORT_BY_ATIME,
- "access date",
- "access-date",
- FALSE,
- },
- {
- NAUTILUS_FILE_SORT_BY_ATIME,
- "access date",
- "access-date-desc",
- TRUE,
- },
- {
- NAUTILUS_FILE_SORT_BY_BTIME,
- "creation date",
- "creation-date",
- FALSE,
- },
- {
- NAUTILUS_FILE_SORT_BY_BTIME,
- "creation date",
- "creation-date-desc",
- TRUE,
- },
- {
- NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
- "trashed",
- "trash-time",
- TRUE,
- },
- {
- NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
- "search_relevance",
- "search-relevance",
- TRUE,
- }
-};
-
-static guint get_icon_size_for_zoom_level (NautilusGridZoomLevel zoom_level);
-
-static const SortConstants *
-get_sorts_constants_from_action_target_name (const gchar *action_target_name)
-{
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (sorts_constants); i++)
- {
- if (g_strcmp0 (sorts_constants[i].action_target_name, action_target_name) == 0)
- {
- return &sorts_constants[i];
- }
- }
-
- return &sorts_constants[0];
-}
-
-static const SortConstants *
-get_sorts_constants_from_sort_type (NautilusFileSortType sort_type,
- gboolean reversed)
-{
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS (sorts_constants); i++)
- {
- if (sort_type == sorts_constants[i].sort_type
- && reversed == sorts_constants[i].reversed)
- {
- return &sorts_constants[i];
- }
- }
-
- return &sorts_constants[0];
-}
-
-static const SortConstants *
-get_sorts_constants_from_metadata_text (const char *metadata_name,
- gboolean reversed)
-{
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS (sorts_constants); i++)
- {
- if (g_strcmp0 (sorts_constants[i].metadata_name, metadata_name) == 0
- && reversed == sorts_constants[i].reversed)
- {
- return &sorts_constants[i];
- }
- }
-
- return &sorts_constants[0];
-}
-
-static const SortConstants *
-get_default_sort_order (NautilusFile *file)
-{
- NautilusFileSortType sort_type;
- gboolean reversed;
-
- sort_type = nautilus_file_get_default_sort_type (file, &reversed);
-
- return get_sorts_constants_from_sort_type (sort_type, reversed);
-}
-
-static const SortConstants *
-get_directory_sort_by (NautilusFile *file)
-{
- const SortConstants *default_sort;
- g_autofree char *sort_by = NULL;
- gboolean reversed;
-
- default_sort = get_default_sort_order (file);
- 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,
- default_sort->reversed);
-
- return get_sorts_constants_from_metadata_text (sort_by, reversed);
-}
-
-static void
-set_directory_sort_metadata (NautilusFile *file,
- const SortConstants *sort)
-{
- const SortConstants *default_sort;
-
- default_sort = get_default_sort_order (file);
-
- 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_sort->reversed,
- sort->reversed);
-}
-
-static void
-update_sort_order_from_metadata_and_preferences (NautilusViewIconController *self)
-{
- const SortConstants *default_directory_sort;
- GActionGroup *view_action_group;
-
- default_directory_sort = get_directory_sort_by (nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self)));
- 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_string (get_sorts_constants_from_sort_type (default_directory_sort->sort_type, default_directory_sort->reversed)->action_target_name));
-}
-
-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)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- NautilusGridZoomLevel new_level;
-
- new_level = self->zoom_level + zoom_increment;
-
- if (new_level >= NAUTILUS_GRID_ZOOM_LEVEL_SMALL &&
- new_level <= NAUTILUS_GRID_ZOOM_LEVEL_LARGEST)
- {
- g_action_group_change_action_state (self->action_group,
- "zoom-to-level",
- g_variant_new_int32 (new_level));
- }
-}
-
-static guint
-get_icon_size_for_zoom_level (NautilusGridZoomLevel zoom_level)
-{
- switch (zoom_level)
- {
- case NAUTILUS_GRID_ZOOM_LEVEL_SMALL:
- {
- return NAUTILUS_GRID_ICON_SIZE_SMALL;
- }
- break;
-
- case NAUTILUS_GRID_ZOOM_LEVEL_STANDARD:
- {
- return NAUTILUS_GRID_ICON_SIZE_STANDARD;
- }
- break;
-
- case NAUTILUS_GRID_ZOOM_LEVEL_LARGE:
- {
- return NAUTILUS_GRID_ICON_SIZE_LARGE;
- }
- break;
-
- case NAUTILUS_GRID_ZOOM_LEVEL_LARGER:
- {
- return NAUTILUS_GRID_ICON_SIZE_LARGER;
- }
- break;
-
- case NAUTILUS_GRID_ZOOM_LEVEL_LARGEST:
- {
- return NAUTILUS_GRID_ICON_SIZE_LARGEST;
- }
- break;
- }
- g_return_val_if_reached (NAUTILUS_GRID_ICON_SIZE_STANDARD);
-}
-
-static gint
-get_default_zoom_level (void)
-{
- NautilusGridZoomLevel default_zoom_level;
-
- default_zoom_level = g_settings_get_enum (nautilus_icon_view_preferences,
- NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL);
-
- return default_zoom_level;
-}
-
-static void
-set_captions_from_preferences (NautilusViewIconController *self)
-{
- g_auto (GStrv) value = NULL;
- gint n_captions_for_zoom_level;
-
- value = g_settings_get_strv (nautilus_icon_view_preferences,
- NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS);
-
- /* Set a celling on the number of captions depending on the zoom level. */
- n_captions_for_zoom_level = MIN (self->zoom_level,
- G_N_ELEMENTS (self->caption_attributes));
-
- /* Reset array to zeros beforehand, as we may not refill all elements. */
- memset (&self->caption_attributes, 0, sizeof (self->caption_attributes));
- for (gint i = 0, quark_i = 0;
- value[i] != NULL && quark_i < n_captions_for_zoom_level;
- i++)
- {
- if (g_strcmp0 (value[i], "none") == 0)
- {
- continue;
- }
-
- /* Convert to quarks in advance, otherwise each NautilusFile attribute
- * getter would call g_quark_from_string() once for each file. */
- self->caption_attributes[quark_i] = g_quark_from_string (value[i]);
- quark_i++;
- }
-}
-
-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)
-{
- self->zoom_level = new_level;
-
- /* The zoom level may change how many captions are allowed. Update it before
- * setting the icon size, under the assumption that NautilusViewIconItemUi
- * 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_files_view_update_toolbar_menus (NAUTILUS_FILES_VIEW (self));
-}
-
-static void
-real_restore_standard_zoom_level (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self;
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- g_action_group_change_action_state (self->action_group,
- "zoom-to-level",
- g_variant_new_int32 (NAUTILUS_GRID_ZOOM_LEVEL_LARGE));
-}
-
-static gboolean
-real_is_zoom_level_default (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self;
- guint icon_size;
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- icon_size = get_icon_size_for_zoom_level (self->zoom_level);
-
- return icon_size == NAUTILUS_GRID_ICON_SIZE_LARGE;
-}
-
-static gboolean
-real_can_zoom_in (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
-
- return self->zoom_level < NAUTILUS_GRID_ZOOM_LEVEL_LARGEST;
-}
-
-static gboolean
-real_can_zoom_out (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (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
- * GtkGridView does (as one of widget subclassing's goal is to modify the parent
- * class's behavior), while claiming the click gestures, so it means GtkGridView
- * will never react to a click event to emit this signal. So we should be pretty
- * safe here with regards to our custom item click handling.
- */
-static void
-on_grid_view_item_activated (GtkGridView *grid_view,
- guint position,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
-
- 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;
- 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");
- target_name = g_variant_get_string (g_action_get_state (action), NULL);
- sort_constants = get_sorts_constants_from_action_target_name (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,
- sort_constants->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)
-{
- 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;
- }
- }
- }
-
- return G_MAXUINT;
-}
-
-static char *
-real_get_first_visible_file (NautilusFilesView *files_view)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- guint i;
- g_autoptr (NautilusViewItemModel) item = NULL;
- gchar *uri = NULL;
-
- 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;
-}
-
-typedef struct
-{
- NautilusViewIconController *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)
-{
- 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);
-
- 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;
-}
-
-static void
-real_sort_directories_first_changed (NautilusFilesView *files_view)
-{
- NautilusViewModelSortData sort_data;
- NautilusViewModelSortData *current_sort_data;
- NautilusViewIconController *self;
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (files_view);
- current_sort_data = nautilus_view_model_get_sort_type (self->model);
- sort_data.sort_type = current_sort_data->sort_type;
- sort_data.reversed = current_sort_data->reversed;
- sort_data.directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self));
-
- nautilus_view_model_set_sort_type (self->model, &sort_data);
-}
-
-static void
-action_sort_order_changed (GSimpleAction *action,
- GVariant *value,
- gpointer user_data)
-{
- const gchar *target_name;
- const SortConstants *sort_constants;
- NautilusViewModelSortData sort_data;
- NautilusViewIconController *self;
-
- /* Don't resort if the action is in the same state as before */
- if (g_strcmp0 (g_variant_get_string (value, NULL), g_variant_get_string (g_action_get_state (G_ACTION (action)), NULL)) == 0)
- {
- return;
- }
-
- self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
- target_name = g_variant_get_string (value, NULL);
- sort_constants = get_sorts_constants_from_action_target_name (target_name);
- sort_data.sort_type = sort_constants->sort_type;
- sort_data.reversed = sort_constants->reversed;
- sort_data.directories_first = nautilus_files_view_should_sort_directories_first (NAUTILUS_FILES_VIEW (self));
-
- nautilus_view_model_set_sort_type (self->model, &sort_data);
- set_directory_sort_metadata (nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (self)),
- sort_constants);
-
- 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,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
- int zoom_level;
-
- zoom_level = g_variant_get_int32 (state);
- set_zoom_level (self, zoom_level);
- g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
-
- if (g_settings_get_enum (nautilus_icon_view_preferences,
- NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL) != zoom_level)
- {
- g_settings_set_enum (nautilus_icon_view_preferences,
- NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
- zoom_level);
- }
-}
-
-static void
-on_captions_preferences_changed (NautilusViewIconController *self)
-{
- set_captions_from_preferences (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);
-}
-
-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_signal_handlers_disconnect_by_data (nautilus_preferences, self);
-
- 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,
- gpointer user_data)
-{
- GtkWidget *item_ui;
- NautilusViewItemModel *item_model;
-
- 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)))
- {
- GtkWidget *parent;
-
- /* At the time of ::setup emission, the item ui has got no parent yet,
- * that's why we need to complete the widget setup process here, on the
- * first time ::bind is emitted. */
- parent = gtk_widget_get_parent (item_ui);
- gtk_widget_set_halign (parent, GTK_ALIGN_CENTER);
- gtk_widget_set_valign (parent, GTK_ALIGN_START);
- gtk_widget_set_margin_top (parent, 3);
- gtk_widget_set_margin_bottom (parent, 3);
- gtk_widget_set_margin_start (parent, 3);
- gtk_widget_set_margin_end (parent, 3);
- }
-}
-
-static void
-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);
-}
-
-static void
-setup_item_ui (GtkSignalListItemFactory *factory,
- GtkListItem *listitem,
- gpointer user_data)
-{
- NautilusViewIconController *self = NAUTILUS_VIEW_ICON_CONTROLLER (user_data);
- NautilusViewIconItemUi *item_ui;
- GtkEventController *controller;
-
- item_ui = nautilus_view_icon_item_ui_new ();
- 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)
-{
- GtkListItemFactory *factory;
- GtkWidget *widget;
-
- 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);
- gtk_widget_set_focusable (widget, TRUE);
- gtk_widget_set_valign (widget, GTK_ALIGN_START);
-
- /* We don't use the built-in child activation feature for clicks because it
- * doesn't fill all our needs nor does it match our expected behavior.
- * Instead, we roll our own event handling and double/single click mode.
- * However, GtkGridView:single-click-activate has other effects besides
- * activation, as it affects the selection behavior as well (e.g. selects on
- * hover). Setting it to FALSE gives us the expected behavior. */
- gtk_grid_view_set_single_click_activate (GTK_GRID_VIEW (widget), FALSE);
- gtk_grid_view_set_max_columns (GTK_GRID_VIEW (widget), 20);
- gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (widget), TRUE);
-
- /* While we don't want to use GTK's click activation, we'll let it handle
- * the key activation part (with Enter).
- */
- g_signal_connect (widget, "activate", G_CALLBACK (on_grid_view_item_activated), self);
-
- return GTK_GRID_VIEW (widget);
-}
-
-const GActionEntry view_icon_actions[] =
-{
- { "sort", NULL, "s", "'invalid'", action_sort_order_changed },
- { "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);
-
- 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;
-}
-
-static void
-nautilus_view_icon_controller_init (NautilusViewIconController *self)
-{
- GdkClipboard *clipboard;
-
- 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);
-
- g_signal_connect_swapped (nautilus_preferences,
- "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
- G_CALLBACK (on_default_sort_order_changed),
- self);
- g_signal_connect_swapped (nautilus_preferences,
- "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
- G_CALLBACK (on_default_sort_order_changed),
- self);
-
- set_captions_from_preferences (self);
- g_signal_connect_swapped (nautilus_icon_view_preferences,
- "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS,
- G_CALLBACK (on_captions_preferences_changed),
- self);
-
- clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
- g_signal_connect_object (clipboard, "changed",
- G_CALLBACK (on_clipboard_owner_changed), self, 0);
-}
-
-NautilusViewIconController *
-nautilus_view_icon_controller_new (NautilusWindowSlot *slot)
-{
- return g_object_new (NAUTILUS_TYPE_VIEW_ICON_CONTROLLER,
- "window-slot", slot,
- NULL);
-}
diff --git a/src/nautilus-view-icon-controller.h b/src/nautilus-view-icon-controller.h
deleted file mode 100644
index be70c94bd8ceac4bdac0e1ea25016e1d4c5d15c6..0000000000000000000000000000000000000000
--- a/src/nautilus-view-icon-controller.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include "nautilus-files-view.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)
-
-NautilusViewIconController *nautilus_view_icon_controller_new (NautilusWindowSlot *slot);
-
-G_END_DECLS
diff --git a/src/nautilus-view-icon-item-ui.c b/src/nautilus-view-icon-item-ui.c
deleted file mode 100644
index d0ebff7b4b6e0df745e1f35bfcf78480d216c77b..0000000000000000000000000000000000000000
--- a/src/nautilus-view-icon-item-ui.c
+++ /dev/null
@@ -1,330 +0,0 @@
-#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;
-
- NautilusViewItemModel *model;
- GQuark *caption_attributes;
-
- GtkWidget *fixed_height_box;
- GtkWidget *icon;
- GtkWidget *label;
- 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
-};
-
-#define EXTRA_WIDTH_FOR_TEXT 36
-
-static void
-update_icon (NautilusViewIconItemUi *self)
-{
- NautilusFileIconFlags flags;
- g_autoptr (GdkPaintable) icon_paintable = NULL;
- GtkStyleContext *style_context;
- NautilusFile *file;
- 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);
- flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
- NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE |
- NAUTILUS_FILE_ICON_FLAGS_USE_EMBLEMS |
- NAUTILUS_FILE_ICON_FLAGS_USE_ONE_EMBLEM;
-
- icon_paintable = nautilus_file_get_icon_paintable (file, icon_size, 1, flags);
- gtk_picture_set_paintable (GTK_PICTURE (self->icon), icon_paintable);
-
- /* Set the same height and width for all icons regardless of aspect ratio.
- */
- gtk_widget_set_size_request (self->fixed_height_box, icon_size, icon_size);
- if (icon_size < NAUTILUS_GRID_ICON_SIZE_LARGEST)
- {
- int extra_margins = 0.5 * EXTRA_WIDTH_FOR_TEXT;
- gtk_widget_set_margin_start (self->fixed_height_box, extra_margins);
- gtk_widget_set_margin_end (self->fixed_height_box, extra_margins);
- }
- style_context = gtk_widget_get_style_context (self->icon);
- thumbnail_path = nautilus_file_get_thumbnail_path (file);
- if (thumbnail_path != NULL &&
- nautilus_file_should_show_thumbnail (file))
- {
- gtk_style_context_add_class (style_context, "thumbnail");
- }
- else
- {
- gtk_style_context_remove_class (style_context, "thumbnail");
- }
-}
-
-static void
-update_captions (NautilusViewIconItemUi *self)
-{
- NautilusFile *file;
- GtkWidget * const caption_labels[] =
- {
- self->first_caption,
- self->second_caption,
- self->third_caption
- };
- G_STATIC_ASSERT (G_N_ELEMENTS (caption_labels) == NAUTILUS_VIEW_ICON_N_CAPTIONS);
-
- file = nautilus_view_item_model_get_file (self->model);
- for (guint i = 0; i < NAUTILUS_VIEW_ICON_N_CAPTIONS; i++)
- {
- GQuark attribute_q = self->caption_attributes[i];
- gboolean show_caption;
-
- show_caption = (attribute_q != 0);
- gtk_widget_set_visible (caption_labels[i], show_caption);
- if (show_caption)
- {
- g_autofree gchar *string = NULL;
- string = nautilus_file_get_string_attribute_q (file, attribute_q);
- gtk_label_set_text (GTK_LABEL (caption_labels[i]), string);
- }
- }
-}
-
-static void
-on_file_changed (NautilusViewIconItemUi *self)
-{
- NautilusFile *file;
-
- 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);
-}
-
-static void
-on_view_item_size_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- 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)
-{
- NautilusViewIconItemUi *self = NAUTILUS_VIEW_ICON_ITEM_UI (user_data);
- gboolean is_cut;
-
- g_object_get (object, "is-cut", &is_cut, NULL);
- if (is_cut)
- {
- gtk_widget_add_css_class (self->icon, "cut");
- }
- else
- {
- gtk_widget_remove_css_class (self->icon, "cut");
- }
-}
-
-static void
-set_model (NautilusViewIconItemUi *self,
- NautilusViewItemModel *model);
-
-static void
-finalize (GObject *object)
-{
- NautilusViewIconItemUi *self = (NautilusViewIconItemUi *) object;
-
- set_model (self, NULL);
- 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)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (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");
-
- gtk_widget_class_bind_template_child (widget_class, NautilusViewIconItemUi, fixed_height_box);
- gtk_widget_class_bind_template_child (widget_class, NautilusViewIconItemUi, icon);
- gtk_widget_class_bind_template_child (widget_class, NautilusViewIconItemUi, label);
- gtk_widget_class_bind_template_child (widget_class, NautilusViewIconItemUi, first_caption);
- gtk_widget_class_bind_template_child (widget_class, NautilusViewIconItemUi, second_caption);
- gtk_widget_class_bind_template_child (widget_class, NautilusViewIconItemUi, third_caption);
-}
-
-static void
-nautilus_view_icon_item_ui_init (NautilusViewIconItemUi *self)
-{
- gtk_widget_init_template (GTK_WIDGET (self));
-
-#if PANGO_VERSION_CHECK (1, 44, 4)
- {
- PangoAttrList *attr_list;
-
- /* GTK4 TODO: This attribute is set in the UI file but GTK 3 ignores it.
- * Remove this block after the switch to GTK 4. */
- attr_list = pango_attr_list_new ();
- pango_attr_list_insert (attr_list, pango_attr_insert_hyphens_new (FALSE));
- gtk_label_set_attributes (GTK_LABEL (self->label), attr_list);
- pango_attr_list_unref (attr_list);
- }
-#endif
-}
-
-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)
-{
- NautilusViewItemModel *model = NULL;
-
- g_object_get (self, "model", &model, NULL);
-
- return model;
-}
-
-void
-nautilus_view_item_ui_set_caption_attributes (NautilusViewIconItemUi *self,
- GQuark *attrs)
-{
- 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
deleted file mode 100644
index edae77dc8537b721be0be0daabc20bfef6cbc10c..0000000000000000000000000000000000000000
--- a/src/nautilus-view-icon-item-ui.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include "nautilus-view-item-model.h"
-
-G_BEGIN_DECLS
-
-enum
-{
- NAUTILUS_VIEW_ICON_FIRST_CAPTION,
- NAUTILUS_VIEW_ICON_SECOND_CAPTION,
- NAUTILUS_VIEW_ICON_THIRD_CAPTION,
- NAUTILUS_VIEW_ICON_N_CAPTIONS
-};
-
-#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)
-
-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);
-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-item-model.c b/src/nautilus-view-item-model.c
deleted file mode 100644
index 6cc3f54f5c1e5d41c22a6183f967835bc8172d54..0000000000000000000000000000000000000000
--- a/src/nautilus-view-item-model.c
+++ /dev/null
@@ -1,257 +0,0 @@
-#include "nautilus-view-item-model.h"
-#include "nautilus-file.h"
-
-struct _NautilusViewItemModel
-{
- GObject parent_instance;
- guint icon_size;
- gboolean is_cut;
- NautilusFile *file;
- GtkWidget *item_ui;
-};
-
-G_DEFINE_TYPE (NautilusViewItemModel, nautilus_view_item_model, G_TYPE_OBJECT)
-
-enum
-{
- PROP_0,
- PROP_FILE,
- PROP_ICON_SIZE,
- PROP_IS_CUT,
- PROP_ITEM_UI,
- N_PROPS
-};
-
-enum
-{
- FILE_CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL];
-
-static void
-nautilus_view_item_model_dispose (GObject *object)
-{
- NautilusViewItemModel *self = NAUTILUS_VIEW_ITEM_MODEL (object);
-
- g_clear_object (&self->item_ui);
-
- G_OBJECT_CLASS (nautilus_view_item_model_parent_class)->dispose (object);
-}
-
-static void
-nautilus_view_item_model_finalize (GObject *object)
-{
- NautilusViewItemModel *self = NAUTILUS_VIEW_ITEM_MODEL (object);
-
- g_clear_object (&self->file);
-
- G_OBJECT_CLASS (nautilus_view_item_model_parent_class)->finalize (object);
-}
-
-static void
-nautilus_view_item_model_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- NautilusViewItemModel *self = NAUTILUS_VIEW_ITEM_MODEL (object);
-
- switch (prop_id)
- {
- case PROP_FILE:
- {
- g_value_set_object (value, self->file);
- }
- break;
-
- case PROP_ICON_SIZE:
- {
- g_value_set_int (value, self->icon_size);
- }
- break;
-
- case PROP_IS_CUT:
- {
- g_value_set_boolean (value, self->is_cut);
- }
- break;
-
- case PROP_ITEM_UI:
- {
- g_value_set_object (value, self->item_ui);
- }
- break;
-
- default:
- {
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
- }
-}
-
-static void
-nautilus_view_item_model_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- NautilusViewItemModel *self = NAUTILUS_VIEW_ITEM_MODEL (object);
-
- switch (prop_id)
- {
- case PROP_FILE:
- {
- self->file = g_value_dup_object (value);
- }
- break;
-
- case PROP_ICON_SIZE:
- {
- self->icon_size = g_value_get_int (value);
- }
- break;
-
- case PROP_IS_CUT:
- {
- self->is_cut = g_value_get_boolean (value);
- }
- break;
-
- case PROP_ITEM_UI:
- {
- g_set_object (&self->item_ui, g_value_get_object (value));
- }
- break;
-
- default:
- {
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
- }
-}
-
-static void
-nautilus_view_item_model_init (NautilusViewItemModel *self)
-{
-}
-
-static void
-nautilus_view_item_model_class_init (NautilusViewItemModelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = nautilus_view_item_model_dispose;
- object_class->finalize = nautilus_view_item_model_finalize;
- object_class->get_property = nautilus_view_item_model_get_property;
- object_class->set_property = nautilus_view_item_model_set_property;
-
- g_object_class_install_property (object_class,
- PROP_ICON_SIZE,
- g_param_spec_int ("icon-size",
- "Icon size",
- "The size in pixels of the icon",
- NAUTILUS_GRID_ICON_SIZE_SMALL,
- NAUTILUS_GRID_ICON_SIZE_LARGEST,
- NAUTILUS_GRID_ICON_SIZE_LARGE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- g_object_class_install_property (object_class,
- PROP_IS_CUT,
- g_param_spec_boolean ("is-cut",
- "", "",
- FALSE,
- G_PARAM_READWRITE));
- g_object_class_install_property (object_class,
- PROP_FILE,
- g_param_spec_object ("file",
- "File",
- "The file the icon item represents",
- NAUTILUS_TYPE_FILE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property (object_class,
- PROP_ITEM_UI,
- g_param_spec_object ("item-ui",
- "Item ui",
- "The UI that reprensents the item model",
- GTK_TYPE_WIDGET,
- G_PARAM_READWRITE));
-
- signals[FILE_CHANGED] = g_signal_new ("file-changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-NautilusViewItemModel *
-nautilus_view_item_model_new (NautilusFile *file,
- guint icon_size)
-{
- return g_object_new (NAUTILUS_TYPE_VIEW_ITEM_MODEL,
- "file", file,
- "icon-size", icon_size,
- NULL);
-}
-
-guint
-nautilus_view_item_model_get_icon_size (NautilusViewItemModel *self)
-{
- g_return_val_if_fail (NAUTILUS_IS_VIEW_ITEM_MODEL (self), -1);
-
- return self->icon_size;
-}
-
-void
-nautilus_view_item_model_set_icon_size (NautilusViewItemModel *self,
- guint icon_size)
-{
- g_return_if_fail (NAUTILUS_IS_VIEW_ITEM_MODEL (self));
-
- g_object_set (self, "icon-size", icon_size, NULL);
-}
-
-void
-nautilus_view_item_model_set_cut (NautilusViewItemModel *self,
- gboolean is_cut)
-{
- g_return_if_fail (NAUTILUS_IS_VIEW_ITEM_MODEL (self));
-
- g_object_set (self, "is-cut", is_cut, NULL);
-}
-
-NautilusFile *
-nautilus_view_item_model_get_file (NautilusViewItemModel *self)
-{
- g_return_val_if_fail (NAUTILUS_IS_VIEW_ITEM_MODEL (self), NULL);
-
- return self->file;
-}
-
-GtkWidget *
-nautilus_view_item_model_get_item_ui (NautilusViewItemModel *self)
-{
- g_return_val_if_fail (NAUTILUS_IS_VIEW_ITEM_MODEL (self), NULL);
-
- return self->item_ui;
-}
-
-void
-nautilus_view_item_model_set_item_ui (NautilusViewItemModel *self,
- GtkWidget *item_ui)
-{
- g_return_if_fail (NAUTILUS_IS_VIEW_ITEM_MODEL (self));
-
- g_object_set (self, "item-ui", item_ui, NULL);
-}
-
-void
-nautilus_view_item_model_file_changed (NautilusViewItemModel *self)
-{
- g_return_if_fail (NAUTILUS_IS_VIEW_ITEM_MODEL (self));
-
- g_signal_emit (self, signals[FILE_CHANGED], 0);
-}
diff --git a/src/nautilus-view-item-model.h b/src/nautilus-view-item-model.h
deleted file mode 100644
index 27c4a8fd9d63e3ec6be4def3937cd79c8bacd2ff..0000000000000000000000000000000000000000
--- a/src/nautilus-view-item-model.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include "nautilus-file.h"
-
-G_BEGIN_DECLS
-
-#define NAUTILUS_TYPE_VIEW_ITEM_MODEL (nautilus_view_item_model_get_type())
-
-G_DECLARE_FINAL_TYPE (NautilusViewItemModel, nautilus_view_item_model, NAUTILUS, VIEW_ITEM_MODEL, GObject)
-
-NautilusViewItemModel * nautilus_view_item_model_new (NautilusFile *file,
- guint icon_size);
-
-void nautilus_view_item_model_set_icon_size (NautilusViewItemModel *self,
- guint icon_size);
-
-guint nautilus_view_item_model_get_icon_size (NautilusViewItemModel *self);
-void nautilus_view_item_model_set_cut (NautilusViewItemModel *self,
- gboolean is_cut);
-
-NautilusFile * nautilus_view_item_model_get_file (NautilusViewItemModel *self);
-
-void nautilus_view_item_model_set_item_ui (NautilusViewItemModel *self,
- GtkWidget *item_ui);
-
-GtkWidget * nautilus_view_item_model_get_item_ui (NautilusViewItemModel *self);
-void nautilus_view_item_model_file_changed (NautilusViewItemModel *self);
-
-G_END_DECLS
diff --git a/src/nautilus-view-item.c b/src/nautilus-view-item.c
new file mode 100644
index 0000000000000000000000000000000000000000..560cfec42f73ee0b8eeb0b6e7217f84f5159ba98
--- /dev/null
+++ b/src/nautilus-view-item.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "nautilus-view-item.h"
+
+struct _NautilusViewItem
+{
+ GObject parent_instance;
+ guint icon_size;
+ gboolean is_cut;
+ NautilusFile *file;
+ GtkWidget *item_ui;
+};
+
+G_DEFINE_TYPE (NautilusViewItem, nautilus_view_item, G_TYPE_OBJECT)
+
+enum
+{
+ PROP_0,
+ PROP_FILE,
+ PROP_ICON_SIZE,
+ PROP_IS_CUT,
+ PROP_ITEM_UI,
+ N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+enum
+{
+ FILE_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+nautilus_view_item_dispose (GObject *object)
+{
+ NautilusViewItem *self = NAUTILUS_VIEW_ITEM (object);
+
+ g_clear_object (&self->item_ui);
+
+ G_OBJECT_CLASS (nautilus_view_item_parent_class)->dispose (object);
+}
+
+static void
+nautilus_view_item_finalize (GObject *object)
+{
+ NautilusViewItem *self = NAUTILUS_VIEW_ITEM (object);
+
+ g_clear_object (&self->file);
+
+ G_OBJECT_CLASS (nautilus_view_item_parent_class)->finalize (object);
+}
+
+static void
+nautilus_view_item_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusViewItem *self = NAUTILUS_VIEW_ITEM (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILE:
+ {
+ g_value_set_object (value, self->file);
+ }
+ break;
+
+ case PROP_ICON_SIZE:
+ {
+ g_value_set_int (value, self->icon_size);
+ }
+ break;
+
+ case PROP_IS_CUT:
+ {
+ g_value_set_boolean (value, self->is_cut);
+ }
+ break;
+
+ case PROP_ITEM_UI:
+ {
+ g_value_set_object (value, self->item_ui);
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+ }
+}
+
+static void
+nautilus_view_item_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusViewItem *self = NAUTILUS_VIEW_ITEM (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILE:
+ {
+ self->file = g_value_dup_object (value);
+ }
+ break;
+
+ case PROP_ICON_SIZE:
+ {
+ self->icon_size = g_value_get_int (value);
+ }
+ break;
+
+ case PROP_IS_CUT:
+ {
+ self->is_cut = g_value_get_boolean (value);
+ }
+ break;
+
+ case PROP_ITEM_UI:
+ {
+ g_set_object (&self->item_ui, g_value_get_object (value));
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+ }
+}
+
+static void
+nautilus_view_item_init (NautilusViewItem *self)
+{
+}
+
+static void
+nautilus_view_item_class_init (NautilusViewItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = nautilus_view_item_dispose;
+ object_class->finalize = nautilus_view_item_finalize;
+ object_class->get_property = nautilus_view_item_get_property;
+ object_class->set_property = nautilus_view_item_set_property;
+
+ properties[PROP_ICON_SIZE] = g_param_spec_int ("icon-size",
+ "", "",
+ NAUTILUS_LIST_ICON_SIZE_SMALL,
+ NAUTILUS_GRID_ICON_SIZE_EXTRA_LARGE,
+ NAUTILUS_GRID_ICON_SIZE_LARGE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+ properties[PROP_IS_CUT] = g_param_spec_boolean ("is-cut",
+ "", "",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ properties[PROP_FILE] = g_param_spec_object ("file",
+ "", "",
+ NAUTILUS_TYPE_FILE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ properties[PROP_ITEM_UI] = g_param_spec_object ("item-ui",
+ "", "",
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ signals[FILE_CHANGED] = g_signal_new ("file-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+NautilusViewItem *
+nautilus_view_item_new (NautilusFile *file,
+ guint icon_size)
+{
+ return g_object_new (NAUTILUS_TYPE_VIEW_ITEM,
+ "file", file,
+ "icon-size", icon_size,
+ NULL);
+}
+
+guint
+nautilus_view_item_get_icon_size (NautilusViewItem *self)
+{
+ g_return_val_if_fail (NAUTILUS_IS_VIEW_ITEM (self), -1);
+
+ return self->icon_size;
+}
+
+void
+nautilus_view_item_set_icon_size (NautilusViewItem *self,
+ guint icon_size)
+{
+ g_return_if_fail (NAUTILUS_IS_VIEW_ITEM (self));
+
+ g_object_set (self, "icon-size", icon_size, NULL);
+}
+
+void
+nautilus_view_item_set_cut (NautilusViewItem *self,
+ gboolean is_cut)
+{
+ g_return_if_fail (NAUTILUS_IS_VIEW_ITEM (self));
+
+ g_object_set (self, "is-cut", is_cut, NULL);
+}
+
+NautilusFile *
+nautilus_view_item_get_file (NautilusViewItem *self)
+{
+ g_return_val_if_fail (NAUTILUS_IS_VIEW_ITEM (self), NULL);
+
+ return self->file;
+}
+
+GtkWidget *
+nautilus_view_item_get_item_ui (NautilusViewItem *self)
+{
+ g_return_val_if_fail (NAUTILUS_IS_VIEW_ITEM (self), NULL);
+
+ return self->item_ui;
+}
+
+void
+nautilus_view_item_set_item_ui (NautilusViewItem *self,
+ GtkWidget *item_ui)
+{
+ g_return_if_fail (NAUTILUS_IS_VIEW_ITEM (self));
+
+ g_object_set (self, "item-ui", item_ui, NULL);
+}
+
+void
+nautilus_view_item_file_changed (NautilusViewItem *self)
+{
+ g_return_if_fail (NAUTILUS_IS_VIEW_ITEM (self));
+
+ g_signal_emit (self, signals[FILE_CHANGED], 0);
+}
diff --git a/src/nautilus-view-item.h b/src/nautilus-view-item.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e620520aa042d546eac4e45d6abfa55b39ad207
--- /dev/null
+++ b/src/nautilus-view-item.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The GNOME project contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include
+#include
+
+#include "nautilus-file.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_VIEW_ITEM (nautilus_view_item_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusViewItem, nautilus_view_item, NAUTILUS, VIEW_ITEM, GObject)
+
+NautilusViewItem * nautilus_view_item_new (NautilusFile *file,
+ guint icon_size);
+
+void nautilus_view_item_set_icon_size (NautilusViewItem *self,
+ guint icon_size);
+
+guint nautilus_view_item_get_icon_size (NautilusViewItem *self);
+void nautilus_view_item_set_cut (NautilusViewItem *self,
+ gboolean is_cut);
+
+NautilusFile * nautilus_view_item_get_file (NautilusViewItem *self);
+
+void nautilus_view_item_set_item_ui (NautilusViewItem *self,
+ GtkWidget *item_ui);
+
+GtkWidget * nautilus_view_item_get_item_ui (NautilusViewItem *self);
+void nautilus_view_item_file_changed (NautilusViewItem *self);
+
+G_END_DECLS
diff --git a/src/nautilus-view-model.c b/src/nautilus-view-model.c
index 69cdeb0f8fdd74e04985bd3b4662160affc785f3..72fd8a79eda54cd74a56ce8561ba7679e1416659 100644
--- a/src/nautilus-view-model.c
+++ b/src/nautilus-view-model.c
@@ -1,5 +1,5 @@
#include "nautilus-view-model.h"
-#include "nautilus-view-item-model.h"
+#include "nautilus-view-item.h"
#include "nautilus-global-preferences.h"
struct _NautilusViewModel
@@ -9,13 +9,14 @@ struct _NautilusViewModel
GHashTable *map_files_to_model;
GListStore *internal_model;
GtkMultiSelection *selection_model;
- NautilusViewModelSortData *sort_data;
+ GtkSorter *sorter;
+ gulong sorter_changed_id;
};
static GType
nautilus_view_model_get_item_type (GListModel *list)
{
- return NAUTILUS_TYPE_VIEW_ITEM_MODEL;
+ return NAUTILUS_TYPE_VIEW_ITEM;
}
static guint
@@ -116,10 +117,12 @@ G_DEFINE_TYPE_WITH_CODE (NautilusViewModel, nautilus_view_model, G_TYPE_OBJECT,
enum
{
PROP_0,
- PROP_SORT_TYPE,
+ PROP_SORTER,
N_PROPS
};
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
static void
dispose (GObject *object)
{
@@ -143,6 +146,8 @@ dispose (GObject *object)
self->internal_model = NULL;
}
+ g_clear_signal_handler (&self->sorter_changed_id, self->sorter);
+
G_OBJECT_CLASS (nautilus_view_model_parent_class)->dispose (object);
}
@@ -154,10 +159,7 @@ finalize (GObject *object)
G_OBJECT_CLASS (nautilus_view_model_parent_class)->finalize (object);
g_hash_table_destroy (self->map_files_to_model);
- if (self->sort_data)
- {
- g_free (self->sort_data);
- }
+ g_clear_object (&self->sorter);
}
static void
@@ -170,9 +172,9 @@ get_property (GObject *object,
switch (prop_id)
{
- case PROP_SORT_TYPE:
+ case PROP_SORTER:
{
- g_value_set_object (value, self->sort_data);
+ g_value_set_object (value, nautilus_view_model_get_sorter (self));
}
break;
@@ -193,9 +195,9 @@ set_property (GObject *object,
switch (prop_id)
{
- case PROP_SORT_TYPE:
+ case PROP_SORTER:
{
- nautilus_view_model_set_sort_type (self, g_value_get_object (value));
+ nautilus_view_model_set_sorter (self, g_value_get_object (value));
}
break;
@@ -213,7 +215,7 @@ constructed (GObject *object)
G_OBJECT_CLASS (nautilus_view_model_parent_class)->constructed (object);
- self->internal_model = g_list_store_new (NAUTILUS_TYPE_VIEW_ITEM_MODEL);
+ self->internal_model = g_list_store_new (NAUTILUS_TYPE_VIEW_ITEM);
self->selection_model = gtk_multi_selection_new (g_object_ref (G_LIST_MODEL (self->internal_model)));
self->map_files_to_model = g_hash_table_new (NULL, NULL);
@@ -233,6 +235,14 @@ nautilus_view_model_class_init (NautilusViewModelClass *klass)
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->constructed = constructed;
+
+ properties[PROP_SORTER] =
+ g_param_spec_object ("sorter",
+ "", "",
+ GTK_TYPE_SORTER,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
@@ -246,16 +256,20 @@ compare_data_func (gconstpointer a,
gpointer user_data)
{
NautilusViewModel *self = NAUTILUS_VIEW_MODEL (user_data);
- NautilusFile *file_a;
- NautilusFile *file_b;
- file_a = nautilus_view_item_model_get_file (NAUTILUS_VIEW_ITEM_MODEL ((gpointer) a));
- file_b = nautilus_view_item_model_get_file (NAUTILUS_VIEW_ITEM_MODEL ((gpointer) b));
+ g_return_val_if_fail (self->sorter != NULL, GTK_ORDERING_EQUAL);
- return nautilus_file_compare_for_sort (file_a, file_b,
- self->sort_data->sort_type,
- self->sort_data->directories_first,
- self->sort_data->reversed);
+ return gtk_sorter_compare (self->sorter, (gpointer) a, (gpointer) b);
+}
+
+static void
+on_sorter_changed (GtkSorter *sorter,
+ GtkSorterChange change,
+ gpointer user_data)
+{
+ NautilusViewModel *self = NAUTILUS_VIEW_MODEL (user_data);
+
+ g_list_store_sort (self->internal_model, compare_data_func, self);
}
NautilusViewModel *
@@ -264,39 +278,38 @@ 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_sort_type (NautilusViewModel *self,
- NautilusViewModelSortData *sort_data)
+nautilus_view_model_set_sorter (NautilusViewModel *self,
+ GtkSorter *sorter)
{
- if (self->sort_data)
+ if (g_set_object (&self->sorter, sorter))
{
- g_free (self->sort_data);
- }
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]);
- self->sort_data = g_new (NautilusViewModelSortData, 1);
- self->sort_data->sort_type = sort_data->sort_type;
- self->sort_data->reversed = sort_data->reversed;
- self->sort_data->directories_first = sort_data->directories_first;
+ g_clear_signal_handler (&self->sorter_changed_id, self->sorter);
+ self->sorter_changed_id = g_signal_connect (self->sorter, "changed",
+ G_CALLBACK (on_sorter_changed), self);
+ }
g_list_store_sort (self->internal_model, compare_data_func, self);
}
-NautilusViewModelSortData *
-nautilus_view_model_get_sort_type (NautilusViewModel *self)
-{
- return self->sort_data;
-}
-
GQueue *
nautilus_view_model_get_items_from_files (NautilusViewModel *self,
GQueue *files)
{
GList *l;
guint n_items;
- GQueue *item_models;
+ GQueue *items;
n_items = g_list_model_get_n_items (G_LIST_MODEL (self->internal_model));
- item_models = g_queue_new ();
+ items = g_queue_new ();
for (l = g_queue_peek_head_link (files); l != NULL; l = l->next)
{
NautilusFile *file1;
@@ -304,27 +317,27 @@ nautilus_view_model_get_items_from_files (NautilusViewModel *self,
file1 = NAUTILUS_FILE (l->data);
for (guint i = 0; i < n_items; i++)
{
- g_autoptr (NautilusViewItemModel) item_model = NULL;
+ g_autoptr (NautilusViewItem) item = NULL;
NautilusFile *file2;
g_autofree gchar *file1_uri = NULL;
g_autofree gchar *file2_uri = NULL;
- item_model = g_list_model_get_item (G_LIST_MODEL (self->internal_model), i);
- file2 = nautilus_view_item_model_get_file (item_model);
+ item = g_list_model_get_item (G_LIST_MODEL (self->internal_model), i);
+ file2 = nautilus_view_item_get_file (item);
file1_uri = nautilus_file_get_uri (file1);
file2_uri = nautilus_file_get_uri (file2);
if (g_strcmp0 (file1_uri, file2_uri) == 0)
{
- g_queue_push_tail (item_models, item_model);
+ g_queue_push_tail (items, item);
break;
}
}
}
- return item_models;
+ return items;
}
-NautilusViewItemModel *
+NautilusViewItem *
nautilus_view_model_get_item_from_file (NautilusViewModel *self,
NautilusFile *file)
{
@@ -332,8 +345,8 @@ nautilus_view_model_get_item_from_file (NautilusViewModel *self,
}
void
-nautilus_view_model_remove_item (NautilusViewModel *self,
- NautilusViewItemModel *item)
+nautilus_view_model_remove_item (NautilusViewModel *self,
+ NautilusViewItem *item)
{
guint i;
@@ -341,7 +354,7 @@ nautilus_view_model_remove_item (NautilusViewModel *self,
{
NautilusFile *file;
- file = nautilus_view_item_model_get_file (item);
+ file = nautilus_view_item_get_file (item);
g_list_store_remove (self->internal_model, i);
g_hash_table_remove (self->map_files_to_model, file);
}
@@ -355,11 +368,11 @@ nautilus_view_model_remove_all_items (NautilusViewModel *self)
}
void
-nautilus_view_model_add_item (NautilusViewModel *self,
- NautilusViewItemModel *item)
+nautilus_view_model_add_item (NautilusViewModel *self,
+ NautilusViewItem *item)
{
g_hash_table_insert (self->map_files_to_model,
- nautilus_view_item_model_get_file (item),
+ nautilus_view_item_get_file (item),
item);
g_list_store_insert_sorted (self->internal_model, item, compare_data_func, self);
}
@@ -373,13 +386,13 @@ nautilus_view_model_add_items (NautilusViewModel *self,
int i = 0;
array = g_malloc_n (g_queue_get_length (items),
- sizeof (NautilusViewItemModel *));
+ sizeof (NautilusViewItem *));
for (l = g_queue_peek_head_link (items); l != NULL; l = l->next)
{
array[i] = l->data;
g_hash_table_insert (self->map_files_to_model,
- nautilus_view_item_model_get_file (l->data),
+ nautilus_view_item_get_file (l->data),
l->data);
i++;
}
@@ -392,8 +405,8 @@ nautilus_view_model_add_items (NautilusViewModel *self,
}
guint
-nautilus_view_model_get_index (NautilusViewModel *self,
- NautilusViewItemModel *item)
+nautilus_view_model_get_index (NautilusViewModel *self,
+ NautilusViewItem *item)
{
guint i = G_MAXUINT;
gboolean found;
diff --git a/src/nautilus-view-model.h b/src/nautilus-view-model.h
index c32e2656e5b009dede69fd1606b1006bd802efe1..839c6d2c70555e4f7fb184152df36692282b7e54 100644
--- a/src/nautilus-view-model.h
+++ b/src/nautilus-view-model.h
@@ -2,7 +2,7 @@
#include
#include "nautilus-file.h"
-#include "nautilus-view-item-model.h"
+#include "nautilus-view-item.h"
G_BEGIN_DECLS
@@ -10,32 +10,25 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (NautilusViewModel, nautilus_view_model, NAUTILUS, VIEW_MODEL, GObject)
-typedef struct
-{
- NautilusFileSortType sort_type;
- gboolean reversed;
- gboolean directories_first;
-} NautilusViewModelSortData;
-
NautilusViewModel * nautilus_view_model_new (void);
-void nautilus_view_model_set_sort_type (NautilusViewModel *self,
- NautilusViewModelSortData *sort_data);
-NautilusViewModelSortData * nautilus_view_model_get_sort_type (NautilusViewModel *self);
-NautilusViewItemModel * nautilus_view_model_get_item_from_file (NautilusViewModel *self,
+GtkSorter *nautilus_view_model_get_sorter (NautilusViewModel *self);
+void nautilus_view_model_set_sorter (NautilusViewModel *self,
+ GtkSorter *sorter);
+NautilusViewItem * nautilus_view_model_get_item_from_file (NautilusViewModel *self,
NautilusFile *file);
GQueue * nautilus_view_model_get_items_from_files (NautilusViewModel *self,
GQueue *files);
/* Don't use inside a loop, use nautilus_view_model_remove_all_items instead. */
void nautilus_view_model_remove_item (NautilusViewModel *self,
- NautilusViewItemModel *item);
+ NautilusViewItem *item);
void nautilus_view_model_remove_all_items (NautilusViewModel *self);
/* Don't use inside a loop, use nautilus_view_model_add_items instead. */
void nautilus_view_model_add_item (NautilusViewModel *self,
- NautilusViewItemModel *item);
+ NautilusViewItem *item);
void nautilus_view_model_add_items (NautilusViewModel *self,
GQueue *items);
guint nautilus_view_model_get_index (NautilusViewModel *self,
- NautilusViewItemModel *item);
+ NautilusViewItem *item);
G_END_DECLS
diff --git a/src/resources/css/Adwaita.css b/src/resources/css/Adwaita.css
index 830eeed069d369df39c7f42573820c2c43d8eea8..47110f38e22e093e27a0e677c65ac42a67dbdd59 100644
--- a/src/resources/css/Adwaita.css
+++ b/src/resources/css/Adwaita.css
@@ -138,13 +138,6 @@
color: shade(@disk_space_free, 0.7);
}
-/* As a workaround for GtkTreeView showing thick border above first row when
- * horizontal grid lines are enabled, we add them using CSS instead. Exclude the
- * drop targets to let through the default feedback style. */
-.nautilus-list-view .view:not(:drop(active)) {
- border-bottom: 1px solid @window_bg_color;
-}
-
.search-information {
background-color: @accent_bg_color;
color:white;
@@ -165,7 +158,63 @@
padding: 6px;
}
-.nautilus-grid-view .thumbnail {
+/* Column view */
+
+/* Setup padding on the list. Horizontal padding must be set on the columnview
+ * for it to calculate column widths correctly. */
+.nautilus-list-view columnview {
+ padding-left: 24px;
+ padding-right: 24px;
+}
+.nautilus-list-view columnview > listview {
+ padding-top: 12px;
+ padding-bottom: 24px;
+}
+
+/* Use negative margins to extend rubberbanding area into the columnview's
+ * padding, then apply positive margin on rows to reestablish positioning. */
+.nautilus-list-view columnview > listview {
+ margin-left: -24px;
+ margin-right: -24px;
+}
+.nautilus-list-view columnview > listview > row {
+ margin-left: 24px;
+ margin-right: 24px;
+}
+
+.nautilus-list-view columnview > listview > row {
+ border-radius: 6px;
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
+
+.nautilus-list-view.compact columnview > listview > row {
+ margin-top: 2px;
+ margin-bottom: 2px;
+}
+
+/* GTK unconditionally sets padding on GtkColumnViewCell, even with .data-table.
+ * We don't want this to hpappen because we have event controllers on the child,
+ * which should thus cover the whole area of the row. */
+.nautilus-list-view columnview > listview > row > cell {
+ padding: 0px;
+}
+
+.nautilus-list-view #NautilusViewCell {
+ padding: 6px;
+}
+
+.nautilus-list-view.compact #NautilusViewCell {
+ padding-top: 3px;
+ padding-bottom: 3px;
+}
+
+.nautilus-list-view:not(.compact) image.star {
+ padding: 6px;
+}
+
+/* Both views */
+.view .thumbnail {
background: url('/org/gnome/nautilus/Checkerboard.png') repeat;
box-shadow: 0px 1px 2px 0px @shade_color,
0px 0px 0px 1px @shade_color,
@@ -173,6 +222,19 @@
border-radius: 2px;
}
-.nautilus-grid-view .cut {
+.view .cut {
opacity: 0.55;
}
+
+.view image.star:hover {
+ opacity: 1;
+}
+
+@keyframes rotate_star {
+ from { -gtk-icon-transform: rotate(-72deg); }
+ to {}
+}
+
+.view image.star.added {
+ animation: rotate_star 0.4s ease;
+}
diff --git a/src/resources/nautilus.gresource.xml b/src/resources/nautilus.gresource.xml
index 304814f75a40cb9453d7d42d90307e1e96c6e20c..d6ae0a20a45418ed37a5b38933120f074e96cfd5 100644
--- a/src/resources/nautilus.gresource.xml
+++ b/src/resources/nautilus.gresource.xml
@@ -25,7 +25,8 @@
ui/nautilus-file-conflict-dialog.ui
ui/nautilus-files-view-select-items.ui
ui/nautilus-operations-ui-manager-request-passphrase.ui
- ui/nautilus-view-icon-item-ui.ui
+ ui/nautilus-grid-cell.ui
+ ui/nautilus-name-cell.ui
../gtk/nautilusgtksidebarrow.ui
../gtk/nautilusgtkplacesview.ui
../gtk/nautilusgtkplacesviewrow.ui
diff --git a/src/resources/ui/nautilus-view-icon-item-ui.ui b/src/resources/ui/nautilus-grid-cell.ui
similarity index 98%
rename from src/resources/ui/nautilus-view-icon-item-ui.ui
rename to src/resources/ui/nautilus-grid-cell.ui
index 0b0f18d26eb25bda7d06e5ab39b4c40dbc008352..2a9417aa86f62f83bc8b642ca2abfb318e170413 100644
--- a/src/resources/ui/nautilus-view-icon-item-ui.ui
+++ b/src/resources/ui/nautilus-grid-cell.ui
@@ -1,7 +1,7 @@
-
+