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 */
34 /* Index to tree store */
36 FILE_COLUMN_POINTER = 0,
40 FILE_COLUMN_MULTILINE,
45 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
50 /* Index to tree view */
52 FILE_VIEW_COLUMN_MARKS = 0,
53 FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
54 FILE_VIEW_COLUMN_THUMB,
55 FILE_VIEW_COLUMN_MULTILINE,
56 FILE_VIEW_COLUMN_NAME,
57 FILE_VIEW_COLUMN_SIZE,
58 FILE_VIEW_COLUMN_DATE,
59 FILE_VIEW_COLUMN_COUNT
64 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
65 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
66 static void vflist_populate_view(ViewFile *vf);
70 *-----------------------------------------------------------------------------
72 *-----------------------------------------------------------------------------
79 } ViewFileFindRowData;
81 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
83 ViewFileFindRowData *find = data;
85 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
96 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
99 ViewFileFindRowData data = {fd, iter, 0, 0};
101 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
102 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
114 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
119 FileData *fd_p = work->data;
120 if (fd == fd_p) return i;
124 GList *work2 = fd_p->sidecar_files;
128 if (fd == fd_p) return i;
139 static gint vflist_sidecar_list_count(GList *work)
144 FileData *fd = work->data;
147 GList *work2 = fd->sidecar_files;
158 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
161 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
166 static void vflist_store_clear(ViewFile *vf)
169 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
170 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
171 gtk_tree_store_clear(GTK_TREE_STORE(store));
174 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
179 if (vflist_find_row(vf, fd, &iter) < 0) return;
180 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
181 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
184 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
189 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
191 tpath = gtk_tree_model_get_path(store, iter);
192 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
193 gtk_tree_path_free(tpath);
197 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
199 GList *columns, *work;
202 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
206 GtkTreeViewColumn *column = work->data;
207 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
213 g_list_free(columns);
219 *-----------------------------------------------------------------------------
221 *-----------------------------------------------------------------------------
224 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
225 GtkSelectionData *selection_data, guint info,
226 guint time, gpointer data)
230 gchar *uri_text = NULL;
233 if (!VFLIST_INFO(vf, click_fd)) return;
235 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
237 list = vf_selection_get_list(vf);
241 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
246 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
251 gtk_selection_data_set(selection_data, selection_data->target,
252 8, (guchar *)uri_text, total);
256 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
260 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
262 if (VFLIST_INFO(vf, thumbs_enabled) &&
263 VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->thumb_pixbuf)
267 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
268 items = vf_selection_count(vf, NULL);
272 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->thumb_pixbuf, items);
276 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
280 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
282 if (context->action == GDK_ACTION_MOVE)
288 void vflist_dnd_init(ViewFile *vf)
290 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
291 dnd_file_drag_types, dnd_file_drag_types_count,
292 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
293 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
294 G_CALLBACK(vflist_dnd_get), vf);
295 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
296 G_CALLBACK(vflist_dnd_begin), vf);
297 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
298 G_CALLBACK(vflist_dnd_end), vf);
302 *-----------------------------------------------------------------------------
304 *-----------------------------------------------------------------------------
307 GList *vflist_pop_menu_file_list(ViewFile *vf)
309 if (!VFLIST_INFO(vf, click_fd)) return NULL;
311 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
313 return vf_selection_get_list(vf);
316 return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
319 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
323 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
327 list = vf_selection_get_list(vf);
328 view_window_new_from_list(list);
333 view_window_new(VFLIST_INFO(vf, click_fd));
337 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
342 list = vf_pop_menu_file_list(vf);
343 if (options->file_ops.enable_in_place_rename &&
344 list && !list->next && VFLIST_INFO(vf, click_fd))
351 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
352 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
356 tpath = gtk_tree_model_get_path(store, &iter);
357 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
358 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
359 vflist_row_rename_cb, vf);
360 gtk_tree_path_free(tpath);
365 file_util_rename(NULL, list, vf->listview);
368 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
372 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
375 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
379 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
383 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
387 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
391 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
394 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
395 VFLIST_INFO(vf, click_fd) = NULL;
401 *-----------------------------------------------------------------------------
403 *-----------------------------------------------------------------------------
406 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
412 if (strlen(new) == 0) return FALSE;
414 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
415 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
417 if (strchr(new, G_DIR_SEPARATOR) != NULL)
419 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
420 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
423 else if (isfile(new_path))
425 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
426 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
431 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
432 file_util_rename_simple(fd, new_path, vf->listview);
441 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
449 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
450 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
451 tpath = gtk_tree_model_get_path(store, &iter);
452 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
453 gtk_tree_path_free(tpath);
455 popup_menu_position_clamp(menu, x, y, 0);
458 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
463 if (event->keyval != GDK_Menu) return FALSE;
465 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
471 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
472 gtk_tree_model_get_iter(store, &iter, tpath);
473 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
474 gtk_tree_path_free(tpath);
478 VFLIST_INFO(vf, click_fd) = NULL;
481 vf->popup = vf_pop_menu(vf);
482 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
487 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
493 GtkTreeViewColumn *column;
495 vf->clicked_mark = 0;
497 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
498 &tpath, &column, NULL, NULL))
501 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
503 if (bevent->button == MOUSE_BUTTON_LEFT &&
504 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
507 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
508 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
510 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
512 gtk_tree_model_get_iter(store, &iter, tpath);
513 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
515 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
517 gtk_tree_path_free(tpath);
520 VFLIST_INFO(vf, click_fd) = fd;
522 if (bevent->button == MOUSE_BUTTON_RIGHT)
524 vf->popup = vf_pop_menu(vf);
525 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
526 bevent->button, bevent->time);
530 if (!fd) return FALSE;
532 if (bevent->button == MOUSE_BUTTON_MIDDLE)
534 if (!vflist_row_is_selected(vf, fd))
536 vflist_color_set(vf, fd, TRUE);
542 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
543 !(bevent->state & GDK_SHIFT_MASK ) &&
544 !(bevent->state & GDK_CONTROL_MASK ) &&
545 vflist_row_is_selected(vf, fd))
547 GtkTreeSelection *selection;
549 gtk_widget_grab_focus(widget);
552 /* returning FALSE and further processing of the event is needed for
553 correct operation of the expander, to show the sidecar files.
554 It however resets the selection of multiple files. With this condition
555 it should work for both cases */
556 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
557 return (gtk_tree_selection_count_selected_rows(selection) > 1);
561 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
563 if (vf->layout) layout_image_full_screen_start(vf->layout);
570 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
577 if (bevent->button == MOUSE_BUTTON_MIDDLE)
579 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
582 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
587 if ((bevent->x != 0 || bevent->y != 0) &&
588 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
589 &tpath, NULL, NULL, NULL))
593 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
594 gtk_tree_model_get_iter(store, &iter, tpath);
595 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
596 gtk_tree_path_free(tpath);
599 if (bevent->button == MOUSE_BUTTON_MIDDLE)
601 if (fd && VFLIST_INFO(vf, click_fd) == fd)
603 GtkTreeSelection *selection;
605 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
606 if (vflist_row_is_selected(vf, fd))
608 gtk_tree_selection_unselect_iter(selection, &iter);
612 gtk_tree_selection_select_iter(selection, &iter);
618 if (fd && VFLIST_INFO(vf, click_fd) == fd &&
619 !(bevent->state & GDK_SHIFT_MASK ) &&
620 !(bevent->state & GDK_CONTROL_MASK ) &&
621 vflist_row_is_selected(vf, fd))
623 GtkTreeSelection *selection;
625 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
626 gtk_tree_selection_unselect_all(selection);
627 gtk_tree_selection_select_iter(selection, &iter);
628 vflist_move_cursor(vf, &iter);
629 // return TRUE;// FIXME - expand
635 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
637 FileData *read_ahead_fd = NULL;
642 cur_fd = layout_image_get_fd(vf->layout);
643 if (sel_fd == cur_fd) return; /* no change */
645 row = g_list_index(vf->list, sel_fd);
646 // FIXME sidecar data
648 if (sel_fd && options->image.enable_read_ahead && row >= 0)
650 if (row > g_list_index(vf->list, cur_fd) &&
651 (guint) (row + 1) < vf_count(vf, NULL))
653 read_ahead_fd = vf_index_get_data(vf, row + 1);
657 read_ahead_fd = vf_index_get_data(vf, row - 1);
661 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
664 static gint vflist_select_idle_cb(gpointer data)
670 VFLIST_INFO(vf, select_idle_id) = -1;
676 if (VFLIST_INFO(vf, select_fd))
678 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
679 VFLIST_INFO(vf, select_fd) = NULL;
682 VFLIST_INFO(vf, select_idle_id) = -1;
686 static void vflist_select_idle_cancel(ViewFile *vf)
688 if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
689 VFLIST_INFO(vf, select_idle_id) = -1;
692 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
693 gboolean path_currently_selected, gpointer data)
698 if (!path_currently_selected &&
699 gtk_tree_model_get_iter(store, &iter, tpath))
701 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
705 VFLIST_INFO(vf, select_fd) = NULL;
709 VFLIST_INFO(vf, select_idle_id) == -1)
711 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
718 *-----------------------------------------------------------------------------
720 *-----------------------------------------------------------------------------
724 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
725 gboolean path_currently_selected, gpointer data)
731 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
734 gchar *sidecars = NULL;
735 gchar *name_sidecars;
737 const gchar *time = text_from_time(fd->date);
738 name_sidecars = (gchar *)fd->name;
740 if (fd->sidecar_files)
742 sidecars = file_data_sc_list_to_string(fd);
743 name_sidecars = g_strdup_printf("%s %s", fd->name, sidecars);
745 size = text_from_size(fd->size);
747 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
749 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
750 FILE_COLUMN_VERSION, fd->version,
751 FILE_COLUMN_THUMB, fd->thumb_pixbuf,
752 FILE_COLUMN_MULTILINE, multiline,
753 FILE_COLUMN_NAME, name_sidecars,
754 FILE_COLUMN_SIZE, size,
755 FILE_COLUMN_DATE, time,
756 #define STORE_SET_IS_SLOW 1
757 #if STORE_SET_IS_SLOW
758 /* this is 3x faster on a directory with 20000 files */
759 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
760 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
761 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
762 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
763 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
764 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
765 #if FILEDATA_MARKS_SIZE != 6
766 #error this needs to be updated
769 FILE_COLUMN_COLOR, FALSE, -1);
771 #if !STORE_SET_IS_SLOW
774 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
775 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
782 g_free(name_sidecars);
787 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
792 gint num_ordered = 0;
793 gint num_prepended = 0;
795 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
801 FileData *fd = work->data;
806 FileData *old_fd = NULL;
807 gint old_version = 0;
812 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
813 FILE_COLUMN_POINTER, &old_fd,
814 FILE_COLUMN_VERSION, &old_version,
824 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
826 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
828 if (match == 0) g_warning("multiple fd for the same path");
843 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
848 here should be used gtk_tree_store_append, but this function seems to be O(n)
849 and it seems to be much faster to add new entries to the beginning and reorder later
852 gtk_tree_store_prepend(store, &new, parent_iter);
855 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
856 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
858 if (g_list_find(selected, fd))
860 /* renamed files - the same fd appears at different position - select it again*/
861 GtkTreeSelection *selection;
862 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
863 gtk_tree_selection_select_iter(selection, &new);
870 file_data_unref(old_fd);
871 valid = gtk_tree_store_remove(store, &iter);
875 if (fd->version != old_version)
877 vflist_setup_iter(vf, store, &iter, fd);
878 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
881 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
892 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
893 file_data_unref(old_fd);
895 valid = gtk_tree_store_remove(store, &iter);
898 /* move the prepended entries to the correct position */
902 gint num_total = num_prepended + num_ordered;
903 gint *new_order = g_malloc(num_total * sizeof(gint));
905 for (i = 0; i < num_total; i++)
908 new_order[i] = num_prepended + i;
910 new_order[i] = num_total - 1 - i;
912 gtk_tree_store_reorder(store, parent_iter, new_order);
918 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
921 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
926 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
927 if (!vf->list) return;
933 FileData *fd = work->data;
934 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
939 vf->sort_method = type;
940 vf->sort_ascend = ascend;
942 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
944 new_order = g_malloc(i * sizeof(gint));
950 FileData *fd = work->data;
951 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
956 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
957 gtk_tree_store_reorder(store, NULL, new_order);
960 g_hash_table_destroy(fd_idx_hash);
964 *-----------------------------------------------------------------------------
966 *-----------------------------------------------------------------------------
969 static gint vflist_thumb_next(ViewFile *vf);
971 static void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
976 FileData *fd = work->data;
979 if (fd->thumb_pixbuf) (*done)++;
981 if (fd->sidecar_files)
983 vflist_thumb_progress_count(fd->sidecar_files, count, done);
989 static gdouble vflist_thumb_progress(ViewFile *vf)
994 vflist_thumb_progress_count(vf->list, &count, &done);
996 DEBUG_1("thumb progress: %d of %d", done, count);
997 return (gdouble)done / count;
1001 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
1003 if (vf->func_thumb_status)
1005 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1009 static void vflist_thumb_cleanup(ViewFile *vf)
1011 vflist_thumb_status(vf, 0.0, NULL);
1013 vf->thumbs_running = FALSE;
1015 thumb_loader_free(vf->thumbs_loader);
1016 vf->thumbs_loader = NULL;
1018 vf->thumbs_filedata = NULL;
1021 static void vflist_thumb_stop(ViewFile *vf)
1023 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1026 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1028 GtkTreeStore *store;
1031 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1033 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1034 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1036 vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
1039 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1041 ViewFile *vf = data;
1043 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1045 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1048 while (vflist_thumb_next(vf));
1051 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1053 ViewFile *vf = data;
1055 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1057 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1060 while (vflist_thumb_next(vf));
1063 static gint vflist_thumb_next(ViewFile *vf)
1066 FileData *fd = NULL;
1068 /* first check the visible files */
1070 if (GTK_WIDGET_REALIZED(vf->listview) &&
1071 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1073 GtkTreeModel *store;
1077 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1078 gtk_tree_model_get_iter(store, &iter, tpath);
1079 gtk_tree_path_free(tpath);
1081 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1083 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1084 if (fd->thumb_pixbuf) fd = NULL;
1086 valid = gtk_tree_model_iter_next(store, &iter);
1090 /* then find first undone */
1094 GList *work = vf->list;
1097 FileData *fd_p = work->data;
1098 if (!fd_p->thumb_pixbuf)
1102 GList *work2 = fd_p->sidecar_files;
1104 while (work2 && !fd)
1107 if (!fd_p->thumb_pixbuf) fd = fd_p;
1108 work2 = work2->next;
1118 vflist_thumb_cleanup(vf);
1122 vf->thumbs_filedata = fd;
1124 thumb_loader_free(vf->thumbs_loader);
1126 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1127 thumb_loader_set_callbacks(vf->thumbs_loader,
1128 vflist_thumb_done_cb,
1129 vflist_thumb_error_cb,
1133 if (!thumb_loader_start(vf->thumbs_loader, fd))
1135 /* set icon to unknown, continue */
1136 DEBUG_1("thumb loader start failed %s", fd->path);
1137 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1145 static void vflist_thumb_update(ViewFile *vf)
1147 vflist_thumb_stop(vf);
1148 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1150 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1151 vf->thumbs_running = TRUE;
1153 while (vflist_thumb_next(vf));
1157 *-----------------------------------------------------------------------------
1159 *-----------------------------------------------------------------------------
1162 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1164 return g_list_nth_data(vf->list, row);
1167 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1172 if (!path) return -1;
1177 FileData *fd = work->data;
1178 if (strcmp(path, fd->path) == 0) return p;
1187 guint vflist_count(ViewFile *vf, gint64 *bytes)
1197 FileData *fd = work->data;
1205 return g_list_length(vf->list);
1208 GList *vflist_get_list(ViewFile *vf)
1216 FileData *fd = work->data;
1219 list = g_list_prepend(list, file_data_ref(fd));
1222 return g_list_reverse(list);
1226 *-----------------------------------------------------------------------------
1228 *-----------------------------------------------------------------------------
1231 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1233 GtkTreeModel *store;
1234 GtkTreeSelection *selection;
1239 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1240 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1242 while (!found && work)
1244 GtkTreePath *tpath = work->data;
1248 gtk_tree_model_get_iter(store, &iter, tpath);
1249 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1250 if (fd_n == fd) found = TRUE;
1253 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1259 gint vflist_index_is_selected(ViewFile *vf, gint row)
1263 fd = vf_index_get_data(vf, row);
1264 return vflist_row_is_selected(vf, fd);
1267 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1269 GtkTreeModel *store;
1270 GtkTreeSelection *selection;
1274 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1275 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1285 GtkTreePath *tpath = work->data;
1289 gtk_tree_model_get_iter(store, &iter, tpath);
1290 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1299 count = g_list_length(slist);
1300 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1306 GList *vflist_selection_get_list(ViewFile *vf)
1308 GtkTreeModel *store;
1309 GtkTreeSelection *selection;
1314 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1315 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1319 GtkTreePath *tpath = work->data;
1323 gtk_tree_model_get_iter(store, &iter, tpath);
1324 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1326 list = g_list_prepend(list, file_data_ref(fd));
1330 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1333 return g_list_reverse(list);
1336 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1338 GtkTreeModel *store;
1339 GtkTreeSelection *selection;
1344 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1345 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1349 GtkTreePath *tpath = work->data;
1353 gtk_tree_model_get_iter(store, &iter, tpath);
1354 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1356 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1360 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1363 return g_list_reverse(list);
1366 void vflist_select_all(ViewFile *vf)
1368 GtkTreeSelection *selection;
1370 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1371 gtk_tree_selection_select_all(selection);
1373 VFLIST_INFO(vf, select_fd) = NULL;
1376 void vflist_select_none(ViewFile *vf)
1378 GtkTreeSelection *selection;
1380 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1381 gtk_tree_selection_unselect_all(selection);
1384 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1389 tpath = gtk_tree_model_get_path(store, iter);
1390 result = gtk_tree_path_prev(tpath);
1392 gtk_tree_model_get_iter(store, iter, tpath);
1394 gtk_tree_path_free(tpath);
1399 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1401 if (!gtk_tree_model_get_iter_first(store, iter))
1406 GtkTreeIter next = *iter;
1408 if (gtk_tree_model_iter_next(store, &next))
1417 void vflist_select_invert(ViewFile *vf)
1420 GtkTreeSelection *selection;
1421 GtkTreeModel *store;
1424 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1425 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1427 /* Backward iteration prevents scrolling to the end of the list,
1428 * it scrolls to the first selected row instead. */
1429 valid = tree_model_get_iter_last(store, &iter);
1433 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1436 gtk_tree_selection_unselect_iter(selection, &iter);
1438 gtk_tree_selection_select_iter(selection, &iter);
1440 valid = tree_model_iter_prev(store, &iter);
1444 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1448 if (vflist_find_row(vf, fd, &iter) < 0) return;
1450 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1452 if (!vflist_row_is_selected(vf, fd))
1454 GtkTreeSelection *selection;
1455 GtkTreeModel *store;
1458 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1459 gtk_tree_selection_unselect_all(selection);
1460 gtk_tree_selection_select_iter(selection, &iter);
1461 vflist_move_cursor(vf, &iter);
1463 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1464 tpath = gtk_tree_model_get_path(store, &iter);
1465 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1466 gtk_tree_path_free(tpath);
1470 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1474 if (sel_fd->parent) sel_fd = sel_fd->parent;
1480 FileData *fd = work->data;
1484 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1488 vflist_select_by_fd(vf, fd);
1495 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1497 GtkTreeModel *store;
1499 GtkTreeSelection *selection;
1503 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1505 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1506 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1508 valid = gtk_tree_model_get_iter_first(store, &iter);
1512 gboolean mark_val, selected;
1513 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1515 mark_val = file_data_get_mark(fd, n);
1516 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1520 case MTS_MODE_SET: selected = mark_val;
1522 case MTS_MODE_OR: selected = mark_val | selected;
1524 case MTS_MODE_AND: selected = mark_val & selected;
1526 case MTS_MODE_MINUS: selected = !mark_val & selected;
1531 gtk_tree_selection_select_iter(selection, &iter);
1533 gtk_tree_selection_unselect_iter(selection, &iter);
1535 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1539 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1541 GtkTreeModel *store;
1542 GtkTreeSelection *selection;
1547 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1549 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1550 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1554 GtkTreePath *tpath = work->data;
1558 gtk_tree_model_get_iter(store, &iter, tpath);
1559 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1561 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1565 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1567 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1569 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1573 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1575 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1579 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1584 *-----------------------------------------------------------------------------
1586 *-----------------------------------------------------------------------------
1589 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1591 GtkTreeViewColumn *column;
1592 GtkCellRenderer *cell;
1596 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1597 if (!column) return;
1599 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1601 list = gtk_tree_view_column_get_cell_renderers(column);
1606 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1607 gtk_tree_view_column_set_visible(column, thumb);
1609 multiline = (thumb && options->thumbnails.max_height >= 48);
1611 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1612 if (!column) return;
1613 gtk_tree_view_column_set_visible(column, multiline);
1614 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1616 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1617 if (!column) return;
1618 gtk_tree_view_column_set_visible(column, !multiline);
1619 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1621 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1622 if (!column) return;
1623 gtk_tree_view_column_set_visible(column, !multiline);
1625 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1626 if (!column) return;
1627 gtk_tree_view_column_set_visible(column, !multiline);
1629 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1632 static void vflist_populate_view(ViewFile *vf)
1634 GtkTreeStore *store;
1636 GtkTreeRowReference *visible_row = NULL;
1640 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1641 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1643 vflist_thumb_stop(vf);
1647 vflist_store_clear(vf);
1652 if (GTK_WIDGET_REALIZED(vf->listview) &&
1653 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1655 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1656 gtk_tree_path_free(tpath);
1659 vflist_listview_set_columns(vf->listview, thumbs);
1661 selected = vflist_selection_get_list(vf);
1663 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1665 if (selected && vflist_selection_count(vf, NULL) == 0)
1667 /* all selected files disappeared */
1668 vflist_select_closest(vf, selected->data);
1671 filelist_free(selected);
1675 if (gtk_tree_row_reference_valid(visible_row))
1677 tpath = gtk_tree_row_reference_get_path(visible_row);
1678 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1679 gtk_tree_path_free(tpath);
1681 gtk_tree_row_reference_free(visible_row);
1685 vflist_thumb_update(vf);
1688 gint vflist_refresh(ViewFile *vf)
1693 old_list = vf->list;
1696 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1699 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1701 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1703 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1705 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1706 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1709 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1711 vflist_populate_view(vf);
1713 filelist_free(old_list);
1714 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1721 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1723 #define CELL_HEIGHT_OVERRIDE 512
1725 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1729 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1730 if (spec && G_IS_PARAM_SPEC_INT(spec))
1732 GParamSpecInt *spec_int;
1734 spec_int = G_PARAM_SPEC_INT(spec);
1735 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1739 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1741 static GdkColor color;
1742 static GtkWidget *done = NULL;
1748 style = gtk_widget_get_style(widget);
1749 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1750 shift_color(&color, -1, 0);
1757 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1758 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1760 ViewFile *vf = data;
1763 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1764 g_object_set(G_OBJECT(cell),
1765 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1766 "cell-background-set", set, NULL);
1769 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1771 GtkTreeViewColumn *column;
1772 GtkCellRenderer *renderer;
1774 column = gtk_tree_view_column_new();
1775 gtk_tree_view_column_set_title(column, title);
1776 gtk_tree_view_column_set_min_width(column, 4);
1780 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1781 renderer = gtk_cell_renderer_text_new();
1784 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1786 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1787 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1789 gtk_tree_view_column_set_expand(column, TRUE);
1793 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1794 renderer = gtk_cell_renderer_pixbuf_new();
1795 cell_renderer_height_override(renderer);
1796 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1797 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1800 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1801 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1802 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1804 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1807 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1809 ViewFile *vf = data;
1810 GtkTreeStore *store;
1811 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1817 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1818 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1821 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1823 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1825 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1827 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1828 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1829 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1831 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1832 gtk_tree_path_free(path);
1835 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1837 GtkTreeViewColumn *column;
1838 GtkCellRenderer *renderer;
1839 GtkTreeStore *store;
1842 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1844 renderer = gtk_cell_renderer_toggle_new();
1845 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1847 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1848 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1849 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1851 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1852 gtk_tree_view_column_set_fixed_width(column, 18);
1853 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1856 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1860 *-----------------------------------------------------------------------------
1862 *-----------------------------------------------------------------------------
1865 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1867 if (!dir_fd) return FALSE;
1868 if (vf->dir_fd == dir_fd) return TRUE;
1870 file_data_unref(vf->dir_fd);
1871 vf->dir_fd = file_data_ref(dir_fd);
1873 /* force complete reload */
1874 vflist_store_clear(vf);
1876 filelist_free(vf->list);
1879 return vf_refresh(vf);
1882 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1884 ViewFile *vf = data;
1886 file_data_unregister_notify_func(vf_notify_cb, vf);
1888 vflist_select_idle_cancel(vf);
1889 vf_refresh_idle_cancel(vf);
1890 vflist_thumb_stop(vf);
1892 filelist_free(vf->list);
1895 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1897 GtkTreeStore *store;
1898 GtkTreeSelection *selection;
1900 GType flist_types[FILE_COLUMN_COUNT];
1904 vf->info = g_new0(ViewFileInfoList, 1);
1906 VFLIST_INFO(vf, click_fd) = NULL;
1907 VFLIST_INFO(vf, select_fd) = NULL;
1908 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1910 VFLIST_INFO(vf, select_idle_id) = -1;
1912 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1913 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1914 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1915 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1916 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1917 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1918 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1919 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1920 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1921 flist_types[i] = G_TYPE_BOOLEAN;
1923 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1925 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1926 g_object_unref(store);
1928 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1929 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1930 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1932 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1933 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1937 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1939 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1940 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1944 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1945 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1948 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1949 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1952 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1953 g_assert(column == FILE_VIEW_COLUMN_NAME);
1956 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1957 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1960 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1961 g_assert(column == FILE_VIEW_COLUMN_DATE);
1964 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1968 void vflist_thumb_set(ViewFile *vf, gint enable)
1970 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1972 VFLIST_INFO(vf, thumbs_enabled) = enable;
1973 if (vf->layout) vf_refresh(vf);
1976 void vflist_marks_set(ViewFile *vf, gint enable)
1978 GList *columns, *work;
1980 if (vf->marks_enabled == enable) return;
1982 vf->marks_enabled = enable;
1984 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1989 GtkTreeViewColumn *column = work->data;
1990 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1993 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1994 gtk_tree_view_column_set_visible(column, enable);
1997 g_list_free(columns);