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)
727 gchar *sidecars = NULL;
729 if (fd->sidecar_files)
730 sidecars = file_data_sc_list_to_string(fd);
731 size = text_from_size(fd->size);
733 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
734 FILE_COLUMN_VERSION, fd->version,
735 FILE_COLUMN_THUMB, fd->pixbuf,
736 FILE_COLUMN_NAME, fd->name,
737 FILE_COLUMN_SIDECARS, sidecars,
738 FILE_COLUMN_SIZE, size,
739 FILE_COLUMN_DATE, text_from_time(fd->date),
740 #define STORE_SET_IS_SLOW 1
741 #if STORE_SET_IS_SLOW
742 /* this is 3x faster on a directory with 20000 files */
743 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
744 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
745 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
746 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
747 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
748 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
749 #if FILEDATA_MARKS_SIZE != 6
750 #error this needs to be updated
753 FILE_COLUMN_COLOR, FALSE, -1);
755 #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);
767 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
772 gint num_ordered = 0;
773 gint num_prepended = 0;
775 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
781 FileData *fd = work->data;
786 FileData *old_fd = NULL;
787 gint old_version = 0;
792 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
793 FILE_COLUMN_POINTER, &old_fd,
794 FILE_COLUMN_VERSION, &old_version,
804 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
806 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
808 if (match == 0) g_warning("multiple fd for the same path");
823 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
828 here should be used gtk_tree_store_append, but this function seems to be O(n)
829 and it seems to be much faster to add new entries to the beginning and reorder later
832 gtk_tree_store_prepend(store, &new, parent_iter);
835 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
836 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
838 if (g_list_find(selected, fd))
840 /* renamed files - the same fd appears at different position - select it again*/
841 GtkTreeSelection *selection;
842 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
843 gtk_tree_selection_select_iter(selection, &new);
850 file_data_unref(old_fd);
851 valid = gtk_tree_store_remove(store, &iter);
855 if (fd->version != old_version)
857 vflist_setup_iter(vf, store, &iter, fd);
858 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
861 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
872 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
873 file_data_unref(old_fd);
875 valid = gtk_tree_store_remove(store, &iter);
878 /* move the prepended entries to the correct position */
882 gint num_total = num_prepended + num_ordered;
883 gint *new_order = g_malloc(num_total * sizeof(gint));
885 for (i = 0; i < num_total; i++)
888 new_order[i] = num_prepended + i;
890 new_order[i] = num_total - 1 - i;
892 gtk_tree_store_reorder(store, parent_iter, new_order);
898 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
901 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
906 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
907 if (!vf->list) return;
913 FileData *fd = work->data;
914 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
919 vf->sort_method = type;
920 vf->sort_ascend = ascend;
922 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
924 new_order = g_malloc(i * sizeof(gint));
930 FileData *fd = work->data;
931 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
936 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
937 gtk_tree_store_reorder(store, NULL, new_order);
940 g_hash_table_destroy(fd_idx_hash);
944 *-----------------------------------------------------------------------------
946 *-----------------------------------------------------------------------------
949 static gint vflist_thumb_next(ViewFile *vf);
951 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
953 if (vf->func_thumb_status)
955 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
959 static void vflist_thumb_cleanup(ViewFile *vf)
961 vflist_thumb_status(vf, 0.0, NULL);
963 vf->thumbs_count = 0;
964 vf->thumbs_running = FALSE;
966 thumb_loader_free(vf->thumbs_loader);
967 vf->thumbs_loader = NULL;
969 vf->thumbs_filedata = NULL;
972 static void vflist_thumb_stop(ViewFile *vf)
974 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
977 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
982 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
984 if (fd->pixbuf) g_object_unref(fd->pixbuf);
985 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
987 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
988 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
990 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
993 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
997 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
999 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1002 while (vflist_thumb_next(vf));
1005 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1007 ViewFile *vf = data;
1009 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1011 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1014 while (vflist_thumb_next(vf));
1017 static gint vflist_thumb_next(ViewFile *vf)
1020 FileData *fd = NULL;
1022 /* first check the visible files */
1024 if (GTK_WIDGET_REALIZED(vf->listview) &&
1025 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1027 GtkTreeModel *store;
1031 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1032 gtk_tree_model_get_iter(store, &iter, tpath);
1033 gtk_tree_path_free(tpath);
1035 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1037 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1038 if (fd->pixbuf) fd = NULL;
1040 valid = gtk_tree_model_iter_next(store, &iter);
1044 /* then find first undone */
1048 GList *work = vf->list;
1051 FileData *fd_p = work->data;
1056 GList *work2 = fd_p->sidecar_files;
1058 while (work2 && !fd)
1061 if (!fd_p->pixbuf) fd = fd_p;
1062 work2 = work2->next;
1072 vflist_thumb_cleanup(vf);
1078 vf->thumbs_filedata = fd;
1080 thumb_loader_free(vf->thumbs_loader);
1082 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1083 thumb_loader_set_callbacks(vf->thumbs_loader,
1084 vflist_thumb_done_cb,
1085 vflist_thumb_error_cb,
1089 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1091 /* set icon to unknown, continue */
1092 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1093 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1101 static void vflist_thumb_update(ViewFile *vf)
1103 vflist_thumb_stop(vf);
1104 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1106 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1107 vf->thumbs_running = TRUE;
1109 while (vflist_thumb_next(vf));
1113 *-----------------------------------------------------------------------------
1115 *-----------------------------------------------------------------------------
1118 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1120 return g_list_nth_data(vf->list, row);
1123 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1128 if (!path) return -1;
1133 FileData *fd = work->data;
1134 if (strcmp(path, fd->path) == 0) return p;
1143 guint vflist_count(ViewFile *vf, gint64 *bytes)
1153 FileData *fd = work->data;
1161 return g_list_length(vf->list);
1164 GList *vflist_get_list(ViewFile *vf)
1172 FileData *fd = work->data;
1175 list = g_list_prepend(list, file_data_ref(fd));
1178 return g_list_reverse(list);
1182 *-----------------------------------------------------------------------------
1184 *-----------------------------------------------------------------------------
1187 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1189 GtkTreeModel *store;
1190 GtkTreeSelection *selection;
1195 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1196 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1198 while (!found && work)
1200 GtkTreePath *tpath = work->data;
1204 gtk_tree_model_get_iter(store, &iter, tpath);
1205 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1206 if (fd_n == fd) found = TRUE;
1209 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1215 gint vflist_index_is_selected(ViewFile *vf, gint row)
1219 fd = vf_index_get_data(vf, row);
1220 return vflist_row_is_selected(vf, fd);
1223 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1225 GtkTreeModel *store;
1226 GtkTreeSelection *selection;
1230 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1231 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1241 GtkTreePath *tpath = work->data;
1245 gtk_tree_model_get_iter(store, &iter, tpath);
1246 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1255 count = g_list_length(slist);
1256 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1262 GList *vflist_selection_get_list(ViewFile *vf)
1264 GtkTreeModel *store;
1265 GtkTreeSelection *selection;
1270 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1271 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1275 GtkTreePath *tpath = work->data;
1279 gtk_tree_model_get_iter(store, &iter, tpath);
1280 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1282 list = g_list_prepend(list, file_data_ref(fd));
1286 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1289 return g_list_reverse(list);
1292 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1294 GtkTreeModel *store;
1295 GtkTreeSelection *selection;
1300 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1301 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1305 GtkTreePath *tpath = work->data;
1309 gtk_tree_model_get_iter(store, &iter, tpath);
1310 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1312 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1316 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1319 return g_list_reverse(list);
1322 void vflist_select_all(ViewFile *vf)
1324 GtkTreeSelection *selection;
1326 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1327 gtk_tree_selection_select_all(selection);
1329 VFLIST_INFO(vf, select_fd) = NULL;
1332 void vflist_select_none(ViewFile *vf)
1334 GtkTreeSelection *selection;
1336 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1337 gtk_tree_selection_unselect_all(selection);
1340 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1345 tpath = gtk_tree_model_get_path(store, iter);
1346 result = gtk_tree_path_prev(tpath);
1348 gtk_tree_model_get_iter(store, iter, tpath);
1350 gtk_tree_path_free(tpath);
1355 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1357 if (!gtk_tree_model_get_iter_first(store, iter))
1362 GtkTreeIter next = *iter;
1364 if (gtk_tree_model_iter_next(store, &next))
1373 void vflist_select_invert(ViewFile *vf)
1376 GtkTreeSelection *selection;
1377 GtkTreeModel *store;
1380 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1381 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1383 /* Backward iteration prevents scrolling to the end of the list,
1384 * it scrolls to the first selected row instead. */
1385 valid = tree_model_get_iter_last(store, &iter);
1389 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1392 gtk_tree_selection_unselect_iter(selection, &iter);
1394 gtk_tree_selection_select_iter(selection, &iter);
1396 valid = tree_model_iter_prev(store, &iter);
1400 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1404 if (vflist_find_row(vf, fd, &iter) < 0) return;
1406 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1408 if (!vflist_row_is_selected(vf, fd))
1410 GtkTreeSelection *selection;
1411 GtkTreeModel *store;
1414 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1415 gtk_tree_selection_unselect_all(selection);
1416 gtk_tree_selection_select_iter(selection, &iter);
1417 vflist_move_cursor(vf, &iter);
1419 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1420 tpath = gtk_tree_model_get_path(store, &iter);
1421 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1422 gtk_tree_path_free(tpath);
1426 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1430 if (sel_fd->parent) sel_fd = sel_fd->parent;
1436 FileData *fd = work->data;
1440 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1444 vflist_select_by_fd(vf, fd);
1451 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1453 GtkTreeModel *store;
1455 GtkTreeSelection *selection;
1459 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1461 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1462 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1464 valid = gtk_tree_model_get_iter_first(store, &iter);
1468 gboolean mark_val, selected;
1469 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1471 mark_val = file_data_get_mark(fd, n);
1472 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1476 case MTS_MODE_SET: selected = mark_val;
1478 case MTS_MODE_OR: selected = mark_val | selected;
1480 case MTS_MODE_AND: selected = mark_val & selected;
1482 case MTS_MODE_MINUS: selected = !mark_val & selected;
1487 gtk_tree_selection_select_iter(selection, &iter);
1489 gtk_tree_selection_unselect_iter(selection, &iter);
1491 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1495 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1497 GtkTreeModel *store;
1498 GtkTreeSelection *selection;
1503 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1505 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1506 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1510 GtkTreePath *tpath = work->data;
1514 gtk_tree_model_get_iter(store, &iter, tpath);
1515 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1517 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1521 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1523 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1525 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1529 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1531 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1535 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1540 *-----------------------------------------------------------------------------
1542 *-----------------------------------------------------------------------------
1545 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1547 GtkTreeViewColumn *column;
1548 GtkCellRenderer *cell;
1551 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
1552 if (!column) return;
1554 gtk_tree_view_column_set_visible(column, thumb);
1556 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 40);
1558 list = gtk_tree_view_column_get_cell_renderers(column);
1563 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1564 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1567 static void vflist_populate_view(ViewFile *vf)
1569 GtkTreeStore *store;
1571 GtkTreeRowReference *visible_row = NULL;
1575 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1576 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1578 vflist_thumb_stop(vf);
1582 vflist_store_clear(vf);
1587 if (GTK_WIDGET_REALIZED(vf->listview) &&
1588 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1590 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1591 gtk_tree_path_free(tpath);
1594 vflist_listview_set_height(vf->listview, thumbs);
1596 selected = vflist_selection_get_list(vf);
1598 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1600 if (selected && vflist_selection_count(vf, NULL) == 0)
1602 /* all selected files disappeared */
1603 vflist_select_closest(vf, selected->data);
1606 filelist_free(selected);
1610 if (gtk_tree_row_reference_valid(visible_row))
1612 tpath = gtk_tree_row_reference_get_path(visible_row);
1613 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1614 gtk_tree_path_free(tpath);
1616 gtk_tree_row_reference_free(visible_row);
1620 vflist_thumb_update(vf);
1623 gint vflist_refresh(ViewFile *vf)
1628 old_list = vf->list;
1631 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1634 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1636 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1638 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1640 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1641 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1644 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1646 vflist_populate_view(vf);
1648 filelist_free(old_list);
1649 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1656 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1658 #define CELL_HEIGHT_OVERRIDE 512
1660 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1664 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1665 if (spec && G_IS_PARAM_SPEC_INT(spec))
1667 GParamSpecInt *spec_int;
1669 spec_int = G_PARAM_SPEC_INT(spec);
1670 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1674 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1676 static GdkColor color;
1677 static GtkWidget *done = NULL;
1683 style = gtk_widget_get_style(widget);
1684 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1685 shift_color(&color, -1, 0);
1692 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1693 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1695 ViewFile *vf = data;
1698 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1699 g_object_set(G_OBJECT(cell),
1700 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1701 "cell-background-set", set, NULL);
1704 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1706 GtkTreeViewColumn *column;
1707 GtkCellRenderer *renderer;
1709 column = gtk_tree_view_column_new();
1710 gtk_tree_view_column_set_title(column, title);
1711 gtk_tree_view_column_set_min_width(column, 4);
1715 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1716 renderer = gtk_cell_renderer_text_new();
1719 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1721 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1722 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1724 gtk_tree_view_column_set_expand(column, TRUE);
1728 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1729 renderer = gtk_cell_renderer_pixbuf_new();
1730 cell_renderer_height_override(renderer);
1731 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1732 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1735 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1736 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1737 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1739 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1742 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1744 ViewFile *vf = data;
1745 GtkTreeStore *store;
1746 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1752 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1753 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1756 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1758 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1760 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1762 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1763 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1764 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1766 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1767 gtk_tree_path_free(path);
1770 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1772 GtkTreeViewColumn *column;
1773 GtkCellRenderer *renderer;
1774 GtkTreeStore *store;
1777 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1779 renderer = gtk_cell_renderer_toggle_new();
1780 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1782 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1783 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1784 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1786 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1787 gtk_tree_view_column_set_fixed_width(column, 16);
1788 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1791 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1795 *-----------------------------------------------------------------------------
1797 *-----------------------------------------------------------------------------
1800 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1802 if (!dir_fd) return FALSE;
1803 if (vf->dir_fd == dir_fd) return TRUE;
1805 file_data_unref(vf->dir_fd);
1806 vf->dir_fd = file_data_ref(dir_fd);
1808 /* force complete reload */
1809 vflist_store_clear(vf);
1811 filelist_free(vf->list);
1814 return vf_refresh(vf);
1817 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1819 ViewFile *vf = data;
1821 file_data_unregister_notify_func(vf_notify_cb, vf);
1823 vflist_select_idle_cancel(vf);
1824 vf_refresh_idle_cancel(vf);
1825 vflist_thumb_stop(vf);
1827 filelist_free(vf->list);
1830 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1832 GtkTreeStore *store;
1833 GtkTreeSelection *selection;
1835 GType flist_types[FILE_COLUMN_COUNT];
1838 vf->info = g_new0(ViewFileInfoList, 1);
1840 VFLIST_INFO(vf, click_fd) = NULL;
1841 VFLIST_INFO(vf, select_fd) = NULL;
1842 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1844 VFLIST_INFO(vf, select_idle_id) = -1;
1846 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1847 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1848 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1849 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1850 flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1851 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1852 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1853 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1854 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1855 flist_types[i] = G_TYPE_BOOLEAN;
1857 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1859 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1860 g_object_unref(store);
1862 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1863 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1864 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1866 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1867 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1869 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1871 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1872 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1874 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
1875 vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1877 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1878 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1880 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1884 void vflist_thumb_set(ViewFile *vf, gint enable)
1886 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1888 VFLIST_INFO(vf, thumbs_enabled) = enable;
1889 if (vf->layout) vf_refresh(vf);
1892 void vflist_marks_set(ViewFile *vf, gint enable)
1894 GList *columns, *work;
1896 if (vf->marks_enabled == enable) return;
1898 vf->marks_enabled = enable;
1900 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1905 GtkTreeViewColumn *column = work->data;
1906 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1909 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1910 gtk_tree_view_column_set_visible(column, enable);
1913 g_list_free(columns);