Trim trailing white spaces.
[geeqie.git] / src / view_file_list.c
index 90e464e..b0bd169 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Geeqie
  * (C) 2004 John Ellis
- * Copyright (C) 2008 The Geeqie Team
+ * Copyright (C) 2008 - 2012 The Geeqie Team
  *
  * Author: John Ellis
  *
 #include "main.h"
 #include "view_file_list.h"
 
+#include "bar.h"
 #include "cache_maint.h"
 #include "dnd.h"
 #include "editors.h"
 #include "img-view.h"
-#include "info.h"
 #include "layout.h"
 #include "layout_image.h"
 #include "menu.h"
+#include "metadata.h"
 #include "thumb.h"
 #include "utilops.h"
-#include "ui_bookmark.h"
 #include "ui_fileops.h"
 #include "ui_menu.h"
 #include "ui_tree_edit.h"
+#include "uri_utils.h"
 #include "view_file.h"
 
 #include <gdk/gdkkeysyms.h> /* for keyboard values */
 
-
+/* Index to tree store */
 enum {
        FILE_COLUMN_POINTER = 0,
        FILE_COLUMN_VERSION,
        FILE_COLUMN_THUMB,
+       FILE_COLUMN_FORMATTED,
        FILE_COLUMN_NAME,
        FILE_COLUMN_SIDECARS,
        FILE_COLUMN_SIZE,
        FILE_COLUMN_DATE,
+       FILE_COLUMN_EXPANDED,
        FILE_COLUMN_COLOR,
        FILE_COLUMN_MARKS,
        FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
@@ -47,10 +50,24 @@ enum {
 };
 
 
-static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
-static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
-static void vflist_populate_view(ViewFile *vf);
-static void vflist_notify_cb(FileData *fd, gpointer data);
+/* Index to tree view */
+enum {
+       FILE_VIEW_COLUMN_MARKS = 0,
+       FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
+       FILE_VIEW_COLUMN_THUMB,
+       FILE_VIEW_COLUMN_FORMATTED,
+       FILE_VIEW_COLUMN_SIZE,
+       FILE_VIEW_COLUMN_DATE,
+       FILE_VIEW_COLUMN_COUNT
+};
+
+
+
+static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd);
+static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
+static void vflist_populate_view(ViewFile *vf, gboolean force);
+static gboolean vflist_is_multiline(ViewFile *vf);
+static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded);
 
 
 /*
@@ -61,7 +78,7 @@ static void vflist_notify_cb(FileData *fd, gpointer data);
 typedef struct {
        FileData *fd;
        GtkTreeIter *iter;
-       gint found;
+       gboolean found;
        gint row;
 } ViewFileFindRowData;
 
@@ -73,7 +90,7 @@ static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTr
        if (fd == find->fd)
                {
                *find->iter = *iter;
-               find->found = 1;
+               find->found = TRUE;
                return TRUE;
                }
        find->row++;
@@ -83,7 +100,7 @@ static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTr
 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
 {
        GtkTreeModel *store;
-       ViewFileFindRowData data = {fd, iter, 0, 0};
+       ViewFileFindRowData data = {fd, iter, FALSE, 0};
 
        store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
        gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
@@ -96,54 +113,50 @@ static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
        return -1;
 }
 
-
-/*
-static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
+static FileData *vflist_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
 {
-       gint i = 0;
-       while (work)
-               {
-               FileData *fd_p = work->data;
-               if (fd == fd_p) return i;
+       GtkTreePath *tpath;
+       GtkTreeViewColumn *column;
 
-               i++;
+       if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
+                                         &tpath, &column, NULL, NULL))
+               {
+               GtkTreeModel *store;
+               GtkTreeIter row;
+               FileData *fd;
 
-               GList *work2 = fd_p->sidecar_files;
-               while (work2)
-                       {
-                       fd_p = work2->data;
-                       if (fd == fd_p) return i;
+               store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+               gtk_tree_model_get_iter(store, &row, tpath);
+               gtk_tree_path_free(tpath);
+               gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &fd, -1);
 
-                       i++;
-                       work2 = work2->next;
-                       }
-               work = work->next;
+               return fd;
                }
-       return -1;
+
+       return NULL;
 }
-*/
 
-static gint vflist_sidecar_list_count(GList *work)
+static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
 {
-       gint i = 0;
-       while (work)
-               {
-               FileData *fd = work->data;
-               i++;
+       FileData *fd;
+       gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
 
-               GList *work2 = fd->sidecar_files;
-               while (work2)
-                       {
-                       i++;
-                       work2 = work2->next;
-                       }
-               work = work->next;
-               }
-       return i;
+       /* it seems that gtk_tree_store_clear may call some callbacks
+          that use the column. Set the pointer to NULL to be safe. */
+       gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILE_COLUMN_POINTER, NULL, -1);
+       file_data_unref(fd);
+       return FALSE;
 }
 
+static void vflist_store_clear(ViewFile *vf)
+{
+       GtkTreeModel *store;
+       store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+       gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
+       gtk_tree_store_clear(GTK_TREE_STORE(store));
+}
 
-void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
+void vflist_color_set(ViewFile *vf, FileData *fd, gboolean color_set)
 {
        GtkTreeModel *store;
        GtkTreeIter iter;
@@ -166,27 +179,6 @@ static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
 }
 
 
-static gint vflist_column_idx(ViewFile *vf, gint store_idx)
-{
-       GList *columns, *work;
-       gint i = 0;
-
-       columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
-       work = columns;
-       while (work)
-               {
-               GtkTreeViewColumn *column = work->data;
-               if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
-                       break;
-               work = work->next;
-               i++;
-               }
-
-       g_list_free(columns);
-       return i;
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  * dnd
@@ -199,49 +191,40 @@ static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
 {
        ViewFile *vf = data;
        GList *list = NULL;
-       gchar *uri_text = NULL;
-       gint total;
 
-       if (!VFLIST_INFO(vf, click_fd)) return;
+       if (!VFLIST(vf)->click_fd) return;
 
-       if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+       if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
                {
                list = vf_selection_get_list(vf);
                }
        else
                {
-               list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
+               list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
                }
 
        if (!list) return;
-
-       uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
+       uri_selection_data_set_uris_from_filelist(selection_data, list);
        filelist_free(list);
-
-       DEBUG_1(uri_text);
-
-       gtk_selection_data_set(selection_data, selection_data->target,
-                              8, (guchar *)uri_text, total);
-       g_free(uri_text);
 }
 
 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
 {
        ViewFile *vf = data;
 
-       vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
+       vflist_color_set(vf, VFLIST(vf)->click_fd, TRUE);
 
-       if (VFLIST_INFO(vf, thumbs_enabled) &&
-           VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->pixbuf)
+       if (VFLIST(vf)->thumbs_enabled &&
+           VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
                {
                guint items;
 
-               if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+               if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
                        items = vf_selection_count(vf, NULL);
                else
                        items = 1;
 
-               dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->pixbuf, items);
+               dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
                }
 }
 
@@ -249,25 +232,52 @@ static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer
 {
        ViewFile *vf = data;
 
-       vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+       vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
 
-       if (context->action == GDK_ACTION_MOVE)
+       if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
                {
                vf_refresh(vf);
                }
 }
 
+static void vflist_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
+                                     int x, int y, GtkSelectionData *selection,
+                                     guint info, guint time, gpointer data)
+{
+       ViewFile *vf = data;
+
+       if (info == TARGET_TEXT_PLAIN) {
+               FileData *fd = vflist_find_data_by_coord(vf, x, y, NULL);
+
+               if (fd) {
+                       /* Add keywords to file */
+                       gchar *str = (gchar *) gtk_selection_data_get_text(selection);
+                       GList *kw_list = string_to_keywords_list(str);
+                       
+                       metadata_append_list(fd, KEYWORD_KEY, kw_list);
+                       string_list_free(kw_list);
+                       g_free(str);
+               }
+       }
+}
+
 void vflist_dnd_init(ViewFile *vf)
 {
        gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
                            dnd_file_drag_types, dnd_file_drag_types_count,
                            GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+       gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
+                           dnd_file_drag_types, dnd_file_drag_types_count,
+                           GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+
        g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
                         G_CALLBACK(vflist_dnd_get), vf);
        g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
                         G_CALLBACK(vflist_dnd_begin), vf);
        g_signal_connect(G_OBJECT(vf->listview), "drag_end",
                         G_CALLBACK(vflist_dnd_end), vf);
+       g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
+                        G_CALLBACK(vflist_drag_data_received), vf);
 }
 
 /*
@@ -276,23 +286,58 @@ void vflist_dnd_init(ViewFile *vf)
  *-----------------------------------------------------------------------------
  */
 
+GList *vflist_selection_get_one(ViewFile *vf, FileData *fd)
+{
+       GList *list = g_list_append(NULL, file_data_ref(fd));
+
+       if (fd->sidecar_files)
+               {
+               /* check if the row is expanded */
+               GtkTreeModel *store;
+               GtkTreeIter iter;
+               
+               store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+               if (vflist_find_row(vf, fd, &iter) >= 0)
+                       {
+                       GtkTreePath *tpath;
+
+                       tpath = gtk_tree_model_get_path(store, &iter);
+                       if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
+                               {
+                               /* unexpanded - add whole group */
+                               GList *work = fd->sidecar_files;
+                               while (work)
+                                       {
+                                       FileData *sfd = work->data;
+                                       list = g_list_prepend(list, file_data_ref(sfd));
+                                       work = work->next;
+                                       }
+                               }
+                       gtk_tree_path_free(tpath);
+                       }
+               list = g_list_reverse(list);
+               }
+
+       return list;
+}
+
 GList *vflist_pop_menu_file_list(ViewFile *vf)
 {
-       if (!VFLIST_INFO(vf, click_fd)) return NULL;
+       if (!VFLIST(vf)->click_fd) return NULL;
 
-       if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+       if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
                {
                return vf_selection_get_list(vf);
                }
-
-       return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
+       return vflist_selection_get_one(vf, VFLIST(vf)->click_fd);
 }
 
+
 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
 {
        ViewFile *vf = data;
 
-       if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+       if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
                {
                GList *list;
 
@@ -302,7 +347,7 @@ void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
                }
        else
                {
-               view_window_new(VFLIST_INFO(vf, click_fd));
+               view_window_new(VFLIST(vf)->click_fd);
                }
 }
 
@@ -313,7 +358,7 @@ void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
 
        list = vf_pop_menu_file_list(vf);
        if (options->file_ops.enable_in_place_rename &&
-           list && !list->next && VFLIST_INFO(vf, click_fd))
+           list && !list->next && VFLIST(vf)->click_fd)
                {
                GtkTreeModel *store;
                GtkTreeIter iter;
@@ -321,13 +366,13 @@ void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
                filelist_free(list);
 
                store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-               if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
+               if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
                        {
                        GtkTreePath *tpath;
 
                        tpath = gtk_tree_model_get_path(store, &iter);
                        tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
-                                         vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
+                                         FILE_VIEW_COLUMN_FORMATTED, VFLIST(vf)->click_fd->name,
                                          vflist_row_rename_cb, vf);
                        gtk_tree_path_free(tpath);
                        }
@@ -341,14 +386,14 @@ void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
 {
        ViewFile *vf = data;
 
-       vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+       vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
        if (vf->layout)
                {
-               layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
+               layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
                }
        else
                {
-               vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
+               vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
                }
 }
 
@@ -356,15 +401,16 @@ void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
 {
        ViewFile *vf = data;
 
-       vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+       vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
        vf_refresh(vf);
+       gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
 }
 
 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
 {
        ViewFile *vf = data;
-       vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
-       VFLIST_INFO(vf, click_fd) = NULL;
+       vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
+       VFLIST(vf)->click_fd = NULL;
        vf->popup = NULL;
 }
 
@@ -375,15 +421,13 @@ void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
  *-----------------------------------------------------------------------------
  */
 
-static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
+static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
 {
        ViewFile *vf = data;
-       gchar *old_path;
        gchar *new_path;
 
-       if (strlen(new) == 0) return FALSE;
+       if (!new || !new[0]) return FALSE;
 
-       old_path = g_build_filename(vf->dir_fd->path, old, NULL);
        new_path = g_build_filename(vf->dir_fd->path, new, NULL);
 
        if (strchr(new, G_DIR_SEPARATOR) != NULL)
@@ -392,26 +436,15 @@ static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar
                file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
                g_free(text);
                }
-       else if (isfile(new_path))
-               {
-               gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
-               file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
-               g_free(text);
-               }
        else
                {
-               gint row = vf_index_by_path(vf, old_path);
-               if (row >= 0)
-                       {
-                       GList *work = g_list_nth(vf->list, row);
-                       FileData *fd = work->data;
-                       
-                       file_util_rename_simple(fd, new_path, vf->listview);
-
-                       }
-
+               gchar *old_path = g_build_filename(vf->dir_fd->path, old, NULL);
+               FileData *fd = file_data_new_group(old_path); /* get the fd from cache */
+               file_util_rename_simple(fd, new_path, vf->listview);
+               file_data_unref(fd);
+               g_free(old_path);
                }
-       g_free(old_path);
+       
        g_free(new_path);
 
        return FALSE;
@@ -425,7 +458,7 @@ static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *p
        GtkTreePath *tpath;
        gint cw, ch;
 
-       if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
+       if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
        store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
        tpath = gtk_tree_model_get_path(store, &iter);
        tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
@@ -434,12 +467,12 @@ static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *p
        popup_menu_position_clamp(menu, x, y, 0);
 }
 
-gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
+gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
 {
        ViewFile *vf = data;
        GtkTreePath *tpath;
 
-       if (event->keyval != GDK_Menu) return FALSE;
+       if (event->keyval != GDK_KEY_Menu) return FALSE;
 
        gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
        if (tpath)
@@ -449,12 +482,12 @@ gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
 
                store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
                gtk_tree_model_get_iter(store, &iter, tpath);
-               gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
+               gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
                gtk_tree_path_free(tpath);
                }
        else
                {
-               VFLIST_INFO(vf, click_fd) = NULL;
+               VFLIST(vf)->click_fd = NULL;
                }
 
        vf->popup = vf_pop_menu(vf);
@@ -463,7 +496,7 @@ gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
        return TRUE;
 }
 
-gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
 {
        ViewFile *vf = data;
        GtkTreePath *tpath;
@@ -490,13 +523,10 @@ gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
 
                gtk_tree_model_get_iter(store, &iter, tpath);
                gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-#if 0
-               gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
-#endif
                gtk_tree_path_free(tpath);
                }
 
-       VFLIST_INFO(vf, click_fd) = fd;
+       VFLIST(vf)->click_fd = fd;
 
        if (bevent->button == MOUSE_BUTTON_RIGHT)
                {
@@ -528,7 +558,7 @@ gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
                gtk_widget_grab_focus(widget);
 
 
-               /* returning FALSE and further processing of the event is needed for 
+               /* returning FALSE and further processing of the event is needed for
                   correct operation of the expander, to show the sidecar files.
                   It however resets the selection of multiple files. With this condition
                   it should work for both cases */
@@ -536,17 +566,15 @@ gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
                return (gtk_tree_selection_count_selected_rows(selection) > 1);
                }
 
-#if 0
        if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
                {
                if (vf->layout) layout_image_full_screen_start(vf->layout);
                }
-#endif
 
        return FALSE;
 }
 
-gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
 {
        ViewFile *vf = data;
        GtkTreePath *tpath;
@@ -555,7 +583,7 @@ gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
 
        if (bevent->button == MOUSE_BUTTON_MIDDLE)
                {
-               vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+               vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
                }
 
        if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
@@ -577,7 +605,7 @@ gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
 
        if (bevent->button == MOUSE_BUTTON_MIDDLE)
                {
-               if (fd && VFLIST_INFO(vf, click_fd) == fd)
+               if (fd && VFLIST(vf)->click_fd == fd)
                        {
                        GtkTreeSelection *selection;
 
@@ -594,7 +622,7 @@ gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
                return TRUE;
                }
 
-       if (fd && VFLIST_INFO(vf, click_fd) == fd &&
+       if (fd && VFLIST(vf)->click_fd == fd &&
            !(bevent->state & GDK_SHIFT_MASK ) &&
            !(bevent->state & GDK_CONTROL_MASK ) &&
            vflist_row_is_selected(vf, fd))
@@ -605,7 +633,6 @@ gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
                gtk_tree_selection_unselect_all(selection);
                gtk_tree_selection_select_iter(selection, &iter);
                vflist_move_cursor(vf, &iter);
-//             return TRUE;// FIXME - expand
                }
 
        return FALSE;
@@ -616,6 +643,7 @@ static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
        FileData *read_ahead_fd = NULL;
        gint row;
        FileData *cur_fd;
+
        if (!sel_fd) return;
 
        cur_fd = layout_image_get_fd(vf->layout);
@@ -640,32 +668,35 @@ static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
        layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
 }
 
-static gint vflist_select_idle_cb(gpointer data)
+static gboolean vflist_select_idle_cb(gpointer data)
 {
        ViewFile *vf = data;
 
        if (!vf->layout)
                {
-               VFLIST_INFO(vf, select_idle_id) = -1;
+               VFLIST(vf)->select_idle_id = 0;
                return FALSE;
                }
 
        vf_send_update(vf);
 
-       if (VFLIST_INFO(vf, select_fd))
+       if (VFLIST(vf)->select_fd)
                {
-               vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
-               VFLIST_INFO(vf, select_fd) = NULL;
+               vflist_select_image(vf, VFLIST(vf)->select_fd);
+               VFLIST(vf)->select_fd = NULL;
                }
 
-       VFLIST_INFO(vf, select_idle_id) = -1;
+       VFLIST(vf)->select_idle_id = 0;
        return FALSE;
 }
 
 static void vflist_select_idle_cancel(ViewFile *vf)
 {
-       if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
-       VFLIST_INFO(vf, select_idle_id) = -1;
+       if (VFLIST(vf)->select_idle_id)
+               {
+               g_source_remove(VFLIST(vf)->select_idle_id);
+               VFLIST(vf)->select_idle_id = 0;
+               }
 }
 
 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
@@ -677,67 +708,153 @@ static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *stor
        if (!path_currently_selected &&
            gtk_tree_model_get_iter(store, &iter, tpath))
                {
-               gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
+               gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
                }
        else
                {
-               VFLIST_INFO(vf, select_fd) = NULL;
+               VFLIST(vf)->select_fd = NULL;
                }
 
        if (vf->layout &&
-           VFLIST_INFO(vf, select_idle_id) == -1)
+           !VFLIST(vf)->select_idle_id)
                {
-               VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
+               VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
                }
 
        return TRUE;
 }
 
+static void vflist_expand_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
+{
+       ViewFile *vf = data;
+       vflist_set_expanded(vf, iter, TRUE);
+}
+
+static void vflist_collapse_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
+{
+       ViewFile *vf = data;
+       vflist_set_expanded(vf, iter, FALSE);
+}
+
 /*
  *-----------------------------------------------------------------------------
  * misc
  *-----------------------------------------------------------------------------
  */
 
-/*
-static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
-                                       gboolean path_currently_selected, gpointer data)
+
+static gchar* vflist_get_formatted(ViewFile *vf, const gchar *name, const gchar *sidecars, const gchar *size, const gchar *time, gboolean expanded)
+ {
+       gboolean multiline = vflist_is_multiline(vf);
+       gchar *text;
+
+       if (multiline)
+               {
+               text = g_strdup_printf("%s %s\n%s\n%s", name, expanded ? "" : sidecars, size, time);
+               }
+       else
+               {
+               text = g_strdup_printf("%s %s", name, expanded ? "" : sidecars);
+               }
+       return text;
+}
+
+static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded)
 {
-       return TRUE;
+       GtkTreeStore *store;
+       gchar *name;
+       gchar *sidecars;
+       gchar *size;
+       gchar *time;
+       gchar *formatted;
+
+       store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+
+       gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
+                                       FILE_COLUMN_NAME, &name,
+                                       FILE_COLUMN_SIDECARS, &sidecars,
+                                       FILE_COLUMN_SIZE, &size,
+                                       FILE_COLUMN_DATE, &time,
+                                       -1);
+       formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
+
+       gtk_tree_store_set(store, iter, FILE_COLUMN_FORMATTED, formatted,
+                                       FILE_COLUMN_EXPANDED, expanded,
+                                       -1);
+       g_free(time);
+       g_free(size);
+       g_free(sidecars);
+       g_free(name);
+       g_free(formatted);
 }
-*/
 
 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
 {
-       int i;
        gchar *size;
        gchar *sidecars = NULL;
+       gchar *name;
+       const gchar *time = text_from_time(fd->date);
+       gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
+       const gchar *disabled_grouping;
+       gchar *formatted;
+       gboolean expanded = FALSE;
+       
+       if (fd->sidecar_files) /* expanded has no effect on files without sidecars */
+               {
+               gtk_tree_model_get(GTK_TREE_MODEL(store), iter, FILE_COLUMN_EXPANDED, &expanded, -1);
+               }
 
-       if (fd->sidecar_files)
-               sidecars = file_data_sc_list_to_string(fd);
-       size = text_from_size(fd->size);
+       sidecars = file_data_sc_list_to_string(fd);
 
+       disabled_grouping = fd->disable_grouping ? _(" [NO GROUPING]") : "";
+       name = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping);
+       size = text_from_size(fd->size);
+       
+       formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
+       
        gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
                                        FILE_COLUMN_VERSION, fd->version,
-                                       FILE_COLUMN_THUMB, (VFLIST_INFO(vf, thumbs_enabled)) ? fd->pixbuf : NULL,
-                                       FILE_COLUMN_NAME, fd->name,
+                                       FILE_COLUMN_THUMB, fd->thumb_pixbuf,
+                                       FILE_COLUMN_FORMATTED, formatted,
                                        FILE_COLUMN_SIDECARS, sidecars,
+                                       FILE_COLUMN_NAME, name,
                                        FILE_COLUMN_SIZE, size,
-                                       FILE_COLUMN_DATE, text_from_time(fd->date),
+                                       FILE_COLUMN_DATE, time,
+#define STORE_SET_IS_SLOW 1
+#if STORE_SET_IS_SLOW
+/* this is 3x faster on a directory with 20000 files */
+                                       FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
+                                       FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
+                                       FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
+                                       FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
+                                       FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
+                                       FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
+#if FILEDATA_MARKS_SIZE != 6
+#error this needs to be updated
+#endif
+#endif
                                        FILE_COLUMN_COLOR, FALSE, -1);
-       for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
-               gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, fd->marks[i], -1);
 
+#if !STORE_SET_IS_SLOW
+       {
+       gint i;
+       for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
+               gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
+       }
+#endif
        g_free(size);
-       if (sidecars)
-               g_free(sidecars);
+       g_free(sidecars);
+       g_free(name);
+       g_free(formatted);
 }
 
-static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
+static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected, gboolean force)
 {
        GList *work;
        GtkTreeIter iter;
-       gint valid;
+       gboolean valid;
+       gint num_ordered = 0;
+       gint num_prepended = 0;
 
        valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
 
@@ -746,7 +863,7 @@ static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTr
                {
                gint match;
                FileData *fd = work->data;
-               gint done = FALSE;
+               gboolean done = FALSE;
 
                while (!done)
                        {
@@ -786,15 +903,21 @@ static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTr
 
                                if (valid)
                                        {
+                                       num_ordered++;
                                        gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
                                        }
                                else
                                        {
-                                       gtk_tree_store_append(store, &new, parent_iter);
+                                       /*
+                                           here should be used gtk_tree_store_append, but this function seems to be O(n)
+                                           and it seems to be much faster to add new entries to the beginning and reorder later
+                                       */
+                                       num_prepended++;
+                                       gtk_tree_store_prepend(store, &new, parent_iter);
                                        }
 
-                               vflist_setup_iter(vf, store, &new, fd);
-                               vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
+                               vflist_setup_iter(vf, store, &new, file_data_ref(fd));
+                               vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected, force);
                                
                                if (g_list_find(selected, fd))
                                        {
@@ -808,14 +931,16 @@ static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTr
                                }
                        else if (match > 0)
                                {
+                               file_data_unref(old_fd);
                                valid = gtk_tree_store_remove(store, &iter);
                                }
                        else
                                {
-                               if (fd->version != old_version)
+                               num_ordered++;
+                               if (fd->version != old_version || force)
                                        {
                                        vflist_setup_iter(vf, store, &iter, fd);
-                                       vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
+                                       vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected, force);
                                        }
 
                                if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
@@ -828,11 +953,34 @@ static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTr
 
        while (valid)
                {
+               FileData *old_fd;
+               gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
+               file_data_unref(old_fd);
+
                valid = gtk_tree_store_remove(store, &iter);
                }
+               
+       /* move the prepended entries to the correct position */
+       if (num_prepended)
+               {
+               gint i;
+               gint num_total = num_prepended + num_ordered;
+               gint *new_order = g_malloc(num_total * sizeof(gint));
+               
+               for (i = 0; i < num_total; i++)
+                       {
+                       if (i < num_ordered)
+                               new_order[i] = num_prepended + i;
+                       else
+                               new_order[i] = num_total - 1 - i;
+                       }
+               gtk_tree_store_reorder(store, parent_iter, new_order);
+
+               g_free(new_order);
+               }
 }
 
-void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
+void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend)
 {
        gint i;
        GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
@@ -883,96 +1031,60 @@ void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
  *-----------------------------------------------------------------------------
  */
 
-static gint vflist_thumb_next(ViewFile *vf);
 
-static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
+void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
 {
-       if (vf->func_thumb_status)
+       GList *work = list;
+       while (work)
                {
-               vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
-               }
-}
-
-static void vflist_thumb_cleanup(ViewFile *vf)
-{
-       vflist_thumb_status(vf, 0.0, NULL);
-
-       vf->thumbs_count = 0;
-       vf->thumbs_running = FALSE;
-
-       thumb_loader_free(vf->thumbs_loader);
-       vf->thumbs_loader = NULL;
-
-       vf->thumbs_filedata = NULL;
-}
+               FileData *fd = work->data;
+               work = work->next;
 
-static void vflist_thumb_stop(ViewFile *vf)
-{
-       if (vf->thumbs_running) vflist_thumb_cleanup(vf);
+               if (fd->thumb_pixbuf) (*done)++;
+               
+               if (fd->sidecar_files)
+                       {
+                       vflist_thumb_progress_count(fd->sidecar_files, count, done);
+                       }
+               (*count)++;
+               }
 }
 
-static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
+void vflist_set_thumb_fd(ViewFile *vf, FileData *fd)
 {
        GtkTreeStore *store;
        GtkTreeIter iter;
 
        if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
 
-       if (fd->pixbuf) g_object_unref(fd->pixbuf);
-       fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
-
        store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-       gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
-
-       vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
+       gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
 }
 
-static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
-{
-       ViewFile *vf = data;
-
-       if (vf->thumbs_filedata && vf->thumbs_loader == tl)
-               {
-               vflist_thumb_do(vf, tl, vf->thumbs_filedata);
-               }
-
-       while (vflist_thumb_next(vf));
-}
-
-static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
-{
-       ViewFile *vf = data;
-
-       if (vf->thumbs_filedata && vf->thumbs_loader == tl)
-               {
-               vflist_thumb_do(vf, tl, vf->thumbs_filedata);
-               }
-
-       while (vflist_thumb_next(vf));
-}
-
-static gint vflist_thumb_next(ViewFile *vf)
+FileData *vflist_thumb_next_fd(ViewFile *vf)
 {
        GtkTreePath *tpath;
        FileData *fd = NULL;
 
        /* first check the visible files */
 
-       if (GTK_WIDGET_REALIZED(vf->listview) &&
-           gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
+       if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
                {
                GtkTreeModel *store;
                GtkTreeIter iter;
-               gint valid = TRUE;
-
+               gboolean valid = TRUE;
+       
                store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
                gtk_tree_model_get_iter(store, &iter, tpath);
                gtk_tree_path_free(tpath);
 
                while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
                        {
-                       gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-                       if (fd->pixbuf) fd = NULL;
+                       FileData *nfd;
+
+                       gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &nfd, -1);
+
+                       if (!nfd->thumb_pixbuf) fd = nfd;
 
                        valid = gtk_tree_model_iter_next(store, &iter);
                        }
@@ -986,7 +1098,7 @@ static gint vflist_thumb_next(ViewFile *vf)
                while (work && !fd)
                        {
                        FileData *fd_p = work->data;
-                       if (!fd_p->pixbuf)
+                       if (!fd_p->thumb_pixbuf)
                                fd = fd_p;
                        else
                                {
@@ -995,7 +1107,7 @@ static gint vflist_thumb_next(ViewFile *vf)
                                while (work2 && !fd)
                                        {
                                        fd_p = work2->data;
-                                       if (!fd_p->pixbuf) fd = fd_p;
+                                       if (!fd_p->thumb_pixbuf) fd = fd_p;
                                        work2 = work2->next;
                                        }
                                }
@@ -1003,47 +1115,23 @@ static gint vflist_thumb_next(ViewFile *vf)
                        }
                }
 
-       if (!fd)
-               {
-               /* done */
-               vflist_thumb_cleanup(vf);
-               return FALSE;
-               }
-
-       vf->thumbs_count++;
-
-       vf->thumbs_filedata = fd;
-
-       thumb_loader_free(vf->thumbs_loader);
+       return fd;
+}
 
-       vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
-       thumb_loader_set_callbacks(vf->thumbs_loader,
-                                  vflist_thumb_done_cb,
-                                  vflist_thumb_error_cb,
-                                  NULL,
-                                  vf);
 
-       if (!thumb_loader_start(vf->thumbs_loader, fd->path))
+void vflist_thumb_reset_all(ViewFile *vf)
+{
+       GList *work = vf->list;
+       while (work)
                {
-               /* set icon to unknown, continue */
-               DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
-               vflist_thumb_do(vf, vf->thumbs_loader, fd);
-
-               return TRUE;
+               FileData *fd = work->data;
+               if (fd->thumb_pixbuf)
+                       {
+                       g_object_unref(fd->thumb_pixbuf);
+                       fd->thumb_pixbuf = NULL;
+                       }
+               work = work->next;
                }
-
-       return FALSE;
-}
-
-static void vflist_thumb_update(ViewFile *vf)
-{
-       vflist_thumb_stop(vf);
-       if (!VFLIST_INFO(vf, thumbs_enabled)) return;
-
-       vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
-       vf->thumbs_running = TRUE;
-
-       while (vflist_thumb_next(vf));
 }
 
 /*
@@ -1057,18 +1145,28 @@ FileData *vflist_index_get_data(ViewFile *vf, gint row)
        return g_list_nth_data(vf->list, row);
 }
 
-gint vflist_index_by_path(ViewFile *vf, const gchar *path)
+gint vflist_index_by_fd(ViewFile *vf, FileData *fd)
 {
        gint p = 0;
-       GList *work;
-
-       if (!path) return -1;
+       GList *work, *work2;
 
        work = vf->list;
        while (work)
                {
-               FileData *fd = work->data;
-               if (strcmp(path, fd->path) == 0) return p;
+               FileData *list_fd = work->data;
+               if (list_fd == fd) return p;
+               
+               work2 = list_fd->sidecar_files;
+               while (work2)
+                       {
+                       /* FIXME: return the same index also for sidecars
+                          it is sufficient for next/prev navigation but it should be rewritten
+                          without using indexes at all
+                       */
+                       FileData *sidecar_fd = work2->data;
+                       if (sidecar_fd == fd) return p;
+                       work2 = work2->next;
+                       }
                
                work = work->next;
                p++;
@@ -1121,13 +1219,13 @@ GList *vflist_get_list(ViewFile *vf)
  *-----------------------------------------------------------------------------
  */
 
-static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
+static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd)
 {
        GtkTreeModel *store;
        GtkTreeSelection *selection;
        GList *slist;
        GList *work;
-       gint found = FALSE;
+       gboolean found = FALSE;
 
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
        slist = gtk_tree_selection_get_selected_rows(selection, &store);
@@ -1149,7 +1247,7 @@ static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
        return found;
 }
 
-gint vflist_index_is_selected(ViewFile *vf, gint row)
+gboolean vflist_index_is_selected(ViewFile *vf, gint row)
 {
        FileData *fd;
 
@@ -1217,6 +1315,18 @@ GList *vflist_selection_get_list(ViewFile *vf)
                gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
 
                list = g_list_prepend(list, file_data_ref(fd));
+               
+               if (!fd->parent && !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
+                       {
+                       /* unexpanded - add whole group */
+                       GList *work2 = fd->sidecar_files;
+                       while (work2)
+                               {
+                               FileData *sfd = work2->data;
+                               list = g_list_prepend(list, file_data_ref(sfd));
+                               work2 = work2->next;
+                               }
+                       }
 
                work = work->next;
                }
@@ -1263,7 +1373,7 @@ void vflist_select_all(ViewFile *vf)
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
        gtk_tree_selection_select_all(selection);
 
-       VFLIST_INFO(vf, select_fd) = NULL;
+       VFLIST(vf)->select_fd = NULL;
 }
 
 void vflist_select_none(ViewFile *vf)
@@ -1323,7 +1433,7 @@ void vflist_select_invert(ViewFile *vf)
 
        while (valid)
                {
-               gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
+               gboolean selected = gtk_tree_selection_iter_is_selected(selection, &iter);
 
                if (selected)
                        gtk_tree_selection_unselect_iter(selection, &iter);
@@ -1363,6 +1473,7 @@ void vflist_select_by_fd(ViewFile *vf, FileData *fd)
 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
 {
        GList *work;
+       FileData *fd = NULL;
        
        if (sel_fd->parent) sel_fd = sel_fd->parent;
        work = vf->list;
@@ -1370,19 +1481,16 @@ static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
        while (work)
                {
                gint match;
-               FileData *fd = work->data;
+               fd = work->data;
                work = work->next;
-               
 
                match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
                
-               if (match >= 0)
-                       {
-                       vflist_select_by_fd(vf, fd);
-                       break;
-                       }
+               if (match >= 0) break;
                }
 
+       if (fd) vflist_select_by_fd(vf, fd);
+
 }
 
 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
@@ -1390,7 +1498,7 @@ void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
        GtkTreeModel *store;
        GtkTreeIter iter;
        GtkTreeSelection *selection;
-       gint valid;
+       gboolean valid;
        gint n = mark - 1;
 
        g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
@@ -1405,18 +1513,18 @@ void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
                gboolean mark_val, selected;
                gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
 
-               mark_val = fd->marks[n];
+               mark_val = file_data_get_mark(fd, n);
                selected = gtk_tree_selection_iter_is_selected(selection, &iter);
 
                switch (mode)
                        {
                        case MTS_MODE_SET: selected = mark_val;
                                break;
-                       case MTS_MODE_OR: selected = mark_val | selected;
+                       case MTS_MODE_OR: selected = mark_val || selected;
                                break;
-                       case MTS_MODE_AND: selected = mark_val & selected;
+                       case MTS_MODE_AND: selected = mark_val && selected;
                                break;
-                       case MTS_MODE_MINUS: selected = !mark_val & selected;
+                       case MTS_MODE_MINUS: selected = !mark_val && selected;
                                break;
                        }
 
@@ -1451,21 +1559,34 @@ void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
                gtk_tree_model_get_iter(store, &iter, tpath);
                gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
 
+               /* the change has a very limited range and the standard notification would trigger
+                  complete re-read of the directory - try to do only minimal update instead */
+               file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
+
                switch (mode)
                        {
-                       case STM_MODE_SET: fd->marks[n] = 1;
+                       case STM_MODE_SET: file_data_set_mark(fd, n, 1);
                                break;
-                       case STM_MODE_RESET: fd->marks[n] = 0;
+                       case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
                                break;
-                       case STM_MODE_TOGGLE: fd->marks[n] = !fd->marks[n];
+                       case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
                                break;
                        }
                
-               file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification */
-               file_data_increment_version(fd);
-               file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+               if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
+                       {
+                       vf_refresh_idle(vf);
+                       }
+               else
+                       {
+                       /* mark functions can have various side effects - update all columns to be sure */
+                       vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
+                       /* mark functions can change sidecars too */
+                       vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
+                       }
 
-               gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, fd->marks[n], -1);
+               
+               file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
 
                work = work->next;
                }
@@ -1479,86 +1600,82 @@ void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
  *-----------------------------------------------------------------------------
  */
 
-static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
+static void vflist_listview_set_columns(GtkWidget *listview, gboolean thumb, gboolean multiline)
 {
        GtkTreeViewColumn *column;
        GtkCellRenderer *cell;
        GList *list;
 
-       column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
+       column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
        if (!column) return;
 
-       gtk_tree_view_column_set_fixed_width(column, ((thumb) ? options->thumbnails.max_width : 4) + 10);
+       gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
 
-       list = gtk_tree_view_column_get_cell_renderers(column);
+       list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
        if (!list) return;
        cell = list->data;
        g_list_free(list);
 
-       g_object_set(G_OBJECT(cell), "height", (thumb) ? options->thumbnails.max_height : -1, NULL);
-       gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
+       g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
+       gtk_tree_view_column_set_visible(column, thumb);
+
+       column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_FORMATTED);
+       if (!column) return;
+       gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
+
+       column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
+       if (!column) return;
+       gtk_tree_view_column_set_visible(column, !multiline);
+
+       column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
+       if (!column) return;
+       gtk_tree_view_column_set_visible(column, !multiline);
+}
+
+static gboolean vflist_is_multiline(ViewFile *vf)
+{
+       return (VFLIST(vf)->thumbs_enabled && options->thumbnails.max_height >= 48);
 }
 
-static void vflist_populate_view(ViewFile *vf)
+
+static void vflist_populate_view(ViewFile *vf, gboolean force)
 {
        GtkTreeStore *store;
-       gint thumbs;
-       GtkTreeRowReference *visible_row = NULL;
-       GtkTreePath *tpath;
        GList *selected;
 
        store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-       thumbs = VFLIST_INFO(vf, thumbs_enabled);
 
-       vflist_thumb_stop(vf);
+       vf_thumb_stop(vf);
 
        if (!vf->list)
                {
-               gtk_tree_store_clear(store);
+               vflist_store_clear(vf);
                vf_send_update(vf);
                return;
                }
 
-       if (GTK_WIDGET_REALIZED(vf->listview) &&
-           gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
-               {
-               visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
-               gtk_tree_path_free(tpath);
-               }
-
-       vflist_listview_set_height(vf->listview, thumbs);
+       vflist_listview_set_columns(vf->listview, VFLIST(vf)->thumbs_enabled, vflist_is_multiline(vf));
 
        selected = vflist_selection_get_list(vf);
        
-       vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
+       vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected, force);
 
        if (selected && vflist_selection_count(vf, NULL) == 0)
                {
                /* all selected files disappeared */
                vflist_select_closest(vf, selected->data);
-               }       
+               }
 
        filelist_free(selected);
        
-       if (visible_row)
-               {
-               if (gtk_tree_row_reference_valid(visible_row))
-                       {
-                       tpath = gtk_tree_row_reference_get_path(visible_row);
-                       gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
-                       gtk_tree_path_free(tpath);
-                       }
-               gtk_tree_row_reference_free(visible_row);
-               }
-
        vf_send_update(vf);
-       vflist_thumb_update(vf);
+       vf_thumb_update(vf);
 }
 
-gint vflist_refresh(ViewFile *vf)
+gboolean vflist_refresh(ViewFile *vf)
 {
        GList *old_list;
-       gint ret = TRUE;
+       gboolean ret = TRUE;
 
        old_list = vf->list;
        vf->list = NULL;
@@ -1566,11 +1683,11 @@ gint vflist_refresh(ViewFile *vf)
        DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
        if (vf->dir_fd)
                {
-               file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
+               file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
 
                ret = filelist_read(vf->dir_fd, &vf->list, NULL);
-
-               file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+               vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
+               file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
 
                DEBUG_1("%s vflist_refresh: sort", get_exec_time());
                vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
@@ -1578,7 +1695,7 @@ gint vflist_refresh(ViewFile *vf)
 
        DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
 
-       vflist_populate_view(vf);
+       vflist_populate_view(vf, FALSE);
 
        filelist_free(old_list);
        DEBUG_1("%s vflist_refresh: done", get_exec_time());
@@ -1586,20 +1703,6 @@ gint vflist_refresh(ViewFile *vf)
        return ret;
 }
 
-static gint vflist_refresh_idle_cb(gpointer data)
-{
-       ViewFile *vf = data;
-
-       vflist_refresh(vf);
-       vf->refresh_idle_id = -1;
-       return FALSE;
-}
-
-static void vflist_refresh_idle_cancel(ViewFile *vf)
-{
-       if (vf->refresh_idle_id != -1) g_source_remove(vf->refresh_idle_id);
-       vf->refresh_idle_id = -1;
-}
 
 
 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
@@ -1650,7 +1753,7 @@ static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRend
                     "cell-background-set", set, NULL);
 }
 
