4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
14 #include "view_file_list.h"
17 #include "cache_maint.h"
23 #include "layout_image.h"
28 #include "ui_fileops.h"
30 #include "ui_tree_edit.h"
31 #include "uri_utils.h"
32 #include "view_file.h"
34 #include <gdk/gdkkeysyms.h> /* for keyboard values */
36 /* Index to tree store */
38 FILE_COLUMN_POINTER = 0,
42 FILE_COLUMN_MULTILINE,
47 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
52 /* Index to tree view */
54 FILE_VIEW_COLUMN_MARKS = 0,
55 FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
56 FILE_VIEW_COLUMN_THUMB,
57 FILE_VIEW_COLUMN_MULTILINE,
58 FILE_VIEW_COLUMN_NAME,
59 FILE_VIEW_COLUMN_SIZE,
60 FILE_VIEW_COLUMN_DATE,
61 FILE_VIEW_COLUMN_COUNT
66 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
67 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
68 static void vflist_populate_view(ViewFile *vf);
72 *-----------------------------------------------------------------------------
74 *-----------------------------------------------------------------------------
81 } ViewFileFindRowData;
83 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
85 ViewFileFindRowData *find = data;
87 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
98 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
101 ViewFileFindRowData data = {fd, iter, 0, 0};
103 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
104 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
114 static FileData *vflist_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
117 GtkTreeViewColumn *column;
119 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
120 &tpath, &column, NULL, NULL))
126 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
127 gtk_tree_model_get_iter(store, &row, tpath);
128 gtk_tree_path_free(tpath);
129 gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &fd, -1);
138 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
143 FileData *fd_p = work->data;
144 if (fd == fd_p) return i;
148 GList *work2 = fd_p->sidecar_files;
152 if (fd == fd_p) return i;
162 static gint vflist_sidecar_list_count(GList *work)
167 FileData *fd = work->data;
170 GList *work2 = fd->sidecar_files;
182 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
185 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
190 static void vflist_store_clear(ViewFile *vf)
193 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
194 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
195 gtk_tree_store_clear(GTK_TREE_STORE(store));
198 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
203 if (vflist_find_row(vf, fd, &iter) < 0) return;
204 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
205 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
208 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
213 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
215 tpath = gtk_tree_model_get_path(store, iter);
216 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
217 gtk_tree_path_free(tpath);
221 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
223 GList *columns, *work;
226 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
230 GtkTreeViewColumn *column = work->data;
231 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
237 g_list_free(columns);
243 *-----------------------------------------------------------------------------
245 *-----------------------------------------------------------------------------
248 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
249 GtkSelectionData *selection_data, guint info,
250 guint time, gpointer data)
254 gchar *uri_text = NULL;
257 if (!VFLIST(vf)->click_fd) return;
259 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
261 list = vf_selection_get_list(vf);
265 list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
270 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
273 DEBUG_1("%s", uri_text);
275 gtk_selection_data_set(selection_data, selection_data->target,
276 8, (guchar *)uri_text, total);
280 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
284 vflist_color_set(vf, VFLIST(vf)->click_fd, TRUE);
286 if (VFLIST(vf)->thumbs_enabled &&
287 VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
291 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
292 items = vf_selection_count(vf, NULL);
296 dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
300 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
304 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
306 if (context->action == GDK_ACTION_MOVE)
312 static void vflist_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
313 int x, int y, GtkSelectionData *selection,
314 guint info, guint time, gpointer data)
318 if (info == TARGET_TEXT_PLAIN) {
319 FileData *fd = vflist_find_data_by_coord(vf, x, y, NULL);
322 /* Add keywords to file */
323 gchar *str = g_strndup(selection->data, selection->length);
324 GList *kw_list = string_to_keywords_list(str);
326 metadata_set(fd, kw_list, NULL, TRUE);
327 string_list_free(kw_list);
329 if (vf->layout && vf->layout->bar_info) {
330 bar_info_set(vf->layout->bar_info, fd);
336 void vflist_dnd_init(ViewFile *vf)
338 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
339 dnd_file_drag_types, dnd_file_drag_types_count,
340 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
341 gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
342 dnd_file_drag_types, dnd_file_drag_types_count,
343 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
345 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
346 G_CALLBACK(vflist_dnd_get), vf);
347 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
348 G_CALLBACK(vflist_dnd_begin), vf);
349 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
350 G_CALLBACK(vflist_dnd_end), vf);
351 g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
352 G_CALLBACK(vflist_drag_data_received), vf);
356 *-----------------------------------------------------------------------------
358 *-----------------------------------------------------------------------------
361 GList *vflist_pop_menu_file_list(ViewFile *vf)
363 if (!VFLIST(vf)->click_fd) return NULL;
365 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
367 return vf_selection_get_list(vf);
370 return g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
373 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
377 if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
381 list = vf_selection_get_list(vf);
382 view_window_new_from_list(list);
387 view_window_new(VFLIST(vf)->click_fd);
391 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
396 list = vf_pop_menu_file_list(vf);
397 if (options->file_ops.enable_in_place_rename &&
398 list && !list->next && VFLIST(vf)->click_fd)
405 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
406 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
410 tpath = gtk_tree_model_get_path(store, &iter);
411 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
412 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST(vf)->click_fd->name,
413 vflist_row_rename_cb, vf);
414 gtk_tree_path_free(tpath);
419 file_util_rename(NULL, list, vf->listview);
422 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
426 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
429 layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
433 vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
437 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
441 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
445 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
448 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
449 VFLIST(vf)->click_fd = NULL;
455 *-----------------------------------------------------------------------------
457 *-----------------------------------------------------------------------------
460 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
466 if (strlen(new) == 0) return FALSE;
468 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
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 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
480 file_util_rename_simple(fd, new_path, vf->listview);
489 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
497 if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
498 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
499 tpath = gtk_tree_model_get_path(store, &iter);
500 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
501 gtk_tree_path_free(tpath);
503 popup_menu_position_clamp(menu, x, y, 0);
506 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
511 if (event->keyval != GDK_Menu) return FALSE;
513 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
519 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
520 gtk_tree_model_get_iter(store, &iter, tpath);
521 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
522 gtk_tree_path_free(tpath);
526 VFLIST(vf)->click_fd = NULL;
529 vf->popup = vf_pop_menu(vf);
530 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
535 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
541 GtkTreeViewColumn *column;
543 vf->clicked_mark = 0;
545 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
546 &tpath, &column, NULL, NULL))
549 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
551 if (bevent->button == MOUSE_BUTTON_LEFT &&
552 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
555 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
556 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
558 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
560 gtk_tree_model_get_iter(store, &iter, tpath);
561 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
563 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
565 gtk_tree_path_free(tpath);
568 VFLIST(vf)->click_fd = fd;
570 if (bevent->button == MOUSE_BUTTON_RIGHT)
572 vf->popup = vf_pop_menu(vf);
573 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
574 bevent->button, bevent->time);
578 if (!fd) return FALSE;
580 if (bevent->button == MOUSE_BUTTON_MIDDLE)
582 if (!vflist_row_is_selected(vf, fd))
584 vflist_color_set(vf, fd, TRUE);
590 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
591 !(bevent->state & GDK_SHIFT_MASK ) &&
592 !(bevent->state & GDK_CONTROL_MASK ) &&
593 vflist_row_is_selected(vf, fd))
595 GtkTreeSelection *selection;
597 gtk_widget_grab_focus(widget);
600 /* returning FALSE and further processing of the event is needed for
601 correct operation of the expander, to show the sidecar files.
602 It however resets the selection of multiple files. With this condition
603 it should work for both cases */
604 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
605 return (gtk_tree_selection_count_selected_rows(selection) > 1);
609 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
611 if (vf->layout) layout_image_full_screen_start(vf->layout);
618 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
625 if (bevent->button == MOUSE_BUTTON_MIDDLE)
627 vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
630 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
635 if ((bevent->x != 0 || bevent->y != 0) &&
636 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
637 &tpath, NULL, NULL, NULL))
641 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
642 gtk_tree_model_get_iter(store, &iter, tpath);
643 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
644 gtk_tree_path_free(tpath);
647 if (bevent->button == MOUSE_BUTTON_MIDDLE)
649 if (fd && VFLIST(vf)->click_fd == fd)
651 GtkTreeSelection *selection;
653 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
654 if (vflist_row_is_selected(vf, fd))
656 gtk_tree_selection_unselect_iter(selection, &iter);
660 gtk_tree_selection_select_iter(selection, &iter);
666 if (fd && VFLIST(vf)->click_fd == fd &&
667 !(bevent->state & GDK_SHIFT_MASK ) &&
668 !(bevent->state & GDK_CONTROL_MASK ) &&
669 vflist_row_is_selected(vf, fd))
671 GtkTreeSelection *selection;
673 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
674 gtk_tree_selection_unselect_all(selection);
675 gtk_tree_selection_select_iter(selection, &iter);
676 vflist_move_cursor(vf, &iter);
677 // return TRUE;// FIXME - expand
683 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
685 FileData *read_ahead_fd = NULL;
690 cur_fd = layout_image_get_fd(vf->layout);
691 if (sel_fd == cur_fd) return; /* no change */
693 row = g_list_index(vf->list, sel_fd);
694 // FIXME sidecar data
696 if (sel_fd && options->image.enable_read_ahead && row >= 0)
698 if (row > g_list_index(vf->list, cur_fd) &&
699 (guint) (row + 1) < vf_count(vf, NULL))
701 read_ahead_fd = vf_index_get_data(vf, row + 1);
705 read_ahead_fd = vf_index_get_data(vf, row - 1);
709 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
712 static gint vflist_select_idle_cb(gpointer data)
718 VFLIST(vf)->select_idle_id = -1;
724 if (VFLIST(vf)->select_fd)
726 vflist_select_image(vf, VFLIST(vf)->select_fd);
727 VFLIST(vf)->select_fd = NULL;
730 VFLIST(vf)->select_idle_id = -1;
734 static void vflist_select_idle_cancel(ViewFile *vf)
736 if (VFLIST(vf)->select_idle_id != -1) g_source_remove(VFLIST(vf)->select_idle_id);
737 VFLIST(vf)->select_idle_id = -1;
740 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
741 gboolean path_currently_selected, gpointer data)
746 if (!path_currently_selected &&
747 gtk_tree_model_get_iter(store, &iter, tpath))
749 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
753 VFLIST(vf)->select_fd = NULL;
757 VFLIST(vf)->select_idle_id == -1)
759 VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
766 *-----------------------------------------------------------------------------
768 *-----------------------------------------------------------------------------
772 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
773 gboolean path_currently_selected, gpointer data)
779 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
782 gchar *sidecars = NULL;
783 gchar *name_sidecars;
785 const gchar *time = text_from_time(fd->date);
786 name_sidecars = (gchar *)fd->name;
788 if (fd->sidecar_files)
790 sidecars = file_data_sc_list_to_string(fd);
791 name_sidecars = g_strdup_printf("%s %s", fd->name, sidecars);
793 size = text_from_size(fd->size);
795 multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
797 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
798 FILE_COLUMN_VERSION, fd->version,
799 FILE_COLUMN_THUMB, fd->thumb_pixbuf,
800 FILE_COLUMN_MULTILINE, multiline,
801 FILE_COLUMN_NAME, name_sidecars,
802 FILE_COLUMN_SIZE, size,
803 FILE_COLUMN_DATE, time,
804 #define STORE_SET_IS_SLOW 1
805 #if STORE_SET_IS_SLOW
806 /* this is 3x faster on a directory with 20000 files */
807 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
808 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
809 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
810 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
811 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
812 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
813 #if FILEDATA_MARKS_SIZE != 6
814 #error this needs to be updated
817 FILE_COLUMN_COLOR, FALSE, -1);
819 #if !STORE_SET_IS_SLOW
822 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
823 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
830 g_free(name_sidecars);
835 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
840 gint num_ordered = 0;
841 gint num_prepended = 0;
843 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
849 FileData *fd = work->data;
854 FileData *old_fd = NULL;
855 gint old_version = 0;
860 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
861 FILE_COLUMN_POINTER, &old_fd,
862 FILE_COLUMN_VERSION, &old_version,
872 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
874 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
876 if (match == 0) g_warning("multiple fd for the same path");
891 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
896 here should be used gtk_tree_store_append, but this function seems to be O(n)
897 and it seems to be much faster to add new entries to the beginning and reorder later
900 gtk_tree_store_prepend(store, &new, parent_iter);
903 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
904 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
906 if (g_list_find(selected, fd))
908 /* renamed files - the same fd appears at different position - select it again*/
909 GtkTreeSelection *selection;
910 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
911 gtk_tree_selection_select_iter(selection, &new);
918 file_data_unref(old_fd);
919 valid = gtk_tree_store_remove(store, &iter);
923 if (fd->version != old_version)
925 vflist_setup_iter(vf, store, &iter, fd);
926 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
929 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
940 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
941 file_data_unref(old_fd);
943 valid = gtk_tree_store_remove(store, &iter);
946 /* move the prepended entries to the correct position */
950 gint num_total = num_prepended + num_ordered;
951 gint *new_order = g_malloc(num_total * sizeof(gint));
953 for (i = 0; i < num_total; i++)
956 new_order[i] = num_prepended + i;
958 new_order[i] = num_total - 1 - i;
960 gtk_tree_store_reorder(store, parent_iter, new_order);
966 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
969 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
974 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
975 if (!vf->list) return;
981 FileData *fd = work->data;
982 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
987 vf->sort_method = type;
988 vf->sort_ascend = ascend;
990 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
992 new_order = g_malloc(i * sizeof(gint));
998 FileData *fd = work->data;
999 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
1004 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1005 gtk_tree_store_reorder(store, NULL, new_order);
1008 g_hash_table_destroy(fd_idx_hash);
1012 *-----------------------------------------------------------------------------
1014 *-----------------------------------------------------------------------------
1017 static gint vflist_thumb_next(ViewFile *vf);
1019 static void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
1024 FileData *fd = work->data;
1027 if (fd->thumb_pixbuf) (*done)++;
1029 if (fd->sidecar_files)
1031 vflist_thumb_progress_count(fd->sidecar_files, count, done);
1037 static gdouble vflist_thumb_progress(ViewFile *vf)
1042 vflist_thumb_progress_count(vf->list, &count, &done);
1044 DEBUG_1("thumb progress: %d of %d", done, count);
1045 return (gdouble)done / count;
1049 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
1051 if (vf->func_thumb_status)
1053 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1057 static void vflist_thumb_cleanup(ViewFile *vf)
1059 vflist_thumb_status(vf, 0.0, NULL);
1061 vf->thumbs_running = FALSE;
1063 thumb_loader_free(vf->thumbs_loader);
1064 vf->thumbs_loader = NULL;
1066 vf->thumbs_filedata = NULL;
1069 static void vflist_thumb_stop(ViewFile *vf)
1071 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1074 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1076 GtkTreeStore *store;
1079 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1081 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1082 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1084 vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
1087 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1089 ViewFile *vf = data;
1091 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1093 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1096 while (vflist_thumb_next(vf));
1099 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1101 ViewFile *vf = data;
1103 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1105 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1108 while (vflist_thumb_next(vf));
1111 static gint vflist_thumb_next(ViewFile *vf)
1114 FileData *fd = NULL;
1116 /* first check the visible files */
1118 if (GTK_WIDGET_REALIZED(vf->listview) &&
1119 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1121 GtkTreeModel *store;
1125 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1126 gtk_tree_model_get_iter(store, &iter, tpath);
1127 gtk_tree_path_free(tpath);
1129 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1131 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1132 if (fd->thumb_pixbuf) fd = NULL;
1134 valid = gtk_tree_model_iter_next(store, &iter);
1138 /* then find first undone */
1142 GList *work = vf->list;
1145 FileData *fd_p = work->data;
1146 if (!fd_p->thumb_pixbuf)
1150 GList *work2 = fd_p->sidecar_files;
1152 while (work2 && !fd)
1155 if (!fd_p->thumb_pixbuf) fd = fd_p;
1156 work2 = work2->next;
1166 vflist_thumb_cleanup(vf);
1170 vf->thumbs_filedata = fd;
1172 thumb_loader_free(vf->thumbs_loader);
1174 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1175 thumb_loader_set_callbacks(vf->thumbs_loader,
1176 vflist_thumb_done_cb,
1177 vflist_thumb_error_cb,
1181 if (!thumb_loader_start(vf->thumbs_loader, fd))
1183 /* set icon to unknown, continue */
1184 DEBUG_1("thumb loader start failed %s", fd->path);
1185 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1193 static void vflist_thumb_update(ViewFile *vf)
1195 vflist_thumb_stop(vf);
1196 if (!VFLIST(vf)->thumbs_enabled) return;
1198 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1199 vf->thumbs_running = TRUE;
1201 while (vflist_thumb_next(vf));
1205 *-----------------------------------------------------------------------------
1207 *-----------------------------------------------------------------------------
1210 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1212 return g_list_nth_data(vf->list, row);
1215 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1220 if (!path) return -1;
1225 FileData *fd = work->data;
1226 if (strcmp(path, fd->path) == 0) return p;
1235 guint vflist_count(ViewFile *vf, gint64 *bytes)
1245 FileData *fd = work->data;
1253 return g_list_length(vf->list);
1256 GList *vflist_get_list(ViewFile *vf)
1264 FileData *fd = work->data;
1267 list = g_list_prepend(list, file_data_ref(fd));
1270 return g_list_reverse(list);
1274 *-----------------------------------------------------------------------------
1276 *-----------------------------------------------------------------------------
1279 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1281 GtkTreeModel *store;
1282 GtkTreeSelection *selection;
1287 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1288 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1290 while (!found && work)
1292 GtkTreePath *tpath = work->data;
1296 gtk_tree_model_get_iter(store, &iter, tpath);
1297 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1298 if (fd_n == fd) found = TRUE;
1301 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1307 gint vflist_index_is_selected(ViewFile *vf, gint row)
1311 fd = vf_index_get_data(vf, row);
1312 return vflist_row_is_selected(vf, fd);
1315 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1317 GtkTreeModel *store;
1318 GtkTreeSelection *selection;
1322 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1323 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1333 GtkTreePath *tpath = work->data;
1337 gtk_tree_model_get_iter(store, &iter, tpath);
1338 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1347 count = g_list_length(slist);
1348 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1354 GList *vflist_selection_get_list(ViewFile *vf)
1356 GtkTreeModel *store;
1357 GtkTreeSelection *selection;
1362 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1363 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1367 GtkTreePath *tpath = work->data;
1371 gtk_tree_model_get_iter(store, &iter, tpath);
1372 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1374 list = g_list_prepend(list, file_data_ref(fd));
1378 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1381 return g_list_reverse(list);
1384 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1386 GtkTreeModel *store;
1387 GtkTreeSelection *selection;
1392 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1393 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1397 GtkTreePath *tpath = work->data;
1401 gtk_tree_model_get_iter(store, &iter, tpath);
1402 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1404 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1408 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1411 return g_list_reverse(list);
1414 void vflist_select_all(ViewFile *vf)
1416 GtkTreeSelection *selection;
1418 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1419 gtk_tree_selection_select_all(selection);
1421 VFLIST(vf)->select_fd = NULL;
1424 void vflist_select_none(ViewFile *vf)
1426 GtkTreeSelection *selection;
1428 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1429 gtk_tree_selection_unselect_all(selection);
1432 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1437 tpath = gtk_tree_model_get_path(store, iter);
1438 result = gtk_tree_path_prev(tpath);
1440 gtk_tree_model_get_iter(store, iter, tpath);
1442 gtk_tree_path_free(tpath);
1447 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1449 if (!gtk_tree_model_get_iter_first(store, iter))
1454 GtkTreeIter next = *iter;
1456 if (gtk_tree_model_iter_next(store, &next))
1465 void vflist_select_invert(ViewFile *vf)
1468 GtkTreeSelection *selection;
1469 GtkTreeModel *store;
1472 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1473 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1475 /* Backward iteration prevents scrolling to the end of the list,
1476 * it scrolls to the first selected row instead. */
1477 valid = tree_model_get_iter_last(store, &iter);
1481 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1484 gtk_tree_selection_unselect_iter(selection, &iter);
1486 gtk_tree_selection_select_iter(selection, &iter);
1488 valid = tree_model_iter_prev(store, &iter);
1492 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1496 if (vflist_find_row(vf, fd, &iter) < 0) return;
1498 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1500 if (!vflist_row_is_selected(vf, fd))
1502 GtkTreeSelection *selection;
1503 GtkTreeModel *store;
1506 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1507 gtk_tree_selection_unselect_all(selection);
1508 gtk_tree_selection_select_iter(selection, &iter);
1509 vflist_move_cursor(vf, &iter);
1511 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1512 tpath = gtk_tree_model_get_path(store, &iter);
1513 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1514 gtk_tree_path_free(tpath);
1518 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1521 FileData *fd = NULL;
1523 if (sel_fd->parent) sel_fd = sel_fd->parent;
1532 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1534 if (match >= 0) break;
1537 if (fd) vflist_select_by_fd(vf, fd);
1541 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1543 GtkTreeModel *store;
1545 GtkTreeSelection *selection;
1549 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1551 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1552 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1554 valid = gtk_tree_model_get_iter_first(store, &iter);
1558 gboolean mark_val, selected;
1559 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1561 mark_val = file_data_get_mark(fd, n);
1562 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1566 case MTS_MODE_SET: selected = mark_val;
1568 case MTS_MODE_OR: selected = mark_val | selected;
1570 case MTS_MODE_AND: selected = mark_val & selected;
1572 case MTS_MODE_MINUS: selected = !mark_val & selected;
1577 gtk_tree_selection_select_iter(selection, &iter);
1579 gtk_tree_selection_unselect_iter(selection, &iter);
1581 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1585 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1587 GtkTreeModel *store;
1588 GtkTreeSelection *selection;
1593 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1595 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1596 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1600 GtkTreePath *tpath = work->data;
1604 gtk_tree_model_get_iter(store, &iter, tpath);
1605 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1607 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1611 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1613 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1615 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1619 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1621 vf_refresh_idle(vf);
1625 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1627 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1631 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1636 *-----------------------------------------------------------------------------
1638 *-----------------------------------------------------------------------------
1641 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1643 GtkTreeViewColumn *column;
1644 GtkCellRenderer *cell;
1648 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1649 if (!column) return;
1651 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1653 list = gtk_tree_view_column_get_cell_renderers(column);
1658 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1659 gtk_tree_view_column_set_visible(column, thumb);
1661 multiline = (thumb && options->thumbnails.max_height >= 48);
1663 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1664 if (!column) return;
1665 gtk_tree_view_column_set_visible(column, multiline);
1666 if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1668 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1669 if (!column) return;
1670 gtk_tree_view_column_set_visible(column, !multiline);
1671 if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1673 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1674 if (!column) return;
1675 gtk_tree_view_column_set_visible(column, !multiline);
1677 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1678 if (!column) return;
1679 gtk_tree_view_column_set_visible(column, !multiline);
1681 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1684 static void vflist_populate_view(ViewFile *vf)
1686 GtkTreeStore *store;
1690 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1691 thumbs = VFLIST(vf)->thumbs_enabled;
1693 vflist_thumb_stop(vf);
1697 vflist_store_clear(vf);
1702 vflist_listview_set_columns(vf->listview, thumbs);
1704 selected = vflist_selection_get_list(vf);
1706 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1708 if (selected && vflist_selection_count(vf, NULL) == 0)
1710 /* all selected files disappeared */
1711 vflist_select_closest(vf, selected->data);
1714 filelist_free(selected);
1717 vflist_thumb_update(vf);
1720 gint vflist_refresh(ViewFile *vf)
1725 old_list = vf->list;
1728 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1731 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1733 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1734 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1735 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1737 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1738 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1741 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1743 vflist_populate_view(vf);
1745 filelist_free(old_list);
1746 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1753 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1755 #define CELL_HEIGHT_OVERRIDE 512
1757 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1761 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1762 if (spec && G_IS_PARAM_SPEC_INT(spec))
1764 GParamSpecInt *spec_int;
1766 spec_int = G_PARAM_SPEC_INT(spec);
1767 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1771 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1773 static GdkColor color;
1774 static GtkWidget *done = NULL;
1780 style = gtk_widget_get_style(widget);
1781 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1782 shift_color(&color, -1, 0);
1789 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1790 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1792 ViewFile *vf = data;
1795 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1796 g_object_set(G_OBJECT(cell),
1797 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1798 "cell-background-set", set, NULL);
1801 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1803 GtkTreeViewColumn *column;
1804 GtkCellRenderer *renderer;
1806 column = gtk_tree_view_column_new();
1807 gtk_tree_view_column_set_title(column, title);
1808 gtk_tree_view_column_set_min_width(column, 4);
1812 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1813 renderer = gtk_cell_renderer_text_new();
1816 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1818 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1819 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1821 gtk_tree_view_column_set_expand(column, TRUE);
1825 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1826 renderer = gtk_cell_renderer_pixbuf_new();
1827 cell_renderer_height_override(renderer);
1828 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1829 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1832 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1833 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1834 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1836 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1839 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1841 ViewFile *vf = data;
1842 GtkTreeStore *store;
1843 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1849 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1850 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1853 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1855 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1857 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1859 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1860 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1861 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1863 vf_refresh_idle(vf);
1865 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1867 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1868 gtk_tree_path_free(path);
1871 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1873 GtkTreeViewColumn *column;
1874 GtkCellRenderer *renderer;
1875 GtkTreeStore *store;
1878 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1880 renderer = gtk_cell_renderer_toggle_new();
1881 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1883 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1884 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1885 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1887 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1888 gtk_tree_view_column_set_fixed_width(column, 18);
1889 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1892 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1896 *-----------------------------------------------------------------------------
1898 *-----------------------------------------------------------------------------
1901 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1903 if (!dir_fd) return FALSE;
1904 if (vf->dir_fd == dir_fd) return TRUE;
1906 file_data_unref(vf->dir_fd);
1907 vf->dir_fd = file_data_ref(dir_fd);
1909 /* force complete reload */
1910 vflist_store_clear(vf);
1912 filelist_free(vf->list);
1915 return vf_refresh(vf);
1918 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1920 ViewFile *vf = data;
1922 file_data_unregister_notify_func(vf_notify_cb, vf);
1924 vflist_select_idle_cancel(vf);
1925 vf_refresh_idle_cancel(vf);
1926 vflist_thumb_stop(vf);
1928 filelist_free(vf->list);
1931 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1933 GtkTreeStore *store;
1934 GtkTreeSelection *selection;
1936 GType flist_types[FILE_COLUMN_COUNT];
1940 vf->info = g_new0(ViewFileInfoList, 1);
1942 VFLIST(vf)->click_fd = NULL;
1943 VFLIST(vf)->select_fd = NULL;
1944 VFLIST(vf)->thumbs_enabled = FALSE;
1946 VFLIST(vf)->select_idle_id = -1;
1948 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1949 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1950 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1951 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1952 flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1953 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1954 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1955 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1956 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1957 flist_types[i] = G_TYPE_BOOLEAN;
1959 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1961 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1962 g_object_unref(store);
1964 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1965 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1966 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1968 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1969 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1973 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1975 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1976 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1980 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1981 g_assert(column == FILE_VIEW_COLUMN_THUMB);
1984 vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1985 g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1988 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1989 g_assert(column == FILE_VIEW_COLUMN_NAME);
1992 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1993 g_assert(column == FILE_VIEW_COLUMN_SIZE);
1996 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1997 g_assert(column == FILE_VIEW_COLUMN_DATE);
2000 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
2004 void vflist_thumb_set(ViewFile *vf, gint enable)
2006 if (VFLIST(vf)->thumbs_enabled == enable) return;
2008 VFLIST(vf)->thumbs_enabled = enable;
2009 if (vf->layout) vf_refresh(vf);
2012 void vflist_marks_set(ViewFile *vf, gint enable)
2014 GList *columns, *work;
2016 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
2021 GtkTreeViewColumn *column = work->data;
2022 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
2025 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
2026 gtk_tree_view_column_set_visible(column, enable);
2029 g_list_free(columns);
2033 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */