Mercurial > geeqie.yaz
annotate src/view_dir_tree.c @ 1532:fffb62c7ba1e
Add pgettext for some ambiguous strings
There are some strings which are ambiguous to translate. There is the
pgettext function to solf that problem.
For example, locations can be translated to german by Ortsangaben
(geographical) or by Pfad (filesystem). I am sure there are also some
ambiguous in other languages.
author | mow |
---|---|
date | Fri, 10 Apr 2009 09:47:20 +0000 |
parents | 24a12aa0cb54 |
children | 94e4a47ccaff |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
112
b15d4c18168f
Fri Nov 17 19:06:19 2006 John Ellis <johne@verizon.net>
gqview
parents:
64
diff
changeset
|
3 * (C) 2006 John Ellis |
1284 | 4 * Copyright (C) 2008 - 2009 The Geeqie Team |
9 | 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 | |
281 | 13 #include "main.h" |
9 | 14 #include "view_dir_tree.h" |
15 | |
16 | |
17 #include "dnd.h" | |
18 #include "dupe.h" | |
586 | 19 #include "filedata.h" |
9 | 20 #include "layout.h" |
21 #include "layout_image.h" | |
22 #include "layout_util.h" | |
23 #include "utilops.h" | |
24 #include "ui_fileops.h" | |
25 #include "ui_menu.h" | |
26 #include "ui_tree_edit.h" | |
380
5afe77bb563a
Introduce a new struct ViewDir to handle directory views common
zas_
parents:
356
diff
changeset
|
27 #include "view_dir.h" |
9 | 28 |
29 #include <gdk/gdkkeysyms.h> /* for keyboard values */ | |
30 | |
31 | |
979 | 32 #define VDTREE(_vd_) ((ViewDirInfoTree *)(_vd_->info)) |
9 | 33 |
34 | |
35 typedef struct _PathData PathData; | |
36 struct _PathData | |
37 { | |
38 gchar *name; | |
39 FileData *node; | |
40 }; | |
41 | |
42 | |
43 | |
44 | |
45 /* | |
46 *---------------------------------------------------------------------------- | |
47 * utils | |
48 *---------------------------------------------------------------------------- | |
49 */ | |
50 | |
51 static void set_cursor(GtkWidget *widget, GdkCursorType cursor_type) | |
52 { | |
53 GdkCursor *cursor = NULL; | |
54 | |
55 if (!widget || !widget->window) return; | |
56 | |
512
f9bf33be53ff
Remove whitespace between function name and first parenthesis for the sake of consistency.
zas_
parents:
475
diff
changeset
|
57 if (cursor_type > -1) cursor = gdk_cursor_new(cursor_type); |
f9bf33be53ff
Remove whitespace between function name and first parenthesis for the sake of consistency.
zas_
parents:
475
diff
changeset
|
58 gdk_window_set_cursor(widget->window, cursor); |
9 | 59 if (cursor) gdk_cursor_unref(cursor); |
60 gdk_flush(); | |
61 } | |
62 | |
382 | 63 static void vdtree_busy_push(ViewDir *vd) |
9 | 64 { |
978
9ff64efe11eb
Replace macros VDLIST_INFO() and VDTREE_INFO() by shorter VDLIST() and VDTREE(). VDLIST_INFO(vd, part) becomes VDLIST(vd)->part.
zas_
parents:
943
diff
changeset
|
65 if (VDTREE(vd)->busy_ref == 0) set_cursor(vd->view, GDK_WATCH); |
9ff64efe11eb
Replace macros VDLIST_INFO() and VDTREE_INFO() by shorter VDLIST() and VDTREE(). VDLIST_INFO(vd, part) becomes VDLIST(vd)->part.
zas_
parents:
943
diff
changeset
|
66 VDTREE(vd)->busy_ref++; |
9 | 67 } |
68 | |
382 | 69 static void vdtree_busy_pop(ViewDir *vd) |
9 | 70 { |
978
9ff64efe11eb
Replace macros VDLIST_INFO() and VDTREE_INFO() by shorter VDLIST() and VDTREE(). VDLIST_INFO(vd, part) becomes VDLIST(vd)->part.
zas_
parents:
943
diff
changeset
|
71 if (VDTREE(vd)->busy_ref == 1) set_cursor(vd->view, -1); |
9ff64efe11eb
Replace macros VDLIST_INFO() and VDTREE_INFO() by shorter VDLIST() and VDTREE(). VDLIST_INFO(vd, part) becomes VDLIST(vd)->part.
zas_
parents:
943
diff
changeset
|
72 if (VDTREE(vd)->busy_ref > 0) VDTREE(vd)->busy_ref--; |
9 | 73 } |
74 | |
1501 | 75 gboolean vdtree_find_row(ViewDir *vd, FileData *fd, GtkTreeIter *iter, GtkTreeIter *parent) |
9 | 76 { |
77 GtkTreeModel *store; | |
1452 | 78 gboolean valid; |
9 | 79 |
382 | 80 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 81 if (parent) |
82 { | |
83 valid = gtk_tree_model_iter_children(store, iter, parent); | |
84 } | |
85 else | |
86 { | |
87 valid = gtk_tree_model_get_iter_first(store, iter); | |
88 } | |
89 while (valid) | |
90 { | |
91 NodeData *nd; | |
92 GtkTreeIter found; | |
93 | |
94 gtk_tree_model_get(GTK_TREE_MODEL(store), iter, DIR_COLUMN_POINTER, &nd, -1); | |
95 if (nd->fd == fd) return TRUE; | |
96 | |
382 | 97 if (vdtree_find_row(vd, fd, &found, iter)) |
9 | 98 { |
99 memcpy(iter, &found, sizeof(found)); | |
100 return TRUE; | |
101 } | |
102 | |
103 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter); | |
104 } | |
105 | |
106 return FALSE; | |
107 } | |
108 | |
382 | 109 static void vdtree_icon_set_by_iter(ViewDir *vd, GtkTreeIter *iter, GdkPixbuf *pixbuf) |
9 | 110 { |
111 GtkTreeModel *store; | |
112 GdkPixbuf *old; | |
113 | |
382 | 114 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 115 gtk_tree_model_get(store, iter, DIR_COLUMN_ICON, &old, -1); |
382 | 116 if (old != vd->pf->deny) |
9 | 117 { |
118 gtk_tree_store_set(GTK_TREE_STORE(store), iter, DIR_COLUMN_ICON, pixbuf, -1); | |
119 } | |
120 } | |
121 | |
1452 | 122 static void vdtree_expand_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean expand) |
9 | 123 { |
124 GtkTreeModel *store; | |
125 GtkTreePath *tpath; | |
126 | |
382 | 127 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 128 tpath = gtk_tree_model_get_path(store, iter); |
129 if (expand) | |
130 { | |
382 | 131 gtk_tree_view_expand_row(GTK_TREE_VIEW(vd->view), tpath, FALSE); |
132 vdtree_icon_set_by_iter(vd, iter, vd->pf->open); | |
9 | 133 } |
134 else | |
135 { | |
382 | 136 gtk_tree_view_collapse_row(GTK_TREE_VIEW(vd->view), tpath); |
9 | 137 } |
138 gtk_tree_path_free(tpath); | |
139 } | |
140 | |
1452 | 141 static void vdtree_expand_by_data(ViewDir *vd, FileData *fd, gboolean expand) |
9 | 142 { |
143 GtkTreeIter iter; | |
144 | |
389 | 145 if (vd_find_row(vd, fd, &iter)) |
9 | 146 { |
382 | 147 vdtree_expand_by_iter(vd, &iter, expand); |
9 | 148 } |
149 } | |
150 | |
151 static void vdtree_node_free(NodeData *nd) | |
152 { | |
153 if (!nd) return; | |
154 | |
138 | 155 file_data_unref(nd->fd); |
9 | 156 g_free(nd); |
157 } | |
158 | |
159 /* | |
160 *---------------------------------------------------------------------------- | |
161 * dnd | |
162 *---------------------------------------------------------------------------- | |
163 */ | |
164 | |
1452 | 165 static gboolean vdtree_dnd_drop_expand_cb(gpointer data) |
9 | 166 { |
382 | 167 ViewDir *vd = data; |
9 | 168 GtkTreeIter iter; |
169 | |
394 | 170 if (vd->drop_fd && vd_find_row(vd, vd->drop_fd, &iter)) |
9 | 171 { |
783 | 172 vdtree_populate_path_by_iter(vd, &iter, FALSE, vd->dir_fd); |
382 | 173 vdtree_expand_by_data(vd, vd->drop_fd, TRUE); |
9 | 174 } |
175 | |
1523 | 176 VDTREE(vd)->drop_expand_id = 0; |
9 | 177 return FALSE; |
178 } | |
179 | |
407 | 180 static void vdtree_dnd_drop_expand_cancel(ViewDir *vd) |
9 | 181 { |
1523 | 182 if (VDTREE(vd)->drop_expand_id) |
183 { | |
184 g_source_remove(VDTREE(vd)->drop_expand_id); | |
185 VDTREE(vd)->drop_expand_id = 0; | |
186 } | |
9 | 187 } |
188 | |
407 | 189 static void vdtree_dnd_drop_expand(ViewDir *vd) |
9 | 190 { |
382 | 191 vdtree_dnd_drop_expand_cancel(vd); |
978
9ff64efe11eb
Replace macros VDLIST_INFO() and VDTREE_INFO() by shorter VDLIST() and VDTREE(). VDLIST_INFO(vd, part) becomes VDLIST(vd)->part.
zas_
parents:
943
diff
changeset
|
192 VDTREE(vd)->drop_expand_id = g_timeout_add(1000, vdtree_dnd_drop_expand_cb, vd); |
9 | 193 } |
194 | |
195 /* | |
196 *---------------------------------------------------------------------------- | |
197 * parts lists | |
198 *---------------------------------------------------------------------------- | |
199 */ | |
200 | |
201 static GList *parts_list(const gchar *path) | |
202 { | |
203 GList *list = NULL; | |
204 const gchar *strb, *strp; | |
205 gint l; | |
206 | |
207 strp = path; | |
208 | |
726 | 209 if (*strp != G_DIR_SEPARATOR) return NULL; |
9 | 210 |
211 strp++; | |
212 strb = strp; | |
213 l = 0; | |
214 | |
215 while (*strp != '\0') | |
216 { | |
726 | 217 if (*strp == G_DIR_SEPARATOR) |
9 | 218 { |
219 if (l > 0) list = g_list_prepend(list, g_strndup(strb, l)); | |
220 strp++; | |
221 strb = strp; | |
222 l = 0; | |
223 } | |
224 else | |
225 { | |
226 strp++; | |
227 l++; | |
228 } | |
229 } | |
230 if (l > 0) list = g_list_prepend(list, g_strndup(strb, l)); | |
231 | |
232 list = g_list_reverse(list); | |
233 | |
725 | 234 list = g_list_prepend(list, g_strdup(G_DIR_SEPARATOR_S)); |
9 | 235 |
236 return list; | |
237 } | |
238 | |
239 static void parts_list_free(GList *list) | |
240 { | |
241 GList *work = list; | |
242 while (work) | |
243 { | |
244 PathData *pd = work->data; | |
245 g_free(pd->name); | |
246 g_free(pd); | |
247 work = work->next; | |
248 } | |
249 | |
250 g_list_free(list); | |
251 } | |
252 | |
382 | 253 static GList *parts_list_add_node_points(ViewDir *vd, GList *list) |
9 | 254 { |
255 GList *work; | |
256 GtkTreeModel *store; | |
257 GtkTreeIter iter; | |
1452 | 258 gboolean valid; |
9 | 259 |
382 | 260 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 261 valid = gtk_tree_model_get_iter_first(store, &iter); |
262 | |
263 work = list; | |
264 while (work) | |
265 { | |
266 PathData *pd; | |
267 FileData *fd = NULL; | |
268 | |
269 pd = g_new0(PathData, 1); | |
270 pd->name = work->data; | |
271 | |
272 while (valid && !fd) | |
273 { | |
274 NodeData *nd; | |
275 | |
276 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); | |
277 if (strcmp(nd->fd->name, pd->name) == 0) | |
278 { | |
279 fd = nd->fd; | |
280 } | |
281 else | |
282 { | |
283 valid = gtk_tree_model_iter_next(store, &iter); | |
284 } | |
285 } | |
286 | |
287 pd->node = fd; | |
288 work->data = pd; | |
289 | |
290 if (fd) | |
291 { | |
292 GtkTreeIter parent; | |
293 memcpy(&parent, &iter, sizeof(parent)); | |
294 valid = gtk_tree_model_iter_children(store, &iter, &parent); | |
295 } | |
296 | |
297 work = work->next; | |
298 } | |
299 | |
300 return list; | |
301 } | |
302 | |
303 /* | |
304 *---------------------------------------------------------------------------- | |
305 * misc | |
306 *---------------------------------------------------------------------------- | |
307 */ | |
308 | |
309 #if 0 | |
310 static void vdtree_row_deleted_cb(GtkTreeModel *tree_model, GtkTreePath *tpath, gpointer data) | |
311 { | |
312 GtkTreeIter iter; | |
313 NodeData *nd; | |
314 | |
315 gtk_tree_model_get_iter(tree_model, &iter, tpath); | |
316 gtk_tree_model_get(tree_model, &iter, DIR_COLUMN_POINTER, &nd, -1); | |
317 | |
318 if (!nd) return; | |
319 | |
138 | 320 file_data_unref(nd->fd); |
9 | 321 g_free(nd); |
322 } | |
323 #endif | |
324 | |
325 /* | |
326 *---------------------------------------------------------------------------- | |
327 * node traversal, management | |
328 *---------------------------------------------------------------------------- | |
329 */ | |
330 | |
1452 | 331 static gboolean vdtree_find_iter_by_data(ViewDir *vd, GtkTreeIter *parent, NodeData *nd, GtkTreeIter *iter) |
9 | 332 { |
333 GtkTreeModel *store; | |
334 | |
382 | 335 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 336 if (!nd || !gtk_tree_model_iter_children(store, iter, parent)) return -1; |
337 do { | |
338 NodeData *cnd; | |
339 | |
340 gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &cnd, -1); | |
341 if (cnd == nd) return TRUE; | |
342 } while (gtk_tree_model_iter_next(store, iter)); | |
343 | |
344 return FALSE; | |
345 } | |
346 | |
382 | 347 static NodeData *vdtree_find_iter_by_name(ViewDir *vd, GtkTreeIter *parent, const gchar *name, GtkTreeIter *iter) |
9 | 348 { |
349 GtkTreeModel *store; | |
350 | |
382 | 351 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 352 if (!name || !gtk_tree_model_iter_children(store, iter, parent)) return NULL; |
353 do { | |
354 NodeData *nd; | |
355 | |
356 gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); | |
357 if (nd && strcmp(nd->fd->name, name) == 0) return nd; | |
358 } while (gtk_tree_model_iter_next(store, iter)); | |
359 | |
360 return NULL; | |
361 } | |
362 | |
1232 | 363 static NodeData *vdtree_find_iter_by_fd(ViewDir *vd, GtkTreeIter *parent, FileData *fd, GtkTreeIter *iter) |
364 { | |
365 GtkTreeModel *store; | |
366 | |
367 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); | |
368 if (!fd || !gtk_tree_model_iter_children(store, iter, parent)) return NULL; | |
369 do { | |
370 NodeData *nd; | |
371 | |
372 gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); | |
373 if (nd && nd->fd == fd) return nd; | |
374 } while (gtk_tree_model_iter_next(store, iter)); | |
375 | |
376 return NULL; | |
377 } | |
378 | |
382 | 379 static void vdtree_add_by_data(ViewDir *vd, FileData *fd, GtkTreeIter *parent) |
9 | 380 { |
381 GtkTreeStore *store; | |
382 GtkTreeIter child; | |
383 NodeData *nd; | |
384 GdkPixbuf *pixbuf; | |
385 NodeData *end; | |
386 GtkTreeIter empty; | |
387 | |
388 if (!fd) return; | |
389 | |
390 if (access_file(fd->path, R_OK | X_OK)) | |
391 { | |
382 | 392 pixbuf = vd->pf->close; |
9 | 393 } |
394 else | |
395 { | |
382 | 396 pixbuf = vd->pf->deny; |
9 | 397 } |
398 | |
399 nd = g_new0(NodeData, 1); | |
400 nd->fd = fd; | |
907 | 401 nd->version = fd->version; |
9 | 402 nd->expanded = FALSE; |
403 nd->last_update = time(NULL); | |
404 | |
382 | 405 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view))); |
9 | 406 gtk_tree_store_append(store, &child, parent); |
407 gtk_tree_store_set(store, &child, DIR_COLUMN_POINTER, nd, | |
408 DIR_COLUMN_ICON, pixbuf, | |
409 DIR_COLUMN_NAME, nd->fd->name, | |
410 DIR_COLUMN_COLOR, FALSE, -1); | |
411 | |
412 /* all nodes are created with an "empty" node, so that the expander is shown | |
413 * this is removed when the child is populated */ | |
414 end = g_new0(NodeData, 1); | |
138 | 415 end->fd = file_data_new_simple(""); |
9 | 416 end->expanded = TRUE; |
417 | |
418 gtk_tree_store_append(store, &empty, &child); | |
419 gtk_tree_store_set(store, &empty, DIR_COLUMN_POINTER, end, | |
420 DIR_COLUMN_NAME, "empty", -1); | |
421 | |
422 if (parent) | |
423 { | |
424 NodeData *pnd; | |
425 GtkTreePath *tpath; | |
426 | |
427 gtk_tree_model_get(GTK_TREE_MODEL(store), parent, DIR_COLUMN_POINTER, &pnd, -1); | |
428 tpath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), parent); | |
320 | 429 if (options->tree_descend_subdirs && |
382 | 430 gtk_tree_view_row_expanded(GTK_TREE_VIEW(vd->view), tpath) && |
9 | 431 !nd->expanded) |
432 { | |
783 | 433 vdtree_populate_path_by_iter(vd, &child, FALSE, vd->dir_fd); |
9 | 434 } |
435 gtk_tree_path_free(tpath); | |
436 } | |
437 } | |
438 | |
1452 | 439 gboolean vdtree_populate_path_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean force, FileData *target_fd) |
9 | 440 { |
441 GtkTreeModel *store; | |
442 GList *list; | |
443 GList *work; | |
444 GList *old; | |
445 time_t current_time; | |
446 GtkTreeIter child; | |
447 NodeData *nd; | |
448 | |
382 | 449 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 450 gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); |
451 | |
452 if (!nd) return FALSE; | |
453 | |
454 current_time = time(NULL); | |
442 | 455 |
9 | 456 if (nd->expanded) |
457 { | |
458 if (!isdir(nd->fd->path)) | |
459 { | |
382 | 460 if (vd->click_fd == nd->fd) vd->click_fd = NULL; |
461 if (vd->drop_fd == nd->fd) vd->drop_fd = NULL; | |
9 | 462 gtk_tree_store_remove(GTK_TREE_STORE(store), iter); |
463 vdtree_node_free(nd); | |
464 return FALSE; | |
465 } | |
995 | 466 if (!force && current_time - nd->last_update < 2) |
943 | 467 { |
468 DEBUG_1("Too frequent update of %s", nd->fd->path); | |
469 return TRUE; | |
470 } | |
471 if (nd->fd->version == nd->version) return TRUE; | |
9 | 472 } |
473 | |
382 | 474 vdtree_busy_push(vd); |
9 | 475 |
783 | 476 filelist_read(nd->fd, NULL, &list); |
9 | 477 |
478 /* when hidden files are not enabled, and the user enters a hidden path, | |
479 * allow the tree to display that path by specifically inserting the hidden entries | |
480 */ | |
356 | 481 if (!options->file_filter.show_hidden_files && |
783 | 482 target_fd && |
483 strncmp(nd->fd->path, target_fd->path, strlen(nd->fd->path)) == 0) | |
9 | 484 { |
485 gint n; | |
486 | |
487 n = strlen(nd->fd->path); | |
783 | 488 if (target_fd->path[n] == G_DIR_SEPARATOR && target_fd->path[n+1] == '.') |
9 | 489 { |
490 gchar *name8; | |
491 struct stat sbuf; | |
492 | |
493 n++; | |
494 | |
783 | 495 while (target_fd->path[n] != '\0' && target_fd->path[n] != G_DIR_SEPARATOR) n++; |
496 name8 = g_strndup(target_fd->path, n); | |
9 | 497 |
498 if (stat_utf8(name8, &sbuf)) | |
499 { | |
145
8be2cc687304
fixed grouping sidecar files and made it configurable via config file
nadvornik
parents:
138
diff
changeset
|
500 list = g_list_prepend(list, file_data_new_simple(name8)); |
9 | 501 } |
502 | |
503 g_free(name8); | |
504 } | |
505 } | |
506 | |
507 old = NULL; | |
508 if (gtk_tree_model_iter_children(store, &child, iter)) | |
509 { | |
510 do { | |
511 NodeData *cnd; | |
512 | |
513 gtk_tree_model_get(store, &child, DIR_COLUMN_POINTER, &cnd, -1); | |
514 old = g_list_prepend(old, cnd); | |
515 } while (gtk_tree_model_iter_next(store, &child)); | |
516 } | |
517 | |
518 work = list; | |
519 while (work) | |
520 { | |
521 FileData *fd; | |
522 | |
523 fd = work->data; | |
524 work = work->next; | |
525 | |
526 if (strcmp(fd->name, ".") == 0 || strcmp(fd->name, "..") == 0) | |
527 { | |
138 | 528 file_data_unref(fd); |
9 | 529 } |
530 else | |
531 { | |
532 NodeData *cnd; | |
533 | |
1232 | 534 cnd = vdtree_find_iter_by_fd(vd, iter, fd, &child); |
9 | 535 if (cnd) |
536 { | |
1232 | 537 if (cnd->expanded && cnd->version != fd->version) |
9 | 538 { |
1232 | 539 vdtree_populate_path_by_iter(vd, &child, FALSE, target_fd); |
9 | 540 } |
541 | |
1232 | 542 gtk_tree_store_set(GTK_TREE_STORE(store), &child, DIR_COLUMN_NAME, fd->name, -1); |
543 cnd->version = fd->version; | |
544 old = g_list_remove(old, cnd); | |
138 | 545 file_data_unref(fd); |
9 | 546 } |
547 else | |
548 { | |
382 | 549 vdtree_add_by_data(vd, fd, iter); |
9 | 550 } |
551 } | |
552 } | |
553 | |
554 work = old; | |
555 while (work) | |
556 { | |
557 NodeData *cnd = work->data; | |
558 work = work->next; | |
559 | |
382 | 560 if (vd->click_fd == cnd->fd) vd->click_fd = NULL; |
561 if (vd->drop_fd == cnd->fd) vd->drop_fd = NULL; | |
9 | 562 |
382 | 563 if (vdtree_find_iter_by_data(vd, iter, cnd, &child)) |
9 | 564 { |
565 gtk_tree_store_remove(GTK_TREE_STORE(store), &child); | |
566 vdtree_node_free(cnd); | |
567 } | |
568 } | |
569 | |
570 g_list_free(old); | |
571 g_list_free(list); | |
572 | |
382 | 573 vdtree_busy_pop(vd); |
9 | 574 |
575 nd->expanded = TRUE; | |
576 nd->last_update = current_time; | |
577 | |
578 return TRUE; | |
579 } | |
580 | |
1452 | 581 FileData *vdtree_populate_path(ViewDir *vd, FileData *target_fd, gboolean expand, gboolean force) |
9 | 582 { |
583 GList *list; | |
584 GList *work; | |
585 FileData *fd = NULL; | |
586 | |
783 | 587 if (!target_fd) return NULL; |
9 | 588 |
382 | 589 vdtree_busy_push(vd); |
9 | 590 |
783 | 591 list = parts_list(target_fd->path); |
382 | 592 list = parts_list_add_node_points(vd, list); |
9 | 593 |
594 work = list; | |
595 while (work) | |
596 { | |
597 PathData *pd = work->data; | |
598 if (pd->node == NULL) | |
599 { | |
600 PathData *parent_pd; | |
601 GtkTreeIter parent_iter; | |
602 GtkTreeIter iter; | |
603 NodeData *nd; | |
604 | |
605 if (work == list) | |
606 { | |
607 /* should not happen */ | |
673
fbebf5cf4a55
Do not use printf() directly but use new wrapper function log_printf() instead.
zas_
parents:
586
diff
changeset
|
608 log_printf("vdtree warning, root node not found\n"); |
9 | 609 parts_list_free(list); |
382 | 610 vdtree_busy_pop(vd); |
9 | 611 return NULL; |
612 } | |
613 | |
614 parent_pd = work->prev->data; | |
615 | |
389 | 616 if (!vd_find_row(vd, parent_pd->node, &parent_iter) || |
783 | 617 !vdtree_populate_path_by_iter(vd, &parent_iter, force, target_fd) || |
382 | 618 (nd = vdtree_find_iter_by_name(vd, &parent_iter, pd->name, &iter)) == NULL) |
9 | 619 { |
673
fbebf5cf4a55
Do not use printf() directly but use new wrapper function log_printf() instead.
zas_
parents:
586
diff
changeset
|
620 log_printf("vdtree warning, aborted at %s\n", parent_pd->name); |
9 | 621 parts_list_free(list); |
382 | 622 vdtree_busy_pop(vd); |
9 | 623 return NULL; |
624 } | |
625 | |
626 pd->node = nd->fd; | |
627 | |
628 if (pd->node) | |
629 { | |
630 if (expand) | |
631 { | |
382 | 632 vdtree_expand_by_iter(vd, &parent_iter, TRUE); |
633 vdtree_expand_by_iter(vd, &iter, TRUE); | |
9 | 634 } |
783 | 635 vdtree_populate_path_by_iter(vd, &iter, force, target_fd); |
9 | 636 } |
637 } | |
638 else | |
639 { | |
640 GtkTreeIter iter; | |
641 | |
389 | 642 if (vd_find_row(vd, pd->node, &iter)) |
9 | 643 { |
382 | 644 if (expand) vdtree_expand_by_iter(vd, &iter, TRUE); |
783 | 645 vdtree_populate_path_by_iter(vd, &iter, force, target_fd); |
9 | 646 } |
647 } | |
648 | |
649 work = work->next; | |
650 } | |
651 | |
652 work = g_list_last(list); | |
653 if (work) | |
654 { | |
655 PathData *pd = work->data; | |
656 fd = pd->node; | |
657 } | |
658 parts_list_free(list); | |
659 | |
382 | 660 vdtree_busy_pop(vd); |
9 | 661 |
662 return fd; | |
663 } | |
664 | |
665 /* | |
666 *---------------------------------------------------------------------------- | |
667 * access | |
668 *---------------------------------------------------------------------------- | |
669 */ | |
670 | |
1437 | 671 static gboolean selection_is_ok = FALSE; |
9 | 672 |
673 static gboolean vdtree_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath, | |
442 | 674 gboolean path_currently_selected, gpointer data) |
9 | 675 { |
676 return selection_is_ok; | |
677 } | |
678 | |
396 | 679 void vdtree_select_row(ViewDir *vd, FileData *fd) |
9 | 680 { |
681 GtkTreeSelection *selection; | |
682 GtkTreeIter iter; | |
442 | 683 |
389 | 684 if (!vd_find_row(vd, fd, &iter)) return; |
382 | 685 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vd->view)); |
9 | 686 |
687 /* hack, such that selection is only allowed to be changed from here */ | |
688 selection_is_ok = TRUE; | |
689 gtk_tree_selection_select_iter(selection, &iter); | |
690 selection_is_ok = FALSE; | |
691 | |
783 | 692 if (!vdtree_populate_path_by_iter(vd, &iter, FALSE, vd->dir_fd)) return; |
9 | 693 |
382 | 694 vdtree_expand_by_iter(vd, &iter, TRUE); |
9 | 695 |
442 | 696 if (fd && vd->select_func) |
697 { | |
698 vd->select_func(vd, fd->path, vd->select_data); | |
699 } | |
9 | 700 } |
701 | |
1452 | 702 gboolean vdtree_set_fd(ViewDir *vd, FileData *dir_fd) |
9 | 703 { |
704 FileData *fd; | |
705 GtkTreeIter iter; | |
706 | |
783 | 707 if (!dir_fd) return FALSE; |
708 if (vd->dir_fd == dir_fd) return TRUE; | |
9 | 709 |
783 | 710 file_data_unref(vd->dir_fd); |
711 vd->dir_fd = file_data_ref(dir_fd);; | |
9 | 712 |
783 | 713 fd = vdtree_populate_path(vd, vd->dir_fd, TRUE, FALSE); |
9 | 714 |
715 if (!fd) return FALSE; | |
716 | |
389 | 717 if (vd_find_row(vd, fd, &iter)) |
9 | 718 { |
719 GtkTreeModel *store; | |
720 GtkTreePath *tpath; | |
721 | |
382 | 722 tree_view_row_make_visible(GTK_TREE_VIEW(vd->view), &iter, TRUE); |
9 | 723 |
382 | 724 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
9 | 725 tpath = gtk_tree_model_get_path(store, &iter); |
382 | 726 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vd->view), tpath, NULL, FALSE); |
9 | 727 gtk_tree_path_free(tpath); |
728 | |
382 | 729 vdtree_select_row(vd, fd); |
9 | 730 } |
731 | |
732 return TRUE; | |
733 } | |
734 | |
735 #if 0 | |
382 | 736 const gchar *vdtree_get_path(ViewDir *vd) |
9 | 737 { |
382 | 738 return vd->path; |
9 | 739 } |
740 #endif | |
741 | |
382 | 742 void vdtree_refresh(ViewDir *vd) |
9 | 743 { |
783 | 744 vdtree_populate_path(vd, vd->dir_fd, FALSE, TRUE); |
9 | 745 } |
746 | |
382 | 747 const gchar *vdtree_row_get_path(ViewDir *vd, gint row) |
9 | 748 { |
673
fbebf5cf4a55
Do not use printf() directly but use new wrapper function log_printf() instead.
zas_
parents:
586
diff
changeset
|
749 log_printf("FIXME: no get row path\n"); |
9 | 750 return NULL; |
751 } | |
752 | |
753 /* | |
754 *---------------------------------------------------------------------------- | |
755 * callbacks | |
756 *---------------------------------------------------------------------------- | |
757 */ | |
758 | |
1452 | 759 gboolean vdtree_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) |
9 | 760 { |
382 | 761 ViewDir *vd = data; |
9 | 762 GtkTreePath *tpath; |
763 GtkTreeIter iter; | |
764 FileData *fd = NULL; | |
765 | |
382 | 766 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vd->view), &tpath, NULL); |
9 | 767 if (tpath) |
768 { | |
769 GtkTreeModel *store; | |
770 NodeData *nd; | |
771 | |
772 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); | |
773 gtk_tree_model_get_iter(store, &iter, tpath); | |
774 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); | |
775 | |
776 gtk_tree_path_free(tpath); | |
777 | |
778 fd = (nd) ? nd->fd : NULL; | |
779 } | |
780 | |
781 switch (event->keyval) | |
782 { | |
783 case GDK_Menu: | |
382 | 784 vd->click_fd = fd; |
383
499d7ba62261
Move some dnd common code from view_dir_list.c and view_dir_tree.c
zas_
parents:
382
diff
changeset
|
785 vd_color_set(vd, vd->click_fd, TRUE); |
9 | 786 |
388
5186f8e38cb8
Make directory view popup menu common and move it to view_dir.{c,h}.
zas_
parents:
384
diff
changeset
|
787 vd->popup = vd_pop_menu(vd, vd->click_fd); |
395 | 788 gtk_menu_popup(GTK_MENU(vd->popup), NULL, NULL, vd_menu_position_cb, vd, 0, GDK_CURRENT_TIME); |
9 | 789 |
790 return TRUE; | |
791 break; | |
792 case GDK_plus: | |
793 case GDK_Right: | |
794 case GDK_KP_Add: | |
795 if (fd) | |
796 { | |
783 | 797 vdtree_populate_path_by_iter(vd, &iter, FALSE, vd->dir_fd); |
382 | 798 vdtree_icon_set_by_iter(vd, &iter, vd->pf->open); |
9 | 799 } |
800 break; | |
801 } | |
802 | |
803 return FALSE; | |
804 } | |
805 | |
1452 | 806 static gboolean vdtree_clicked_on_expander(GtkTreeView *treeview, GtkTreePath *tpath, |
807 GtkTreeViewColumn *column, gint x, gint y, gint *left_of_expander) | |
9 | 808 { |
809 gint depth; | |
810 gint size; | |
811 gint sep; | |
812 gint exp_width; | |
813 | |
814 if (column != gtk_tree_view_get_expander_column(treeview)) return FALSE; | |
815 | |
816 gtk_widget_style_get(GTK_WIDGET(treeview), "expander-size", &size, "horizontal-separator", &sep, NULL); | |
817 depth = gtk_tree_path_get_depth(tpath); | |
818 | |
819 exp_width = sep + size + sep; | |
820 | |
821 if (x <= depth * exp_width) | |
822 { | |
823 if (left_of_expander) *left_of_expander = !(x >= (depth - 1) * exp_width); | |
824 return TRUE; | |
825 } | |
826 | |
827 return FALSE; | |
828 } | |
829 | |
1452 | 830 gboolean vdtree_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) |
9 | 831 { |
382 | 832 ViewDir *vd = data; |
9 | 833 GtkTreePath *tpath; |
834 GtkTreeViewColumn *column; | |
835 GtkTreeIter iter; | |
836 NodeData *nd = NULL; | |
837 | |
838 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, | |
839 &tpath, &column, NULL, NULL)) | |
840 { | |
841 GtkTreeModel *store; | |
842 gint left_of_expander; | |
843 | |
844 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); | |
845 gtk_tree_model_get_iter(store, &iter, tpath); | |
846 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); | |
847 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE); | |
848 | |
849 if (vdtree_clicked_on_expander(GTK_TREE_VIEW(widget), tpath, column, bevent->x, bevent->y, &left_of_expander)) | |
850 { | |
382 | 851 vd->click_fd = NULL; |
9 | 852 |
853 /* clicking this region should automatically reveal an expander, if necessary | |
854 * treeview bug: the expander will not expand until a button_motion_event highlights it. | |
855 */ | |
448
a73cc0fa14d0
Use explicit names for mouse buttons instead of numbers.
zas_
parents:
442
diff
changeset
|
856 if (bevent->button == MOUSE_BUTTON_LEFT && |
9 | 857 !left_of_expander && |
382 | 858 !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vd->view), tpath)) |
9 | 859 { |
783 | 860 vdtree_populate_path_by_iter(vd, &iter, FALSE, vd->dir_fd); |
382 | 861 vdtree_icon_set_by_iter(vd, &iter, vd->pf->open); |
9 | 862 } |
863 | |
864 gtk_tree_path_free(tpath); | |
865 return FALSE; | |
866 } | |
867 | |
868 gtk_tree_path_free(tpath); | |
869 } | |
870 | |
382 | 871 vd->click_fd = (nd) ? nd->fd : NULL; |
383
499d7ba62261
Move some dnd common code from view_dir_list.c and view_dir_tree.c
zas_
parents:
382
diff
changeset
|
872 vd_color_set(vd, vd->click_fd, TRUE); |
9 | 873 |
448
a73cc0fa14d0
Use explicit names for mouse buttons instead of numbers.
zas_
parents:
442
diff
changeset
|
874 if (bevent->button == MOUSE_BUTTON_RIGHT) |
9 | 875 { |
388
5186f8e38cb8
Make directory view popup menu common and move it to view_dir.{c,h}.
zas_
parents:
384
diff
changeset
|
876 vd->popup = vd_pop_menu(vd, vd->click_fd); |
382 | 877 gtk_menu_popup(GTK_MENU(vd->popup), NULL, NULL, NULL, NULL, |
9 | 878 bevent->button, bevent->time); |
879 } | |
880 | |
448
a73cc0fa14d0
Use explicit names for mouse buttons instead of numbers.
zas_
parents:
442
diff
changeset
|
881 return (bevent->button != MOUSE_BUTTON_LEFT); |
9 | 882 } |
883 | |
884 static void vdtree_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *tpath, gpointer data) | |
885 { | |
382 | 886 ViewDir *vd = data; |
9 | 887 |
382 | 888 vdtree_populate_path_by_iter(vd, iter, FALSE, NULL); |
889 vdtree_icon_set_by_iter(vd, iter, vd->pf->open); | |
9 | 890 } |
891 | |
892 static void vdtree_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *tpath, gpointer data) | |
893 { | |
382 | 894 ViewDir *vd = data; |
9 | 895 |
382 | 896 vdtree_icon_set_by_iter(vd, iter, vd->pf->close); |
9 | 897 } |
898 | |
899 static gint vdtree_sort_cb(GtkTreeModel *store, GtkTreeIter *a, GtkTreeIter *b, gpointer data) | |
900 { | |
901 NodeData *nda; | |
902 NodeData *ndb; | |
903 | |
904 gtk_tree_model_get(store, a, DIR_COLUMN_POINTER, &nda, -1); | |
905 gtk_tree_model_get(store, b, DIR_COLUMN_POINTER, &ndb, -1); | |
906 | |
785 | 907 if (options->file_sort.case_sensitive) |
819 | 908 return strcmp(nda->fd->collate_key_name, ndb->fd->collate_key_name); |
785 | 909 else |
819 | 910 return strcmp(nda->fd->collate_key_name_nocase, ndb->fd->collate_key_name_nocase); |
9 | 911 } |
912 | |
913 /* | |
914 *---------------------------------------------------------------------------- | |
915 * core | |
916 *---------------------------------------------------------------------------- | |
917 */ | |
918 | |
382 | 919 static void vdtree_setup_root(ViewDir *vd) |
9 | 920 { |
725 | 921 const gchar *path = G_DIR_SEPARATOR_S; |
9 | 922 FileData *fd; |
923 | |
138 | 924 |
925 fd = file_data_new_simple(path); | |
382 | 926 vdtree_add_by_data(vd, fd, NULL); |
9 | 927 |
382 | 928 vdtree_expand_by_data(vd, fd, TRUE); |
783 | 929 vdtree_populate_path(vd, fd, FALSE, FALSE); |
9 | 930 } |
931 | |
932 static gboolean vdtree_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GtkTreeIter *iter, gpointer data) | |
933 { | |
934 NodeData *nd; | |
935 | |
936 gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); | |
937 vdtree_node_free(nd); | |
938 | |
939 return FALSE; | |
940 } | |
941 | |
401
0a2e1b130a25
Add some wrappers in view_dir.c and simplify even more.
zas_
parents:
397
diff
changeset
|
942 void vdtree_destroy_cb(GtkWidget *widget, gpointer data) |
9 | 943 { |
382 | 944 ViewDir *vd = data; |
9 | 945 GtkTreeModel *store; |
946 | |
382 | 947 vdtree_dnd_drop_expand_cancel(vd); |
394 | 948 vd_dnd_drop_scroll_cancel(vd); |
382 | 949 widget_auto_scroll_stop(vd->view); |
9 | 950 |
382 | 951 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); |
952 gtk_tree_model_foreach(store, vdtree_destroy_node_cb, vd); | |
9 | 953 } |
954 | |
783 | 955 ViewDir *vdtree_new(ViewDir *vd, FileData *dir_fd) |
9 | 956 { |
957 GtkTreeStore *store; | |
958 GtkTreeSelection *selection; | |
959 GtkTreeViewColumn *column; | |
960 GtkCellRenderer *renderer; | |
961 | |
382 | 962 vd->info = g_new0(ViewDirInfoTree, 1); |
1365
249bf204004a
When g_new0() is used, drop redundant initializations to NULL, FALSE or 0.
zas_
parents:
1284
diff
changeset
|
963 |
382 | 964 vd->type = DIRVIEW_TREE; |
442 | 965 |
407 | 966 vd->dnd_drop_leave_func = vdtree_dnd_drop_expand_cancel; |
967 vd->dnd_drop_update_func = vdtree_dnd_drop_expand; | |
9 | 968 |
969 store = gtk_tree_store_new(4, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); | |
382 | 970 vd->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); |
9 | 971 g_object_unref(store); |
972 | |
382 | 973 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vd->view), FALSE); |
974 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vd->view), FALSE); | |
975 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), vdtree_sort_cb, vd, NULL); | |
9 | 976 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), |
977 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); | |
978 | |
382 | 979 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vd->view)); |
9 | 980 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); |
382 | 981 gtk_tree_selection_set_select_function(selection, vdtree_select_cb, vd, NULL); |
9 | 982 |
983 column = gtk_tree_view_column_new(); | |
984 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY); | |
985 | |
986 renderer = gtk_cell_renderer_pixbuf_new(); | |
987 gtk_tree_view_column_pack_start(column, renderer, FALSE); | |
988 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", DIR_COLUMN_ICON); | |
396 | 989 gtk_tree_view_column_set_cell_data_func(column, renderer, vd_color_cb, vd, NULL); |
9 | 990 |
991 renderer = gtk_cell_renderer_text_new(); | |
992 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
993 gtk_tree_view_column_add_attribute(column, renderer, "text", DIR_COLUMN_NAME); | |
396 | 994 gtk_tree_view_column_set_cell_data_func(column, renderer, vd_color_cb, vd, NULL); |
9 | 995 |
382 | 996 gtk_tree_view_append_column(GTK_TREE_VIEW(vd->view), column); |
9 | 997 |
382 | 998 vdtree_setup_root(vd); |
9 | 999 |
405 | 1000 g_signal_connect(G_OBJECT(vd->view), "row_expanded", |
1001 G_CALLBACK(vdtree_row_expanded), vd); | |
1002 g_signal_connect(G_OBJECT(vd->view), "row_collapsed", | |
1003 G_CALLBACK(vdtree_row_collapsed), vd); | |
9 | 1004 |
382 | 1005 return vd; |
9 | 1006 } |
1055
1646720364cf
Adding a vim modeline to all files - patch by Klaus Ethgen
nadvornik
parents:
995
diff
changeset
|
1007 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ |