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"
18 #include "cache_maint.h"
24 #include "layout_image.h"
29 #include "ui_fileops.h"
31 #include "ui_tree_edit.h"
32 #include "uri_utils.h"
33 #include "view_file.h"
35 #include <gdk/gdkkeysyms.h> /* for keyboard values */
37 /* Index to tree store */
39 FILE_COLUMN_POINTER = 0,
43 FILE_COLUMN_MULTILINE,
48 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
53 /* Index to tree view */
55 FILE_VIEW_COLUMN_MARKS = 0,
56 FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
57 FILE_VIEW_COLUMN_THUMB,
58 FILE_VIEW_COLUMN_MULTILINE,
59 FILE_VIEW_COLUMN_NAME,
60 FILE_VIEW_COLUMN_SIZE,
61 FILE_VIEW_COLUMN_DATE,
62 FILE_VIEW_COLUMN_COUNT
67 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
68 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
69 static void vflist_populate_view(ViewFile *vf);
73 *-----------------------------------------------------------------------------
75 *-----------------------------------------------------------------------------
82 } ViewFileFindRowData;
84 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
86 ViewFileFindRowData *find = data;
88 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
99 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
102 ViewFileFindRowData data = {fd, iter, 0, 0};
104 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
105 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
115 static FileData *vflist_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
118 GtkTreeViewColumn *column;
120 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
121 &tpath, &column, NULL, NULL))
127 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
128 gtk_tree_model_get_iter(store, &row, tpath);
129 gtk_tree_path_free(tpath);
130 gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &fd, -1);
139 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
144 FileData *fd_p = work->data;
145 if (fd == fd_p) return i;
149 GList *work2 = fd_p->sidecar_files;
153 if (fd == fd_p) return i;
163 static gint vflist_sidecar_list_count(GList *work)
168 FileData *fd = work->data;
171 GList *work2 = fd->sidecar_files;
183 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
186 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
191 static void vflist_store_clear(ViewFile *vf)
194 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
195 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
196 gtk_tree_store_clear(GTK_TREE_STORE(store));
199 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
204 if (vflist_find_row(vf, fd, &iter) < 0) return;
205 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
206 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
209 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
214 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
216 tpath = gtk_tree_model_get_path(store, iter);
217 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
218 gtk_tree_path_free(tpath);
222 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
224 GList *columns, *work;
227 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
231 GtkTreeViewColumn *column = work->data;
232 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
238 g_list_free(columns);
244 *-----------------------------------------------------------------------------
246 *-----------------------------------------------------------------------------
249 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
250 GtkSelectionData *selection_data, guint info,
251 guint time, gpointer data)
255 gchar *uri_text = NULL;
258 if (!VFLIST(vf)->click_fd) return;
260 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
262 list = vf_selection_get_list(vf);
266 list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
271 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
274 DEBUG_1("%s", uri_text);
276 gtk_selection_data_set(selection_data, selection_data->target,
277 8, (guchar *)uri_text, total);
281 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
285 vflist_color_set(vf, VFLIST(vf)->click_fd, TRUE);
287 if (VFLIST(vf)->thumbs_enabled &&
288 VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
292 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
293 items = vf_selection_count(vf, NULL);
297 dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
301 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
305 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
307 if (context->action == GDK_ACTION_MOVE)
313 static void vflist_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
314 int x, int y, GtkSelectionData *selection,
315 guint info, guint time, gpointer data)
319 if (info == TARGET_TEXT_PLAIN) {
320 FileData *fd = vflist_find_data_by_coord(vf, x, y, NULL);
323 /* Add keywords to file */
324 gchar *str = g_strndup((gchar *)selection->data, selection->length);
325 GList *kw_list = string_to_keywords_list(str);
327 metadata_append_list(fd, KEYWORD_KEY, kw_list);
328 string_list_free(kw_list);
331 file notification should handle this automatically
332 if (vf->layout && vf->layout->bar_info) {
333 bar_set_fd(vf->layout->bar_info, fd);
340 void vflist_dnd_init(ViewFile *vf)
342 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
343 dnd_file_drag_types, dnd_file_drag_types_count,
344 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
345 gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
346 dnd_file_drag_types, dnd_file_drag_types_count,
347 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
349 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
350 G_CALLBACK(vflist_dnd_get), vf);
351 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
352 G_CALLBACK(vflist_dnd_begin), vf);
353 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
354 G_CALLBACK(vflist_dnd_end), vf);
355 g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
356 G_CALLBACK(vflist_drag_data_received), vf);
360 *-----------------------------------------------------------------------------
362 *-----------------------------------------------------------------------------
365 GList *vflist_pop_menu_file_list(ViewFile *vf)
367 if (!VFLIST(vf)->click_fd) return NULL;
369 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
371 return vf_selection_get_list(vf);
374 return g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
377 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
381 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
385 list = vf_selection_get_list(vf);
386 view_window_new_from_list(list);
391 view_window_new(VFLIST(vf)->click_fd);
395 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
400 list = vf_pop_menu_file_list(vf);
401 if (options->file_ops.enable_in_place_rename &&
402 list && !list->next && VFLIST(vf)->click_fd)
409 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
410 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
414 tpath = gtk_tree_model_get_path(store, &iter);
415 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
416 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST(vf)->click_fd->name,
417 vflist_row_rename_cb, vf);
418 gtk_tree_path_free(tpath);
423 file_util_rename(NULL, list, vf->listview);
426 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
430 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
433 layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
437 vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
441 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
445 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
449 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
452 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
453 VFLIST(vf)->click_fd = NULL;
459 *-----------------------------------------------------------------------------
461 *-----------------------------------------------------------------------------
464 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
470 if (strlen(new) == 0) return FALSE;
472 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
473 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
475 if (strchr(new, G_DIR_SEPARATOR) != NULL)
477 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
478 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
483 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
484 file_util_rename_simple(fd, new_path, vf->listview);
493 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
501 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
502 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
503 tpath = gtk_tree_model_get_path(store, &iter);
504 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
505 gtk_tree_path_free(tpath);
507 popup_menu_position_clamp(menu, x, y, 0);
510 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
515 if (event->keyval != GDK_Menu) return FALSE;
517 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
523 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
524 gtk_tree_model_get_iter(store, &iter, tpath);
525 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
526 gtk_tree_path_free(tpath);
530 VFLIST(vf)->click_fd = NULL;
533 vf->popup = vf_pop_menu(vf);
534 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
539 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
545 GtkTreeViewColumn *column;
547 vf->clicked_mark = 0;
549 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
550 &tpath, &column, NULL, NULL))
553 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
555 if (bevent->button == MOUSE_BUTTON_LEFT &&
556 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
559 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
560 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
562 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
564 gtk_tree_model_get_iter(store, &iter, tpath);
565 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
567 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
569 gtk_tree_path_free(tpath);
572 VFLIST(vf)->click_fd = fd;
574 if (bevent->button == MOUSE_BUTTON_RIGHT)
576 vf->popup = vf_pop_menu(vf);
577 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
578 bevent->button, bevent->time);
582 if (!fd) return FALSE;
584 if (bevent->button == MOUSE_BUTTON_MIDDLE)
586 if (!vflist_row_is_selected(vf, fd))
588 vflist_color_set(vf, fd, TRUE);
594 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
595 !(bevent->state & GDK_SHIFT_MASK ) &&
596 !(bevent->state & GDK_CONTROL_MASK ) &&
597 vflist_row_is_selected(vf, fd))
599 GtkTreeSelection *selection;
601 gtk_widget_grab_focus(widget);
604 /* returning FALSE and further processing of the event is needed for
605 correct operation of the expander, to show the sidecar files.
606 It however resets the selection of multiple files. With this condition
607 it should work for both cases */
608 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
609 return (gtk_tree_selection_count_selected_rows(selection) > 1);
613 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
615 if (vf->layout) layout_image_full_screen_start(vf->layout);
622 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
629 if (bevent->button == MOUSE_BUTTON_MIDDLE)
631 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
634 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
639 if ((bevent->x != 0 || bevent->y != 0) &&
640 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
641 &tpath, NULL, NULL, NULL))
645 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
646 gtk_tree_model_get_iter(store, &iter, tpath);
647 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
648 gtk_tree_path_free(tpath);
651 if (bevent->button == MOUSE_BUTTON_MIDDLE)
653 if (fd && VFLIST(vf)->click_fd == fd)
655 GtkTreeSelection *selection;
657 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
658 if (vflist_row_is_selected(vf, fd))
660 gtk_tree_selection_unselect_iter(selection, &iter);
664 gtk_tree_selection_select_iter(selection, &iter);
670 if (fd && VFLIST(vf)->click_fd == fd &&
671 !(bevent->state & GDK_SHIFT_MASK ) &&
672 !(bevent->state & GDK_CONTROL_MASK ) &&
673 vflist_row_is_selected(vf, fd))
675 GtkTreeSelection *selection;
677 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
678 gtk_tree_selection_unselect_all(selection);
679 gtk_tree_selection_select_iter(selection, &iter);
680 vflist_move_cursor(vf, &iter);
681 // return TRUE;// FIXME - expand
687 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
689 FileData *read_ahead_fd = NULL;
694 cur_fd = layout_image_get_fd(vf->layout);
695 if (sel_fd == cur_fd) return; /* no change */
697 row = g_list_index(vf->list, sel_fd);
698 // FIXME sidecar data
700 if (sel_fd && options->image.enable_read_ahead && row >= 0)
702 if (row > g_list_index(vf->list, cur_fd) &&
703 (guint) (row + 1) < vf_count(vf, NULL))
705 read_ahead_fd = vf_index_get_data(vf, row + 1);
709 read_ahead_fd = vf_index_get_data(vf, row - 1);
713 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
716 static gint vflist_select_idle_cb(gpointer data)
722 VFLIST(vf)->select_idle_id = -1;
728 if (VFLIST(vf)->select_fd)
730 vflist_select_image(vf, VFLIST(vf)->select_fd);
731 VFLIST(vf)->select_fd = NULL;
734 VFLIST(vf)->select_idle_id = -1;
738 static void vflist_select_idle_cancel(ViewFile *vf)
740 if (VFLIST(vf)->select_idle_id != -1) g_source_remove(VFLIST(vf)->select_idle_id);
741 VFLIST(vf)->select_idle_id = -1;
744 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
745 gboolean path_currently_selected, gpointer data)
750 if (!path_currently_selected &&
751 gtk_tree_model_get_iter(store, &iter, tpath))
753 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
757 VFLIST(vf)->select_fd = NULL;
761 VFLIST(vf)->select_idle_id == -1)
763 VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
770 *-----------------------------------------------------------------------------
772 *-----------------------------------------------------------------------------
776 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
777 gboolean path_currently_selected, gpointer data)
783 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
786 gchar *sidecars = NULL;
787 gchar *name_sidecars;
789 const gchar *time = text_from_time(fd->date);
790 gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
793 if (fd->sidecar_files)
795 sidecars = file_data_sc_list_to_string(fd);
796 name_sidecars = g_strdup_printf("%s%s %s", link, fd->name, sidecars);
800 name_sidecars = g_strdup_printf("%s%s", link, fd->name);
802 size = text_from_size(fd->size);
804 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
806 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
807 FILE_COLUMN_VERSION, fd->version,
808 FILE_COLUMN_THUMB, fd->thumb_pixbuf,
809 FILE_COLUMN_MULTILINE, multiline,
810 FILE_COLUMN_NAME, name_sidecars,
811 FILE_COLUMN_SIZE, size,
812 FILE_COLUMN_DATE, time,
813 #define STORE_SET_IS_SLOW 1
814 #if STORE_SET_IS_SLOW
815 /* this is 3x faster on a directory with 20000 files */
816 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
817 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
818 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
819 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
820 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
821 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
822 #if FILEDATA_MARKS_SIZE != 6
823 #error this needs to be updated
826 FILE_COLUMN_COLOR, FALSE, -1);
828 #if !STORE_SET_IS_SLOW
831 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
832 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
837 g_free(name_sidecars);
841 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
846 gint num_ordered = 0;
847 gint num_prepended = 0;
849 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
855 FileData *fd = work->data;
860 FileData *old_fd = NULL;
861 gint old_version = 0;
866 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
867 FILE_COLUMN_POINTER, &old_fd,
868 FILE_COLUMN_VERSION, &old_version,
878 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
880 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
882 if (match == 0) g_warning("multiple fd for the same path");
897 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
902 here should be used gtk_tree_store_append, but this function seems to be O(n)
903 and it seems to be much faster to add new entries to the beginning and reorder later
906 gtk_tree_store_prepend(store, &new, parent_iter);
909 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
910 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
912 if (g_list_find(selected, fd))
914 /* renamed files - the same fd appears at different position - select it again*/
915 GtkTreeSelection *selection;
916 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
917 gtk_tree_selection_select_iter(selection, &new);
924 file_data_unref(old_fd);
925 valid = gtk_tree_store_remove(store, &iter);
929 if (fd->version != old_version)
931 vflist_setup_iter(vf, store, &iter, fd);
932 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
935 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
946 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
947 file_data_unref(old_fd);
949 valid = gtk_tree_store_remove(store, &iter);
952 /* move the prepended entries to the correct position */
956 gint num_total = num_prepended + num_ordered;
957 gint *new_order = g_malloc(num_total * sizeof(gint));
959 for (i = 0; i < num_total; i++)
962 new_order[i] = num_prepended + i;
964 new_order[i] = num_total - 1 - i;
966 gtk_tree_store_reorder(store, parent_iter, new_order);
972 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
975 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
980 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
981 if (!vf->list) return;
987 FileData *fd = work->data;
988 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
993 vf->sort_method = type;
994 vf->sort_ascend = ascend;
996 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
998 new_order = g_malloc(i * sizeof(gint));
1004 FileData *fd = work->data;
1005 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
1010 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1011 gtk_tree_store_reorder(store, NULL, new_order);
1014 g_hash_table_destroy(fd_idx_hash);
1018 *-----------------------------------------------------------------------------
1020 *-----------------------------------------------------------------------------
1023 static gint vflist_thumb_next(ViewFile *vf);
1025 static void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
1030 FileData *fd = work->data;
1033 if (fd->thumb_pixbuf) (*done)++;
1035 if (fd->sidecar_files)
1037 vflist_thumb_progress_count(fd->sidecar_files, count, done);
1043 static gdouble vflist_thumb_progress(ViewFile *vf)
1048 vflist_thumb_progress_count(vf->list, &count, &done);
1050 DEBUG_1("thumb progress: %d of %d", done, count);
1051 return (gdouble)done / count;
1055 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
1057 if (vf->func_thumb_status)
1059 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1063 static void vflist_thumb_cleanup(ViewFile *vf)
1065 vflist_thumb_status(vf, 0.0, NULL);
1067 vf->thumbs_running = FALSE;
1069 thumb_loader_free(vf->thumbs_loader);
1070 vf->thumbs_loader = NULL;
1072 vf->thumbs_filedata = NULL;
1075 static void vflist_thumb_stop(ViewFile *vf)
1077 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1080 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1082 GtkTreeStore *store;
1085 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1087 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1088 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1090 vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
1093 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1095 ViewFile *vf = data;
1097 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1099 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1102 while (vflist_thumb_next(vf));
1105 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1107 ViewFile *vf = data;
1109 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1111 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1114 while (vflist_thumb_next(vf));
1117 static gint vflist_thumb_next(ViewFile *vf)
1120 FileData *fd = NULL;
1122 /* first check the visible files */
1124 if (GTK_WIDGET_REALIZED(vf->listview) &&
1125 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1127 GtkTreeModel *store;
1131 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1132 gtk_tree_model_get_iter(store, &iter, tpath);
1133 gtk_tree_path_free(tpath);
1135 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1137 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1138 if (fd->thumb_pixbuf) fd = NULL;
1140 valid = gtk_tree_model_iter_next(store, &iter);
1144 /* then find first undone */
1148 GList *work = vf->list;
1151 FileData *fd_p = work->data;
1152 if (!fd_p->thumb_pixbuf)
1156 GList *work2 = fd_p->sidecar_files;
1158 while (work2 && !fd)
1161 if (!fd_p->thumb_pixbuf) fd = fd_p;
1162 work2 = work2->next;
1172 vflist_thumb_cleanup(vf);
1176 vf->thumbs_filedata = fd;
1178 thumb_loader_free(vf->thumbs_loader);
1180 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1181 thumb_loader_set_callbacks(vf->thumbs_loader,
1182 vflist_thumb_done_cb,
1183 vflist_thumb_error_cb,
1187 if (!thumb_loader_start(vf->thumbs_loader, fd))
1189 /* set icon to unknown, continue */
1190 DEBUG_1("thumb loader start failed %s", fd->path);
1191 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1199 static void vflist_thumb_update(ViewFile *vf)
1201 vflist_thumb_stop(vf);
1202 if (!VFLIST(vf)->thumbs_enabled) return;
1204 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1205 vf->thumbs_running = TRUE;
1207 while (vflist_thumb_next(vf));
1211 *-----------------------------------------------------------------------------
1213 *-----------------------------------------------------------------------------
1216 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1218 return g_list_nth_data(vf->list, row);
1221 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1226 if (!path) return -1;
1231 FileData *fd = work->data;
1232 if (strcmp(path, fd->path) == 0) return p;
1241 guint vflist_count(ViewFile *vf, gint64 *bytes)
1251 FileData *fd = work->data;
1259 return g_list_length(vf->list);
1262 GList *vflist_get_list(ViewFile *vf)
1270 FileData *fd = work->data;
1273 list = g_list_prepend(list, file_data_ref(fd));
1276 return g_list_reverse(list);
1280 *-----------------------------------------------------------------------------
1282 *-----------------------------------------------------------------------------
1285 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1287 GtkTreeModel *store;
1288 GtkTreeSelection *selection;
1293 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1294 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1296 while (!found && work)
1298 GtkTreePath *tpath = work->data;
1302 gtk_tree_model_get_iter(store, &iter, tpath);
1303 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1304 if (fd_n == fd) found = TRUE;
1307 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1313 gint vflist_index_is_selected(ViewFile *vf, gint row)
1317 fd = vf_index_get_data(vf, row);
1318 return vflist_row_is_selected(vf, fd);
1321 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1323 GtkTreeModel *store;
1324 GtkTreeSelection *selection;
1328 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1329 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1339 GtkTreePath *tpath = work->data;
1343 gtk_tree_model_get_iter(store, &iter, tpath);
1344 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1353 count = g_list_length(slist);
1354 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1360 GList *vflist_selection_get_list(ViewFile *vf)
1362 GtkTreeModel *store;
1363 GtkTreeSelection *selection;
1368 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1369 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1373 GtkTreePath *tpath = work->data;
1377 gtk_tree_model_get_iter(store, &iter, tpath);
1378 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1380 list = g_list_prepend(list, file_data_ref(fd));
1384 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1387 return g_list_reverse(list);
1390 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1392 GtkTreeModel *store;
1393 GtkTreeSelection *selection;
1398 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1399 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1403 GtkTreePath *tpath = work->data;
1407 gtk_tree_model_get_iter(store, &iter, tpath);
1408 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1410 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1414 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1417 return g_list_reverse(list);
1420 void vflist_select_all(ViewFile *vf)
1422 GtkTreeSelection *selection;
1424 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1425 gtk_tree_selection_select_all(selection);
1427 VFLIST(vf)->select_fd = NULL;
1430 void vflist_select_none(ViewFile *vf)
1432 GtkTreeSelection *selection;
1434 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1435 gtk_tree_selection_unselect_all(selection);
1438 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1443 tpath = gtk_tree_model_get_path(store, iter);
1444 result = gtk_tree_path_prev(tpath);
1446 gtk_tree_model_get_iter(store, iter, tpath);
1448 gtk_tree_path_free(tpath);
1453 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1455 if (!gtk_tree_model_get_iter_first(store, iter))
1460 GtkTreeIter next = *iter;
1462 if (gtk_tree_model_iter_next(store, &next))
1471 void vflist_select_invert(ViewFile *vf)
1474 GtkTreeSelection *selection;
1475 GtkTreeModel *store;
1478 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1479 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1481 /* Backward iteration prevents scrolling to the end of the list,
1482 * it scrolls to the first selected row instead. */
1483 valid = tree_model_get_iter_last(store, &iter);
1487 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1490 gtk_tree_selection_unselect_iter(selection, &iter);
1492 gtk_tree_selection_select_iter(selection, &iter);
1494 valid = tree_model_iter_prev(store, &iter);
1498 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1502 if (vflist_find_row(vf, fd, &iter) < 0) return;
1504 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1506 if (!vflist_row_is_selected(vf, fd))
1508 GtkTreeSelection *selection;
1509 GtkTreeModel *store;
1512 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1513 gtk_tree_selection_unselect_all(selection);
1514 gtk_tree_selection_select_iter(selection, &iter);
1515 vflist_move_cursor(vf, &iter);
1517 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1518 tpath = gtk_tree_model_get_path(store, &iter);
1519 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1520 gtk_tree_path_free(tpath);
1524 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1527 FileData *fd = NULL;
1529 if (sel_fd->parent) sel_fd = sel_fd->parent;
1538 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1540 if (match >= 0) break;
1543 if (fd) vflist_select_by_fd(vf, fd);
1547 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1549 GtkTreeModel *store;
1551 GtkTreeSelection *selection;
1555 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1557 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1558 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1560 valid = gtk_tree_model_get_iter_first(store, &iter);
1564 gboolean mark_val, selected;
1565 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1567 mark_val = file_data_get_mark(fd, n);
1568 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1572 case MTS_MODE_SET: selected = mark_val;
1574 case MTS_MODE_OR: selected = mark_val | selected;
1576 case MTS_MODE_AND: selected = mark_val & selected;
1578 case MTS_MODE_MINUS: selected = !mark_val & selected;
1583 gtk_tree_selection_select_iter(selection, &iter);
1585 gtk_tree_selection_unselect_iter(selection, &iter);
1587 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1591 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1593 GtkTreeModel *store;
1594 GtkTreeSelection *selection;
1599 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1601 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1602 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1606 GtkTreePath *tpath = work->data;
1610 gtk_tree_model_get_iter(store, &iter, tpath);
1611 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1613 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1617 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1619 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1621 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1625 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1627 vf_refresh_idle(vf);
1631 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1633 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1637 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1642 *-----------------------------------------------------------------------------
1644 *-----------------------------------------------------------------------------
1647 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1649 GtkTreeViewColumn *column;
1650 GtkCellRenderer *cell;
1654 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1655 if (!column) return;
1657 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1659 list = gtk_tree_view_column_get_cell_renderers(column);
1664 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1665 gtk_tree_view_column_set_visible(column, thumb);
1667 multiline = (thumb && options->thumbnails.max_height >= 48);
1669 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1670 if (!column) return;
1671 gtk_tree_view_column_set_visible(column, multiline);
1672 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1674 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1675 if (!column) return;
1676 gtk_tree_view_column_set_visible(column, !multiline);
1677 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1679 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1680 if (!column) return;
1681 gtk_tree_view_column_set_visible(column, !multiline);
1683 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1684 if (!column) return;
1685 gtk_tree_view_column_set_visible(column, !multiline);
1687 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1690 static void vflist_populate_view(ViewFile *vf)
1692 GtkTreeStore *store;
1696 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1697 thumbs = VFLIST(vf)->thumbs_enabled;
1699 vflist_thumb_stop(vf);
1703 vflist_store_clear(vf);
1708 vflist_listview_set_columns(vf->listview, thumbs);
1710 selected = vflist_selection_get_list(vf);
1712 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1714 if (selected && vflist_selection_count(vf, NULL) == 0)
1716 /* all selected files disappeared */
1717 vflist_select_closest(vf, selected->data);
1720 filelist_free(selected);
1723 vflist_thumb_update(vf);
1726 gint vflist_refresh(ViewFile *vf)
1731 old_list = vf->list;
1734 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1737 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1739 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1740 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1741 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1743 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1744 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1747 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1749 vflist_populate_view(vf);
1751 filelist_free(old_list);
1752 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1759 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1761 #define CELL_HEIGHT_OVERRIDE 512
1763 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1767 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1768 if (spec && G_IS_PARAM_SPEC_INT(spec))
1770 GParamSpecInt *spec_int;
1772 spec_int = G_PARAM_SPEC_INT(spec);
1773 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1777 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1779 static GdkColor color;
1780 static GtkWidget *done = NULL;
1786 style = gtk_widget_get_style(widget);
1787 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1788 shift_color(&color, -1, 0);
1795 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1796 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1798 ViewFile *vf = data;
1801 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1802 g_object_set(G_OBJECT(cell),
1803 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1804 "cell-background-set", set, NULL);
1807 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1809 GtkTreeViewColumn *column;
1810 GtkCellRenderer *renderer;
1812 column = gtk_tree_view_column_new();
1813 gtk_tree_view_column_set_title(column, title);
1814 gtk_tree_view_column_set_min_width(column, 4);
1818 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1819 renderer = gtk_cell_renderer_text_new();
1822 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1824 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1825 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1827 gtk_tree_view_column_set_expand(column, TRUE);
1831 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1832 renderer = gtk_cell_renderer_pixbuf_new();
1833 cell_renderer_height_override(renderer);
1834 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1835 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1838 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1839 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1840 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1842 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1845 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1847 ViewFile *vf = data;
1848 GtkTreeStore *store;
1849 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1855 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1856 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1859 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1861 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1863 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1865 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1866 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1867 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1869 vf_refresh_idle(vf);
1871 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1873 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1874 gtk_tree_path_free(path);
1877 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1879 GtkTreeViewColumn *column;
1880 GtkCellRenderer *renderer;
1881 GtkTreeStore *store;
1884 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1886 renderer = gtk_cell_renderer_toggle_new();
1887 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1889 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1890 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1891 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1893 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1894 gtk_tree_view_column_set_fixed_width(column, 22);
1895 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1898 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1902 *-----------------------------------------------------------------------------
1904 *-----------------------------------------------------------------------------
1907 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1909 if (!dir_fd) return FALSE;
1910 if (vf->dir_fd == dir_fd) return TRUE;
1912 file_data_unref(vf->dir_fd);
1913 vf->dir_fd = file_data_ref(dir_fd);
1915 /* force complete reload */
1916 vflist_store_clear(vf);
1918 filelist_free(vf->list);
1921 return vf_refresh(vf);
1924 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1926 ViewFile *vf = data;
1928 file_data_unregister_notify_func(vf_notify_cb, vf);
1930 vflist_select_idle_cancel(vf);
1931 vf_refresh_idle_cancel(vf);
1932 vflist_thumb_stop(vf);
1934 filelist_free(vf->list);
1937 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1939 GtkTreeStore *store;
1940 GtkTreeSelection *selection;
1942 GType flist_types[FILE_COLUMN_COUNT];
1946 vf->info = g_new0(ViewFileInfoList, 1);
1948 VFLIST(vf)->click_fd = NULL;
1949 VFLIST(vf)->select_fd = NULL;
1950 VFLIST(vf)->thumbs_enabled = FALSE;
1952 VFLIST(vf)->select_idle_id = -1;
1954 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1955 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1956 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1957 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1958 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1959 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1960 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1961 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1962 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1963 flist_types[i] = G_TYPE_BOOLEAN;
1965 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1967 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1968 g_object_unref(store);
1970 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1971 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1972 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1974 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1975 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1979 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1981 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1982 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1986 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1987 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1990 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1991 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1994 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1995 g_assert(column == FILE_VIEW_COLUMN_NAME);
1998 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1999 g_assert(column == FILE_VIEW_COLUMN_SIZE);
2002 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
2003 g_assert(column == FILE_VIEW_COLUMN_DATE);
2006 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
2010 void vflist_thumb_set(ViewFile *vf, gint enable)
2012 if (VFLIST(vf)->thumbs_enabled == enable) return;
2014 VFLIST(vf)->thumbs_enabled = enable;
2015 if (vf->layout) vf_refresh(vf);
2018 void vflist_marks_set(ViewFile *vf, gint enable)
2020 GList *columns, *work;
2022 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
2027 GtkTreeViewColumn *column = work->data;
2028 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
2031 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
2032 gtk_tree_view_column_set_visible(column, enable);
2035 g_list_free(columns);
2039 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */