[nautilus/wip/csoriano/list-box] general: Add GtkListBox based list view



commit d36f88dd034c8eedf46b7355426d0b6f19bae34d
Author: Carlos Soriano <csoriano gnome org>
Date:   Fri May 12 23:25:08 2017 +0200

    general: Add GtkListBox based list view

 src/meson.build                     |    6 +
 src/nautilus-files-view.c           |   10 +-
 src/nautilus-view-list-controller.c |  928 +++++++++++++++++++++++++++++++++++
 src/nautilus-view-list-controller.h |   24 +
 src/nautilus-view-list-item-ui.c    |  247 ++++++++++
 src/nautilus-view-list-item-ui.h    |   22 +
 src/nautilus-view-list-ui.c         |  233 +++++++++
 src/nautilus-view-list-ui.h         |   41 ++
 src/resources/css/Adwaita.css       |    3 +
 9 files changed, 1513 insertions(+), 1 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index 83723b9..2dbbd75 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -129,6 +129,12 @@ libnautilus_sources = [
     'nautilus-view-icon-item-ui.h',
     'nautilus-view-icon-ui.c',
     'nautilus-view-icon-ui.h',
+    'nautilus-view-list-controller.c',
+    'nautilus-view-list-controller.h',
+    'nautilus-view-list-item-ui.c',
+    'nautilus-view-list-item-ui.h',
+    'nautilus-view-list-ui.c',
+    'nautilus-view-list-ui.h',
     'nautilus-view-item-model.c',
     'nautilus-view-item-model.h',
     'nautilus-view-model.c',
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index b6974db..4ed9fe3 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -36,6 +36,7 @@
 #include "nautilus-file-undo-manager.h"
 #include "nautilus-floating-bar.h"
 #include "nautilus-view-icon-controller.h"
+#include "nautilus-view-list-controller.h"
 #include "nautilus-list-view.h"
 #include "nautilus-canvas-view.h"
 #include "nautilus-mime-actions.h"
@@ -9736,7 +9737,14 @@ nautilus_files_view_new (guint               id,
 
         case NAUTILUS_VIEW_LIST_ID:
         {
-            view = nautilus_list_view_new (slot);
+            if (use_experimental_views)
+            {
+                view = NAUTILUS_FILES_VIEW (nautilus_view_list_controller_new (slot));
+            }
+            else
+            {
+              view = nautilus_list_view_new (slot);
+            }
         }
         break;
     }
diff --git a/src/nautilus-view-list-controller.c b/src/nautilus-view-list-controller.c
new file mode 100644
index 0000000..23fc94a
--- /dev/null
+++ b/src/nautilus-view-list-controller.c
@@ -0,0 +1,928 @@
+#include "nautilus-view-list-controller.h"
+#include "nautilus-view-list-ui.h"
+#include "nautilus-view-item-model.h"
+#include "nautilus-view-list-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-global-preferences.h"
+
+struct _NautilusViewListController
+{
+    NautilusFilesView parent_instance;
+
+    NautilusViewListUi *view_ui;
+    NautilusViewModel *model;
+    GtkEventBox *event_box;
+
+    GIcon *view_icon;
+    GActionGroup *action_group;
+    gint zoom_level;
+};
+
+G_DEFINE_TYPE (NautilusViewListController, nautilus_view_list_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_TRASHED_TIME,
+        "trashed",
+        "trash-time",
+        TRUE,
+    },
+    {
+        NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
+        NULL,
+        "search-relevance",
+        TRUE,
+    }
+};
+
+static guint get_icon_size_for_zoom_level (NautilusListZoomLevel 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;
+    NautilusFileSortType default_sort_order;
+    gboolean reversed;
+
+    default_sort_order = g_settings_get_enum (nautilus_preferences,
+                                              NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER);
+    reversed = g_settings_get_boolean (nautilus_preferences,
+                                       NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER);
+
+    /* If this is a special folder (e.g. search or recent), override the sort
+     * order and reversed flag with values appropriate for the folder */
+    sort_type = nautilus_file_get_default_sort_type (file, &reversed);
+
+    if (sort_type == NAUTILUS_FILE_SORT_NONE)
+    {
+        sort_type = CLAMP (default_sort_order,
+                           NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
+                           NAUTILUS_FILE_SORT_BY_ATIME);
+    }
+
+    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_LIST_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_LIST_VIEW_SORT_REVERSED,
+                                        default_sort->reversed,
+                                        sort->reversed);
+}
+
+static void
+update_sort_order_from_metadata_and_preferences (NautilusViewListController *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)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_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)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+
+    nautilus_view_model_remove_all_items (self->model);
+}
+
+
+/* FIXME: ideally this should go into the model so there is not need to
+ * recreate the model with the new data */
+static void
+real_file_changed (NautilusFilesView *files_view,
+                   NautilusFile      *file,
+                   NautilusDirectory *directory)
+{
+    NautilusViewListController *self;
+    NautilusViewItemModel *item_model;
+    NautilusViewItemModel *new_item_model;
+
+    self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    item_model = nautilus_view_model_get_item_from_file (self->model, file);
+    nautilus_view_model_remove_item (self->model, item_model);
+    new_item_model = nautilus_view_item_model_new (file,
+                                                   get_icon_size_for_zoom_level (self->zoom_level));
+    nautilus_view_model_add_item (self->model, new_item_model);
+}
+
+static GList *
+real_get_selection (NautilusFilesView *files_view)
+{
+    NautilusViewListController *self;
+    GList *selected_files = NULL;
+    GList *l;
+    g_autoptr (GList) selected_items = NULL;
+
+    self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    selected_items = gtk_flow_box_get_selected_children (GTK_FLOW_BOX (self->view_ui));
+    for (l = selected_items; l != NULL; l = l->next)
+    {
+        NautilusViewItemModel *item_model;
+
+        item_model = nautilus_view_list_item_ui_get_model (NAUTILUS_VIEW_LIST_ITEM_UI (l->data));
+        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)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+
+    return g_list_model_get_n_items (G_LIST_MODEL (nautilus_view_model_get_g_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)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    NautilusFile *current_file;
+    NautilusViewItemModel *current_item_model;
+    guint i = 0;
+
+    while ((current_item_model = NAUTILUS_VIEW_ITEM_MODEL (g_list_model_get_item (G_LIST_MODEL 
(nautilus_view_model_get_g_model (self->model)), i))))
+    {
+        current_file = nautilus_view_item_model_get_file (current_item_model);
+        if (current_file == file)
+        {
+            g_list_store_remove (nautilus_view_model_get_g_model (self->model), i);
+            break;
+        }
+        i++;
+    }
+}
+
+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 (NautilusViewListController *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)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    g_autoptr (GQueue) selection_files = NULL;
+    g_autoptr (GQueue) selection_item_models = NULL;
+
+    selection_files = convert_glist_to_queue (selection);
+    selection_item_models = nautilus_view_model_get_items_from_files (self->model, selection_files);
+    nautilus_view_list_ui_set_selection (self->view_ui, selection_item_models);
+    nautilus_files_view_notify_selection_changed (files_view);
+}
+
+static void
+real_select_all (NautilusFilesView *files_view)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    gtk_flow_box_select_all (GTK_FLOW_BOX (self->view_ui));
+}
+
+static void
+real_reveal_selection (NautilusFilesView *files_view)
+{
+    GList *selection;
+    NautilusViewItemModel *item_model;
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    GtkWidget *item_ui;
+    GtkAllocation allocation;
+    GtkWidget *content_widget;
+    GtkAdjustment *vadjustment;
+
+    selection = nautilus_view_get_selection (NAUTILUS_VIEW (files_view));
+    if (selection == NULL)
+    {
+        return;
+    }
+
+    item_model = nautilus_view_model_get_item_from_file (self->model,
+                                                         NAUTILUS_FILE (selection->data));
+    item_ui = nautilus_view_item_model_get_item_ui (item_model);
+    gtk_widget_get_allocation (item_ui, &allocation);
+    content_widget = nautilus_files_view_get_content_widget (files_view);
+    vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (content_widget));
+    gtk_adjustment_set_value (vadjustment, allocation.y);
+
+    g_list_foreach (selection, (GFunc) g_object_unref, NULL);
+}
+
+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_list_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)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    NautilusListZoomLevel new_level;
+
+    new_level = self->zoom_level + zoom_increment;
+
+    if (new_level >= NAUTILUS_LIST_ZOOM_LEVEL_SMALL &&
+        new_level <= NAUTILUS_LIST_ZOOM_LEVEL_LARGER)
+    {
+        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 (NautilusListZoomLevel zoom_level)
+{
+    switch (zoom_level)
+    {
+        case NAUTILUS_LIST_ZOOM_LEVEL_SMALL:
+        {
+            return NAUTILUS_LIST_ICON_SIZE_SMALL;
+        }
+        break;
+
+        case NAUTILUS_LIST_ZOOM_LEVEL_STANDARD:
+        {
+            return NAUTILUS_LIST_ICON_SIZE_STANDARD;
+        }
+        break;
+
+        case NAUTILUS_LIST_ZOOM_LEVEL_LARGE:
+        {
+            return NAUTILUS_LIST_ICON_SIZE_LARGE;
+        }
+        break;
+
+        case NAUTILUS_LIST_ZOOM_LEVEL_LARGER:
+        {
+            return NAUTILUS_LIST_ICON_SIZE_LARGER;
+        }
+        break;
+    }
+    g_return_val_if_reached (NAUTILUS_LIST_ICON_SIZE_STANDARD);
+}
+
+static gint
+get_default_zoom_level ()
+{
+    NautilusCanvasZoomLevel default_zoom_level;
+
+    default_zoom_level = g_settings_get_enum (nautilus_list_view_preferences,
+                                              NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL);
+
+    return default_zoom_level;
+}
+
+static void
+set_list_size (NautilusViewListController *self,
+               gint                        list_size)
+{
+    NautilusViewItemModel *current_item_model;
+    guint i = 0;
+
+    while ((current_item_model = NAUTILUS_VIEW_ITEM_MODEL (g_list_model_get_item (G_LIST_MODEL 
(nautilus_view_model_get_g_model (self->model)), i))))
+    {
+        nautilus_view_item_model_set_icon_size (current_item_model,
+                                                get_icon_size_for_zoom_level (self->zoom_level));
+        i++;
+    }
+}
+
+static void
+set_zoom_level (NautilusViewListController *self,
+                guint                       new_level)
+{
+    self->zoom_level = new_level;
+
+    set_list_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)
+{
+    NautilusViewListController *self;
+
+    self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    g_action_group_change_action_state (self->action_group,
+                                        "zoom-to-level",
+                                        g_variant_new_int32 (NAUTILUS_LIST_ZOOM_LEVEL_LARGE));
+}
+
+static gfloat
+real_get_zoom_level_percentage (NautilusFilesView *files_view)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+
+    return (gfloat) get_icon_size_for_zoom_level (self->zoom_level) /
+           NAUTILUS_LIST_ICON_SIZE_LARGE;
+}
+
+static gboolean
+real_can_zoom_in (NautilusFilesView *files_view)
+{
+    return TRUE;
+}
+
+static gboolean
+real_can_zoom_out (NautilusFilesView *files_view)
+{
+    return TRUE;
+}
+
+static GdkRectangle *
+real_compute_rename_popover_pointing_to (NautilusFilesView *files_view)
+{
+    NautilusViewListController *self;
+    GdkRectangle *allocation;
+    GtkAdjustment *vadjustment;
+    GtkAdjustment *hadjustment;
+    GtkWidget *parent_container;
+    g_autoptr (GQueue) selection_files = NULL;
+    g_autoptr (GQueue) selection_item_models = NULL;
+    GList *selection;
+    GtkWidget *list_item_ui;
+
+    self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    allocation = g_new0 (GdkRectangle, 1);
+
+    parent_container = nautilus_files_view_get_content_widget (files_view);
+    vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (parent_container));
+    hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (parent_container));
+    selection = nautilus_view_get_selection (NAUTILUS_VIEW (files_view));
+    selection_files = convert_glist_to_queue (selection);
+    selection_item_models = nautilus_view_model_get_items_from_files (self->model, selection_files);
+    /* We only allow one item to be renamed with a popover */
+    list_item_ui = nautilus_view_item_model_get_item_ui (g_queue_peek_head (selection_item_models));
+    gtk_widget_get_allocation (list_item_ui, allocation);
+
+    allocation->x -= gtk_adjustment_get_value (hadjustment);
+    allocation->y -= gtk_adjustment_get_value (vadjustment);
+
+    return allocation;
+}
+
+static void
+real_click_policy_changed (NautilusFilesView *files_view)
+{
+}
+
+static gboolean
+on_button_press_event (GtkWidget *widget,
+                       GdkEvent  *event,
+                       gpointer   user_data)
+{
+    NautilusViewListController *self;
+    g_autoptr (GList) selection = NULL;
+    GtkWidget *child_at_pos;
+    GdkEventButton *event_button;
+
+    self = NAUTILUS_VIEW_LIST_CONTROLLER (user_data);
+    event_button = (GdkEventButton *) event;
+
+    /* Need to update the selection so the popup has the right actions enabled */
+    selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
+    child_at_pos = GTK_WIDGET (gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (self->view_ui),
+                                                              event_button->x, event_button->y));
+    if (child_at_pos != NULL)
+    {
+        NautilusFile *selected_file;
+        NautilusViewItemModel *item_model;
+
+        item_model = nautilus_view_list_item_ui_get_model (NAUTILUS_VIEW_LIST_ITEM_UI (child_at_pos));
+        selected_file = nautilus_view_item_model_get_file (item_model);
+        if (g_list_find (selection, selected_file) == NULL)
+        {
+            g_list_foreach (selection, (GFunc) g_object_unref, NULL);
+            selection = g_list_append (NULL, selected_file);
+        }
+        else
+        {
+            selection = g_list_prepend (selection, g_object_ref (selected_file));
+        }
+
+        nautilus_view_set_selection (NAUTILUS_VIEW (self), selection);
+
+        if (event_button->button == GDK_BUTTON_SECONDARY)
+        {
+            nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (self),
+                                                               event_button);
+        }
+    }
+    else
+    {
+        nautilus_view_set_selection (NAUTILUS_VIEW (self), NULL);
+        if (event_button->button == GDK_BUTTON_SECONDARY)
+        {
+            nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (self),
+                                                                event_button);
+        }
+    }
+
+    g_list_foreach (selection, (GFunc) g_object_unref, NULL);
+
+    return GDK_EVENT_STOP;
+}
+
+static int
+real_compare_files (NautilusFilesView *files_view,
+                    NautilusFile      *file1,
+                    NautilusFile      *file2)
+{
+    if (file1 < file2)
+    {
+        return -1;
+    }
+
+    if (file1 > file2)
+    {
+        return +1;
+    }
+
+    return 0;
+}
+
+static gboolean
+real_using_manual_layout (NautilusFilesView *files_view)
+{
+    return FALSE;
+}
+
+static void
+real_end_loading (NautilusFilesView *files_view,
+                  gboolean           all_files_seen)
+{
+}
+
+static char *
+real_get_first_visible_file (NautilusFilesView *files_view)
+{
+    return NULL;
+}
+
+static void
+real_scroll_to_file (NautilusFilesView *files_view,
+                     const char        *uri)
+{
+}
+
+static void
+real_sort_directories_first_changed (NautilusFilesView *files_view)
+{
+    NautilusViewModelSortData sort_data;
+    NautilusViewModelSortData *current_sort_data;
+    NautilusViewListController *self;
+
+    self = NAUTILUS_VIEW_LIST_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 *sorts_constants;
+    NautilusViewModelSortData sort_data;
+    NautilusViewListController *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_LIST_CONTROLLER (user_data);
+    target_name = g_variant_get_string (value, NULL);
+    sorts_constants = get_sorts_constants_from_action_target_name (target_name);
+    sort_data.sort_type = sorts_constants->sort_type;
+    sort_data.reversed = sorts_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)),
+                                 sorts_constants);
+
+    g_simple_action_set_state (action, value);
+}
+
+static void
+real_add_files (NautilusFilesView *files_view,
+                GList             *files)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+    g_autoptr (GQueue) files_queue;
+    g_autoptr (GQueue) item_models;
+
+    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);
+}
+
+
+static guint
+real_get_view_id (NautilusFilesView *files_view)
+{
+    return NAUTILUS_VIEW_LIST_ID;
+}
+
+static GIcon *
+real_get_icon (NautilusFilesView *files_view)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (files_view);
+
+    return self->view_icon;
+}
+
+static void
+real_select_first (NautilusFilesView *files_view)
+{
+}
+
+static void
+action_zoom_to_level (GSimpleAction *action,
+                      GVariant      *state,
+                      gpointer       user_data)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_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_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);
+    }
+}
+
+static void
+finalize (GObject *object)
+{
+    G_OBJECT_CLASS (nautilus_view_list_controller_parent_class)->finalize (object);
+}
+
+
+const GActionEntry view_list_actions[] =
+{
+    { "sort", NULL, "s", "'invalid'", action_sort_order_changed },
+    { "zoom-to-level", NULL, NULL, "100", action_zoom_to_level }
+};
+
+static void
+constructed (GObject *object)
+{
+    NautilusViewListController *self = NAUTILUS_VIEW_LIST_CONTROLLER (object);
+    GtkWidget *content_widget;
+    GActionGroup *view_action_group;
+
+    self->model = nautilus_view_model_new ();
+    self->view_ui = nautilus_view_list_ui_new (self);
+    gtk_widget_show (GTK_WIDGET (self->view_ui));
+    self->view_icon = g_themed_icon_new ("view-list-symbolic");
+
+    self->event_box = GTK_EVENT_BOX (gtk_event_box_new ());
+    gtk_container_add (GTK_CONTAINER (self->event_box), GTK_WIDGET (self->view_ui));
+    g_signal_connect (GTK_WIDGET (self->event_box), "button-press-event",
+                      (GCallback) on_button_press_event, self);
+
+    content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (self));
+    gtk_container_add (GTK_CONTAINER (content_widget), GTK_WIDGET (self->event_box));
+
+    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_list_actions,
+                                     G_N_ELEMENTS (view_list_actions),
+                                     self);
+
+    gtk_widget_show_all (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_list_actions,
+                                     G_N_ELEMENTS (view_list_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_list_controller_class_init (NautilusViewListControllerClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NautilusFilesViewClass *files_view_class = NAUTILUS_FILES_VIEW_CLASS (klass);
+
+    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->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->using_manual_layout = real_using_manual_layout;
+    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->get_icon = real_get_icon;
+    files_view_class->select_first = real_select_first;
+    files_view_class->restore_standard_zoom_level = real_restore_standard_zoom_level;
+    files_view_class->get_zoom_level_percentage = real_get_zoom_level_percentage;
+    files_view_class->compute_rename_popover_pointing_to = real_compute_rename_popover_pointing_to;
+}
+
+static void
+nautilus_view_list_controller_init (NautilusViewListController *self)
+{
+}
+
+NautilusViewListController *
+nautilus_view_list_controller_new (NautilusWindowSlot *slot)
+{
+    return g_object_new (NAUTILUS_TYPE_VIEW_LIST_CONTROLLER,
+                         "window-slot", slot,
+                         NULL);
+}
+
+NautilusViewModel *
+nautilus_view_list_controller_get_model (NautilusViewListController *self)
+{
+    g_return_val_if_fail (NAUTILUS_IS_VIEW_LIST_CONTROLLER (self), NULL);
+
+    return self->model;
+}
diff --git a/src/nautilus-view-list-controller.h b/src/nautilus-view-list-controller.h
new file mode 100644
index 0000000..845d411
--- /dev/null
+++ b/src/nautilus-view-list-controller.h
@@ -0,0 +1,24 @@
+#ifndef NAUTILUS_VIEW_LIST_CONTROLLER_H
+#define NAUTILUS_VIEW_LIST_CONTROLLER_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "nautilus-files-view.h"
+#include "nautilus-window-slot.h"
+#include "nautilus-view-model.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_VIEW_LIST_CONTROLLER (nautilus_view_list_controller_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusViewListController, nautilus_view_list_controller, NAUTILUS, 
VIEW_LIST_CONTROLLER, NautilusFilesView)
+
+NautilusViewListController *nautilus_view_list_controller_new (NautilusWindowSlot *slot);
+
+NautilusViewModel * nautilus_view_list_controller_get_model (NautilusViewListController *self);
+
+G_END_DECLS
+
+#endif /* NAUTILUS_VIEW_LIST_CONTROLLER_H */
+
diff --git a/src/nautilus-view-list-item-ui.c b/src/nautilus-view-list-item-ui.c
new file mode 100644
index 0000000..7eb5cb0
--- /dev/null
+++ b/src/nautilus-view-list-item-ui.c
@@ -0,0 +1,247 @@
+#include "nautilus-view-list-item-ui.h"
+#include "nautilus-view-item-model.h"
+#include "nautilus-container-max-width.h"
+#include "nautilus-file.h"
+#include "nautilus-thumbnails.h"
+
+struct _NautilusViewListItemUi
+{
+    GtkListBoxRow parent_instance;
+
+    NautilusViewItemModel *model;
+
+    GtkBox *container;
+    GtkWidget *icon;
+    GtkLabel *label;
+};
+
+G_DEFINE_TYPE (NautilusViewListItemUi, nautilus_view_list_item_ui, GTK_TYPE_LIST_BOX_ROW)
+
+enum
+{
+    PROP_0,
+    PROP_MODEL,
+    N_PROPS
+};
+
+static GtkWidget *
+create_icon (NautilusViewListItemUi *self)
+{
+    NautilusFileIconFlags flags;
+    g_autoptr (GdkPixbuf) icon_pixbuf;
+    GtkImage *icon;
+    GtkBox *fixed_height_box;
+    GtkStyleContext *style_context;
+    NautilusFile *file;
+    guint icon_size;
+
+    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_pixbuf = nautilus_file_get_icon_pixbuf (file, icon_size,
+                                                 TRUE, 1, flags);
+    icon = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_pixbuf));
+    gtk_widget_set_hexpand (GTK_WIDGET (icon), TRUE);
+    gtk_widget_set_vexpand (GTK_WIDGET (icon), TRUE);
+    gtk_widget_set_valign (GTK_WIDGET (icon), GTK_ALIGN_CENTER);
+    gtk_widget_set_halign (GTK_WIDGET (icon), GTK_ALIGN_CENTER);
+
+    fixed_height_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0));
+    gtk_widget_set_valign (GTK_WIDGET (fixed_height_box), GTK_ALIGN_CENTER);
+    gtk_widget_set_halign (GTK_WIDGET (fixed_height_box), GTK_ALIGN_CENTER);
+    gtk_widget_set_size_request (GTK_WIDGET (fixed_height_box), icon_size, icon_size);
+
+    if (nautilus_can_thumbnail (file) &&
+        nautilus_file_should_show_thumbnail (file))
+    {
+        style_context = gtk_widget_get_style_context (GTK_WIDGET (fixed_height_box));
+        gtk_style_context_add_class (style_context, "icon-background");
+    }
+
+    gtk_box_pack_start (fixed_height_box, GTK_WIDGET (icon), FALSE, FALSE, 0);
+
+    return GTK_WIDGET (fixed_height_box);
+}
+
+static void
+update_icon (NautilusViewListItemUi *self)
+{
+    if (self->icon)
+    {
+        gtk_container_remove (GTK_CONTAINER (self->container), GTK_WIDGET (self->icon));
+    }
+    self->icon = create_icon (self);
+    gtk_widget_show_all (GTK_WIDGET (self->icon));
+    gtk_box_pack_start (self->container, GTK_WIDGET (self->icon), FALSE, FALSE, 0);
+}
+
+static void
+on_view_item_file_changed (GObject    *object,
+                           GParamSpec *pspec,
+                           gpointer    user_data)
+{
+    NautilusViewListItemUi *self = NAUTILUS_VIEW_LIST_ITEM_UI (user_data);
+    NautilusFile *file;
+
+    file = nautilus_view_item_model_get_file (self->model);
+
+    if (self->icon)
+    {
+        update_icon (self);
+    }
+
+    if (self->label)
+    {
+        gtk_label_set_text (self->label,
+                            nautilus_file_get_display_name (file));
+    }
+}
+
+static void
+on_view_item_size_changed (GObject    *object,
+                           GParamSpec *pspec,
+                           gpointer    user_data)
+{
+    NautilusViewListItemUi *self = NAUTILUS_VIEW_LIST_ITEM_UI (user_data);
+
+    if (self->icon)
+    {
+        update_icon (self);
+    }
+}
+
+static void
+constructed (GObject *object)
+{
+    NautilusViewListItemUi *self = NAUTILUS_VIEW_LIST_ITEM_UI (object);
+    GtkLabel *label;
+    GtkStyleContext *style_context;
+    NautilusFile *file;
+
+    G_OBJECT_CLASS (nautilus_view_list_item_ui_parent_class)->constructed (object);
+
+    file = nautilus_view_item_model_get_file (self->model);
+    self->container = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10));
+    gtk_widget_set_halign (GTK_WIDGET (self->container), GTK_ALIGN_START);
+
+    self->icon = create_icon (self);
+    gtk_box_pack_start (self->container, GTK_WIDGET (self->icon), FALSE, FALSE, 0);
+
+    label = GTK_LABEL (gtk_label_new (nautilus_file_get_display_name (file)));
+    gtk_widget_show (GTK_WIDGET (label));
+    gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_MIDDLE);
+    gtk_label_set_line_wrap (label, FALSE);
+    gtk_label_set_line_wrap_mode (label, PANGO_WRAP_WORD_CHAR);
+    gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
+    gtk_box_pack_end (self->container, GTK_WIDGET (label), TRUE, TRUE, 0);
+    gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->container));
+    gtk_widget_show_all (GTK_WIDGET (self->container));
+
+    style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+    gtk_style_context_add_class (style_context, "view-list-row");
+
+    g_signal_connect (self->model, "notify::icon-size",
+                      (GCallback) on_view_item_size_changed, self);
+    g_signal_connect (self->model, "notify::file",
+                      (GCallback) on_view_item_file_changed, self);
+}
+
+static void
+finalize (GObject *object)
+{
+    NautilusViewListItemUi *self = (NautilusViewListItemUi *) object;
+
+    g_signal_handlers_disconnect_by_data (self->model, self);
+    G_OBJECT_CLASS (nautilus_view_list_item_ui_parent_class)->finalize (object);
+}
+
+static void
+get_property (GObject    *object,
+              guint       prop_id,
+              GValue     *value,
+              GParamSpec *pspec)
+{
+    NautilusViewListItemUi *self = NAUTILUS_VIEW_LIST_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 (NautilusViewListItemUi *self,
+           NautilusViewItemModel  *model)
+{
+    self->model = g_object_ref (model);
+}
+
+static void
+set_property (GObject      *object,
+              guint         prop_id,
+              const GValue *value,
+              GParamSpec   *pspec)
+{
+    NautilusViewListItemUi *self = NAUTILUS_VIEW_LIST_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_list_item_ui_class_init (NautilusViewListItemUiClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = finalize;
+    object_class->get_property = get_property;
+    object_class->set_property = set_property;
+    object_class->constructed = constructed;
+
+    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 | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+nautilus_view_list_item_ui_init (NautilusViewListItemUi *self)
+{
+}
+
+NautilusViewListItemUi *
+nautilus_view_list_item_ui_new (NautilusViewItemModel *model)
+{
+    return g_object_new (NAUTILUS_TYPE_VIEW_LIST_ITEM_UI,
+                         "model", model,
+                         NULL);
+}
+
+NautilusViewItemModel *
+nautilus_view_list_item_ui_get_model (NautilusViewListItemUi *self)
+{
+    return self->model;
+}
diff --git a/src/nautilus-view-list-item-ui.h b/src/nautilus-view-list-item-ui.h
new file mode 100644
index 0000000..8572284
--- /dev/null
+++ b/src/nautilus-view-list-item-ui.h
@@ -0,0 +1,22 @@
+#ifndef NAUTILUS_VIEW_LIST_ITEM_UI_H
+#define NAUTILUS_VIEW_LIST_ITEM_UI_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "nautilus-view-item-model.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_VIEW_LIST_ITEM_UI (nautilus_view_list_item_ui_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusViewListItemUi, nautilus_view_list_item_ui, NAUTILUS, VIEW_LIST_ITEM_UI, 
GtkListBoxRow)
+
+NautilusViewListItemUi * nautilus_view_list_item_ui_new (NautilusViewItemModel *item_model);
+
+NautilusViewItemModel * nautilus_view_list_item_ui_get_model (NautilusViewListItemUi *self);
+
+G_END_DECLS
+
+#endif /* NAUTILUS_VIEW_LIST_ITEM_UI_H */
+
diff --git a/src/nautilus-view-list-ui.c b/src/nautilus-view-list-ui.c
new file mode 100644
index 0000000..7e5192e
--- /dev/null
+++ b/src/nautilus-view-list-ui.c
@@ -0,0 +1,233 @@
+/* nautilus-view-list-ui.c
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano gnome org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "nautilus-view-list-ui.h"
+#include "nautilus-view-list-item-ui.h"
+#include "nautilus-view-list-controller.h"
+#include "nautilus-files-view.h"
+#include "nautilus-file.h"
+#include "nautilus-directory.h"
+#include "nautilus-global-preferences.h"
+
+struct _NautilusViewListUi
+{
+    GtkListBox parent_instance;
+
+    NautilusViewListController *controller;
+};
+
+G_DEFINE_TYPE (NautilusViewListUi, nautilus_view_list_ui, GTK_TYPE_LIST_BOX)
+
+enum
+{
+    PROP_0,
+    PROP_CONTROLLER,
+    N_PROPS
+};
+
+static void
+set_controller (NautilusViewListUi         *self,
+                NautilusViewListController *controller)
+{
+    self->controller = controller;
+
+    g_object_notify (G_OBJECT (self), "controller");
+}
+
+static void
+get_property (GObject    *object,
+              guint       prop_id,
+              GValue     *value,
+              GParamSpec *pspec)
+{
+    NautilusViewListUi *self = NAUTILUS_VIEW_LIST_UI (object);
+
+    switch (prop_id)
+    {
+        case PROP_CONTROLLER:
+        {
+            g_value_set_object (value, self->controller);
+        }
+        break;
+
+        default:
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+    }
+}
+
+static void
+set_property (GObject      *object,
+              guint         prop_id,
+              const GValue *value,
+              GParamSpec   *pspec)
+{
+    NautilusViewListUi *self = NAUTILUS_VIEW_LIST_UI (object);
+
+    switch (prop_id)
+    {
+        case PROP_CONTROLLER:
+        {
+            set_controller (self, g_value_get_object (value));
+        }
+        break;
+
+        default:
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+    }
+}
+
+void
+nautilus_view_list_ui_set_selection (NautilusViewListUi *self,
+                                     GQueue             *selection)
+{
+    NautilusViewItemModel *item_model;
+    NautilusViewModel *model;
+    GListStore *gmodel;
+    gint i = 0;
+
+    model = nautilus_view_list_controller_get_model (self->controller);
+    gmodel = nautilus_view_model_get_g_model (model);
+    while ((item_model = NAUTILUS_VIEW_ITEM_MODEL (g_list_model_get_item (G_LIST_MODEL (gmodel), i))))
+    {
+        GtkWidget *item_ui;
+
+        item_ui = nautilus_view_item_model_get_item_ui (item_model);
+        if (g_queue_find (selection, item_model) != NULL)
+        {
+            gtk_list_box_select_row (GTK_LIST_BOX (self),
+                                     GTK_LIST_BOX_ROW (item_ui));
+        }
+        else
+        {
+            gtk_list_box_unselect_row (GTK_LIST_BOX (self),
+                                       GTK_LIST_BOX_ROW (item_ui));
+        }
+
+        i++;
+    }
+}
+
+
+static GtkWidget *
+create_widget_func (gpointer item,
+                    gpointer user_data)
+{
+    NautilusViewItemModel *item_model = NAUTILUS_VIEW_ITEM_MODEL (item);
+    NautilusViewListItemUi *child;
+
+    child = nautilus_view_list_item_ui_new (item_model);
+    nautilus_view_item_model_set_item_ui (item_model, GTK_WIDGET (child));
+    gtk_widget_show (GTK_WIDGET (child));
+
+    return GTK_WIDGET (child);
+}
+
+static void
+on_child_activated (GtkListBox      *list_box,
+                    GtkListBoxRow   *child,
+                    gpointer         user_data)
+{
+    NautilusViewListUi *self = NAUTILUS_VIEW_LIST_UI (user_data);
+    NautilusViewItemModel *item_model;
+    NautilusFile *file;
+    g_autoptr (GList) list = NULL;
+
+    item_model = nautilus_view_list_item_ui_get_model (NAUTILUS_VIEW_LIST_ITEM_UI (child));
+    file = nautilus_view_item_model_get_file (item_model);
+    list = g_list_append (list, file);
+
+    nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (self->controller), list, 0, TRUE);
+}
+
+static void
+on_ui_selected_children_changed (GtkListBox *box,
+                                 gpointer    user_data)
+{
+    NautilusViewListUi *self;
+
+    self = NAUTILUS_VIEW_LIST_UI (user_data);
+    nautilus_files_view_notify_selection_changed (NAUTILUS_FILES_VIEW (self->controller));
+}
+
+static void
+finalize (GObject *object)
+{
+    G_OBJECT_CLASS (nautilus_view_list_ui_parent_class)->finalize (object);
+}
+
+static void
+constructed (GObject *object)
+{
+    NautilusViewListUi *self = NAUTILUS_VIEW_LIST_UI (object);
+    NautilusViewModel *model;
+    GListStore *gmodel;
+
+    G_OBJECT_CLASS (nautilus_view_list_ui_parent_class)->constructed (object);
+
+    gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (self), FALSE);
+    gtk_list_box_set_selection_mode (GTK_LIST_BOX (self), GTK_SELECTION_MULTIPLE);
+    gtk_widget_set_valign (GTK_WIDGET (self), GTK_ALIGN_START);
+
+    model = nautilus_view_list_controller_get_model (self->controller);
+    gmodel = nautilus_view_model_get_g_model (model);
+    gtk_list_box_bind_model (GTK_LIST_BOX (self),
+                             G_LIST_MODEL (gmodel),
+                             create_widget_func, self, NULL);
+
+    g_signal_connect (self, "row-activated", (GCallback) on_child_activated, self);
+    g_signal_connect (self, "selected-rows-changed", (GCallback) on_ui_selected_children_changed, self);
+}
+
+static void
+nautilus_view_list_ui_class_init (NautilusViewListUiClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->constructed = constructed;
+
+    g_object_class_install_property (object_class,
+                                     PROP_CONTROLLER,
+                                     g_param_spec_object ("controller",
+                                                          "Controller",
+                                                          "The controller of the view",
+                                                          NAUTILUS_TYPE_VIEW_LIST_CONTROLLER,
+                                                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+nautilus_view_list_ui_init (NautilusViewListUi *self)
+{
+}
+
+NautilusViewListUi *
+nautilus_view_list_ui_new (NautilusViewListController *controller)
+{
+    return g_object_new (NAUTILUS_TYPE_VIEW_LIST_UI,
+                         "controller", controller,
+                         NULL);
+}
diff --git a/src/nautilus-view-list-ui.h b/src/nautilus-view-list-ui.h
new file mode 100644
index 0000000..25324c8
--- /dev/null
+++ b/src/nautilus-view-list-ui.h
@@ -0,0 +1,41 @@
+/* nautilus-view-list-ui.h
+ *
+ * Copyright (C) 2016 Carlos Soriano <csoriano gnome org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#ifndef NAUTILUS_VIEW_LIST_UI_H
+#define NAUTILUS_VIEW_LIST_UI_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "nautilus-view-list-controller.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_VIEW_LIST_UI (nautilus_view_list_ui_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusViewListUi, nautilus_view_list_ui, NAUTILUS, VIEW_LIST_UI, GtkListBox)
+
+NautilusViewListUi * nautilus_view_list_ui_new (NautilusViewListController *controller);
+/* TODO: this should become the "nautilus_view_set_selection" once we have a proper
+ * MVC also in the nautilus-view level. */
+void nautilus_view_list_ui_set_selection (NautilusViewListUi *self,
+                                          GQueue             *selection);
+
+G_END_DECLS
+
+#endif /* NAUTILUS_VIEW_LIST_UI_H */
+
diff --git a/src/resources/css/Adwaita.css b/src/resources/css/Adwaita.css
index a388917..e7be4f9 100644
--- a/src/resources/css/Adwaita.css
+++ b/src/resources/css/Adwaita.css
@@ -195,3 +195,6 @@ flowboxchild:selected > widget > box > .icon-background {background-color:black;
 flowboxchild > widget > .icon-item-background {padding:4px;}
 flowboxchild:selected > widget > .icon-item-background {padding:4px; background-color:#4a90d9; 
border-color:#4a90d9; border-style:solid; border-width:0px; border-radius:4px 4px 4px 4px;}
 
+/* List view */
+.view-list-row{border-bottom:1px solid rgba(0, 0, 0, 0.1); padding:5px;}
+


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