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 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1569 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1573 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1578 *-----------------------------------------------------------------------------
1580 *-----------------------------------------------------------------------------
1583 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1585 GtkTreeViewColumn *column;
1586 GtkCellRenderer *cell;
1590 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1591 if (!column) return;
1593 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1595 list = gtk_tree_view_column_get_cell_renderers(column);
1600 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1601 gtk_tree_view_column_set_visible(column, thumb);
1603 multiline = (thumb && options->thumbnails.max_height >= 48);
1605 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1606 if (!column) return;
1607 gtk_tree_view_column_set_visible(column, multiline);
1608 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1610 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1611 if (!column) return;
1612 gtk_tree_view_column_set_visible(column, !multiline);
1613 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1615 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1616 if (!column) return;
1617 gtk_tree_view_column_set_visible(column, !multiline);
1619 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1620 if (!column) return;
1621 gtk_tree_view_column_set_visible(column, !multiline);
1623 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1626 static void vflist_populate_view(ViewFile *vf)
1628 GtkTreeStore *store;
1630 GtkTreeRowReference *visible_row = NULL;
1634 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1635 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1637 vflist_thumb_stop(vf);
1641 vflist_store_clear(vf);
1646 if (GTK_WIDGET_REALIZED(vf->listview) &&
1647 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1649 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1650 gtk_tree_path_free(tpath);
1653 vflist_listview_set_columns(vf->listview, thumbs);
1655 selected = vflist_selection_get_list(vf);
1657 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1659 if (selected && vflist_selection_count(vf, NULL) == 0)
1661 /* all selected files disappeared */
1662 vflist_select_closest(vf, selected->data);
1665 filelist_free(selected);
1669 if (gtk_tree_row_reference_valid(visible_row))
1671 tpath = gtk_tree_row_reference_get_path(visible_row);
1672 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1673 gtk_tree_path_free(tpath);
1675 gtk_tree_row_reference_free(visible_row);
1679 vflist_thumb_update(vf);
1682 gint vflist_refresh(ViewFile *vf)
1687 old_list = vf->list;
1690 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1693 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1695 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1697 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1699 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1700 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1703 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1705 vflist_populate_view(vf);
1707 filelist_free(old_list);
1708 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1715 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1717 #define CELL_HEIGHT_OVERRIDE 512
1719 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1723 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1724 if (spec && G_IS_PARAM_SPEC_INT(spec))
1726 GParamSpecInt *spec_int;
1728 spec_int = G_PARAM_SPEC_INT(spec);
1729 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1733 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1735 static GdkColor color;
1736 static GtkWidget *done = NULL;
1742 style = gtk_widget_get_style(widget);
1743 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1744 shift_color(&color, -1, 0);
1751 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1752 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1754 ViewFile *vf = data;
1757 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1758 g_object_set(G_OBJECT(cell),
1759 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1760 "cell-background-set", set, NULL);
1763 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1765 GtkTreeViewColumn *column;
1766 GtkCellRenderer *renderer;
1768 column = gtk_tree_view_column_new();
1769 gtk_tree_view_column_set_title(column, title);
1770 gtk_tree_view_column_set_min_width(column, 4);
1774 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1775 renderer = gtk_cell_renderer_text_new();
1778 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1780 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1781 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1783 gtk_tree_view_column_set_expand(column, TRUE);
1787 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1788 renderer = gtk_cell_renderer_pixbuf_new();
1789 cell_renderer_height_override(renderer);
1790 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1791 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1794 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1795 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1796 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1798 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1801 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1803 ViewFile *vf = data;
1804 GtkTreeStore *store;
1805 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1811 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1812 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1815 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1817 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1819 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1821 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1822 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1823 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1825 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1826 gtk_tree_path_free(path);
1829 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1831 GtkTreeViewColumn *column;
1832 GtkCellRenderer *renderer;
1833 GtkTreeStore *store;
1836 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1838 renderer = gtk_cell_renderer_toggle_new();
1839 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1841 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1842 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1843 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1845 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1846 gtk_tree_view_column_set_fixed_width(column, 18);
1847 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1850 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1854 *-----------------------------------------------------------------------------
1856 *-----------------------------------------------------------------------------
1859 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1861 if (!dir_fd) return FALSE;
1862 if (vf->dir_fd == dir_fd) return TRUE;
1864 file_data_unref(vf->dir_fd);
1865 vf->dir_fd = file_data_ref(dir_fd);
1867 /* force complete reload */
1868 vflist_store_clear(vf);
1870 filelist_free(vf->list);
1873 return vf_refresh(vf);
1876 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1878 ViewFile *vf = data;
1880 file_data_unregister_notify_func(vf_notify_cb, vf);
1882 vflist_select_idle_cancel(vf);
1883 vf_refresh_idle_cancel(vf);
1884 vflist_thumb_stop(vf);
1886 filelist_free(vf->list);
1889 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1891 GtkTreeStore *store;
1892 GtkTreeSelection *selection;
1894 GType flist_types[FILE_COLUMN_COUNT];
1898 vf->info = g_new0(ViewFileInfoList, 1);
1900 VFLIST_INFO(vf, click_fd) = NULL;
1901 VFLIST_INFO(vf, select_fd) = NULL;
1902 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1904 VFLIST_INFO(vf, select_idle_id) = -1;
1906 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1907 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1908 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1909 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1910 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1911 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1912 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1913 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1914 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1915 flist_types[i] = G_TYPE_BOOLEAN;
1917 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1919 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1920 g_object_unref(store);
1922 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1923 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1924 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1926 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1927 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1931 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1933 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1934 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1938 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1939 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1942 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1943 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1946 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1947 g_assert(column == FILE_VIEW_COLUMN_NAME);
1950 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1951 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1954 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1955 g_assert(column == FILE_VIEW_COLUMN_DATE);
1958 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1962 void vflist_thumb_set(ViewFile *vf, gint enable)
1964 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1966 VFLIST_INFO(vf, thumbs_enabled) = enable;
1967 if (vf->layout) vf_refresh(vf);
1970 void vflist_marks_set(ViewFile *vf, gint enable)
1972 GList *columns, *work;
1974 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1979 GtkTreeViewColumn *column = work->data;
1980 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1983 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1984 gtk_tree_view_column_set_visible(column, enable);
1987 g_list_free(columns);