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 gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
66 static gint 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, 0, 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, gint 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 gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
468 if (strlen(new) == 0) return FALSE;
470 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
471 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
473 if (strchr(new, G_DIR_SEPARATOR) != NULL)
475 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
476 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
481 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
482 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 gint 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 gint 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 gint 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;
692 cur_fd = layout_image_get_fd(vf->layout);
693 if (sel_fd == cur_fd) return; /* no change */
695 row = g_list_index(vf->list, sel_fd);
696 // FIXME sidecar data
698 if (sel_fd && options->image.enable_read_ahead && row >= 0)
700 if (row > g_list_index(vf->list, cur_fd) &&
701 (guint) (row + 1) < vf_count(vf, NULL))
703 read_ahead_fd = vf_index_get_data(vf, row + 1);
707 read_ahead_fd = vf_index_get_data(vf, row - 1);
711 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
714 static gint vflist_select_idle_cb(gpointer data)
720 VFLIST(vf)->select_idle_id = -1;
726 if (VFLIST(vf)->select_fd)
728 vflist_select_image(vf, VFLIST(vf)->select_fd);
729 VFLIST(vf)->select_fd = NULL;
732 VFLIST(vf)->select_idle_id = -1;
736 static void vflist_select_idle_cancel(ViewFile *vf)
738 if (VFLIST(vf)->select_idle_id != -1) g_source_remove(VFLIST(vf)->select_idle_id);
739 VFLIST(vf)->select_idle_id = -1;
742 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
743 gboolean path_currently_selected, gpointer data)
748 if (!path_currently_selected &&
749 gtk_tree_model_get_iter(store, &iter, tpath))
751 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
755 VFLIST(vf)->select_fd = NULL;
759 VFLIST(vf)->select_idle_id == -1)
761 VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
768 *-----------------------------------------------------------------------------
770 *-----------------------------------------------------------------------------
774 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
775 gboolean path_currently_selected, gpointer data)
781 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
784 gchar *sidecars = NULL;
785 gchar *name_sidecars;
787 const gchar *time = text_from_time(fd->date);
788 gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
791 if (fd->sidecar_files)
793 sidecars = file_data_sc_list_to_string(fd);
794 name_sidecars = g_strdup_printf("%s%s %s", link, fd->name, sidecars);
798 name_sidecars = g_strdup_printf("%s%s", link, fd->name);
800 size = text_from_size(fd->size);
802 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
804 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
805 FILE_COLUMN_VERSION, fd->version,
806 FILE_COLUMN_THUMB, fd->thumb_pixbuf,
807 FILE_COLUMN_MULTILINE, multiline,
808 FILE_COLUMN_NAME, name_sidecars,
809 FILE_COLUMN_SIZE, size,
810 FILE_COLUMN_DATE, time,
811 #define STORE_SET_IS_SLOW 1
812 #if STORE_SET_IS_SLOW
813 /* this is 3x faster on a directory with 20000 files */
814 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
815 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
816 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
817 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
818 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
819 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
820 #if FILEDATA_MARKS_SIZE != 6
821 #error this needs to be updated
824 FILE_COLUMN_COLOR, FALSE, -1);
826 #if !STORE_SET_IS_SLOW
829 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
830 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
835 g_free(name_sidecars);
839 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
844 gint num_ordered = 0;
845 gint num_prepended = 0;
847 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
853 FileData *fd = work->data;
858 FileData *old_fd = NULL;
859 gint old_version = 0;
864 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
865 FILE_COLUMN_POINTER, &old_fd,
866 FILE_COLUMN_VERSION, &old_version,
876 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
878 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
880 if (match == 0) g_warning("multiple fd for the same path");
895 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
900 here should be used gtk_tree_store_append, but this function seems to be O(n)
901 and it seems to be much faster to add new entries to the beginning and reorder later
904 gtk_tree_store_prepend(store, &new, parent_iter);
907 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
908 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
910 if (g_list_find(selected, fd))
912 /* renamed files - the same fd appears at different position - select it again*/
913 GtkTreeSelection *selection;
914 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
915 gtk_tree_selection_select_iter(selection, &new);
922 file_data_unref(old_fd);
923 valid = gtk_tree_store_remove(store, &iter);
927 if (fd->version != old_version)
929 vflist_setup_iter(vf, store, &iter, fd);
930 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
933 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
944 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
945 file_data_unref(old_fd);
947 valid = gtk_tree_store_remove(store, &iter);
950 /* move the prepended entries to the correct position */
954 gint num_total = num_prepended + num_ordered;
955 gint *new_order = g_malloc(num_total * sizeof(gint));
957 for (i = 0; i < num_total; i++)
960 new_order[i] = num_prepended + i;
962 new_order[i] = num_total - 1 - i;
964 gtk_tree_store_reorder(store, parent_iter, new_order);
970 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
973 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
978 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
979 if (!vf->list) return;
985 FileData *fd = work->data;
986 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
991 vf->sort_method = type;
992 vf->sort_ascend = ascend;
994 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
996 new_order = g_malloc(i * sizeof(gint));
1002 FileData *fd = work->data;
1003 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
1008 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1009 gtk_tree_store_reorder(store, NULL, new_order);
1012 g_hash_table_destroy(fd_idx_hash);
1016 *-----------------------------------------------------------------------------
1018 *-----------------------------------------------------------------------------
1021 static gint vflist_thumb_next(ViewFile *vf);
1023 static void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
1028 FileData *fd = work->data;
1031 if (fd->thumb_pixbuf) (*done)++;
1033 if (fd->sidecar_files)
1035 vflist_thumb_progress_count(fd->sidecar_files, count, done);
1041 static gdouble vflist_thumb_progress(ViewFile *vf)
1046 vflist_thumb_progress_count(vf->list, &count, &done);
1048 DEBUG_1("thumb progress: %d of %d", done, count);
1049 return (gdouble)done / count;
1053 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
1055 if (vf->func_thumb_status)
1057 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1061 static void vflist_thumb_cleanup(ViewFile *vf)
1063 vflist_thumb_status(vf, 0.0, NULL);
1065 vf->thumbs_running = FALSE;
1067 thumb_loader_free(vf->thumbs_loader);
1068 vf->thumbs_loader = NULL;
1070 vf->thumbs_filedata = NULL;
1073 static void vflist_thumb_stop(ViewFile *vf)
1075 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1078 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1080 GtkTreeStore *store;
1083 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1085 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1086 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1088 vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
1091 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1093 ViewFile *vf = data;
1095 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1097 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1100 while (vflist_thumb_next(vf));
1103 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1105 ViewFile *vf = data;
1107 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1109 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1112 while (vflist_thumb_next(vf));
1115 static gint vflist_thumb_next(ViewFile *vf)
1118 FileData *fd = NULL;
1120 /* first check the visible files */
1122 if (GTK_WIDGET_REALIZED(vf->listview) &&
1123 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1125 GtkTreeModel *store;
1129 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1130 gtk_tree_model_get_iter(store, &iter, tpath);
1131 gtk_tree_path_free(tpath);
1133 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1135 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1136 if (fd->thumb_pixbuf) fd = NULL;
1138 valid = gtk_tree_model_iter_next(store, &iter);
1142 /* then find first undone */
1146 GList *work = vf->list;
1149 FileData *fd_p = work->data;
1150 if (!fd_p->thumb_pixbuf)
1154 GList *work2 = fd_p->sidecar_files;
1156 while (work2 && !fd)
1159 if (!fd_p->thumb_pixbuf) fd = fd_p;
1160 work2 = work2->next;
1170 vflist_thumb_cleanup(vf);
1174 vf->thumbs_filedata = fd;
1176 thumb_loader_free(vf->thumbs_loader);
1178 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1179 thumb_loader_set_callbacks(vf->thumbs_loader,
1180 vflist_thumb_done_cb,
1181 vflist_thumb_error_cb,
1185 if (!thumb_loader_start(vf->thumbs_loader, fd))
1187 /* set icon to unknown, continue */
1188 DEBUG_1("thumb loader start failed %s", fd->path);
1189 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1197 static void vflist_thumb_update(ViewFile *vf)
1199 vflist_thumb_stop(vf);
1200 if (!VFLIST(vf)->thumbs_enabled) return;
1202 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1203 vf->thumbs_running = TRUE;
1205 while (vflist_thumb_next(vf));
1209 *-----------------------------------------------------------------------------
1211 *-----------------------------------------------------------------------------
1214 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1216 return g_list_nth_data(vf->list, row);
1219 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1224 if (!path) return -1;
1229 FileData *fd = work->data;
1230 if (strcmp(path, fd->path) == 0) return p;
1239 guint vflist_count(ViewFile *vf, gint64 *bytes)
1249 FileData *fd = work->data;
1257 return g_list_length(vf->list);
1260 GList *vflist_get_list(ViewFile *vf)
1268 FileData *fd = work->data;
1271 list = g_list_prepend(list, file_data_ref(fd));
1274 return g_list_reverse(list);
1278 *-----------------------------------------------------------------------------
1280 *-----------------------------------------------------------------------------
1283 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1285 GtkTreeModel *store;
1286 GtkTreeSelection *selection;
1291 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1292 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1294 while (!found && work)
1296 GtkTreePath *tpath = work->data;
1300 gtk_tree_model_get_iter(store, &iter, tpath);
1301 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1302 if (fd_n == fd) found = TRUE;
1305 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1311 gint vflist_index_is_selected(ViewFile *vf, gint row)
1315 fd = vf_index_get_data(vf, row);
1316 return vflist_row_is_selected(vf, fd);
1319 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1321 GtkTreeModel *store;
1322 GtkTreeSelection *selection;
1326 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1327 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1337 GtkTreePath *tpath = work->data;
1341 gtk_tree_model_get_iter(store, &iter, tpath);
1342 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1351 count = g_list_length(slist);
1352 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1358 GList *vflist_selection_get_list(ViewFile *vf)
1360 GtkTreeModel *store;
1361 GtkTreeSelection *selection;
1366 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1367 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1371 GtkTreePath *tpath = work->data;
1375 gtk_tree_model_get_iter(store, &iter, tpath);
1376 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1378 list = g_list_prepend(list, file_data_ref(fd));
1382 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1385 return g_list_reverse(list);
1388 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1390 GtkTreeModel *store;
1391 GtkTreeSelection *selection;
1396 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1397 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1401 GtkTreePath *tpath = work->data;
1405 gtk_tree_model_get_iter(store, &iter, tpath);
1406 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1408 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1412 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1415 return g_list_reverse(list);
1418 void vflist_select_all(ViewFile *vf)
1420 GtkTreeSelection *selection;
1422 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1423 gtk_tree_selection_select_all(selection);
1425 VFLIST(vf)->select_fd = NULL;
1428 void vflist_select_none(ViewFile *vf)
1430 GtkTreeSelection *selection;
1432 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1433 gtk_tree_selection_unselect_all(selection);
1436 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1441 tpath = gtk_tree_model_get_path(store, iter);
1442 result = gtk_tree_path_prev(tpath);
1444 gtk_tree_model_get_iter(store, iter, tpath);
1446 gtk_tree_path_free(tpath);
1451 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1453 if (!gtk_tree_model_get_iter_first(store, iter))
1458 GtkTreeIter next = *iter;
1460 if (gtk_tree_model_iter_next(store, &next))
1469 void vflist_select_invert(ViewFile *vf)
1472 GtkTreeSelection *selection;
1473 GtkTreeModel *store;
1476 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1477 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1479 /* Backward iteration prevents scrolling to the end of the list,
1480 * it scrolls to the first selected row instead. */
1481 valid = tree_model_get_iter_last(store, &iter);
1485 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1488 gtk_tree_selection_unselect_iter(selection, &iter);
1490 gtk_tree_selection_select_iter(selection, &iter);
1492 valid = tree_model_iter_prev(store, &iter);
1496 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1500 if (vflist_find_row(vf, fd, &iter) < 0) return;
1502 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1504 if (!vflist_row_is_selected(vf, fd))
1506 GtkTreeSelection *selection;
1507 GtkTreeModel *store;
1510 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1511 gtk_tree_selection_unselect_all(selection);
1512 gtk_tree_selection_select_iter(selection, &iter);
1513 vflist_move_cursor(vf, &iter);
1515 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1516 tpath = gtk_tree_model_get_path(store, &iter);
1517 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1518 gtk_tree_path_free(tpath);
1522 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1525 FileData *fd = NULL;
1527 if (sel_fd->parent) sel_fd = sel_fd->parent;
1536 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1538 if (match >= 0) break;
1541 if (fd) vflist_select_by_fd(vf, fd);
1545 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1547 GtkTreeModel *store;
1549 GtkTreeSelection *selection;
1553 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1555 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1556 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1558 valid = gtk_tree_model_get_iter_first(store, &iter);
1562 gboolean mark_val, selected;
1563 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1565 mark_val = file_data_get_mark(fd, n);
1566 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1570 case MTS_MODE_SET: selected = mark_val;
1572 case MTS_MODE_OR: selected = mark_val | selected;
1574 case MTS_MODE_AND: selected = mark_val & selected;
1576 case MTS_MODE_MINUS: selected = !mark_val & selected;
1581 gtk_tree_selection_select_iter(selection, &iter);
1583 gtk_tree_selection_unselect_iter(selection, &iter);
1585 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1589 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1591 GtkTreeModel *store;
1592 GtkTreeSelection *selection;
1597 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1599 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1600 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1604 GtkTreePath *tpath = work->data;
1608 gtk_tree_model_get_iter(store, &iter, tpath);
1609 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1611 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1615 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1617 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1619 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1623 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1625 vf_refresh_idle(vf);
1629 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1631 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1635 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1640 *-----------------------------------------------------------------------------
1642 *-----------------------------------------------------------------------------
1645 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1647 GtkTreeViewColumn *column;
1648 GtkCellRenderer *cell;
1652 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1653 if (!column) return;
1655 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1657 list = gtk_tree_view_column_get_cell_renderers(column);
1662 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1663 gtk_tree_view_column_set_visible(column, thumb);
1665 multiline = (thumb && options->thumbnails.max_height >= 48);
1667 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1668 if (!column) return;
1669 gtk_tree_view_column_set_visible(column, multiline);
1670 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1672 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1673 if (!column) return;
1674 gtk_tree_view_column_set_visible(column, !multiline);
1675 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1677 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1678 if (!column) return;
1679 gtk_tree_view_column_set_visible(column, !multiline);
1681 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1682 if (!column) return;
1683 gtk_tree_view_column_set_visible(column, !multiline);
1685 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1688 static void vflist_populate_view(ViewFile *vf)
1690 GtkTreeStore *store;
1694 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1695 thumbs = VFLIST(vf)->thumbs_enabled;
1697 vflist_thumb_stop(vf);
1701 vflist_store_clear(vf);
1706 vflist_listview_set_columns(vf->listview, thumbs);
1708 selected = vflist_selection_get_list(vf);
1710 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1712 if (selected && vflist_selection_count(vf, NULL) == 0)
1714 /* all selected files disappeared */
1715 vflist_select_closest(vf, selected->data);
1718 filelist_free(selected);
1721 vflist_thumb_update(vf);
1724 gint vflist_refresh(ViewFile *vf)
1729 old_list = vf->list;
1732 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1735 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1737 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1738 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1739 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1741 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1742 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1745 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1747 vflist_populate_view(vf);
1749 filelist_free(old_list);
1750 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1757 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1759 #define CELL_HEIGHT_OVERRIDE 512
1761 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1765 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1766 if (spec && G_IS_PARAM_SPEC_INT(spec))
1768 GParamSpecInt *spec_int;
1770 spec_int = G_PARAM_SPEC_INT(spec);
1771 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1775 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1777 static GdkColor color;
1778 static GtkWidget *done = NULL;
1784 style = gtk_widget_get_style(widget);
1785 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1786 shift_color(&color, -1, 0);
1793 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1794 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1796 ViewFile *vf = data;
1799 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1800 g_object_set(G_OBJECT(cell),
1801 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1802 "cell-background-set", set, NULL);
1805 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1807 GtkTreeViewColumn *column;
1808 GtkCellRenderer *renderer;
1810 column = gtk_tree_view_column_new();
1811 gtk_tree_view_column_set_title(column, title);
1812 gtk_tree_view_column_set_min_width(column, 4);
1816 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1817 renderer = gtk_cell_renderer_text_new();
1820 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1822 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1823 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1825 gtk_tree_view_column_set_expand(column, TRUE);
1829 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1830 renderer = gtk_cell_renderer_pixbuf_new();
1831 cell_renderer_height_override(renderer);
1832 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1833 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1836 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1837 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1838 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1840 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1843 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1845 ViewFile *vf = data;
1846 GtkTreeStore *store;
1847 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1853 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1854 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1857 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1859 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1861 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1863 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1864 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1865 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1867 vf_refresh_idle(vf);
1869 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1871 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1872 gtk_tree_path_free(path);
1875 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1877 GtkTreeViewColumn *column;
1878 GtkCellRenderer *renderer;
1879 GtkTreeStore *store;
1882 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1884 renderer = gtk_cell_renderer_toggle_new();
1885 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1887 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1888 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1889 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1891 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1892 gtk_tree_view_column_set_fixed_width(column, 22);
1893 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1896 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1900 *-----------------------------------------------------------------------------
1902 *-----------------------------------------------------------------------------
1905 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1907 if (!dir_fd) return FALSE;
1908 if (vf->dir_fd == dir_fd) return TRUE;
1910 file_data_unref(vf->dir_fd);
1911 vf->dir_fd = file_data_ref(dir_fd);
1913 /* force complete reload */
1914 vflist_store_clear(vf);
1916 filelist_free(vf->list);
1919 return vf_refresh(vf);
1922 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1924 ViewFile *vf = data;
1926 file_data_unregister_notify_func(vf_notify_cb, vf);
1928 vflist_select_idle_cancel(vf);
1929 vf_refresh_idle_cancel(vf);
1930 vflist_thumb_stop(vf);
1932 filelist_free(vf->list);
1935 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1937 GtkTreeStore *store;
1938 GtkTreeSelection *selection;
1940 GType flist_types[FILE_COLUMN_COUNT];
1944 vf->info = g_new0(ViewFileInfoList, 1);
1946 VFLIST(vf)->click_fd = NULL;
1947 VFLIST(vf)->select_fd = NULL;
1948 VFLIST(vf)->thumbs_enabled = FALSE;
1950 VFLIST(vf)->select_idle_id = -1;
1952 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1953 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1954 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1955 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1956 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1957 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1958 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1959 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1960 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1961 flist_types[i] = G_TYPE_BOOLEAN;
1963 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1965 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1966 g_object_unref(store);
1968 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1969 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1970 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1972 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1973 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1977 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1979 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1980 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1984 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1985 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1988 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1989 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1992 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1993 g_assert(column == FILE_VIEW_COLUMN_NAME);
1996 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1997 g_assert(column == FILE_VIEW_COLUMN_SIZE);
2000 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
2001 g_assert(column == FILE_VIEW_COLUMN_DATE);
2004 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
2008 void vflist_thumb_set(ViewFile *vf, gint enable)
2010 if (VFLIST(vf)->thumbs_enabled == enable) return;
2012 VFLIST(vf)->thumbs_enabled = enable;
2013 if (vf->layout) vf_refresh(vf);
2016 void vflist_marks_set(ViewFile *vf, gint enable)
2018 GList *columns, *work;
2020 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
2025 GtkTreeViewColumn *column = work->data;
2026 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
2029 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
2030 gtk_tree_view_column_set_visible(column, enable);
2033 g_list_free(columns);
2037 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */