4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
14 #include "view_file_list.h"
16 #include "cache_maint.h"
22 #include "layout_image.h"
26 #include "ui_bookmark.h"
27 #include "ui_fileops.h"
29 #include "ui_tree_edit.h"
30 #include "view_file.h"
32 #include <gdk/gdkkeysyms.h> /* for keyboard values */
36 FILE_COLUMN_POINTER = 0,
45 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
50 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
51 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
52 static void vflist_populate_view(ViewFile *vf);
56 *-----------------------------------------------------------------------------
58 *-----------------------------------------------------------------------------
65 } ViewFileFindRowData;
67 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
69 ViewFileFindRowData *find = data;
71 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
82 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
85 ViewFileFindRowData data = {fd, iter, 0, 0};
87 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
88 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
100 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
105 FileData *fd_p = work->data;
106 if (fd == fd_p) return i;
110 GList *work2 = fd_p->sidecar_files;
114 if (fd == fd_p) return i;
125 static gint vflist_sidecar_list_count(GList *work)
130 FileData *fd = work->data;
133 GList *work2 = fd->sidecar_files;
144 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
147 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
152 static void vflist_store_clear(ViewFile *vf)
155 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
156 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
157 gtk_tree_store_clear(GTK_TREE_STORE(store));
160 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
165 if (vflist_find_row(vf, fd, &iter) < 0) return;
166 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
167 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
170 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
175 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
177 tpath = gtk_tree_model_get_path(store, iter);
178 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
179 gtk_tree_path_free(tpath);
183 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
185 GList *columns, *work;
188 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
192 GtkTreeViewColumn *column = work->data;
193 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
199 g_list_free(columns);
205 *-----------------------------------------------------------------------------
207 *-----------------------------------------------------------------------------
210 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
211 GtkSelectionData *selection_data, guint info,
212 guint time, gpointer data)
216 gchar *uri_text = NULL;
219 if (!VFLIST_INFO(vf, click_fd)) return;
221 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
223 list = vf_selection_get_list(vf);
227 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
232 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
237 gtk_selection_data_set(selection_data, selection_data->target,
238 8, (guchar *)uri_text, total);
242 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
246 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
248 if (VFLIST_INFO(vf, thumbs_enabled) &&
249 VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->pixbuf)
253 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
254 items = vf_selection_count(vf, NULL);
258 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->pixbuf, items);
262 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
266 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
268 if (context->action == GDK_ACTION_MOVE)
274 void vflist_dnd_init(ViewFile *vf)
276 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
277 dnd_file_drag_types, dnd_file_drag_types_count,
278 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
279 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
280 G_CALLBACK(vflist_dnd_get), vf);
281 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
282 G_CALLBACK(vflist_dnd_begin), vf);
283 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
284 G_CALLBACK(vflist_dnd_end), vf);
288 *-----------------------------------------------------------------------------
290 *-----------------------------------------------------------------------------
293 GList *vflist_pop_menu_file_list(ViewFile *vf)
295 if (!VFLIST_INFO(vf, click_fd)) return NULL;
297 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
299 return vf_selection_get_list(vf);
302 return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
305 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
309 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
313 list = vf_selection_get_list(vf);
314 view_window_new_from_list(list);
319 view_window_new(VFLIST_INFO(vf, click_fd));
323 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
328 list = vf_pop_menu_file_list(vf);
329 if (options->file_ops.enable_in_place_rename &&
330 list && !list->next && VFLIST_INFO(vf, click_fd))
337 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
338 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
342 tpath = gtk_tree_model_get_path(store, &iter);
343 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
344 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
345 vflist_row_rename_cb, vf);
346 gtk_tree_path_free(tpath);
351 file_util_rename(NULL, list, vf->listview);
354 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
358 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
361 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
365 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
369 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
373 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
377 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
380 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
381 VFLIST_INFO(vf, click_fd) = NULL;
387 *-----------------------------------------------------------------------------
389 *-----------------------------------------------------------------------------
392 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
398 if (strlen(new) == 0) return FALSE;
400 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
401 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
403 if (strchr(new, G_DIR_SEPARATOR) != NULL)
405 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
406 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
409 else if (isfile(new_path))
411 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
412 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
417 gint row = vf_index_by_path(vf, old_path);
420 GList *work = g_list_nth(vf->list, row);
421 FileData *fd = work->data;
423 file_util_rename_simple(fd, new_path, vf->listview);
434 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
442 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
443 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
444 tpath = gtk_tree_model_get_path(store, &iter);
445 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
446 gtk_tree_path_free(tpath);
448 popup_menu_position_clamp(menu, x, y, 0);
451 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
456 if (event->keyval != GDK_Menu) return FALSE;
458 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
464 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
465 gtk_tree_model_get_iter(store, &iter, tpath);
466 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
467 gtk_tree_path_free(tpath);
471 VFLIST_INFO(vf, click_fd) = NULL;
474 vf->popup = vf_pop_menu(vf);
475 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
480 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
486 GtkTreeViewColumn *column;
488 vf->clicked_mark = 0;
490 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
491 &tpath, &column, NULL, NULL))
494 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
496 if (bevent->button == MOUSE_BUTTON_LEFT &&
497 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
500 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
501 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
503 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
505 gtk_tree_model_get_iter(store, &iter, tpath);
506 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
508 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
510 gtk_tree_path_free(tpath);
513 VFLIST_INFO(vf, click_fd) = fd;
515 if (bevent->button == MOUSE_BUTTON_RIGHT)
517 vf->popup = vf_pop_menu(vf);
518 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
519 bevent->button, bevent->time);
523 if (!fd) return FALSE;
525 if (bevent->button == MOUSE_BUTTON_MIDDLE)
527 if (!vflist_row_is_selected(vf, fd))
529 vflist_color_set(vf, fd, TRUE);
535 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
536 !(bevent->state & GDK_SHIFT_MASK ) &&
537 !(bevent->state & GDK_CONTROL_MASK ) &&
538 vflist_row_is_selected(vf, fd))
540 GtkTreeSelection *selection;
542 gtk_widget_grab_focus(widget);
545 /* returning FALSE and further processing of the event is needed for
546 correct operation of the expander, to show the sidecar files.
547 It however resets the selection of multiple files. With this condition
548 it should work for both cases */
549 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
550 return (gtk_tree_selection_count_selected_rows(selection) > 1);
554 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
556 if (vf->layout) layout_image_full_screen_start(vf->layout);
563 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
570 if (bevent->button == MOUSE_BUTTON_MIDDLE)
572 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
575 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
580 if ((bevent->x != 0 || bevent->y != 0) &&
581 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
582 &tpath, NULL, NULL, NULL))
586 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
587 gtk_tree_model_get_iter(store, &iter, tpath);
588 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
589 gtk_tree_path_free(tpath);
592 if (bevent->button == MOUSE_BUTTON_MIDDLE)
594 if (fd && VFLIST_INFO(vf, click_fd) == fd)
596 GtkTreeSelection *selection;
598 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
599 if (vflist_row_is_selected(vf, fd))
601 gtk_tree_selection_unselect_iter(selection, &iter);
605 gtk_tree_selection_select_iter(selection, &iter);
611 if (fd && VFLIST_INFO(vf, click_fd) == fd &&
612 !(bevent->state & GDK_SHIFT_MASK ) &&
613 !(bevent->state & GDK_CONTROL_MASK ) &&
614 vflist_row_is_selected(vf, fd))
616 GtkTreeSelection *selection;
618 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
619 gtk_tree_selection_unselect_all(selection);
620 gtk_tree_selection_select_iter(selection, &iter);
621 vflist_move_cursor(vf, &iter);
622 // return TRUE;// FIXME - expand
628 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
630 FileData *read_ahead_fd = NULL;
635 cur_fd = layout_image_get_fd(vf->layout);
636 if (sel_fd == cur_fd) return; /* no change */
638 row = g_list_index(vf->list, sel_fd);
639 // FIXME sidecar data
641 if (sel_fd && options->image.enable_read_ahead && row >= 0)
643 if (row > g_list_index(vf->list, cur_fd) &&
644 (guint) (row + 1) < vf_count(vf, NULL))
646 read_ahead_fd = vf_index_get_data(vf, row + 1);
650 read_ahead_fd = vf_index_get_data(vf, row - 1);
654 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
657 static gint vflist_select_idle_cb(gpointer data)
663 VFLIST_INFO(vf, select_idle_id) = -1;
669 if (VFLIST_INFO(vf, select_fd))
671 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
672 VFLIST_INFO(vf, select_fd) = NULL;
675 VFLIST_INFO(vf, select_idle_id) = -1;
679 static void vflist_select_idle_cancel(ViewFile *vf)
681 if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
682 VFLIST_INFO(vf, select_idle_id) = -1;
685 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
686 gboolean path_currently_selected, gpointer data)
691 if (!path_currently_selected &&
692 gtk_tree_model_get_iter(store, &iter, tpath))
694 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
698 VFLIST_INFO(vf, select_fd) = NULL;
702 VFLIST_INFO(vf, select_idle_id) == -1)
704 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
711 *-----------------------------------------------------------------------------
713 *-----------------------------------------------------------------------------
717 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
718 gboolean path_currently_selected, gpointer data)
724 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
728 gchar *sidecars = NULL;
730 if (fd->sidecar_files)
731 sidecars = file_data_sc_list_to_string(fd);
732 size = text_from_size(fd->size);
734 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
735 FILE_COLUMN_VERSION, fd->version,
736 FILE_COLUMN_THUMB, fd->pixbuf,
737 FILE_COLUMN_NAME, fd->name,
738 FILE_COLUMN_SIDECARS, sidecars,
739 FILE_COLUMN_SIZE, size,
740 FILE_COLUMN_DATE, text_from_time(fd->date),
741 #define STORE_SET_IS_SLOW 1
742 #if STORE_SET_IS_SLOW
743 /* this is 3x faster on a directory with 20000 files */
744 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
745 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
746 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
747 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
748 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
749 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
750 #if FILEDATA_MARKS_SIZE != 6
751 #error this needs to be updated
754 FILE_COLUMN_COLOR, FALSE, -1);
756 #if !STORE_SET_IS_SLOW
758 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
759 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
766 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
772 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
778 FileData *fd = work->data;
783 FileData *old_fd = NULL;
784 gint old_version = 0;
788 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
789 FILE_COLUMN_POINTER, &old_fd,
790 FILE_COLUMN_VERSION, &old_version,
800 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
802 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
804 if (match == 0) g_warning("multiple fd for the same path");
819 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
823 gtk_tree_store_append(store, &new, parent_iter);
826 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
827 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
829 if (g_list_find(selected, fd))
831 /* renamed files - the same fd appears at different position - select it again*/
832 GtkTreeSelection *selection;
833 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
834 gtk_tree_selection_select_iter(selection, &new);
841 file_data_unref(old_fd);
842 valid = gtk_tree_store_remove(store, &iter);
846 if (fd->version != old_version)
848 vflist_setup_iter(vf, store, &iter, fd);
849 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
852 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
863 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
864 file_data_unref(old_fd);
866 valid = gtk_tree_store_remove(store, &iter);
870 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
873 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
878 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
879 if (!vf->list) return;
885 FileData *fd = work->data;
886 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
891 vf->sort_method = type;
892 vf->sort_ascend = ascend;
894 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
896 new_order = g_malloc(i * sizeof(gint));
902 FileData *fd = work->data;
903 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
908 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
909 gtk_tree_store_reorder(store, NULL, new_order);
912 g_hash_table_destroy(fd_idx_hash);
916 *-----------------------------------------------------------------------------
918 *-----------------------------------------------------------------------------
921 static gint vflist_thumb_next(ViewFile *vf);
923 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
925 if (vf->func_thumb_status)
927 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
931 static void vflist_thumb_cleanup(ViewFile *vf)
933 vflist_thumb_status(vf, 0.0, NULL);
935 vf->thumbs_count = 0;
936 vf->thumbs_running = FALSE;
938 thumb_loader_free(vf->thumbs_loader);
939 vf->thumbs_loader = NULL;
941 vf->thumbs_filedata = NULL;
944 static void vflist_thumb_stop(ViewFile *vf)
946 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
949 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
954 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
956 if (fd->pixbuf) g_object_unref(fd->pixbuf);
957 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
959 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
960 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
962 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
965 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
969 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
971 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
974 while (vflist_thumb_next(vf));
977 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
981 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
983 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
986 while (vflist_thumb_next(vf));
989 static gint vflist_thumb_next(ViewFile *vf)
994 /* first check the visible files */
996 if (GTK_WIDGET_REALIZED(vf->listview) &&
997 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1003 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1004 gtk_tree_model_get_iter(store, &iter, tpath);
1005 gtk_tree_path_free(tpath);
1007 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1009 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1010 if (fd->pixbuf) fd = NULL;
1012 valid = gtk_tree_model_iter_next(store, &iter);
1016 /* then find first undone */
1020 GList *work = vf->list;
1023 FileData *fd_p = work->data;
1028 GList *work2 = fd_p->sidecar_files;
1030 while (work2 && !fd)
1033 if (!fd_p->pixbuf) fd = fd_p;
1034 work2 = work2->next;
1044 vflist_thumb_cleanup(vf);
1050 vf->thumbs_filedata = fd;
1052 thumb_loader_free(vf->thumbs_loader);
1054 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1055 thumb_loader_set_callbacks(vf->thumbs_loader,
1056 vflist_thumb_done_cb,
1057 vflist_thumb_error_cb,
1061 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1063 /* set icon to unknown, continue */
1064 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1065 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1073 static void vflist_thumb_update(ViewFile *vf)
1075 vflist_thumb_stop(vf);
1076 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1078 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1079 vf->thumbs_running = TRUE;
1081 while (vflist_thumb_next(vf));
1085 *-----------------------------------------------------------------------------
1087 *-----------------------------------------------------------------------------
1090 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1092 return g_list_nth_data(vf->list, row);
1095 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1100 if (!path) return -1;
1105 FileData *fd = work->data;
1106 if (strcmp(path, fd->path) == 0) return p;
1115 guint vflist_count(ViewFile *vf, gint64 *bytes)
1125 FileData *fd = work->data;
1133 return g_list_length(vf->list);
1136 GList *vflist_get_list(ViewFile *vf)
1144 FileData *fd = work->data;
1147 list = g_list_prepend(list, file_data_ref(fd));
1150 return g_list_reverse(list);
1154 *-----------------------------------------------------------------------------
1156 *-----------------------------------------------------------------------------
1159 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1161 GtkTreeModel *store;
1162 GtkTreeSelection *selection;
1167 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1168 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1170 while (!found && work)
1172 GtkTreePath *tpath = work->data;
1176 gtk_tree_model_get_iter(store, &iter, tpath);
1177 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1178 if (fd_n == fd) found = TRUE;
1181 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1187 gint vflist_index_is_selected(ViewFile *vf, gint row)
1191 fd = vf_index_get_data(vf, row);
1192 return vflist_row_is_selected(vf, fd);
1195 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1197 GtkTreeModel *store;
1198 GtkTreeSelection *selection;
1202 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1203 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1213 GtkTreePath *tpath = work->data;
1217 gtk_tree_model_get_iter(store, &iter, tpath);
1218 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1227 count = g_list_length(slist);
1228 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1234 GList *vflist_selection_get_list(ViewFile *vf)
1236 GtkTreeModel *store;
1237 GtkTreeSelection *selection;
1242 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1243 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1247 GtkTreePath *tpath = work->data;
1251 gtk_tree_model_get_iter(store, &iter, tpath);
1252 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1254 list = g_list_prepend(list, file_data_ref(fd));
1258 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1261 return g_list_reverse(list);
1264 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1266 GtkTreeModel *store;
1267 GtkTreeSelection *selection;
1272 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1273 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1277 GtkTreePath *tpath = work->data;
1281 gtk_tree_model_get_iter(store, &iter, tpath);
1282 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1284 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1288 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1291 return g_list_reverse(list);
1294 void vflist_select_all(ViewFile *vf)
1296 GtkTreeSelection *selection;
1298 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1299 gtk_tree_selection_select_all(selection);
1301 VFLIST_INFO(vf, select_fd) = NULL;
1304 void vflist_select_none(ViewFile *vf)
1306 GtkTreeSelection *selection;
1308 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1309 gtk_tree_selection_unselect_all(selection);
1312 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1317 tpath = gtk_tree_model_get_path(store, iter);
1318 result = gtk_tree_path_prev(tpath);
1320 gtk_tree_model_get_iter(store, iter, tpath);
1322 gtk_tree_path_free(tpath);
1327 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1329 if (!gtk_tree_model_get_iter_first(store, iter))
1334 GtkTreeIter next = *iter;
1336 if (gtk_tree_model_iter_next(store, &next))
1345 void vflist_select_invert(ViewFile *vf)
1348 GtkTreeSelection *selection;
1349 GtkTreeModel *store;
1352 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1353 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1355 /* Backward iteration prevents scrolling to the end of the list,
1356 * it scrolls to the first selected row instead. */
1357 valid = tree_model_get_iter_last(store, &iter);
1361 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1364 gtk_tree_selection_unselect_iter(selection, &iter);
1366 gtk_tree_selection_select_iter(selection, &iter);
1368 valid = tree_model_iter_prev(store, &iter);
1372 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1376 if (vflist_find_row(vf, fd, &iter) < 0) return;
1378 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1380 if (!vflist_row_is_selected(vf, fd))
1382 GtkTreeSelection *selection;
1383 GtkTreeModel *store;
1386 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1387 gtk_tree_selection_unselect_all(selection);
1388 gtk_tree_selection_select_iter(selection, &iter);
1389 vflist_move_cursor(vf, &iter);
1391 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1392 tpath = gtk_tree_model_get_path(store, &iter);
1393 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1394 gtk_tree_path_free(tpath);
1398 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1402 if (sel_fd->parent) sel_fd = sel_fd->parent;
1408 FileData *fd = work->data;
1412 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1416 vflist_select_by_fd(vf, fd);
1423 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1425 GtkTreeModel *store;
1427 GtkTreeSelection *selection;
1431 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1433 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1434 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1436 valid = gtk_tree_model_get_iter_first(store, &iter);
1440 gboolean mark_val, selected;
1441 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1443 mark_val = file_data_get_mark(fd, n);
1444 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1448 case MTS_MODE_SET: selected = mark_val;
1450 case MTS_MODE_OR: selected = mark_val | selected;
1452 case MTS_MODE_AND: selected = mark_val & selected;
1454 case MTS_MODE_MINUS: selected = !mark_val & selected;
1459 gtk_tree_selection_select_iter(selection, &iter);
1461 gtk_tree_selection_unselect_iter(selection, &iter);
1463 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1467 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1469 GtkTreeModel *store;
1470 GtkTreeSelection *selection;
1475 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1477 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1478 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1482 GtkTreePath *tpath = work->data;
1486 gtk_tree_model_get_iter(store, &iter, tpath);
1487 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1489 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1493 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1495 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1497 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1501 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1503 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1507 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1512 *-----------------------------------------------------------------------------
1514 *-----------------------------------------------------------------------------
1517 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1519 GtkTreeViewColumn *column;
1520 GtkCellRenderer *cell;
1523 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
1524 if (!column) return;
1526 gtk_tree_view_column_set_visible(column, thumb);
1528 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 40);
1530 list = gtk_tree_view_column_get_cell_renderers(column);
1535 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1536 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1539 static void vflist_populate_view(ViewFile *vf)
1541 GtkTreeStore *store;
1543 GtkTreeRowReference *visible_row = NULL;
1547 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1548 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1550 vflist_thumb_stop(vf);
1554 vflist_store_clear(vf);
1559 if (GTK_WIDGET_REALIZED(vf->listview) &&
1560 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1562 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1563 gtk_tree_path_free(tpath);
1566 vflist_listview_set_height(vf->listview, thumbs);
1568 selected = vflist_selection_get_list(vf);
1570 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1572 if (selected && vflist_selection_count(vf, NULL) == 0)
1574 /* all selected files disappeared */
1575 vflist_select_closest(vf, selected->data);
1578 filelist_free(selected);
1582 if (gtk_tree_row_reference_valid(visible_row))
1584 tpath = gtk_tree_row_reference_get_path(visible_row);
1585 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1586 gtk_tree_path_free(tpath);
1588 gtk_tree_row_reference_free(visible_row);
1592 vflist_thumb_update(vf);
1595 gint vflist_refresh(ViewFile *vf)
1600 old_list = vf->list;
1603 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1606 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1608 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1610 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1612 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1613 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1616 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1618 vflist_populate_view(vf);
1620 filelist_free(old_list);
1621 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1628 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1630 #define CELL_HEIGHT_OVERRIDE 512
1632 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1636 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1637 if (spec && G_IS_PARAM_SPEC_INT(spec))
1639 GParamSpecInt *spec_int;
1641 spec_int = G_PARAM_SPEC_INT(spec);
1642 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1646 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1648 static GdkColor color;
1649 static GtkWidget *done = NULL;
1655 style = gtk_widget_get_style(widget);
1656 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1657 shift_color(&color, -1, 0);
1664 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1665 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1667 ViewFile *vf = data;
1670 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1671 g_object_set(G_OBJECT(cell),
1672 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1673 "cell-background-set", set, NULL);
1676 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1678 GtkTreeViewColumn *column;
1679 GtkCellRenderer *renderer;
1681 column = gtk_tree_view_column_new();
1682 gtk_tree_view_column_set_title(column, title);
1683 gtk_tree_view_column_set_min_width(column, 4);
1687 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1688 renderer = gtk_cell_renderer_text_new();
1691 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1693 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1694 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1696 gtk_tree_view_column_set_expand(column, TRUE);
1700 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1701 renderer = gtk_cell_renderer_pixbuf_new();
1702 cell_renderer_height_override(renderer);
1703 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1704 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1707 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1708 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1709 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1711 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1714 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1716 ViewFile *vf = data;
1717 GtkTreeStore *store;
1718 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1724 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1725 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1728 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1730 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1732 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1734 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1735 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1736 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1738 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1739 gtk_tree_path_free(path);
1742 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1744 GtkTreeViewColumn *column;
1745 GtkCellRenderer *renderer;
1746 GtkTreeStore *store;
1749 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1751 renderer = gtk_cell_renderer_toggle_new();
1752 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1754 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1755 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1756 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1758 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1759 gtk_tree_view_column_set_fixed_width(column, 16);
1760 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1763 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1767 *-----------------------------------------------------------------------------
1769 *-----------------------------------------------------------------------------
1772 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1774 if (!dir_fd) return FALSE;
1775 if (vf->dir_fd == dir_fd) return TRUE;
1777 file_data_unref(vf->dir_fd);
1778 vf->dir_fd = file_data_ref(dir_fd);
1780 /* force complete reload */
1781 vflist_store_clear(vf);
1783 filelist_free(vf->list);
1786 return vf_refresh(vf);
1789 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1791 ViewFile *vf = data;
1793 file_data_unregister_notify_func(vf_notify_cb, vf);
1795 vflist_select_idle_cancel(vf);
1796 vf_refresh_idle_cancel(vf);
1797 vflist_thumb_stop(vf);
1799 filelist_free(vf->list);
1802 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1804 GtkTreeStore *store;
1805 GtkTreeSelection *selection;
1807 GType flist_types[FILE_COLUMN_COUNT];
1810 vf->info = g_new0(ViewFileInfoList, 1);
1812 VFLIST_INFO(vf, click_fd) = NULL;
1813 VFLIST_INFO(vf, select_fd) = NULL;
1814 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1816 VFLIST_INFO(vf, select_idle_id) = -1;
1818 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1819 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1820 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1821 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1822 flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1823 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1824 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1825 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1826 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1827 flist_types[i] = G_TYPE_BOOLEAN;
1829 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1831 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1832 g_object_unref(store);
1834 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1835 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1836 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1838 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1839 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1841 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1843 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1844 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1846 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
1847 vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1849 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1850 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1852 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1856 void vflist_thumb_set(ViewFile *vf, gint enable)
1858 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1860 VFLIST_INFO(vf, thumbs_enabled) = enable;
1861 if (vf->layout) vf_refresh(vf);
1864 void vflist_marks_set(ViewFile *vf, gint enable)
1866 GList *columns, *work;
1868 if (vf->marks_enabled == enable) return;
1870 vf->marks_enabled = enable;
1872 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1877 GtkTreeViewColumn *column = work->data;
1878 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1881 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1882 gtk_tree_view_column_set_visible(column, enable);
1885 g_list_free(columns);