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_progress_count(GList *list, gint *count, gint *done)
983 FileData *fd = work->data;
986 if (fd->pixbuf) (*done)++;
988 if (fd->sidecar_files)
990 vflist_thumb_progress_count(fd->sidecar_files, count, done);
996 static gdouble vflist_thumb_progress(ViewFile *vf)
1001 vflist_thumb_progress_count(vf->list, &count, &done);
1003 DEBUG_1("thumb progress: %d of %d", done, count);
1004 return (gdouble)done / count;
1008 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
1010 if (vf->func_thumb_status)
1012 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1016 static void vflist_thumb_cleanup(ViewFile *vf)
1018 vflist_thumb_status(vf, 0.0, NULL);
1020 vf->thumbs_running = FALSE;
1022 thumb_loader_free(vf->thumbs_loader);
1023 vf->thumbs_loader = NULL;
1025 vf->thumbs_filedata = NULL;
1028 static void vflist_thumb_stop(ViewFile *vf)
1030 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1033 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1035 GtkTreeStore *store;
1038 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1040 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1041 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
1043 vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
1046 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1048 ViewFile *vf = data;
1050 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1052 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1055 while (vflist_thumb_next(vf));
1058 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1060 ViewFile *vf = data;
1062 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1064 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1067 while (vflist_thumb_next(vf));
1070 static gint vflist_thumb_next(ViewFile *vf)
1073 FileData *fd = NULL;
1075 /* first check the visible files */
1077 if (GTK_WIDGET_REALIZED(vf->listview) &&
1078 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1080 GtkTreeModel *store;
1084 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1085 gtk_tree_model_get_iter(store, &iter, tpath);
1086 gtk_tree_path_free(tpath);
1088 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1090 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1091 if (fd->pixbuf) fd = NULL;
1093 valid = gtk_tree_model_iter_next(store, &iter);
1097 /* then find first undone */
1101 GList *work = vf->list;
1104 FileData *fd_p = work->data;
1109 GList *work2 = fd_p->sidecar_files;
1111 while (work2 && !fd)
1114 if (!fd_p->pixbuf) fd = fd_p;
1115 work2 = work2->next;
1125 vflist_thumb_cleanup(vf);
1129 vf->thumbs_filedata = fd;
1131 thumb_loader_free(vf->thumbs_loader);
1133 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1134 thumb_loader_set_callbacks(vf->thumbs_loader,
1135 vflist_thumb_done_cb,
1136 vflist_thumb_error_cb,
1140 if (!thumb_loader_start(vf->thumbs_loader, fd))
1142 /* set icon to unknown, continue */
1143 DEBUG_1("thumb loader start failed %s", fd->path);
1144 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1152 static void vflist_thumb_update(ViewFile *vf)
1154 vflist_thumb_stop(vf);
1155 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1157 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1158 vf->thumbs_running = TRUE;
1160 while (vflist_thumb_next(vf));
1164 *-----------------------------------------------------------------------------
1166 *-----------------------------------------------------------------------------
1169 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1171 return g_list_nth_data(vf->list, row);
1174 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1179 if (!path) return -1;
1184 FileData *fd = work->data;
1185 if (strcmp(path, fd->path) == 0) return p;
1194 guint vflist_count(ViewFile *vf, gint64 *bytes)
1204 FileData *fd = work->data;
1212 return g_list_length(vf->list);
1215 GList *vflist_get_list(ViewFile *vf)
1223 FileData *fd = work->data;
1226 list = g_list_prepend(list, file_data_ref(fd));
1229 return g_list_reverse(list);
1233 *-----------------------------------------------------------------------------
1235 *-----------------------------------------------------------------------------
1238 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1240 GtkTreeModel *store;
1241 GtkTreeSelection *selection;
1246 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1247 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1249 while (!found && work)
1251 GtkTreePath *tpath = work->data;
1255 gtk_tree_model_get_iter(store, &iter, tpath);
1256 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1257 if (fd_n == fd) found = TRUE;
1260 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1266 gint vflist_index_is_selected(ViewFile *vf, gint row)
1270 fd = vf_index_get_data(vf, row);
1271 return vflist_row_is_selected(vf, fd);
1274 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1276 GtkTreeModel *store;
1277 GtkTreeSelection *selection;
1281 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1282 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1292 GtkTreePath *tpath = work->data;
1296 gtk_tree_model_get_iter(store, &iter, tpath);
1297 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1306 count = g_list_length(slist);
1307 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1313 GList *vflist_selection_get_list(ViewFile *vf)
1315 GtkTreeModel *store;
1316 GtkTreeSelection *selection;
1321 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1322 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1326 GtkTreePath *tpath = work->data;
1330 gtk_tree_model_get_iter(store, &iter, tpath);
1331 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1333 list = g_list_prepend(list, file_data_ref(fd));
1337 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1340 return g_list_reverse(list);
1343 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1345 GtkTreeModel *store;
1346 GtkTreeSelection *selection;
1351 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1352 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1356 GtkTreePath *tpath = work->data;
1360 gtk_tree_model_get_iter(store, &iter, tpath);
1361 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1363 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1367 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1370 return g_list_reverse(list);
1373 void vflist_select_all(ViewFile *vf)
1375 GtkTreeSelection *selection;
1377 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1378 gtk_tree_selection_select_all(selection);
1380 VFLIST_INFO(vf, select_fd) = NULL;
1383 void vflist_select_none(ViewFile *vf)
1385 GtkTreeSelection *selection;
1387 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1388 gtk_tree_selection_unselect_all(selection);
1391 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1396 tpath = gtk_tree_model_get_path(store, iter);
1397 result = gtk_tree_path_prev(tpath);
1399 gtk_tree_model_get_iter(store, iter, tpath);
1401 gtk_tree_path_free(tpath);
1406 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1408 if (!gtk_tree_model_get_iter_first(store, iter))
1413 GtkTreeIter next = *iter;
1415 if (gtk_tree_model_iter_next(store, &next))
1424 void vflist_select_invert(ViewFile *vf)
1427 GtkTreeSelection *selection;
1428 GtkTreeModel *store;
1431 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1432 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1434 /* Backward iteration prevents scrolling to the end of the list,
1435 * it scrolls to the first selected row instead. */
1436 valid = tree_model_get_iter_last(store, &iter);
1440 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1443 gtk_tree_selection_unselect_iter(selection, &iter);
1445 gtk_tree_selection_select_iter(selection, &iter);
1447 valid = tree_model_iter_prev(store, &iter);
1451 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1455 if (vflist_find_row(vf, fd, &iter) < 0) return;
1457 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1459 if (!vflist_row_is_selected(vf, fd))
1461 GtkTreeSelection *selection;
1462 GtkTreeModel *store;
1465 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1466 gtk_tree_selection_unselect_all(selection);
1467 gtk_tree_selection_select_iter(selection, &iter);
1468 vflist_move_cursor(vf, &iter);
1470 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1471 tpath = gtk_tree_model_get_path(store, &iter);
1472 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1473 gtk_tree_path_free(tpath);
1477 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1481 if (sel_fd->parent) sel_fd = sel_fd->parent;
1487 FileData *fd = work->data;
1491 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1495 vflist_select_by_fd(vf, fd);
1502 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1504 GtkTreeModel *store;
1506 GtkTreeSelection *selection;
1510 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1512 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1513 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1515 valid = gtk_tree_model_get_iter_first(store, &iter);
1519 gboolean mark_val, selected;
1520 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1522 mark_val = file_data_get_mark(fd, n);
1523 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1527 case MTS_MODE_SET: selected = mark_val;
1529 case MTS_MODE_OR: selected = mark_val | selected;
1531 case MTS_MODE_AND: selected = mark_val & selected;
1533 case MTS_MODE_MINUS: selected = !mark_val & selected;
1538 gtk_tree_selection_select_iter(selection, &iter);
1540 gtk_tree_selection_unselect_iter(selection, &iter);
1542 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1546 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1548 GtkTreeModel *store;
1549 GtkTreeSelection *selection;
1554 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1556 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1557 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1561 GtkTreePath *tpath = work->data;
1565 gtk_tree_model_get_iter(store, &iter, tpath);
1566 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1568 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1572 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1574 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1576 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1580 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1582 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1586 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1591 *-----------------------------------------------------------------------------
1593 *-----------------------------------------------------------------------------
1596 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1598 GtkTreeViewColumn *column;
1599 GtkCellRenderer *cell;
1603 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1604 if (!column) return;
1606 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1608 list = gtk_tree_view_column_get_cell_renderers(column);
1613 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1614 gtk_tree_view_column_set_visible(column, thumb);
1616 multiline = (thumb && options->thumbnails.max_height >= 48);
1618 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1619 if (!column) return;
1620 gtk_tree_view_column_set_visible(column, multiline);
1621 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1623 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1624 if (!column) return;
1625 gtk_tree_view_column_set_visible(column, !multiline);
1626 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1628 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1629 if (!column) return;
1630 gtk_tree_view_column_set_visible(column, !multiline);
1632 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1633 if (!column) return;
1634 gtk_tree_view_column_set_visible(column, !multiline);
1636 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1639 static void vflist_populate_view(ViewFile *vf)
1641 GtkTreeStore *store;
1643 GtkTreeRowReference *visible_row = NULL;
1647 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1648 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1650 vflist_thumb_stop(vf);
1654 vflist_store_clear(vf);
1659 if (GTK_WIDGET_REALIZED(vf->listview) &&
1660 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1662 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1663 gtk_tree_path_free(tpath);
1666 vflist_listview_set_columns(vf->listview, thumbs);
1668 selected = vflist_selection_get_list(vf);
1670 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1672 if (selected && vflist_selection_count(vf, NULL) == 0)
1674 /* all selected files disappeared */
1675 vflist_select_closest(vf, selected->data);
1678 filelist_free(selected);
1682 if (gtk_tree_row_reference_valid(visible_row))
1684 tpath = gtk_tree_row_reference_get_path(visible_row);
1685 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1686 gtk_tree_path_free(tpath);
1688 gtk_tree_row_reference_free(visible_row);
1692 vflist_thumb_update(vf);
1695 gint vflist_refresh(ViewFile *vf)
1700 old_list = vf->list;
1703 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1706 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1708 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1710 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1712 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1713 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1716 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1718 vflist_populate_view(vf);
1720 filelist_free(old_list);
1721 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1728 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1730 #define CELL_HEIGHT_OVERRIDE 512
1732 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1736 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1737 if (spec && G_IS_PARAM_SPEC_INT(spec))
1739 GParamSpecInt *spec_int;
1741 spec_int = G_PARAM_SPEC_INT(spec);
1742 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1746 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1748 static GdkColor color;
1749 static GtkWidget *done = NULL;
1755 style = gtk_widget_get_style(widget);
1756 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1757 shift_color(&color, -1, 0);
1764 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1765 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1767 ViewFile *vf = data;
1770 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1771 g_object_set(G_OBJECT(cell),
1772 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1773 "cell-background-set", set, NULL);
1776 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1778 GtkTreeViewColumn *column;
1779 GtkCellRenderer *renderer;
1781 column = gtk_tree_view_column_new();
1782 gtk_tree_view_column_set_title(column, title);
1783 gtk_tree_view_column_set_min_width(column, 4);
1787 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1788 renderer = gtk_cell_renderer_text_new();
1791 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1793 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1794 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1796 gtk_tree_view_column_set_expand(column, TRUE);
1800 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1801 renderer = gtk_cell_renderer_pixbuf_new();
1802 cell_renderer_height_override(renderer);
1803 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1804 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1807 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1808 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1809 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1811 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1814 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1816 ViewFile *vf = data;
1817 GtkTreeStore *store;
1818 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1824 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1825 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1828 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1830 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1832 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1834 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1835 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1836 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1838 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1839 gtk_tree_path_free(path);
1842 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1844 GtkTreeViewColumn *column;
1845 GtkCellRenderer *renderer;
1846 GtkTreeStore *store;
1849 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1851 renderer = gtk_cell_renderer_toggle_new();
1852 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1854 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1855 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1856 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1858 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1859 gtk_tree_view_column_set_fixed_width(column, 18);
1860 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1863 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1867 *-----------------------------------------------------------------------------
1869 *-----------------------------------------------------------------------------
1872 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1874 if (!dir_fd) return FALSE;
1875 if (vf->dir_fd == dir_fd) return TRUE;
1877 file_data_unref(vf->dir_fd);
1878 vf->dir_fd = file_data_ref(dir_fd);
1880 /* force complete reload */
1881 vflist_store_clear(vf);
1883 filelist_free(vf->list);
1886 return vf_refresh(vf);
1889 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1891 ViewFile *vf = data;
1893 file_data_unregister_notify_func(vf_notify_cb, vf);
1895 vflist_select_idle_cancel(vf);
1896 vf_refresh_idle_cancel(vf);
1897 vflist_thumb_stop(vf);
1899 filelist_free(vf->list);
1902 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1904 GtkTreeStore *store;
1905 GtkTreeSelection *selection;
1907 GType flist_types[FILE_COLUMN_COUNT];
1911 vf->info = g_new0(ViewFileInfoList, 1);
1913 VFLIST_INFO(vf, click_fd) = NULL;
1914 VFLIST_INFO(vf, select_fd) = NULL;
1915 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1917 VFLIST_INFO(vf, select_idle_id) = -1;
1919 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1920 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1921 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1922 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1923 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1924 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1925 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1926 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1927 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1928 flist_types[i] = G_TYPE_BOOLEAN;
1930 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1932 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1933 g_object_unref(store);
1935 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1936 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1937 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1939 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1940 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1944 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1946 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1947 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1951 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1952 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1955 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1956 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1959 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1960 g_assert(column == FILE_VIEW_COLUMN_NAME);
1963 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1964 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1967 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1968 g_assert(column == FILE_VIEW_COLUMN_DATE);
1971 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1975 void vflist_thumb_set(ViewFile *vf, gint enable)
1977 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1979 VFLIST_INFO(vf, thumbs_enabled) = enable;
1980 if (vf->layout) vf_refresh(vf);
1983 void vflist_marks_set(ViewFile *vf, gint enable)
1985 GList *columns, *work;
1987 if (vf->marks_enabled == enable) return;
1989 vf->marks_enabled = enable;
1991 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1996 GtkTreeViewColumn *column = work->data;
1997 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
2000 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
2001 gtk_tree_view_column_set_visible(column, enable);
2004 g_list_free(columns);