Mercurial > geeqie
comparison src/view_file_list.c @ 9:d907d608745f
Sync to GQview 1.5.9 release.
########
DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS!
This CVS is never up to date with current development and is provided
solely for reference purposes, please use the latest official release
package when making any changes or translation updates.
########
author | gqview |
---|---|
date | Sat, 26 Feb 2005 00:13:35 +0000 |
parents | |
children | 04ff0df3ad2f |
comparison
equal
deleted
inserted
replaced
8:e0d0593d519e | 9:d907d608745f |
---|---|
1 /* | |
2 * GQview | |
3 * (C) 2004 John Ellis | |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 #include "gqview.h" | |
13 #include "view_file_list.h" | |
14 | |
15 #include "cache_maint.h" | |
16 #include "dnd.h" | |
17 #include "editors.h" | |
18 #include "img-view.h" | |
19 #include "info.h" | |
20 #include "layout.h" | |
21 #include "layout_image.h" | |
22 #include "menu.h" | |
23 #include "thumb.h" | |
24 #include "utilops.h" | |
25 #include "ui_bookmark.h" | |
26 #include "ui_fileops.h" | |
27 #include "ui_menu.h" | |
28 #include "ui_tree_edit.h" | |
29 | |
30 #include <gdk/gdkkeysyms.h> /* for keyboard values */ | |
31 | |
32 | |
33 enum { | |
34 FILE_COLUMN_POINTER = 0, | |
35 FILE_COLUMN_THUMB, | |
36 FILE_COLUMN_NAME, | |
37 FILE_COLUMN_SIZE, | |
38 FILE_COLUMN_DATE, | |
39 FILE_COLUMN_COLOR, | |
40 FILE_COLUMN_COUNT | |
41 }; | |
42 | |
43 | |
44 static gint vflist_row_is_selected(ViewFileList *vfl, FileData *fd); | |
45 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data); | |
46 static void vflist_populate_view(ViewFileList *vfl); | |
47 | |
48 /* | |
49 *----------------------------------------------------------------------------- | |
50 * signals | |
51 *----------------------------------------------------------------------------- | |
52 */ | |
53 | |
54 static void vflist_send_update(ViewFileList *vfl) | |
55 { | |
56 if (vfl->func_status) vfl->func_status(vfl, vfl->data_status); | |
57 } | |
58 | |
59 /* | |
60 *----------------------------------------------------------------------------- | |
61 * misc | |
62 *----------------------------------------------------------------------------- | |
63 */ | |
64 | |
65 static gint vflist_find_row(ViewFileList *vfl, FileData *fd, GtkTreeIter *iter) | |
66 { | |
67 GtkTreeModel *store; | |
68 gint valid; | |
69 gint row = 0; | |
70 | |
71 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)); | |
72 valid = gtk_tree_model_get_iter_first(store, iter); | |
73 while (valid) | |
74 { | |
75 FileData *fd_n; | |
76 gtk_tree_model_get(GTK_TREE_MODEL(store), iter, FILE_COLUMN_POINTER, &fd_n, -1); | |
77 if (fd_n == fd) return row; | |
78 | |
79 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter); | |
80 row++; | |
81 } | |
82 | |
83 return -1; | |
84 } | |
85 | |
86 static void vflist_color_set(ViewFileList *vfl, FileData *fd, gint color_set) | |
87 { | |
88 GtkTreeModel *store; | |
89 GtkTreeIter iter; | |
90 | |
91 if (vflist_find_row(vfl, fd, &iter) < 0) return; | |
92 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)); | |
93 gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1); | |
94 } | |
95 | |
96 static void vflist_move_cursor(ViewFileList *vfl, GtkTreeIter *iter) | |
97 { | |
98 GtkTreeModel *store; | |
99 GtkTreePath *tpath; | |
100 | |
101 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)); | |
102 | |
103 tpath = gtk_tree_model_get_path(store, iter); | |
104 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vfl->listview), tpath, NULL, FALSE); | |
105 gtk_tree_path_free(tpath); | |
106 } | |
107 | |
108 /* | |
109 *----------------------------------------------------------------------------- | |
110 * dnd | |
111 *----------------------------------------------------------------------------- | |
112 */ | |
113 | |
114 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context, | |
115 GtkSelectionData *selection_data, guint info, | |
116 guint time, gpointer data) | |
117 { | |
118 ViewFileList *vfl = data; | |
119 GList *list = NULL; | |
120 gchar *uri_text = NULL; | |
121 gint total; | |
122 | |
123 if (!vfl->click_fd) return; | |
124 | |
125 if (vflist_row_is_selected(vfl, vfl->click_fd)) | |
126 { | |
127 list = vflist_selection_get_list(vfl); | |
128 } | |
129 else | |
130 { | |
131 list = g_list_append(NULL, g_strdup(vfl->click_fd->path)); | |
132 } | |
133 | |
134 if (!list) return; | |
135 | |
136 uri_text = uri_text_from_list(list, &total, (info == TARGET_TEXT_PLAIN)); | |
137 path_list_free(list); | |
138 | |
139 if (debug) printf(uri_text); | |
140 | |
141 gtk_selection_data_set(selection_data, selection_data->target, 8, uri_text, total); | |
142 g_free(uri_text); | |
143 } | |
144 | |
145 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data) | |
146 { | |
147 ViewFileList *vfl = data; | |
148 | |
149 vflist_color_set(vfl, vfl->click_fd, TRUE); | |
150 | |
151 if (vfl->thumbs_enabled && | |
152 vfl->click_fd && vfl->click_fd->pixbuf) | |
153 { | |
154 gint items; | |
155 | |
156 if (vflist_row_is_selected(vfl, vfl->click_fd)) | |
157 items = vflist_selection_count(vfl, NULL); | |
158 else | |
159 items = 1; | |
160 | |
161 dnd_set_drag_icon(widget, context, vfl->click_fd->pixbuf, items); | |
162 } | |
163 } | |
164 | |
165 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data) | |
166 { | |
167 ViewFileList *vfl = data; | |
168 | |
169 vflist_color_set(vfl, vfl->click_fd, FALSE); | |
170 | |
171 if (context->action == GDK_ACTION_MOVE) | |
172 { | |
173 vflist_refresh(vfl); | |
174 } | |
175 } | |
176 | |
177 static void vflist_dnd_init(ViewFileList *vfl) | |
178 { | |
179 gtk_drag_source_set(vfl->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, | |
180 dnd_file_drag_types, dnd_file_drag_types_count, | |
181 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); | |
182 g_signal_connect(G_OBJECT(vfl->listview), "drag_data_get", | |
183 G_CALLBACK(vflist_dnd_get), vfl); | |
184 g_signal_connect(G_OBJECT(vfl->listview), "drag_begin", | |
185 G_CALLBACK(vflist_dnd_begin), vfl); | |
186 g_signal_connect(G_OBJECT(vfl->listview), "drag_end", | |
187 G_CALLBACK(vflist_dnd_end), vfl); | |
188 } | |
189 | |
190 /* | |
191 *----------------------------------------------------------------------------- | |
192 * pop-up menu | |
193 *----------------------------------------------------------------------------- | |
194 */ | |
195 | |
196 static GList *vflist_pop_menu_file_list(ViewFileList *vfl) | |
197 { | |
198 if (!vfl->click_fd) return NULL; | |
199 | |
200 if (vflist_row_is_selected(vfl, vfl->click_fd)) | |
201 { | |
202 return vflist_selection_get_list(vfl); | |
203 } | |
204 | |
205 return g_list_append(NULL, g_strdup(vfl->click_fd->path)); | |
206 } | |
207 | |
208 static void vflist_pop_menu_edit_cb(GtkWidget *widget, gpointer data) | |
209 { | |
210 ViewFileList *vfl; | |
211 gint n; | |
212 GList *list; | |
213 | |
214 vfl = submenu_item_get_data(widget); | |
215 n = GPOINTER_TO_INT(data); | |
216 | |
217 if (!vfl) return; | |
218 | |
219 list = vflist_pop_menu_file_list(vfl); | |
220 start_editor_from_path_list(n, list); | |
221 path_list_free(list); | |
222 } | |
223 | |
224 static void vflist_pop_menu_info_cb(GtkWidget *widget, gpointer data) | |
225 { | |
226 ViewFileList *vfl = data; | |
227 | |
228 info_window_new(NULL, vflist_pop_menu_file_list(vfl)); | |
229 } | |
230 | |
231 static void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data) | |
232 { | |
233 ViewFileList *vfl = data; | |
234 | |
235 if (vflist_row_is_selected(vfl, vfl->click_fd)) | |
236 { | |
237 GList *list; | |
238 | |
239 list = vflist_selection_get_list(vfl); | |
240 view_window_new_from_list(list); | |
241 path_list_free(list); | |
242 } | |
243 else | |
244 { | |
245 const gchar *path; | |
246 | |
247 path = vfl->click_fd->path; | |
248 view_window_new(path); | |
249 } | |
250 } | |
251 | |
252 static void vflist_pop_menu_copy_cb(GtkWidget *widget, gpointer data) | |
253 { | |
254 ViewFileList *vfl = data; | |
255 | |
256 file_util_copy(NULL, vflist_pop_menu_file_list(vfl), NULL, vfl->listview); | |
257 } | |
258 | |
259 static void vflist_pop_menu_move_cb(GtkWidget *widget, gpointer data) | |
260 { | |
261 ViewFileList *vfl = data; | |
262 | |
263 file_util_move(NULL, vflist_pop_menu_file_list(vfl), NULL, vfl->listview); | |
264 } | |
265 | |
266 static void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data) | |
267 { | |
268 ViewFileList *vfl = data; | |
269 GList *list; | |
270 | |
271 list = vflist_pop_menu_file_list(vfl); | |
272 if (enable_in_place_rename && | |
273 list && !list->next && vfl->click_fd) | |
274 { | |
275 GtkTreeModel *store; | |
276 GtkTreeIter iter; | |
277 | |
278 path_list_free(list); | |
279 | |
280 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)); | |
281 if (vflist_find_row(vfl, vfl->click_fd, &iter) >= 0) | |
282 { | |
283 GtkTreePath *tpath; | |
284 | |
285 tpath = gtk_tree_model_get_path(store, &iter); | |
286 tree_edit_by_path(GTK_TREE_VIEW(vfl->listview), tpath, | |
287 FILE_COLUMN_NAME -1, vfl->click_fd->name, | |
288 vflist_row_rename_cb, vfl); | |
289 gtk_tree_path_free(tpath); | |
290 } | |
291 return; | |
292 } | |
293 | |
294 file_util_rename(NULL, list, vfl->listview); | |
295 } | |
296 | |
297 static void vflist_pop_menu_delete_cb(GtkWidget *widget, gpointer data) | |
298 { | |
299 ViewFileList *vfl = data; | |
300 | |
301 file_util_delete(NULL, vflist_pop_menu_file_list(vfl), vfl->listview); | |
302 } | |
303 | |
304 static void vflist_pop_menu_sort_cb(GtkWidget *widget, gpointer data) | |
305 { | |
306 ViewFileList *vfl; | |
307 SortType type; | |
308 | |
309 vfl = submenu_item_get_data(widget); | |
310 if (!vfl) return; | |
311 | |
312 type = (SortType)GPOINTER_TO_INT(data); | |
313 | |
314 if (vfl->layout) | |
315 { | |
316 layout_sort_set(vfl->layout, type, vfl->sort_ascend); | |
317 } | |
318 else | |
319 { | |
320 vflist_sort_set(vfl, type, vfl->sort_ascend); | |
321 } | |
322 } | |
323 | |
324 static void vflist_pop_menu_sort_ascend_cb(GtkWidget *widget, gpointer data) | |
325 { | |
326 ViewFileList *vfl = data; | |
327 | |
328 if (vfl->layout) | |
329 { | |
330 layout_sort_set(vfl->layout, vfl->sort_method, !vfl->sort_ascend); | |
331 } | |
332 else | |
333 { | |
334 vflist_sort_set(vfl, vfl->sort_method, !vfl->sort_ascend); | |
335 } | |
336 } | |
337 | |
338 static void vflist_pop_menu_icons_cb(GtkWidget *widget, gpointer data) | |
339 { | |
340 ViewFileList *vfl = data; | |
341 | |
342 if (vfl->layout) layout_views_set(vfl->layout, vfl->layout->tree_view, TRUE); | |
343 } | |
344 | |
345 static void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data) | |
346 { | |
347 ViewFileList *vfl = data; | |
348 | |
349 vflist_color_set(vfl, vfl->click_fd, FALSE); | |
350 if (vfl->layout) | |
351 { | |
352 layout_thumb_set(vfl->layout, !vfl->thumbs_enabled); | |
353 } | |
354 else | |
355 { | |
356 vflist_thumb_set(vfl, !vfl->thumbs_enabled); | |
357 } | |
358 } | |
359 | |
360 static void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data) | |
361 { | |
362 ViewFileList *vfl = data; | |
363 | |
364 vflist_color_set(vfl, vfl->click_fd, FALSE); | |
365 vflist_refresh(vfl); | |
366 } | |
367 | |
368 static void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data) | |
369 { | |
370 ViewFileList *vfl = data; | |
371 vflist_color_set(vfl, vfl->click_fd, FALSE); | |
372 vfl->click_fd = NULL; | |
373 vfl->popup = NULL; | |
374 } | |
375 | |
376 static GtkWidget *vflist_pop_menu(ViewFileList *vfl, FileData *fd) | |
377 { | |
378 GtkWidget *menu; | |
379 GtkWidget *item; | |
380 GtkWidget *submenu; | |
381 gint active; | |
382 | |
383 vflist_color_set(vfl, fd, TRUE); | |
384 active = (fd != NULL); | |
385 | |
386 menu = popup_menu_short_lived(); | |
387 g_signal_connect(G_OBJECT(menu), "destroy", | |
388 G_CALLBACK(vflist_popup_destroy_cb), vfl); | |
389 | |
390 submenu_add_edit(menu, &item, G_CALLBACK(vflist_pop_menu_edit_cb), vfl); | |
391 gtk_widget_set_sensitive(item, active); | |
392 | |
393 menu_item_add_stock_sensitive(menu, _("_Properties"), GTK_STOCK_PROPERTIES, active, | |
394 G_CALLBACK(vflist_pop_menu_info_cb), vfl); | |
395 menu_item_add_stock_sensitive(menu, _("View in _new window"), GTK_STOCK_NEW, active, | |
396 G_CALLBACK(vflist_pop_menu_view_cb), vfl); | |
397 | |
398 menu_item_add_divider(menu); | |
399 menu_item_add_stock_sensitive(menu, _("_Copy..."), GTK_STOCK_COPY, active, | |
400 G_CALLBACK(vflist_pop_menu_copy_cb), vfl); | |
401 menu_item_add_sensitive(menu, _("_Move..."), active, | |
402 G_CALLBACK(vflist_pop_menu_move_cb), vfl); | |
403 menu_item_add_sensitive(menu, _("_Rename..."), active, | |
404 G_CALLBACK(vflist_pop_menu_rename_cb), vfl); | |
405 menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, active, | |
406 G_CALLBACK(vflist_pop_menu_delete_cb), vfl); | |
407 | |
408 menu_item_add_divider(menu); | |
409 | |
410 submenu = submenu_add_sort(NULL, G_CALLBACK(vflist_pop_menu_sort_cb), vfl, | |
411 FALSE, FALSE, TRUE, vfl->sort_method); | |
412 menu_item_add_divider(submenu); | |
413 menu_item_add_check(submenu, _("Ascending"), vfl->sort_ascend, | |
414 G_CALLBACK(vflist_pop_menu_sort_ascend_cb), vfl); | |
415 | |
416 item = menu_item_add(menu, _("_Sort"), NULL, NULL); | |
417 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); | |
418 | |
419 menu_item_add_check(menu, _("View as _icons"), FALSE, | |
420 G_CALLBACK(vflist_pop_menu_icons_cb), vfl); | |
421 menu_item_add_check(menu, _("Show _thumbnails"), vfl->thumbs_enabled, | |
422 G_CALLBACK(vflist_pop_menu_thumbs_cb), vfl); | |
423 menu_item_add_stock(menu, _("Re_fresh"), GTK_STOCK_REFRESH, G_CALLBACK(vflist_pop_menu_refresh_cb), vfl); | |
424 | |
425 return menu; | |
426 } | |
427 | |
428 /* | |
429 *----------------------------------------------------------------------------- | |
430 * callbacks | |
431 *----------------------------------------------------------------------------- | |
432 */ | |
433 | |
434 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data) | |
435 { | |
436 ViewFileList *vfl = data; | |
437 gchar *old_path; | |
438 gchar *new_path; | |
439 | |
440 if (strlen(new) == 0) return FALSE; | |
441 | |
442 old_path = concat_dir_and_file(vfl->path, old); | |
443 new_path = concat_dir_and_file(vfl->path, new); | |
444 | |
445 if (strchr(new, '/') != NULL) | |
446 { | |
447 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new); | |
448 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vfl->listview); | |
449 g_free(text); | |
450 } | |
451 else if (isfile(new_path)) | |
452 { | |
453 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new); | |
454 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vfl->listview); | |
455 g_free(text); | |
456 } | |
457 else if (!rename_file(old_path, new_path)) | |
458 { | |
459 gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\nto:\n%s"), old, new); | |
460 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vfl->listview); | |
461 g_free(text); | |
462 } | |
463 else | |
464 { | |
465 file_maint_renamed(old_path, new_path); | |
466 } | |
467 | |
468 g_free(old_path); | |
469 g_free(new_path); | |
470 | |
471 return FALSE; | |
472 } | |
473 | |
474 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data) | |
475 { | |
476 ViewFileList *vfl = data; | |
477 GtkTreeModel *store; | |
478 GtkTreeIter iter; | |
479 GtkTreePath *tpath; | |
480 gint cw, ch; | |
481 | |
482 if (vflist_find_row(vfl, vfl->click_fd, &iter) < 0) return; | |
483 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)); | |
484 tpath = gtk_tree_model_get_path(store, &iter); | |
485 tree_view_get_cell_clamped(GTK_TREE_VIEW(vfl->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch); | |
486 gtk_tree_path_free(tpath); | |
487 *y += ch; | |
488 popup_menu_position_clamp(menu, x, y, 0); | |
489 } | |
490 | |
491 static gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
492 { | |
493 ViewFileList *vfl = data; | |
494 GtkTreePath *tpath; | |
495 | |
496 if (event->keyval != GDK_Menu) return FALSE; | |
497 | |
498 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vfl->listview), &tpath, NULL); | |
499 if (tpath) | |
500 { | |
501 GtkTreeModel *store; | |
502 GtkTreeIter iter; | |
503 | |
504 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); | |
505 gtk_tree_model_get_iter(store, &iter, tpath); | |
506 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &vfl->click_fd, -1); | |
507 gtk_tree_path_free(tpath); | |
508 } | |
509 else | |
510 { | |
511 vfl->click_fd = NULL; | |
512 } | |
513 | |
514 vfl->popup = vflist_pop_menu(vfl, vfl->click_fd); | |
515 gtk_menu_popup(GTK_MENU(vfl->popup), NULL, NULL, vflist_menu_position_cb, vfl, 0, GDK_CURRENT_TIME); | |
516 | |
517 return TRUE; | |
518 } | |
519 | |
520 static gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
521 { | |
522 ViewFileList *vfl = data; | |
523 GtkTreePath *tpath; | |
524 GtkTreeIter iter; | |
525 FileData *fd = NULL; | |
526 | |
527 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, | |
528 &tpath, NULL, NULL, NULL)) | |
529 { | |
530 GtkTreeModel *store; | |
531 | |
532 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); | |
533 gtk_tree_model_get_iter(store, &iter, tpath); | |
534 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1); | |
535 #if 0 | |
536 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE); | |
537 #endif | |
538 gtk_tree_path_free(tpath); | |
539 } | |
540 | |
541 vfl->click_fd = fd; | |
542 | |
543 if (bevent->button == 3) | |
544 { | |
545 vfl->popup = vflist_pop_menu(vfl, vfl->click_fd); | |
546 gtk_menu_popup(GTK_MENU(vfl->popup), NULL, NULL, NULL, NULL, | |
547 bevent->button, bevent->time); | |
548 return TRUE; | |
549 } | |
550 | |
551 if (!fd) return FALSE; | |
552 | |
553 if (bevent->button == 2) | |
554 { | |
555 if (!vflist_row_is_selected(vfl, fd)) | |
556 { | |
557 vflist_color_set(vfl, fd, TRUE); | |
558 } | |
559 return TRUE; | |
560 } | |
561 | |
562 | |
563 if (bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS && | |
564 !(bevent->state & GDK_SHIFT_MASK ) && | |
565 !(bevent->state & GDK_CONTROL_MASK ) && | |
566 vflist_row_is_selected(vfl, fd)) | |
567 { | |
568 gtk_widget_grab_focus(widget); | |
569 return TRUE; | |
570 } | |
571 | |
572 #if 0 | |
573 if (bevent->button == 1 && bevent->type == GDK_2BUTTON_PRESS) | |
574 { | |
575 if (vfl->layout) layout_image_full_screen_start(vfl->layout); | |
576 } | |
577 #endif | |
578 | |
579 return FALSE; | |
580 } | |
581 | |
582 static gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
583 { | |
584 ViewFileList *vfl = data; | |
585 GtkTreePath *tpath; | |
586 GtkTreeIter iter; | |
587 FileData *fd = NULL; | |
588 | |
589 if (bevent->button == 2) | |
590 { | |
591 vflist_color_set(vfl, vfl->click_fd, FALSE); | |
592 } | |
593 | |
594 if (bevent->button != 1 && bevent->button != 2) | |
595 { | |
596 return TRUE; | |
597 } | |
598 | |
599 if ((bevent->x != 0 || bevent->y != 0) && | |
600 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, | |
601 &tpath, NULL, NULL, NULL)) | |
602 { | |
603 GtkTreeModel *store; | |
604 | |
605 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); | |
606 gtk_tree_model_get_iter(store, &iter, tpath); | |
607 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1); | |
608 gtk_tree_path_free(tpath); | |
609 } | |
610 | |
611 if (bevent->button == 2) | |
612 { | |
613 if (fd && vfl->click_fd == fd) | |
614 { | |
615 GtkTreeSelection *selection; | |
616 | |
617 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); | |
618 if (vflist_row_is_selected(vfl, fd)) | |
619 { | |
620 gtk_tree_selection_unselect_iter(selection, &iter); | |
621 } | |
622 else | |
623 { | |
624 gtk_tree_selection_select_iter(selection, &iter); | |
625 } | |
626 } | |
627 return TRUE; | |
628 } | |
629 | |
630 if (fd && vfl->click_fd == fd && | |
631 !(bevent->state & GDK_SHIFT_MASK ) && | |
632 !(bevent->state & GDK_CONTROL_MASK ) && | |
633 vflist_row_is_selected(vfl, fd)) | |
634 { | |
635 GtkTreeSelection *selection; | |
636 | |
637 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); | |
638 gtk_tree_selection_unselect_all(selection); | |
639 gtk_tree_selection_select_iter(selection, &iter); | |
640 vflist_move_cursor(vfl, &iter); | |
641 return TRUE; | |
642 } | |
643 | |
644 return FALSE; | |
645 } | |
646 | |
647 static void vflist_select_image(ViewFileList *vfl, gint row) | |
648 { | |
649 const gchar *path; | |
650 const gchar *read_ahead_path = NULL; | |
651 | |
652 path = vflist_index_get_path(vfl, row); | |
653 if (!path) return; | |
654 | |
655 if (path && enable_read_ahead) | |
656 { | |
657 FileData *fd; | |
658 if (row > vflist_index_by_path(vfl, layout_image_get_path(vfl->layout)) && | |
659 row + 1 < vflist_count(vfl, NULL)) | |
660 { | |
661 fd = vflist_index_get_data(vfl, row + 1); | |
662 } | |
663 else if (row > 0) | |
664 { | |
665 fd = vflist_index_get_data(vfl, row - 1); | |
666 } | |
667 else | |
668 { | |
669 fd = NULL; | |
670 } | |
671 if (fd) read_ahead_path = fd->path; | |
672 } | |
673 | |
674 layout_image_set_with_ahead(vfl->layout, path, read_ahead_path); | |
675 } | |
676 | |
677 static gint vflist_select_idle_cb(gpointer data) | |
678 { | |
679 ViewFileList *vfl = data; | |
680 | |
681 if (!vfl->layout) | |
682 { | |
683 vfl->select_idle_id = -1; | |
684 return FALSE; | |
685 } | |
686 | |
687 vflist_send_update(vfl); | |
688 | |
689 if (vfl->select_fd) | |
690 { | |
691 vflist_select_image(vfl, g_list_index(vfl->list, vfl->select_fd)); | |
692 vfl->select_fd = NULL; | |
693 } | |
694 | |
695 vfl->select_idle_id = -1; | |
696 return FALSE; | |
697 } | |
698 | |
699 static void vflist_select_idle_cancel(ViewFileList *vfl) | |
700 { | |
701 if (vfl->select_idle_id != -1) g_source_remove(vfl->select_idle_id); | |
702 vfl->select_idle_id = -1; | |
703 } | |
704 | |
705 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath, | |
706 gboolean path_currently_selected, gpointer data) | |
707 { | |
708 ViewFileList *vfl = data; | |
709 GtkTreeIter iter; | |
710 | |
711 if (!path_currently_selected && | |
712 gtk_tree_model_get_iter(store, &iter, tpath)) | |
713 { | |
714 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &vfl->select_fd, -1); | |
715 } | |
716 else | |
717 { | |
718 vfl->select_fd = NULL; | |
719 } | |
720 | |
721 if (vfl->layout && | |
722 vfl->select_idle_id == -1) | |
723 { | |
724 vfl->select_idle_id = g_idle_add(vflist_select_idle_cb, vfl); | |
725 } | |
726 | |
727 return TRUE; | |
728 } | |
729 | |
730 /* | |
731 *----------------------------------------------------------------------------- | |
732 * misc | |
733 *----------------------------------------------------------------------------- | |
734 */ | |
735 | |
736 void vflist_sort_set(ViewFileList *vfl, SortType type, gint ascend) | |
737 { | |
738 GtkListStore *store; | |
739 GList *work; | |
740 | |
741 if (vfl->sort_method == type && vfl->sort_ascend == ascend) return; | |
742 | |
743 vfl->sort_method = type; | |
744 vfl->sort_ascend = ascend; | |
745 | |
746 if (!vfl->list) return; | |
747 | |
748 vfl->list = filelist_sort(vfl->list, vfl->sort_method, vfl->sort_ascend); | |
749 | |
750 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview))); | |
751 | |
752 /* reorder the treeview, maintaining current selection */ | |
753 work = g_list_last(vfl->list); | |
754 while (work) | |
755 { | |
756 FileData *fd; | |
757 GtkTreeIter iter; | |
758 | |
759 fd = work->data; | |
760 if (vflist_find_row(vfl, fd, &iter) >= 0) | |
761 { | |
762 gtk_list_store_move_after(store, &iter, NULL); | |
763 } | |
764 | |
765 work = work->prev; | |
766 } | |
767 } | |
768 | |
769 /* | |
770 *----------------------------------------------------------------------------- | |
771 * thumb updates | |
772 *----------------------------------------------------------------------------- | |
773 */ | |
774 | |
775 static gint vflist_thumb_next(ViewFileList *vfl); | |
776 | |
777 static void vflist_thumb_status(ViewFileList *vfl, gdouble val, const gchar *text) | |
778 { | |
779 if (vfl->func_thumb_status) | |
780 { | |
781 vfl->func_thumb_status(vfl, val, text, vfl->data_thumb_status); | |
782 } | |
783 } | |
784 | |
785 static void vflist_thumb_cleanup(ViewFileList *vfl) | |
786 { | |
787 vflist_thumb_status(vfl, 0.0, NULL); | |
788 | |
789 vfl->thumbs_count = 0; | |
790 vfl->thumbs_running = FALSE; | |
791 | |
792 thumb_loader_free(vfl->thumbs_loader); | |
793 vfl->thumbs_loader = NULL; | |
794 | |
795 vfl->thumbs_filedata = NULL; | |
796 } | |
797 | |
798 static void vflist_thumb_stop(ViewFileList *vfl) | |
799 { | |
800 if (vfl->thumbs_running) vflist_thumb_cleanup(vfl); | |
801 } | |
802 | |
803 static void vflist_thumb_do(ViewFileList *vfl, ThumbLoader *tl, FileData *fd) | |
804 { | |
805 GtkListStore *store; | |
806 GtkTreeIter iter; | |
807 | |
808 if (!fd || vflist_find_row(vfl, fd, &iter) < 0) return; | |
809 | |
810 if (fd->pixbuf) g_object_unref(fd->pixbuf); | |
811 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE); | |
812 | |
813 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview))); | |
814 gtk_list_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1); | |
815 | |
816 vflist_thumb_status(vfl, (gdouble)(vfl->thumbs_count) / g_list_length(vfl->list), _("Loading thumbs...")); | |
817 } | |
818 | |
819 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data) | |
820 { | |
821 ViewFileList *vfl = data; | |
822 | |
823 if (vfl->thumbs_filedata && vfl->thumbs_loader == tl) | |
824 { | |
825 vflist_thumb_do(vfl, tl, vfl->thumbs_filedata); | |
826 } | |
827 | |
828 while (vflist_thumb_next(vfl)); | |
829 } | |
830 | |
831 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data) | |
832 { | |
833 ViewFileList *vfl = data; | |
834 | |
835 if (vfl->thumbs_filedata && vfl->thumbs_loader == tl) | |
836 { | |
837 vflist_thumb_do(vfl, tl, vfl->thumbs_filedata); | |
838 } | |
839 | |
840 while (vflist_thumb_next(vfl)); | |
841 } | |
842 | |
843 static gint vflist_thumb_next(ViewFileList *vfl) | |
844 { | |
845 GtkTreePath *tpath; | |
846 FileData *fd = NULL; | |
847 | |
848 /* first check the visible files */ | |
849 | |
850 if (GTK_WIDGET_REALIZED(vfl->listview) && | |
851 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vfl->listview), 0, 0, &tpath, NULL, NULL, NULL)) | |
852 { | |
853 GtkTreeModel *store; | |
854 GtkTreeIter iter; | |
855 gint valid = TRUE; | |
856 | |
857 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)); | |
858 gtk_tree_model_get_iter(store, &iter, tpath); | |
859 gtk_tree_path_free(tpath); | |
860 | |
861 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vfl->listview), &iter, FALSE) == 0) | |
862 { | |
863 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1); | |
864 if (fd->pixbuf) fd = NULL; | |
865 | |
866 valid = gtk_tree_model_iter_next(store, &iter); | |
867 } | |
868 } | |
869 | |
870 /* then find first undone */ | |
871 | |
872 if (!fd) | |
873 { | |
874 GList *work = vfl->list; | |
875 while (work && !fd) | |
876 { | |
877 FileData *fd_p = work->data; | |
878 work = work->next; | |
879 | |
880 if (!fd_p->pixbuf) fd = fd_p; | |
881 } | |
882 } | |
883 | |
884 if (!fd) | |
885 { | |
886 /* done */ | |
887 vflist_thumb_cleanup(vfl); | |
888 return FALSE; | |
889 } | |
890 | |
891 vfl->thumbs_count++; | |
892 | |
893 vfl->thumbs_filedata = fd; | |
894 | |
895 thumb_loader_free(vfl->thumbs_loader); | |
896 | |
897 vfl->thumbs_loader = thumb_loader_new(thumb_max_width, thumb_max_height); | |
898 thumb_loader_set_callbacks(vfl->thumbs_loader, | |
899 vflist_thumb_done_cb, | |
900 vflist_thumb_error_cb, | |
901 NULL, | |
902 vfl); | |
903 | |
904 if (!thumb_loader_start(vfl->thumbs_loader, fd->path)) | |
905 { | |
906 /* set icon to unknown, continue */ | |
907 if (debug) printf("thumb loader start failed %s\n", vfl->thumbs_loader->path); | |
908 vflist_thumb_do(vfl, vfl->thumbs_loader, fd); | |
909 | |
910 return TRUE; | |
911 } | |
912 | |
913 return FALSE; | |
914 } | |
915 | |
916 static void vflist_thumb_update(ViewFileList *vfl) | |
917 { | |
918 vflist_thumb_stop(vfl); | |
919 if (!vfl->thumbs_enabled) return; | |
920 | |
921 vflist_thumb_status(vfl, 0.0, _("Loading thumbs...")); | |
922 vfl->thumbs_running = TRUE; | |
923 | |
924 while (vflist_thumb_next(vfl)); | |
925 } | |
926 | |
927 /* | |
928 *----------------------------------------------------------------------------- | |
929 * row stuff | |
930 *----------------------------------------------------------------------------- | |
931 */ | |
932 | |
933 FileData *vflist_index_get_data(ViewFileList *vfl, gint row) | |
934 { | |
935 return g_list_nth_data(vfl->list, row); | |
936 } | |
937 | |
938 gchar *vflist_index_get_path(ViewFileList *vfl, gint row) | |
939 { | |
940 FileData *fd; | |
941 | |
942 fd = g_list_nth_data(vfl->list, row); | |
943 | |
944 return (fd ? fd->path : NULL); | |
945 } | |
946 | |
947 static gint vflist_row_by_path(ViewFileList *vfl, const gchar *path, FileData **fd) | |
948 { | |
949 gint p = 0; | |
950 GList *work; | |
951 | |
952 if (!path) return -1; | |
953 | |
954 work = vfl->list; | |
955 while (work) | |
956 { | |
957 FileData *fd_n = work->data; | |
958 if (strcmp(path, fd_n->path) == 0) | |
959 { | |
960 if (fd) *fd = fd_n; | |
961 return p; | |
962 } | |
963 work = work->next; | |
964 p++; | |
965 } | |
966 | |
967 if (fd) *fd = NULL; | |
968 return -1; | |
969 } | |
970 | |
971 gint vflist_index_by_path(ViewFileList *vfl, const gchar *path) | |
972 { | |
973 return vflist_row_by_path(vfl, path, NULL); | |
974 } | |
975 | |
976 gint vflist_count(ViewFileList *vfl, gint64 *bytes) | |
977 { | |
978 if (bytes) | |
979 { | |
980 gint64 b = 0; | |
981 GList *work; | |
982 | |
983 work = vfl->list; | |
984 while (work) | |
985 { | |
986 FileData *fd = work->data; | |
987 work = work->next; | |
988 b += fd->size; | |
989 } | |
990 | |
991 *bytes = b; | |
992 } | |
993 | |
994 return g_list_length(vfl->list); | |
995 } | |
996 | |
997 GList *vflist_get_list(ViewFileList *vfl) | |
998 { | |
999 GList *list = NULL; | |
1000 GList *work; | |
1001 | |
1002 work = vfl->list; | |
1003 while (work) | |
1004 { | |
1005 FileData *fd = work->data; | |
1006 work = work->next; | |
1007 | |
1008 list = g_list_prepend(list, g_strdup(fd->path)); | |
1009 } | |
1010 | |
1011 return g_list_reverse(list); | |
1012 } | |
1013 | |
1014 /* | |
1015 *----------------------------------------------------------------------------- | |
1016 * selections | |
1017 *----------------------------------------------------------------------------- | |
1018 */ | |
1019 | |
1020 static gint vflist_row_is_selected(ViewFileList *vfl, FileData *fd) | |
1021 { | |
1022 GtkTreeModel *store; | |
1023 GtkTreeSelection *selection; | |
1024 GList *slist; | |
1025 GList *work; | |
1026 gint found = FALSE; | |
1027 | |
1028 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1029 slist = gtk_tree_selection_get_selected_rows(selection, &store); | |
1030 work = slist; | |
1031 while (!found && work) | |
1032 { | |
1033 GtkTreePath *tpath = work->data; | |
1034 FileData *fd_n; | |
1035 GtkTreeIter iter; | |
1036 | |
1037 gtk_tree_model_get_iter(store, &iter, tpath); | |
1038 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1); | |
1039 if (fd_n == fd) found = TRUE; | |
1040 work = work->next; | |
1041 } | |
1042 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); | |
1043 g_list_free(slist); | |
1044 | |
1045 return found; | |
1046 } | |
1047 | |
1048 gint vflist_index_is_selected(ViewFileList *vfl, gint row) | |
1049 { | |
1050 FileData *fd; | |
1051 | |
1052 fd = vflist_index_get_data(vfl, row); | |
1053 return vflist_row_is_selected(vfl, fd); | |
1054 } | |
1055 | |
1056 gint vflist_selection_count(ViewFileList *vfl, gint64 *bytes) | |
1057 { | |
1058 GtkTreeModel *store; | |
1059 GtkTreeSelection *selection; | |
1060 GList *slist; | |
1061 gint count; | |
1062 | |
1063 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1064 slist = gtk_tree_selection_get_selected_rows(selection, &store); | |
1065 | |
1066 if (bytes) | |
1067 { | |
1068 gint64 b = 0; | |
1069 GList *work; | |
1070 | |
1071 work = slist; | |
1072 while (work) | |
1073 { | |
1074 GtkTreePath *tpath = work->data; | |
1075 GtkTreeIter iter; | |
1076 FileData *fd; | |
1077 | |
1078 gtk_tree_model_get_iter(store, &iter, tpath); | |
1079 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1); | |
1080 b += fd->size; | |
1081 | |
1082 work = work->next; | |
1083 } | |
1084 | |
1085 *bytes = b; | |
1086 } | |
1087 | |
1088 count = g_list_length(slist); | |
1089 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); | |
1090 g_list_free(slist); | |
1091 | |
1092 return count; | |
1093 } | |
1094 | |
1095 GList *vflist_selection_get_list(ViewFileList *vfl) | |
1096 { | |
1097 GtkTreeModel *store; | |
1098 GtkTreeSelection *selection; | |
1099 GList *slist; | |
1100 GList *list = NULL; | |
1101 GList *work; | |
1102 | |
1103 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1104 slist = gtk_tree_selection_get_selected_rows(selection, &store); | |
1105 work = slist; | |
1106 while (work) | |
1107 { | |
1108 GtkTreePath *tpath = work->data; | |
1109 FileData *fd; | |
1110 GtkTreeIter iter; | |
1111 | |
1112 gtk_tree_model_get_iter(store, &iter, tpath); | |
1113 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1); | |
1114 | |
1115 list = g_list_prepend(list, g_strdup(fd->path)); | |
1116 | |
1117 work = work->next; | |
1118 } | |
1119 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); | |
1120 g_list_free(slist); | |
1121 | |
1122 return g_list_reverse(list); | |
1123 } | |
1124 | |
1125 GList *vflist_selection_get_list_by_index(ViewFileList *vfl) | |
1126 { | |
1127 GtkTreeModel *store; | |
1128 GtkTreeSelection *selection; | |
1129 GList *slist; | |
1130 GList *list = NULL; | |
1131 GList *work; | |
1132 | |
1133 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1134 slist = gtk_tree_selection_get_selected_rows(selection, &store); | |
1135 work = slist; | |
1136 while (work) | |
1137 { | |
1138 GtkTreePath *tpath = work->data; | |
1139 FileData *fd; | |
1140 GtkTreeIter iter; | |
1141 | |
1142 gtk_tree_model_get_iter(store, &iter, tpath); | |
1143 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1); | |
1144 | |
1145 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vfl->list, fd))); | |
1146 | |
1147 work = work->next; | |
1148 } | |
1149 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); | |
1150 g_list_free(slist); | |
1151 | |
1152 return g_list_reverse(list); | |
1153 } | |
1154 | |
1155 void vflist_select_all(ViewFileList *vfl) | |
1156 { | |
1157 GtkTreeSelection *selection; | |
1158 | |
1159 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1160 gtk_tree_selection_select_all(selection); | |
1161 | |
1162 vfl->select_fd = NULL; | |
1163 } | |
1164 | |
1165 void vflist_select_none(ViewFileList *vfl) | |
1166 { | |
1167 GtkTreeSelection *selection; | |
1168 | |
1169 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1170 gtk_tree_selection_unselect_all(selection); | |
1171 } | |
1172 | |
1173 void vflist_select_by_path(ViewFileList *vfl, const gchar *path) | |
1174 { | |
1175 FileData *fd; | |
1176 GtkTreeIter iter; | |
1177 | |
1178 if (vflist_row_by_path(vfl, path, &fd) < 0) return; | |
1179 if (vflist_find_row(vfl, fd, &iter) < 0) return; | |
1180 | |
1181 tree_view_row_make_visible(GTK_TREE_VIEW(vfl->listview), &iter, TRUE); | |
1182 | |
1183 if (!vflist_row_is_selected(vfl, fd)) | |
1184 { | |
1185 GtkTreeSelection *selection; | |
1186 GtkTreeModel *store; | |
1187 GtkTreePath *tpath; | |
1188 | |
1189 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1190 gtk_tree_selection_unselect_all(selection); | |
1191 gtk_tree_selection_select_iter(selection, &iter); | |
1192 vflist_move_cursor(vfl, &iter); | |
1193 | |
1194 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)); | |
1195 tpath = gtk_tree_model_get_path(store, &iter); | |
1196 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vfl->listview), tpath, NULL, FALSE); | |
1197 gtk_tree_path_free(tpath); | |
1198 } | |
1199 } | |
1200 | |
1201 /* | |
1202 *----------------------------------------------------------------------------- | |
1203 * core (population) | |
1204 *----------------------------------------------------------------------------- | |
1205 */ | |
1206 | |
1207 static void vflist_listview_set_height(GtkWidget *listview, gint thumb) | |
1208 { | |
1209 GtkTreeViewColumn *column; | |
1210 GtkCellRenderer *cell; | |
1211 GList *list; | |
1212 | |
1213 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_COLUMN_THUMB - 1); | |
1214 if (!column) return; | |
1215 | |
1216 gtk_tree_view_column_set_fixed_width(column, (thumb) ? thumb_max_width : 4); | |
1217 | |
1218 list = gtk_tree_view_column_get_cell_renderers(column); | |
1219 if (!list) return; | |
1220 cell = list->data; | |
1221 g_list_free(list); | |
1222 | |
1223 g_object_set(G_OBJECT(cell), "height", (thumb) ? thumb_max_height : -1, NULL); | |
1224 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview)); | |
1225 } | |
1226 | |
1227 static void vflist_populate_view(ViewFileList *vfl) | |
1228 { | |
1229 GtkListStore *store; | |
1230 GtkTreeIter iter; | |
1231 gint thumbs; | |
1232 GList *work; | |
1233 GtkTreeRowReference *visible_row = NULL; | |
1234 GtkTreePath *tpath; | |
1235 gint valid; | |
1236 | |
1237 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview))); | |
1238 thumbs = vfl->thumbs_enabled; | |
1239 | |
1240 vflist_thumb_stop(vfl); | |
1241 | |
1242 if (!vfl->list) | |
1243 { | |
1244 gtk_list_store_clear(store); | |
1245 vflist_send_update(vfl); | |
1246 return; | |
1247 } | |
1248 | |
1249 if (GTK_WIDGET_REALIZED(vfl->listview) && | |
1250 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vfl->listview), 0, 0, &tpath, NULL, NULL, NULL)) | |
1251 { | |
1252 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath); | |
1253 gtk_tree_path_free(tpath); | |
1254 } | |
1255 | |
1256 vflist_listview_set_height(vfl->listview, thumbs); | |
1257 | |
1258 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); | |
1259 | |
1260 work = vfl->list; | |
1261 while (work) | |
1262 { | |
1263 gint match; | |
1264 FileData *fd = work->data; | |
1265 gint done = FALSE; | |
1266 | |
1267 while (!done) | |
1268 { | |
1269 FileData *old_fd = NULL; | |
1270 | |
1271 if (valid) | |
1272 { | |
1273 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1); | |
1274 match = CASE_SORT(fd->name, old_fd->name); | |
1275 } | |
1276 else | |
1277 { | |
1278 match = -1; | |
1279 } | |
1280 | |
1281 if (match < 0) | |
1282 { | |
1283 GtkTreeIter new; | |
1284 gchar *size; | |
1285 | |
1286 size = text_from_size(fd->size); | |
1287 if (valid) | |
1288 { | |
1289 gtk_list_store_insert_before(store, &new, &iter); | |
1290 } | |
1291 else | |
1292 { | |
1293 gtk_list_store_append(store, &new); | |
1294 } | |
1295 gtk_list_store_set(store, &new, FILE_COLUMN_POINTER, fd, | |
1296 FILE_COLUMN_THUMB, (thumbs) ? fd->pixbuf : NULL, | |
1297 FILE_COLUMN_NAME, fd->name, | |
1298 FILE_COLUMN_SIZE, size, | |
1299 FILE_COLUMN_DATE, text_from_time(fd->date), | |
1300 FILE_COLUMN_COLOR, FALSE, -1); | |
1301 g_free(size); | |
1302 | |
1303 done = TRUE; | |
1304 } | |
1305 else if (match > 0) | |
1306 { | |
1307 valid = gtk_list_store_remove(store, &iter); | |
1308 } | |
1309 else | |
1310 { | |
1311 gtk_list_store_set(store, &iter, FILE_COLUMN_POINTER, fd, -1); | |
1312 if (fd->date != old_fd->date) | |
1313 { | |
1314 gchar *size; | |
1315 | |
1316 /* update, file changed */ | |
1317 size = text_from_size(fd->size); | |
1318 gtk_list_store_set(store, &iter, FILE_COLUMN_SIZE, size, | |
1319 FILE_COLUMN_DATE, text_from_time(fd->date), -1); | |
1320 g_free(size); | |
1321 } | |
1322 else if (fd != old_fd) | |
1323 { | |
1324 /* preserve thumbnail */ | |
1325 if (fd->pixbuf) g_object_unref(fd->pixbuf); | |
1326 fd->pixbuf = old_fd->pixbuf; | |
1327 if (fd->pixbuf) g_object_ref(fd->pixbuf); | |
1328 } | |
1329 | |
1330 gtk_list_store_set(store, &iter, FILE_COLUMN_THUMB, (thumbs) ? fd->pixbuf : NULL, -1); | |
1331 | |
1332 if (vfl->select_fd == old_fd) vfl->select_fd = fd; | |
1333 | |
1334 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter); | |
1335 | |
1336 done = TRUE; | |
1337 } | |
1338 } | |
1339 work = work->next; | |
1340 } | |
1341 | |
1342 while (valid) | |
1343 { | |
1344 valid = gtk_list_store_remove(store, &iter); | |
1345 } | |
1346 | |
1347 if (visible_row) | |
1348 { | |
1349 if (gtk_tree_row_reference_valid(visible_row)) | |
1350 { | |
1351 tpath = gtk_tree_row_reference_get_path(visible_row); | |
1352 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vfl->listview), tpath, NULL, TRUE, 0.0, 0.0); | |
1353 gtk_tree_path_free(tpath); | |
1354 } | |
1355 gtk_tree_row_reference_free(visible_row); | |
1356 } | |
1357 | |
1358 vflist_send_update(vfl); | |
1359 vflist_thumb_update(vfl); | |
1360 } | |
1361 | |
1362 gint vflist_refresh(ViewFileList *vfl) | |
1363 { | |
1364 GList *old_list; | |
1365 gint ret = TRUE; | |
1366 | |
1367 old_list = vfl->list; | |
1368 vfl->list = NULL; | |
1369 | |
1370 if (vfl->path) | |
1371 { | |
1372 ret = filelist_read(vfl->path, &vfl->list, NULL); | |
1373 } | |
1374 | |
1375 vfl->list = filelist_sort(vfl->list, vfl->sort_method, vfl->sort_ascend); | |
1376 vflist_populate_view(vfl); | |
1377 | |
1378 filelist_free(old_list); | |
1379 | |
1380 return ret; | |
1381 } | |
1382 | |
1383 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */ | |
1384 | |
1385 #define CELL_HEIGHT_OVERRIDE 512 | |
1386 | |
1387 static void cell_renderer_height_override(GtkCellRenderer *renderer) | |
1388 { | |
1389 GParamSpec *spec; | |
1390 | |
1391 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height"); | |
1392 if (spec && G_IS_PARAM_SPEC_INT(spec)) | |
1393 { | |
1394 GParamSpecInt *spec_int; | |
1395 | |
1396 spec_int = G_PARAM_SPEC_INT(spec); | |
1397 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE; | |
1398 } | |
1399 } | |
1400 | |
1401 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget) | |
1402 { | |
1403 static GdkColor color; | |
1404 static GtkWidget *done = NULL; | |
1405 | |
1406 if (done != widget) | |
1407 { | |
1408 GtkStyle *style; | |
1409 | |
1410 style = gtk_widget_get_style(widget); | |
1411 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color)); | |
1412 shift_color(&color, -1, 0); | |
1413 done = widget; | |
1414 } | |
1415 | |
1416 return &color; | |
1417 } | |
1418 | |
1419 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, | |
1420 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) | |
1421 { | |
1422 ViewFileList *vfl = data; | |
1423 gboolean set; | |
1424 | |
1425 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1); | |
1426 g_object_set(G_OBJECT(cell), | |
1427 "cell-background-gdk", vflist_listview_color_shifted(vfl->listview), | |
1428 "cell-background-set", set, NULL); | |
1429 } | |
1430 | |
1431 static void vflist_listview_add_column(ViewFileList *vfl, gint n, const gchar *title, gint image, gint right_justify) | |
1432 { | |
1433 GtkTreeViewColumn *column; | |
1434 GtkCellRenderer *renderer; | |
1435 | |
1436 column = gtk_tree_view_column_new(); | |
1437 gtk_tree_view_column_set_title(column, title); | |
1438 gtk_tree_view_column_set_min_width(column, 4); | |
1439 | |
1440 if (!image) | |
1441 { | |
1442 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY); | |
1443 renderer = gtk_cell_renderer_text_new(); | |
1444 if (right_justify) | |
1445 { | |
1446 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL); | |
1447 } | |
1448 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
1449 gtk_tree_view_column_add_attribute(column, renderer, "text", n); | |
1450 } | |
1451 else | |
1452 { | |
1453 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); | |
1454 renderer = gtk_cell_renderer_pixbuf_new(); | |
1455 cell_renderer_height_override(renderer); | |
1456 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
1457 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n); | |
1458 } | |
1459 | |
1460 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vfl, NULL); | |
1461 | |
1462 gtk_tree_view_append_column(GTK_TREE_VIEW(vfl->listview), column); | |
1463 } | |
1464 | |
1465 /* | |
1466 *----------------------------------------------------------------------------- | |
1467 * base | |
1468 *----------------------------------------------------------------------------- | |
1469 */ | |
1470 | |
1471 gint vflist_set_path(ViewFileList *vfl, const gchar *path) | |
1472 { | |
1473 GtkListStore *store; | |
1474 | |
1475 if (!path) return FALSE; | |
1476 if (vfl->path && strcmp(path, vfl->path) == 0) return TRUE; | |
1477 | |
1478 g_free(vfl->path); | |
1479 vfl->path = g_strdup(path); | |
1480 | |
1481 /* force complete reload */ | |
1482 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview))); | |
1483 gtk_list_store_clear(store); | |
1484 | |
1485 filelist_free(vfl->list); | |
1486 vfl->list = NULL; | |
1487 | |
1488 return vflist_refresh(vfl); | |
1489 } | |
1490 | |
1491 static void vflist_destroy_cb(GtkWidget *widget, gpointer data) | |
1492 { | |
1493 ViewFileList *vfl = data; | |
1494 | |
1495 if (vfl->popup) | |
1496 { | |
1497 g_signal_handlers_disconnect_matched(G_OBJECT(vfl->popup), G_SIGNAL_MATCH_DATA, | |
1498 0, 0, 0, NULL, vfl); | |
1499 gtk_widget_destroy(vfl->popup); | |
1500 } | |
1501 | |
1502 vflist_select_idle_cancel(vfl); | |
1503 vflist_thumb_stop(vfl); | |
1504 | |
1505 g_free(vfl->path); | |
1506 filelist_free(vfl->list); | |
1507 g_free(vfl); | |
1508 } | |
1509 | |
1510 ViewFileList *vflist_new(const gchar *path, gint thumbs) | |
1511 { | |
1512 ViewFileList *vfl; | |
1513 GtkListStore *store; | |
1514 GtkTreeSelection *selection; | |
1515 | |
1516 vfl = g_new0(ViewFileList, 1); | |
1517 | |
1518 vfl->path = NULL; | |
1519 vfl->list = NULL; | |
1520 vfl->click_fd = NULL; | |
1521 vfl->select_fd = NULL; | |
1522 vfl->sort_method = SORT_NAME; | |
1523 vfl->sort_ascend = TRUE; | |
1524 vfl->thumbs_enabled = thumbs; | |
1525 | |
1526 vfl->thumbs_running = FALSE; | |
1527 vfl->thumbs_count = 0; | |
1528 vfl->thumbs_loader = NULL; | |
1529 vfl->thumbs_filedata = NULL; | |
1530 | |
1531 vfl->select_idle_id = -1; | |
1532 | |
1533 vfl->popup = NULL; | |
1534 | |
1535 vfl->widget = gtk_scrolled_window_new(NULL, NULL); | |
1536 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(vfl->widget), GTK_SHADOW_IN); | |
1537 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vfl->widget), | |
1538 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
1539 g_signal_connect(G_OBJECT(vfl->widget), "destroy", | |
1540 G_CALLBACK(vflist_destroy_cb), vfl); | |
1541 | |
1542 store = gtk_list_store_new(6, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, | |
1543 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); | |
1544 vfl->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); | |
1545 g_object_unref(store); | |
1546 | |
1547 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1548 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE); | |
1549 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vfl, NULL); | |
1550 | |
1551 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vfl->listview), FALSE); | |
1552 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vfl->listview), FALSE); | |
1553 | |
1554 vflist_listview_add_column(vfl, FILE_COLUMN_THUMB, "", TRUE, FALSE); | |
1555 vflist_listview_add_column(vfl, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE); | |
1556 vflist_listview_add_column(vfl, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE); | |
1557 vflist_listview_add_column(vfl, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE); | |
1558 | |
1559 g_signal_connect(G_OBJECT(vfl->listview), "key_press_event", | |
1560 G_CALLBACK(vflist_press_key_cb), vfl); | |
1561 | |
1562 gtk_container_add (GTK_CONTAINER(vfl->widget), vfl->listview); | |
1563 gtk_widget_show(vfl->listview); | |
1564 | |
1565 vflist_dnd_init(vfl); | |
1566 | |
1567 g_signal_connect(G_OBJECT(vfl->listview), "button_press_event", | |
1568 G_CALLBACK(vflist_press_cb), vfl); | |
1569 g_signal_connect(G_OBJECT(vfl->listview), "button_release_event", | |
1570 G_CALLBACK(vflist_release_cb), vfl); | |
1571 | |
1572 if (path) vflist_set_path(vfl, path); | |
1573 | |
1574 return vfl; | |
1575 } | |
1576 | |
1577 void vflist_set_status_func(ViewFileList *vfl, | |
1578 void (*func)(ViewFileList *vfl, gpointer data), gpointer data) | |
1579 { | |
1580 vfl->func_status = func; | |
1581 vfl->data_status = data; | |
1582 } | |
1583 | |
1584 void vflist_set_thumb_status_func(ViewFileList *vfl, | |
1585 void (*func)(ViewFileList *vfl, gdouble val, const gchar *text, gpointer data), | |
1586 gpointer data) | |
1587 { | |
1588 vfl->func_thumb_status = func; | |
1589 vfl->data_thumb_status = data; | |
1590 } | |
1591 | |
1592 void vflist_thumb_set(ViewFileList *vfl, gint enable) | |
1593 { | |
1594 if (vfl->thumbs_enabled == enable) return; | |
1595 | |
1596 vfl->thumbs_enabled = enable; | |
1597 vflist_refresh(vfl); | |
1598 } | |
1599 | |
1600 void vflist_set_layout(ViewFileList *vfl, LayoutWindow *layout) | |
1601 { | |
1602 vfl->layout = layout; | |
1603 } | |
1604 | |
1605 /* | |
1606 *----------------------------------------------------------------------------- | |
1607 * maintenance (for rename, move, remove) | |
1608 *----------------------------------------------------------------------------- | |
1609 */ | |
1610 | |
1611 static gint vflist_maint_find_closest(ViewFileList *vfl, gint row, gint count, GList *ignore_list) | |
1612 { | |
1613 GList *list = NULL; | |
1614 GList *work; | |
1615 gint rev = row - 1; | |
1616 row ++; | |
1617 | |
1618 work = ignore_list; | |
1619 while (work) | |
1620 { | |
1621 gint f = vflist_index_by_path(vfl, work->data); | |
1622 if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f)); | |
1623 work = work->next; | |
1624 } | |
1625 | |
1626 while (list) | |
1627 { | |
1628 gint c = TRUE; | |
1629 work = list; | |
1630 while (work && c) | |
1631 { | |
1632 gpointer p = work->data; | |
1633 work = work->next; | |
1634 if (row == GPOINTER_TO_INT(p)) | |
1635 { | |
1636 row++; | |
1637 c = FALSE; | |
1638 } | |
1639 if (rev == GPOINTER_TO_INT(p)) | |
1640 { | |
1641 rev--; | |
1642 c = FALSE; | |
1643 } | |
1644 if (!c) list = g_list_remove(list, p); | |
1645 } | |
1646 if (c && list) | |
1647 { | |
1648 g_list_free(list); | |
1649 list = NULL; | |
1650 } | |
1651 } | |
1652 if (row > count - 1) | |
1653 { | |
1654 if (rev < 0) | |
1655 return -1; | |
1656 else | |
1657 return rev; | |
1658 } | |
1659 else | |
1660 { | |
1661 return row; | |
1662 } | |
1663 } | |
1664 | |
1665 gint vflist_maint_renamed(ViewFileList *vfl, const gchar *source, const gchar *dest) | |
1666 { | |
1667 gint ret = FALSE; | |
1668 gint row; | |
1669 gchar *source_base; | |
1670 gchar *dest_base; | |
1671 GList *work; | |
1672 FileData *fd; | |
1673 | |
1674 row = vflist_index_by_path(vfl, source); | |
1675 if (row < 0) return FALSE; | |
1676 | |
1677 source_base = remove_level_from_path(source); | |
1678 dest_base = remove_level_from_path(dest); | |
1679 | |
1680 work = g_list_nth(vfl->list, row); | |
1681 fd = work->data; | |
1682 | |
1683 if (strcmp(source_base, dest_base) == 0) | |
1684 { | |
1685 GtkListStore *store; | |
1686 GtkTreeIter iter; | |
1687 GtkTreeIter position; | |
1688 gint old_row; | |
1689 gint n; | |
1690 | |
1691 old_row = g_list_index(vfl->list, fd); | |
1692 | |
1693 vfl->list = g_list_remove(vfl->list, fd); | |
1694 g_free(fd->path); | |
1695 | |
1696 fd->path = g_strdup(dest); | |
1697 fd->name = filename_from_path(fd->path); | |
1698 | |
1699 vfl->list = filelist_insert_sort(vfl->list, fd, vfl->sort_method, vfl->sort_ascend); | |
1700 n = g_list_index(vfl->list, fd); | |
1701 | |
1702 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview))); | |
1703 row = vflist_find_row(vfl, fd, &iter); | |
1704 if (vflist_find_row(vfl, fd, &iter) >= 0 && | |
1705 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &position, NULL, n)) | |
1706 { | |
1707 if (old_row >= n) | |
1708 { | |
1709 gtk_list_store_move_before(store, &iter, &position); | |
1710 } | |
1711 else | |
1712 { | |
1713 gtk_list_store_move_after(store, &iter, &position); | |
1714 } | |
1715 } | |
1716 gtk_list_store_set(store, &iter, FILE_COLUMN_NAME, fd->name, -1); | |
1717 | |
1718 ret = TRUE; | |
1719 } | |
1720 else | |
1721 { | |
1722 ret = vflist_maint_removed(vfl, source, NULL); | |
1723 } | |
1724 | |
1725 g_free(source_base); | |
1726 g_free(dest_base); | |
1727 | |
1728 return ret; | |
1729 } | |
1730 | |
1731 gint vflist_maint_removed(ViewFileList *vfl, const gchar *path, GList *ignore_list) | |
1732 { | |
1733 GtkTreeIter iter; | |
1734 GList *list; | |
1735 FileData *fd; | |
1736 gint row; | |
1737 gint new_row = -1; | |
1738 | |
1739 row = vflist_index_by_path(vfl, path); | |
1740 if (row < 0) return FALSE; | |
1741 | |
1742 if (vflist_index_is_selected(vfl, row) && | |
1743 layout_image_get_collection(vfl->layout, NULL) == NULL) | |
1744 { | |
1745 gint n; | |
1746 | |
1747 n = vflist_count(vfl, NULL); | |
1748 if (ignore_list) | |
1749 { | |
1750 new_row = vflist_maint_find_closest(vfl, row, n, ignore_list); | |
1751 if (debug) printf("row = %d, closest is %d\n", row, new_row); | |
1752 } | |
1753 else | |
1754 { | |
1755 if (row + 1 < n) | |
1756 { | |
1757 new_row = row + 1; | |
1758 } | |
1759 else if (row > 0) | |
1760 { | |
1761 new_row = row - 1; | |
1762 } | |
1763 } | |
1764 vflist_select_none(vfl); | |
1765 if (new_row >= 0) | |
1766 { | |
1767 fd = vflist_index_get_data(vfl, new_row); | |
1768 if (vflist_find_row(vfl, fd, &iter) >= 0) | |
1769 { | |
1770 GtkTreeSelection *selection; | |
1771 | |
1772 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview)); | |
1773 gtk_tree_selection_select_iter(selection, &iter); | |
1774 vflist_move_cursor(vfl, &iter); | |
1775 } | |
1776 } | |
1777 } | |
1778 | |
1779 fd = vflist_index_get_data(vfl, row); | |
1780 if (vflist_find_row(vfl, fd, &iter) >= 0) | |
1781 { | |
1782 GtkListStore *store; | |
1783 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview))); | |
1784 gtk_list_store_remove(store, &iter); | |
1785 } | |
1786 list = g_list_nth(vfl->list, row); | |
1787 fd = list->data; | |
1788 | |
1789 /* thumbnail loader check */ | |
1790 if (fd == vfl->thumbs_filedata) vfl->thumbs_filedata = NULL; | |
1791 | |
1792 vfl->list = g_list_remove(vfl->list, fd); | |
1793 file_data_free(fd); | |
1794 | |
1795 vflist_send_update(vfl); | |
1796 | |
1797 return TRUE; | |
1798 } | |
1799 | |
1800 gint vflist_maint_moved(ViewFileList *vfl, const gchar *source, const gchar *dest, GList *ignore_list) | |
1801 { | |
1802 gint ret = FALSE; | |
1803 gchar *buf; | |
1804 | |
1805 if (!source || !vfl->path) return FALSE; | |
1806 | |
1807 buf = remove_level_from_path(source); | |
1808 | |
1809 if (strcmp(buf, vfl->path) == 0) | |
1810 { | |
1811 ret = vflist_maint_removed(vfl, source, ignore_list); | |
1812 } | |
1813 | |
1814 g_free(buf); | |
1815 | |
1816 return ret; | |
1817 } | |
1818 |