-static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
+static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gboolean image, gboolean right_justify, gboolean expand)
 {
        GtkTreeViewColumn *column;
        GtkCellRenderer *renderer;
@@ -1695,25 +1798,37 @@ static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *
        GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
        GtkTreeIter iter;
        FileData *fd;
-       gboolean mark;
+       gboolean marked;
        guint col_idx;
 
        store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
        if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
-               return;
+               return;
 
        col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
 
        g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
 
-       gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
-       mark = !mark;
-       fd->marks[col_idx - FILE_COLUMN_MARKS] = mark;
-       file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification */
-       file_data_increment_version(fd);
-       file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+       gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &marked, -1);
+       marked = !marked;
+       
+       /* the change has a very limited range and the standard notification would trigger
+          complete re-read of the directory - try to do only minimal update instead */
+       file_data_unregister_notify_func(vf_notify_cb, vf);
+       file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, marked);
+       if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
+               {
+               vf_refresh_idle(vf);
+               }
+       else
+               {
+               /* mark functions can have various side effects - update all columns to be sure */
+               vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
+               /* mark functions can change sidecars too */
+               vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
+               }
+       file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
 
-       gtk_tree_store_set(store, &iter, col_idx, mark, -1);
        gtk_tree_path_free(path);
 }
 
@@ -1721,10 +1836,6 @@ static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar
 {
        GtkTreeViewColumn *column;
        GtkCellRenderer *renderer;
-       GtkTreeStore *store;
-       gint index;
-
-       store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
 
        renderer = gtk_cell_renderer_toggle_new();
        column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
@@ -1733,8 +1844,8 @@ static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar
        g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
        g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
 
-       index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
-       gtk_tree_view_column_set_fixed_width(column, 16);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
+       gtk_tree_view_column_set_fixed_width(column, 22);
        gtk_tree_view_column_set_visible(column, vf->marks_enabled);
 
 
@@ -1747,10 +1858,9 @@ static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar
  *-----------------------------------------------------------------------------
  */
 
-gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
+gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd)
 {
-       GtkTreeStore *store;
-
+       gboolean ret;
        if (!dir_fd) return FALSE;
        if (vf->dir_fd == dir_fd) return TRUE;
 
@@ -1758,24 +1868,25 @@ gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
        vf->dir_fd = file_data_ref(dir_fd);
 
        /* force complete reload */
-       store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-       gtk_tree_store_clear(store);
+       vflist_store_clear(vf);
 
        filelist_free(vf->list);
        vf->list = NULL;
 
-       return vf_refresh(vf);
+       ret = vf_refresh(vf);
+       gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+       return ret;
 }
 
 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
 {
        ViewFile *vf = data;
 
-       file_data_unregister_notify_func(vflist_notify_cb, vf);
+       file_data_unregister_notify_func(vf_notify_cb, vf);
 
        vflist_select_idle_cancel(vf);
-       vflist_refresh_idle_cancel(vf);
-       vflist_thumb_stop(vf);
+       vf_refresh_idle_cancel(vf);
+       vf_thumb_stop(vf);
 
        filelist_free(vf->list);
 }
@@ -1784,27 +1895,21 @@ ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
 {
        GtkTreeStore *store;
        GtkTreeSelection *selection;
-
        GType flist_types[FILE_COLUMN_COUNT];
-       int i;
+       gint i;
+       gint column;
 
        vf->info = g_new0(ViewFileInfoList, 1);
        
-       VFLIST_INFO(vf, click_fd) = NULL;
-       VFLIST_INFO(vf, select_fd) = NULL;
-       VFLIST_INFO(vf, thumbs_enabled) = FALSE;
-
-       VFLIST_INFO(vf, select_idle_id) = -1;
-       vf->refresh_idle_id = -1;
-
-
        flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
        flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
        flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
+       flist_types[FILE_COLUMN_FORMATTED] = G_TYPE_STRING;
        flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
        flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
        flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
        flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
+       flist_types[FILE_COLUMN_EXPANDED] = G_TYPE_BOOLEAN;
        flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
        for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
                flist_types[i] = G_TYPE_BOOLEAN;
@@ -1814,6 +1919,12 @@ ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
        vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
        g_object_unref(store);
 
+       g_signal_connect(G_OBJECT(vf->listview), "row-expanded",
+                        G_CALLBACK(vflist_expand_cb), vf);
+
+       g_signal_connect(G_OBJECT(vf->listview), "row-collapsed",
+                        G_CALLBACK(vflist_collapse_cb), vf);
+
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
        gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
        gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
@@ -1821,37 +1932,56 @@ ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
        gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
 
-       vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
+       column = 0;
 
        for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
-               vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
+               {
+               vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
+               g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
+               column++;
+               }
 
-       vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
-       vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
+       vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
+       g_assert(column == FILE_VIEW_COLUMN_THUMB);
+       column++;
+       
+       vflist_listview_add_column(vf, FILE_COLUMN_FORMATTED, _("Name"), FALSE, FALSE, TRUE);
+       g_assert(column == FILE_VIEW_COLUMN_FORMATTED);
+       column++;
 
        vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
+       g_assert(column == FILE_VIEW_COLUMN_SIZE);
+       column++;
+
        vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
+       g_assert(column == FILE_VIEW_COLUMN_DATE);
+       column++;
 
-       file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+       file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
        return vf;
 }
 
-void vflist_thumb_set(ViewFile *vf, gint enable)
+void vflist_thumb_set(ViewFile *vf, gboolean enable)
 {
-       if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
+       if (VFLIST(vf)->thumbs_enabled == enable) return;
 
-       VFLIST_INFO(vf, thumbs_enabled) = enable;
-       if (vf->layout) vf_refresh(vf);
+       VFLIST(vf)->thumbs_enabled = enable;
+       
+       /* vflist_populate_view is better than vf_refresh:
+          - no need to re-read the directory
+          - force update because the formatted string has changed
+       */
+       if (vf->layout)
+               {
+               vflist_populate_view(vf, TRUE);
+               gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+               }
 }
 
-void vflist_marks_set(ViewFile *vf, gint enable)
+void vflist_marks_set(ViewFile *vf, gboolean enable)
 {
        GList *columns, *work;
 
-       if (vf->marks_enabled == enable) return;
-
-       vf->marks_enabled = enable;
-
        columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
 
        work = columns;
@@ -1866,272 +1996,6 @@ void vflist_marks_set(ViewFile *vf, gint enable)
                }
 
        g_list_free(columns);
-       //vf_refresh(vf);
 }
 
