run idle function just once
[geeqie.git] / src / view_file_list.c
1 /*
2  * Geeqie
3  * (C) 2004 John Ellis
4  * Copyright (C) 2008 The Geeqie Team
5  *
6  * Author: John Ellis
7  *
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!
11  */
12
13 #include "main.h"
14 #include "view_file_list.h"
15
16 #include "cache_maint.h"
17 #include "dnd.h"
18 #include "editors.h"
19 #include "img-view.h"
20 #include "info.h"
21 #include "layout.h"
22 #include "layout_image.h"
23 #include "menu.h"
24 #include "thumb.h"
25 #include "utilops.h"
26 #include "ui_bookmark.h"
27 #include "ui_fileops.h"
28 #include "ui_menu.h"
29 #include "ui_tree_edit.h"
30 #include "view_file.h"
31
32 #include <gdk/gdkkeysyms.h> /* for keyboard values */
33
34
35 enum {
36         FILE_COLUMN_POINTER = 0,
37         FILE_COLUMN_VERSION,
38         FILE_COLUMN_THUMB,
39         FILE_COLUMN_NAME,
40         FILE_COLUMN_SIDECARS,
41         FILE_COLUMN_SIZE,
42         FILE_COLUMN_DATE,
43         FILE_COLUMN_COLOR,
44         FILE_COLUMN_MARKS,
45         FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
46         FILE_COLUMN_COUNT
47 };
48
49
50 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
51 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
52 static void vflist_populate_view(ViewFile *vf);
53 static void vflist_notify_cb(FileData *fd, NotifyType type, gpointer data);
54
55
56 /*
57  *-----------------------------------------------------------------------------
58  * misc
59  *-----------------------------------------------------------------------------
60  */
61 typedef struct {
62         FileData *fd;
63         GtkTreeIter *iter;
64         gint found;
65         gint row;
66 } ViewFileFindRowData;
67
68 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
69 {
70         ViewFileFindRowData *find = data;
71         FileData *fd;
72         gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
73         if (fd == find->fd)
74                 {
75                 *find->iter = *iter;
76                 find->found = 1;
77                 return TRUE;
78                 }
79         find->row++;
80         return FALSE;
81 }
82
83 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
84 {
85         GtkTreeModel *store;
86         ViewFileFindRowData data = {fd, iter, 0, 0};
87
88         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
89         gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
90
91         if (data.found)
92                 {
93                 return data.row;
94                 }
95
96         return -1;
97 }
98
99
100 /*
101 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
102 {
103         gint i = 0;
104         while (work)
105                 {
106                 FileData *fd_p = work->data;
107                 if (fd == fd_p) return i;
108
109                 i++;
110
111                 GList *work2 = fd_p->sidecar_files;
112                 while (work2)
113                         {
114                         fd_p = work2->data;
115                         if (fd == fd_p) return i;
116
117                         i++;
118                         work2 = work2->next;
119                         }
120                 work = work->next;
121                 }
122         return -1;
123 }
124 */
125
126 static gint vflist_sidecar_list_count(GList *work)
127 {
128         gint i = 0;
129         while (work)
130                 {
131                 FileData *fd = work->data;
132                 i++;
133
134                 GList *work2 = fd->sidecar_files;
135                 while (work2)
136                         {
137                         i++;
138                         work2 = work2->next;
139                         }
140                 work = work->next;
141                 }
142         return i;
143 }
144
145 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
146 {
147         FileData *fd;
148         gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
149         file_data_unref(fd);
150         return FALSE;
151 }
152
153 static void vflist_store_clear(ViewFile *vf)
154 {
155         GtkTreeModel *store;
156         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
157         gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
158         gtk_tree_store_clear(GTK_TREE_STORE(store));
159 }
160
161 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
162 {
163         GtkTreeModel *store;
164         GtkTreeIter iter;
165
166         if (vflist_find_row(vf, fd, &iter) < 0) return;
167         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
168         gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
169 }
170
171 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
172 {
173         GtkTreeModel *store;
174         GtkTreePath *tpath;
175
176         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
177
178         tpath = gtk_tree_model_get_path(store, iter);
179         gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
180         gtk_tree_path_free(tpath);
181 }
182
183
184 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
185 {
186         GList *columns, *work;
187         gint i = 0;
188
189         columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
190         work = columns;
191         while (work)
192                 {
193                 GtkTreeViewColumn *column = work->data;
194                 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
195                         break;
196                 work = work->next;
197                 i++;
198                 }
199
200         g_list_free(columns);
201         return i;
202 }
203
204
205 /*
206  *-----------------------------------------------------------------------------
207  * dnd
208  *-----------------------------------------------------------------------------
209  */
210
211 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
212                            GtkSelectionData *selection_data, guint info,
213                            guint time, gpointer data)
214 {
215         ViewFile *vf = data;
216         GList *list = NULL;
217         gchar *uri_text = NULL;
218         gint total;
219
220         if (!VFLIST_INFO(vf, click_fd)) return;
221
222         if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
223                 {
224                 list = vf_selection_get_list(vf);
225                 }
226         else
227                 {
228                 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
229                 }
230
231         if (!list) return;
232
233         uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
234         filelist_free(list);
235
236         DEBUG_1(uri_text);
237
238         gtk_selection_data_set(selection_data, selection_data->target,
239                                8, (guchar *)uri_text, total);
240         g_free(uri_text);
241 }
242
243 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
244 {
245         ViewFile *vf = data;
246
247         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
248
249         if (VFLIST_INFO(vf, thumbs_enabled) &&
250             VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->pixbuf)
251                 {
252                 guint items;
253
254                 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
255                         items = vf_selection_count(vf, NULL);
256                 else
257                         items = 1;
258
259                 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->pixbuf, items);
260                 }
261 }
262
263 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
264 {
265         ViewFile *vf = data;
266
267         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
268
269         if (context->action == GDK_ACTION_MOVE)
270                 {
271                 vf_refresh(vf);
272                 }
273 }
274
275 void vflist_dnd_init(ViewFile *vf)
276 {
277         gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
278                             dnd_file_drag_types, dnd_file_drag_types_count,
279                             GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
280         g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
281                          G_CALLBACK(vflist_dnd_get), vf);
282         g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
283                          G_CALLBACK(vflist_dnd_begin), vf);
284         g_signal_connect(G_OBJECT(vf->listview), "drag_end",
285                          G_CALLBACK(vflist_dnd_end), vf);
286 }
287
288 /*
289  *-----------------------------------------------------------------------------
290  * pop-up menu
291  *-----------------------------------------------------------------------------
292  */
293
294 GList *vflist_pop_menu_file_list(ViewFile *vf)
295 {
296         if (!VFLIST_INFO(vf, click_fd)) return NULL;
297
298         if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
299                 {
300                 return vf_selection_get_list(vf);
301                 }
302
303         return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
304 }
305
306 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
307 {
308         ViewFile *vf = data;
309
310         if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
311                 {
312                 GList *list;
313
314                 list = vf_selection_get_list(vf);
315                 view_window_new_from_list(list);
316                 filelist_free(list);
317                 }
318         else
319                 {
320                 view_window_new(VFLIST_INFO(vf, click_fd));
321                 }
322 }
323
324 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
325 {
326         ViewFile *vf = data;
327         GList *list;
328
329         list = vf_pop_menu_file_list(vf);
330         if (options->file_ops.enable_in_place_rename &&
331             list && !list->next && VFLIST_INFO(vf, click_fd))
332                 {
333                 GtkTreeModel *store;
334                 GtkTreeIter iter;
335
336                 filelist_free(list);
337
338                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
339                 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
340                         {
341                         GtkTreePath *tpath;
342
343                         tpath = gtk_tree_model_get_path(store, &iter);
344                         tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
345                                           vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
346                                           vflist_row_rename_cb, vf);
347                         gtk_tree_path_free(tpath);
348                         }
349                 return;
350                 }
351
352         file_util_rename(NULL, list, vf->listview);
353 }
354
355 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
356 {
357         ViewFile *vf = data;
358
359         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
360         if (vf->layout)
361                 {
362                 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
363                 }
364         else
365                 {
366                 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
367                 }
368 }
369
370 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
371 {
372         ViewFile *vf = data;
373
374         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
375         vf_refresh(vf);
376 }
377
378 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
379 {
380         ViewFile *vf = data;
381         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
382         VFLIST_INFO(vf, click_fd) = NULL;
383         vf->popup = NULL;
384 }
385
386
387 /*
388  *-----------------------------------------------------------------------------
389  * callbacks
390  *-----------------------------------------------------------------------------
391  */
392
393 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
394 {
395         ViewFile *vf = data;
396         gchar *old_path;
397         gchar *new_path;
398
399         if (strlen(new) == 0) return FALSE;
400
401         old_path = g_build_filename(vf->dir_fd->path, old, NULL);
402         new_path = g_build_filename(vf->dir_fd->path, new, NULL);
403
404         if (strchr(new, G_DIR_SEPARATOR) != NULL)
405                 {
406                 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
407                 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
408                 g_free(text);
409                 }
410         else if (isfile(new_path))
411                 {
412                 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
413                 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
414                 g_free(text);
415                 }
416         else
417                 {
418                 gint row = vf_index_by_path(vf, old_path);
419                 if (row >= 0)
420                         {
421                         GList *work = g_list_nth(vf->list, row);
422                         FileData *fd = work->data;
423                         
424                         file_util_rename_simple(fd, new_path, vf->listview);
425
426                         }
427
428                 }
429         g_free(old_path);
430         g_free(new_path);
431
432         return FALSE;
433 }
434
435 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
436 {
437         ViewFile *vf = data;
438         GtkTreeModel *store;
439         GtkTreeIter iter;
440         GtkTreePath *tpath;
441         gint cw, ch;
442
443         if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
444         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
445         tpath = gtk_tree_model_get_path(store, &iter);
446         tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
447         gtk_tree_path_free(tpath);
448         *y += ch;
449         popup_menu_position_clamp(menu, x, y, 0);
450 }
451
452 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
453 {
454         ViewFile *vf = data;
455         GtkTreePath *tpath;
456
457         if (event->keyval != GDK_Menu) return FALSE;
458
459         gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
460         if (tpath)
461                 {
462                 GtkTreeModel *store;
463                 GtkTreeIter iter;
464
465                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
466                 gtk_tree_model_get_iter(store, &iter, tpath);
467                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
468                 gtk_tree_path_free(tpath);
469                 }
470         else
471                 {
472                 VFLIST_INFO(vf, click_fd) = NULL;
473                 }
474
475         vf->popup = vf_pop_menu(vf);
476         gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
477
478         return TRUE;
479 }
480
481 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
482 {
483         ViewFile *vf = data;
484         GtkTreePath *tpath;
485         GtkTreeIter iter;
486         FileData *fd = NULL;
487         GtkTreeViewColumn *column;
488         
489         vf->clicked_mark = 0;
490
491         if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
492                                           &tpath, &column, NULL, NULL))
493                 {
494                 GtkTreeModel *store;
495                 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
496
497                 if (bevent->button == MOUSE_BUTTON_LEFT &&
498                     col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
499                         return FALSE;
500
501                 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
502                         vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
503
504                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
505
506                 gtk_tree_model_get_iter(store, &iter, tpath);
507                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
508 #if 0
509                 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
510 #endif
511                 gtk_tree_path_free(tpath);
512                 }
513
514         VFLIST_INFO(vf, click_fd) = fd;
515
516         if (bevent->button == MOUSE_BUTTON_RIGHT)
517                 {
518                 vf->popup = vf_pop_menu(vf);
519                 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
520                                 bevent->button, bevent->time);
521                 return TRUE;
522                 }
523
524         if (!fd) return FALSE;
525
526         if (bevent->button == MOUSE_BUTTON_MIDDLE)
527                 {
528                 if (!vflist_row_is_selected(vf, fd))
529                         {
530                         vflist_color_set(vf, fd, TRUE);
531                         }
532                 return TRUE;
533                 }
534
535
536         if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
537             !(bevent->state & GDK_SHIFT_MASK ) &&
538             !(bevent->state & GDK_CONTROL_MASK ) &&
539             vflist_row_is_selected(vf, fd))
540                 {
541                 GtkTreeSelection *selection;
542
543                 gtk_widget_grab_focus(widget);
544
545
546                 /* returning FALSE and further processing of the event is needed for 
547                    correct operation of the expander, to show the sidecar files.
548                    It however resets the selection of multiple files. With this condition
549                    it should work for both cases */
550                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
551                 return (gtk_tree_selection_count_selected_rows(selection) > 1);
552                 }
553
554 #if 0
555         if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
556                 {
557                 if (vf->layout) layout_image_full_screen_start(vf->layout);
558                 }
559 #endif
560
561         return FALSE;
562 }
563
564 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
565 {
566         ViewFile *vf = data;
567         GtkTreePath *tpath;
568         GtkTreeIter iter;
569         FileData *fd = NULL;
570
571         if (bevent->button == MOUSE_BUTTON_MIDDLE)
572                 {
573                 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
574                 }
575
576         if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
577                 {
578                 return TRUE;
579                 }
580
581         if ((bevent->x != 0 || bevent->y != 0) &&
582             gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
583                                           &tpath, NULL, NULL, NULL))
584                 {
585                 GtkTreeModel *store;
586
587                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
588                 gtk_tree_model_get_iter(store, &iter, tpath);
589                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
590                 gtk_tree_path_free(tpath);
591                 }
592
593         if (bevent->button == MOUSE_BUTTON_MIDDLE)
594                 {
595                 if (fd && VFLIST_INFO(vf, click_fd) == fd)
596                         {
597                         GtkTreeSelection *selection;
598
599                         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
600                         if (vflist_row_is_selected(vf, fd))
601                                 {
602                                 gtk_tree_selection_unselect_iter(selection, &iter);
603                                 }
604                         else
605                                 {
606                                 gtk_tree_selection_select_iter(selection, &iter);
607                                 }
608                         }
609                 return TRUE;
610                 }
611
612         if (fd && VFLIST_INFO(vf, click_fd) == fd &&
613             !(bevent->state & GDK_SHIFT_MASK ) &&
614             !(bevent->state & GDK_CONTROL_MASK ) &&
615             vflist_row_is_selected(vf, fd))
616                 {
617                 GtkTreeSelection *selection;
618
619                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
620                 gtk_tree_selection_unselect_all(selection);
621                 gtk_tree_selection_select_iter(selection, &iter);
622                 vflist_move_cursor(vf, &iter);
623 //              return TRUE;// FIXME - expand
624                 }
625
626         return FALSE;
627 }
628
629 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
630 {
631         FileData *read_ahead_fd = NULL;
632         gint row;
633         FileData *cur_fd;
634         if (!sel_fd) return;
635
636         cur_fd = layout_image_get_fd(vf->layout);
637         if (sel_fd == cur_fd) return; /* no change */
638
639         row = g_list_index(vf->list, sel_fd);
640         // FIXME sidecar data
641
642         if (sel_fd && options->image.enable_read_ahead && row >= 0)
643                 {
644                 if (row > g_list_index(vf->list, cur_fd) &&
645                     (guint) (row + 1) < vf_count(vf, NULL))
646                         {
647                         read_ahead_fd = vf_index_get_data(vf, row + 1);
648                         }
649                 else if (row > 0)
650                         {
651                         read_ahead_fd = vf_index_get_data(vf, row - 1);
652                         }
653                 }
654
655         layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
656 }
657
658 static gint vflist_select_idle_cb(gpointer data)
659 {
660         ViewFile *vf = data;
661
662         if (!vf->layout)
663                 {
664                 VFLIST_INFO(vf, select_idle_id) = -1;
665                 return FALSE;
666                 }
667
668         vf_send_update(vf);
669
670         if (VFLIST_INFO(vf, select_fd))
671                 {
672                 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
673                 VFLIST_INFO(vf, select_fd) = NULL;
674                 }
675
676         VFLIST_INFO(vf, select_idle_id) = -1;
677         return FALSE;
678 }
679
680 static void vflist_select_idle_cancel(ViewFile *vf)
681 {
682         if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
683         VFLIST_INFO(vf, select_idle_id) = -1;
684 }
685
686 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
687                                  gboolean path_currently_selected, gpointer data)
688 {
689         ViewFile *vf = data;
690         GtkTreeIter iter;
691
692         if (!path_currently_selected &&
693             gtk_tree_model_get_iter(store, &iter, tpath))
694                 {
695                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
696                 }
697         else
698                 {
699                 VFLIST_INFO(vf, select_fd) = NULL;
700                 }
701
702         if (vf->layout &&
703             VFLIST_INFO(vf, select_idle_id) == -1)
704                 {
705                 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
706                 }
707
708         return TRUE;
709 }
710
711 /*
712  *-----------------------------------------------------------------------------
713  * misc
714  *-----------------------------------------------------------------------------
715  */
716
717 /*
718 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
719                                         gboolean path_currently_selected, gpointer data)
720 {
721         return TRUE;
722 }
723 */
724
725 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
726 {
727         int i;
728         gchar *size;
729         gchar *sidecars = NULL;
730
731         if (fd->sidecar_files)
732                 sidecars = file_data_sc_list_to_string(fd);
733         size = text_from_size(fd->size);
734
735         gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
736                                         FILE_COLUMN_VERSION, fd->version,
737                                         FILE_COLUMN_THUMB, fd->pixbuf,
738                                         FILE_COLUMN_NAME, fd->name,
739                                         FILE_COLUMN_SIDECARS, sidecars,
740                                         FILE_COLUMN_SIZE, size,
741                                         FILE_COLUMN_DATE, text_from_time(fd->date),
742                                         FILE_COLUMN_COLOR, FALSE, -1);
743         for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
744                 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
745
746         g_free(size);
747         if (sidecars)
748                 g_free(sidecars);
749 }
750
751 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
752 {
753         GList *work;
754         GtkTreeIter iter;
755         gint valid;
756
757         valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
758
759         work = list;
760         while (work)
761                 {
762                 gint match;
763                 FileData *fd = work->data;
764                 gint done = FALSE;
765
766                 while (!done)
767                         {
768                         FileData *old_fd = NULL;
769                         gint old_version = 0;
770
771                         if (valid)
772                                 {
773                                 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
774                                                    FILE_COLUMN_POINTER, &old_fd,
775                                                    FILE_COLUMN_VERSION, &old_version,
776                                                    -1);
777
778                                 if (fd == old_fd)
779                                         {
780                                         match = 0;
781                                         }
782                                 else
783                                         {
784                                         if (parent_iter)
785                                                 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
786                                         else
787                                                 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
788
789                                         if (match == 0) g_warning("multiple fd for the same path");
790                                         }
791                                         
792                                 }
793                         else
794                                 {
795                                 match = -1;
796                                 }
797
798                         if (match < 0)
799                                 {
800                                 GtkTreeIter new;
801
802                                 if (valid)
803                                         {
804                                         gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
805                                         }
806                                 else
807                                         {
808                                         gtk_tree_store_append(store, &new, parent_iter);
809                                         }
810
811                                 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
812                                 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
813                                 
814                                 if (g_list_find(selected, fd))
815                                         {
816                                         /* renamed files - the same fd appears at different position - select it again*/
817                                         GtkTreeSelection *selection;
818                                         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
819                                         gtk_tree_selection_select_iter(selection, &new);
820                                         }
821
822                                 done = TRUE;
823                                 }
824                         else if (match > 0)
825                                 {
826                                 file_data_unref(old_fd);
827                                 valid = gtk_tree_store_remove(store, &iter);
828                                 }
829                         else
830                                 {
831                                 if (fd->version != old_version)
832                                         {
833                                         vflist_setup_iter(vf, store, &iter, fd);
834                                         vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
835                                         }
836
837                                 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
838
839                                 done = TRUE;
840                                 }
841                         }
842                 work = work->next;
843                 }
844
845         while (valid)
846                 {
847                 FileData *old_fd;
848                 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
849                 file_data_unref(old_fd);
850
851                 valid = gtk_tree_store_remove(store, &iter);
852                 }
853 }
854
855 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
856 {
857         gint i;
858         GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
859         gint *new_order;
860         GtkTreeStore *store;
861         GList *work;
862
863         if (vf->sort_method == type && vf->sort_ascend == ascend) return;
864         if (!vf->list) return;
865
866         work = vf->list;
867         i = 0;
868         while (work)
869                 {
870                 FileData *fd = work->data;
871                 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
872                 i++;
873                 work = work->next;
874                 }
875
876         vf->sort_method = type;
877         vf->sort_ascend = ascend;
878
879         vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
880
881         new_order = g_malloc(i * sizeof(gint));
882
883         work = vf->list;
884         i = 0;
885         while (work)
886                 {
887                 FileData *fd = work->data;
888                 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
889                 i++;
890                 work = work->next;
891                 }
892
893         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
894         gtk_tree_store_reorder(store, NULL, new_order);
895
896         g_free(new_order);
897         g_hash_table_destroy(fd_idx_hash);
898 }
899
900 /*
901  *-----------------------------------------------------------------------------
902  * thumb updates
903  *-----------------------------------------------------------------------------
904  */
905
906 static gint vflist_thumb_next(ViewFile *vf);
907
908 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
909 {
910         if (vf->func_thumb_status)
911                 {
912                 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
913                 }
914 }
915
916 static void vflist_thumb_cleanup(ViewFile *vf)
917 {
918         vflist_thumb_status(vf, 0.0, NULL);
919
920         vf->thumbs_count = 0;
921         vf->thumbs_running = FALSE;
922
923         thumb_loader_free(vf->thumbs_loader);
924         vf->thumbs_loader = NULL;
925
926         vf->thumbs_filedata = NULL;
927 }
928
929 static void vflist_thumb_stop(ViewFile *vf)
930 {
931         if (vf->thumbs_running) vflist_thumb_cleanup(vf);
932 }
933
934 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
935 {
936         GtkTreeStore *store;
937         GtkTreeIter iter;
938
939         if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
940
941         if (fd->pixbuf) g_object_unref(fd->pixbuf);
942         fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
943
944         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
945         gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
946
947         vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
948 }
949
950 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
951 {
952         ViewFile *vf = data;
953
954         if (vf->thumbs_filedata && vf->thumbs_loader == tl)
955                 {
956                 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
957                 }
958
959         while (vflist_thumb_next(vf));
960 }
961
962 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
963 {
964         ViewFile *vf = data;
965
966         if (vf->thumbs_filedata && vf->thumbs_loader == tl)
967                 {
968                 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
969                 }
970
971         while (vflist_thumb_next(vf));
972 }
973
974 static gint vflist_thumb_next(ViewFile *vf)
975 {
976         GtkTreePath *tpath;
977         FileData *fd = NULL;
978
979         /* first check the visible files */
980
981         if (GTK_WIDGET_REALIZED(vf->listview) &&
982             gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
983                 {
984                 GtkTreeModel *store;
985                 GtkTreeIter iter;
986                 gint valid = TRUE;
987
988                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
989                 gtk_tree_model_get_iter(store, &iter, tpath);
990                 gtk_tree_path_free(tpath);
991
992                 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
993                         {
994                         gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
995                         if (fd->pixbuf) fd = NULL;
996
997                         valid = gtk_tree_model_iter_next(store, &iter);
998                         }
999                 }
1000
1001         /* then find first undone */
1002
1003         if (!fd)
1004                 {
1005                 GList *work = vf->list;
1006                 while (work && !fd)
1007                         {
1008                         FileData *fd_p = work->data;
1009                         if (!fd_p->pixbuf)
1010                                 fd = fd_p;
1011                         else
1012                                 {
1013                                 GList *work2 = fd_p->sidecar_files;
1014
1015                                 while (work2 && !fd)
1016                                         {
1017                                         fd_p = work2->data;
1018                                         if (!fd_p->pixbuf) fd = fd_p;
1019                                         work2 = work2->next;
1020                                         }
1021                                 }
1022                         work = work->next;
1023                         }
1024                 }
1025
1026         if (!fd)
1027                 {
1028                 /* done */
1029                 vflist_thumb_cleanup(vf);
1030                 return FALSE;
1031                 }
1032
1033         vf->thumbs_count++;
1034
1035         vf->thumbs_filedata = fd;
1036
1037         thumb_loader_free(vf->thumbs_loader);
1038
1039         vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1040         thumb_loader_set_callbacks(vf->thumbs_loader,
1041                                    vflist_thumb_done_cb,
1042                                    vflist_thumb_error_cb,
1043                                    NULL,
1044                                    vf);
1045
1046         if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1047                 {
1048                 /* set icon to unknown, continue */
1049                 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1050                 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1051
1052                 return TRUE;
1053                 }
1054
1055         return FALSE;
1056 }
1057
1058 static void vflist_thumb_update(ViewFile *vf)
1059 {
1060         vflist_thumb_stop(vf);
1061         if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1062
1063         vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1064         vf->thumbs_running = TRUE;
1065
1066         while (vflist_thumb_next(vf));
1067 }
1068
1069 /*
1070  *-----------------------------------------------------------------------------
1071  * row stuff
1072  *-----------------------------------------------------------------------------
1073  */
1074
1075 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1076 {
1077         return g_list_nth_data(vf->list, row);
1078 }
1079
1080 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1081 {
1082         gint p = 0;
1083         GList *work;
1084
1085         if (!path) return -1;
1086
1087         work = vf->list;
1088         while (work)
1089                 {
1090                 FileData *fd = work->data;
1091                 if (strcmp(path, fd->path) == 0) return p;
1092                 
1093                 work = work->next;
1094                 p++;
1095                 }
1096
1097         return -1;
1098 }
1099
1100 guint vflist_count(ViewFile *vf, gint64 *bytes)
1101 {
1102         if (bytes)
1103                 {
1104                 gint64 b = 0;
1105                 GList *work;
1106
1107                 work = vf->list;
1108                 while (work)
1109                         {
1110                         FileData *fd = work->data;
1111                         work = work->next;
1112                         b += fd->size;
1113                         }
1114
1115                 *bytes = b;
1116                 }
1117
1118         return g_list_length(vf->list);
1119 }
1120
1121 GList *vflist_get_list(ViewFile *vf)
1122 {
1123         GList *list = NULL;
1124         GList *work;
1125
1126         work = vf->list;
1127         while (work)
1128                 {
1129                 FileData *fd = work->data;
1130                 work = work->next;
1131
1132                 list = g_list_prepend(list, file_data_ref(fd));
1133                 }
1134
1135         return g_list_reverse(list);
1136 }
1137
1138 /*
1139  *-----------------------------------------------------------------------------
1140  * selections
1141  *-----------------------------------------------------------------------------
1142  */
1143
1144 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1145 {
1146         GtkTreeModel *store;
1147         GtkTreeSelection *selection;
1148         GList *slist;
1149         GList *work;
1150         gint found = FALSE;
1151
1152         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1153         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1154         work = slist;
1155         while (!found && work)
1156                 {
1157                 GtkTreePath *tpath = work->data;
1158                 FileData *fd_n;
1159                 GtkTreeIter iter;
1160
1161                 gtk_tree_model_get_iter(store, &iter, tpath);
1162                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1163                 if (fd_n == fd) found = TRUE;
1164                 work = work->next;
1165                 }
1166         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1167         g_list_free(slist);
1168
1169         return found;
1170 }
1171
1172 gint vflist_index_is_selected(ViewFile *vf, gint row)
1173 {
1174         FileData *fd;
1175
1176         fd = vf_index_get_data(vf, row);
1177         return vflist_row_is_selected(vf, fd);
1178 }
1179
1180 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1181 {
1182         GtkTreeModel *store;
1183         GtkTreeSelection *selection;
1184         GList *slist;
1185         guint count;
1186
1187         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1188         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1189
1190         if (bytes)
1191                 {
1192                 gint64 b = 0;
1193                 GList *work;
1194
1195                 work = slist;
1196                 while (work)
1197                         {
1198                         GtkTreePath *tpath = work->data;
1199                         GtkTreeIter iter;
1200                         FileData *fd;
1201
1202                         gtk_tree_model_get_iter(store, &iter, tpath);
1203                         gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1204                         b += fd->size;
1205
1206                         work = work->next;
1207                         }
1208
1209                 *bytes = b;
1210                 }
1211
1212         count = g_list_length(slist);
1213         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1214         g_list_free(slist);
1215
1216         return count;
1217 }
1218
1219 GList *vflist_selection_get_list(ViewFile *vf)
1220 {
1221         GtkTreeModel *store;
1222         GtkTreeSelection *selection;
1223         GList *slist;
1224         GList *list = NULL;
1225         GList *work;
1226
1227         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1228         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1229         work = slist;
1230         while (work)
1231                 {
1232                 GtkTreePath *tpath = work->data;
1233                 FileData *fd;
1234                 GtkTreeIter iter;
1235
1236                 gtk_tree_model_get_iter(store, &iter, tpath);
1237                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1238
1239                 list = g_list_prepend(list, file_data_ref(fd));
1240
1241                 work = work->next;
1242                 }
1243         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1244         g_list_free(slist);
1245
1246         return g_list_reverse(list);
1247 }
1248
1249 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1250 {
1251         GtkTreeModel *store;
1252         GtkTreeSelection *selection;
1253         GList *slist;
1254         GList *list = NULL;
1255         GList *work;
1256
1257         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1258         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1259         work = slist;
1260         while (work)
1261                 {
1262                 GtkTreePath *tpath = work->data;
1263                 FileData *fd;
1264                 GtkTreeIter iter;
1265
1266                 gtk_tree_model_get_iter(store, &iter, tpath);
1267                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1268
1269                 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1270
1271                 work = work->next;
1272                 }
1273         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1274         g_list_free(slist);
1275
1276         return g_list_reverse(list);
1277 }
1278
1279 void vflist_select_all(ViewFile *vf)
1280 {
1281         GtkTreeSelection *selection;
1282
1283         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1284         gtk_tree_selection_select_all(selection);
1285
1286         VFLIST_INFO(vf, select_fd) = NULL;
1287 }
1288
1289 void vflist_select_none(ViewFile *vf)
1290 {
1291         GtkTreeSelection *selection;
1292
1293         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1294         gtk_tree_selection_unselect_all(selection);
1295 }
1296
1297 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1298 {
1299         GtkTreePath *tpath;
1300         gboolean result;
1301
1302         tpath = gtk_tree_model_get_path(store, iter);
1303         result = gtk_tree_path_prev(tpath);
1304         if (result)
1305                 gtk_tree_model_get_iter(store, iter, tpath);
1306
1307         gtk_tree_path_free(tpath);
1308
1309         return result;
1310 }
1311
1312 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1313 {
1314         if (!gtk_tree_model_get_iter_first(store, iter))
1315                 return FALSE;
1316
1317         while (TRUE)
1318                 {
1319                 GtkTreeIter next = *iter;
1320                 
1321                 if (gtk_tree_model_iter_next(store, &next))
1322                         *iter = next;
1323                 else
1324                         break;
1325                 }
1326         
1327         return TRUE;
1328 }
1329
1330 void vflist_select_invert(ViewFile *vf)
1331 {
1332         GtkTreeIter iter;
1333         GtkTreeSelection *selection;
1334         GtkTreeModel *store;
1335         gboolean valid;
1336
1337         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1338         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1339
1340         /* Backward iteration prevents scrolling to the end of the list,
1341          * it scrolls to the first selected row instead. */
1342         valid = tree_model_get_iter_last(store, &iter);
1343
1344         while (valid)
1345                 {
1346                 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1347
1348                 if (selected)
1349                         gtk_tree_selection_unselect_iter(selection, &iter);
1350                 else
1351                         gtk_tree_selection_select_iter(selection, &iter);
1352                                 
1353                 valid = tree_model_iter_prev(store, &iter);
1354                 }
1355 }
1356
1357 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1358 {
1359         GtkTreeIter iter;
1360
1361         if (vflist_find_row(vf, fd, &iter) < 0) return;
1362
1363         tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1364
1365         if (!vflist_row_is_selected(vf, fd))
1366                 {
1367                 GtkTreeSelection *selection;
1368                 GtkTreeModel *store;
1369                 GtkTreePath *tpath;
1370
1371                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1372                 gtk_tree_selection_unselect_all(selection);
1373                 gtk_tree_selection_select_iter(selection, &iter);
1374                 vflist_move_cursor(vf, &iter);
1375
1376                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1377                 tpath = gtk_tree_model_get_path(store, &iter);
1378                 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1379                 gtk_tree_path_free(tpath);
1380                 }
1381 }
1382
1383 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1384 {
1385         GList *work;
1386         
1387         if (sel_fd->parent) sel_fd = sel_fd->parent;
1388         work = vf->list;
1389         
1390         while (work)
1391                 {
1392                 gint match;
1393                 FileData *fd = work->data;
1394                 work = work->next;
1395                 
1396
1397                 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1398                 
1399                 if (match >= 0)
1400                         {
1401                         vflist_select_by_fd(vf, fd);
1402                         break;
1403                         }
1404                 }
1405
1406 }
1407
1408 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1409 {
1410         GtkTreeModel *store;
1411         GtkTreeIter iter;
1412         GtkTreeSelection *selection;
1413         gint valid;
1414         gint n = mark - 1;
1415
1416         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1417
1418         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1419         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1420
1421         valid = gtk_tree_model_get_iter_first(store, &iter);
1422         while (valid)
1423                 {
1424                 FileData *fd;
1425                 gboolean mark_val, selected;
1426                 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1427
1428                 mark_val = file_data_get_mark(fd, n);
1429                 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1430
1431                 switch (mode)
1432                         {
1433                         case MTS_MODE_SET: selected = mark_val;
1434                                 break;
1435                         case MTS_MODE_OR: selected = mark_val | selected;
1436                                 break;
1437                         case MTS_MODE_AND: selected = mark_val & selected;
1438                                 break;
1439                         case MTS_MODE_MINUS: selected = !mark_val & selected;
1440                                 break;
1441                         }
1442
1443                 if (selected)
1444                         gtk_tree_selection_select_iter(selection, &iter);
1445                 else
1446                         gtk_tree_selection_unselect_iter(selection, &iter);
1447
1448                 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1449                 }
1450 }
1451
1452 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1453 {
1454         GtkTreeModel *store;
1455         GtkTreeSelection *selection;
1456         GList *slist;
1457         GList *work;
1458         gint n = mark - 1;
1459
1460         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1461
1462         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1463         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1464         work = slist;
1465         while (work)
1466                 {
1467                 GtkTreePath *tpath = work->data;
1468                 FileData *fd;
1469                 GtkTreeIter iter;
1470
1471                 gtk_tree_model_get_iter(store, &iter, tpath);
1472                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1473
1474                 file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification */
1475
1476                 switch (mode)
1477                         {
1478                         case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1479                                 break;
1480                         case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1481                                 break;
1482                         case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1483                                 break;
1484                         }
1485                 
1486                 file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1487
1488                 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1489
1490                 work = work->next;
1491                 }
1492         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1493         g_list_free(slist);
1494 }
1495
1496 /*
1497  *-----------------------------------------------------------------------------
1498  * core (population)
1499  *-----------------------------------------------------------------------------
1500  */
1501
1502 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1503 {
1504         GtkTreeViewColumn *column;
1505         GtkCellRenderer *cell;
1506         GList *list;
1507
1508         column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
1509         if (!column) return;
1510
1511         gtk_tree_view_column_set_visible(column, thumb);
1512
1513         gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 40);
1514
1515         list = gtk_tree_view_column_get_cell_renderers(column);
1516         if (!list) return;
1517         cell = list->data;
1518         g_list_free(list);
1519
1520         g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1521         gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1522 }
1523
1524 static void vflist_populate_view(ViewFile *vf)
1525 {
1526         GtkTreeStore *store;
1527         gint thumbs;
1528         GtkTreeRowReference *visible_row = NULL;
1529         GtkTreePath *tpath;
1530         GList *selected;
1531
1532         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1533         thumbs = VFLIST_INFO(vf, thumbs_enabled);
1534
1535         vflist_thumb_stop(vf);
1536
1537         if (!vf->list)
1538                 {
1539                 vflist_store_clear(vf);
1540                 vf_send_update(vf);
1541                 return;
1542                 }
1543
1544         if (GTK_WIDGET_REALIZED(vf->listview) &&
1545             gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1546                 {
1547                 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1548                 gtk_tree_path_free(tpath);
1549                 }
1550
1551         vflist_listview_set_height(vf->listview, thumbs);
1552
1553         selected = vflist_selection_get_list(vf);
1554         
1555         vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1556
1557         if (selected && vflist_selection_count(vf, NULL) == 0)
1558                 {
1559                 /* all selected files disappeared */
1560                 vflist_select_closest(vf, selected->data);
1561                 }       
1562
1563         filelist_free(selected);
1564         
1565         if (visible_row)
1566                 {
1567                 if (gtk_tree_row_reference_valid(visible_row))
1568                         {
1569                         tpath = gtk_tree_row_reference_get_path(visible_row);
1570                         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1571                         gtk_tree_path_free(tpath);
1572                         }
1573                 gtk_tree_row_reference_free(visible_row);
1574                 }
1575
1576         vf_send_update(vf);
1577         vflist_thumb_update(vf);
1578 }
1579
1580 gint vflist_refresh(ViewFile *vf)
1581 {
1582         GList *old_list;
1583         gint ret = TRUE;
1584
1585         old_list = vf->list;
1586         vf->list = NULL;
1587
1588         DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1589         if (vf->dir_fd)
1590                 {
1591                 file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1592
1593                 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1594
1595                 file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1596
1597                 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1598                 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1599                 }
1600
1601         DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1602
1603         vflist_populate_view(vf);
1604
1605         filelist_free(old_list);
1606         DEBUG_1("%s vflist_refresh: done", get_exec_time());
1607
1608         return ret;
1609 }
1610
1611 static gint vflist_refresh_idle_cb(gpointer data)
1612 {
1613         ViewFile *vf = data;
1614
1615         vflist_refresh(vf);
1616         vf->refresh_idle_id = -1;
1617         return FALSE;
1618 }
1619
1620 static void vflist_refresh_idle_cancel(ViewFile *vf)
1621 {
1622         if (vf->refresh_idle_id != -1) g_source_remove(vf->refresh_idle_id);
1623         vf->refresh_idle_id = -1;
1624 }
1625
1626
1627 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1628
1629 #define CELL_HEIGHT_OVERRIDE 512
1630
1631 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1632 {
1633         GParamSpec *spec;
1634
1635         spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1636         if (spec && G_IS_PARAM_SPEC_INT(spec))
1637                 {
1638                 GParamSpecInt *spec_int;
1639
1640                 spec_int = G_PARAM_SPEC_INT(spec);
1641                 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1642                 }
1643 }
1644
1645 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1646 {
1647         static GdkColor color;
1648         static GtkWidget *done = NULL;
1649
1650         if (done != widget)
1651                 {
1652                 GtkStyle *style;
1653
1654                 style = gtk_widget_get_style(widget);
1655                 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1656                 shift_color(&color, -1, 0);
1657                 done = widget;
1658                 }
1659
1660         return &color;
1661 }
1662
1663 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1664                                      GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1665 {
1666         ViewFile *vf = data;
1667         gboolean set;
1668
1669         gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1670         g_object_set(G_OBJECT(cell),
1671                      "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1672                      "cell-background-set", set, NULL);
1673 }
1674
1675 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1676 {
1677         GtkTreeViewColumn *column;
1678         GtkCellRenderer *renderer;
1679
1680         column = gtk_tree_view_column_new();
1681         gtk_tree_view_column_set_title(column, title);
1682         gtk_tree_view_column_set_min_width(column, 4);
1683
1684         if (!image)
1685                 {
1686                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1687                 renderer = gtk_cell_renderer_text_new();
1688                 if (right_justify)
1689                         {
1690                         g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1691                         }
1692                 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1693                 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1694                 if (expand)
1695                         gtk_tree_view_column_set_expand(column, TRUE);
1696                 }
1697         else
1698                 {
1699                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1700                 renderer = gtk_cell_renderer_pixbuf_new();
1701                 cell_renderer_height_override(renderer);
1702                 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1703                 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1704                 }
1705
1706         gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1707         g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1708         g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1709
1710         gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1711 }
1712
1713 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1714 {
1715         ViewFile *vf = data;
1716         GtkTreeStore *store;
1717         GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1718         GtkTreeIter iter;
1719         FileData *fd;
1720         gboolean mark;
1721         guint col_idx;
1722
1723         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1724         if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1725                 return;
1726
1727         col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1728
1729         g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1730
1731         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1732         mark = !mark;
1733         file_data_unregister_notify_func(vflist_notify_cb, vf); /* we don't need the notification */
1734         file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1735         file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1736
1737         gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1738         gtk_tree_path_free(path);
1739 }
1740
1741 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1742 {
1743         GtkTreeViewColumn *column;
1744         GtkCellRenderer *renderer;
1745         GtkTreeStore *store;
1746         gint index;
1747
1748         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1749
1750         renderer = gtk_cell_renderer_toggle_new();
1751         column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1752
1753         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1754         g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1755         g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1756
1757         index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1758         gtk_tree_view_column_set_fixed_width(column, 16);
1759         gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1760
1761
1762         g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1763 }
1764
1765 /*
1766  *-----------------------------------------------------------------------------
1767  * base
1768  *-----------------------------------------------------------------------------
1769  */
1770
1771 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1772 {
1773         if (!dir_fd) return FALSE;
1774         if (vf->dir_fd == dir_fd) return TRUE;
1775
1776         file_data_unref(vf->dir_fd);
1777         vf->dir_fd = file_data_ref(dir_fd);
1778
1779         /* force complete reload */
1780         vflist_store_clear(vf);
1781
1782         filelist_free(vf->list);
1783         vf->list = NULL;
1784
1785         return vf_refresh(vf);
1786 }
1787
1788 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1789 {
1790         ViewFile *vf = data;
1791
1792         file_data_unregister_notify_func(vflist_notify_cb, vf);
1793
1794         vflist_select_idle_cancel(vf);
1795         vflist_refresh_idle_cancel(vf);
1796         vflist_thumb_stop(vf);
1797
1798         filelist_free(vf->list);
1799 }
1800
1801 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1802 {
1803         GtkTreeStore *store;
1804         GtkTreeSelection *selection;
1805
1806         GType flist_types[FILE_COLUMN_COUNT];
1807         int i;
1808
1809         vf->info = g_new0(ViewFileInfoList, 1);
1810         
1811         VFLIST_INFO(vf, click_fd) = NULL;
1812         VFLIST_INFO(vf, select_fd) = NULL;
1813         VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1814
1815         VFLIST_INFO(vf, select_idle_id) = -1;
1816         vf->refresh_idle_id = -1;
1817
1818
1819         flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1820         flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1821         flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1822         flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1823         flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1824         flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1825         flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1826         flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1827         for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1828                 flist_types[i] = G_TYPE_BOOLEAN;
1829
1830         store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1831
1832         vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1833         g_object_unref(store);
1834
1835         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1836         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1837         gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1838
1839         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1840         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1841
1842         vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1843
1844         for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1845                 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1846
1847         vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
1848         vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1849
1850         vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1851         vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1852
1853         file_data_register_notify_func(vflist_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1854         return vf;
1855 }
1856
1857 void vflist_thumb_set(ViewFile *vf, gint enable)
1858 {
1859         if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1860
1861         VFLIST_INFO(vf, thumbs_enabled) = enable;
1862         if (vf->layout) vf_refresh(vf);
1863 }
1864
1865 void vflist_marks_set(ViewFile *vf, gint enable)
1866 {
1867         GList *columns, *work;
1868
1869         if (vf->marks_enabled == enable) return;
1870
1871         vf->marks_enabled = enable;
1872
1873         columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1874
1875         work = columns;
1876         while (work)
1877                 {
1878                 GtkTreeViewColumn *column = work->data;
1879                 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1880                 work = work->next;
1881
1882                 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1883                         gtk_tree_view_column_set_visible(column, enable);
1884                 }
1885
1886         g_list_free(columns);
1887         //vf_refresh(vf);
1888 }
1889
1890 /*
1891  *-----------------------------------------------------------------------------
1892  * maintenance (for rename, move, remove)
1893  *-----------------------------------------------------------------------------
1894  */
1895
1896 static void vflist_notify_cb(FileData *fd, NotifyType type, gpointer data)
1897 {
1898         ViewFile *vf = data;
1899         gboolean refresh;
1900
1901         if (vf->refresh_idle_id != -1) return;
1902         
1903         refresh = (fd == vf->dir_fd);
1904
1905         if (!refresh)
1906                 {
1907                 gchar *base = remove_level_from_path(fd->path);
1908                 refresh = (strcmp(base, vf->dir_fd->path) == 0);
1909                 g_free(base);
1910                 }
1911
1912         if (type == NOTIFY_TYPE_CHANGE && fd->change)
1913                 {
1914                 if (!refresh && fd->change->dest)
1915                         {
1916                         gchar *dest_base = remove_level_from_path(fd->change->dest);
1917                         refresh = (strcmp(dest_base, vf->dir_fd->path) == 0);
1918                         g_free(dest_base);
1919                         }
1920
1921                 if (!refresh && fd->change->source)
1922                         {
1923                         gchar *source_base = remove_level_from_path(fd->change->source);
1924                         refresh = (strcmp(source_base, vf->dir_fd->path) == 0);
1925                         g_free(source_base);
1926                         }
1927                 }
1928         
1929         if (refresh && vf->refresh_idle_id == -1)
1930                 {
1931                 vf->refresh_idle_id = g_idle_add(vflist_refresh_idle_cb, vf);
1932                 }
1933 }
1934
1935 #if 0
1936
1937 gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
1938 {
1939         vflist_maint(vf, fd);
1940         return TRUE;
1941 }
1942 gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
1943 {
1944         vflist_maint(vf, fd);
1945         return TRUE;
1946 }
1947 gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
1948 {
1949         vflist_maint(vf, fd);
1950         return TRUE;
1951 }
1952
1953
1954 static gint vflist_maint_find_closest(ViewFile *vf, gint row, gint count, GList *ignore_list)
1955 {
1956         GList *list = NULL;
1957         GList *work;
1958         gint rev = row - 1;
1959         row ++;
1960
1961         work = ignore_list;
1962         while (work)
1963                 {
1964                 gint f = vf_index_by_path(vf, work->data);
1965                 if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f));
1966                 work = work->next;
1967                 }
1968
1969         while (list)
1970                 {
1971                 gint c = TRUE;
1972                 work = list;
1973                 while (work && c)
1974                         {
1975                         gpointer p = work->data;
1976                         work = work->next;
1977                         if (row == GPOINTER_TO_INT(p))
1978                                 {
1979                                 row++;
1980                                 c = FALSE;
1981                                 }
1982                         if (rev == GPOINTER_TO_INT(p))
1983                                 {
1984                                 rev--;
1985                                 c = FALSE;
1986                                 }
1987                         if (!c) list = g_list_remove(list, p);
1988                         }
1989                 if (c && list)
1990                         {
1991                         g_list_free(list);
1992                         list = NULL;
1993                         }
1994                 }
1995         if (row > count - 1)
1996                 {
1997                 if (rev < 0)
1998                         return -1;
1999                 else
2000                         return rev;
2001                 }
2002         else
2003                 {
2004                 return row;
2005                 }
2006 }
2007
2008 gint vflist_maint_renamed(ViewFile *vf, FileData *fd)
2009 {
2010         gint ret = FALSE;
2011         gchar *source_base;
2012         gchar *dest_base;
2013
2014         DEBUG_1("%s vflist_maint_renamed: start", get_exec_time());
2015
2016         if (g_list_index(vf->list, fd) < 0) return FALSE;
2017
2018         source_base = remove_level_from_path(fd->change->source);
2019         dest_base = remove_level_from_path(fd->change->dest);
2020
2021
2022         if (strcmp(source_base, dest_base) == 0)
2023                 {
2024                 GtkTreeStore *store;
2025                 GtkTreeIter iter;
2026                 GtkTreeIter position;
2027                 gint old_row;
2028                 gint n;
2029
2030                 old_row = g_list_index(vf->list, fd);
2031
2032                 vf->list = g_list_remove(vf->list, fd);
2033
2034                 vf->list = filelist_insert_sort(vf->list, fd, vf->sort_method, vf->sort_ascend);
2035                 n = g_list_index(vf->list, fd);
2036
2037                 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
2038                 if (vflist_find_row(vf, fd, &iter) >= 0 &&
2039                     gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &position, NULL, n))
2040                         {
2041                         if (old_row >= n)
2042                                 {
2043                                 gtk_tree_store_move_before(store, &iter, &position);
2044                                 }
2045                         else
2046                                 {
2047                                 gtk_tree_store_move_after(store, &iter, &position);
2048                                 }
2049                         }
2050                 gtk_tree_store_set(store, &iter, FILE_COLUMN_NAME, fd->name, -1);
2051
2052                 ret = TRUE;
2053                 }
2054         else
2055                 {
2056                 ret = vflist_maint_removed(vf, fd, NULL);
2057                 }
2058
2059         g_free(source_base);
2060         g_free(dest_base);
2061
2062         DEBUG_1("%s vflist_maint_renamed: done", get_exec_time());
2063
2064         return ret;
2065 }
2066
2067 gint vflist_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list)
2068 {
2069         GtkTreeIter iter;
2070         GList *list;
2071         gint row;
2072         gint new_row = -1;
2073
2074         DEBUG_1("%s vflist_maint_removed: start", get_exec_time());
2075
2076         row = g_list_index(vf->list, fd);
2077         if (row < 0) return FALSE;
2078
2079         if (vflist_index_is_selected(vf, row) &&
2080             layout_image_get_collection(vf->layout, NULL) == NULL)
2081                 {
2082                 gint n;
2083
2084                 n = vf_count(vf, NULL);
2085                 if (ignore_list)
2086                         {
2087                         new_row = vflist_maint_find_closest(vf, row, n, ignore_list);
2088                         DEBUG_1("row = %d, closest is %d", row, new_row);
2089                         }
2090                 else
2091                         {
2092                         if (row + 1 < n)
2093                                 {
2094                                 new_row = row + 1;
2095                                 }
2096                         else if (row > 0)
2097                                 {
2098                                 new_row = row - 1;
2099                                 }
2100                         }
2101                 vf_select_none(vf);
2102                 if (new_row >= 0)
2103                         {
2104                         fd = vf_index_get_data(vf, new_row);
2105                         if (vflist_find_row(vf, fd, &iter) >= 0)
2106                                 {
2107                                 GtkTreeSelection *selection;
2108
2109                                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
2110                                 gtk_tree_selection_select_iter(selection, &iter);
2111                                 vflist_move_cursor(vf, &iter);
2112                                 }
2113                         }
2114                 }
2115
2116         fd = vf_index_get_data(vf, row);
2117         if (vflist_find_row(vf, fd, &iter) >= 0)
2118                 {
2119                 GtkTreeStore *store;
2120                 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
2121                 gtk_tree_store_remove(store, &iter);
2122                 }
2123         list = g_list_nth(vf->list, row);
2124         fd = list->data;
2125
2126         /* thumbnail loader check */
2127         if (fd == vf->thumbs_filedata) vf->thumbs_filedata = NULL;
2128         if (vf->thumbs_count > 0) vf->thumbs_count--;
2129
2130         vf->list = g_list_remove(vf->list, fd);
2131         file_data_unref(fd);
2132
2133         vf_send_update(vf);
2134
2135         DEBUG_1("%s vflist_maint_removed: done", get_exec_time());
2136
2137         return TRUE;
2138 }
2139
2140 gint vflist_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list)
2141 {
2142         gint ret = FALSE;
2143         gchar *buf;
2144
2145         if (!fd->change->source || !vf->path) return FALSE;
2146
2147         buf = remove_level_from_path(fd->change->source);
2148
2149         if (strcmp(buf, vf->path) == 0)
2150                 {
2151                 ret = vflist_maint_removed(vf, fd, ignore_list);
2152                 }
2153
2154         g_free(buf);
2155
2156         return ret;
2157 }
2158 #endif