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)
365 if (!VFLIST(vf)->click_fd) return NULL;
367 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
369 return vf_selection_get_list(vf);
372 return g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
375 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
379 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
383 list = vf_selection_get_list(vf);
384 view_window_new_from_list(list);
389 view_window_new(VFLIST(vf)->click_fd);
393 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
398 list = vf_pop_menu_file_list(vf);
399 if (options->file_ops.enable_in_place_rename &&
400 list && !list->next && VFLIST(vf)->click_fd)
407 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
408 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
412 tpath = gtk_tree_model_get_path(store, &iter);
413 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
414 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST(vf)->click_fd->name,
415 vflist_row_rename_cb, vf);
416 gtk_tree_path_free(tpath);
421 file_util_rename(NULL, list, vf->listview);
424 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
428 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
431 layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
435 vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
439 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
443 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
447 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
450 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
451 VFLIST(vf)->click_fd = NULL;
457 *-----------------------------------------------------------------------------
459 *-----------------------------------------------------------------------------
462 static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
467 if (!new || !new[0]) return FALSE;
469 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
471 if (strchr(new, G_DIR_SEPARATOR) != NULL)
473 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
474 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
479 gchar *old_path = g_build_filename(vf->dir_fd->path, old, NULL);
480 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
481 file_util_rename_simple(fd, new_path, vf->listview);
491 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
499 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
500 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
501 tpath = gtk_tree_model_get_path(store, &iter);
502 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
503 gtk_tree_path_free(tpath);
505 popup_menu_position_clamp(menu, x, y, 0);
508 gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
513 if (event->keyval != GDK_Menu) return FALSE;
515 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
521 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
522 gtk_tree_model_get_iter(store, &iter, tpath);
523 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
524 gtk_tree_path_free(tpath);
528 VFLIST(vf)->click_fd = NULL;
531 vf->popup = vf_pop_menu(vf);
532 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
537 gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
543 GtkTreeViewColumn *column;
545 vf->clicked_mark = 0;
547 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
548 &tpath, &column, NULL, NULL))
551 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
553 if (bevent->button == MOUSE_BUTTON_LEFT &&
554 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
557 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
558 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
560 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
562 gtk_tree_model_get_iter(store, &iter, tpath);
563 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
565 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
567 gtk_tree_path_free(tpath);
570 VFLIST(vf)->click_fd = fd;
572 if (bevent->button == MOUSE_BUTTON_RIGHT)
574 vf->popup = vf_pop_menu(vf);
575 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
576 bevent->button, bevent->time);
580 if (!fd) return FALSE;
582 if (bevent->button == MOUSE_BUTTON_MIDDLE)
584 if (!vflist_row_is_selected(vf, fd))
586 vflist_color_set(vf, fd, TRUE);
592 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
593 !(bevent->state & GDK_SHIFT_MASK ) &&
594 !(bevent->state & GDK_CONTROL_MASK ) &&
595 vflist_row_is_selected(vf, fd))
597 GtkTreeSelection *selection;
599 gtk_widget_grab_focus(widget);
602 /* returning FALSE and further processing of the event is needed for
603 correct operation of the expander, to show the sidecar files.
604 It however resets the selection of multiple files. With this condition
605 it should work for both cases */
606 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
607 return (gtk_tree_selection_count_selected_rows(selection) > 1);
611 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
613 if (vf->layout) layout_image_full_screen_start(vf->layout);
620 gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
627 if (bevent->button == MOUSE_BUTTON_MIDDLE)
629 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
632 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
637 if ((bevent->x != 0 || bevent->y != 0) &&
638 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
639 &tpath, NULL, NULL, NULL))
643 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
644 gtk_tree_model_get_iter(store, &iter, tpath);
645 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
646 gtk_tree_path_free(tpath);
649 if (bevent->button == MOUSE_BUTTON_MIDDLE)
651 if (fd && VFLIST(vf)->click_fd == fd)
653 GtkTreeSelection *selection;
655 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
656 if (vflist_row_is_selected(vf, fd))
658 gtk_tree_selection_unselect_iter(selection, &iter);
662 gtk_tree_selection_select_iter(selection, &iter);
668 if (fd && VFLIST(vf)->click_fd == fd &&
669 !(bevent->state & GDK_SHIFT_MASK ) &&
670 !(bevent->state & GDK_CONTROL_MASK ) &&
671 vflist_row_is_selected(vf, fd))
673 GtkTreeSelection *selection;
675 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
676 gtk_tree_selection_unselect_all(selection);
677 gtk_tree_selection_select_iter(selection, &iter);
678 vflist_move_cursor(vf, &iter);
679 // return TRUE;// FIXME - expand
685 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
687 FileData *read_ahead_fd = NULL;
693 cur_fd = layout_image_get_fd(vf->layout);
694 if (sel_fd == cur_fd) return; /* no change */
696 row = g_list_index(vf->list, sel_fd);
697 // FIXME sidecar data
699 if (sel_fd && options->image.enable_read_ahead && row >= 0)
701 if (row > g_list_index(vf->list, cur_fd) &&
702 (guint) (row + 1) < vf_count(vf, NULL))
704 read_ahead_fd = vf_index_get_data(vf, row + 1);
708 read_ahead_fd = vf_index_get_data(vf, row - 1);
712 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
715 static gboolean vflist_select_idle_cb(gpointer data)
721 VFLIST(vf)->select_idle_id = 0;
727 if (VFLIST(vf)->select_fd)
729 vflist_select_image(vf, VFLIST(vf)->select_fd);
730 VFLIST(vf)->select_fd = NULL;
733 VFLIST(vf)->select_idle_id = 0;
737 static void vflist_select_idle_cancel(ViewFile *vf)
739 if (VFLIST(vf)->select_idle_id)
741 g_source_remove(VFLIST(vf)->select_idle_id);
742 VFLIST(vf)->select_idle_id = 0;
746 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
747 gboolean path_currently_selected, gpointer data)
752 if (!path_currently_selected &&
753 gtk_tree_model_get_iter(store, &iter, tpath))
755 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
759 VFLIST(vf)->select_fd = NULL;
763 !VFLIST(vf)->select_idle_id)
765 VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
772 *-----------------------------------------------------------------------------
774 *-----------------------------------------------------------------------------
778 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
779 gboolean path_currently_selected, gpointer data)
785 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
788 gchar *sidecars = NULL;
789 gchar *name_sidecars;
791 const gchar *time = text_from_time(fd->date);
792 gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
795 if (fd->sidecar_files)
797 sidecars = file_data_sc_list_to_string(fd);
798 name_sidecars = g_strdup_printf("%s%s %s", link, fd->name, sidecars);
802 gchar *disabled_grouping = fd->disable_grouping ? _(" [NO GROUPING]") : "";
803 name_sidecars = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping);
805 size = text_from_size(fd->size);
807 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
809 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
810 FILE_COLUMN_VERSION, fd->version,
811 FILE_COLUMN_THUMB, fd->thumb_pixbuf,
812 FILE_COLUMN_MULTILINE, multiline,
813 FILE_COLUMN_NAME, name_sidecars,
814 FILE_COLUMN_SIZE, size,
815 FILE_COLUMN_DATE, time,
816 #define STORE_SET_IS_SLOW 1
817 #if STORE_SET_IS_SLOW
818 /* this is 3x faster on a directory with 20000 files */
819 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
820 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
821 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
822 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
823 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
824 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
825 #if FILEDATA_MARKS_SIZE != 6
826 #error this needs to be updated
829 FILE_COLUMN_COLOR, FALSE, -1);
831 #if !STORE_SET_IS_SLOW
834 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
835 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
840 g_free(name_sidecars);
844 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
849 gint num_ordered = 0;
850 gint num_prepended = 0;
852 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
858 FileData *fd = work->data;
859 gboolean done = FALSE;
863 FileData *old_fd = NULL;
864 gint old_version = 0;
869 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
870 FILE_COLUMN_POINTER, &old_fd,
871 FILE_COLUMN_VERSION, &old_version,
881 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
883 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
885 if (match == 0) g_warning("multiple fd for the same path");
900 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
905 here should be used gtk_tree_store_append, but this function seems to be O(n)
906 and it seems to be much faster to add new entries to the beginning and reorder later
909 gtk_tree_store_prepend(store, &new, parent_iter);
912 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
913 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
915 if (g_list_find(selected, fd))
917 /* renamed files - the same fd appears at different position - select it again*/
918 GtkTreeSelection *selection;
919 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
920 gtk_tree_selection_select_iter(selection, &new);
927 file_data_unref(old_fd);
928 valid = gtk_tree_store_remove(store, &iter);
932 if (fd->version != old_version)
934 vflist_setup_iter(vf, store, &iter, fd);
935 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
938 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
949 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
950 file_data_unref(old_fd);
952 valid = gtk_tree_store_remove(store, &iter);
955 /* move the prepended entries to the correct position */
959 gint num_total = num_prepended + num_ordered;
960 gint *new_order = g_malloc(num_total * sizeof(gint));
962 for (i = 0; i < num_total; i++)
965 new_order[i] = num_prepended + i;
967 new_order[i] = num_total - 1 - i;
969 gtk_tree_store_reorder(store, parent_iter, new_order);
975 void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend)
978 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
983 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
984 if (!vf->list) return;
990 FileData *fd = work->data;
991 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
996 vf->sort_method = type;
997 vf->sort_ascend = ascend;
999 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1001 new_order = g_malloc(i * sizeof(gint));
1007 FileData *fd = work->data;
1008 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
1013 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1014 gtk_tree_store_reorder(store, NULL, new_order);
1017 g_hash_table_destroy(fd_idx_hash);
1021 *-----------------------------------------------------------------------------
1023 *-----------------------------------------------------------------------------
1027 void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
1032 FileData *fd = work->data;
1035 if (fd->thumb_pixbuf) (*done)++;
1037 if (fd->sidecar_files)
1039 vflist_thumb_progress_count(fd->sidecar_files, count, done);
1045 void vflist_set_thumb_fd(ViewFile *vf, FileData *fd)
1047 GtkTreeStore *store;
1050 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1052 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1053 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1056 FileData *vflist_thumb_next_fd(ViewFile *vf)
1059 FileData *fd = NULL;
1061 /* first check the visible files */
1063 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1065 GtkTreeModel *store;
1067 gboolean valid = TRUE;
1069 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1070 gtk_tree_model_get_iter(store, &iter, tpath);
1071 gtk_tree_path_free(tpath);
1073 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1077 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &nfd, -1);
1079 if (!nfd->thumb_pixbuf) fd = nfd;
1081 valid = gtk_tree_model_iter_next(store, &iter);
1085 /* then find first undone */
1089 GList *work = vf->list;
1092 FileData *fd_p = work->data;
1093 if (!fd_p->thumb_pixbuf)
1097 GList *work2 = fd_p->sidecar_files;
1099 while (work2 && !fd)
1102 if (!fd_p->thumb_pixbuf) fd = fd_p;
1103 work2 = work2->next;
1114 void vflist_thumb_reset_all(ViewFile *vf)
1116 GList *work = vf->list;
1119 FileData *fd = work->data;
1120 if (fd->thumb_pixbuf)
1122 g_object_unref(fd->thumb_pixbuf);
1123 fd->thumb_pixbuf = NULL;
1130 *-----------------------------------------------------------------------------
1132 *-----------------------------------------------------------------------------
1135 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1137 return g_list_nth_data(vf->list, row);
1140 gint vflist_index_by_fd(ViewFile *vf, FileData *fd)
1143 GList *work, *work2;
1148 FileData *list_fd = work->data;
1149 if (list_fd == fd) return p;
1151 work2 = list_fd->sidecar_files;
1154 /* FIXME: return the same index also for sidecars
1155 it is sufficient for next/prev navigation but it should be rewritten
1156 without using indexes at all
1158 FileData *sidecar_fd = work2->data;
1159 if (sidecar_fd == fd) return p;
1160 work2 = work2->next;
1170 guint vflist_count(ViewFile *vf, gint64 *bytes)
1180 FileData *fd = work->data;
1188 return g_list_length(vf->list);
1191 GList *vflist_get_list(ViewFile *vf)
1199 FileData *fd = work->data;
1202 list = g_list_prepend(list, file_data_ref(fd));
1205 return g_list_reverse(list);
1209 *-----------------------------------------------------------------------------
1211 *-----------------------------------------------------------------------------
1214 static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd)
1216 GtkTreeModel *store;
1217 GtkTreeSelection *selection;
1220 gboolean found = FALSE;
1222 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1223 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1225 while (!found && work)
1227 GtkTreePath *tpath = work->data;
1231 gtk_tree_model_get_iter(store, &iter, tpath);
1232 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1233 if (fd_n == fd) found = TRUE;
1236 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1242 gboolean vflist_index_is_selected(ViewFile *vf, gint row)
1246 fd = vf_index_get_data(vf, row);
1247 return vflist_row_is_selected(vf, fd);
1250 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1252 GtkTreeModel *store;
1253 GtkTreeSelection *selection;
1257 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1258 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1268 GtkTreePath *tpath = work->data;
1272 gtk_tree_model_get_iter(store, &iter, tpath);
1273 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1282 count = g_list_length(slist);
1283 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1289 GList *vflist_selection_get_list(ViewFile *vf)
1291 GtkTreeModel *store;
1292 GtkTreeSelection *selection;
1297 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1298 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1302 GtkTreePath *tpath = work->data;
1306 gtk_tree_model_get_iter(store, &iter, tpath);
1307 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1309 list = g_list_prepend(list, file_data_ref(fd));
1313 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1316 return g_list_reverse(list);
1319 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1321 GtkTreeModel *store;
1322 GtkTreeSelection *selection;
1327 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1328 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1332 GtkTreePath *tpath = work->data;
1336 gtk_tree_model_get_iter(store, &iter, tpath);
1337 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1339 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1343 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1346 return g_list_reverse(list);
1349 void vflist_select_all(ViewFile *vf)
1351 GtkTreeSelection *selection;
1353 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1354 gtk_tree_selection_select_all(selection);
1356 VFLIST(vf)->select_fd = NULL;
1359 void vflist_select_none(ViewFile *vf)
1361 GtkTreeSelection *selection;
1363 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1364 gtk_tree_selection_unselect_all(selection);
1367 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1372 tpath = gtk_tree_model_get_path(store, iter);
1373 result = gtk_tree_path_prev(tpath);
1375 gtk_tree_model_get_iter(store, iter, tpath);
1377 gtk_tree_path_free(tpath);
1382 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1384 if (!gtk_tree_model_get_iter_first(store, iter))
1389 GtkTreeIter next = *iter;
1391 if (gtk_tree_model_iter_next(store, &next))
1400 void vflist_select_invert(ViewFile *vf)
1403 GtkTreeSelection *selection;
1404 GtkTreeModel *store;
1407 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1408 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1410 /* Backward iteration prevents scrolling to the end of the list,
1411 * it scrolls to the first selected row instead. */
1412 valid = tree_model_get_iter_last(store, &iter);
1416 gboolean selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1419 gtk_tree_selection_unselect_iter(selection, &iter);
1421 gtk_tree_selection_select_iter(selection, &iter);
1423 valid = tree_model_iter_prev(store, &iter);
1427 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1431 if (vflist_find_row(vf, fd, &iter) < 0) return;
1433 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1435 if (!vflist_row_is_selected(vf, fd))
1437 GtkTreeSelection *selection;
1438 GtkTreeModel *store;
1441 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1442 gtk_tree_selection_unselect_all(selection);
1443 gtk_tree_selection_select_iter(selection, &iter);
1444 vflist_move_cursor(vf, &iter);
1446 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1447 tpath = gtk_tree_model_get_path(store, &iter);
1448 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1449 gtk_tree_path_free(tpath);
1453 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1456 FileData *fd = NULL;
1458 if (sel_fd->parent) sel_fd = sel_fd->parent;
1467 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1469 if (match >= 0) break;
1472 if (fd) vflist_select_by_fd(vf, fd);
1476 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1478 GtkTreeModel *store;
1480 GtkTreeSelection *selection;
1484 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1486 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1487 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1489 valid = gtk_tree_model_get_iter_first(store, &iter);
1493 gboolean mark_val, selected;
1494 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1496 mark_val = file_data_get_mark(fd, n);
1497 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1501 case MTS_MODE_SET: selected = mark_val;
1503 case MTS_MODE_OR: selected = mark_val | selected;
1505 case MTS_MODE_AND: selected = mark_val & selected;
1507 case MTS_MODE_MINUS: selected = !mark_val & selected;
1512 gtk_tree_selection_select_iter(selection, &iter);
1514 gtk_tree_selection_unselect_iter(selection, &iter);
1516 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1520 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1522 GtkTreeModel *store;
1523 GtkTreeSelection *selection;
1528 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1530 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1531 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1535 GtkTreePath *tpath = work->data;
1539 gtk_tree_model_get_iter(store, &iter, tpath);
1540 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1542 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1546 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1548 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1550 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1554 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1556 vf_refresh_idle(vf);
1560 /* mark functions can have various side effects - update all columns to be sure */
1561 vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
1565 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1569 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1574 *-----------------------------------------------------------------------------
1576 *-----------------------------------------------------------------------------
1579 static void vflist_listview_set_columns(GtkWidget *listview, gboolean thumb)
1581 GtkTreeViewColumn *column;
1582 GtkCellRenderer *cell;
1586 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1587 if (!column) return;
1589 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1591 list = gtk_tree_view_column_get_cell_renderers(column);
1596 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1597 gtk_tree_view_column_set_visible(column, thumb);
1599 multiline = (thumb && options->thumbnails.max_height >= 48);
1601 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1602 if (!column) return;
1603 gtk_tree_view_column_set_visible(column, multiline);
1604 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1606 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1607 if (!column) return;
1608 gtk_tree_view_column_set_visible(column, !multiline);
1609 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1611 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1612 if (!column) return;
1613 gtk_tree_view_column_set_visible(column, !multiline);
1615 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1616 if (!column) return;
1617 gtk_tree_view_column_set_visible(column, !multiline);
1619 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1622 static void vflist_populate_view(ViewFile *vf)
1624 GtkTreeStore *store;
1625 gboolean thumbs_enabled;
1628 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1629 thumbs_enabled = VFLIST(vf)->thumbs_enabled;
1635 vflist_store_clear(vf);
1640 vflist_listview_set_columns(vf->listview, thumbs_enabled);
1642 selected = vflist_selection_get_list(vf);
1644 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1646 if (selected && vflist_selection_count(vf, NULL) == 0)
1648 /* all selected files disappeared */
1649 vflist_select_closest(vf, selected->data);
1652 filelist_free(selected);
1655 vf_thumb_update(vf);
1658 gboolean vflist_refresh(ViewFile *vf)
1661 gboolean ret = TRUE;
1663 old_list = vf->list;
1666 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1669 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1671 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1672 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1673 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1675 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1676 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1679 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1681 vflist_populate_view(vf);
1683 filelist_free(old_list);
1684 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1691 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1693 #define CELL_HEIGHT_OVERRIDE 512
1695 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1699 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1700 if (spec && G_IS_PARAM_SPEC_INT(spec))
1702 GParamSpecInt *spec_int;
1704 spec_int = G_PARAM_SPEC_INT(spec);
1705 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1709 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1711 static GdkColor color;
1712 static GtkWidget *done = NULL;
1718 style = gtk_widget_get_style(widget);
1719 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1720 shift_color(&color, -1, 0);
1727 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1728 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1730 ViewFile *vf = data;
1733 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1734 g_object_set(G_OBJECT(cell),
1735 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1736 "cell-background-set", set, NULL);
1739 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gboolean image, gboolean right_justify, gboolean expand)
1741 GtkTreeViewColumn *column;
1742 GtkCellRenderer *renderer;
1744 column = gtk_tree_view_column_new();
1745 gtk_tree_view_column_set_title(column, title);
1746 gtk_tree_view_column_set_min_width(column, 4);
1750 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1751 renderer = gtk_cell_renderer_text_new();
1754 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1756 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1757 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1759 gtk_tree_view_column_set_expand(column, TRUE);
1763 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1764 renderer = gtk_cell_renderer_pixbuf_new();
1765 cell_renderer_height_override(renderer);
1766 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1767 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1770 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1771 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1772 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1774 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1777 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1779 ViewFile *vf = data;
1780 GtkTreeStore *store;
1781 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1787 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1788 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1791 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1793 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1795 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &marked, -1);
1797 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1798 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, marked);
1799 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1801 vf_refresh_idle(vf);
1805 /* mark functions can have various side effects - update all columns to be sure */
1806 vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
1808 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1810 gtk_tree_path_free(path);
1813 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1815 GtkTreeViewColumn *column;
1816 GtkCellRenderer *renderer;
1817 GtkTreeStore *store;
1820 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1822 renderer = gtk_cell_renderer_toggle_new();
1823 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1825 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1826 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1827 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1829 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1830 gtk_tree_view_column_set_fixed_width(column, 22);
1831 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1834 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1838 *-----------------------------------------------------------------------------
1840 *-----------------------------------------------------------------------------
1843 gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1845 if (!dir_fd) return FALSE;
1846 if (vf->dir_fd == dir_fd) return TRUE;
1848 file_data_unref(vf->dir_fd);
1849 vf->dir_fd = file_data_ref(dir_fd);
1851 /* force complete reload */
1852 vflist_store_clear(vf);
1854 filelist_free(vf->list);
1857 return vf_refresh(vf);
1860 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1862 ViewFile *vf = data;
1864 file_data_unregister_notify_func(vf_notify_cb, vf);
1866 vflist_select_idle_cancel(vf);
1867 vf_refresh_idle_cancel(vf);
1870 filelist_free(vf->list);
1873 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1875 GtkTreeStore *store;
1876 GtkTreeSelection *selection;
1877 GType flist_types[FILE_COLUMN_COUNT];
1881 vf->info = g_new0(ViewFileInfoList, 1);
1883 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1884 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1885 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1886 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1887 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1888 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1889 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1890 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1891 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1892 flist_types[i] = G_TYPE_BOOLEAN;
1894 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1896 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1897 g_object_unref(store);
1899 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1900 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1901 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1903 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1904 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1908 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1910 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1911 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1915 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1916 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1919 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1920 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1923 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1924 g_assert(column == FILE_VIEW_COLUMN_NAME);
1927 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1928 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1931 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1932 g_assert(column == FILE_VIEW_COLUMN_DATE);
1935 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1939 void vflist_thumb_set(ViewFile *vf, gboolean enable)
1941 if (VFLIST(vf)->thumbs_enabled == enable) return;
1943 VFLIST(vf)->thumbs_enabled = enable;
1944 if (vf->layout) vf_refresh(vf);
1947 void vflist_marks_set(ViewFile *vf, gboolean enable)
1949 GList *columns, *work;
1951 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1956 GtkTreeViewColumn *column = work->data;
1957 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1960 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1961 gtk_tree_view_column_set_visible(column, enable);
1964 g_list_free(columns);
1968 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */