implemented marks filter
[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_fileops.h"
27 #include "ui_menu.h"
28 #include "ui_tree_edit.h"
29 #include "uri_utils.h"
30 #include "view_file.h"
31
32 #include <gdk/gdkkeysyms.h> /* for keyboard values */
33
34 /* Index to tree store */
35 enum {
36         FILE_COLUMN_POINTER = 0,
37         FILE_COLUMN_VERSION,
38         FILE_COLUMN_THUMB,
39         FILE_COLUMN_NAME,
40         FILE_COLUMN_MULTILINE,
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 /* Index to tree view */
51 enum {
52         FILE_VIEW_COLUMN_MARKS = 0,
53         FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
54         FILE_VIEW_COLUMN_THUMB,
55         FILE_VIEW_COLUMN_MULTILINE,
56         FILE_VIEW_COLUMN_NAME,
57         FILE_VIEW_COLUMN_SIZE,
58         FILE_VIEW_COLUMN_DATE,
59         FILE_VIEW_COLUMN_COUNT
60 };
61
62
63
64 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
65 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
66 static void vflist_populate_view(ViewFile *vf);
67
68
69 /*
70  *-----------------------------------------------------------------------------
71  * misc
72  *-----------------------------------------------------------------------------
73  */
74 typedef struct {
75         FileData *fd;
76         GtkTreeIter *iter;
77         gint found;
78         gint row;
79 } ViewFileFindRowData;
80
81 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
82 {
83         ViewFileFindRowData *find = data;
84         FileData *fd;
85         gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
86         if (fd == find->fd)
87                 {
88                 *find->iter = *iter;
89                 find->found = 1;
90                 return TRUE;
91                 }
92         find->row++;
93         return FALSE;
94 }
95
96 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
97 {
98         GtkTreeModel *store;
99         ViewFileFindRowData data = {fd, iter, 0, 0};
100
101         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
102         gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
103
104         if (data.found)
105                 {
106                 return data.row;
107                 }
108
109         return -1;
110 }
111
112
113 /*
114 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
115 {
116         gint i = 0;
117         while (work)
118                 {
119                 FileData *fd_p = work->data;
120                 if (fd == fd_p) return i;
121
122                 i++;
123
124                 GList *work2 = fd_p->sidecar_files;
125                 while (work2)
126                         {
127                         fd_p = work2->data;
128                         if (fd == fd_p) return i;
129
130                         i++;
131                         work2 = work2->next;
132                         }
133                 work = work->next;
134                 }
135         return -1;
136 }
137 */
138
139 static gint vflist_sidecar_list_count(GList *work)
140 {
141         gint i = 0;
142         while (work)
143                 {
144                 FileData *fd = work->data;
145                 i++;
146
147                 GList *work2 = fd->sidecar_files;
148                 while (work2)
149                         {
150                         i++;
151                         work2 = work2->next;
152                         }
153                 work = work->next;
154                 }
155         return i;
156 }
157
158 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
159 {
160         FileData *fd;
161         gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
162         file_data_unref(fd);
163         return FALSE;
164 }
165
166 static void vflist_store_clear(ViewFile *vf)
167 {
168         GtkTreeModel *store;
169         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
170         gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
171         gtk_tree_store_clear(GTK_TREE_STORE(store));
172 }
173
174 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
175 {
176         GtkTreeModel *store;
177         GtkTreeIter iter;
178
179         if (vflist_find_row(vf, fd, &iter) < 0) return;
180         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
181         gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
182 }
183
184 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
185 {
186         GtkTreeModel *store;
187         GtkTreePath *tpath;
188
189         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
190
191         tpath = gtk_tree_model_get_path(store, iter);
192         gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
193         gtk_tree_path_free(tpath);
194 }
195
196
197 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
198 {
199         GList *columns, *work;
200         gint i = 0;
201
202         columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
203         work = columns;
204         while (work)
205                 {
206                 GtkTreeViewColumn *column = work->data;
207                 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
208                         break;
209                 work = work->next;
210                 i++;
211                 }
212
213         g_list_free(columns);
214         return i;
215 }
216
217
218 /*
219  *-----------------------------------------------------------------------------
220  * dnd
221  *-----------------------------------------------------------------------------
222  */
223
224 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
225                            GtkSelectionData *selection_data, guint info,
226                            guint time, gpointer data)
227 {
228         ViewFile *vf = data;
229         GList *list = NULL;
230         gchar *uri_text = NULL;
231         gint total;
232
233         if (!VFLIST_INFO(vf, click_fd)) return;
234
235         if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
236                 {
237                 list = vf_selection_get_list(vf);
238                 }
239         else
240                 {
241                 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
242                 }
243
244         if (!list) return;
245
246         uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
247         filelist_free(list);
248
249         DEBUG_1(uri_text);
250
251         gtk_selection_data_set(selection_data, selection_data->target,
252                                8, (guchar *)uri_text, total);
253         g_free(uri_text);
254 }
255
256 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
257 {
258         ViewFile *vf = data;
259
260         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
261
262         if (VFLIST_INFO(vf, thumbs_enabled) &&
263             VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->thumb_pixbuf)
264                 {
265                 guint items;
266
267                 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
268                         items = vf_selection_count(vf, NULL);
269                 else
270                         items = 1;
271
272                 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->thumb_pixbuf, items);
273                 }
274 }
275
276 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
277 {
278         ViewFile *vf = data;
279
280         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
281
282         if (context->action == GDK_ACTION_MOVE)
283                 {
284                 vf_refresh(vf);
285                 }
286 }
287
288 void vflist_dnd_init(ViewFile *vf)
289 {
290         gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
291                             dnd_file_drag_types, dnd_file_drag_types_count,
292                             GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
293         g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
294                          G_CALLBACK(vflist_dnd_get), vf);
295         g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
296                          G_CALLBACK(vflist_dnd_begin), vf);
297         g_signal_connect(G_OBJECT(vf->listview), "drag_end",
298                          G_CALLBACK(vflist_dnd_end), vf);
299 }
300
301 /*
302  *-----------------------------------------------------------------------------
303  * pop-up menu
304  *-----------------------------------------------------------------------------
305  */
306
307 GList *vflist_pop_menu_file_list(ViewFile *vf)
308 {
309         if (!VFLIST_INFO(vf, click_fd)) return NULL;
310
311         if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
312                 {
313                 return vf_selection_get_list(vf);
314                 }
315
316         return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
317 }
318
319 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
320 {
321         ViewFile *vf = data;
322
323         if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
324                 {
325                 GList *list;
326
327                 list = vf_selection_get_list(vf);
328                 view_window_new_from_list(list);
329                 filelist_free(list);
330                 }
331         else
332                 {
333                 view_window_new(VFLIST_INFO(vf, click_fd));
334                 }
335 }
336
337 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
338 {
339         ViewFile *vf = data;
340         GList *list;
341
342         list = vf_pop_menu_file_list(vf);
343         if (options->file_ops.enable_in_place_rename &&
344             list && !list->next && VFLIST_INFO(vf, click_fd))
345                 {
346                 GtkTreeModel *store;
347                 GtkTreeIter iter;
348
349                 filelist_free(list);
350
351                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
352                 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
353                         {
354                         GtkTreePath *tpath;
355
356                         tpath = gtk_tree_model_get_path(store, &iter);
357                         tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
358                                           vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
359                                           vflist_row_rename_cb, vf);
360                         gtk_tree_path_free(tpath);
361                         }
362                 return;
363                 }
364
365         file_util_rename(NULL, list, vf->listview);
366 }
367
368 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
369 {
370         ViewFile *vf = data;
371
372         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
373         if (vf->layout)
374                 {
375                 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
376                 }
377         else
378                 {
379                 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
380                 }
381 }
382
383 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
384 {
385         ViewFile *vf = data;
386
387         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
388         vf_refresh(vf);
389 }
390
391 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
392 {
393         ViewFile *vf = data;
394         vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
395         VFLIST_INFO(vf, click_fd) = NULL;
396         vf->popup = NULL;
397 }
398
399
400 /*
401  *-----------------------------------------------------------------------------
402  * callbacks
403  *-----------------------------------------------------------------------------
404  */
405
406 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
407 {
408         ViewFile *vf = data;
409         gchar *old_path;
410         gchar *new_path;
411
412         if (strlen(new) == 0) return FALSE;
413
414         old_path = g_build_filename(vf->dir_fd->path, old, NULL);
415         new_path = g_build_filename(vf->dir_fd->path, new, NULL);
416
417         if (strchr(new, G_DIR_SEPARATOR) != NULL)
418                 {
419                 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
420                 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
421                 g_free(text);
422                 }
423         else
424                 {
425                 FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
426                 file_util_rename_simple(fd, new_path, vf->listview);
427                 file_data_unref(fd);
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         gchar *size;
728         gchar *sidecars = NULL;
729         gchar *name_sidecars;
730         gchar *multiline;
731         const gchar *time = text_from_time(fd->date);
732         name_sidecars = (gchar *)fd->name;
733
734         if (fd->sidecar_files)
735                 {
736                 sidecars = file_data_sc_list_to_string(fd);
737                 name_sidecars = g_strdup_printf("%s %s", fd->name, sidecars);
738                 }
739         size = text_from_size(fd->size);
740         
741         multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
742
743         gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
744                                         FILE_COLUMN_VERSION, fd->version,
745                                         FILE_COLUMN_THUMB, fd->thumb_pixbuf,
746                                         FILE_COLUMN_MULTILINE, multiline,
747                                         FILE_COLUMN_NAME, name_sidecars,
748                                         FILE_COLUMN_SIZE, size,
749                                         FILE_COLUMN_DATE, time,
750 #define STORE_SET_IS_SLOW 1
751 #if STORE_SET_IS_SLOW   
752 /* this is 3x faster on a directory with 20000 files */
753                                         FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
754                                         FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
755                                         FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
756                                         FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
757                                         FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
758                                         FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
759 #if FILEDATA_MARKS_SIZE != 6
760 #error this needs to be updated  
761 #endif
762 #endif
763                                         FILE_COLUMN_COLOR, FALSE, -1);
764
765 #if !STORE_SET_IS_SLOW                                  
766         {
767         gint i;
768         for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
769                 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
770         }
771 #endif
772         g_free(size);
773         if (sidecars)
774                 {
775                 g_free(sidecars);
776                 g_free(name_sidecars);
777                 }
778         g_free(multiline);
779 }
780
781 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
782 {
783         GList *work;
784         GtkTreeIter iter;
785         gint valid;
786         gint num_ordered = 0;
787         gint num_prepended = 0;
788
789         valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
790
791         work = list;
792         while (work)
793                 {
794                 gint match;
795                 FileData *fd = work->data;
796                 gint done = FALSE;
797
798                 while (!done)
799                         {
800                         FileData *old_fd = NULL;
801                         gint old_version = 0;
802
803                         if (valid)
804                                 {
805                                 num_ordered++;
806                                 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
807                                                    FILE_COLUMN_POINTER, &old_fd,
808                                                    FILE_COLUMN_VERSION, &old_version,
809                                                    -1);
810
811                                 if (fd == old_fd)
812                                         {
813                                         match = 0;
814                                         }
815                                 else
816                                         {
817                                         if (parent_iter)
818                                                 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
819                                         else
820                                                 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
821
822                                         if (match == 0) g_warning("multiple fd for the same path");
823                                         }
824                                         
825                                 }
826                         else
827                                 {
828                                 match = -1;
829                                 }
830
831                         if (match < 0)
832                                 {
833                                 GtkTreeIter new;
834
835                                 if (valid)
836                                         {
837                                         gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
838                                         }
839                                 else
840                                         {
841                                         /*
842                                             here should be used gtk_tree_store_append, but this function seems to be O(n)
843                                             and it seems to be much faster to add new entries to the beginning and reorder later
844                                         */
845                                         num_prepended++;
846                                         gtk_tree_store_prepend(store, &new, parent_iter);
847                                         }
848
849                                 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
850                                 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
851                                 
852                                 if (g_list_find(selected, fd))
853                                         {
854                                         /* renamed files - the same fd appears at different position - select it again*/
855                                         GtkTreeSelection *selection;
856                                         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
857                                         gtk_tree_selection_select_iter(selection, &new);
858                                         }
859
860                                 done = TRUE;
861                                 }
862                         else if (match > 0)
863                                 {
864                                 file_data_unref(old_fd);
865                                 valid = gtk_tree_store_remove(store, &iter);
866                                 }
867                         else
868                                 {
869                                 if (fd->version != old_version)
870                                         {
871                                         vflist_setup_iter(vf, store, &iter, fd);
872                                         vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
873                                         }
874
875                                 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
876
877                                 done = TRUE;
878                                 }
879                         }
880                 work = work->next;
881                 }
882
883         while (valid)
884                 {
885                 FileData *old_fd;
886                 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
887                 file_data_unref(old_fd);
888
889                 valid = gtk_tree_store_remove(store, &iter);
890                 }
891                 
892         /* move the prepended entries to the correct position */
893         if (num_prepended)
894                 {
895                 gint i;
896                 gint num_total = num_prepended + num_ordered;
897                 gint *new_order = g_malloc(num_total * sizeof(gint));
898                 
899                 for (i = 0; i < num_total; i++)
900                         {
901                         if (i < num_ordered)
902                                 new_order[i] = num_prepended + i;
903                         else
904                                 new_order[i] = num_total - 1 - i;
905                         }
906                 gtk_tree_store_reorder(store, parent_iter, new_order);
907
908                 g_free(new_order);
909                 }
910 }
911
912 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
913 {
914         gint i;
915         GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
916         gint *new_order;
917         GtkTreeStore *store;
918         GList *work;
919
920         if (vf->sort_method == type && vf->sort_ascend == ascend) return;
921         if (!vf->list) return;
922
923         work = vf->list;
924         i = 0;
925         while (work)
926                 {
927                 FileData *fd = work->data;
928                 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
929                 i++;
930                 work = work->next;
931                 }
932
933         vf->sort_method = type;
934         vf->sort_ascend = ascend;
935
936         vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
937
938         new_order = g_malloc(i * sizeof(gint));
939
940         work = vf->list;
941         i = 0;
942         while (work)
943                 {
944                 FileData *fd = work->data;
945                 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
946                 i++;
947                 work = work->next;
948                 }
949
950         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
951         gtk_tree_store_reorder(store, NULL, new_order);
952
953         g_free(new_order);
954         g_hash_table_destroy(fd_idx_hash);
955 }
956
957 /*
958  *-----------------------------------------------------------------------------
959  * thumb updates
960  *-----------------------------------------------------------------------------
961  */
962
963 static gint vflist_thumb_next(ViewFile *vf);
964
965 static void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
966 {
967         GList *work = list;
968         while (work)
969                 {
970                 FileData *fd = work->data;
971                 work = work->next;
972
973                 if (fd->thumb_pixbuf) (*done)++;
974                 
975                 if (fd->sidecar_files) 
976                         {
977                         vflist_thumb_progress_count(fd->sidecar_files, count, done);
978                         }
979                 (*count)++;
980                 }
981 }
982
983 static gdouble vflist_thumb_progress(ViewFile *vf)
984 {
985         gint count = 0;
986         gint done = 0;
987         
988         vflist_thumb_progress_count(vf->list, &count, &done);
989
990         DEBUG_1("thumb progress: %d of %d", done, count);
991         return (gdouble)done / count;
992 }
993
994
995 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
996 {
997         if (vf->func_thumb_status)
998                 {
999                 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
1000                 }
1001 }
1002
1003 static void vflist_thumb_cleanup(ViewFile *vf)
1004 {
1005         vflist_thumb_status(vf, 0.0, NULL);
1006
1007         vf->thumbs_running = FALSE;
1008
1009         thumb_loader_free(vf->thumbs_loader);
1010         vf->thumbs_loader = NULL;
1011
1012         vf->thumbs_filedata = NULL;
1013 }
1014
1015 static void vflist_thumb_stop(ViewFile *vf)
1016 {
1017         if (vf->thumbs_running) vflist_thumb_cleanup(vf);
1018 }
1019
1020 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
1021 {
1022         GtkTreeStore *store;
1023         GtkTreeIter iter;
1024
1025         if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
1026
1027         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1028         gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
1029
1030         vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
1031 }
1032
1033 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
1034 {
1035         ViewFile *vf = data;
1036
1037         if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1038                 {
1039                 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1040                 }
1041
1042         while (vflist_thumb_next(vf));
1043 }
1044
1045 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
1046 {
1047         ViewFile *vf = data;
1048
1049         if (vf->thumbs_filedata && vf->thumbs_loader == tl)
1050                 {
1051                 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
1052                 }
1053
1054         while (vflist_thumb_next(vf));
1055 }
1056
1057 static gint vflist_thumb_next(ViewFile *vf)
1058 {
1059         GtkTreePath *tpath;
1060         FileData *fd = NULL;
1061
1062         /* first check the visible files */
1063
1064         if (GTK_WIDGET_REALIZED(vf->listview) &&
1065             gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1066                 {
1067                 GtkTreeModel *store;
1068                 GtkTreeIter iter;
1069                 gint valid = TRUE;
1070
1071                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1072                 gtk_tree_model_get_iter(store, &iter, tpath);
1073                 gtk_tree_path_free(tpath);
1074
1075                 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1076                         {
1077                         gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1078                         if (fd->thumb_pixbuf) fd = NULL;
1079
1080                         valid = gtk_tree_model_iter_next(store, &iter);
1081                         }
1082                 }
1083
1084         /* then find first undone */
1085
1086         if (!fd)
1087                 {
1088                 GList *work = vf->list;
1089                 while (work && !fd)
1090                         {
1091                         FileData *fd_p = work->data;
1092                         if (!fd_p->thumb_pixbuf)
1093                                 fd = fd_p;
1094                         else
1095                                 {
1096                                 GList *work2 = fd_p->sidecar_files;
1097
1098                                 while (work2 && !fd)
1099                                         {
1100                                         fd_p = work2->data;
1101                                         if (!fd_p->thumb_pixbuf) fd = fd_p;
1102                                         work2 = work2->next;
1103                                         }
1104                                 }
1105                         work = work->next;
1106                         }
1107                 }
1108
1109         if (!fd)
1110                 {
1111                 /* done */
1112                 vflist_thumb_cleanup(vf);
1113                 return FALSE;
1114                 }
1115
1116         vf->thumbs_filedata = fd;
1117
1118         thumb_loader_free(vf->thumbs_loader);
1119
1120         vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1121         thumb_loader_set_callbacks(vf->thumbs_loader,
1122                                    vflist_thumb_done_cb,
1123                                    vflist_thumb_error_cb,
1124                                    NULL,
1125                                    vf);
1126
1127         if (!thumb_loader_start(vf->thumbs_loader, fd))
1128                 {
1129                 /* set icon to unknown, continue */
1130                 DEBUG_1("thumb loader start failed %s", fd->path);
1131                 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1132
1133                 return TRUE;
1134                 }
1135
1136         return FALSE;
1137 }
1138
1139 static void vflist_thumb_update(ViewFile *vf)
1140 {
1141         vflist_thumb_stop(vf);
1142         if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1143
1144         vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1145         vf->thumbs_running = TRUE;
1146
1147         while (vflist_thumb_next(vf));
1148 }
1149
1150 /*
1151  *-----------------------------------------------------------------------------
1152  * row stuff
1153  *-----------------------------------------------------------------------------
1154  */
1155
1156 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1157 {
1158         return g_list_nth_data(vf->list, row);
1159 }
1160
1161 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1162 {
1163         gint p = 0;
1164         GList *work;
1165
1166         if (!path) return -1;
1167
1168         work = vf->list;
1169         while (work)
1170                 {
1171                 FileData *fd = work->data;
1172                 if (strcmp(path, fd->path) == 0) return p;
1173                 
1174                 work = work->next;
1175                 p++;
1176                 }
1177
1178         return -1;
1179 }
1180
1181 guint vflist_count(ViewFile *vf, gint64 *bytes)
1182 {
1183         if (bytes)
1184                 {
1185                 gint64 b = 0;
1186                 GList *work;
1187
1188                 work = vf->list;
1189                 while (work)
1190                         {
1191                         FileData *fd = work->data;
1192                         work = work->next;
1193                         b += fd->size;
1194                         }
1195
1196                 *bytes = b;
1197                 }
1198
1199         return g_list_length(vf->list);
1200 }
1201
1202 GList *vflist_get_list(ViewFile *vf)
1203 {
1204         GList *list = NULL;
1205         GList *work;
1206
1207         work = vf->list;
1208         while (work)
1209                 {
1210                 FileData *fd = work->data;
1211                 work = work->next;
1212
1213                 list = g_list_prepend(list, file_data_ref(fd));
1214                 }
1215
1216         return g_list_reverse(list);
1217 }
1218
1219 /*
1220  *-----------------------------------------------------------------------------
1221  * selections
1222  *-----------------------------------------------------------------------------
1223  */
1224
1225 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1226 {
1227         GtkTreeModel *store;
1228         GtkTreeSelection *selection;
1229         GList *slist;
1230         GList *work;
1231         gint found = FALSE;
1232
1233         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1234         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1235         work = slist;
1236         while (!found && work)
1237                 {
1238                 GtkTreePath *tpath = work->data;
1239                 FileData *fd_n;
1240                 GtkTreeIter iter;
1241
1242                 gtk_tree_model_get_iter(store, &iter, tpath);
1243                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1244                 if (fd_n == fd) found = TRUE;
1245                 work = work->next;
1246                 }
1247         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1248         g_list_free(slist);
1249
1250         return found;
1251 }
1252
1253 gint vflist_index_is_selected(ViewFile *vf, gint row)
1254 {
1255         FileData *fd;
1256
1257         fd = vf_index_get_data(vf, row);
1258         return vflist_row_is_selected(vf, fd);
1259 }
1260
1261 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1262 {
1263         GtkTreeModel *store;
1264         GtkTreeSelection *selection;
1265         GList *slist;
1266         guint count;
1267
1268         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1269         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1270
1271         if (bytes)
1272                 {
1273                 gint64 b = 0;
1274                 GList *work;
1275
1276                 work = slist;
1277                 while (work)
1278                         {
1279                         GtkTreePath *tpath = work->data;
1280                         GtkTreeIter iter;
1281                         FileData *fd;
1282
1283                         gtk_tree_model_get_iter(store, &iter, tpath);
1284                         gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1285                         b += fd->size;
1286
1287                         work = work->next;
1288                         }
1289
1290                 *bytes = b;
1291                 }
1292
1293         count = g_list_length(slist);
1294         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1295         g_list_free(slist);
1296
1297         return count;
1298 }
1299
1300 GList *vflist_selection_get_list(ViewFile *vf)
1301 {
1302         GtkTreeModel *store;
1303         GtkTreeSelection *selection;
1304         GList *slist;
1305         GList *list = NULL;
1306         GList *work;
1307
1308         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1309         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1310         work = slist;
1311         while (work)
1312                 {
1313                 GtkTreePath *tpath = work->data;
1314                 FileData *fd;
1315                 GtkTreeIter iter;
1316
1317                 gtk_tree_model_get_iter(store, &iter, tpath);
1318                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1319
1320                 list = g_list_prepend(list, file_data_ref(fd));
1321
1322                 work = work->next;
1323                 }
1324         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1325         g_list_free(slist);
1326
1327         return g_list_reverse(list);
1328 }
1329
1330 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1331 {
1332         GtkTreeModel *store;
1333         GtkTreeSelection *selection;
1334         GList *slist;
1335         GList *list = NULL;
1336         GList *work;
1337
1338         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1339         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1340         work = slist;
1341         while (work)
1342                 {
1343                 GtkTreePath *tpath = work->data;
1344                 FileData *fd;
1345                 GtkTreeIter iter;
1346
1347                 gtk_tree_model_get_iter(store, &iter, tpath);
1348                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1349
1350                 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1351
1352                 work = work->next;
1353                 }
1354         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1355         g_list_free(slist);
1356
1357         return g_list_reverse(list);
1358 }
1359
1360 void vflist_select_all(ViewFile *vf)
1361 {
1362         GtkTreeSelection *selection;
1363
1364         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1365         gtk_tree_selection_select_all(selection);
1366
1367         VFLIST_INFO(vf, select_fd) = NULL;
1368 }
1369
1370 void vflist_select_none(ViewFile *vf)
1371 {
1372         GtkTreeSelection *selection;
1373
1374         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1375         gtk_tree_selection_unselect_all(selection);
1376 }
1377
1378 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1379 {
1380         GtkTreePath *tpath;
1381         gboolean result;
1382
1383         tpath = gtk_tree_model_get_path(store, iter);
1384         result = gtk_tree_path_prev(tpath);
1385         if (result)
1386                 gtk_tree_model_get_iter(store, iter, tpath);
1387
1388         gtk_tree_path_free(tpath);
1389
1390         return result;
1391 }
1392
1393 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1394 {
1395         if (!gtk_tree_model_get_iter_first(store, iter))
1396                 return FALSE;
1397
1398         while (TRUE)
1399                 {
1400                 GtkTreeIter next = *iter;
1401                 
1402                 if (gtk_tree_model_iter_next(store, &next))
1403                         *iter = next;
1404                 else
1405                         break;
1406                 }
1407         
1408         return TRUE;
1409 }
1410
1411 void vflist_select_invert(ViewFile *vf)
1412 {
1413         GtkTreeIter iter;
1414         GtkTreeSelection *selection;
1415         GtkTreeModel *store;
1416         gboolean valid;
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         /* Backward iteration prevents scrolling to the end of the list,
1422          * it scrolls to the first selected row instead. */
1423         valid = tree_model_get_iter_last(store, &iter);
1424
1425         while (valid)
1426                 {
1427                 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1428
1429                 if (selected)
1430                         gtk_tree_selection_unselect_iter(selection, &iter);
1431                 else
1432                         gtk_tree_selection_select_iter(selection, &iter);
1433                                 
1434                 valid = tree_model_iter_prev(store, &iter);
1435                 }
1436 }
1437
1438 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1439 {
1440         GtkTreeIter iter;
1441
1442         if (vflist_find_row(vf, fd, &iter) < 0) return;
1443
1444         tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1445
1446         if (!vflist_row_is_selected(vf, fd))
1447                 {
1448                 GtkTreeSelection *selection;
1449                 GtkTreeModel *store;
1450                 GtkTreePath *tpath;
1451
1452                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1453                 gtk_tree_selection_unselect_all(selection);
1454                 gtk_tree_selection_select_iter(selection, &iter);
1455                 vflist_move_cursor(vf, &iter);
1456
1457                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1458                 tpath = gtk_tree_model_get_path(store, &iter);
1459                 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1460                 gtk_tree_path_free(tpath);
1461                 }
1462 }
1463
1464 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1465 {
1466         GList *work;
1467         
1468         if (sel_fd->parent) sel_fd = sel_fd->parent;
1469         work = vf->list;
1470         
1471         while (work)
1472                 {
1473                 gint match;
1474                 FileData *fd = work->data;
1475                 work = work->next;
1476                 
1477
1478                 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1479                 
1480                 if (match >= 0)
1481                         {
1482                         vflist_select_by_fd(vf, fd);
1483                         break;
1484                         }
1485                 }
1486
1487 }
1488
1489 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1490 {
1491         GtkTreeModel *store;
1492         GtkTreeIter iter;
1493         GtkTreeSelection *selection;
1494         gint valid;
1495         gint n = mark - 1;
1496
1497         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1498
1499         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1500         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1501
1502         valid = gtk_tree_model_get_iter_first(store, &iter);
1503         while (valid)
1504                 {
1505                 FileData *fd;
1506                 gboolean mark_val, selected;
1507                 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1508
1509                 mark_val = file_data_get_mark(fd, n);
1510                 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1511
1512                 switch (mode)
1513                         {
1514                         case MTS_MODE_SET: selected = mark_val;
1515                                 break;
1516                         case MTS_MODE_OR: selected = mark_val | selected;
1517                                 break;
1518                         case MTS_MODE_AND: selected = mark_val & selected;
1519                                 break;
1520                         case MTS_MODE_MINUS: selected = !mark_val & selected;
1521                                 break;
1522                         }
1523
1524                 if (selected)
1525                         gtk_tree_selection_select_iter(selection, &iter);
1526                 else
1527                         gtk_tree_selection_unselect_iter(selection, &iter);
1528
1529                 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1530                 }
1531 }
1532
1533 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1534 {
1535         GtkTreeModel *store;
1536         GtkTreeSelection *selection;
1537         GList *slist;
1538         GList *work;
1539         gint n = mark - 1;
1540
1541         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1542
1543         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1544         slist = gtk_tree_selection_get_selected_rows(selection, &store);
1545         work = slist;
1546         while (work)
1547                 {
1548                 GtkTreePath *tpath = work->data;
1549                 FileData *fd;
1550                 GtkTreeIter iter;
1551
1552                 gtk_tree_model_get_iter(store, &iter, tpath);
1553                 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1554
1555                 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1556
1557                 switch (mode)
1558                         {
1559                         case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1560                                 break;
1561                         case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1562                                 break;
1563                         case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1564                                 break;
1565                         }
1566                 
1567                 if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1568                         {
1569                         vf_refresh_idle(vf);
1570                         }
1571
1572                 
1573                 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1574
1575                 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1576
1577                 work = work->next;
1578                 }
1579         g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1580         g_list_free(slist);
1581 }
1582
1583 /*
1584  *-----------------------------------------------------------------------------
1585  * core (population)
1586  *-----------------------------------------------------------------------------
1587  */
1588
1589 static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
1590 {
1591         GtkTreeViewColumn *column;
1592         GtkCellRenderer *cell;
1593         GList *list;
1594         gboolean multiline;
1595
1596         column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
1597         if (!column) return;
1598
1599         gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
1600
1601         list = gtk_tree_view_column_get_cell_renderers(column);
1602         if (!list) return;
1603         cell = list->data;
1604         g_list_free(list);
1605
1606         g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1607         gtk_tree_view_column_set_visible(column, thumb);
1608
1609         multiline = (thumb && options->thumbnails.max_height >= 48);
1610         
1611         column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
1612         if (!column) return;
1613         gtk_tree_view_column_set_visible(column, multiline);
1614         if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1615
1616         column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
1617         if (!column) return;
1618         gtk_tree_view_column_set_visible(column, !multiline);
1619         if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
1620
1621         column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
1622         if (!column) return;
1623         gtk_tree_view_column_set_visible(column, !multiline);
1624
1625         column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
1626         if (!column) return;
1627         gtk_tree_view_column_set_visible(column, !multiline);
1628
1629         gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1630 }
1631
1632 static void vflist_populate_view(ViewFile *vf)
1633 {
1634         GtkTreeStore *store;
1635         gint thumbs;
1636         GtkTreeRowReference *visible_row = NULL;
1637         GtkTreePath *tpath;
1638         GList *selected;
1639
1640         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1641         thumbs = VFLIST_INFO(vf, thumbs_enabled);
1642
1643         vflist_thumb_stop(vf);
1644
1645         if (!vf->list)
1646                 {
1647                 vflist_store_clear(vf);
1648                 vf_send_update(vf);
1649                 return;
1650                 }
1651
1652         if (GTK_WIDGET_REALIZED(vf->listview) &&
1653             gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1654                 {
1655                 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1656                 gtk_tree_path_free(tpath);
1657                 }
1658
1659         vflist_listview_set_columns(vf->listview, thumbs);
1660
1661         selected = vflist_selection_get_list(vf);
1662         
1663         vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1664
1665         if (selected && vflist_selection_count(vf, NULL) == 0)
1666                 {
1667                 /* all selected files disappeared */
1668                 vflist_select_closest(vf, selected->data);
1669                 }       
1670
1671         filelist_free(selected);
1672         
1673         if (visible_row)
1674                 {
1675                 if (gtk_tree_row_reference_valid(visible_row))
1676                         {
1677                         tpath = gtk_tree_row_reference_get_path(visible_row);
1678                         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1679                         gtk_tree_path_free(tpath);
1680                         }
1681                 gtk_tree_row_reference_free(visible_row);
1682                 }
1683
1684         vf_send_update(vf);
1685         vflist_thumb_update(vf);
1686 }
1687
1688 gint vflist_refresh(ViewFile *vf)
1689 {
1690         GList *old_list;
1691         gint ret = TRUE;
1692
1693         old_list = vf->list;
1694         vf->list = NULL;
1695
1696         DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1697         if (vf->dir_fd)
1698                 {
1699                 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1700
1701                 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1702                 vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
1703                 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1704
1705                 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1706                 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1707                 }
1708
1709         DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1710
1711         vflist_populate_view(vf);
1712
1713         filelist_free(old_list);
1714         DEBUG_1("%s vflist_refresh: done", get_exec_time());
1715
1716         return ret;
1717 }
1718
1719
1720
1721 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1722
1723 #define CELL_HEIGHT_OVERRIDE 512
1724
1725 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1726 {
1727         GParamSpec *spec;
1728
1729         spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1730         if (spec && G_IS_PARAM_SPEC_INT(spec))
1731                 {
1732                 GParamSpecInt *spec_int;
1733
1734                 spec_int = G_PARAM_SPEC_INT(spec);
1735                 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1736                 }
1737 }
1738
1739 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1740 {
1741         static GdkColor color;
1742         static GtkWidget *done = NULL;
1743
1744         if (done != widget)
1745                 {
1746                 GtkStyle *style;
1747
1748                 style = gtk_widget_get_style(widget);
1749                 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1750                 shift_color(&color, -1, 0);
1751                 done = widget;
1752                 }
1753
1754         return &color;
1755 }
1756
1757 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1758                                      GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1759 {
1760         ViewFile *vf = data;
1761         gboolean set;
1762
1763         gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1764         g_object_set(G_OBJECT(cell),
1765                      "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1766                      "cell-background-set", set, NULL);
1767 }
1768
1769 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1770 {
1771         GtkTreeViewColumn *column;
1772         GtkCellRenderer *renderer;
1773
1774         column = gtk_tree_view_column_new();
1775         gtk_tree_view_column_set_title(column, title);
1776         gtk_tree_view_column_set_min_width(column, 4);
1777
1778         if (!image)
1779                 {
1780                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1781                 renderer = gtk_cell_renderer_text_new();
1782                 if (right_justify)
1783                         {
1784                         g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1785                         }
1786                 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1787                 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1788                 if (expand)
1789                         gtk_tree_view_column_set_expand(column, TRUE);
1790                 }
1791         else
1792                 {
1793                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1794                 renderer = gtk_cell_renderer_pixbuf_new();
1795                 cell_renderer_height_override(renderer);
1796                 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1797                 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1798                 }
1799
1800         gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1801         g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1802         g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1803
1804         gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1805 }
1806
1807 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1808 {
1809         ViewFile *vf = data;
1810         GtkTreeStore *store;
1811         GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1812         GtkTreeIter iter;
1813         FileData *fd;
1814         gboolean mark;
1815         guint col_idx;
1816
1817         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1818         if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1819                 return;
1820
1821         col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1822
1823         g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1824
1825         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1826         mark = !mark;
1827         file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1828         file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1829         if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
1830                 {
1831                 vf_refresh_idle(vf);
1832                 }
1833         file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1834
1835         gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1836         gtk_tree_path_free(path);
1837 }
1838
1839 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1840 {
1841         GtkTreeViewColumn *column;
1842         GtkCellRenderer *renderer;
1843         GtkTreeStore *store;
1844         gint index;
1845
1846         store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1847
1848         renderer = gtk_cell_renderer_toggle_new();
1849         column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1850
1851         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1852         g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1853         g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1854
1855         index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1856         gtk_tree_view_column_set_fixed_width(column, 18);
1857         gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1858
1859
1860         g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1861 }
1862
1863 /*
1864  *-----------------------------------------------------------------------------
1865  * base
1866  *-----------------------------------------------------------------------------
1867  */
1868
1869 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1870 {
1871         if (!dir_fd) return FALSE;
1872         if (vf->dir_fd == dir_fd) return TRUE;
1873
1874         file_data_unref(vf->dir_fd);
1875         vf->dir_fd = file_data_ref(dir_fd);
1876
1877         /* force complete reload */
1878         vflist_store_clear(vf);
1879
1880         filelist_free(vf->list);
1881         vf->list = NULL;
1882
1883         return vf_refresh(vf);
1884 }
1885
1886 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1887 {
1888         ViewFile *vf = data;
1889
1890         file_data_unregister_notify_func(vf_notify_cb, vf);
1891
1892         vflist_select_idle_cancel(vf);
1893         vf_refresh_idle_cancel(vf);
1894         vflist_thumb_stop(vf);
1895
1896         filelist_free(vf->list);
1897 }
1898
1899 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1900 {
1901         GtkTreeStore *store;
1902         GtkTreeSelection *selection;
1903
1904         GType flist_types[FILE_COLUMN_COUNT];
1905         gint i;
1906         gint column;
1907
1908         vf->info = g_new0(ViewFileInfoList, 1);
1909         
1910         VFLIST_INFO(vf, click_fd) = NULL;
1911         VFLIST_INFO(vf, select_fd) = NULL;
1912         VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1913
1914         VFLIST_INFO(vf, select_idle_id) = -1;
1915
1916         flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1917         flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1918         flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1919         flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1920         flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
1921         flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1922         flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1923         flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1924         for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1925                 flist_types[i] = G_TYPE_BOOLEAN;
1926
1927         store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1928
1929         vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1930         g_object_unref(store);
1931
1932         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1933         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1934         gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1935
1936         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1937         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1938
1939         column = 0;
1940
1941         for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1942                 {
1943                 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1944                 g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
1945                 column++;
1946                 }
1947
1948         vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1949         g_assert(column == FILE_VIEW_COLUMN_THUMB);
1950         column++;
1951         
1952         vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
1953         g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
1954         column++;
1955
1956         vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
1957         g_assert(column == FILE_VIEW_COLUMN_NAME);
1958         column++;
1959
1960         vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1961         g_assert(column == FILE_VIEW_COLUMN_SIZE);
1962         column++;
1963
1964         vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1965         g_assert(column == FILE_VIEW_COLUMN_DATE);
1966         column++;
1967
1968         file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1969         return vf;
1970 }
1971
1972 void vflist_thumb_set(ViewFile *vf, gint enable)
1973 {
1974         if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1975
1976         VFLIST_INFO(vf, thumbs_enabled) = enable;
1977         if (vf->layout) vf_refresh(vf);
1978 }
1979
1980 void vflist_marks_set(ViewFile *vf, gint enable)
1981 {
1982         GList *columns, *work;
1983
1984         columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1985
1986         work = columns;
1987         while (work)
1988                 {
1989                 GtkTreeViewColumn *column = work->data;
1990                 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1991                 work = work->next;
1992
1993                 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1994                         gtk_tree_view_column_set_visible(column, enable);
1995                 }
1996
1997         g_list_free(columns);
1998         //vf_refresh(vf);
1999 }
2000