4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
14 #include "view_file_list.h"
16 #include "cache_maint.h"
22 #include "layout_image.h"
26 #include "ui_bookmark.h"
27 #include "ui_fileops.h"
29 #include "ui_tree_edit.h"
30 #include "view_file.h"
32 #include <gdk/gdkkeysyms.h> /* for keyboard values */
36 FILE_COLUMN_POINTER = 0,
45 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
50 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
51 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
52 static void vflist_populate_view(ViewFile *vf);
53 static void vflist_notify_cb(FileData *fd, NotifyType type, gpointer data);
57 *-----------------------------------------------------------------------------
59 *-----------------------------------------------------------------------------
66 } ViewFileFindRowData;
68 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
70 ViewFileFindRowData *find = data;
72 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
83 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
86 ViewFileFindRowData data = {fd, iter, 0, 0};
88 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
89 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
101 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
106 FileData *fd_p = work->data;
107 if (fd == fd_p) return i;
111 GList *work2 = fd_p->sidecar_files;
115 if (fd == fd_p) return i;
126 static gint vflist_sidecar_list_count(GList *work)
131 FileData *fd = work->data;
134 GList *work2 = fd->sidecar_files;
145 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
148 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
153 static void vflist_store_clear(ViewFile *vf)
156 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
157 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
158 gtk_tree_store_clear(GTK_TREE_STORE(store));
161 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
166 if (vflist_find_row(vf, fd, &iter) < 0) return;
167 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
168 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
171 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
176 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
178 tpath = gtk_tree_model_get_path(store, iter);
179 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
180 gtk_tree_path_free(tpath);
184 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
186 GList *columns, *work;
189 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
193 GtkTreeViewColumn *column = work->data;
194 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
200 g_list_free(columns);
206 *-----------------------------------------------------------------------------
208 *-----------------------------------------------------------------------------
211 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
212 GtkSelectionData *selection_data, guint info,
213 guint time, gpointer data)
217 gchar *uri_text = NULL;
220 if (!VFLIST_INFO(vf, click_fd)) return;
222 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
224 list = vf_selection_get_list(vf);
228 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
233 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
238 gtk_selection_data_set(selection_data, selection_data->target,
239 8, (guchar *)uri_text, total);
243 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
247 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
249 if (VFLIST_INFO(vf, thumbs_enabled) &&
250 VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->pixbuf)
254 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
255 items = vf_selection_count(vf, NULL);
259 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->pixbuf, items);
263 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
267 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
269 if (context->action == GDK_ACTION_MOVE)
275 void vflist_dnd_init(ViewFile *vf)
277 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
278 dnd_file_drag_types, dnd_file_drag_types_count,
279 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
280 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
281 G_CALLBACK(vflist_dnd_get), vf);
282 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
283 G_CALLBACK(vflist_dnd_begin), vf);
284 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
285 G_CALLBACK(vflist_dnd_end), vf);
289 *-----------------------------------------------------------------------------
291 *-----------------------------------------------------------------------------
294 GList *vflist_pop_menu_file_list(ViewFile *vf)
296 if (!VFLIST_INFO(vf, click_fd)) return NULL;
298 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
300 return vf_selection_get_list(vf);
303 return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
306 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
310 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
314 list = vf_selection_get_list(vf);
315 view_window_new_from_list(list);
320 view_window_new(VFLIST_INFO(vf, click_fd));
324 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
329 list = vf_pop_menu_file_list(vf);
330 if (options->file_ops.enable_in_place_rename &&
331 list && !list->next && VFLIST_INFO(vf, click_fd))
338 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
339 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
343 tpath = gtk_tree_model_get_path(store, &iter);
344 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
345 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
346 vflist_row_rename_cb, vf);
347 gtk_tree_path_free(tpath);
352 file_util_rename(NULL, list, vf->listview);
355 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
359 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
362 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
366 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
370 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
374 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
378 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
381 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
382 VFLIST_INFO(vf, click_fd) = NULL;
388 *-----------------------------------------------------------------------------
390 *-----------------------------------------------------------------------------
393 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
399 if (strlen(new) == 0) return FALSE;
401 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
402 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
404 if (strchr(new, G_DIR_SEPARATOR) != NULL)
406 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
407 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
410 else if (isfile(new_path))
412 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
413 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
418 gint row = vf_index_by_path(vf, old_path);
421 GList *work = g_list_nth(vf->list, row);
422 FileData *fd = work->data;
424 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)
729 gchar *sidecars = NULL;
731 if (fd->sidecar_files)
732 sidecars = file_data_sc_list_to_string(fd);
733 size = text_from_size(fd->size);
735 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
736 FILE_COLUMN_VERSION, fd->version,
737 FILE_COLUMN_THUMB, (VFLIST_INFO(vf, thumbs_enabled)) ? fd->pixbuf : NULL,
738 FILE_COLUMN_NAME, fd->name,
739 FILE_COLUMN_SIDECARS, sidecars,
740 FILE_COLUMN_SIZE, size,
741 FILE_COLUMN_DATE, text_from_time(fd->date),
742 FILE_COLUMN_COLOR, FALSE, -1);
743 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
744 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
751 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
757 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
763 FileData *fd = work->data;
768 FileData *old_fd = NULL;
769 gint old_version = 0;
773 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
774 FILE_COLUMN_POINTER, &old_fd,
775 FILE_COLUMN_VERSION, &old_version,
785 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
787 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
789 if (match == 0) g_warning("multiple fd for the same path");
804 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
808 gtk_tree_store_append(store, &new, parent_iter);
811 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
812 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
814 if (g_list_find(selected, fd))
816 /* renamed files - the same fd appears at different position - select it again*/
817 GtkTreeSelection *selection;
818 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
819 gtk_tree_selection_select_iter(selection, &new);
826 file_data_unref(old_fd);
827 valid = gtk_tree_store_remove(store, &iter);
831 if (fd->version != old_version)
833 vflist_setup_iter(vf, store, &iter, fd);
834 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
837 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
848 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
849 file_data_unref(old_fd);
851 valid = gtk_tree_store_remove(store, &iter);
855 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
858 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
863 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
864 if (!vf->list) return;
870 FileData *fd = work->data;
871 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
876 vf->sort_method = type;
877 vf->sort_ascend = ascend;
879 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
881 new_order = g_malloc(i * sizeof(gint));
887 FileData *fd = work->data;
888 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
893 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
894 gtk_tree_store_reorder(store, NULL, new_order);
897 g_hash_table_destroy(fd_idx_hash);
901 *-----------------------------------------------------------------------------
903 *-----------------------------------------------------------------------------
906 static gint vflist_thumb_next(ViewFile *vf);
908 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
910 if (vf->func_thumb_status)
912 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
916 static void vflist_thumb_cleanup(ViewFile *vf)
918 vflist_thumb_status(vf, 0.0, NULL);
920 vf->thumbs_count = 0;
921 vf->thumbs_running = FALSE;
923 thumb_loader_free(vf->thumbs_loader);
924 vf->thumbs_loader = NULL;
926 vf->thumbs_filedata = NULL;
929 static void vflist_thumb_stop(ViewFile *vf)
931 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
934 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
939 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
941 if (fd->pixbuf) g_object_unref(fd->pixbuf);
942 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
944 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
945 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
947 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
950 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
954 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
956 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
959 while (vflist_thumb_next(vf));
962 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
966 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
968 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
971 while (vflist_thumb_next(vf));
974 static gint vflist_thumb_next(ViewFile *vf)
979 /* first check the visible files */
981 if (GTK_WIDGET_REALIZED(vf->listview) &&
982 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
988 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
989 gtk_tree_model_get_iter(store, &iter, tpath);
990 gtk_tree_path_free(tpath);
992 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
994 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
995 if (fd->pixbuf) fd = NULL;
997 valid = gtk_tree_model_iter_next(store, &iter);
1001 /* then find first undone */
1005 GList *work = vf->list;
1008 FileData *fd_p = work->data;
1013 GList *work2 = fd_p->sidecar_files;
1015 while (work2 && !fd)
1018 if (!fd_p->pixbuf) fd = fd_p;
1019 work2 = work2->next;
1029 vflist_thumb_cleanup(vf);
1035 vf->thumbs_filedata = fd;
1037 thumb_loader_free(vf->thumbs_loader);
1039 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1040 thumb_loader_set_callbacks(vf->thumbs_loader,
1041 vflist_thumb_done_cb,
1042 vflist_thumb_error_cb,
1046 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1048 /* set icon to unknown, continue */
1049 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1050 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1058 static void vflist_thumb_update(ViewFile *vf)
1060 vflist_thumb_stop(vf);
1061 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1063 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1064 vf->thumbs_running = TRUE;
1066 while (vflist_thumb_next(vf));
1070 *-----------------------------------------------------------------------------
1072 *-----------------------------------------------------------------------------
1075 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1077 return g_list_nth_data(vf->list, row);
1080 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1085 if (!path) return -1;
1090 FileData *fd = work->data;
1091 if (strcmp(path, fd->path) == 0) return p;
1100 guint vflist_count(ViewFile *vf, gint64 *bytes)
1110 FileData *fd = work->data;
1118 return g_list_length(vf->list);
1121 GList *vflist_get_list(ViewFile *vf)
1129 FileData *fd = work->data;
1132 list = g_list_prepend(list, file_data_ref(fd));
1135 return g_list_reverse(list);
1139 *-----------------------------------------------------------------------------
1141 *-----------------------------------------------------------------------------
1144 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1146 GtkTreeModel *store;
1147 GtkTreeSelection *selection;
1152 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1153 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1155 while (!found && work)
1157 GtkTreePath *tpath = work->data;
1161 gtk_tree_model_get_iter(store, &iter, tpath);
1162 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1163 if (fd_n == fd) found = TRUE;
1166 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1172 gint vflist_index_is_selected(ViewFile *vf, gint row)
1176 fd = vf_index_get_data(vf, row);
1177 return vflist_row_is_selected(vf, fd);
1180 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1182 GtkTreeModel *store;
1183 GtkTreeSelection *selection;
1187 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1188 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1198 GtkTreePath *tpath = work->data;
1202 gtk_tree_model_get_iter(store, &iter, tpath);
1203 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1212 count = g_list_length(slist);
1213 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1219 GList *vflist_selection_get_list(ViewFile *vf)
1221 GtkTreeModel *store;
1222 GtkTreeSelection *selection;
1227 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1228 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1232 GtkTreePath *tpath = work->data;
1236 gtk_tree_model_get_iter(store, &iter, tpath);
1237 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1239 list = g_list_prepend(list, file_data_ref(fd));
1243 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1246 return g_list_reverse(list);
1249 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1251 GtkTreeModel *store;
1252 GtkTreeSelection *selection;
1257 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1258 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1262 GtkTreePath *tpath = work->data;
1266 gtk_tree_model_get_iter(store, &iter, tpath);
1267 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1269 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1273 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1276 return g_list_reverse(list);
1279 void vflist_select_all(ViewFile *vf)
1281 GtkTreeSelection *selection;
1283 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1284 gtk_tree_selection_select_all(selection);
1286 VFLIST_INFO(vf, select_fd) = NULL;
1289 void vflist_select_none(ViewFile *vf)
1291 GtkTreeSelection *selection;
1293 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1294 gtk_tree_selection_unselect_all(selection);
1297 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1302 tpath = gtk_tree_model_get_path(store, iter);
1303 result = gtk_tree_path_prev(tpath);
1305 gtk_tree_model_get_iter(store, iter, tpath);
1307 gtk_tree_path_free(tpath);
1312 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1314 if (!gtk_tree_model_get_iter_first(store, iter))
1319 GtkTreeIter next = *iter;
1321 if (gtk_tree_model_iter_next(store, &next))
1330 void vflist_select_invert(ViewFile *vf)
1333 GtkTreeSelection *selection;
1334 GtkTreeModel *store;
1337 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1338 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1340 /* Backward iteration prevents scrolling to the end of the list,
1341 * it scrolls to the first selected row instead. */
1342 valid = tree_model_get_iter_last(store, &iter);
1346 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1349 gtk_tree_selection_unselect_iter(selection, &iter);
1351 gtk_tree_selection_select_iter(selection, &iter);
1353 valid = tree_model_iter_prev(store, &iter);
1357 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1361 if (vflist_find_row(vf, fd, &iter) < 0) return;
1363 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1365 if (!vflist_row_is_selected(vf, fd))
1367 GtkTreeSelection *selection;
1368 GtkTreeModel *store;
1371 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1372 gtk_tree_selection_unselect_all(selection);
1373 gtk_tree_selection_select_iter(selection, &iter);
1374 vflist_move_cursor(vf, &iter);
1376 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1377 tpath = gtk_tree_model_get_path(store, &iter);
1378 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1379 gtk_tree_path_free(tpath);
1383 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1387 if (sel_fd->parent) sel_fd = sel_fd->parent;
1393 FileData *fd = work->data;
1397 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1401 vflist_select_by_fd(vf, fd);
1408 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1410 GtkTreeModel *store;
1412 GtkTreeSelection *selection;
1416 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
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 valid = gtk_tree_model_get_iter_first(store, &iter);
1425 gboolean mark_val, selected;
1426 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1428 mark_val = file_data_get_mark(fd, n);
1429 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1433 case MTS_MODE_SET: selected = mark_val;
1435 case MTS_MODE_OR: selected = mark_val | selected;
1437 case MTS_MODE_AND: selected = mark_val & selected;
1439 case MTS_MODE_MINUS: selected = !mark_val & selected;
1444 gtk_tree_selection_select_iter(selection, &iter);
1446 gtk_tree_selection_unselect_iter(selection, &iter);
1448 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1452 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1454 GtkTreeModel *store;
1455 GtkTreeSelection *selection;
1460 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1462 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1463 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1467 GtkTreePath *tpath = work->data;
1471 gtk_tree_model_get_iter(store, &iter, tpath);
1472 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1474 file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification */
1478 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1480 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1482 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1486 file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1488 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1492 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1497 *-----------------------------------------------------------------------------
1499 *-----------------------------------------------------------------------------
1502 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1504 GtkTreeViewColumn *column;
1505 GtkCellRenderer *cell;
1508 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
1509 if (!column) return;
1511 gtk_tree_view_column_set_fixed_width(column, ((thumb) ? options->thumbnails.max_width : 4) + 10);
1513 list = gtk_tree_view_column_get_cell_renderers(column);
1518 g_object_set(G_OBJECT(cell), "height", (thumb) ? options->thumbnails.max_height : -1, NULL);
1519 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1522 static void vflist_populate_view(ViewFile *vf)
1524 GtkTreeStore *store;
1526 GtkTreeRowReference *visible_row = NULL;
1530 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1531 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1533 vflist_thumb_stop(vf);
1537 vflist_store_clear(vf);
1542 if (GTK_WIDGET_REALIZED(vf->listview) &&
1543 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1545 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1546 gtk_tree_path_free(tpath);
1549 vflist_listview_set_height(vf->listview, thumbs);
1551 selected = vflist_selection_get_list(vf);
1553 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1555 if (selected && vflist_selection_count(vf, NULL) == 0)
1557 /* all selected files disappeared */
1558 vflist_select_closest(vf, selected->data);
1561 filelist_free(selected);
1565 if (gtk_tree_row_reference_valid(visible_row))
1567 tpath = gtk_tree_row_reference_get_path(visible_row);
1568 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1569 gtk_tree_path_free(tpath);
1571 gtk_tree_row_reference_free(visible_row);
1575 vflist_thumb_update(vf);
1578 gint vflist_refresh(ViewFile *vf)
1583 old_list = vf->list;
1586 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1589 file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1591 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1593 file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1595 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1596 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1599 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1601 vflist_populate_view(vf);
1603 filelist_free(old_list);
1604 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1609 static gint vflist_refresh_idle_cb(gpointer data)
1611 ViewFile *vf = data;
1614 vf->refresh_idle_id = -1;
1618 static void vflist_refresh_idle_cancel(ViewFile *vf)
1620 if (vf->refresh_idle_id != -1) g_source_remove(vf->refresh_idle_id);
1621 vf->refresh_idle_id = -1;
1625 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1627 #define CELL_HEIGHT_OVERRIDE 512
1629 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1633 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1634 if (spec && G_IS_PARAM_SPEC_INT(spec))
1636 GParamSpecInt *spec_int;
1638 spec_int = G_PARAM_SPEC_INT(spec);
1639 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1643 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1645 static GdkColor color;
1646 static GtkWidget *done = NULL;
1652 style = gtk_widget_get_style(widget);
1653 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1654 shift_color(&color, -1, 0);
1661 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1662 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1664 ViewFile *vf = data;
1667 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1668 g_object_set(G_OBJECT(cell),
1669 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1670 "cell-background-set", set, NULL);
1673 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1675 GtkTreeViewColumn *column;
1676 GtkCellRenderer *renderer;
1678 column = gtk_tree_view_column_new();
1679 gtk_tree_view_column_set_title(column, title);
1680 gtk_tree_view_column_set_min_width(column, 4);
1684 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1685 renderer = gtk_cell_renderer_text_new();
1688 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1690 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1691 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1693 gtk_tree_view_column_set_expand(column, TRUE);
1697 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1698 renderer = gtk_cell_renderer_pixbuf_new();
1699 cell_renderer_height_override(renderer);
1700 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1701 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1704 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1705 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1706 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1708 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1711 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1713 ViewFile *vf = data;
1714 GtkTreeStore *store;
1715 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1721 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1722 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1725 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1727 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1729 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1731 file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification */
1732 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1733 file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1735 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1736 gtk_tree_path_free(path);
1739 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1741 GtkTreeViewColumn *column;
1742 GtkCellRenderer *renderer;
1743 GtkTreeStore *store;
1746 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1748 renderer = gtk_cell_renderer_toggle_new();
1749 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1751 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1752 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1753 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1755 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1756 gtk_tree_view_column_set_fixed_width(column, 16);
1757 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1760 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1764 *-----------------------------------------------------------------------------
1766 *-----------------------------------------------------------------------------
1769 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1771 if (!dir_fd) return FALSE;
1772 if (vf->dir_fd == dir_fd) return TRUE;
1774 file_data_unref(vf->dir_fd);
1775 vf->dir_fd = file_data_ref(dir_fd);
1777 /* force complete reload */
1778 vflist_store_clear(vf);
1780 filelist_free(vf->list);
1783 return vf_refresh(vf);
1786 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1788 ViewFile *vf = data;
1790 file_data_unregister_notify_func(vflist_notify_cb, vf);
1792 vflist_select_idle_cancel(vf);
1793 vflist_refresh_idle_cancel(vf);
1794 vflist_thumb_stop(vf);
1796 filelist_free(vf->list);
1799 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1801 GtkTreeStore *store;
1802 GtkTreeSelection *selection;
1804 GType flist_types[FILE_COLUMN_COUNT];
1807 vf->info = g_new0(ViewFileInfoList, 1);
1809 VFLIST_INFO(vf, click_fd) = NULL;
1810 VFLIST_INFO(vf, select_fd) = NULL;
1811 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1813 VFLIST_INFO(vf, select_idle_id) = -1;
1814 vf->refresh_idle_id = -1;
1817 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1818 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1819 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1820 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1821 flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1822 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1823 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1824 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1825 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1826 flist_types[i] = G_TYPE_BOOLEAN;
1828 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1830 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1831 g_object_unref(store);
1833 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1834 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1835 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1837 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1838 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1840 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1842 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1843 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1845 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
1846 vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1848 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1849 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1851 file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1855 void vflist_thumb_set(ViewFile *vf, gint enable)
1857 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1859 VFLIST_INFO(vf, thumbs_enabled) = enable;
1860 if (vf->layout) vf_refresh(vf);
1863 void vflist_marks_set(ViewFile *vf, gint enable)
1865 GList *columns, *work;
1867 if (vf->marks_enabled == enable) return;
1869 vf->marks_enabled = enable;
1871 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1876 GtkTreeViewColumn *column = work->data;
1877 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1880 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1881 gtk_tree_view_column_set_visible(column, enable);
1884 g_list_free(columns);
1889 *-----------------------------------------------------------------------------
1890 * maintenance (for rename, move, remove)
1891 *-----------------------------------------------------------------------------
1894 static void vflist_notify_cb(FileData *fd, NotifyType type, gpointer data)
1896 ViewFile *vf = data;
1899 if (vf->refresh_idle_id != -1) return;
1901 refresh = (fd == vf->dir_fd);
1905 gchar *base = remove_level_from_path(fd->path);
1906 refresh = (strcmp(base, vf->dir_fd->path) == 0);
1910 if (!refresh && fd->change && fd->change->dest)
1912 gchar *dest_base = remove_level_from_path(fd->change->dest);
1913 refresh = (strcmp(dest_base, vf->dir_fd->path) == 0);
1917 if (!refresh && fd->change && fd->change->source)
1919 gchar *source_base = remove_level_from_path(fd->change->source);
1920 refresh = (strcmp(source_base, vf->dir_fd->path) == 0);
1921 g_free(source_base);
1926 vf->refresh_idle_id = g_idle_add(vflist_refresh_idle_cb, vf);
1932 gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
1934 vflist_maint(vf, fd);
1937 gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
1939 vflist_maint(vf, fd);
1942 gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
1944 vflist_maint(vf, fd);
1949 static gint vflist_maint_find_closest(ViewFile *vf, gint row, gint count, GList *ignore_list)
1959 gint f = vf_index_by_path(vf, work->data);
1960 if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f));
1970 gpointer p = work->data;
1972 if (row == GPOINTER_TO_INT(p))
1977 if (rev == GPOINTER_TO_INT(p))
1982 if (!c) list = g_list_remove(list, p);
1990 if (row > count - 1)
2003 gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
2009 DEBUG_1("%s vflist_maint_renamed: start", get_exec_time());
2011 if (g_list_index(vf->list, fd) < 0) return FALSE;
2013 source_base = remove_level_from_path(fd->change->source);
2014 dest_base = remove_level_from_path(fd->change->dest);
2017 if (strcmp(source_base, dest_base) == 0)
2019 GtkTreeStore *store;
2021 GtkTreeIter position;
2025 old_row = g_list_index(vf->list, fd);
2027 vf->list = g_list_remove(vf->list, fd);
2029 vf->list = filelist_insert_sort(vf->list, fd, vf->sort_method, vf->sort_ascend);
2030 n = g_list_index(vf->list, fd);
2032 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
2033 if (vflist_find_row(vf, fd, &iter) >= 0 &&
2034 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &position, NULL, n))
2038 gtk_tree_store_move_before(store, &iter, &position);
2042 gtk_tree_store_move_after(store, &iter, &position);
2045 gtk_tree_store_set(store, &iter, FILE_COLUMN_NAME, fd->name, -1);
2051 ret = vflist_maint_removed(vf, fd, NULL);
2054 g_free(source_base);
2057 DEBUG_1("%s vflist_maint_renamed: done", get_exec_time());
2062 gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
2069 DEBUG_1("%s vflist_maint_removed: start", get_exec_time());
2071 row = g_list_index(vf->list, fd);
2072 if (row < 0) return FALSE;
2074 if (vflist_index_is_selected(vf, row) &&
2075 layout_image_get_collection(vf->layout, NULL) == NULL)
2079 n = vf_count(vf, NULL);
2082 new_row = vflist_maint_find_closest(vf, row, n, ignore_list);
2083 DEBUG_1("row = %d, closest is %d", row, new_row);
2099 fd = vf_index_get_data(vf, new_row);
2100 if (vflist_find_row(vf, fd, &iter) >= 0)
2102 GtkTreeSelection *selection;
2104 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
2105 gtk_tree_selection_select_iter(selection, &iter);
2106 vflist_move_cursor(vf, &iter);
2111 fd = vf_index_get_data(vf, row);
2112 if (vflist_find_row(vf, fd, &iter) >= 0)
2114 GtkTreeStore *store;
2115 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
2116 gtk_tree_store_remove(store, &iter);
2118 list = g_list_nth(vf->list, row);
2121 /* thumbnail loader check */
2122 if (fd == vf->thumbs_filedata) vf->thumbs_filedata = NULL;
2123 if (vf->thumbs_count > 0) vf->thumbs_count--;
2125 vf->list = g_list_remove(vf->list, fd);
2126 file_data_unref(fd);
2130 DEBUG_1("%s vflist_maint_removed: done", get_exec_time());
2135 gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
2140 if (!fd->change->source || !vf->path) return FALSE;
2142 buf = remove_level_from_path(fd->change->source);
2144 if (strcmp(buf, vf->path) == 0)
2146 ret = vflist_maint_removed(vf, fd, ignore_list);