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;
138 static gint vflist_sidecar_list_count(GList *work)
143 FileData *fd = work->data;
146 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(vf)->click_fd) return;
235 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
237 list = vf_selection_get_list(vf);
241 list = g_list_append(NULL, file_data_ref(VFLIST(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(vf)->click_fd, TRUE);
262 if (VFLIST(vf)->thumbs_enabled &&
263 VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
267 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
268 items = vf_selection_count(vf, NULL);
272 dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
276 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
280 vflist_color_set(vf, VFLIST(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(vf)->click_fd) return NULL;
311 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
313 return vf_selection_get_list(vf);
316 return g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
319 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
323 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
327 list = vf_selection_get_list(vf);
328 view_window_new_from_list(list);
333 view_window_new(VFLIST(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(vf)->click_fd)
351 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
352 if (vflist_find_row(vf, VFLIST(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(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(vf)->click_fd, FALSE);
375 layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
379 vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
383 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
387 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
391 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
394 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
395 VFLIST(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(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(vf)->click_fd, -1);
468 gtk_tree_path_free(tpath);
472 VFLIST(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(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(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(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(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(vf)->select_idle_id = -1;
670 if (VFLIST(vf)->select_fd)
672 vflist_select_image(vf, VFLIST(vf)->select_fd);
673 VFLIST(vf)->select_fd = NULL;
676 VFLIST(vf)->select_idle_id = -1;
680 static void vflist_select_idle_cancel(ViewFile *vf)
682 if (VFLIST(vf)->select_idle_id != -1) g_source_remove(VFLIST(vf)->select_idle_id);
683 VFLIST(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(vf)->select_fd, -1);
699 VFLIST(vf)->select_fd = NULL;
703 VFLIST(vf)->select_idle_id == -1)
705 VFLIST(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(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(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;
1638 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1639 thumbs = VFLIST(vf)->thumbs_enabled;
1641 vflist_thumb_stop(vf);
1645 vflist_store_clear(vf);
1650 vflist_listview_set_columns(vf->listview, thumbs);
1652 selected = vflist_selection_get_list(vf);
1654 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1656 if (selected && vflist_selection_count(vf, NULL) == 0)
1658 /* all selected files disappeared */
1659 vflist_select_closest(vf, selected->data);
1662 filelist_free(selected);
1665 vflist_thumb_update(vf);
1668 gint vflist_refresh(ViewFile *vf)
1673 old_list = vf->list;
1676 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1679 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1681 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1682 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1683 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1685 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1686 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1689 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1691 vflist_populate_view(vf);
1693 filelist_free(old_list);
1694 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1701 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1703 #define CELL_HEIGHT_OVERRIDE 512
1705 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1709 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1710 if (spec && G_IS_PARAM_SPEC_INT(spec))
1712 GParamSpecInt *spec_int;
1714 spec_int = G_PARAM_SPEC_INT(spec);
1715 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1719 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1721 static GdkColor color;
1722 static GtkWidget *done = NULL;
1728 style = gtk_widget_get_style(widget);
1729 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1730 shift_color(&color, -1, 0);
1737 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1738 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1740 ViewFile *vf = data;
1743 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1744 g_object_set(G_OBJECT(cell),
1745 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1746 "cell-background-set", set, NULL);
1749 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1751 GtkTreeViewColumn *column;
1752 GtkCellRenderer *renderer;
1754 column = gtk_tree_view_column_new();
1755 gtk_tree_view_column_set_title(column, title);
1756 gtk_tree_view_column_set_min_width(column, 4);
1760 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1761 renderer = gtk_cell_renderer_text_new();
1764 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1766 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1767 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1769 gtk_tree_view_column_set_expand(column, TRUE);
1773 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1774 renderer = gtk_cell_renderer_pixbuf_new();
1775 cell_renderer_height_override(renderer);
1776 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1777 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1780 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1781 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1782 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1784 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1787 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1789 ViewFile *vf = data;
1790 GtkTreeStore *store;
1791 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1797 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1798 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1801 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1803 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1805 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1807 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1808 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1809 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1811 vf_refresh_idle(vf);
1813 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1815 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1816 gtk_tree_path_free(path);
1819 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1821 GtkTreeViewColumn *column;
1822 GtkCellRenderer *renderer;
1823 GtkTreeStore *store;
1826 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1828 renderer = gtk_cell_renderer_toggle_new();
1829 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1831 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1832 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1833 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1835 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1836 gtk_tree_view_column_set_fixed_width(column, 18);
1837 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1840 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1844 *-----------------------------------------------------------------------------
1846 *-----------------------------------------------------------------------------
1849 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1851 if (!dir_fd) return FALSE;
1852 if (vf->dir_fd == dir_fd) return TRUE;
1854 file_data_unref(vf->dir_fd);
1855 vf->dir_fd = file_data_ref(dir_fd);
1857 /* force complete reload */
1858 vflist_store_clear(vf);
1860 filelist_free(vf->list);
1863 return vf_refresh(vf);
1866 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1868 ViewFile *vf = data;
1870 file_data_unregister_notify_func(vf_notify_cb, vf);
1872 vflist_select_idle_cancel(vf);
1873 vf_refresh_idle_cancel(vf);
1874 vflist_thumb_stop(vf);
1876 filelist_free(vf->list);
1879 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1881 GtkTreeStore *store;
1882 GtkTreeSelection *selection;
1884 GType flist_types[FILE_COLUMN_COUNT];
1888 vf->info = g_new0(ViewFileInfoList, 1);
1890 VFLIST(vf)->click_fd = NULL;
1891 VFLIST(vf)->select_fd = NULL;
1892 VFLIST(vf)->thumbs_enabled = FALSE;
1894 VFLIST(vf)->select_idle_id = -1;
1896 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1897 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1898 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1899 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1900 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1901 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1902 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1903 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1904 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1905 flist_types[i] = G_TYPE_BOOLEAN;
1907 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1909 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1910 g_object_unref(store);
1912 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1913 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1914 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1916 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1917 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1921 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1923 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1924 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1928 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1929 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1932 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1933 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1936 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1937 g_assert(column == FILE_VIEW_COLUMN_NAME);
1940 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1941 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1944 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1945 g_assert(column == FILE_VIEW_COLUMN_DATE);
1948 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1952 void vflist_thumb_set(ViewFile *vf, gint enable)
1954 if (VFLIST(vf)->thumbs_enabled == enable) return;
1956 VFLIST(vf)->thumbs_enabled = enable;
1957 if (vf->layout) vf_refresh(vf);
1960 void vflist_marks_set(ViewFile *vf, gint enable)
1962 GList *columns, *work;
1964 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1969 GtkTreeViewColumn *column = work->data;
1970 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1973 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1974 gtk_tree_view_column_set_visible(column, enable);
1977 g_list_free(columns);