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 */
34 /* Index to tree store */
36 FILE_COLUMN_POINTER = 0,
40 FILE_COLUMN_MULTILINE,
45 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
50 /* Index to tree view */
52 FILE_VIEW_COLUMN_MARKS = 0,
53 FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
54 FILE_VIEW_COLUMN_THUMB,
55 FILE_VIEW_COLUMN_MULTILINE,
56 FILE_VIEW_COLUMN_NAME,
57 FILE_VIEW_COLUMN_SIZE,
58 FILE_VIEW_COLUMN_DATE,
59 FILE_VIEW_COLUMN_COUNT
64 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
65 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
66 static void vflist_populate_view(ViewFile *vf);
70 *-----------------------------------------------------------------------------
72 *-----------------------------------------------------------------------------
79 } ViewFileFindRowData;
81 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
83 ViewFileFindRowData *find = data;
85 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
96 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
99 ViewFileFindRowData data = {fd, iter, 0, 0};
101 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
102 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
114 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
119 FileData *fd_p = work->data;
120 if (fd == fd_p) return i;
124 GList *work2 = fd_p->sidecar_files;
128 if (fd == fd_p) return i;
139 static gint vflist_sidecar_list_count(GList *work)
144 FileData *fd = work->data;
147 GList *work2 = fd->sidecar_files;
158 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
161 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
166 static void vflist_store_clear(ViewFile *vf)
169 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
170 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
171 gtk_tree_store_clear(GTK_TREE_STORE(store));
174 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
179 if (vflist_find_row(vf, fd, &iter) < 0) return;
180 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
181 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
184 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
189 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
191 tpath = gtk_tree_model_get_path(store, iter);
192 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
193 gtk_tree_path_free(tpath);
197 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
199 GList *columns, *work;
202 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
206 GtkTreeViewColumn *column = work->data;
207 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
213 g_list_free(columns);
219 *-----------------------------------------------------------------------------
221 *-----------------------------------------------------------------------------
224 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
225 GtkSelectionData *selection_data, guint info,
226 guint time, gpointer data)
230 gchar *uri_text = NULL;
233 if (!VFLIST_INFO(vf, click_fd)) return;
235 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
237 list = vf_selection_get_list(vf);
241 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
246 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
251 gtk_selection_data_set(selection_data, selection_data->target,
252 8, (guchar *)uri_text, total);
256 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
260 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
262 if (VFLIST_INFO(vf, thumbs_enabled) &&
263 VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->pixbuf)
267 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
268 items = vf_selection_count(vf, NULL);
272 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->pixbuf, items);
276 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
280 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
282 if (context->action == GDK_ACTION_MOVE)
288 void vflist_dnd_init(ViewFile *vf)
290 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
291 dnd_file_drag_types, dnd_file_drag_types_count,
292 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
293 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
294 G_CALLBACK(vflist_dnd_get), vf);
295 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
296 G_CALLBACK(vflist_dnd_begin), vf);
297 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
298 G_CALLBACK(vflist_dnd_end), vf);
302 *-----------------------------------------------------------------------------
304 *-----------------------------------------------------------------------------
307 GList *vflist_pop_menu_file_list(ViewFile *vf)
309 if (!VFLIST_INFO(vf, click_fd)) return NULL;
311 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
313 return vf_selection_get_list(vf);
316 return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
319 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
323 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
327 list = vf_selection_get_list(vf);
328 view_window_new_from_list(list);
333 view_window_new(VFLIST_INFO(vf, click_fd));
337 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
342 list = vf_pop_menu_file_list(vf);
343 if (options->file_ops.enable_in_place_rename &&
344 list && !list->next && VFLIST_INFO(vf, click_fd))
351 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
352 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
356 tpath = gtk_tree_model_get_path(store, &iter);
357 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
358 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
359 vflist_row_rename_cb, vf);
360 gtk_tree_path_free(tpath);
365 file_util_rename(NULL, list, vf->listview);
368 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
372 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
375 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
379 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
383 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
387 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
391 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
394 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
395 VFLIST_INFO(vf, click_fd) = NULL;
401 *-----------------------------------------------------------------------------
403 *-----------------------------------------------------------------------------
406 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
412 if (strlen(new) == 0) return FALSE;
414 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
415 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
417 if (strchr(new, G_DIR_SEPARATOR) != NULL)
419 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
420 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
423 else if (isfile(new_path))
425 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
426 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
431 gint row = vf_index_by_path(vf, old_path);
434 GList *work = g_list_nth(vf->list, row);
435 FileData *fd = work->data;
437 file_util_rename_simple(fd, new_path, vf->listview);
448 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
456 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
457 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
458 tpath = gtk_tree_model_get_path(store, &iter);
459 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
460 gtk_tree_path_free(tpath);
462 popup_menu_position_clamp(menu, x, y, 0);
465 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
470 if (event->keyval != GDK_Menu) return FALSE;
472 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
478 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
479 gtk_tree_model_get_iter(store, &iter, tpath);
480 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
481 gtk_tree_path_free(tpath);
485 VFLIST_INFO(vf, click_fd) = NULL;
488 vf->popup = vf_pop_menu(vf);
489 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
494 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
500 GtkTreeViewColumn *column;
502 vf->clicked_mark = 0;
504 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
505 &tpath, &column, NULL, NULL))
508 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
510 if (bevent->button == MOUSE_BUTTON_LEFT &&
511 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
514 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
515 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
517 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
519 gtk_tree_model_get_iter(store, &iter, tpath);
520 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
522 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
524 gtk_tree_path_free(tpath);
527 VFLIST_INFO(vf, click_fd) = fd;
529 if (bevent->button == MOUSE_BUTTON_RIGHT)
531 vf->popup = vf_pop_menu(vf);
532 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
533 bevent->button, bevent->time);
537 if (!fd) return FALSE;
539 if (bevent->button == MOUSE_BUTTON_MIDDLE)
541 if (!vflist_row_is_selected(vf, fd))
543 vflist_color_set(vf, fd, TRUE);
549 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
550 !(bevent->state & GDK_SHIFT_MASK ) &&
551 !(bevent->state & GDK_CONTROL_MASK ) &&
552 vflist_row_is_selected(vf, fd))
554 GtkTreeSelection *selection;
556 gtk_widget_grab_focus(widget);
559 /* returning FALSE and further processing of the event is needed for
560 correct operation of the expander, to show the sidecar files.
561 It however resets the selection of multiple files. With this condition
562 it should work for both cases */
563 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
564 return (gtk_tree_selection_count_selected_rows(selection) > 1);
568 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
570 if (vf->layout) layout_image_full_screen_start(vf->layout);
577 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
584 if (bevent->button == MOUSE_BUTTON_MIDDLE)
586 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
589 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
594 if ((bevent->x != 0 || bevent->y != 0) &&
595 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
596 &tpath, NULL, NULL, NULL))
600 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
601 gtk_tree_model_get_iter(store, &iter, tpath);
602 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
603 gtk_tree_path_free(tpath);
606 if (bevent->button == MOUSE_BUTTON_MIDDLE)
608 if (fd && VFLIST_INFO(vf, click_fd) == fd)
610 GtkTreeSelection *selection;
612 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
613 if (vflist_row_is_selected(vf, fd))
615 gtk_tree_selection_unselect_iter(selection, &iter);
619 gtk_tree_selection_select_iter(selection, &iter);
625 if (fd && VFLIST_INFO(vf, click_fd) == fd &&
626 !(bevent->state & GDK_SHIFT_MASK ) &&
627 !(bevent->state & GDK_CONTROL_MASK ) &&
628 vflist_row_is_selected(vf, fd))
630 GtkTreeSelection *selection;
632 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
633 gtk_tree_selection_unselect_all(selection);
634 gtk_tree_selection_select_iter(selection, &iter);
635 vflist_move_cursor(vf, &iter);
636 // return TRUE;// FIXME - expand
642 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
644 FileData *read_ahead_fd = NULL;
649 cur_fd = layout_image_get_fd(vf->layout);
650 if (sel_fd == cur_fd) return; /* no change */
652 row = g_list_index(vf->list, sel_fd);
653 // FIXME sidecar data
655 if (sel_fd && options->image.enable_read_ahead && row >= 0)
657 if (row > g_list_index(vf->list, cur_fd) &&
658 (guint) (row + 1) < vf_count(vf, NULL))
660 read_ahead_fd = vf_index_get_data(vf, row + 1);
664 read_ahead_fd = vf_index_get_data(vf, row - 1);
668 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
671 static gint vflist_select_idle_cb(gpointer data)
677 VFLIST_INFO(vf, select_idle_id) = -1;
683 if (VFLIST_INFO(vf, select_fd))
685 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
686 VFLIST_INFO(vf, select_fd) = NULL;
689 VFLIST_INFO(vf, select_idle_id) = -1;
693 static void vflist_select_idle_cancel(ViewFile *vf)
695 if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
696 VFLIST_INFO(vf, select_idle_id) = -1;
699 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
700 gboolean path_currently_selected, gpointer data)
705 if (!path_currently_selected &&
706 gtk_tree_model_get_iter(store, &iter, tpath))
708 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
712 VFLIST_INFO(vf, select_fd) = NULL;
716 VFLIST_INFO(vf, select_idle_id) == -1)
718 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
725 *-----------------------------------------------------------------------------
727 *-----------------------------------------------------------------------------
731 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
732 gboolean path_currently_selected, gpointer data)
738 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
741 gchar *sidecars = NULL;
742 gchar *name_sidecars;
744 const gchar *time = text_from_time(fd->date);
745 name_sidecars = (gchar *)fd->name;
747 if (fd->sidecar_files)
749 sidecars = file_data_sc_list_to_string(fd);
750 name_sidecars = g_strdup_printf("%s %s", fd->name, sidecars);
752 size = text_from_size(fd->size);
754 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
756 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
757 FILE_COLUMN_VERSION, fd->version,
758 FILE_COLUMN_THUMB, fd->pixbuf,
759 FILE_COLUMN_MULTILINE, multiline,
760 FILE_COLUMN_NAME, name_sidecars,
761 FILE_COLUMN_SIZE, size,
762 FILE_COLUMN_DATE, time,
763 #define STORE_SET_IS_SLOW 1
764 #if STORE_SET_IS_SLOW
765 /* this is 3x faster on a directory with 20000 files */
766 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
767 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
768 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
769 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
770 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
771 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
772 #if FILEDATA_MARKS_SIZE != 6
773 #error this needs to be updated
776 FILE_COLUMN_COLOR, FALSE, -1);
778 #if !STORE_SET_IS_SLOW
781 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
782 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
789 g_free(name_sidecars);
794 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
799 gint num_ordered = 0;
800 gint num_prepended = 0;
802 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
808 FileData *fd = work->data;
813 FileData *old_fd = NULL;
814 gint old_version = 0;
819 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
820 FILE_COLUMN_POINTER, &old_fd,
821 FILE_COLUMN_VERSION, &old_version,
831 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
833 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
835 if (match == 0) g_warning("multiple fd for the same path");
850 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
855 here should be used gtk_tree_store_append, but this function seems to be O(n)
856 and it seems to be much faster to add new entries to the beginning and reorder later
859 gtk_tree_store_prepend(store, &new, parent_iter);
862 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
863 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
865 if (g_list_find(selected, fd))
867 /* renamed files - the same fd appears at different position - select it again*/
868 GtkTreeSelection *selection;
869 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
870 gtk_tree_selection_select_iter(selection, &new);
877 file_data_unref(old_fd);
878 valid = gtk_tree_store_remove(store, &iter);
882 if (fd->version != old_version)
884 vflist_setup_iter(vf, store, &iter, fd);
885 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
888 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
899 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
900 file_data_unref(old_fd);
902 valid = gtk_tree_store_remove(store, &iter);
905 /* move the prepended entries to the correct position */
909 gint num_total = num_prepended + num_ordered;
910 gint *new_order = g_malloc(num_total * sizeof(gint));
912 for (i = 0; i < num_total; i++)
915 new_order[i] = num_prepended + i;
917 new_order[i] = num_total - 1 - i;
919 gtk_tree_store_reorder(store, parent_iter, new_order);
925 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
928 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
933 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
934 if (!vf->list) return;
940 FileData *fd = work->data;
941 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
946 vf->sort_method = type;
947 vf->sort_ascend = ascend;
949 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
951 new_order = g_malloc(i * sizeof(gint));
957 FileData *fd = work->data;
958 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
963 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
964 gtk_tree_store_reorder(store, NULL, new_order);
967 g_hash_table_destroy(fd_idx_hash);
971 *-----------------------------------------------------------------------------
973 *-----------------------------------------------------------------------------
976 static gint vflist_thumb_next(ViewFile *vf);
978 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
980 if (vf->func_thumb_status)
982 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
986 static void vflist_thumb_cleanup(ViewFile *vf)
988 vflist_thumb_status(vf, 0.0, NULL);
990 vf->thumbs_count = 0;
991 vf->thumbs_running = FALSE;
993 thumb_loader_free(vf->thumbs_loader);
994 vf->thumbs_loader = NULL;
996 vf->thumbs_filedata = NULL;
999 static void vflist_thumb_stop(ViewFile *vf)
1001 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1004 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1006 GtkTreeStore *store;
1009 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1011 if (fd->pixbuf) g_object_unref(fd->pixbuf);
1012 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
1014 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1015 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
1017 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
1020 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1022 ViewFile *vf = data;
1024 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1026 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1029 while (vflist_thumb_next(vf));
1032 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1034 ViewFile *vf = data;
1036 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1038 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1041 while (vflist_thumb_next(vf));
1044 static gint vflist_thumb_next(ViewFile *vf)
1047 FileData *fd = NULL;
1049 /* first check the visible files */
1051 if (GTK_WIDGET_REALIZED(vf->listview) &&
1052 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1054 GtkTreeModel *store;
1058 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1059 gtk_tree_model_get_iter(store, &iter, tpath);
1060 gtk_tree_path_free(tpath);
1062 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1064 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1065 if (fd->pixbuf) fd = NULL;
1067 valid = gtk_tree_model_iter_next(store, &iter);
1071 /* then find first undone */
1075 GList *work = vf->list;
1078 FileData *fd_p = work->data;
1083 GList *work2 = fd_p->sidecar_files;
1085 while (work2 && !fd)
1088 if (!fd_p->pixbuf) fd = fd_p;
1089 work2 = work2->next;
1099 vflist_thumb_cleanup(vf);
1105 vf->thumbs_filedata = fd;
1107 thumb_loader_free(vf->thumbs_loader);
1109 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1110 thumb_loader_set_callbacks(vf->thumbs_loader,
1111 vflist_thumb_done_cb,
1112 vflist_thumb_error_cb,
1116 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1118 /* set icon to unknown, continue */
1119 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1120 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1128 static void vflist_thumb_update(ViewFile *vf)
1130 vflist_thumb_stop(vf);
1131 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1133 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1134 vf->thumbs_running = TRUE;
1136 while (vflist_thumb_next(vf));
1140 *-----------------------------------------------------------------------------
1142 *-----------------------------------------------------------------------------
1145 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1147 return g_list_nth_data(vf->list, row);
1150 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1155 if (!path) return -1;
1160 FileData *fd = work->data;
1161 if (strcmp(path, fd->path) == 0) return p;
1170 guint vflist_count(ViewFile *vf, gint64 *bytes)
1180 FileData *fd = work->data;
1188 return g_list_length(vf->list);
1191 GList *vflist_get_list(ViewFile *vf)
1199 FileData *fd = work->data;
1202 list = g_list_prepend(list, file_data_ref(fd));
1205 return g_list_reverse(list);
1209 *-----------------------------------------------------------------------------
1211 *-----------------------------------------------------------------------------
1214 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1216 GtkTreeModel *store;
1217 GtkTreeSelection *selection;
1222 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1223 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1225 while (!found && work)
1227 GtkTreePath *tpath = work->data;
1231 gtk_tree_model_get_iter(store, &iter, tpath);
1232 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1233 if (fd_n == fd) found = TRUE;
1236 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1242 gint vflist_index_is_selected(ViewFile *vf, gint row)
1246 fd = vf_index_get_data(vf, row);
1247 return vflist_row_is_selected(vf, fd);
1250 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1252 GtkTreeModel *store;
1253 GtkTreeSelection *selection;
1257 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1258 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1268 GtkTreePath *tpath = work->data;
1272 gtk_tree_model_get_iter(store, &iter, tpath);
1273 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1282 count = g_list_length(slist);
1283 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1289 GList *vflist_selection_get_list(ViewFile *vf)
1291 GtkTreeModel *store;
1292 GtkTreeSelection *selection;
1297 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1298 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1302 GtkTreePath *tpath = work->data;
1306 gtk_tree_model_get_iter(store, &iter, tpath);
1307 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1309 list = g_list_prepend(list, file_data_ref(fd));
1313 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1316 return g_list_reverse(list);
1319 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1321 GtkTreeModel *store;
1322 GtkTreeSelection *selection;
1327 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1328 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1332 GtkTreePath *tpath = work->data;
1336 gtk_tree_model_get_iter(store, &iter, tpath);
1337 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1339 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1343 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1346 return g_list_reverse(list);
1349 void vflist_select_all(ViewFile *vf)
1351 GtkTreeSelection *selection;
1353 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1354 gtk_tree_selection_select_all(selection);
1356 VFLIST_INFO(vf, select_fd) = NULL;
1359 void vflist_select_none(ViewFile *vf)
1361 GtkTreeSelection *selection;
1363 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1364 gtk_tree_selection_unselect_all(selection);
1367 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1372 tpath = gtk_tree_model_get_path(store, iter);
1373 result = gtk_tree_path_prev(tpath);
1375 gtk_tree_model_get_iter(store, iter, tpath);
1377 gtk_tree_path_free(tpath);
1382 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1384 if (!gtk_tree_model_get_iter_first(store, iter))
1389 GtkTreeIter next = *iter;
1391 if (gtk_tree_model_iter_next(store, &next))
1400 void vflist_select_invert(ViewFile *vf)
1403 GtkTreeSelection *selection;
1404 GtkTreeModel *store;
1407 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1408 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1410 /* Backward iteration prevents scrolling to the end of the list,
1411 * it scrolls to the first selected row instead. */
1412 valid = tree_model_get_iter_last(store, &iter);
1416 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1419 gtk_tree_selection_unselect_iter(selection, &iter);
1421 gtk_tree_selection_select_iter(selection, &iter);
1423 valid = tree_model_iter_prev(store, &iter);
1427 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1431 if (vflist_find_row(vf, fd, &iter) < 0) return;
1433 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1435 if (!vflist_row_is_selected(vf, fd))
1437 GtkTreeSelection *selection;
1438 GtkTreeModel *store;
1441 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1442 gtk_tree_selection_unselect_all(selection);
1443 gtk_tree_selection_select_iter(selection, &iter);
1444 vflist_move_cursor(vf, &iter);
1446 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1447 tpath = gtk_tree_model_get_path(store, &iter);
1448 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1449 gtk_tree_path_free(tpath);
1453 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1457 if (sel_fd->parent) sel_fd = sel_fd->parent;
1463 FileData *fd = work->data;
1467 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1471 vflist_select_by_fd(vf, fd);
1478 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1480 GtkTreeModel *store;
1482 GtkTreeSelection *selection;
1486 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1488 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1489 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1491 valid = gtk_tree_model_get_iter_first(store, &iter);
1495 gboolean mark_val, selected;
1496 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1498 mark_val = file_data_get_mark(fd, n);
1499 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1503 case MTS_MODE_SET: selected = mark_val;
1505 case MTS_MODE_OR: selected = mark_val | selected;
1507 case MTS_MODE_AND: selected = mark_val & selected;
1509 case MTS_MODE_MINUS: selected = !mark_val & selected;
1514 gtk_tree_selection_select_iter(selection, &iter);
1516 gtk_tree_selection_unselect_iter(selection, &iter);
1518 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1522 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1524 GtkTreeModel *store;
1525 GtkTreeSelection *selection;
1530 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1532 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1533 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1537 GtkTreePath *tpath = work->data;
1541 gtk_tree_model_get_iter(store, &iter, tpath);
1542 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1544 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1548 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1550 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1552 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1556 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1558 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1562 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1567 *-----------------------------------------------------------------------------
1569 *-----------------------------------------------------------------------------
1572 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1574 GtkTreeViewColumn *column;
1575 GtkCellRenderer *cell;
1579 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1580 if (!column) return;
1582 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1584 list = gtk_tree_view_column_get_cell_renderers(column);
1589 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1590 gtk_tree_view_column_set_visible(column, thumb);
1592 multiline = (thumb && options->thumbnails.max_height >= 48);
1594 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1595 if (!column) return;
1596 gtk_tree_view_column_set_visible(column, multiline);
1597 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1599 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1600 if (!column) return;
1601 gtk_tree_view_column_set_visible(column, !multiline);
1602 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1604 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1605 if (!column) return;
1606 gtk_tree_view_column_set_visible(column, !multiline);
1608 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1609 if (!column) return;
1610 gtk_tree_view_column_set_visible(column, !multiline);
1612 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1615 static void vflist_populate_view(ViewFile *vf)
1617 GtkTreeStore *store;
1619 GtkTreeRowReference *visible_row = NULL;
1623 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1624 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1626 vflist_thumb_stop(vf);
1630 vflist_store_clear(vf);
1635 if (GTK_WIDGET_REALIZED(vf->listview) &&
1636 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1638 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1639 gtk_tree_path_free(tpath);
1642 vflist_listview_set_columns(vf->listview, thumbs);
1644 selected = vflist_selection_get_list(vf);
1646 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1648 if (selected && vflist_selection_count(vf, NULL) == 0)
1650 /* all selected files disappeared */
1651 vflist_select_closest(vf, selected->data);
1654 filelist_free(selected);
1658 if (gtk_tree_row_reference_valid(visible_row))
1660 tpath = gtk_tree_row_reference_get_path(visible_row);
1661 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1662 gtk_tree_path_free(tpath);
1664 gtk_tree_row_reference_free(visible_row);
1668 vflist_thumb_update(vf);
1671 gint vflist_refresh(ViewFile *vf)
1676 old_list = vf->list;
1679 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1682 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1684 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1686 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1688 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1689 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1692 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1694 vflist_populate_view(vf);
1696 filelist_free(old_list);
1697 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1704 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1706 #define CELL_HEIGHT_OVERRIDE 512
1708 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1712 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1713 if (spec && G_IS_PARAM_SPEC_INT(spec))
1715 GParamSpecInt *spec_int;
1717 spec_int = G_PARAM_SPEC_INT(spec);
1718 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1722 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1724 static GdkColor color;
1725 static GtkWidget *done = NULL;
1731 style = gtk_widget_get_style(widget);
1732 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1733 shift_color(&color, -1, 0);
1740 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1741 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1743 ViewFile *vf = data;
1746 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1747 g_object_set(G_OBJECT(cell),
1748 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1749 "cell-background-set", set, NULL);
1752 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1754 GtkTreeViewColumn *column;
1755 GtkCellRenderer *renderer;
1757 column = gtk_tree_view_column_new();
1758 gtk_tree_view_column_set_title(column, title);
1759 gtk_tree_view_column_set_min_width(column, 4);
1763 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1764 renderer = gtk_cell_renderer_text_new();
1767 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1769 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1770 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1772 gtk_tree_view_column_set_expand(column, TRUE);
1776 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1777 renderer = gtk_cell_renderer_pixbuf_new();
1778 cell_renderer_height_override(renderer);
1779 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1780 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1783 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1784 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1785 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1787 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1790 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1792 ViewFile *vf = data;
1793 GtkTreeStore *store;
1794 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1800 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1801 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1804 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1806 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1808 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1810 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1811 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1812 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1814 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1815 gtk_tree_path_free(path);
1818 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1820 GtkTreeViewColumn *column;
1821 GtkCellRenderer *renderer;
1822 GtkTreeStore *store;
1825 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1827 renderer = gtk_cell_renderer_toggle_new();
1828 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1830 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1831 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1832 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1834 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1835 gtk_tree_view_column_set_fixed_width(column, 18);
1836 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1839 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1843 *-----------------------------------------------------------------------------
1845 *-----------------------------------------------------------------------------
1848 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1850 if (!dir_fd) return FALSE;
1851 if (vf->dir_fd == dir_fd) return TRUE;
1853 file_data_unref(vf->dir_fd);
1854 vf->dir_fd = file_data_ref(dir_fd);
1856 /* force complete reload */
1857 vflist_store_clear(vf);
1859 filelist_free(vf->list);
1862 return vf_refresh(vf);
1865 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1867 ViewFile *vf = data;
1869 file_data_unregister_notify_func(vf_notify_cb, vf);
1871 vflist_select_idle_cancel(vf);
1872 vf_refresh_idle_cancel(vf);
1873 vflist_thumb_stop(vf);
1875 filelist_free(vf->list);
1878 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1880 GtkTreeStore *store;
1881 GtkTreeSelection *selection;
1883 GType flist_types[FILE_COLUMN_COUNT];
1887 vf->info = g_new0(ViewFileInfoList, 1);
1889 VFLIST_INFO(vf, click_fd) = NULL;
1890 VFLIST_INFO(vf, select_fd) = NULL;
1891 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1893 VFLIST_INFO(vf, select_idle_id) = -1;
1895 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1896 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1897 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1898 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1899 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1900 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1901 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1902 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1903 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1904 flist_types[i] = G_TYPE_BOOLEAN;
1906 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1908 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1909 g_object_unref(store);
1911 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1912 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1913 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1915 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1916 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1920 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1922 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1923 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1927 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1928 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1931 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1932 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1935 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1936 g_assert(column == FILE_VIEW_COLUMN_NAME);
1939 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1940 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1943 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1944 g_assert(column == FILE_VIEW_COLUMN_DATE);
1947 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1951 void vflist_thumb_set(ViewFile *vf, gint enable)
1953 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1955 VFLIST_INFO(vf, thumbs_enabled) = enable;
1956 if (vf->layout) vf_refresh(vf);
1959 void vflist_marks_set(ViewFile *vf, gint enable)
1961 GList *columns, *work;
1963 if (vf->marks_enabled == enable) return;
1965 vf->marks_enabled = enable;
1967 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1972 GtkTreeViewColumn *column = work->data;
1973 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1976 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1977 gtk_tree_view_column_set_visible(column, enable);
1980 g_list_free(columns);