-/*
- *-----------------------------------------------------------------------------
- * maintenance (for rename, move, remove)
- *-----------------------------------------------------------------------------
- */
-
-static void vflist_notify_cb(FileData *fd, gpointer data)
-{
-       ViewFile *vf = data;
-       gboolean refresh;
-
-       if (vf->refresh_idle_id != -1) return;
-       
-       refresh = (fd == vf->dir_fd);
-
-       if (!refresh)
-               {
-               gchar *base = remove_level_from_path(fd->path);
-               refresh = (strcmp(base, vf->dir_fd->path) == 0);
-               g_free(base);
-               }
-
-       if (!refresh && fd->change && fd->change->dest)
-               {
-               gchar *dest_base = remove_level_from_path(fd->change->dest);
-               refresh = (strcmp(dest_base, vf->dir_fd->path) == 0);
-               g_free(dest_base);
-               }
-
-       if (!refresh && fd->change && fd->change->source)
-               {
-               gchar *source_base = remove_level_from_path(fd->change->source);
-               refresh = (strcmp(source_base, vf->dir_fd->path) == 0);
-               g_free(source_base);
-               }
-       
-       if (refresh)
-               {
-               vf->refresh_idle_id = g_idle_add(vflist_refresh_idle_cb, vf);
-               }
-}
-
-#if 0
-
-gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
-{
-       vflist_maint(vf, fd);
-       return TRUE;
-}
-gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
-{
-       vflist_maint(vf, fd);
-       return TRUE;
-}
-gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
-{
-       vflist_maint(vf, fd);
-       return TRUE;
-}
-
-
-static gint vflist_maint_find_closest(ViewFile *vf, gint row, gint count, GList *ignore_list)
-{
-       GList *list = NULL;
-       GList *work;
-       gint rev = row - 1;
-       row ++;
-
-       work = ignore_list;
-       while (work)
-               {
-               gint f = vf_index_by_path(vf, work->data);
-               if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f));
-               work = work->next;
-               }
-
-       while (list)
-               {
-               gint c = TRUE;
-               work = list;
-               while (work && c)
-                       {
-                       gpointer p = work->data;
-                       work = work->next;
-                       if (row == GPOINTER_TO_INT(p))
-                               {
-                               row++;
-                               c = FALSE;
-                               }
-                       if (rev == GPOINTER_TO_INT(p))
-                               {
-                               rev--;
-                               c = FALSE;
-                               }
-                       if (!c) list = g_list_remove(list, p);
-                       }
-               if (c && list)
-                       {
-                       g_list_free(list);
-                       list = NULL;
-                       }
-               }
-       if (row > count - 1)
-               {
-               if (rev < 0)
-                       return -1;
-               else
-                       return rev;
-               }
-       else
-               {
-               return row;
-               }
-}
-
-gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
-{
-       gint ret = FALSE;
-       gchar *source_base;
-       gchar *dest_base;
-
-       DEBUG_1("%s vflist_maint_renamed: start", get_exec_time());
-
-       if (g_list_index(vf->list, fd) < 0) return FALSE;
-
-       source_base = remove_level_from_path(fd->change->source);
-       dest_base = remove_level_from_path(fd->change->dest);
-
-
-       if (strcmp(source_base, dest_base) == 0)
-               {
-               GtkTreeStore *store;
-               GtkTreeIter iter;
-               GtkTreeIter position;
-               gint old_row;
-               gint n;
-
-               old_row = g_list_index(vf->list, fd);
-
-               vf->list = g_list_remove(vf->list, fd);
-
-               vf->list = filelist_insert_sort(vf->list, fd, vf->sort_method, vf->sort_ascend);
-               n = g_list_index(vf->list, fd);
-
-               store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-               if (vflist_find_row(vf, fd, &iter) >= 0 &&
-                   gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &position, NULL, n))
-                       {
-                       if (old_row >= n)
-                               {
-                               gtk_tree_store_move_before(store, &iter, &position);
-                               }
-                       else
-                               {
-                               gtk_tree_store_move_after(store, &iter, &position);
-                               }
-                       }
-               gtk_tree_store_set(store, &iter, FILE_COLUMN_NAME, fd->name, -1);
-
-               ret = TRUE;
-               }
-       else
-               {
-               ret = vflist_maint_removed(vf, fd, NULL);
-               }
-
-       g_free(source_base);
-       g_free(dest_base);
-
-       DEBUG_1("%s vflist_maint_renamed: done", get_exec_time());
-
-       return ret;
-}
-
-gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
-{
-       GtkTreeIter iter;
-       GList *list;
-       gint row;
-       gint new_row = -1;
-
-       DEBUG_1("%s vflist_maint_removed: start", get_exec_time());
-
-       row = g_list_index(vf->list, fd);
-       if (row < 0) return FALSE;
-
-       if (vflist_index_is_selected(vf, row) &&
-           layout_image_get_collection(vf->layout, NULL) == NULL)
-               {
-               gint n;
-
-               n = vf_count(vf, NULL);
-               if (ignore_list)
-                       {
-                       new_row = vflist_maint_find_closest(vf, row, n, ignore_list);
-                       DEBUG_1("row = %d, closest is %d", row, new_row);
-                       }
-               else
-                       {
-                       if (row + 1 < n)
-                               {
-                               new_row = row + 1;
-                               }
-                       else if (row > 0)
-                               {
-                               new_row = row - 1;
-                               }
-                       }
-               vf_select_none(vf);
-               if (new_row >= 0)
-                       {
-                       fd = vf_index_get_data(vf, new_row);
-                       if (vflist_find_row(vf, fd, &iter) >= 0)
-                               {
-                               GtkTreeSelection *selection;
-
-                               selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-                               gtk_tree_selection_select_iter(selection, &iter);
-                               vflist_move_cursor(vf, &iter);
-                               }
-                       }
-               }
-
-       fd = vf_index_get_data(vf, row);
-       if (vflist_find_row(vf, fd, &iter) >= 0)
-               {
-               GtkTreeStore *store;
-               store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-               gtk_tree_store_remove(store, &iter);
-               }
-       list = g_list_nth(vf->list, row);
-       fd = list->data;
-
-       /* thumbnail loader check */
-       if (fd == vf->thumbs_filedata) vf->thumbs_filedata = NULL;
-       if (vf->thumbs_count > 0) vf->thumbs_count--;
-
-       vf->list = g_list_remove(vf->list, fd);
-       file_data_unref(fd);
-
-       vf_send_update(vf);
-
-       DEBUG_1("%s vflist_maint_removed: done", get_exec_time());
-
-       return TRUE;
-}
-
-gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
-{
-       gint ret = FALSE;
-       gchar *buf;
-
-       if (!fd->change->source || !vf->path) return FALSE;
-
-       buf = remove_level_from_path(fd->change->source);
-
-       if (strcmp(buf, vf->path) == 0)
-               {
-               ret = vflist_maint_removed(vf, fd, ignore_list);
-               }
-
-       g_free(buf);
-
-       return ret;
-}
-#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */