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);
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 = g_build_filename(vf->path, old, NULL);
386 new_path = g_build_filename(vf->path, new, NULL);
388 if (strchr(new, G_DIR_SEPARATOR) != 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 file_util_rename_simple(fd, new_path, vf->listview);
419 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
427 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
428 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
429 tpath = gtk_tree_model_get_path(store, &iter);
430 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
431 gtk_tree_path_free(tpath);
433 popup_menu_position_clamp(menu, x, y, 0);
436 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
441 if (event->keyval != GDK_Menu) return FALSE;
443 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
449 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
450 gtk_tree_model_get_iter(store, &iter, tpath);
451 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
452 gtk_tree_path_free(tpath);
456 VFLIST_INFO(vf, click_fd) = NULL;
459 vf->popup = vf_pop_menu(vf);
460 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
465 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
471 GtkTreeViewColumn *column;
473 vf->clicked_mark = 0;
475 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
476 &tpath, &column, NULL, NULL))
479 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
481 if (bevent->button == MOUSE_BUTTON_LEFT &&
482 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
485 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
486 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
488 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
490 gtk_tree_model_get_iter(store, &iter, tpath);
491 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
493 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
495 gtk_tree_path_free(tpath);
498 VFLIST_INFO(vf, click_fd) = fd;
500 if (bevent->button == MOUSE_BUTTON_RIGHT)
502 vf->popup = vf_pop_menu(vf);
503 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
504 bevent->button, bevent->time);
508 if (!fd) return FALSE;
510 if (bevent->button == MOUSE_BUTTON_MIDDLE)
512 if (!vflist_row_is_selected(vf, fd))
514 vflist_color_set(vf, fd, TRUE);
520 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
521 !(bevent->state & GDK_SHIFT_MASK ) &&
522 !(bevent->state & GDK_CONTROL_MASK ) &&
523 vflist_row_is_selected(vf, fd))
525 GtkTreeSelection *selection;
527 gtk_widget_grab_focus(widget);
530 /* returning FALSE and further processing of the event is needed for
531 correct operation of the expander, to show the sidecar files.
532 It however resets the selection of multiple files. With this condition
533 it should work for both cases */
534 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
535 return (gtk_tree_selection_count_selected_rows(selection) > 1);
539 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
541 if (vf->layout) layout_image_full_screen_start(vf->layout);
548 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
555 if (bevent->button == MOUSE_BUTTON_MIDDLE)
557 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
560 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
565 if ((bevent->x != 0 || bevent->y != 0) &&
566 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
567 &tpath, NULL, NULL, NULL))
571 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
572 gtk_tree_model_get_iter(store, &iter, tpath);
573 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
574 gtk_tree_path_free(tpath);
577 if (bevent->button == MOUSE_BUTTON_MIDDLE)
579 if (fd && VFLIST_INFO(vf, click_fd) == fd)
581 GtkTreeSelection *selection;
583 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
584 if (vflist_row_is_selected(vf, fd))
586 gtk_tree_selection_unselect_iter(selection, &iter);
590 gtk_tree_selection_select_iter(selection, &iter);
596 if (fd && VFLIST_INFO(vf, click_fd) == fd &&
597 !(bevent->state & GDK_SHIFT_MASK ) &&
598 !(bevent->state & GDK_CONTROL_MASK ) &&
599 vflist_row_is_selected(vf, fd))
601 GtkTreeSelection *selection;
603 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
604 gtk_tree_selection_unselect_all(selection);
605 gtk_tree_selection_select_iter(selection, &iter);
606 vflist_move_cursor(vf, &iter);
607 // return TRUE;// FIXME - expand
613 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
615 FileData *read_ahead_fd = NULL;
620 cur_fd = layout_image_get_fd(vf->layout);
621 if (sel_fd == cur_fd) return; /* no change */
623 row = g_list_index(vf->list, sel_fd);
624 // FIXME sidecar data
626 if (sel_fd && options->image.enable_read_ahead && row >= 0)
628 if (row > g_list_index(vf->list, cur_fd) &&
629 (guint) (row + 1) < vf_count(vf, NULL))
631 read_ahead_fd = vf_index_get_data(vf, row + 1);
635 read_ahead_fd = vf_index_get_data(vf, row - 1);
639 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
642 static gint vflist_select_idle_cb(gpointer data)
648 VFLIST_INFO(vf, select_idle_id) = -1;
654 if (VFLIST_INFO(vf, select_fd))
656 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
657 VFLIST_INFO(vf, select_fd) = NULL;
660 VFLIST_INFO(vf, select_idle_id) = -1;
664 static void vflist_select_idle_cancel(ViewFile *vf)
666 if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
667 VFLIST_INFO(vf, select_idle_id) = -1;
670 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
671 gboolean path_currently_selected, gpointer data)
676 if (!path_currently_selected &&
677 gtk_tree_model_get_iter(store, &iter, tpath))
679 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
683 VFLIST_INFO(vf, select_fd) = NULL;
687 VFLIST_INFO(vf, select_idle_id) == -1)
689 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
696 *-----------------------------------------------------------------------------
698 *-----------------------------------------------------------------------------
702 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
703 gboolean path_currently_selected, gpointer data)
709 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
713 gchar *sidecars = NULL;
715 if (fd->sidecar_files)
716 sidecars = file_data_sc_list_to_string(fd);
717 size = text_from_size(fd->size);
719 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
720 FILE_COLUMN_VERSION, fd->version,
721 FILE_COLUMN_THUMB, (VFLIST_INFO(vf, thumbs_enabled)) ? fd->pixbuf : NULL,
722 FILE_COLUMN_NAME, fd->name,
723 FILE_COLUMN_SIDECARS, sidecars,
724 FILE_COLUMN_SIZE, size,
725 FILE_COLUMN_DATE, text_from_time(fd->date),
726 FILE_COLUMN_COLOR, FALSE, -1);
727 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
728 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, fd->marks[i], -1);
735 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
741 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
747 FileData *fd = work->data;
752 FileData *old_fd = NULL;
753 gint old_version = 0;
757 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
758 FILE_COLUMN_POINTER, &old_fd,
759 FILE_COLUMN_VERSION, &old_version,
769 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
771 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
773 if (match == 0) g_warning("multiple fd for the same path");
788 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
792 gtk_tree_store_append(store, &new, parent_iter);
795 vflist_setup_iter(vf, store, &new, fd);
796 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
798 if (g_list_find(selected, fd))
800 /* renamed files - the same fd appears at different position - select it again*/
801 GtkTreeSelection *selection;
802 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
803 gtk_tree_selection_select_iter(selection, &new);
810 valid = gtk_tree_store_remove(store, &iter);
814 if (fd->version != old_version)
816 vflist_setup_iter(vf, store, &iter, fd);
817 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
820 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
830 valid = gtk_tree_store_remove(store, &iter);
834 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
837 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
842 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
843 if (!vf->list) return;
849 FileData *fd = work->data;
850 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
855 vf->sort_method = type;
856 vf->sort_ascend = ascend;
858 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
860 new_order = g_malloc(i * sizeof(gint));
866 FileData *fd = work->data;
867 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
872 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
873 gtk_tree_store_reorder(store, NULL, new_order);
876 g_hash_table_destroy(fd_idx_hash);
880 *-----------------------------------------------------------------------------
882 *-----------------------------------------------------------------------------
885 static gint vflist_thumb_next(ViewFile *vf);
887 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
889 if (vf->func_thumb_status)
891 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
895 static void vflist_thumb_cleanup(ViewFile *vf)
897 vflist_thumb_status(vf, 0.0, NULL);
899 vf->thumbs_count = 0;
900 vf->thumbs_running = FALSE;
902 thumb_loader_free(vf->thumbs_loader);
903 vf->thumbs_loader = NULL;
905 vf->thumbs_filedata = NULL;
908 static void vflist_thumb_stop(ViewFile *vf)
910 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
913 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
918 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
920 if (fd->pixbuf) g_object_unref(fd->pixbuf);
921 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
923 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
924 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
926 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
929 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
933 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
935 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
938 while (vflist_thumb_next(vf));
941 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
945 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
947 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
950 while (vflist_thumb_next(vf));
953 static gint vflist_thumb_next(ViewFile *vf)
958 /* first check the visible files */
960 if (GTK_WIDGET_REALIZED(vf->listview) &&
961 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
967 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
968 gtk_tree_model_get_iter(store, &iter, tpath);
969 gtk_tree_path_free(tpath);
971 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
973 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
974 if (fd->pixbuf) fd = NULL;
976 valid = gtk_tree_model_iter_next(store, &iter);
980 /* then find first undone */
984 GList *work = vf->list;
987 FileData *fd_p = work->data;
992 GList *work2 = fd_p->sidecar_files;
997 if (!fd_p->pixbuf) fd = fd_p;
1008 vflist_thumb_cleanup(vf);
1014 vf->thumbs_filedata = fd;
1016 thumb_loader_free(vf->thumbs_loader);
1018 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1019 thumb_loader_set_callbacks(vf->thumbs_loader,
1020 vflist_thumb_done_cb,
1021 vflist_thumb_error_cb,
1025 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1027 /* set icon to unknown, continue */
1028 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1029 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1037 static void vflist_thumb_update(ViewFile *vf)
1039 vflist_thumb_stop(vf);
1040 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1042 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1043 vf->thumbs_running = TRUE;
1045 while (vflist_thumb_next(vf));
1049 *-----------------------------------------------------------------------------
1051 *-----------------------------------------------------------------------------
1054 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1056 return g_list_nth_data(vf->list, row);
1059 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1064 if (!path) return -1;
1069 FileData *fd = work->data;
1070 if (strcmp(path, fd->path) == 0) return p;
1079 guint vflist_count(ViewFile *vf, gint64 *bytes)
1089 FileData *fd = work->data;
1097 return g_list_length(vf->list);
1100 GList *vflist_get_list(ViewFile *vf)
1108 FileData *fd = work->data;
1111 list = g_list_prepend(list, file_data_ref(fd));
1114 return g_list_reverse(list);
1118 *-----------------------------------------------------------------------------
1120 *-----------------------------------------------------------------------------
1123 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1125 GtkTreeModel *store;
1126 GtkTreeSelection *selection;
1131 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1132 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1134 while (!found && work)
1136 GtkTreePath *tpath = work->data;
1140 gtk_tree_model_get_iter(store, &iter, tpath);
1141 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1142 if (fd_n == fd) found = TRUE;
1145 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1151 gint vflist_index_is_selected(ViewFile *vf, gint row)
1155 fd = vf_index_get_data(vf, row);
1156 return vflist_row_is_selected(vf, fd);
1159 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1161 GtkTreeModel *store;
1162 GtkTreeSelection *selection;
1166 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1167 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1177 GtkTreePath *tpath = work->data;
1181 gtk_tree_model_get_iter(store, &iter, tpath);
1182 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1191 count = g_list_length(slist);
1192 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1198 GList *vflist_selection_get_list(ViewFile *vf)
1200 GtkTreeModel *store;
1201 GtkTreeSelection *selection;
1206 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1207 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1211 GtkTreePath *tpath = work->data;
1215 gtk_tree_model_get_iter(store, &iter, tpath);
1216 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1218 list = g_list_prepend(list, file_data_ref(fd));
1222 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1225 return g_list_reverse(list);
1228 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1230 GtkTreeModel *store;
1231 GtkTreeSelection *selection;
1236 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1237 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1241 GtkTreePath *tpath = work->data;
1245 gtk_tree_model_get_iter(store, &iter, tpath);
1246 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1248 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1252 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1255 return g_list_reverse(list);
1258 void vflist_select_all(ViewFile *vf)
1260 GtkTreeSelection *selection;
1262 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1263 gtk_tree_selection_select_all(selection);
1265 VFLIST_INFO(vf, select_fd) = NULL;
1268 void vflist_select_none(ViewFile *vf)
1270 GtkTreeSelection *selection;
1272 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1273 gtk_tree_selection_unselect_all(selection);
1276 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1281 tpath = gtk_tree_model_get_path(store, iter);
1282 result = gtk_tree_path_prev(tpath);
1284 gtk_tree_model_get_iter(store, iter, tpath);
1286 gtk_tree_path_free(tpath);
1291 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1293 if (!gtk_tree_model_get_iter_first(store, iter))
1298 GtkTreeIter next = *iter;
1300 if (gtk_tree_model_iter_next(store, &next))
1309 void vflist_select_invert(ViewFile *vf)
1312 GtkTreeSelection *selection;
1313 GtkTreeModel *store;
1316 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1317 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1319 /* Backward iteration prevents scrolling to the end of the list,
1320 * it scrolls to the first selected row instead. */
1321 valid = tree_model_get_iter_last(store, &iter);
1325 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1328 gtk_tree_selection_unselect_iter(selection, &iter);
1330 gtk_tree_selection_select_iter(selection, &iter);
1332 valid = tree_model_iter_prev(store, &iter);
1336 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1340 if (vflist_find_row(vf, fd, &iter) < 0) return;
1342 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1344 if (!vflist_row_is_selected(vf, fd))
1346 GtkTreeSelection *selection;
1347 GtkTreeModel *store;
1350 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1351 gtk_tree_selection_unselect_all(selection);
1352 gtk_tree_selection_select_iter(selection, &iter);
1353 vflist_move_cursor(vf, &iter);
1355 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1356 tpath = gtk_tree_model_get_path(store, &iter);
1357 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1358 gtk_tree_path_free(tpath);
1362 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1366 if (sel_fd->parent) sel_fd = sel_fd->parent;
1372 FileData *fd = work->data;
1376 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1380 vflist_select_by_fd(vf, fd);
1387 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1389 GtkTreeModel *store;
1391 GtkTreeSelection *selection;
1395 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1397 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1398 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1400 valid = gtk_tree_model_get_iter_first(store, &iter);
1404 gboolean mark_val, selected;
1405 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1407 mark_val = fd->marks[n];
1408 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1412 case MTS_MODE_SET: selected = mark_val;
1414 case MTS_MODE_OR: selected = mark_val | selected;
1416 case MTS_MODE_AND: selected = mark_val & selected;
1418 case MTS_MODE_MINUS: selected = !mark_val & selected;
1423 gtk_tree_selection_select_iter(selection, &iter);
1425 gtk_tree_selection_unselect_iter(selection, &iter);
1427 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1431 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1433 GtkTreeModel *store;
1434 GtkTreeSelection *selection;
1439 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1441 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1442 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1446 GtkTreePath *tpath = work->data;
1450 gtk_tree_model_get_iter(store, &iter, tpath);
1451 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1455 case STM_MODE_SET: fd->marks[n] = 1;
1457 case STM_MODE_RESET: fd->marks[n] = 0;
1459 case STM_MODE_TOGGLE: fd->marks[n] = !fd->marks[n];
1463 file_data_increment_version(fd);
1465 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, fd->marks[n], -1);
1469 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1474 *-----------------------------------------------------------------------------
1476 *-----------------------------------------------------------------------------
1479 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1481 GtkTreeViewColumn *column;
1482 GtkCellRenderer *cell;
1485 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
1486 if (!column) return;
1488 gtk_tree_view_column_set_fixed_width(column, ((thumb) ? options->thumbnails.max_width : 4) + 10);
1490 list = gtk_tree_view_column_get_cell_renderers(column);
1495 g_object_set(G_OBJECT(cell), "height", (thumb) ? options->thumbnails.max_height : -1, NULL);
1496 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1499 static void vflist_populate_view(ViewFile *vf)
1501 GtkTreeStore *store;
1503 GtkTreeRowReference *visible_row = NULL;
1507 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1508 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1510 vflist_thumb_stop(vf);
1514 gtk_tree_store_clear(store);
1519 if (GTK_WIDGET_REALIZED(vf->listview) &&
1520 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1522 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1523 gtk_tree_path_free(tpath);
1526 vflist_listview_set_height(vf->listview, thumbs);
1528 selected = vflist_selection_get_list(vf);
1530 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1532 if (selected && vflist_selection_count(vf, NULL) == 0)
1534 /* all selected files disappeared */
1535 vflist_select_closest(vf, selected->data);
1538 filelist_free(selected);
1542 if (gtk_tree_row_reference_valid(visible_row))
1544 tpath = gtk_tree_row_reference_get_path(visible_row);
1545 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1546 gtk_tree_path_free(tpath);
1548 gtk_tree_row_reference_free(visible_row);
1552 vflist_thumb_update(vf);
1555 gint vflist_refresh(ViewFile *vf)
1560 old_list = vf->list;
1563 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1566 ret = filelist_read(vf->path, &vf->list, NULL);
1568 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1570 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1572 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1574 vflist_populate_view(vf);
1576 filelist_free(old_list);
1577 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1582 static gint vflist_refresh_idle_cb(gpointer data)
1584 ViewFile *vf = data;
1587 vf->refresh_idle_id = -1;
1591 static void vflist_refresh_idle_cancel(ViewFile *vf)
1593 if (vf->refresh_idle_id != -1) g_source_remove(vf->refresh_idle_id);
1594 vf->refresh_idle_id = -1;
1598 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1600 #define CELL_HEIGHT_OVERRIDE 512
1602 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1606 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1607 if (spec && G_IS_PARAM_SPEC_INT(spec))
1609 GParamSpecInt *spec_int;
1611 spec_int = G_PARAM_SPEC_INT(spec);
1612 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1616 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1618 static GdkColor color;
1619 static GtkWidget *done = NULL;
1625 style = gtk_widget_get_style(widget);
1626 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1627 shift_color(&color, -1, 0);
1634 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1635 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1637 ViewFile *vf = data;
1640 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1641 g_object_set(G_OBJECT(cell),
1642 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1643 "cell-background-set", set, NULL);
1646 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1648 GtkTreeViewColumn *column;
1649 GtkCellRenderer *renderer;
1651 column = gtk_tree_view_column_new();
1652 gtk_tree_view_column_set_title(column, title);
1653 gtk_tree_view_column_set_min_width(column, 4);
1657 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1658 renderer = gtk_cell_renderer_text_new();
1661 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1663 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1664 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1666 gtk_tree_view_column_set_expand(column, TRUE);
1670 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1671 renderer = gtk_cell_renderer_pixbuf_new();
1672 cell_renderer_height_override(renderer);
1673 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1674 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1677 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1678 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1679 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1681 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1684 static void vflist_listview_mark_toggled(GtkCellRendererToggle *cell, gchar *path_str, GtkTreeStore *store)
1686 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1692 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1695 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1697 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1699 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1701 fd->marks[col_idx - FILE_COLUMN_MARKS] = mark;
1702 file_data_increment_version(fd);
1704 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1705 gtk_tree_path_free(path);
1708 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1710 GtkTreeViewColumn *column;
1711 GtkCellRenderer *renderer;
1712 GtkTreeStore *store;
1715 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1717 renderer = gtk_cell_renderer_toggle_new();
1718 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1720 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1721 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1722 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1724 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1725 gtk_tree_view_column_set_fixed_width(column, 16);
1726 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1729 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled), store);
1733 *-----------------------------------------------------------------------------
1735 *-----------------------------------------------------------------------------
1738 gint vflist_set_path(ViewFile *vf, const gchar *path)
1740 GtkTreeStore *store;
1742 if (!path) return FALSE;
1743 if (vf->path && strcmp(path, vf->path) == 0) return TRUE;
1746 vf->path = g_strdup(path);
1748 /* force complete reload */
1749 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1750 gtk_tree_store_clear(store);
1752 filelist_free(vf->list);
1755 return vf_refresh(vf);
1758 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1760 ViewFile *vf = data;
1762 vflist_select_idle_cancel(vf);
1763 vflist_refresh_idle_cancel(vf);
1764 vflist_thumb_stop(vf);
1766 filelist_free(vf->list);
1769 ViewFile *vflist_new(ViewFile *vf, const gchar *path)
1771 GtkTreeStore *store;
1772 GtkTreeSelection *selection;
1774 GType flist_types[FILE_COLUMN_COUNT];
1777 vf->info = g_new0(ViewFileInfoList, 1);
1779 VFLIST_INFO(vf, click_fd) = NULL;
1780 VFLIST_INFO(vf, select_fd) = NULL;
1781 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1783 VFLIST_INFO(vf, select_idle_id) = -1;
1784 vf->refresh_idle_id = -1;
1787 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1788 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1789 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1790 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1791 flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1792 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1793 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1794 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1795 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1796 flist_types[i] = G_TYPE_BOOLEAN;
1798 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1800 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1801 g_object_unref(store);
1803 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1804 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1805 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1807 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1808 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1810 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1812 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1813 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1815 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
1816 vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1818 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1819 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1824 void vflist_thumb_set(ViewFile *vf, gint enable)
1826 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1828 VFLIST_INFO(vf, thumbs_enabled) = enable;
1829 if (vf->layout) vf_refresh(vf);
1832 void vflist_marks_set(ViewFile *vf, gint enable)
1834 GList *columns, *work;
1836 if (vf->marks_enabled == enable) return;
1838 vf->marks_enabled = enable;
1840 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1845 GtkTreeViewColumn *column = work->data;
1846 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1849 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1850 gtk_tree_view_column_set_visible(column, enable);
1853 g_list_free(columns);
1858 *-----------------------------------------------------------------------------
1859 * maintenance (for rename, move, remove)
1860 *-----------------------------------------------------------------------------
1863 void vflist_maint(ViewFile *vf, FileData *fd)
1868 if (vf->refresh_idle_id != -1) return;
1870 source_base = remove_level_from_path(fd->change->source);
1871 dest_base = remove_level_from_path(fd->change->dest);
1873 if (strcmp(source_base, vf->path) == 0 ||
1874 strcmp(dest_base, vf->path) == 0 ||
1875 strcmp(fd->path, vf->path) == 0)
1877 vf->refresh_idle_id = g_idle_add(vflist_refresh_idle_cb, vf);
1879 g_free(source_base);
1883 /* the plan is to drop these functions and use vflist_maint directly */
1885 gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
1887 vflist_maint(vf, fd);
1890 gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
1892 vflist_maint(vf, fd);
1895 gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
1897 vflist_maint(vf, fd);
1903 static gint vflist_maint_find_closest(ViewFile *vf, gint row, gint count, GList *ignore_list)
1913 gint f = vf_index_by_path(vf, work->data);
1914 if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f));
1924 gpointer p = work->data;
1926 if (row == GPOINTER_TO_INT(p))
1931 if (rev == GPOINTER_TO_INT(p))
1936 if (!c) list = g_list_remove(list, p);
1944 if (row > count - 1)
1957 gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
1963 DEBUG_1("%s vflist_maint_renamed: start", get_exec_time());
1965 if (g_list_index(vf->list, fd) < 0) return FALSE;
1967 source_base = remove_level_from_path(fd->change->source);
1968 dest_base = remove_level_from_path(fd->change->dest);
1971 if (strcmp(source_base, dest_base) == 0)
1973 GtkTreeStore *store;
1975 GtkTreeIter position;
1979 old_row = g_list_index(vf->list, fd);
1981 vf->list = g_list_remove(vf->list, fd);
1983 vf->list = filelist_insert_sort(vf->list, fd, vf->sort_method, vf->sort_ascend);
1984 n = g_list_index(vf->list, fd);
1986 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1987 if (vflist_find_row(vf, fd, &iter) >= 0 &&
1988 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &position, NULL, n))
1992 gtk_tree_store_move_before(store, &iter, &position);
1996 gtk_tree_store_move_after(store, &iter, &position);
1999 gtk_tree_store_set(store, &iter, FILE_COLUMN_NAME, fd->name, -1);
2005 ret = vflist_maint_removed(vf, fd, NULL);
2008 g_free(source_base);
2011 DEBUG_1("%s vflist_maint_renamed: done", get_exec_time());
2016 gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
2023 DEBUG_1("%s vflist_maint_removed: start", get_exec_time());
2025 row = g_list_index(vf->list, fd);
2026 if (row < 0) return FALSE;
2028 if (vflist_index_is_selected(vf, row) &&
2029 layout_image_get_collection(vf->layout, NULL) == NULL)
2033 n = vf_count(vf, NULL);
2036 new_row = vflist_maint_find_closest(vf, row, n, ignore_list);
2037 DEBUG_1("row = %d, closest is %d", row, new_row);
2053 fd = vf_index_get_data(vf, new_row);
2054 if (vflist_find_row(vf, fd, &iter) >= 0)
2056 GtkTreeSelection *selection;
2058 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
2059 gtk_tree_selection_select_iter(selection, &iter);
2060 vflist_move_cursor(vf, &iter);
2065 fd = vf_index_get_data(vf, row);
2066 if (vflist_find_row(vf, fd, &iter) >= 0)
2068 GtkTreeStore *store;
2069 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
2070 gtk_tree_store_remove(store, &iter);
2072 list = g_list_nth(vf->list, row);
2075 /* thumbnail loader check */
2076 if (fd == vf->thumbs_filedata) vf->thumbs_filedata = NULL;
2077 if (vf->thumbs_count > 0) vf->thumbs_count--;
2079 vf->list = g_list_remove(vf->list, fd);
2080 file_data_unref(fd);
2084 DEBUG_1("%s vflist_maint_removed: done", get_exec_time());
2089 gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
2094 if (!fd->change->source || !vf->path) return FALSE;
2096 buf = remove_level_from_path(fd->change->source);
2098 if (strcmp(buf, vf->path) == 0)
2100 ret = vflist_maint_removed(vf, fd, ignore_list);