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;
728 gchar *name_sidecars;
730 name_sidecars = (gchar *)fd->name;
732 if (fd->sidecar_files)
734 sidecars = file_data_sc_list_to_string(fd);
735 name_sidecars = g_strdup_printf("%s %s", fd->name, sidecars);
737 size = text_from_size(fd->size);
739 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
740 FILE_COLUMN_VERSION, fd->version,
741 FILE_COLUMN_THUMB, fd->pixbuf,
742 FILE_COLUMN_NAME, name_sidecars,
743 FILE_COLUMN_SIZE, size,
744 FILE_COLUMN_DATE, text_from_time(fd->date),
745 #define STORE_SET_IS_SLOW 1
746 #if STORE_SET_IS_SLOW
747 /* this is 3x faster on a directory with 20000 files */
748 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
749 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
750 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
751 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
752 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
753 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
754 #if FILEDATA_MARKS_SIZE != 6
755 #error this needs to be updated
758 FILE_COLUMN_COLOR, FALSE, -1);
760 #if !STORE_SET_IS_SLOW
763 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
764 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
771 g_free(name_sidecars);
775 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
780 gint num_ordered = 0;
781 gint num_prepended = 0;
783 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
789 FileData *fd = work->data;
794 FileData *old_fd = NULL;
795 gint old_version = 0;
800 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
801 FILE_COLUMN_POINTER, &old_fd,
802 FILE_COLUMN_VERSION, &old_version,
812 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
814 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
816 if (match == 0) g_warning("multiple fd for the same path");
831 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
836 here should be used gtk_tree_store_append, but this function seems to be O(n)
837 and it seems to be much faster to add new entries to the beginning and reorder later
840 gtk_tree_store_prepend(store, &new, parent_iter);
843 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
844 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
846 if (g_list_find(selected, fd))
848 /* renamed files - the same fd appears at different position - select it again*/
849 GtkTreeSelection *selection;
850 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
851 gtk_tree_selection_select_iter(selection, &new);
858 file_data_unref(old_fd);
859 valid = gtk_tree_store_remove(store, &iter);
863 if (fd->version != old_version)
865 vflist_setup_iter(vf, store, &iter, fd);
866 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
869 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
880 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
881 file_data_unref(old_fd);
883 valid = gtk_tree_store_remove(store, &iter);
886 /* move the prepended entries to the correct position */
890 gint num_total = num_prepended + num_ordered;
891 gint *new_order = g_malloc(num_total * sizeof(gint));
893 for (i = 0; i < num_total; i++)
896 new_order[i] = num_prepended + i;
898 new_order[i] = num_total - 1 - i;
900 gtk_tree_store_reorder(store, parent_iter, new_order);
906 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
909 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
914 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
915 if (!vf->list) return;
921 FileData *fd = work->data;
922 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
927 vf->sort_method = type;
928 vf->sort_ascend = ascend;
930 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
932 new_order = g_malloc(i * sizeof(gint));
938 FileData *fd = work->data;
939 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
944 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
945 gtk_tree_store_reorder(store, NULL, new_order);
948 g_hash_table_destroy(fd_idx_hash);
952 *-----------------------------------------------------------------------------
954 *-----------------------------------------------------------------------------
957 static gint vflist_thumb_next(ViewFile *vf);
959 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
961 if (vf->func_thumb_status)
963 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
967 static void vflist_thumb_cleanup(ViewFile *vf)
969 vflist_thumb_status(vf, 0.0, NULL);
971 vf->thumbs_count = 0;
972 vf->thumbs_running = FALSE;
974 thumb_loader_free(vf->thumbs_loader);
975 vf->thumbs_loader = NULL;
977 vf->thumbs_filedata = NULL;
980 static void vflist_thumb_stop(ViewFile *vf)
982 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
985 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
990 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
992 if (fd->pixbuf) g_object_unref(fd->pixbuf);
993 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
995 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
996 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
998 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
1001 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1003 ViewFile *vf = data;
1005 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1007 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1010 while (vflist_thumb_next(vf));
1013 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1015 ViewFile *vf = data;
1017 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1019 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1022 while (vflist_thumb_next(vf));
1025 static gint vflist_thumb_next(ViewFile *vf)
1028 FileData *fd = NULL;
1030 /* first check the visible files */
1032 if (GTK_WIDGET_REALIZED(vf->listview) &&
1033 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1035 GtkTreeModel *store;
1039 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1040 gtk_tree_model_get_iter(store, &iter, tpath);
1041 gtk_tree_path_free(tpath);
1043 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1045 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1046 if (fd->pixbuf) fd = NULL;
1048 valid = gtk_tree_model_iter_next(store, &iter);
1052 /* then find first undone */
1056 GList *work = vf->list;
1059 FileData *fd_p = work->data;
1064 GList *work2 = fd_p->sidecar_files;
1066 while (work2 && !fd)
1069 if (!fd_p->pixbuf) fd = fd_p;
1070 work2 = work2->next;
1080 vflist_thumb_cleanup(vf);
1086 vf->thumbs_filedata = fd;
1088 thumb_loader_free(vf->thumbs_loader);
1090 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1091 thumb_loader_set_callbacks(vf->thumbs_loader,
1092 vflist_thumb_done_cb,
1093 vflist_thumb_error_cb,
1097 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1099 /* set icon to unknown, continue */
1100 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1101 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1109 static void vflist_thumb_update(ViewFile *vf)
1111 vflist_thumb_stop(vf);
1112 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1114 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1115 vf->thumbs_running = TRUE;
1117 while (vflist_thumb_next(vf));
1121 *-----------------------------------------------------------------------------
1123 *-----------------------------------------------------------------------------
1126 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1128 return g_list_nth_data(vf->list, row);
1131 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1136 if (!path) return -1;
1141 FileData *fd = work->data;
1142 if (strcmp(path, fd->path) == 0) return p;
1151 guint vflist_count(ViewFile *vf, gint64 *bytes)
1161 FileData *fd = work->data;
1169 return g_list_length(vf->list);
1172 GList *vflist_get_list(ViewFile *vf)
1180 FileData *fd = work->data;
1183 list = g_list_prepend(list, file_data_ref(fd));
1186 return g_list_reverse(list);
1190 *-----------------------------------------------------------------------------
1192 *-----------------------------------------------------------------------------
1195 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1197 GtkTreeModel *store;
1198 GtkTreeSelection *selection;
1203 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1204 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1206 while (!found && work)
1208 GtkTreePath *tpath = work->data;
1212 gtk_tree_model_get_iter(store, &iter, tpath);
1213 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1214 if (fd_n == fd) found = TRUE;
1217 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1223 gint vflist_index_is_selected(ViewFile *vf, gint row)
1227 fd = vf_index_get_data(vf, row);
1228 return vflist_row_is_selected(vf, fd);
1231 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1233 GtkTreeModel *store;
1234 GtkTreeSelection *selection;
1238 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1239 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1249 GtkTreePath *tpath = work->data;
1253 gtk_tree_model_get_iter(store, &iter, tpath);
1254 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1263 count = g_list_length(slist);
1264 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1270 GList *vflist_selection_get_list(ViewFile *vf)
1272 GtkTreeModel *store;
1273 GtkTreeSelection *selection;
1278 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1279 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1283 GtkTreePath *tpath = work->data;
1287 gtk_tree_model_get_iter(store, &iter, tpath);
1288 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1290 list = g_list_prepend(list, file_data_ref(fd));
1294 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1297 return g_list_reverse(list);
1300 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1302 GtkTreeModel *store;
1303 GtkTreeSelection *selection;
1308 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1309 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1313 GtkTreePath *tpath = work->data;
1317 gtk_tree_model_get_iter(store, &iter, tpath);
1318 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1320 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1324 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1327 return g_list_reverse(list);
1330 void vflist_select_all(ViewFile *vf)
1332 GtkTreeSelection *selection;
1334 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1335 gtk_tree_selection_select_all(selection);
1337 VFLIST_INFO(vf, select_fd) = NULL;
1340 void vflist_select_none(ViewFile *vf)
1342 GtkTreeSelection *selection;
1344 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1345 gtk_tree_selection_unselect_all(selection);
1348 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1353 tpath = gtk_tree_model_get_path(store, iter);
1354 result = gtk_tree_path_prev(tpath);
1356 gtk_tree_model_get_iter(store, iter, tpath);
1358 gtk_tree_path_free(tpath);
1363 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1365 if (!gtk_tree_model_get_iter_first(store, iter))
1370 GtkTreeIter next = *iter;
1372 if (gtk_tree_model_iter_next(store, &next))
1381 void vflist_select_invert(ViewFile *vf)
1384 GtkTreeSelection *selection;
1385 GtkTreeModel *store;
1388 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1389 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1391 /* Backward iteration prevents scrolling to the end of the list,
1392 * it scrolls to the first selected row instead. */
1393 valid = tree_model_get_iter_last(store, &iter);
1397 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1400 gtk_tree_selection_unselect_iter(selection, &iter);
1402 gtk_tree_selection_select_iter(selection, &iter);
1404 valid = tree_model_iter_prev(store, &iter);
1408 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1412 if (vflist_find_row(vf, fd, &iter) < 0) return;
1414 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1416 if (!vflist_row_is_selected(vf, fd))
1418 GtkTreeSelection *selection;
1419 GtkTreeModel *store;
1422 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1423 gtk_tree_selection_unselect_all(selection);
1424 gtk_tree_selection_select_iter(selection, &iter);
1425 vflist_move_cursor(vf, &iter);
1427 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1428 tpath = gtk_tree_model_get_path(store, &iter);
1429 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1430 gtk_tree_path_free(tpath);
1434 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1438 if (sel_fd->parent) sel_fd = sel_fd->parent;
1444 FileData *fd = work->data;
1448 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1452 vflist_select_by_fd(vf, fd);
1459 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1461 GtkTreeModel *store;
1463 GtkTreeSelection *selection;
1467 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1469 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1470 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1472 valid = gtk_tree_model_get_iter_first(store, &iter);
1476 gboolean mark_val, selected;
1477 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1479 mark_val = file_data_get_mark(fd, n);
1480 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1484 case MTS_MODE_SET: selected = mark_val;
1486 case MTS_MODE_OR: selected = mark_val | selected;
1488 case MTS_MODE_AND: selected = mark_val & selected;
1490 case MTS_MODE_MINUS: selected = !mark_val & selected;
1495 gtk_tree_selection_select_iter(selection, &iter);
1497 gtk_tree_selection_unselect_iter(selection, &iter);
1499 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1503 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1505 GtkTreeModel *store;
1506 GtkTreeSelection *selection;
1511 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1513 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1514 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1518 GtkTreePath *tpath = work->data;
1522 gtk_tree_model_get_iter(store, &iter, tpath);
1523 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1525 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1529 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1531 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1533 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1537 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1539 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1543 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1548 *-----------------------------------------------------------------------------
1550 *-----------------------------------------------------------------------------
1553 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1555 GtkTreeViewColumn *column;
1556 GtkCellRenderer *cell;
1559 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
1560 if (!column) return;
1562 gtk_tree_view_column_set_visible(column, thumb);
1564 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 40);
1566 list = gtk_tree_view_column_get_cell_renderers(column);
1571 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1572 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1575 static void vflist_populate_view(ViewFile *vf)
1577 GtkTreeStore *store;
1579 GtkTreeRowReference *visible_row = NULL;
1583 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1584 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1586 vflist_thumb_stop(vf);
1590 vflist_store_clear(vf);
1595 if (GTK_WIDGET_REALIZED(vf->listview) &&
1596 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1598 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1599 gtk_tree_path_free(tpath);
1602 vflist_listview_set_height(vf->listview, thumbs);
1604 selected = vflist_selection_get_list(vf);
1606 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1608 if (selected && vflist_selection_count(vf, NULL) == 0)
1610 /* all selected files disappeared */
1611 vflist_select_closest(vf, selected->data);
1614 filelist_free(selected);
1618 if (gtk_tree_row_reference_valid(visible_row))
1620 tpath = gtk_tree_row_reference_get_path(visible_row);
1621 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1622 gtk_tree_path_free(tpath);
1624 gtk_tree_row_reference_free(visible_row);
1628 vflist_thumb_update(vf);
1631 gint vflist_refresh(ViewFile *vf)
1636 old_list = vf->list;
1639 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1642 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1644 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1646 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1648 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1649 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1652 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1654 vflist_populate_view(vf);
1656 filelist_free(old_list);
1657 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1664 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1666 #define CELL_HEIGHT_OVERRIDE 512
1668 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1672 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1673 if (spec && G_IS_PARAM_SPEC_INT(spec))
1675 GParamSpecInt *spec_int;
1677 spec_int = G_PARAM_SPEC_INT(spec);
1678 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1682 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1684 static GdkColor color;
1685 static GtkWidget *done = NULL;
1691 style = gtk_widget_get_style(widget);
1692 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1693 shift_color(&color, -1, 0);
1700 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1701 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1703 ViewFile *vf = data;
1706 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1707 g_object_set(G_OBJECT(cell),
1708 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1709 "cell-background-set", set, NULL);
1712 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1714 GtkTreeViewColumn *column;
1715 GtkCellRenderer *renderer;
1717 column = gtk_tree_view_column_new();
1718 gtk_tree_view_column_set_title(column, title);
1719 gtk_tree_view_column_set_min_width(column, 4);
1723 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1724 renderer = gtk_cell_renderer_text_new();
1727 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1729 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1730 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1732 gtk_tree_view_column_set_expand(column, TRUE);
1736 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1737 renderer = gtk_cell_renderer_pixbuf_new();
1738 cell_renderer_height_override(renderer);
1739 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1740 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1743 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1744 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1745 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1747 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1750 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1752 ViewFile *vf = data;
1753 GtkTreeStore *store;
1754 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1760 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1761 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1764 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1766 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1768 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1770 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1771 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1772 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1774 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1775 gtk_tree_path_free(path);
1778 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1780 GtkTreeViewColumn *column;
1781 GtkCellRenderer *renderer;
1782 GtkTreeStore *store;
1785 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1787 renderer = gtk_cell_renderer_toggle_new();
1788 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1790 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1791 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1792 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1794 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1795 gtk_tree_view_column_set_fixed_width(column, 16);
1796 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1799 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1803 *-----------------------------------------------------------------------------
1805 *-----------------------------------------------------------------------------
1808 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1810 if (!dir_fd) return FALSE;
1811 if (vf->dir_fd == dir_fd) return TRUE;
1813 file_data_unref(vf->dir_fd);
1814 vf->dir_fd = file_data_ref(dir_fd);
1816 /* force complete reload */
1817 vflist_store_clear(vf);
1819 filelist_free(vf->list);
1822 return vf_refresh(vf);
1825 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1827 ViewFile *vf = data;
1829 file_data_unregister_notify_func(vf_notify_cb, vf);
1831 vflist_select_idle_cancel(vf);
1832 vf_refresh_idle_cancel(vf);
1833 vflist_thumb_stop(vf);
1835 filelist_free(vf->list);
1838 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1840 GtkTreeStore *store;
1841 GtkTreeSelection *selection;
1843 GType flist_types[FILE_COLUMN_COUNT];
1846 vf->info = g_new0(ViewFileInfoList, 1);
1848 VFLIST_INFO(vf, click_fd) = NULL;
1849 VFLIST_INFO(vf, select_fd) = NULL;
1850 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1852 VFLIST_INFO(vf, select_idle_id) = -1;
1854 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1855 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1856 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1857 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1858 flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1859 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1860 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1861 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1862 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1863 flist_types[i] = G_TYPE_BOOLEAN;
1865 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1867 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1868 g_object_unref(store);
1870 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1871 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1872 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1874 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1875 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1877 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1879 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1880 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1882 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1883 vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1885 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1886 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1888 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1892 void vflist_thumb_set(ViewFile *vf, gint enable)
1894 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1896 VFLIST_INFO(vf, thumbs_enabled) = enable;
1897 if (vf->layout) vf_refresh(vf);
1900 void vflist_marks_set(ViewFile *vf, gint enable)
1902 GList *columns, *work;
1904 if (vf->marks_enabled == enable) return;
1906 vf->marks_enabled = enable;
1908 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1913 GtkTreeViewColumn *column = work->data;
1914 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1917 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1918 gtk_tree_view_column_set_visible(column, enable);
1921 g_list_free(columns);