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"
23 #include "layout_image.h"
27 #include "ui_bookmark.h"
28 #include "ui_fileops.h"
30 #include "ui_tree_edit.h"
31 #include "view_file.h"
33 #include <gdk/gdkkeysyms.h> /* for keyboard values */
37 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);
56 *-----------------------------------------------------------------------------
58 *-----------------------------------------------------------------------------
65 } ViewFileFindRowData;
67 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
69 ViewFileFindRowData *find = data;
71 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
82 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
85 ViewFileFindRowData data = {fd, iter, 0, 0};
87 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
88 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
100 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
105 FileData *fd_p = work->data;
106 if (fd == fd_p) return i;
110 GList *work2 = fd_p->sidecar_files;
114 if (fd == fd_p) return i;
125 static gint vflist_sidecar_list_count(GList *work)
130 FileData *fd = work->data;
133 GList *work2 = fd->sidecar_files;
145 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
150 if (vflist_find_row(vf, fd, &iter) < 0) return;
151 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
152 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
155 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
160 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
162 tpath = gtk_tree_model_get_path(store, iter);
163 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
164 gtk_tree_path_free(tpath);
168 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
170 GList *columns, *work;
173 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
177 GtkTreeViewColumn *column = work->data;
178 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
184 g_list_free(columns);
190 *-----------------------------------------------------------------------------
192 *-----------------------------------------------------------------------------
195 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
196 GtkSelectionData *selection_data, guint info,
197 guint time, gpointer data)
201 gchar *uri_text = NULL;
204 if (!VFLIST_INFO(vf, click_fd)) return;
206 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
208 list = vf_selection_get_list(vf);
212 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
217 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
222 gtk_selection_data_set(selection_data, selection_data->target,
223 8, (guchar *)uri_text, total);
227 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
231 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
233 if (VFLIST_INFO(vf, thumbs_enabled) &&
234 VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->pixbuf)
238 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
239 items = vf_selection_count(vf, NULL);
243 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->pixbuf, items);
247 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
251 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
253 if (context->action == GDK_ACTION_MOVE)
259 void vflist_dnd_init(ViewFile *vf)
261 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
262 dnd_file_drag_types, dnd_file_drag_types_count,
263 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
264 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
265 G_CALLBACK(vflist_dnd_get), vf);
266 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
267 G_CALLBACK(vflist_dnd_begin), vf);
268 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
269 G_CALLBACK(vflist_dnd_end), vf);
273 *-----------------------------------------------------------------------------
275 *-----------------------------------------------------------------------------
278 GList *vflist_pop_menu_file_list(ViewFile *vf)
280 if (!VFLIST_INFO(vf, click_fd)) return NULL;
282 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
284 return vf_selection_get_list(vf);
287 return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
290 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
294 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
298 list = vf_selection_get_list(vf);
299 view_window_new_from_list(list);
304 view_window_new(VFLIST_INFO(vf, click_fd));
308 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
313 list = vf_pop_menu_file_list(vf);
314 if (options->file_ops.enable_in_place_rename &&
315 list && !list->next && VFLIST_INFO(vf, click_fd))
322 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
323 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
327 tpath = gtk_tree_model_get_path(store, &iter);
328 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
329 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
330 vflist_row_rename_cb, vf);
331 gtk_tree_path_free(tpath);
336 file_util_rename(NULL, list, vf->listview);
339 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
343 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
346 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
350 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
354 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
358 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
362 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
365 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
366 VFLIST_INFO(vf, click_fd) = NULL;
372 *-----------------------------------------------------------------------------
374 *-----------------------------------------------------------------------------
377 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
383 if (strlen(new) == 0) return FALSE;
385 old_path = concat_dir_and_file(vf->path, old);
386 new_path = concat_dir_and_file(vf->path, new);
388 if (strchr(new, '/') != NULL)
390 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
391 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
394 else if (isfile(new_path))
396 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
397 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
402 gint row = vf_index_by_path(vf, old_path);
405 GList *work = g_list_nth(vf->list, row);
406 FileData *fd = work->data;
408 if (!file_data_add_change_info(fd, FILEDATA_CHANGE_RENAME, old_path, new_path) || !rename_file_ext(fd))
410 gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\nto:\n%s"), old, new);
411 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
423 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
431 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
432 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
433 tpath = gtk_tree_model_get_path(store, &iter);
434 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
435 gtk_tree_path_free(tpath);
437 popup_menu_position_clamp(menu, x, y, 0);
440 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
445 if (event->keyval != GDK_Menu) return FALSE;
447 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
453 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
454 gtk_tree_model_get_iter(store, &iter, tpath);
455 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
456 gtk_tree_path_free(tpath);
460 VFLIST_INFO(vf, click_fd) = NULL;
463 vf->popup = vf_pop_menu(vf);
464 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
469 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
475 GtkTreeViewColumn *column;
477 vf->clicked_mark = 0;
479 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
480 &tpath, &column, NULL, NULL))
483 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
485 if (bevent->button == MOUSE_BUTTON_LEFT &&
486 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
489 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
490 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
492 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
494 gtk_tree_model_get_iter(store, &iter, tpath);
495 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
497 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
499 gtk_tree_path_free(tpath);
502 VFLIST_INFO(vf, click_fd) = fd;
504 if (bevent->button == MOUSE_BUTTON_RIGHT)
506 vf->popup = vf_pop_menu(vf);
507 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
508 bevent->button, bevent->time);
512 if (!fd) return FALSE;
514 if (bevent->button == MOUSE_BUTTON_MIDDLE)
516 if (!vflist_row_is_selected(vf, fd))
518 vflist_color_set(vf, fd, TRUE);
524 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
525 !(bevent->state & GDK_SHIFT_MASK ) &&
526 !(bevent->state & GDK_CONTROL_MASK ) &&
527 vflist_row_is_selected(vf, fd))
529 GtkTreeSelection *selection;
531 gtk_widget_grab_focus(widget);
534 /* returning FALSE and further processing of the event is needed for
535 correct operation of the expander, to show the sidecar files.
536 It however resets the selection of multiple files. With this condition
537 it should work for both cases */
538 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
539 return (gtk_tree_selection_count_selected_rows(selection) > 1);
543 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
545 if (vf->layout) layout_image_full_screen_start(vf->layout);
552 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
559 if (bevent->button == MOUSE_BUTTON_MIDDLE)
561 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
564 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
569 if ((bevent->x != 0 || bevent->y != 0) &&
570 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
571 &tpath, NULL, NULL, NULL))
575 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
576 gtk_tree_model_get_iter(store, &iter, tpath);
577 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
578 gtk_tree_path_free(tpath);
581 if (bevent->button == MOUSE_BUTTON_MIDDLE)
583 if (fd && VFLIST_INFO(vf, click_fd) == fd)
585 GtkTreeSelection *selection;
587 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
588 if (vflist_row_is_selected(vf, fd))
590 gtk_tree_selection_unselect_iter(selection, &iter);
594 gtk_tree_selection_select_iter(selection, &iter);
600 if (fd && VFLIST_INFO(vf, click_fd) == fd &&
601 !(bevent->state & GDK_SHIFT_MASK ) &&
602 !(bevent->state & GDK_CONTROL_MASK ) &&
603 vflist_row_is_selected(vf, fd))
605 GtkTreeSelection *selection;
607 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
608 gtk_tree_selection_unselect_all(selection);
609 gtk_tree_selection_select_iter(selection, &iter);
610 vflist_move_cursor(vf, &iter);
611 // return TRUE;// FIXME - expand
617 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
619 FileData *read_ahead_fd = NULL;
624 cur_fd = layout_image_get_fd(vf->layout);
625 if (sel_fd == cur_fd) return; /* no change */
627 row = g_list_index(vf->list, sel_fd);
628 // FIXME sidecar data
630 if (sel_fd && options->image.enable_read_ahead && row >= 0)
632 if (row > g_list_index(vf->list, cur_fd) &&
633 row + 1 < vf_count(vf, NULL))
635 read_ahead_fd = vf_index_get_data(vf, row + 1);
639 read_ahead_fd = vf_index_get_data(vf, row - 1);
643 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
646 static gint vflist_select_idle_cb(gpointer data)
652 VFLIST_INFO(vf, select_idle_id) = -1;
658 if (VFLIST_INFO(vf, select_fd))
660 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
661 VFLIST_INFO(vf, select_fd) = NULL;
664 VFLIST_INFO(vf, select_idle_id) = -1;
668 static void vflist_select_idle_cancel(ViewFile *vf)
670 if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
671 VFLIST_INFO(vf, select_idle_id) = -1;
674 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
675 gboolean path_currently_selected, gpointer data)
680 if (!path_currently_selected &&
681 gtk_tree_model_get_iter(store, &iter, tpath))
683 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
687 VFLIST_INFO(vf, select_fd) = NULL;
691 VFLIST_INFO(vf, select_idle_id) == -1)
693 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
700 *-----------------------------------------------------------------------------
702 *-----------------------------------------------------------------------------
706 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
707 gboolean path_currently_selected, gpointer data)
714 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
718 gchar *sidecars = NULL;
720 if (fd->sidecar_files)
721 sidecars = file_data_sc_list_to_string(fd);
722 size = text_from_size(fd->size);
724 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
725 FILE_COLUMN_THUMB, (VFLIST_INFO(vf, thumbs_enabled)) ? fd->pixbuf : NULL,
726 FILE_COLUMN_NAME, fd->name,
727 FILE_COLUMN_SIDECARS, sidecars,
728 FILE_COLUMN_SIZE, size,
729 FILE_COLUMN_DATE, text_from_time(fd->date),
730 FILE_COLUMN_COLOR, FALSE, -1);
731 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
732 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, fd->marks[i], -1);
739 static void vflist_setup_iter_with_sidecars(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
745 vflist_setup_iter(vf, store, iter, fd);
748 /* this is almost the same code as in vflist_populate_view
749 maybe it should be made more generic and used in both places */
752 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &s_iter, iter);
754 work = fd->sidecar_files;
758 FileData *sfd = work->data;
763 FileData *old_sfd = NULL;
767 gtk_tree_model_get(GTK_TREE_MODEL(store), &s_iter, FILE_COLUMN_POINTER, &old_sfd, -1);
775 match = filelist_sort_compare_filedata_full(sfd, old_sfd, SORT_NAME, TRUE);
790 gtk_tree_store_insert_before(store, &new, iter, &s_iter);
794 gtk_tree_store_append(store, &new, iter);
797 vflist_setup_iter(vf, store, &new, sfd);
803 valid = gtk_tree_store_remove(store, &s_iter);
807 vflist_setup_iter(vf, store, &s_iter, sfd);
809 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &s_iter);
819 valid = gtk_tree_store_remove(store, &s_iter);
823 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
826 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
831 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
832 if (!vf->list) return;
838 FileData *fd = work->data;
839 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
844 vf->sort_method = type;
845 vf->sort_ascend = ascend;
847 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
849 new_order = g_malloc(i * sizeof(gint));
855 FileData *fd = work->data;
856 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
861 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
862 gtk_tree_store_reorder(store, NULL, new_order);
865 g_hash_table_destroy(fd_idx_hash);
869 *-----------------------------------------------------------------------------
871 *-----------------------------------------------------------------------------
874 static gint vflist_thumb_next(ViewFile *vf);
876 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
878 if (vf->func_thumb_status)
880 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
884 static void vflist_thumb_cleanup(ViewFile *vf)
886 vflist_thumb_status(vf, 0.0, NULL);
888 vf->thumbs_count = 0;
889 vf->thumbs_running = FALSE;
891 thumb_loader_free(vf->thumbs_loader);
892 vf->thumbs_loader = NULL;
894 vf->thumbs_filedata = NULL;
897 static void vflist_thumb_stop(ViewFile *vf)
899 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
902 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
907 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
909 if (fd->pixbuf) g_object_unref(fd->pixbuf);
910 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
912 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
913 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
915 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
918 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
922 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
924 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
927 while (vflist_thumb_next(vf));
930 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
934 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
936 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
939 while (vflist_thumb_next(vf));
942 static gint vflist_thumb_next(ViewFile *vf)
947 /* first check the visible files */
949 if (GTK_WIDGET_REALIZED(vf->listview) &&
950 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
956 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
957 gtk_tree_model_get_iter(store, &iter, tpath);
958 gtk_tree_path_free(tpath);
960 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
962 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
963 if (fd->pixbuf) fd = NULL;
965 valid = gtk_tree_model_iter_next(store, &iter);
969 /* then find first undone */
973 GList *work = vf->list;
976 FileData *fd_p = work->data;
981 GList *work2 = fd_p->sidecar_files;
986 if (!fd_p->pixbuf) fd = fd_p;
997 vflist_thumb_cleanup(vf);
1003 vf->thumbs_filedata = fd;
1005 thumb_loader_free(vf->thumbs_loader);
1007 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1008 thumb_loader_set_callbacks(vf->thumbs_loader,
1009 vflist_thumb_done_cb,
1010 vflist_thumb_error_cb,
1014 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1016 /* set icon to unknown, continue */
1017 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1018 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1026 static void vflist_thumb_update(ViewFile *vf)
1028 vflist_thumb_stop(vf);
1029 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1031 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1032 vf->thumbs_running = TRUE;
1034 while (vflist_thumb_next(vf));
1038 *-----------------------------------------------------------------------------
1040 *-----------------------------------------------------------------------------
1043 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1045 return g_list_nth_data(vf->list, row);
1048 static gint vflist_row_by_path(ViewFile *vf, const gchar *path, FileData **fd)
1053 if (!path) return -1;
1058 FileData *fd_n = work->data;
1059 if (strcmp(path, fd_n->path) == 0)
1072 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1074 return vflist_row_by_path(vf, path, NULL);
1077 gint vflist_count(ViewFile *vf, gint64 *bytes)
1087 FileData *fd = work->data;
1095 return g_list_length(vf->list);
1098 GList *vflist_get_list(ViewFile *vf)
1106 FileData *fd = work->data;
1109 list = g_list_prepend(list, file_data_ref(fd));
1112 return g_list_reverse(list);
1116 *-----------------------------------------------------------------------------
1118 *-----------------------------------------------------------------------------
1121 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1123 GtkTreeModel *store;
1124 GtkTreeSelection *selection;
1129 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1130 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1132 while (!found && work)
1134 GtkTreePath *tpath = work->data;
1138 gtk_tree_model_get_iter(store, &iter, tpath);
1139 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1140 if (fd_n == fd) found = TRUE;
1143 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1149 gint vflist_index_is_selected(ViewFile *vf, gint row)
1153 fd = vf_index_get_data(vf, row);
1154 return vflist_row_is_selected(vf, fd);
1157 gint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1159 GtkTreeModel *store;
1160 GtkTreeSelection *selection;
1164 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1165 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1175 GtkTreePath *tpath = work->data;
1179 gtk_tree_model_get_iter(store, &iter, tpath);
1180 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1189 count = g_list_length(slist);
1190 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1196 GList *vflist_selection_get_list(ViewFile *vf)
1198 GtkTreeModel *store;
1199 GtkTreeSelection *selection;
1204 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1205 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1209 GtkTreePath *tpath = work->data;
1213 gtk_tree_model_get_iter(store, &iter, tpath);
1214 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1216 list = g_list_prepend(list, file_data_ref(fd));
1220 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1223 return g_list_reverse(list);
1226 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1228 GtkTreeModel *store;
1229 GtkTreeSelection *selection;
1234 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1235 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1239 GtkTreePath *tpath = work->data;
1243 gtk_tree_model_get_iter(store, &iter, tpath);
1244 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1246 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1250 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1253 return g_list_reverse(list);
1256 void vflist_select_all(ViewFile *vf)
1258 GtkTreeSelection *selection;
1260 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1261 gtk_tree_selection_select_all(selection);
1263 VFLIST_INFO(vf, select_fd) = NULL;
1266 void vflist_select_none(ViewFile *vf)
1268 GtkTreeSelection *selection;
1270 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1271 gtk_tree_selection_unselect_all(selection);
1274 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1279 tpath = gtk_tree_model_get_path(store, iter);
1280 result = gtk_tree_path_prev(tpath);
1282 gtk_tree_model_get_iter(store, iter, tpath);
1284 gtk_tree_path_free(tpath);
1289 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1291 if (!gtk_tree_model_get_iter_first(store, iter))
1296 GtkTreeIter next = *iter;
1298 if (gtk_tree_model_iter_next(store, &next))
1307 void vflist_select_invert(ViewFile *vf)
1310 GtkTreeSelection *selection;
1311 GtkTreeModel *store;
1314 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1315 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1317 /* Backward iteration prevents scrolling to the end of the list,
1318 * it scrolls to the first selected row instead. */
1319 valid = tree_model_get_iter_last(store, &iter);
1323 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1326 gtk_tree_selection_unselect_iter(selection, &iter);
1328 gtk_tree_selection_select_iter(selection, &iter);
1330 valid = tree_model_iter_prev(store, &iter);
1334 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1338 if (vflist_find_row(vf, fd, &iter) < 0) return;
1340 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1342 if (!vflist_row_is_selected(vf, fd))
1344 GtkTreeSelection *selection;
1345 GtkTreeModel *store;
1348 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1349 gtk_tree_selection_unselect_all(selection);
1350 gtk_tree_selection_select_iter(selection, &iter);
1351 vflist_move_cursor(vf, &iter);
1353 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1354 tpath = gtk_tree_model_get_path(store, &iter);
1355 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1356 gtk_tree_path_free(tpath);
1360 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1362 GtkTreeModel *store;
1364 GtkTreeSelection *selection;
1368 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1370 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1371 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1373 valid = gtk_tree_model_get_iter_first(store, &iter);
1377 gboolean mark_val, selected;
1378 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1380 mark_val = fd->marks[n];
1381 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1385 case MTS_MODE_SET: selected = mark_val;
1387 case MTS_MODE_OR: selected = mark_val | selected;
1389 case MTS_MODE_AND: selected = mark_val & selected;
1391 case MTS_MODE_MINUS: selected = !mark_val & selected;
1396 gtk_tree_selection_select_iter(selection, &iter);
1398 gtk_tree_selection_unselect_iter(selection, &iter);
1400 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1404 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1406 GtkTreeModel *store;
1407 GtkTreeSelection *selection;
1412 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1414 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1415 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1419 GtkTreePath *tpath = work->data;
1423 gtk_tree_model_get_iter(store, &iter, tpath);
1424 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1428 case STM_MODE_SET: fd->marks[n] = 1;
1430 case STM_MODE_RESET: fd->marks[n] = 0;
1432 case STM_MODE_TOGGLE: fd->marks[n] = !fd->marks[n];
1436 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, fd->marks[n], -1);
1440 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1445 *-----------------------------------------------------------------------------
1447 *-----------------------------------------------------------------------------
1450 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1452 GtkTreeViewColumn *column;
1453 GtkCellRenderer *cell;
1456 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_COLUMN_THUMB - 1);
1457 if (!column) return;
1459 gtk_tree_view_column_set_fixed_width(column, ((thumb) ? options->thumbnails.max_width : 4) + 10);
1461 list = gtk_tree_view_column_get_cell_renderers(column);
1466 g_object_set(G_OBJECT(cell), "height", (thumb) ? options->thumbnails.max_height : -1, NULL);
1467 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1470 static void vflist_populate_view(ViewFile *vf)
1472 GtkTreeStore *store;
1476 GtkTreeRowReference *visible_row = NULL;
1480 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1481 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1483 vflist_thumb_stop(vf);
1487 gtk_tree_store_clear(store);
1492 if (GTK_WIDGET_REALIZED(vf->listview) &&
1493 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1495 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1496 gtk_tree_path_free(tpath);
1499 vflist_listview_set_height(vf->listview, thumbs);
1501 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1507 FileData *fd = work->data;
1512 FileData *old_fd = NULL;
1516 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
1524 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
1526 match = -1; /* probably should not happen*/
1541 gtk_tree_store_insert_before(store, &new, NULL, &iter);
1545 gtk_tree_store_append(store, &new, NULL);
1547 vflist_setup_iter_with_sidecars(vf, store, &new, fd);
1553 valid = gtk_tree_store_remove(store, &iter);
1557 vflist_setup_iter_with_sidecars(vf, store, &iter, fd);
1559 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1569 valid = gtk_tree_store_remove(store, &iter);
1574 if (gtk_tree_row_reference_valid(visible_row))
1576 tpath = gtk_tree_row_reference_get_path(visible_row);
1577 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1578 gtk_tree_path_free(tpath);
1580 gtk_tree_row_reference_free(visible_row);
1584 vflist_thumb_update(vf);
1587 gint vflist_refresh(ViewFile *vf)
1592 old_list = vf->list;
1597 ret = filelist_read(vf->path, &vf->list, NULL);
1600 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1601 vflist_populate_view(vf);
1603 filelist_free(old_list);
1608 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1610 #define CELL_HEIGHT_OVERRIDE 512
1612 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1616 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1617 if (spec && G_IS_PARAM_SPEC_INT(spec))
1619 GParamSpecInt *spec_int;
1621 spec_int = G_PARAM_SPEC_INT(spec);
1622 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1626 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1628 static GdkColor color;
1629 static GtkWidget *done = NULL;
1635 style = gtk_widget_get_style(widget);
1636 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1637 shift_color(&color, -1, 0);
1644 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1645 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1647 ViewFile *vf = data;
1650 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1651 g_object_set(G_OBJECT(cell),
1652 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1653 "cell-background-set", set, NULL);
1656 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1658 GtkTreeViewColumn *column;
1659 GtkCellRenderer *renderer;
1661 column = gtk_tree_view_column_new();
1662 gtk_tree_view_column_set_title(column, title);
1663 gtk_tree_view_column_set_min_width(column, 4);
1667 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1668 renderer = gtk_cell_renderer_text_new();
1671 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1673 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1674 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1676 gtk_tree_view_column_set_expand(column, TRUE);
1680 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1681 renderer = gtk_cell_renderer_pixbuf_new();
1682 cell_renderer_height_override(renderer);
1683 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1684 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1687 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1688 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1689 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1691 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1694 static void vflist_listview_mark_toggled(GtkCellRendererToggle *cell, gchar *path_str, GtkTreeStore *store)
1696 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1702 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1705 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1707 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1709 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1711 fd->marks[col_idx - FILE_COLUMN_MARKS] = mark;
1713 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1714 gtk_tree_path_free(path);
1717 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1719 GtkTreeViewColumn *column;
1720 GtkCellRenderer *renderer;
1721 GtkTreeStore *store;
1724 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1726 renderer = gtk_cell_renderer_toggle_new();
1727 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1729 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1730 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1731 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1733 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1734 gtk_tree_view_column_set_fixed_width(column, 16);
1735 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1738 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled), store);
1742 *-----------------------------------------------------------------------------
1744 *-----------------------------------------------------------------------------
1747 gint vflist_set_path(ViewFile *vf, const gchar *path)
1749 GtkTreeStore *store;
1751 if (!path) return FALSE;
1752 if (vf->path && strcmp(path, vf->path) == 0) return TRUE;
1755 vf->path = g_strdup(path);
1757 /* force complete reload */
1758 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1759 gtk_tree_store_clear(store);
1761 filelist_free(vf->list);
1764 return vf_refresh(vf);
1767 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1769 ViewFile *vf = data;
1771 vflist_select_idle_cancel(vf);
1772 vflist_thumb_stop(vf);
1774 filelist_free(vf->list);
1777 ViewFile *vflist_new(ViewFile *vf, const gchar *path)
1779 GtkTreeStore *store;
1780 GtkTreeSelection *selection;
1782 GType flist_types[FILE_COLUMN_COUNT];
1785 vf->info = g_new0(ViewFileInfoList, 1);
1787 VFLIST_INFO(vf, click_fd) = NULL;
1788 VFLIST_INFO(vf, select_fd) = NULL;
1789 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1791 VFLIST_INFO(vf, select_idle_id) = -1;
1793 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1794 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1795 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1796 flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1797 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1798 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1799 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1800 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1801 flist_types[i] = G_TYPE_BOOLEAN;
1803 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1805 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1806 g_object_unref(store);
1808 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1809 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1810 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1812 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1813 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1815 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1817 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1818 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1820 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
1821 vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1823 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1824 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1829 void vflist_thumb_set(ViewFile *vf, gint enable)
1831 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1833 VFLIST_INFO(vf, thumbs_enabled) = enable;
1834 if (vf->layout) vf_refresh(vf);
1837 void vflist_marks_set(ViewFile *vf, gint enable)
1839 GList *columns, *work;
1841 if (vf->marks_enabled == enable) return;
1843 vf->marks_enabled = enable;
1845 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1850 GtkTreeViewColumn *column = work->data;
1851 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1854 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1855 gtk_tree_view_column_set_visible(column, enable);
1858 g_list_free(columns);
1863 *-----------------------------------------------------------------------------
1864 * maintenance (for rename, move, remove)
1865 *-----------------------------------------------------------------------------
1868 static gint vflist_maint_find_closest(ViewFile *vf, gint row, gint count, GList *ignore_list)
1878 gint f = vf_index_by_path(vf, work->data);
1879 if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f));
1889 gpointer p = work->data;
1891 if (row == GPOINTER_TO_INT(p))
1896 if (rev == GPOINTER_TO_INT(p))
1901 if (!c) list = g_list_remove(list, p);
1909 if (row > count - 1)
1922 gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
1928 if (g_list_index(vf->list, fd) < 0) return FALSE;
1930 source_base = remove_level_from_path(fd->change->source);
1931 dest_base = remove_level_from_path(fd->change->dest);
1934 if (strcmp(source_base, dest_base) == 0)
1936 GtkTreeStore *store;
1938 GtkTreeIter position;
1942 old_row = g_list_index(vf->list, fd);
1944 vf->list = g_list_remove(vf->list, fd);
1946 vf->list = filelist_insert_sort(vf->list, fd, vf->sort_method, vf->sort_ascend);
1947 n = g_list_index(vf->list, fd);
1949 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1950 if (vflist_find_row(vf, fd, &iter) >= 0 &&
1951 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &position, NULL, n))
1955 gtk_tree_store_move_before(store, &iter, &position);
1959 gtk_tree_store_move_after(store, &iter, &position);
1962 gtk_tree_store_set(store, &iter, FILE_COLUMN_NAME, fd->name, -1);
1968 ret = vflist_maint_removed(vf, fd, NULL);
1971 g_free(source_base);
1977 gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
1984 row = g_list_index(vf->list, fd);
1985 if (row < 0) return FALSE;
1987 if (vflist_index_is_selected(vf, row) &&
1988 layout_image_get_collection(vf->layout, NULL) == NULL)
1992 n = vf_count(vf, NULL);
1995 new_row = vflist_maint_find_closest(vf, row, n, ignore_list);
1996 DEBUG_1("row = %d, closest is %d", row, new_row);
2012 fd = vf_index_get_data(vf, new_row);
2013 if (vflist_find_row(vf, fd, &iter) >= 0)
2015 GtkTreeSelection *selection;
2017 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
2018 gtk_tree_selection_select_iter(selection, &iter);
2019 vflist_move_cursor(vf, &iter);
2024 fd = vf_index_get_data(vf, row);
2025 if (vflist_find_row(vf, fd, &iter) >= 0)
2027 GtkTreeStore *store;
2028 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
2029 gtk_tree_store_remove(store, &iter);
2031 list = g_list_nth(vf->list, row);
2034 /* thumbnail loader check */
2035 if (fd == vf->thumbs_filedata) vf->thumbs_filedata = NULL;
2036 if (vf->thumbs_count > 0) vf->thumbs_count--;
2038 vf->list = g_list_remove(vf->list, fd);
2039 file_data_unref(fd);
2046 gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
2051 if (!fd->change->source || !vf->path) return FALSE;
2053 buf = remove_level_from_path(fd->change->source);
2055 if (strcmp(buf, vf->path) == 0)
2057 ret = vflist_maint_removed(vf, fd, ignore_list);