4 * Copyright (C) 2008 - 2009 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"
17 #include "cache_maint.h"
22 #include "layout_image.h"
27 #include "ui_fileops.h"
29 #include "ui_tree_edit.h"
30 #include "uri_utils.h"
31 #include "view_file.h"
33 #include <gdk/gdkkeysyms.h> /* for keyboard values */
35 /* Index to tree store */
37 FILE_COLUMN_POINTER = 0,
41 FILE_COLUMN_MULTILINE,
46 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
51 /* Index to tree view */
53 FILE_VIEW_COLUMN_MARKS = 0,
54 FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
55 FILE_VIEW_COLUMN_THUMB,
56 FILE_VIEW_COLUMN_MULTILINE,
57 FILE_VIEW_COLUMN_NAME,
58 FILE_VIEW_COLUMN_SIZE,
59 FILE_VIEW_COLUMN_DATE,
60 FILE_VIEW_COLUMN_COUNT
65 static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd);
66 static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
67 static void vflist_populate_view(ViewFile *vf);
71 *-----------------------------------------------------------------------------
73 *-----------------------------------------------------------------------------
80 } ViewFileFindRowData;
82 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
84 ViewFileFindRowData *find = data;
86 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
97 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
100 ViewFileFindRowData data = {fd, iter, FALSE, 0};
102 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
103 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
113 static FileData *vflist_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
116 GtkTreeViewColumn *column;
118 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
119 &tpath, &column, NULL, NULL))
125 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
126 gtk_tree_model_get_iter(store, &row, tpath);
127 gtk_tree_path_free(tpath);
128 gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &fd, -1);
137 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
142 FileData *fd_p = work->data;
143 if (fd == fd_p) return i;
147 GList *work2 = fd_p->sidecar_files;
151 if (fd == fd_p) return i;
161 static gint vflist_sidecar_list_count(GList *work)
166 FileData *fd = work->data;
169 GList *work2 = fd->sidecar_files;
181 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
184 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
189 static void vflist_store_clear(ViewFile *vf)
192 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
193 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
194 gtk_tree_store_clear(GTK_TREE_STORE(store));
197 void vflist_color_set(ViewFile *vf, FileData *fd, gboolean color_set)
202 if (vflist_find_row(vf, fd, &iter) < 0) return;
203 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
204 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
207 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
212 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
214 tpath = gtk_tree_model_get_path(store, iter);
215 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
216 gtk_tree_path_free(tpath);
220 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
222 GList *columns, *work;
225 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
229 GtkTreeViewColumn *column = work->data;
230 if (store_idx == GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx")))
236 g_list_free(columns);
242 *-----------------------------------------------------------------------------
244 *-----------------------------------------------------------------------------
247 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
248 GtkSelectionData *selection_data, guint info,
249 guint time, gpointer data)
253 gchar *uri_text = NULL;
256 if (!VFLIST(vf)->click_fd) return;
258 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
260 list = vf_selection_get_list(vf);
264 list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
269 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
272 DEBUG_1("%s", uri_text);
274 gtk_selection_data_set(selection_data, selection_data->target,
275 8, (guchar *)uri_text, total);
279 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
283 vflist_color_set(vf, VFLIST(vf)->click_fd, TRUE);
285 if (VFLIST(vf)->thumbs_enabled &&
286 VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
290 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
291 items = vf_selection_count(vf, NULL);
295 dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
299 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
303 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
305 if (context->action == GDK_ACTION_MOVE)
311 static void vflist_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
312 int x, int y, GtkSelectionData *selection,
313 guint info, guint time, gpointer data)
317 if (info == TARGET_TEXT_PLAIN) {
318 FileData *fd = vflist_find_data_by_coord(vf, x, y, NULL);
321 /* Add keywords to file */
322 gchar *str = g_strndup((gchar *)selection->data, selection->length);
323 GList *kw_list = string_to_keywords_list(str);
325 metadata_append_list(fd, KEYWORD_KEY, kw_list);
326 string_list_free(kw_list);
329 file notification should handle this automatically
330 if (vf->layout && vf->layout->bar_info) {
331 bar_set_fd(vf->layout->bar_info, fd);
338 void vflist_dnd_init(ViewFile *vf)
340 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
341 dnd_file_drag_types, dnd_file_drag_types_count,
342 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
343 gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
344 dnd_file_drag_types, dnd_file_drag_types_count,
345 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
347 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
348 G_CALLBACK(vflist_dnd_get), vf);
349 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
350 G_CALLBACK(vflist_dnd_begin), vf);
351 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
352 G_CALLBACK(vflist_dnd_end), vf);
353 g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
354 G_CALLBACK(vflist_drag_data_received), vf);
358 *-----------------------------------------------------------------------------
360 *-----------------------------------------------------------------------------
363 GList *vflist_pop_menu_file_list(ViewFile *vf)
366 if (!VFLIST(vf)->click_fd) return NULL;
368 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
370 return vf_selection_get_list(vf);
373 list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
375 if (VFLIST(vf)->click_fd->sidecar_files)
377 /* check if the row is expanded */
381 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
382 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
386 tpath = gtk_tree_model_get_path(store, &iter);
387 if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
389 /* unexpanded - add whole group */
390 GList *work = VFLIST(vf)->click_fd->sidecar_files;
393 FileData *sfd = work->data;
394 list = g_list_prepend(list, file_data_ref(sfd));
398 gtk_tree_path_free(tpath);
400 list = g_list_reverse(list);
406 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
410 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
414 list = vf_selection_get_list(vf);
415 view_window_new_from_list(list);
420 view_window_new(VFLIST(vf)->click_fd);
424 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
429 list = vf_pop_menu_file_list(vf);
430 if (options->file_ops.enable_in_place_rename &&
431 list && !list->next && VFLIST(vf)->click_fd)
438 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
439 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
443 tpath = gtk_tree_model_get_path(store, &iter);
444 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
445 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST(vf)->click_fd->name,
446 vflist_row_rename_cb, vf);
447 gtk_tree_path_free(tpath);
452 file_util_rename(NULL, list, vf->listview);
455 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
459 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
462 layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
466 vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
470 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
474 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
478 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
481 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
482 VFLIST(vf)->click_fd = NULL;
488 *-----------------------------------------------------------------------------
490 *-----------------------------------------------------------------------------
493 static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
498 if (!new || !new[0]) return FALSE;
500 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
502 if (strchr(new, G_DIR_SEPARATOR) != NULL)
504 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
505 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
510 gchar *old_path = g_build_filename(vf->dir_fd->path, old, NULL);
511 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
512 file_util_rename_simple(fd, new_path, vf->listview);
522 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
530 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
531 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
532 tpath = gtk_tree_model_get_path(store, &iter);
533 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
534 gtk_tree_path_free(tpath);
536 popup_menu_position_clamp(menu, x, y, 0);
539 gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
544 if (event->keyval != GDK_Menu) return FALSE;
546 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
552 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
553 gtk_tree_model_get_iter(store, &iter, tpath);
554 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
555 gtk_tree_path_free(tpath);
559 VFLIST(vf)->click_fd = NULL;
562 vf->popup = vf_pop_menu(vf);
563 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
568 gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
574 GtkTreeViewColumn *column;
576 vf->clicked_mark = 0;
578 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
579 &tpath, &column, NULL, NULL))
582 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
584 if (bevent->button == MOUSE_BUTTON_LEFT &&
585 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
588 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
589 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
591 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
593 gtk_tree_model_get_iter(store, &iter, tpath);
594 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
596 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
598 gtk_tree_path_free(tpath);
601 VFLIST(vf)->click_fd = fd;
603 if (bevent->button == MOUSE_BUTTON_RIGHT)
605 vf->popup = vf_pop_menu(vf);
606 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
607 bevent->button, bevent->time);
611 if (!fd) return FALSE;
613 if (bevent->button == MOUSE_BUTTON_MIDDLE)
615 if (!vflist_row_is_selected(vf, fd))
617 vflist_color_set(vf, fd, TRUE);
623 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
624 !(bevent->state & GDK_SHIFT_MASK ) &&
625 !(bevent->state & GDK_CONTROL_MASK ) &&
626 vflist_row_is_selected(vf, fd))
628 GtkTreeSelection *selection;
630 gtk_widget_grab_focus(widget);
633 /* returning FALSE and further processing of the event is needed for
634 correct operation of the expander, to show the sidecar files.
635 It however resets the selection of multiple files. With this condition
636 it should work for both cases */
637 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
638 return (gtk_tree_selection_count_selected_rows(selection) > 1);
642 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
644 if (vf->layout) layout_image_full_screen_start(vf->layout);
651 gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
658 if (bevent->button == MOUSE_BUTTON_MIDDLE)
660 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
663 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
668 if ((bevent->x != 0 || bevent->y != 0) &&
669 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
670 &tpath, NULL, NULL, NULL))
674 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
675 gtk_tree_model_get_iter(store, &iter, tpath);
676 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
677 gtk_tree_path_free(tpath);
680 if (bevent->button == MOUSE_BUTTON_MIDDLE)
682 if (fd && VFLIST(vf)->click_fd == fd)
684 GtkTreeSelection *selection;
686 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
687 if (vflist_row_is_selected(vf, fd))
689 gtk_tree_selection_unselect_iter(selection, &iter);
693 gtk_tree_selection_select_iter(selection, &iter);
699 if (fd && VFLIST(vf)->click_fd == fd &&
700 !(bevent->state & GDK_SHIFT_MASK ) &&
701 !(bevent->state & GDK_CONTROL_MASK ) &&
702 vflist_row_is_selected(vf, fd))
704 GtkTreeSelection *selection;
706 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
707 gtk_tree_selection_unselect_all(selection);
708 gtk_tree_selection_select_iter(selection, &iter);
709 vflist_move_cursor(vf, &iter);
710 // return TRUE;// FIXME - expand
716 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
718 FileData *read_ahead_fd = NULL;
724 cur_fd = layout_image_get_fd(vf->layout);
725 if (sel_fd == cur_fd) return; /* no change */
727 row = g_list_index(vf->list, sel_fd);
728 // FIXME sidecar data
730 if (sel_fd && options->image.enable_read_ahead && row >= 0)
732 if (row > g_list_index(vf->list, cur_fd) &&
733 (guint) (row + 1) < vf_count(vf, NULL))
735 read_ahead_fd = vf_index_get_data(vf, row + 1);
739 read_ahead_fd = vf_index_get_data(vf, row - 1);
743 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
746 static gboolean vflist_select_idle_cb(gpointer data)
752 VFLIST(vf)->select_idle_id = 0;
758 if (VFLIST(vf)->select_fd)
760 vflist_select_image(vf, VFLIST(vf)->select_fd);
761 VFLIST(vf)->select_fd = NULL;
764 VFLIST(vf)->select_idle_id = 0;
768 static void vflist_select_idle_cancel(ViewFile *vf)
770 if (VFLIST(vf)->select_idle_id)
772 g_source_remove(VFLIST(vf)->select_idle_id);
773 VFLIST(vf)->select_idle_id = 0;
777 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
778 gboolean path_currently_selected, gpointer data)
783 if (!path_currently_selected &&
784 gtk_tree_model_get_iter(store, &iter, tpath))
786 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
790 VFLIST(vf)->select_fd = NULL;
794 !VFLIST(vf)->select_idle_id)
796 VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
803 *-----------------------------------------------------------------------------
805 *-----------------------------------------------------------------------------
809 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
810 gboolean path_currently_selected, gpointer data)
816 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
819 gchar *sidecars = NULL;
820 gchar *name_sidecars;
822 const gchar *time = text_from_time(fd->date);
823 gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
826 if (fd->sidecar_files)
828 sidecars = file_data_sc_list_to_string(fd);
829 name_sidecars = g_strdup_printf("%s%s %s", link, fd->name, sidecars);
833 gchar *disabled_grouping = fd->disable_grouping ? _(" [NO GROUPING]") : "";
834 name_sidecars = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping);
836 size = text_from_size(fd->size);
838 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
840 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
841 FILE_COLUMN_VERSION, fd->version,
842 FILE_COLUMN_THUMB, fd->thumb_pixbuf,
843 FILE_COLUMN_MULTILINE, multiline,
844 FILE_COLUMN_NAME, name_sidecars,
845 FILE_COLUMN_SIZE, size,
846 FILE_COLUMN_DATE, time,
847 #define STORE_SET_IS_SLOW 1
848 #if STORE_SET_IS_SLOW
849 /* this is 3x faster on a directory with 20000 files */
850 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
851 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
852 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
853 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
854 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
855 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
856 #if FILEDATA_MARKS_SIZE != 6
857 #error this needs to be updated
860 FILE_COLUMN_COLOR, FALSE, -1);
862 #if !STORE_SET_IS_SLOW
865 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
866 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
871 g_free(name_sidecars);
875 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
880 gint num_ordered = 0;
881 gint num_prepended = 0;
883 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
889 FileData *fd = work->data;
890 gboolean done = FALSE;
894 FileData *old_fd = NULL;
895 gint old_version = 0;
900 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
901 FILE_COLUMN_POINTER, &old_fd,
902 FILE_COLUMN_VERSION, &old_version,
912 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
914 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
916 if (match == 0) g_warning("multiple fd for the same path");
931 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
936 here should be used gtk_tree_store_append, but this function seems to be O(n)
937 and it seems to be much faster to add new entries to the beginning and reorder later
940 gtk_tree_store_prepend(store, &new, parent_iter);
943 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
944 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
946 if (g_list_find(selected, fd))
948 /* renamed files - the same fd appears at different position - select it again*/
949 GtkTreeSelection *selection;
950 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
951 gtk_tree_selection_select_iter(selection, &new);
958 file_data_unref(old_fd);
959 valid = gtk_tree_store_remove(store, &iter);
963 if (fd->version != old_version)
965 vflist_setup_iter(vf, store, &iter, fd);
966 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
969 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
980 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
981 file_data_unref(old_fd);
983 valid = gtk_tree_store_remove(store, &iter);
986 /* move the prepended entries to the correct position */
990 gint num_total = num_prepended + num_ordered;
991 gint *new_order = g_malloc(num_total * sizeof(gint));
993 for (i = 0; i < num_total; i++)
996 new_order[i] = num_prepended + i;
998 new_order[i] = num_total - 1 - i;
1000 gtk_tree_store_reorder(store, parent_iter, new_order);
1006 void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend)
1009 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
1011 GtkTreeStore *store;
1014 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
1015 if (!vf->list) return;
1021 FileData *fd = work->data;
1022 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
1027 vf->sort_method = type;
1028 vf->sort_ascend = ascend;
1030 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1032 new_order = g_malloc(i * sizeof(gint));
1038 FileData *fd = work->data;
1039 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
1044 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1045 gtk_tree_store_reorder(store, NULL, new_order);
1048 g_hash_table_destroy(fd_idx_hash);
1052 *-----------------------------------------------------------------------------
1054 *-----------------------------------------------------------------------------
1058 void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
1063 FileData *fd = work->data;
1066 if (fd->thumb_pixbuf) (*done)++;
1068 if (fd->sidecar_files)
1070 vflist_thumb_progress_count(fd->sidecar_files, count, done);
1076 void vflist_set_thumb_fd(ViewFile *vf, FileData *fd)
1078 GtkTreeStore *store;
1081 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1083 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1084 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1087 FileData *vflist_thumb_next_fd(ViewFile *vf)
1090 FileData *fd = NULL;
1092 /* first check the visible files */
1094 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1096 GtkTreeModel *store;
1098 gboolean valid = TRUE;
1100 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1101 gtk_tree_model_get_iter(store, &iter, tpath);
1102 gtk_tree_path_free(tpath);
1104 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1108 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &nfd, -1);
1110 if (!nfd->thumb_pixbuf) fd = nfd;
1112 valid = gtk_tree_model_iter_next(store, &iter);
1116 /* then find first undone */
1120 GList *work = vf->list;
1123 FileData *fd_p = work->data;
1124 if (!fd_p->thumb_pixbuf)
1128 GList *work2 = fd_p->sidecar_files;
1130 while (work2 && !fd)
1133 if (!fd_p->thumb_pixbuf) fd = fd_p;
1134 work2 = work2->next;
1145 void vflist_thumb_reset_all(ViewFile *vf)
1147 GList *work = vf->list;
1150 FileData *fd = work->data;
1151 if (fd->thumb_pixbuf)
1153 g_object_unref(fd->thumb_pixbuf);
1154 fd->thumb_pixbuf = NULL;
1161 *-----------------------------------------------------------------------------
1163 *-----------------------------------------------------------------------------
1166 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1168 return g_list_nth_data(vf->list, row);
1171 gint vflist_index_by_fd(ViewFile *vf, FileData *fd)
1174 GList *work, *work2;
1179 FileData *list_fd = work->data;
1180 if (list_fd == fd) return p;
1182 work2 = list_fd->sidecar_files;
1185 /* FIXME: return the same index also for sidecars
1186 it is sufficient for next/prev navigation but it should be rewritten
1187 without using indexes at all
1189 FileData *sidecar_fd = work2->data;
1190 if (sidecar_fd == fd) return p;
1191 work2 = work2->next;
1201 guint vflist_count(ViewFile *vf, gint64 *bytes)
1211 FileData *fd = work->data;
1219 return g_list_length(vf->list);
1222 GList *vflist_get_list(ViewFile *vf)
1230 FileData *fd = work->data;
1233 list = g_list_prepend(list, file_data_ref(fd));
1236 return g_list_reverse(list);
1240 *-----------------------------------------------------------------------------
1242 *-----------------------------------------------------------------------------
1245 static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd)
1247 GtkTreeModel *store;
1248 GtkTreeSelection *selection;
1251 gboolean found = FALSE;
1253 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1254 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1256 while (!found && work)
1258 GtkTreePath *tpath = work->data;
1262 gtk_tree_model_get_iter(store, &iter, tpath);
1263 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1264 if (fd_n == fd) found = TRUE;
1267 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1273 gboolean vflist_index_is_selected(ViewFile *vf, gint row)
1277 fd = vf_index_get_data(vf, row);
1278 return vflist_row_is_selected(vf, fd);
1281 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1283 GtkTreeModel *store;
1284 GtkTreeSelection *selection;
1288 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1289 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1299 GtkTreePath *tpath = work->data;
1303 gtk_tree_model_get_iter(store, &iter, tpath);
1304 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1313 count = g_list_length(slist);
1314 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1320 GList *vflist_selection_get_list(ViewFile *vf)
1322 GtkTreeModel *store;
1323 GtkTreeSelection *selection;
1328 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1329 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1333 GtkTreePath *tpath = work->data;
1337 gtk_tree_model_get_iter(store, &iter, tpath);
1338 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1340 list = g_list_prepend(list, file_data_ref(fd));
1342 if (!fd->parent && !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
1344 /* unexpanded - add whole group */
1345 GList *work2 = fd->sidecar_files;
1348 FileData *sfd = work2->data;
1349 list = g_list_prepend(list, file_data_ref(sfd));
1350 work2 = work2->next;
1356 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1359 return g_list_reverse(list);
1362 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1364 GtkTreeModel *store;
1365 GtkTreeSelection *selection;
1370 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1371 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1375 GtkTreePath *tpath = work->data;
1379 gtk_tree_model_get_iter(store, &iter, tpath);
1380 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1382 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1386 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1389 return g_list_reverse(list);
1392 void vflist_select_all(ViewFile *vf)
1394 GtkTreeSelection *selection;
1396 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1397 gtk_tree_selection_select_all(selection);
1399 VFLIST(vf)->select_fd = NULL;
1402 void vflist_select_none(ViewFile *vf)
1404 GtkTreeSelection *selection;
1406 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1407 gtk_tree_selection_unselect_all(selection);
1410 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1415 tpath = gtk_tree_model_get_path(store, iter);
1416 result = gtk_tree_path_prev(tpath);
1418 gtk_tree_model_get_iter(store, iter, tpath);
1420 gtk_tree_path_free(tpath);
1425 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1427 if (!gtk_tree_model_get_iter_first(store, iter))
1432 GtkTreeIter next = *iter;
1434 if (gtk_tree_model_iter_next(store, &next))
1443 void vflist_select_invert(ViewFile *vf)
1446 GtkTreeSelection *selection;
1447 GtkTreeModel *store;
1450 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1451 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1453 /* Backward iteration prevents scrolling to the end of the list,
1454 * it scrolls to the first selected row instead. */
1455 valid = tree_model_get_iter_last(store, &iter);
1459 gboolean selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1462 gtk_tree_selection_unselect_iter(selection, &iter);
1464 gtk_tree_selection_select_iter(selection, &iter);
1466 valid = tree_model_iter_prev(store, &iter);
1470 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1474 if (vflist_find_row(vf, fd, &iter) < 0) return;
1476 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1478 if (!vflist_row_is_selected(vf, fd))
1480 GtkTreeSelection *selection;
1481 GtkTreeModel *store;
1484 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1485 gtk_tree_selection_unselect_all(selection);
1486 gtk_tree_selection_select_iter(selection, &iter);
1487 vflist_move_cursor(vf, &iter);
1489 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1490 tpath = gtk_tree_model_get_path(store, &iter);
1491 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1492 gtk_tree_path_free(tpath);
1496 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1499 FileData *fd = NULL;
1501 if (sel_fd->parent) sel_fd = sel_fd->parent;
1510 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1512 if (match >= 0) break;
1515 if (fd) vflist_select_by_fd(vf, fd);
1519 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1521 GtkTreeModel *store;
1523 GtkTreeSelection *selection;
1527 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1529 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1530 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1532 valid = gtk_tree_model_get_iter_first(store, &iter);
1536 gboolean mark_val, selected;
1537 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1539 mark_val = file_data_get_mark(fd, n);
1540 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1544 case MTS_MODE_SET: selected = mark_val;
1546 case MTS_MODE_OR: selected = mark_val | selected;
1548 case MTS_MODE_AND: selected = mark_val & selected;
1550 case MTS_MODE_MINUS: selected = !mark_val & selected;
1555 gtk_tree_selection_select_iter(selection, &iter);
1557 gtk_tree_selection_unselect_iter(selection, &iter);
1559 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1563 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1565 GtkTreeModel *store;
1566 GtkTreeSelection *selection;
1571 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1573 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1574 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1578 GtkTreePath *tpath = work->data;
1582 gtk_tree_model_get_iter(store, &iter, tpath);
1583 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1585 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1589 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1591 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1593 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1597 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1599 vf_refresh_idle(vf);
1603 /* mark functions can have various side effects - update all columns to be sure */
1604 vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
1608 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1612 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1617 *-----------------------------------------------------------------------------
1619 *-----------------------------------------------------------------------------
1622 static void vflist_listview_set_columns(GtkWidget *listview, gboolean thumb)
1624 GtkTreeViewColumn *column;
1625 GtkCellRenderer *cell;
1629 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1630 if (!column) return;
1632 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1634 list = gtk_tree_view_column_get_cell_renderers(column);
1639 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1640 gtk_tree_view_column_set_visible(column, thumb);
1642 multiline = (thumb && options->thumbnails.max_height >= 48);
1644 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1645 if (!column) return;
1646 gtk_tree_view_column_set_visible(column, multiline);
1647 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1649 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1650 if (!column) return;
1651 gtk_tree_view_column_set_visible(column, !multiline);
1652 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1654 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1655 if (!column) return;
1656 gtk_tree_view_column_set_visible(column, !multiline);
1658 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1659 if (!column) return;
1660 gtk_tree_view_column_set_visible(column, !multiline);
1662 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1665 static void vflist_populate_view(ViewFile *vf)
1667 GtkTreeStore *store;
1668 gboolean thumbs_enabled;
1671 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1672 thumbs_enabled = VFLIST(vf)->thumbs_enabled;
1678 vflist_store_clear(vf);
1683 vflist_listview_set_columns(vf->listview, thumbs_enabled);
1685 selected = vflist_selection_get_list(vf);
1687 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1689 if (selected && vflist_selection_count(vf, NULL) == 0)
1691 /* all selected files disappeared */
1692 vflist_select_closest(vf, selected->data);
1695 filelist_free(selected);
1698 vf_thumb_update(vf);
1701 gboolean vflist_refresh(ViewFile *vf)
1704 gboolean ret = TRUE;
1706 old_list = vf->list;
1709 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1712 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1714 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1715 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1716 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1718 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1719 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1722 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1724 vflist_populate_view(vf);
1726 filelist_free(old_list);
1727 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1734 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1736 #define CELL_HEIGHT_OVERRIDE 512
1738 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1742 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1743 if (spec && G_IS_PARAM_SPEC_INT(spec))
1745 GParamSpecInt *spec_int;
1747 spec_int = G_PARAM_SPEC_INT(spec);
1748 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1752 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1754 static GdkColor color;
1755 static GtkWidget *done = NULL;
1761 style = gtk_widget_get_style(widget);
1762 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1763 shift_color(&color, -1, 0);
1770 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1771 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1773 ViewFile *vf = data;
1776 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1777 g_object_set(G_OBJECT(cell),
1778 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1779 "cell-background-set", set, NULL);
1782 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gboolean image, gboolean right_justify, gboolean expand)
1784 GtkTreeViewColumn *column;
1785 GtkCellRenderer *renderer;
1787 column = gtk_tree_view_column_new();
1788 gtk_tree_view_column_set_title(column, title);
1789 gtk_tree_view_column_set_min_width(column, 4);
1793 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1794 renderer = gtk_cell_renderer_text_new();
1797 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1799 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1800 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1802 gtk_tree_view_column_set_expand(column, TRUE);
1806 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1807 renderer = gtk_cell_renderer_pixbuf_new();
1808 cell_renderer_height_override(renderer);
1809 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1810 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1813 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1814 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1815 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1817 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1820 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1822 ViewFile *vf = data;
1823 GtkTreeStore *store;
1824 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1830 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1831 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1834 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1836 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1838 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &marked, -1);
1840 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1841 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, marked);
1842 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1844 vf_refresh_idle(vf);
1848 /* mark functions can have various side effects - update all columns to be sure */
1849 vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
1851 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1853 gtk_tree_path_free(path);
1856 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1858 GtkTreeViewColumn *column;
1859 GtkCellRenderer *renderer;
1860 GtkTreeStore *store;
1863 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1865 renderer = gtk_cell_renderer_toggle_new();
1866 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1868 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1869 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1870 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1872 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1873 gtk_tree_view_column_set_fixed_width(column, 22);
1874 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1877 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1881 *-----------------------------------------------------------------------------
1883 *-----------------------------------------------------------------------------
1886 gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1888 if (!dir_fd) return FALSE;
1889 if (vf->dir_fd == dir_fd) return TRUE;
1891 file_data_unref(vf->dir_fd);
1892 vf->dir_fd = file_data_ref(dir_fd);
1894 /* force complete reload */
1895 vflist_store_clear(vf);
1897 filelist_free(vf->list);
1900 return vf_refresh(vf);
1903 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1905 ViewFile *vf = data;
1907 file_data_unregister_notify_func(vf_notify_cb, vf);
1909 vflist_select_idle_cancel(vf);
1910 vf_refresh_idle_cancel(vf);
1913 filelist_free(vf->list);
1916 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1918 GtkTreeStore *store;
1919 GtkTreeSelection *selection;
1920 GType flist_types[FILE_COLUMN_COUNT];
1924 vf->info = g_new0(ViewFileInfoList, 1);
1926 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1927 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1928 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1929 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1930 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1931 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1932 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1933 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1934 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1935 flist_types[i] = G_TYPE_BOOLEAN;
1937 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1939 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1940 g_object_unref(store);
1942 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1943 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1944 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1946 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1947 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1951 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1953 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1954 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1958 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1959 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1962 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1963 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1966 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1967 g_assert(column == FILE_VIEW_COLUMN_NAME);
1970 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1971 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1974 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1975 g_assert(column == FILE_VIEW_COLUMN_DATE);
1978 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1982 void vflist_thumb_set(ViewFile *vf, gboolean enable)
1984 if (VFLIST(vf)->thumbs_enabled == enable) return;
1986 VFLIST(vf)->thumbs_enabled = enable;
1987 if (vf->layout) vf_refresh(vf);
1990 void vflist_marks_set(ViewFile *vf, gboolean enable)
1992 GList *columns, *work;
1994 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1999 GtkTreeViewColumn *column = work->data;
2000 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
2003 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
2004 gtk_tree_view_column_set_visible(column, enable);
2007 g_list_free(columns);
2011 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */