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 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1012 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
1014 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
1017 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1019 ViewFile *vf = data;
1021 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1023 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1026 while (vflist_thumb_next(vf));
1029 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1031 ViewFile *vf = data;
1033 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1035 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1038 while (vflist_thumb_next(vf));
1041 static gint vflist_thumb_next(ViewFile *vf)
1044 FileData *fd = NULL;
1046 /* first check the visible files */
1048 if (GTK_WIDGET_REALIZED(vf->listview) &&
1049 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1051 GtkTreeModel *store;
1055 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1056 gtk_tree_model_get_iter(store, &iter, tpath);
1057 gtk_tree_path_free(tpath);
1059 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1061 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1062 if (fd->pixbuf) fd = NULL;
1064 valid = gtk_tree_model_iter_next(store, &iter);
1068 /* then find first undone */
1072 GList *work = vf->list;
1075 FileData *fd_p = work->data;
1080 GList *work2 = fd_p->sidecar_files;
1082 while (work2 && !fd)
1085 if (!fd_p->pixbuf) fd = fd_p;
1086 work2 = work2->next;
1096 vflist_thumb_cleanup(vf);
1102 vf->thumbs_filedata = fd;
1104 thumb_loader_free(vf->thumbs_loader);
1106 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1107 thumb_loader_set_callbacks(vf->thumbs_loader,
1108 vflist_thumb_done_cb,
1109 vflist_thumb_error_cb,
1113 if (!thumb_loader_start(vf->thumbs_loader, fd))
1115 /* set icon to unknown, continue */
1116 DEBUG_1("thumb loader start failed %s", fd->path);
1117 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1125 static void vflist_thumb_update(ViewFile *vf)
1127 vflist_thumb_stop(vf);
1128 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1130 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1131 vf->thumbs_running = TRUE;
1133 while (vflist_thumb_next(vf));
1137 *-----------------------------------------------------------------------------
1139 *-----------------------------------------------------------------------------
1142 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1144 return g_list_nth_data(vf->list, row);
1147 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1152 if (!path) return -1;
1157 FileData *fd = work->data;
1158 if (strcmp(path, fd->path) == 0) return p;
1167 guint vflist_count(ViewFile *vf, gint64 *bytes)
1177 FileData *fd = work->data;
1185 return g_list_length(vf->list);
1188 GList *vflist_get_list(ViewFile *vf)
1196 FileData *fd = work->data;
1199 list = g_list_prepend(list, file_data_ref(fd));
1202 return g_list_reverse(list);
1206 *-----------------------------------------------------------------------------
1208 *-----------------------------------------------------------------------------
1211 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1213 GtkTreeModel *store;
1214 GtkTreeSelection *selection;
1219 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1220 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1222 while (!found && work)
1224 GtkTreePath *tpath = work->data;
1228 gtk_tree_model_get_iter(store, &iter, tpath);
1229 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1230 if (fd_n == fd) found = TRUE;
1233 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1239 gint vflist_index_is_selected(ViewFile *vf, gint row)
1243 fd = vf_index_get_data(vf, row);
1244 return vflist_row_is_selected(vf, fd);
1247 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1249 GtkTreeModel *store;
1250 GtkTreeSelection *selection;
1254 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1255 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1265 GtkTreePath *tpath = work->data;
1269 gtk_tree_model_get_iter(store, &iter, tpath);
1270 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1279 count = g_list_length(slist);
1280 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1286 GList *vflist_selection_get_list(ViewFile *vf)
1288 GtkTreeModel *store;
1289 GtkTreeSelection *selection;
1294 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1295 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1299 GtkTreePath *tpath = work->data;
1303 gtk_tree_model_get_iter(store, &iter, tpath);
1304 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1306 list = g_list_prepend(list, file_data_ref(fd));
1310 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1313 return g_list_reverse(list);
1316 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1318 GtkTreeModel *store;
1319 GtkTreeSelection *selection;
1324 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1325 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1329 GtkTreePath *tpath = work->data;
1333 gtk_tree_model_get_iter(store, &iter, tpath);
1334 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1336 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1340 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1343 return g_list_reverse(list);
1346 void vflist_select_all(ViewFile *vf)
1348 GtkTreeSelection *selection;
1350 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1351 gtk_tree_selection_select_all(selection);
1353 VFLIST_INFO(vf, select_fd) = NULL;
1356 void vflist_select_none(ViewFile *vf)
1358 GtkTreeSelection *selection;
1360 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1361 gtk_tree_selection_unselect_all(selection);
1364 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1369 tpath = gtk_tree_model_get_path(store, iter);
1370 result = gtk_tree_path_prev(tpath);
1372 gtk_tree_model_get_iter(store, iter, tpath);
1374 gtk_tree_path_free(tpath);
1379 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1381 if (!gtk_tree_model_get_iter_first(store, iter))
1386 GtkTreeIter next = *iter;
1388 if (gtk_tree_model_iter_next(store, &next))
1397 void vflist_select_invert(ViewFile *vf)
1400 GtkTreeSelection *selection;
1401 GtkTreeModel *store;
1404 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1405 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1407 /* Backward iteration prevents scrolling to the end of the list,
1408 * it scrolls to the first selected row instead. */
1409 valid = tree_model_get_iter_last(store, &iter);
1413 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1416 gtk_tree_selection_unselect_iter(selection, &iter);
1418 gtk_tree_selection_select_iter(selection, &iter);
1420 valid = tree_model_iter_prev(store, &iter);
1424 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1428 if (vflist_find_row(vf, fd, &iter) < 0) return;
1430 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1432 if (!vflist_row_is_selected(vf, fd))
1434 GtkTreeSelection *selection;
1435 GtkTreeModel *store;
1438 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1439 gtk_tree_selection_unselect_all(selection);
1440 gtk_tree_selection_select_iter(selection, &iter);
1441 vflist_move_cursor(vf, &iter);
1443 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1444 tpath = gtk_tree_model_get_path(store, &iter);
1445 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1446 gtk_tree_path_free(tpath);
1450 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1454 if (sel_fd->parent) sel_fd = sel_fd->parent;
1460 FileData *fd = work->data;
1464 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1468 vflist_select_by_fd(vf, fd);
1475 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1477 GtkTreeModel *store;
1479 GtkTreeSelection *selection;
1483 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1485 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1486 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1488 valid = gtk_tree_model_get_iter_first(store, &iter);
1492 gboolean mark_val, selected;
1493 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1495 mark_val = file_data_get_mark(fd, n);
1496 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1500 case MTS_MODE_SET: selected = mark_val;
1502 case MTS_MODE_OR: selected = mark_val | selected;
1504 case MTS_MODE_AND: selected = mark_val & selected;
1506 case MTS_MODE_MINUS: selected = !mark_val & selected;
1511 gtk_tree_selection_select_iter(selection, &iter);
1513 gtk_tree_selection_unselect_iter(selection, &iter);
1515 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1519 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1521 GtkTreeModel *store;
1522 GtkTreeSelection *selection;
1527 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1529 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1530 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1534 GtkTreePath *tpath = work->data;
1538 gtk_tree_model_get_iter(store, &iter, tpath);
1539 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1541 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1545 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1547 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1549 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1553 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1555 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1559 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1564 *-----------------------------------------------------------------------------
1566 *-----------------------------------------------------------------------------
1569 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1571 GtkTreeViewColumn *column;
1572 GtkCellRenderer *cell;
1576 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1577 if (!column) return;
1579 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1581 list = gtk_tree_view_column_get_cell_renderers(column);
1586 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1587 gtk_tree_view_column_set_visible(column, thumb);
1589 multiline = (thumb && options->thumbnails.max_height >= 48);
1591 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1592 if (!column) return;
1593 gtk_tree_view_column_set_visible(column, multiline);
1594 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1596 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1597 if (!column) return;
1598 gtk_tree_view_column_set_visible(column, !multiline);
1599 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1601 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1602 if (!column) return;
1603 gtk_tree_view_column_set_visible(column, !multiline);
1605 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1606 if (!column) return;
1607 gtk_tree_view_column_set_visible(column, !multiline);
1609 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1612 static void vflist_populate_view(ViewFile *vf)
1614 GtkTreeStore *store;
1616 GtkTreeRowReference *visible_row = NULL;
1620 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1621 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1623 vflist_thumb_stop(vf);
1627 vflist_store_clear(vf);
1632 if (GTK_WIDGET_REALIZED(vf->listview) &&
1633 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1635 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1636 gtk_tree_path_free(tpath);
1639 vflist_listview_set_columns(vf->listview, thumbs);
1641 selected = vflist_selection_get_list(vf);
1643 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1645 if (selected && vflist_selection_count(vf, NULL) == 0)
1647 /* all selected files disappeared */
1648 vflist_select_closest(vf, selected->data);
1651 filelist_free(selected);
1655 if (gtk_tree_row_reference_valid(visible_row))
1657 tpath = gtk_tree_row_reference_get_path(visible_row);
1658 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1659 gtk_tree_path_free(tpath);
1661 gtk_tree_row_reference_free(visible_row);
1665 vflist_thumb_update(vf);
1668 gint vflist_refresh(ViewFile *vf)
1673 old_list = vf->list;
1676 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1679 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1681 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1683 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1685 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1686 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1689 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1691 vflist_populate_view(vf);
1693 filelist_free(old_list);
1694 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1701 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1703 #define CELL_HEIGHT_OVERRIDE 512
1705 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1709 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1710 if (spec && G_IS_PARAM_SPEC_INT(spec))
1712 GParamSpecInt *spec_int;
1714 spec_int = G_PARAM_SPEC_INT(spec);
1715 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1719 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1721 static GdkColor color;
1722 static GtkWidget *done = NULL;
1728 style = gtk_widget_get_style(widget);
1729 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1730 shift_color(&color, -1, 0);
1737 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1738 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1740 ViewFile *vf = data;
1743 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1744 g_object_set(G_OBJECT(cell),
1745 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1746 "cell-background-set", set, NULL);
1749 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1751 GtkTreeViewColumn *column;
1752 GtkCellRenderer *renderer;
1754 column = gtk_tree_view_column_new();
1755 gtk_tree_view_column_set_title(column, title);
1756 gtk_tree_view_column_set_min_width(column, 4);
1760 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1761 renderer = gtk_cell_renderer_text_new();
1764 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1766 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1767 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1769 gtk_tree_view_column_set_expand(column, TRUE);
1773 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1774 renderer = gtk_cell_renderer_pixbuf_new();
1775 cell_renderer_height_override(renderer);
1776 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1777 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1780 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1781 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1782 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1784 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1787 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1789 ViewFile *vf = data;
1790 GtkTreeStore *store;
1791 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1797 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1798 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1801 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1803 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1805 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1807 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1808 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1809 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1811 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1812 gtk_tree_path_free(path);
1815 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1817 GtkTreeViewColumn *column;
1818 GtkCellRenderer *renderer;
1819 GtkTreeStore *store;
1822 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1824 renderer = gtk_cell_renderer_toggle_new();
1825 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1827 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1828 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1829 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1831 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1832 gtk_tree_view_column_set_fixed_width(column, 18);
1833 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1836 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1840 *-----------------------------------------------------------------------------
1842 *-----------------------------------------------------------------------------
1845 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1847 if (!dir_fd) return FALSE;
1848 if (vf->dir_fd == dir_fd) return TRUE;
1850 file_data_unref(vf->dir_fd);
1851 vf->dir_fd = file_data_ref(dir_fd);
1853 /* force complete reload */
1854 vflist_store_clear(vf);
1856 filelist_free(vf->list);
1859 return vf_refresh(vf);
1862 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1864 ViewFile *vf = data;
1866 file_data_unregister_notify_func(vf_notify_cb, vf);
1868 vflist_select_idle_cancel(vf);
1869 vf_refresh_idle_cancel(vf);
1870 vflist_thumb_stop(vf);
1872 filelist_free(vf->list);
1875 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1877 GtkTreeStore *store;
1878 GtkTreeSelection *selection;
1880 GType flist_types[FILE_COLUMN_COUNT];
1884 vf->info = g_new0(ViewFileInfoList, 1);
1886 VFLIST_INFO(vf, click_fd) = NULL;
1887 VFLIST_INFO(vf, select_fd) = NULL;
1888 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1890 VFLIST_INFO(vf, select_idle_id) = -1;
1892 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1893 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1894 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1895 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1896 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1897 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1898 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1899 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1900 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1901 flist_types[i] = G_TYPE_BOOLEAN;
1903 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1905 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1906 g_object_unref(store);
1908 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1909 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1910 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1912 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1913 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1917 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1919 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1920 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1924 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1925 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1928 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1929 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1932 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1933 g_assert(column == FILE_VIEW_COLUMN_NAME);
1936 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1937 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1940 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1941 g_assert(column == FILE_VIEW_COLUMN_DATE);
1944 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1948 void vflist_thumb_set(ViewFile *vf, gint enable)
1950 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1952 VFLIST_INFO(vf, thumbs_enabled) = enable;
1953 if (vf->layout) vf_refresh(vf);
1956 void vflist_marks_set(ViewFile *vf, gint enable)
1958 GList *columns, *work;
1960 if (vf->marks_enabled == enable) return;
1962 vf->marks_enabled = enable;
1964 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1969 GtkTreeViewColumn *column = work->data;
1970 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1973 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1974 gtk_tree_view_column_set_visible(column, enable);
1977 g_list_free(columns);