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_fileops.h"
28 #include "ui_tree_edit.h"
29 #include "uri_utils.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)->thumb_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)->thumb_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);
425 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
426 file_util_rename_simple(fd, new_path, vf->listview);
435 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
443 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
444 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
445 tpath = gtk_tree_model_get_path(store, &iter);
446 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
447 gtk_tree_path_free(tpath);
449 popup_menu_position_clamp(menu, x, y, 0);
452 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
457 if (event->keyval != GDK_Menu) return FALSE;
459 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
465 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
466 gtk_tree_model_get_iter(store, &iter, tpath);
467 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
468 gtk_tree_path_free(tpath);
472 VFLIST_INFO(vf, click_fd) = NULL;
475 vf->popup = vf_pop_menu(vf);
476 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
481 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
487 GtkTreeViewColumn *column;
489 vf->clicked_mark = 0;
491 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
492 &tpath, &column, NULL, NULL))
495 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
497 if (bevent->button == MOUSE_BUTTON_LEFT &&
498 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
501 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
502 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
504 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
506 gtk_tree_model_get_iter(store, &iter, tpath);
507 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
509 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
511 gtk_tree_path_free(tpath);
514 VFLIST_INFO(vf, click_fd) = fd;
516 if (bevent->button == MOUSE_BUTTON_RIGHT)
518 vf->popup = vf_pop_menu(vf);
519 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
520 bevent->button, bevent->time);
524 if (!fd) return FALSE;
526 if (bevent->button == MOUSE_BUTTON_MIDDLE)
528 if (!vflist_row_is_selected(vf, fd))
530 vflist_color_set(vf, fd, TRUE);
536 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
537 !(bevent->state & GDK_SHIFT_MASK ) &&
538 !(bevent->state & GDK_CONTROL_MASK ) &&
539 vflist_row_is_selected(vf, fd))
541 GtkTreeSelection *selection;
543 gtk_widget_grab_focus(widget);
546 /* returning FALSE and further processing of the event is needed for
547 correct operation of the expander, to show the sidecar files.
548 It however resets the selection of multiple files. With this condition
549 it should work for both cases */
550 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
551 return (gtk_tree_selection_count_selected_rows(selection) > 1);
555 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
557 if (vf->layout) layout_image_full_screen_start(vf->layout);
564 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
571 if (bevent->button == MOUSE_BUTTON_MIDDLE)
573 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
576 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
581 if ((bevent->x != 0 || bevent->y != 0) &&
582 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
583 &tpath, NULL, NULL, NULL))
587 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
588 gtk_tree_model_get_iter(store, &iter, tpath);
589 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
590 gtk_tree_path_free(tpath);
593 if (bevent->button == MOUSE_BUTTON_MIDDLE)
595 if (fd && VFLIST_INFO(vf, click_fd) == fd)
597 GtkTreeSelection *selection;
599 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
600 if (vflist_row_is_selected(vf, fd))
602 gtk_tree_selection_unselect_iter(selection, &iter);
606 gtk_tree_selection_select_iter(selection, &iter);
612 if (fd && VFLIST_INFO(vf, click_fd) == fd &&
613 !(bevent->state & GDK_SHIFT_MASK ) &&
614 !(bevent->state & GDK_CONTROL_MASK ) &&
615 vflist_row_is_selected(vf, fd))
617 GtkTreeSelection *selection;
619 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
620 gtk_tree_selection_unselect_all(selection);
621 gtk_tree_selection_select_iter(selection, &iter);
622 vflist_move_cursor(vf, &iter);
623 // return TRUE;// FIXME - expand
629 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
631 FileData *read_ahead_fd = NULL;
636 cur_fd = layout_image_get_fd(vf->layout);
637 if (sel_fd == cur_fd) return; /* no change */
639 row = g_list_index(vf->list, sel_fd);
640 // FIXME sidecar data
642 if (sel_fd && options->image.enable_read_ahead && row >= 0)
644 if (row > g_list_index(vf->list, cur_fd) &&
645 (guint) (row + 1) < vf_count(vf, NULL))
647 read_ahead_fd = vf_index_get_data(vf, row + 1);
651 read_ahead_fd = vf_index_get_data(vf, row - 1);
655 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
658 static gint vflist_select_idle_cb(gpointer data)
664 VFLIST_INFO(vf, select_idle_id) = -1;
670 if (VFLIST_INFO(vf, select_fd))
672 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
673 VFLIST_INFO(vf, select_fd) = NULL;
676 VFLIST_INFO(vf, select_idle_id) = -1;
680 static void vflist_select_idle_cancel(ViewFile *vf)
682 if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
683 VFLIST_INFO(vf, select_idle_id) = -1;
686 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
687 gboolean path_currently_selected, gpointer data)
692 if (!path_currently_selected &&
693 gtk_tree_model_get_iter(store, &iter, tpath))
695 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
699 VFLIST_INFO(vf, select_fd) = NULL;
703 VFLIST_INFO(vf, select_idle_id) == -1)
705 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
712 *-----------------------------------------------------------------------------
714 *-----------------------------------------------------------------------------
718 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
719 gboolean path_currently_selected, gpointer data)
725 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
728 gchar *sidecars = NULL;
729 gchar *name_sidecars;
731 const gchar *time = text_from_time(fd->date);
732 name_sidecars = (gchar *)fd->name;
734 if (fd->sidecar_files)
736 sidecars = file_data_sc_list_to_string(fd);
737 name_sidecars = g_strdup_printf("%s %s", fd->name, sidecars);
739 size = text_from_size(fd->size);
741 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
743 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
744 FILE_COLUMN_VERSION, fd->version,
745 FILE_COLUMN_THUMB, fd->thumb_pixbuf,
746 FILE_COLUMN_MULTILINE, multiline,
747 FILE_COLUMN_NAME, name_sidecars,
748 FILE_COLUMN_SIZE, size,
749 FILE_COLUMN_DATE, time,
750 #define STORE_SET_IS_SLOW 1
751 #if STORE_SET_IS_SLOW
752 /* this is 3x faster on a directory with 20000 files */
753 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
754 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
755 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
756 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
757 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
758 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
759 #if FILEDATA_MARKS_SIZE != 6
760 #error this needs to be updated
763 FILE_COLUMN_COLOR, FALSE, -1);
765 #if !STORE_SET_IS_SLOW
768 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
769 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
776 g_free(name_sidecars);
781 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
786 gint num_ordered = 0;
787 gint num_prepended = 0;
789 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
795 FileData *fd = work->data;
800 FileData *old_fd = NULL;
801 gint old_version = 0;
806 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
807 FILE_COLUMN_POINTER, &old_fd,
808 FILE_COLUMN_VERSION, &old_version,
818 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
820 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
822 if (match == 0) g_warning("multiple fd for the same path");
837 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
842 here should be used gtk_tree_store_append, but this function seems to be O(n)
843 and it seems to be much faster to add new entries to the beginning and reorder later
846 gtk_tree_store_prepend(store, &new, parent_iter);
849 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
850 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
852 if (g_list_find(selected, fd))
854 /* renamed files - the same fd appears at different position - select it again*/
855 GtkTreeSelection *selection;
856 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
857 gtk_tree_selection_select_iter(selection, &new);
864 file_data_unref(old_fd);
865 valid = gtk_tree_store_remove(store, &iter);
869 if (fd->version != old_version)
871 vflist_setup_iter(vf, store, &iter, fd);
872 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
875 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
886 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
887 file_data_unref(old_fd);
889 valid = gtk_tree_store_remove(store, &iter);
892 /* move the prepended entries to the correct position */
896 gint num_total = num_prepended + num_ordered;
897 gint *new_order = g_malloc(num_total * sizeof(gint));
899 for (i = 0; i < num_total; i++)
902 new_order[i] = num_prepended + i;
904 new_order[i] = num_total - 1 - i;
906 gtk_tree_store_reorder(store, parent_iter, new_order);
912 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
915 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
920 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
921 if (!vf->list) return;
927 FileData *fd = work->data;
928 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
933 vf->sort_method = type;
934 vf->sort_ascend = ascend;
936 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
938 new_order = g_malloc(i * sizeof(gint));
944 FileData *fd = work->data;
945 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
950 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
951 gtk_tree_store_reorder(store, NULL, new_order);
954 g_hash_table_destroy(fd_idx_hash);
958 *-----------------------------------------------------------------------------
960 *-----------------------------------------------------------------------------
963 static gint vflist_thumb_next(ViewFile *vf);
965 static void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
970 FileData *fd = work->data;
973 if (fd->thumb_pixbuf) (*done)++;
975 if (fd->sidecar_files)
977 vflist_thumb_progress_count(fd->sidecar_files, count, done);
983 static gdouble vflist_thumb_progress(ViewFile *vf)
988 vflist_thumb_progress_count(vf->list, &count, &done);
990 DEBUG_1("thumb progress: %d of %d", done, count);
991 return (gdouble)done / count;
995 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
997 if (vf->func_thumb_status)
999 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1003 static void vflist_thumb_cleanup(ViewFile *vf)
1005 vflist_thumb_status(vf, 0.0, NULL);
1007 vf->thumbs_running = FALSE;
1009 thumb_loader_free(vf->thumbs_loader);
1010 vf->thumbs_loader = NULL;
1012 vf->thumbs_filedata = NULL;
1015 static void vflist_thumb_stop(ViewFile *vf)
1017 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1020 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1022 GtkTreeStore *store;
1025 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1027 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1028 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1030 vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
1033 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1035 ViewFile *vf = data;
1037 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1039 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1042 while (vflist_thumb_next(vf));
1045 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1047 ViewFile *vf = data;
1049 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1051 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1054 while (vflist_thumb_next(vf));
1057 static gint vflist_thumb_next(ViewFile *vf)
1060 FileData *fd = NULL;
1062 /* first check the visible files */
1064 if (GTK_WIDGET_REALIZED(vf->listview) &&
1065 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1067 GtkTreeModel *store;
1071 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1072 gtk_tree_model_get_iter(store, &iter, tpath);
1073 gtk_tree_path_free(tpath);
1075 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1077 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1078 if (fd->thumb_pixbuf) fd = NULL;
1080 valid = gtk_tree_model_iter_next(store, &iter);
1084 /* then find first undone */
1088 GList *work = vf->list;
1091 FileData *fd_p = work->data;
1092 if (!fd_p->thumb_pixbuf)
1096 GList *work2 = fd_p->sidecar_files;
1098 while (work2 && !fd)
1101 if (!fd_p->thumb_pixbuf) fd = fd_p;
1102 work2 = work2->next;
1112 vflist_thumb_cleanup(vf);
1116 vf->thumbs_filedata = fd;
1118 thumb_loader_free(vf->thumbs_loader);
1120 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1121 thumb_loader_set_callbacks(vf->thumbs_loader,
1122 vflist_thumb_done_cb,
1123 vflist_thumb_error_cb,
1127 if (!thumb_loader_start(vf->thumbs_loader, fd))
1129 /* set icon to unknown, continue */
1130 DEBUG_1("thumb loader start failed %s", fd->path);
1131 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1139 static void vflist_thumb_update(ViewFile *vf)
1141 vflist_thumb_stop(vf);
1142 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1144 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1145 vf->thumbs_running = TRUE;
1147 while (vflist_thumb_next(vf));
1151 *-----------------------------------------------------------------------------
1153 *-----------------------------------------------------------------------------
1156 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1158 return g_list_nth_data(vf->list, row);
1161 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1166 if (!path) return -1;
1171 FileData *fd = work->data;
1172 if (strcmp(path, fd->path) == 0) return p;
1181 guint vflist_count(ViewFile *vf, gint64 *bytes)
1191 FileData *fd = work->data;
1199 return g_list_length(vf->list);
1202 GList *vflist_get_list(ViewFile *vf)
1210 FileData *fd = work->data;
1213 list = g_list_prepend(list, file_data_ref(fd));
1216 return g_list_reverse(list);
1220 *-----------------------------------------------------------------------------
1222 *-----------------------------------------------------------------------------
1225 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1227 GtkTreeModel *store;
1228 GtkTreeSelection *selection;
1233 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1234 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1236 while (!found && work)
1238 GtkTreePath *tpath = work->data;
1242 gtk_tree_model_get_iter(store, &iter, tpath);
1243 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1244 if (fd_n == fd) found = TRUE;
1247 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1253 gint vflist_index_is_selected(ViewFile *vf, gint row)
1257 fd = vf_index_get_data(vf, row);
1258 return vflist_row_is_selected(vf, fd);
1261 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1263 GtkTreeModel *store;
1264 GtkTreeSelection *selection;
1268 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1269 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1279 GtkTreePath *tpath = work->data;
1283 gtk_tree_model_get_iter(store, &iter, tpath);
1284 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1293 count = g_list_length(slist);
1294 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1300 GList *vflist_selection_get_list(ViewFile *vf)
1302 GtkTreeModel *store;
1303 GtkTreeSelection *selection;
1308 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1309 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1313 GtkTreePath *tpath = work->data;
1317 gtk_tree_model_get_iter(store, &iter, tpath);
1318 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1320 list = g_list_prepend(list, file_data_ref(fd));
1324 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1327 return g_list_reverse(list);
1330 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1332 GtkTreeModel *store;
1333 GtkTreeSelection *selection;
1338 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1339 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1343 GtkTreePath *tpath = work->data;
1347 gtk_tree_model_get_iter(store, &iter, tpath);
1348 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1350 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1354 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1357 return g_list_reverse(list);
1360 void vflist_select_all(ViewFile *vf)
1362 GtkTreeSelection *selection;
1364 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1365 gtk_tree_selection_select_all(selection);
1367 VFLIST_INFO(vf, select_fd) = NULL;
1370 void vflist_select_none(ViewFile *vf)
1372 GtkTreeSelection *selection;
1374 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1375 gtk_tree_selection_unselect_all(selection);
1378 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1383 tpath = gtk_tree_model_get_path(store, iter);
1384 result = gtk_tree_path_prev(tpath);
1386 gtk_tree_model_get_iter(store, iter, tpath);
1388 gtk_tree_path_free(tpath);
1393 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1395 if (!gtk_tree_model_get_iter_first(store, iter))
1400 GtkTreeIter next = *iter;
1402 if (gtk_tree_model_iter_next(store, &next))
1411 void vflist_select_invert(ViewFile *vf)
1414 GtkTreeSelection *selection;
1415 GtkTreeModel *store;
1418 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1419 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1421 /* Backward iteration prevents scrolling to the end of the list,
1422 * it scrolls to the first selected row instead. */
1423 valid = tree_model_get_iter_last(store, &iter);
1427 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1430 gtk_tree_selection_unselect_iter(selection, &iter);
1432 gtk_tree_selection_select_iter(selection, &iter);
1434 valid = tree_model_iter_prev(store, &iter);
1438 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1442 if (vflist_find_row(vf, fd, &iter) < 0) return;
1444 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1446 if (!vflist_row_is_selected(vf, fd))
1448 GtkTreeSelection *selection;
1449 GtkTreeModel *store;
1452 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1453 gtk_tree_selection_unselect_all(selection);
1454 gtk_tree_selection_select_iter(selection, &iter);
1455 vflist_move_cursor(vf, &iter);
1457 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1458 tpath = gtk_tree_model_get_path(store, &iter);
1459 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1460 gtk_tree_path_free(tpath);
1464 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1468 if (sel_fd->parent) sel_fd = sel_fd->parent;
1474 FileData *fd = work->data;
1478 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1482 vflist_select_by_fd(vf, fd);
1489 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1491 GtkTreeModel *store;
1493 GtkTreeSelection *selection;
1497 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1499 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1500 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1502 valid = gtk_tree_model_get_iter_first(store, &iter);
1506 gboolean mark_val, selected;
1507 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1509 mark_val = file_data_get_mark(fd, n);
1510 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1514 case MTS_MODE_SET: selected = mark_val;
1516 case MTS_MODE_OR: selected = mark_val | selected;
1518 case MTS_MODE_AND: selected = mark_val & selected;
1520 case MTS_MODE_MINUS: selected = !mark_val & selected;
1525 gtk_tree_selection_select_iter(selection, &iter);
1527 gtk_tree_selection_unselect_iter(selection, &iter);
1529 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1533 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1535 GtkTreeModel *store;
1536 GtkTreeSelection *selection;
1541 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1543 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1544 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1548 GtkTreePath *tpath = work->data;
1552 gtk_tree_model_get_iter(store, &iter, tpath);
1553 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1555 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1559 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1561 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1563 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1567 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1569 vf_refresh_idle(vf);
1573 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1575 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1579 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1584 *-----------------------------------------------------------------------------
1586 *-----------------------------------------------------------------------------
1589 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1591 GtkTreeViewColumn *column;
1592 GtkCellRenderer *cell;
1596 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1597 if (!column) return;
1599 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1601 list = gtk_tree_view_column_get_cell_renderers(column);
1606 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1607 gtk_tree_view_column_set_visible(column, thumb);
1609 multiline = (thumb && options->thumbnails.max_height >= 48);
1611 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1612 if (!column) return;
1613 gtk_tree_view_column_set_visible(column, multiline);
1614 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1616 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1617 if (!column) return;
1618 gtk_tree_view_column_set_visible(column, !multiline);
1619 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1621 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1622 if (!column) return;
1623 gtk_tree_view_column_set_visible(column, !multiline);
1625 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1626 if (!column) return;
1627 gtk_tree_view_column_set_visible(column, !multiline);
1629 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1632 static void vflist_populate_view(ViewFile *vf)
1634 GtkTreeStore *store;
1636 GtkTreeRowReference *visible_row = NULL;
1640 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1641 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1643 vflist_thumb_stop(vf);
1647 vflist_store_clear(vf);
1652 if (GTK_WIDGET_REALIZED(vf->listview) &&
1653 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1655 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1656 gtk_tree_path_free(tpath);
1659 vflist_listview_set_columns(vf->listview, thumbs);
1661 selected = vflist_selection_get_list(vf);
1663 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1665 if (selected && vflist_selection_count(vf, NULL) == 0)
1667 /* all selected files disappeared */
1668 vflist_select_closest(vf, selected->data);
1671 filelist_free(selected);
1675 if (gtk_tree_row_reference_valid(visible_row))
1677 tpath = gtk_tree_row_reference_get_path(visible_row);
1678 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1679 gtk_tree_path_free(tpath);
1681 gtk_tree_row_reference_free(visible_row);
1685 vflist_thumb_update(vf);
1688 gint vflist_refresh(ViewFile *vf)
1693 old_list = vf->list;
1696 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1699 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1701 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1702 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1703 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1705 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1706 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1709 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1711 vflist_populate_view(vf);
1713 filelist_free(old_list);
1714 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1721 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1723 #define CELL_HEIGHT_OVERRIDE 512
1725 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1729 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1730 if (spec && G_IS_PARAM_SPEC_INT(spec))
1732 GParamSpecInt *spec_int;
1734 spec_int = G_PARAM_SPEC_INT(spec);
1735 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1739 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1741 static GdkColor color;
1742 static GtkWidget *done = NULL;
1748 style = gtk_widget_get_style(widget);
1749 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1750 shift_color(&color, -1, 0);
1757 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1758 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1760 ViewFile *vf = data;
1763 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1764 g_object_set(G_OBJECT(cell),
1765 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1766 "cell-background-set", set, NULL);
1769 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1771 GtkTreeViewColumn *column;
1772 GtkCellRenderer *renderer;
1774 column = gtk_tree_view_column_new();
1775 gtk_tree_view_column_set_title(column, title);
1776 gtk_tree_view_column_set_min_width(column, 4);
1780 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1781 renderer = gtk_cell_renderer_text_new();
1784 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1786 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1787 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1789 gtk_tree_view_column_set_expand(column, TRUE);
1793 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1794 renderer = gtk_cell_renderer_pixbuf_new();
1795 cell_renderer_height_override(renderer);
1796 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1797 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1800 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1801 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1802 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1804 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1807 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1809 ViewFile *vf = data;
1810 GtkTreeStore *store;
1811 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1817 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1818 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1821 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1823 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1825 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1827 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1828 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1829 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1831 vf_refresh_idle(vf);
1833 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1835 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1836 gtk_tree_path_free(path);
1839 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1841 GtkTreeViewColumn *column;
1842 GtkCellRenderer *renderer;
1843 GtkTreeStore *store;
1846 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1848 renderer = gtk_cell_renderer_toggle_new();
1849 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1851 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1852 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1853 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1855 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1856 gtk_tree_view_column_set_fixed_width(column, 18);
1857 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1860 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1864 *-----------------------------------------------------------------------------
1866 *-----------------------------------------------------------------------------
1869 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1871 if (!dir_fd) return FALSE;
1872 if (vf->dir_fd == dir_fd) return TRUE;
1874 file_data_unref(vf->dir_fd);
1875 vf->dir_fd = file_data_ref(dir_fd);
1877 /* force complete reload */
1878 vflist_store_clear(vf);
1880 filelist_free(vf->list);
1883 return vf_refresh(vf);
1886 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1888 ViewFile *vf = data;
1890 file_data_unregister_notify_func(vf_notify_cb, vf);
1892 vflist_select_idle_cancel(vf);
1893 vf_refresh_idle_cancel(vf);
1894 vflist_thumb_stop(vf);
1896 filelist_free(vf->list);
1899 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1901 GtkTreeStore *store;
1902 GtkTreeSelection *selection;
1904 GType flist_types[FILE_COLUMN_COUNT];
1908 vf->info = g_new0(ViewFileInfoList, 1);
1910 VFLIST_INFO(vf, click_fd) = NULL;
1911 VFLIST_INFO(vf, select_fd) = NULL;
1912 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1914 VFLIST_INFO(vf, select_idle_id) = -1;
1916 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1917 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1918 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1919 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1920 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1921 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1922 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1923 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1924 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1925 flist_types[i] = G_TYPE_BOOLEAN;
1927 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1929 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1930 g_object_unref(store);
1932 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1933 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1934 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1936 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1937 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1941 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1943 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1944 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1948 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1949 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1952 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1953 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1956 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1957 g_assert(column == FILE_VIEW_COLUMN_NAME);
1960 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1961 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1964 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1965 g_assert(column == FILE_VIEW_COLUMN_DATE);
1968 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1972 void vflist_thumb_set(ViewFile *vf, gint enable)
1974 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1976 VFLIST_INFO(vf, thumbs_enabled) = enable;
1977 if (vf->layout) vf_refresh(vf);
1980 void vflist_marks_set(ViewFile *vf, gint enable)
1982 GList *columns, *work;
1984 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1989 GtkTreeViewColumn *column = work->data;
1990 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1993 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1994 gtk_tree_view_column_set_visible(column, enable);
1997 g_list_free(columns);