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