1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2
3 /*
4 * GImageView
5 * Copyright (C) 2002 Takuro Ashie
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id: dirview2.c,v 1.38 2004/12/20 14:53:45 makeinu Exp $
22 */
23
24 #include "dirview.h"
25
26 #ifdef ENABLE_TREEVIEW
27
28 #include <string.h>
29
30 #include "charset.h"
31 #include "dirview_priv.h"
32 #include "dnd.h"
33 #include "fileutil.h"
34 #include "gfileutil.h"
35 #include "gtk2-compat.h"
36 #include "gtk_prop.h"
37 #include "gimv_icon_stock.h"
38 #include "gimv_thumb_win.h"
39 #include "menu.h"
40 #include "prefs.h"
41
42
43 typedef enum {
44 COLUMN_TERMINATOR = -1,
45 COLUMN_LABEL,
46 COLUMN_FULLPATH,
47 COLUMN_ICON_OPEN,
48 COLUMN_ICON_CLOSE,
49 COLUMN_IS_DUMMY,
50 N_COLUMN
51 } TreeStoreColumn;
52
53
54 /* callback functions */
55 static void cb_dirview_destroyed (GtkWidget *widget,
56 DirView *dv);
57 static gboolean cb_button_press (GtkWidget *widget,
58 GdkEventButton *event,
59 DirView *dv);
60 static gboolean cb_button_release (GtkWidget *widget,
61 GdkEventButton *event,
62 DirView *dv);
63 static gboolean cb_scroll (GtkWidget *widget,
64 GdkEventScroll *se,
65 DirView *dv);
66 static gboolean cb_key_press (GtkWidget *widget,
67 GdkEventKey *event,
68 DirView *dv);
69 static void cb_tree_expand (GtkTreeView *treeview,
70 GtkTreeIter *parent_iter,
71 GtkTreePath *treepath,
72 gpointer data);
73
74
75 /* callback functions for popup menu */
76 static void cb_open_thumbnail (DirView *dv,
77 ScanSubDirType scan_subdir,
78 GtkWidget *menuitem);
79 static void cb_go_to_here (DirView *dv,
80 guint action,
81 GtkWidget *menuitem);
82 static void cb_refresh_dir_tree (DirView *dv,
83 guint action,
84 GtkWidget *menuitem);
85 static void cb_file_property (DirView *tv,
86 guint action,
87 GtkWidget *menuitem);
88 static void cb_mkdir (DirView *dv,
89 guint action,
90 GtkWidget *menuitem);
91 static void cb_rename_dir (DirView *dv,
92 guint action,
93 GtkWidget *menuitem);
94 static void cb_delete_dir (DirView *dv,
95 guint action,
96 GtkWidget *menuitem);
97
98 /* Callback functions for toolbar buttons */
99 static void cb_home_button (GtkWidget *widget,
100 DirView *dv);
101 static void cb_up_button (GtkWidget *widget,
102 DirView *dv);
103 static void cb_refresh_button (GtkWidget *widget,
104 DirView *dv);
105 static void cb_dotfile_button (GtkWidget *widget,
106 DirView *dv);
107
108 /* Callback functions for DnD */
109 static void cb_drag_data_get (GtkWidget *dirtree,
110 GdkDragContext *context,
111 GtkSelectionData *seldata,
112 guint info,
113 guint time,
114 gpointer data);
115 static void cb_drag_data_received (GtkWidget *dirtree,
116 GdkDragContext *context,
117 gint x,
118 gint y,
119 GtkSelectionData *seldata,
120 guint info,
121 guint32 time,
122 gpointer data);
123 static void cb_drag_end (GtkWidget *dirtree,
124 GdkDragContext *context,
125 gpointer data);
126 static void cb_toolbar_drag_begin (GtkWidget *widget,
127 GdkDragContext *context,
128 gpointer data);
129 static gboolean cb_drag_motion (GtkWidget *widget,
130 GdkDragContext *drag_context,
131 gint x,
132 gint y,
133 guint time,
134 gpointer data);
135 static void cb_toolbar_drag_data_get (GtkWidget *widget,
136 GdkDragContext *context,
137 GtkSelectionData *seldata,
138 guint info,
139 guint time,
140 gpointer data);
141 static void cb_com_swap_drag_data_received (GtkWidget *widget,
142 GdkDragContext *context,
143 gint x,
144 gint y,
145 GtkSelectionData *seldata,
146 guint info,
147 guint time,
148 gpointer data);
149
150 /* other private functions */
151 static void get_icon_pixbufs (void);
152 static void set_columns_type (GtkTreeView *tree_view);
153 static void dirview_create_treeview (DirView *dv,
154 const gchar *root);
155 static GtkWidget *dirview_create_toolbar (DirView *dv);
156 static void insert_dummy_row (GtkTreeStore *store,
157 GtkTreeIter *parent_iter);
158 static void insert_row (GtkTreeStore *store,
159 GtkTreeIter *iter,
160 GtkTreeIter *parent_iter,
161 const gchar *label,
162 const gchar *fullpath);
163 static gboolean get_iter_from_path (DirView *dv,
164 const gchar *str,
165 GtkTreeIter *iter);
166 static void adjust_tree (GtkTreeView *treeview,
167 GtkTreeIter *iter);
168 static void adjust_tree_idle (DirView *dv,
169 GtkTreeIter *iter);
170 static void get_expanded_dirs (GtkTreeView *treeview,
171 GtkTreePath *treepath,
172 gpointer data);
173 static void refresh_dir_tree (DirView *dv,
174 GtkTreeIter *parent_iter);
175 static void dirview_popup_menu (DirView *dv,
176 GdkEventButton *event);
177 static gboolean dirview_button_action (DirView *dv,
178 GdkEventButton *event,
179 gint num);
180
181
182 static GtkItemFactoryEntry dirview_popup_items [] =
183 {
184 {N_("/_Load Thumbnail"), NULL, cb_open_thumbnail, SCAN_SUB_DIR_NONE, NULL},
185 {N_("/Load Thumbnail re_cursively"), NULL, cb_open_thumbnail, SCAN_SUB_DIR, NULL},
186 {N_("/Load Thumbnail recursively in _one tab"), NULL, cb_open_thumbnail, SCAN_SUB_DIR_ONE_TAB, NULL},
187 {N_("/---"), NULL, NULL, 0, "<Separator>"},
188 {N_("/_Go to here"), NULL, cb_go_to_here, 0, NULL},
189 {N_("/_Refresh Tree"), NULL, cb_refresh_dir_tree, 0, NULL},
190 {N_("/---"), NULL, NULL, 0, "<Separator>"},
191 {N_("/_Property..."), NULL, cb_file_property, 0, NULL},
192 {N_("/---"), NULL, NULL, 0, "<Separator>"},
193 {N_("/_Make Directory..."), NULL, cb_mkdir, 0, NULL},
194 {N_("/Re_name Directory..."), NULL, cb_rename_dir, 0, NULL},
195 {N_("/_Delete Directory..."), NULL, cb_delete_dir, 0, NULL},
196 {NULL, NULL, NULL, 0, NULL},
197 };
198
199
200 static GdkPixbuf *folder = NULL;
201 static GdkPixbuf *ofolder = NULL;
202 static GdkPixbuf *lfolder = NULL;
203 static GdkPixbuf *lofolder = NULL;
204 static GdkPixbuf *go_folder = NULL;
205 static GdkPixbuf *up_folder = NULL;
206 static GdkPixbuf *lock_folder = NULL;
207
208
209
210 /******************************************************************************
211 *
212 * Callback functions
213 *
214 ******************************************************************************/
215 static void
cb_dirview_destroyed(GtkWidget * widget,DirView * dv)216 cb_dirview_destroyed (GtkWidget *widget, DirView *dv)
217 {
218 g_return_if_fail (dv);
219
220 if (dv->priv->button_action_id)
221 gtk_idle_remove (dv->priv->button_action_id);
222 dv->priv->button_action_id = 0;
223
224 if (dv->priv->swap_com_id)
225 gtk_idle_remove (dv->priv->swap_com_id);
226 dv->priv->swap_com_id = 0;
227
228 if (dv->priv->adjust_tree_id)
229 gtk_idle_remove (dv->priv->adjust_tree_id);
230 dv->priv->adjust_tree_id = 0;
231
232 g_free (dv->root_dir);
233 g_free (dv->priv);
234 g_free (dv);
235 }
236
237
238 static gboolean
cb_button_press(GtkWidget * widget,GdkEventButton * event,DirView * dv)239 cb_button_press (GtkWidget *widget, GdkEventButton *event, DirView *dv)
240 {
241 gint num;
242
243 g_return_val_if_fail (dv, FALSE);
244 g_return_val_if_fail (event, FALSE);
245
246 num = prefs_mouse_get_num_from_event (event, conf.dirview_mouse_button);
247 if (event->type == GDK_2BUTTON_PRESS) {
248 dv->priv->button_2pressed_queue = num;
249 } else if (num > 0) {
250 return dirview_button_action (dv, event, num);
251 }
252
253 return FALSE;
254 }
255
256
257 static gboolean
cb_button_release(GtkWidget * widget,GdkEventButton * event,DirView * dv)258 cb_button_release (GtkWidget *widget, GdkEventButton *event, DirView *dv)
259 {
260 gint num;
261
262 g_return_val_if_fail (dv, FALSE);
263 g_return_val_if_fail (event, FALSE);
264
265 if (dv->priv->button_2pressed_queue) {
266 num = dv->priv->button_2pressed_queue;
267 if (num > 0)
268 num = 0 - num;
269 dv->priv->button_2pressed_queue = 0;
270 } else {
271 num = prefs_mouse_get_num_from_event (event, conf.dirview_mouse_button);
272 }
273 if (num < 0)
274 return dirview_button_action (dv, event, num);
275
276 return FALSE;
277 }
278
279
280 static gboolean
cb_scroll(GtkWidget * widget,GdkEventScroll * se,DirView * dv)281 cb_scroll (GtkWidget *widget, GdkEventScroll *se, DirView *dv)
282 {
283 GdkEventButton be;
284 gboolean retval = FALSE;
285 gint num;
286
287 g_return_val_if_fail (GTK_IS_WIDGET(widget), FALSE);
288
289 be.type = GDK_BUTTON_PRESS;
290 be.window = se->window;
291 be.send_event = se->send_event;
292 be.time = se->time;
293 be.x = se->x;
294 be.y = se->y;
295 be.axes = NULL;
296 be.state = se->state;
297 be.device = se->device;
298 be.x_root = se->x_root;
299 be.y_root = se->y_root;
300 switch ((se)->direction) {
301 case GDK_SCROLL_UP:
302 be.button = 4;
303 break;
304 case GDK_SCROLL_DOWN:
305 be.button = 5;
306 break;
307 case GDK_SCROLL_LEFT:
308 be.button = 6;
309 break;
310 case GDK_SCROLL_RIGHT:
311 be.button = 7;
312 break;
313 default:
314 g_warning ("invalid scroll direction!");
315 be.button = 0;
316 break;
317 }
318
319 num = prefs_mouse_get_num_from_event (&be, conf.dirview_mouse_button);
320 if (num > 0)
321 retval = dirview_button_action (dv, &be, num);
322
323 be.type = GDK_BUTTON_RELEASE;
324 if (num < 0)
325 retval = dirview_button_action (dv, &be, num);
326
327 return retval;
328 }
329
330
331 static gboolean
cb_key_press(GtkWidget * widget,GdkEventKey * event,DirView * dv)332 cb_key_press (GtkWidget *widget, GdkEventKey *event, DirView *dv)
333 {
334 guint keyval, popup_key;
335 GdkModifierType modval, popup_mod;
336 gboolean success;
337 GtkTreeSelection *selection;
338 GtkTreeModel *model;
339 GtkTreeIter iter;
340 GtkTreePath *treepath;
341 gboolean retval = FALSE;
342 gchar *label, *path;
343
344 g_return_val_if_fail (dv, FALSE);
345 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
346
347 keyval = event->keyval;
348 modval = event->state;
349
350 if (akey.common_popup_menu || *akey.common_popup_menu)
351 gtk_accelerator_parse (akey.common_popup_menu, &popup_key, &popup_mod);
352 else
353 return FALSE;
354
355 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dv->dirtree));
356 g_return_val_if_fail (selection, FALSE);
357
358 success = gtk_tree_selection_get_selected (selection, &model, &iter);
359 if (!success) return FALSE;
360 treepath = gtk_tree_model_get_path (model, &iter);
361 if (!treepath) return FALSE;
362
363 gtk_tree_model_get (model, &iter,
364 COLUMN_LABEL, &label,
365 COLUMN_FULLPATH, &path,
366 COLUMN_TERMINATOR);
367
368 if (keyval == popup_key && (!popup_mod || (modval & popup_mod))) {
369 dirview_popup_menu (dv, NULL);
370 } else {
371 switch (keyval) {
372 case GDK_KP_Enter:
373 case GDK_Return:
374 case GDK_ISO_Enter:
375 {
376 if (!strcmp (label, ".") || !strcmp (label, "..")) {
377 dirview_change_root (dv, path);
378 } else {
379 open_dir_images (path, dv->tw, NULL,
380 LOAD_CACHE, conf.scan_dir_recursive);
381 }
382 retval = TRUE;
383 break;
384 }
385 case GDK_space:
386 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), treepath))
387 gtk_tree_view_collapse_row (GTK_TREE_VIEW (widget), treepath);
388 else
389 gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), treepath, FALSE);
390 retval = TRUE;
391 break;
392 case GDK_Right:
393 if (modval & GDK_CONTROL_MASK) {
394 dirview_change_root (dv, path);
395 } else {
396 gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), treepath, FALSE);
397 }
398 retval = TRUE;
399 break;
400 case GDK_Left:
401 if (modval & GDK_CONTROL_MASK) {
402 dirview_change_root_to_parent (dv);
403 } else {
404 gtk_tree_view_collapse_row (GTK_TREE_VIEW (widget), treepath);
405 }
406 retval = TRUE;
407 break;
408 case GDK_Up:
409 if (modval & GDK_CONTROL_MASK) {
410 dirview_change_root_to_parent (dv);
411 retval = TRUE;
412 }
413 break;
414 case GDK_Down:
415 if (modval & GDK_CONTROL_MASK) {
416 dirview_change_root (dv, path);
417 retval = TRUE;
418 }
419 break;
420 }
421 }
422
423 g_free (label);
424 g_free (path);
425 gtk_tree_path_free(treepath);
426
427 return retval;
428 }
429
430
431 static void
cb_tree_expand(GtkTreeView * treeview,GtkTreeIter * parent_iter,GtkTreePath * treepath,gpointer data)432 cb_tree_expand (GtkTreeView *treeview,
433 GtkTreeIter *parent_iter,
434 GtkTreePath *treepath,
435 gpointer data)
436 {
437 DirView *dv = data;
438 GtkTreeStore *store;
439 GtkTreeIter child_iter, iter;
440 gchar *parent_dir;
441 gboolean dummy;
442 GList *subdir_list = NULL, *node;
443 GetDirFlags flags;
444
445 g_return_if_fail (dv);
446
447 store = GTK_TREE_STORE (gtk_tree_view_get_model (treeview));
448
449 gtk_tree_model_iter_children (GTK_TREE_MODEL (store),
450 &child_iter, parent_iter);
451 gtk_tree_model_get (GTK_TREE_MODEL (store), &child_iter,
452 COLUMN_IS_DUMMY, &dummy,
453 COLUMN_TERMINATOR);
454 if (!dummy) return;
455
456 gtk_tree_model_get (GTK_TREE_MODEL (store), parent_iter,
457 COLUMN_FULLPATH, &parent_dir,
458 COLUMN_TERMINATOR);
459
460 flags = GETDIR_FOLLOW_SYMLINK | GETDIR_READ_DOT;
461 get_dir (parent_dir, flags, NULL, &subdir_list);
462
463 if (dv->show_dotfile || conf.dirview_show_current_dir) {
464 insert_row (store, &iter, parent_iter, ".", parent_dir);
465 }
466
467 if (dv->show_dotfile || conf.dirview_show_parent_dir) {
468 gchar *end, *grandparent = remove_slash(parent_dir);
469
470 end = strrchr (grandparent, '/');
471 if (end) *(end + 1) = '\0';
472
473 insert_row (store, &iter, parent_iter, "..", grandparent);
474
475 g_free (grandparent);
476 }
477
478 for (node = subdir_list; node; node = g_list_next (node)) {
479 gchar *path = node->data;
480 gboolean dot_file_check;
481
482 dot_file_check = g_basename(path)[0] != '.'
483 || (dv->show_dotfile && g_basename(path)[0] == '.')
484 || (conf.dirview_show_current_dir && !strcmp (g_basename(path), "."))
485 || (conf.dirview_show_parent_dir && !strcmp (g_basename(path), ".."));
486
487 if (isdir (path) && dot_file_check) {
488 insert_row (store, &iter, parent_iter, g_basename (path), path);
489 }
490 }
491 g_list_foreach (subdir_list, (GFunc) g_free, NULL);
492 g_list_free (subdir_list);
493
494 gtk_tree_store_remove (store, &child_iter);
495
496 g_free (parent_dir);
497 }
498
499
500
501 /******************************************************************************
502 *
503 * Callback functions for popup menu
504 *
505 ******************************************************************************/
506 static void
cb_open_thumbnail(DirView * dv,ScanSubDirType scan_subdir,GtkWidget * menuitem)507 cb_open_thumbnail (DirView *dv, ScanSubDirType scan_subdir, GtkWidget *menuitem)
508 {
509 gchar *path;
510
511 path = dirview_get_selected_path (dv);
512 if (!path) return;
513
514 open_dir_images (path, dv->tw, NULL, LOAD_CACHE, scan_subdir);
515
516 g_free (path);
517 }
518
519
520 static void
cb_go_to_here(DirView * dv,guint action,GtkWidget * menuitem)521 cb_go_to_here (DirView *dv, guint action, GtkWidget *menuitem)
522 {
523 gchar *path;
524
525 path = dirview_get_selected_path (dv);
526 if (!path) return;
527
528 dirview_change_root (dv, path);
529
530 g_free (path);
531 }
532
533
534 static void
cb_refresh_dir_tree(DirView * dv,guint action,GtkWidget * menuitem)535 cb_refresh_dir_tree (DirView *dv, guint action, GtkWidget *menuitem)
536 {
537 GtkTreeModel *model;
538 GtkTreeSelection *selection;
539 GtkTreeIter iter;
540 gboolean success;
541
542 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
543 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dv->dirtree));
544 success = gtk_tree_selection_get_selected (selection, &model, &iter);
545 if (!success) return;
546
547 refresh_dir_tree (dv, &iter);
548 }
549
550
551 static void
cb_file_property(DirView * dv,guint action,GtkWidget * menuitem)552 cb_file_property (DirView *dv, guint action, GtkWidget *menuitem)
553 {
554 GimvImageInfo *info;
555 gchar *path, *tmpstr;
556
557 g_return_if_fail (dv);
558
559 tmpstr = dirview_get_selected_path (dv);
560 if (!tmpstr) return;
561
562 path = remove_slash (tmpstr);
563 g_free(tmpstr);
564
565 info = gimv_image_info_get (path);
566 if (!info) {
567 g_free (path);
568 return;
569 }
570
571 dlg_prop_from_image_info (info, 0);
572
573 gimv_image_info_unref (info);
574 g_free (path);
575 }
576
577
578 static void
cb_mkdir(DirView * dv,guint action,GtkWidget * menuitem)579 cb_mkdir (DirView *dv, guint action, GtkWidget *menuitem)
580 {
581 gchar *parent_path;
582 gboolean success;
583 GtkTreeIter iter;
584
585 g_return_if_fail (dv);
586
587 parent_path = dirview_get_selected_path (dv);
588 if (!parent_path) return;
589
590 success = make_dir_dialog (
591 parent_path,
592 GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
593
594 if (success) {
595 if (get_iter_from_path (dv, parent_path, &iter))
596 refresh_dir_tree (dv, &iter);
597 else
598 refresh_dir_tree (dv, NULL);
599 }
600
601 g_free (parent_path);
602 }
603
604
605 static void
cb_rename_dir(DirView * dv,guint action,GtkWidget * menuitem)606 cb_rename_dir (DirView *dv, guint action, GtkWidget *menuitem)
607 {
608 gboolean success;
609 gchar *path;
610
611 g_return_if_fail (dv);
612
613 path = dirview_get_selected_path (dv);
614 if (!path) return;
615
616 success = rename_dir_dialog
617 (path, GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
618
619 if (success) {
620 gchar *tmp_path, *parent_dir;
621 GtkTreeIter iter;
622
623 tmp_path = remove_slash (path);
624 parent_dir = g_dirname (tmp_path);
625
626 if (get_iter_from_path (dv, parent_dir, &iter))
627 refresh_dir_tree (dv, &iter);
628 else
629 refresh_dir_tree (dv, NULL);
630
631 g_free (tmp_path);
632 g_free (parent_dir);
633 }
634 }
635
636
637 static void
cb_delete_dir(DirView * dv,guint action,GtkWidget * menuitem)638 cb_delete_dir (DirView *dv, guint action, GtkWidget *menuitem)
639 {
640 gchar *path, *parent_dir;
641 GtkTreeIter iter;
642
643 g_return_if_fail (dv);
644
645 path = dirview_get_selected_path (dv);
646 if (!path) return;
647
648 if (path [strlen (path) - 1] == '/')
649 path [strlen (path) - 1] = '\0';
650
651 delete_dir (path, GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
652 g_free (path);
653
654 parent_dir = g_dirname (path);
655
656 /* refresh dir tree */
657 if (get_iter_from_path (dv, parent_dir, &iter))
658 refresh_dir_tree (dv, &iter);
659 else
660 refresh_dir_tree (dv, NULL);
661
662 g_free (parent_dir);
663 }
664
665
666
667 /******************************************************************************
668 *
669 * Callback functions for toolbar buttons.
670 *
671 ******************************************************************************/
672 static void
cb_home_button(GtkWidget * widget,DirView * dv)673 cb_home_button (GtkWidget *widget, DirView *dv)
674 {
675 g_return_if_fail (dv);
676
677 dirview_go_home (dv);
678 }
679
680
681 static void
cb_up_button(GtkWidget * widget,DirView * dv)682 cb_up_button (GtkWidget *widget, DirView *dv)
683 {
684 dirview_change_root_to_parent (dv);
685 }
686
687
688 static void
cb_refresh_button(GtkWidget * widget,DirView * dv)689 cb_refresh_button (GtkWidget *widget, DirView *dv)
690 {
691 GtkTreeModel *model;
692 GtkTreeIter iter;
693 gboolean success;
694
695 g_return_if_fail (widget && dv);
696
697 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
698 success = gtk_tree_model_get_iter_first (model, &iter);
699 if (!success) return;
700
701 refresh_dir_tree (dv, &iter);
702 }
703
704
705 static void
cb_dotfile_button(GtkWidget * widget,DirView * dv)706 cb_dotfile_button (GtkWidget *widget, DirView *dv)
707 {
708 GtkTreeModel *model;
709 GtkTreeIter iter;
710 gboolean success;
711
712 g_return_if_fail (widget && dv);
713
714 dv->show_dotfile = !dv->show_dotfile;
715
716 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
717 success = gtk_tree_model_get_iter_first (model, &iter);
718 if (!success) return;
719
720 refresh_dir_tree (dv, &iter);
721 }
722
723
724 /******************************************************************************
725 *
726 * Callback functions for DnD
727 *
728 ******************************************************************************/
729 static void
cb_drag_data_get(GtkWidget * dirtree,GdkDragContext * context,GtkSelectionData * seldata,guint info,guint time,gpointer data)730 cb_drag_data_get (GtkWidget *dirtree,
731 GdkDragContext *context,
732 GtkSelectionData *seldata,
733 guint info,
734 guint time,
735 gpointer data)
736 {
737 DirView *dv = data;
738 gchar *path, *urilist;
739
740 g_return_if_fail (dv);
741
742 path = dirview_get_selected_path(dv);
743 if (!path) return;
744 if (!*path) {
745 g_free (path);
746 return;
747 }
748
749 if (path [strlen (path) - 1] == '/')
750 path [strlen (path) - 1] = '\0';
751 urilist = g_strconcat ("file://", path, "\r\n", NULL);
752
753 gtk_selection_data_set(seldata, seldata->target,
754 8, urilist, strlen(urilist));
755
756 g_free (path);
757 g_free (urilist);
758 }
759
760
761 static gboolean
cb_drag_motion(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,guint time,gpointer data)762 cb_drag_motion (GtkWidget *widget,
763 GdkDragContext *drag_context,
764 gint x, gint y, guint time,
765 gpointer data)
766 {
767 GtkTreeModel *model;
768 GtkTreeIter iter;
769 GtkTreePath *dest_path = NULL;
770 GtkTreeViewDropPosition pos;
771 gboolean success, retval = FALSE;
772 /* DirView *dv = data; */
773
774 g_return_val_if_fail(GTK_IS_TREE_VIEW(widget), FALSE);
775 g_return_val_if_fail(data, FALSE);
776
777 success = gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),
778 x, y,
779 &dest_path, &pos);
780 if (!success) return FALSE;
781
782 model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
783 gtk_tree_model_get_iter(model, &iter, dest_path);
784 /*
785 gtk_tree_model_get(model, &iter,
786 COLUMN_FULLPATH, &path,
787 COLUMN_TERMINATOR);
788 */
789
790 if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
791 pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
792 {
793 gdk_drag_status(drag_context, GDK_ACTION_MOVE, time);
794 }
795 else if (pos == GTK_TREE_VIEW_DROP_BEFORE ||
796 pos == GTK_TREE_VIEW_DROP_AFTER)
797 {
798 gdk_drag_status(drag_context, 0, time);
799 retval = TRUE;
800 }
801
802 if (dest_path)
803 gtk_tree_path_free(dest_path);
804
805 return retval;
806 }
807
808
809 static void
cb_drag_data_received(GtkWidget * dirtree,GdkDragContext * context,gint x,gint y,GtkSelectionData * seldata,guint info,guint32 time,gpointer data)810 cb_drag_data_received (GtkWidget *dirtree,
811 GdkDragContext *context,
812 gint x, gint y,
813 GtkSelectionData *seldata,
814 guint info,
815 guint32 time,
816 gpointer data)
817 {
818 DirView *dv = data;
819 GtkTreePath *treepath;
820 GtkTreeModel *model;
821 GtkTreeIter iter;
822 gboolean success;
823 gchar *path;
824
825 g_return_if_fail (dv);
826
827 success = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (dirtree),
828 x, y,
829 &treepath, NULL,
830 NULL, NULL);
831 if (!success) return;
832
833 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dirtree));
834 gtk_tree_model_get_iter (model, &iter, treepath);
835 gtk_tree_model_get (model, &iter,
836 COLUMN_FULLPATH, &path,
837 COLUMN_TERMINATOR);
838
839 if (path && *path) {
840 if (iswritable (path)) {
841 dnd_file_operation (path, context, seldata, time, dv->tw);
842 success = gtk_tree_model_get_iter_first (model, &iter);
843 if (success)
844 refresh_dir_tree (dv, &iter);
845 else
846 refresh_dir_tree (dv, NULL);
847 } else {
848 gchar error_message[BUF_SIZE], *dir_internal;
849
850 dir_internal = charset_to_internal (path,
851 conf.charset_filename,
852 conf.charset_auto_detect_fn,
853 conf.charset_filename_mode);
854 g_snprintf (error_message, BUF_SIZE,
855 _("Permission denied: %s"),
856 dir_internal);
857 gtkutil_message_dialog (
858 _("Error!!"), error_message,
859 GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
860
861 g_free (dir_internal);
862 }
863 }
864
865 gtk_tree_path_free (treepath);
866 g_free (path);
867 }
868
869
870 static void
cb_drag_end(GtkWidget * dirtree,GdkDragContext * context,gpointer data)871 cb_drag_end (GtkWidget *dirtree, GdkDragContext *context, gpointer data)
872 {
873 DirView *dv = data;
874 GtkTreeModel *model;
875 GtkTreeIter iter;
876
877 g_return_if_fail (dirtree && dv);
878
879 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dirtree));
880 if (gtk_tree_model_get_iter_first (model, &iter))
881 refresh_dir_tree (dv, &iter);
882 else
883 refresh_dir_tree (dv, NULL);
884 }
885
886
887 static void
cb_toolbar_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)888 cb_toolbar_drag_begin (GtkWidget *widget,
889 GdkDragContext *context,
890 gpointer data)
891 {
892 GdkColormap *colormap;
893 GimvIcon *icon;
894
895 icon = gimv_icon_stock_get_icon ("paper");
896 colormap = gdk_colormap_get_system ();
897 gtk_drag_set_icon_pixmap (context, colormap,
898 icon->pixmap, icon->mask,
899 0, 0);
900 }
901
902
903 static void
cb_toolbar_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * seldata,guint info,guint time,gpointer data)904 cb_toolbar_drag_data_get (GtkWidget *widget,
905 GdkDragContext *context,
906 GtkSelectionData *seldata,
907 guint info,
908 guint time,
909 gpointer data)
910 {
911 switch (info) {
912 case TARGET_GIMV_COMPONENT:
913 gtk_selection_data_set(seldata, seldata->target,
914 8, "dummy", strlen("dummy"));
915 break;
916 }
917 }
918
919
920 typedef struct SwapCom_Tag
921 {
922 GimvThumbWin *tw;
923 gint src;
924 gint dest;
925 } SwapCom;
926
927
928 static gint
idle_thumbwin_swap_component(gpointer data)929 idle_thumbwin_swap_component (gpointer data)
930 {
931 SwapCom *swap = data;
932 gimv_thumb_win_swap_component (swap->tw, swap->src, swap->dest);
933 return FALSE;
934 }
935
936
937 static void
cb_com_swap_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * seldata,guint info,guint time,gpointer data)938 cb_com_swap_drag_data_received (GtkWidget *widget,
939 GdkDragContext *context,
940 gint x, gint y,
941 GtkSelectionData *seldata,
942 guint info,
943 guint time,
944 gpointer data)
945 {
946 GimvThumbWin *tw = data;
947 GtkWidget *src_widget;
948 gpointer p;
949 gint src, dest;
950
951 switch (info) {
952 case TARGET_GIMV_COMPONENT:
953 src_widget = gtk_drag_get_source_widget (context);
954 if (gdk_window_get_toplevel (src_widget->window)
955 != gdk_window_get_toplevel (widget->window))
956 {
957 return;
958 }
959
960 p = g_object_get_data (G_OBJECT (src_widget), "gimv-component");
961 src = GPOINTER_TO_INT (p);
962 if (!src) return;
963
964 p = g_object_get_data (G_OBJECT (widget), "gimv-component");
965 dest = GPOINTER_TO_INT (p);
966 if (!dest) return;
967
968 {
969 SwapCom *swap = g_new0 (SwapCom, 1);
970 swap->tw = tw;
971 swap->src = src;
972 swap->dest = dest;
973 /* to avoid gtk's bug, exec redraw after exit this callback function */
974 gtk_idle_add_full (/* GTK_PRIORITY_REDRAW */G_PRIORITY_LOW,
975 idle_thumbwin_swap_component, NULL, swap,
976 (GtkDestroyNotify) g_free);
977 }
978
979 break;
980
981 default:
982 break;
983 }
984 }
985
986
987
988 /******************************************************************************
989 *
990 * Other private functions
991 *
992 ******************************************************************************/
993 static void
get_icon_pixbufs(void)994 get_icon_pixbufs (void)
995 {
996 if (!folder) {
997 folder = gimv_icon_stock_get_pixbuf ("folder");
998 if (folder) g_object_ref (folder);
999 }
1000
1001 if (!ofolder) {
1002 ofolder = gimv_icon_stock_get_pixbuf ("folder-open");
1003 if (ofolder) g_object_ref (ofolder);
1004 }
1005
1006 if (!lfolder) {
1007 lfolder = gimv_icon_stock_get_pixbuf ("folder-link");
1008 if (lfolder) g_object_ref (lfolder);
1009 }
1010
1011 if (!lofolder) {
1012 lofolder = gimv_icon_stock_get_pixbuf ("folder-link-open");
1013 if (lofolder) g_object_ref (lofolder);
1014 }
1015
1016 if (!go_folder) {
1017 go_folder = gimv_icon_stock_get_pixbuf ("folder-go");
1018 if (go_folder) g_object_ref (go_folder);
1019 }
1020
1021 if (!up_folder) {
1022 up_folder = gimv_icon_stock_get_pixbuf ("folder-up");
1023 if (up_folder) g_object_ref (up_folder);
1024 }
1025
1026 if (!lock_folder) {
1027 lock_folder = gimv_icon_stock_get_pixbuf ("folder-lock");
1028 if (lock_folder) g_object_ref (lock_folder);
1029 }
1030 }
1031
1032
1033 static void
set_columns_type(GtkTreeView * tree_view)1034 set_columns_type (GtkTreeView *tree_view)
1035 {
1036 GtkTreeViewColumn *col;
1037 GtkCellRenderer *render;
1038
1039 gtk_tree_view_set_rules_hint (tree_view, FALSE);
1040 gtk_tree_view_set_rules_hint (tree_view, TRUE);
1041
1042 col = gtk_tree_view_column_new();
1043 gtk_tree_view_column_set_title (col, "Directory Name");
1044
1045 render = gtk_cell_renderer_pixbuf_new ();
1046 gtk_tree_view_column_pack_start (col, render, FALSE);
1047 gtk_tree_view_column_add_attribute (col, render,
1048 "pixbuf", COLUMN_ICON_CLOSE);
1049 gtk_tree_view_column_add_attribute (col, render,
1050 "pixbuf-expander-open",
1051 COLUMN_ICON_OPEN);
1052 gtk_tree_view_column_add_attribute (col, render,
1053 "pixbuf-expander-closed",
1054 COLUMN_ICON_CLOSE);
1055
1056 render = gtk_cell_renderer_text_new ();
1057 gtk_tree_view_column_pack_start (col, render, TRUE);
1058 gtk_tree_view_column_add_attribute (col, render, "text", COLUMN_LABEL);
1059
1060 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
1061 gtk_tree_view_set_expander_column (tree_view, col);
1062 }
1063
1064
1065 static void
dirview_create_treeview(DirView * dv,const gchar * root)1066 dirview_create_treeview (DirView *dv, const gchar *root)
1067 {
1068 GtkTreeStore *store;
1069 GtkTreeIter root_iter;
1070 GtkTreePath *treepath;
1071
1072 get_icon_pixbufs();
1073
1074 store = gtk_tree_store_new (N_COLUMN,
1075 G_TYPE_STRING,
1076 G_TYPE_STRING,
1077 GDK_TYPE_PIXBUF,
1078 GDK_TYPE_PIXBUF,
1079 G_TYPE_BOOLEAN);
1080
1081 dv->dirtree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1082
1083 insert_row (store, &root_iter, NULL, root, root);
1084
1085 g_object_unref (G_OBJECT (store));
1086
1087 g_signal_connect (G_OBJECT (dv->dirtree), "row-expanded",
1088 G_CALLBACK (cb_tree_expand), dv);
1089 g_signal_connect (G_OBJECT (dv->dirtree),"button_press_event",
1090 G_CALLBACK (cb_button_press), dv);
1091 g_signal_connect (G_OBJECT (dv->dirtree),"button_release_event",
1092 G_CALLBACK (cb_button_release), dv);
1093 g_signal_connect (G_OBJECT(dv->dirtree), "scroll-event",
1094 G_CALLBACK(cb_scroll), dv);
1095 g_signal_connect (G_OBJECT (dv->dirtree), "key_press_event",
1096 G_CALLBACK (cb_key_press), dv);
1097
1098 /* for DnD */
1099 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (dv->dirtree),
1100 GDK_BUTTON1_MASK
1101 | GDK_BUTTON2_MASK
1102 | GDK_BUTTON3_MASK,
1103 dnd_types_uri,
1104 dnd_types_uri_num,
1105 GDK_ACTION_ASK | GDK_ACTION_COPY
1106 | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1107 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (dv->dirtree),
1108 dnd_types_uri,
1109 dnd_types_uri_num,
1110 GDK_ACTION_ASK | GDK_ACTION_COPY
1111 | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1112 g_signal_connect (G_OBJECT (dv->dirtree), "drag_data_get",
1113 G_CALLBACK (cb_drag_data_get), dv);
1114 g_signal_connect (G_OBJECT (dv->dirtree), "drag_motion",
1115 G_CALLBACK (cb_drag_motion), dv);
1116 g_signal_connect (G_OBJECT (dv->dirtree), "drag_data_received",
1117 G_CALLBACK (cb_drag_data_received), dv);
1118 g_signal_connect (G_OBJECT (dv->dirtree), "drag_end",
1119 G_CALLBACK (cb_drag_end), dv);
1120
1121 set_columns_type (GTK_TREE_VIEW (dv->dirtree));
1122 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dv->dirtree), FALSE);
1123
1124 gtk_container_add (GTK_CONTAINER (dv->scroll_win), dv->dirtree);
1125 gtk_widget_show (dv->dirtree);
1126
1127 treepath = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &root_iter);
1128 gtk_tree_view_expand_row (GTK_TREE_VIEW (dv->dirtree), treepath, FALSE);
1129
1130 gtk_tree_path_free (treepath);
1131
1132 adjust_tree_idle (dv, NULL);
1133 }
1134
1135
1136 static GtkWidget *
dirview_create_toolbar(DirView * dv)1137 dirview_create_toolbar (DirView *dv)
1138 {
1139 GtkWidget *toolbar;
1140 GtkWidget *button;
1141 GtkWidget *iconw;
1142
1143 g_return_val_if_fail (dv, NULL);
1144
1145 toolbar = gtkutil_create_toolbar ();
1146
1147 /* file open button */
1148 iconw = gimv_icon_stock_get_widget ("small_home");
1149 button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
1150 _("Home"),
1151 _("Home"),
1152 _("Home"),
1153 iconw,
1154 G_CALLBACK (cb_home_button),
1155 dv);
1156
1157 /* preference button */
1158 iconw = gimv_icon_stock_get_widget ("small_up");
1159 button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
1160 _("Up"),
1161 _("Up"),
1162 _("Up"),
1163 iconw,
1164 G_CALLBACK (cb_up_button),
1165 dv);
1166
1167 /* refresh button */
1168 iconw = gimv_icon_stock_get_widget ("small_refresh");
1169 button = gtk_toolbar_append_item(GTK_TOOLBAR (toolbar),
1170 _("Refresh"),
1171 _("Refresh"),
1172 _("Refresh"),
1173 iconw,
1174 G_CALLBACK (cb_refresh_button),
1175 dv);
1176
1177 /* preference button */
1178 iconw = gimv_icon_stock_get_widget ("dotfile");
1179 button = gtk_toolbar_append_item(GTK_TOOLBAR (toolbar),
1180 _("Dotfile"),
1181 _("Show/Hide dotfile"),
1182 _("Show/Hide dotfile"),
1183 iconw,
1184 G_CALLBACK (cb_dotfile_button),
1185 dv);
1186
1187 gtk_widget_show_all (toolbar);
1188 gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
1189
1190 return toolbar;
1191 }
1192
1193
1194 /*
1195 * remove all children, and insert dummy row.
1196 */
1197 static void
insert_dummy_row(GtkTreeStore * store,GtkTreeIter * parent_iter)1198 insert_dummy_row (GtkTreeStore *store, GtkTreeIter *parent_iter)
1199 {
1200 GtkTreeIter iter;
1201 gboolean success;
1202
1203 g_return_if_fail (store);
1204
1205 gtk_tree_store_prepend (store, &iter, parent_iter);
1206 gtk_tree_store_set (store, &iter,
1207 COLUMN_IS_DUMMY, TRUE,
1208 COLUMN_TERMINATOR);
1209
1210 success = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
1211 &iter,
1212 parent_iter,
1213 1);
1214 if (!success) return;
1215
1216 while (gtk_tree_store_is_ancestor (store, parent_iter, &iter)) {
1217 gtk_tree_store_remove (store, &iter);
1218 }
1219 }
1220
1221
1222 /*
1223 * fullpath shouldn't be terminated with "/" character.
1224 */
1225 static void
insert_row(GtkTreeStore * store,GtkTreeIter * iter,GtkTreeIter * parent_iter,const gchar * label,const gchar * fullpath)1226 insert_row (GtkTreeStore *store,
1227 GtkTreeIter *iter, GtkTreeIter *parent_iter,
1228 const gchar *label, const gchar *fullpath)
1229 {
1230 GdkPixbuf *icon, *oicon;
1231 gchar *path, *tmpstr;
1232 gchar *label_internal;
1233
1234 g_return_if_fail (store);
1235 g_return_if_fail (iter);
1236 g_return_if_fail (label && *label);
1237 g_return_if_fail (fullpath && *fullpath);
1238
1239 path = remove_slash (fullpath);
1240
1241 if (!strcmp (label, ".")) {
1242 icon = go_folder;
1243 oicon = go_folder;
1244 } else if (!strcmp (label, "..")) {
1245 icon = up_folder;
1246 oicon = up_folder;
1247 } else if (access(path, R_OK)) {
1248 icon = lock_folder;
1249 oicon = lock_folder;
1250 } else if (islink(path)) {
1251 icon = lfolder;
1252 oicon = lofolder;
1253 } else if (isdir(path)) {
1254 icon = folder;
1255 oicon = ofolder;
1256 } else {
1257 return;
1258 }
1259
1260 tmpstr = add_slash (path);
1261 g_free(path);
1262 path = tmpstr;
1263
1264 /* convert charset */
1265 label_internal = charset_to_internal (label, conf.charset_filename,
1266 conf.charset_auto_detect_fn,
1267 conf.charset_filename_mode);
1268
1269 gtk_tree_store_append (store, iter, parent_iter);
1270 gtk_tree_store_set (store, iter,
1271 COLUMN_LABEL, label_internal,
1272 COLUMN_FULLPATH, path,
1273 COLUMN_ICON_OPEN, oicon,
1274 COLUMN_ICON_CLOSE, icon,
1275 COLUMN_IS_DUMMY, FALSE,
1276 COLUMN_TERMINATOR);
1277
1278 if (strcmp (label, ".") && strcmp (label, "..") && !access(path, R_OK))
1279 insert_dummy_row (store, iter);
1280
1281 g_free (label_internal);
1282 g_free (path);
1283 }
1284
1285
1286 static gboolean
is_in_view(GtkTreeView * treeview,GtkTreePath * treepath)1287 is_in_view (GtkTreeView *treeview, GtkTreePath *treepath)
1288 {
1289 GdkRectangle widget_area, cell_area;
1290
1291 if (!GTK_WIDGET_REALIZED (treeview))
1292 return FALSE;
1293
1294 /* widget area */
1295 gtkutil_get_widget_area (GTK_WIDGET (treeview), &widget_area);
1296
1297 gtk_tree_view_get_cell_area(treeview, treepath, NULL, &cell_area);
1298
1299 if (cell_area.y >= 0 && cell_area.y < widget_area.height)
1300 return TRUE;
1301 else
1302 return FALSE;
1303 }
1304
1305
1306 static void
adjust_tree(GtkTreeView * treeview,GtkTreeIter * iter)1307 adjust_tree (GtkTreeView *treeview, GtkTreeIter *iter)
1308 {
1309 GtkTreeModel *model;
1310 GtkTreePath *treepath;
1311 GtkTreeSelection *selection;
1312 GtkTreeIter tmp_iter;
1313 gboolean success;
1314
1315 model = gtk_tree_view_get_model (treeview);
1316 selection = gtk_tree_view_get_selection (treeview);
1317
1318 if (iter) {
1319 treepath = gtk_tree_model_get_path (model, iter);
1320 tmp_iter = *iter;
1321 } else {
1322 treepath = gtk_tree_path_new_from_string ("0");
1323 success = gtk_tree_model_get_iter (model, &tmp_iter, treepath);
1324 if (!success) goto FUNC_END;
1325 }
1326
1327 gtk_tree_selection_select_path (selection, treepath);
1328 if (!is_in_view(treeview, treepath))
1329 gtk_tree_view_scroll_to_cell (treeview, treepath, NULL,
1330 TRUE, 0.0, 0.0);
1331
1332 FUNC_END:
1333 gtk_tree_path_free (treepath);
1334 treepath = NULL;
1335 }
1336
1337
1338 static gboolean
get_iter_from_path(DirView * dv,const gchar * str,GtkTreeIter * iter)1339 get_iter_from_path (DirView *dv, const gchar *str, GtkTreeIter *iter)
1340 {
1341 GtkTreeModel *model;
1342 GtkTreeIter parent_iter, child_iter;
1343 GtkTreePath *treepath;
1344 GtkTreeSelection *selection;
1345 gchar *destpath;
1346 gint len_src, len_dest;
1347 gboolean go_next, retval = FALSE;
1348
1349 g_return_val_if_fail (dv, FALSE);
1350 g_return_val_if_fail (iter, FALSE);
1351
1352 destpath = add_slash (str);
1353 if (!destpath) return FALSE;
1354
1355 len_src = strlen (dv->root_dir);
1356 len_dest = strlen (destpath);
1357
1358 if (len_dest < len_src || strncmp (dv->root_dir, destpath, len_src)) {
1359 goto ERROR;
1360 }
1361
1362 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
1363 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dv->dirtree));
1364
1365 go_next = gtk_tree_model_get_iter_from_string (model, &parent_iter, "0");
1366 if (!go_next) goto ERROR;
1367 treepath = gtk_tree_model_get_path (model, &parent_iter);
1368
1369 if (!strcmp (destpath, dv->root_dir)) {
1370 gtk_tree_path_free (treepath);
1371 g_free (destpath);
1372 return gtk_tree_model_get_iter_first (model, iter);
1373 }
1374
1375 gtk_tree_view_expand_row (GTK_TREE_VIEW (dv->dirtree), treepath, FALSE);
1376 gtk_tree_path_free (treepath);
1377 treepath = NULL;
1378
1379 go_next = gtk_tree_model_get_iter_from_string (model, &parent_iter, "0:0");
1380
1381 while (go_next) {
1382 gint len;
1383 gchar *path, *label;
1384
1385 gtk_tree_model_get (model, &parent_iter,
1386 COLUMN_LABEL, &label,
1387 COLUMN_FULLPATH, &path,
1388 COLUMN_TERMINATOR);
1389
1390 len = strlen (path); /* path will be terminated by "/" */
1391
1392 /* It is just the directory! */
1393 if (!strcmp (label, ".") || !strcmp (label, "..")) {
1394 go_next = gtk_tree_model_iter_next (model, &parent_iter);
1395 } else if (!strcmp (destpath, path)) {
1396 *iter = parent_iter;
1397 go_next = FALSE;
1398 retval = TRUE;
1399
1400 /* It is the parent directory of the destpath */
1401 } else if (!strncmp (destpath, path, len)) {
1402 treepath = gtk_tree_model_get_path (model, &parent_iter);
1403 go_next = gtk_tree_view_expand_row (GTK_TREE_VIEW (dv->dirtree), treepath,
1404 FALSE);
1405 go_next = gtk_tree_model_iter_children (model,
1406 &child_iter,
1407 &parent_iter);
1408 parent_iter = child_iter;
1409
1410 gtk_tree_path_free (treepath);
1411 treepath = NULL;
1412
1413 /* No match. Search the next... */
1414 } else {
1415 go_next = gtk_tree_model_iter_next (model, &parent_iter);
1416 }
1417
1418 g_free (path);
1419 g_free (label);
1420 }
1421
1422
1423 g_free (destpath);
1424 return retval;
1425
1426 ERROR:
1427 g_free (destpath);
1428 return FALSE;
1429 }
1430
1431
1432 struct AdjustTreeIdle {
1433 DirView *dv;
1434 GtkTreeView *treeview;
1435 gboolean has_iter;
1436 GtkTreeIter iter;
1437 };
1438
1439
1440 static gint
idle_adjust_tree(gpointer data)1441 idle_adjust_tree (gpointer data)
1442 {
1443 struct AdjustTreeIdle *idle = data;
1444
1445 idle->dv->priv->adjust_tree_id = 0;
1446 if (idle->has_iter)
1447 adjust_tree (idle->treeview, &idle->iter);
1448 else
1449 adjust_tree (idle->treeview, NULL);
1450
1451 return FALSE;
1452 }
1453
1454
1455 static void
adjust_tree_idle(DirView * dv,GtkTreeIter * iter)1456 adjust_tree_idle (DirView *dv, GtkTreeIter *iter)
1457 {
1458 GtkTreeView *treeview = GTK_TREE_VIEW (dv->dirtree);
1459 struct AdjustTreeIdle *idle;
1460
1461 g_return_if_fail (GTK_IS_TREE_VIEW (treeview));
1462
1463 idle = g_new0(struct AdjustTreeIdle, 1);
1464
1465 idle->dv = dv;
1466 idle->treeview = treeview;
1467 if (iter) {
1468 idle->iter = *iter;
1469 idle->has_iter = TRUE;
1470 } else {
1471 idle->has_iter = FALSE;
1472 }
1473
1474 dv->priv->adjust_tree_id =
1475 gtk_idle_add_full (G_PRIORITY_DEFAULT,
1476 idle_adjust_tree, NULL, idle,
1477 (GtkDestroyNotify) g_free);
1478 }
1479
1480
1481 static void
get_expanded_dirs(GtkTreeView * treeview,GtkTreePath * treepath,gpointer data)1482 get_expanded_dirs (GtkTreeView *treeview, GtkTreePath *treepath, gpointer data)
1483 {
1484 GtkTreeModel *model;
1485 GtkTreeIter iter;
1486 GList **list;
1487 gchar *path;
1488
1489 g_return_if_fail (data);
1490 list = data;
1491
1492 model = gtk_tree_view_get_model (treeview);
1493
1494 gtk_tree_model_get_iter (model, &iter, treepath);
1495 gtk_tree_model_get (model, &iter,
1496 COLUMN_FULLPATH, &path,
1497 COLUMN_TERMINATOR);
1498
1499 g_return_if_fail (path && *path);
1500
1501 *list = g_list_append (*list, path);
1502 }
1503
1504
1505 static void
refresh_dir_tree(DirView * dv,GtkTreeIter * parent_iter)1506 refresh_dir_tree (DirView *dv, GtkTreeIter *parent_iter)
1507 {
1508 GtkTreeView *treeview;
1509 GtkTreeStore *store;
1510 GtkTreeIter root_iter, iter;
1511 GtkTreePath *treepath;
1512 gchar *root_dir, *selected_path;
1513 GList *expand_list = NULL, *node;
1514 gboolean selected;
1515
1516 g_return_if_fail (dv);
1517
1518 selected_path = dirview_get_selected_path (dv);
1519 if (!selected_path) selected_path = g_strdup (dv->root_dir);
1520
1521 /* get expanded directory list */
1522 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (dv->dirtree),
1523 get_expanded_dirs,
1524 &expand_list);
1525
1526 /* replace root node */
1527 root_dir = g_strdup (dv->root_dir);
1528 #if 1 /* almost same with dirview_change_root () */
1529 g_free (dv->root_dir);
1530 dv->root_dir = add_slash (root_dir);
1531
1532 treeview = GTK_TREE_VIEW (dv->dirtree);
1533
1534 store = GTK_TREE_STORE (gtk_tree_view_get_model (treeview));
1535 gtk_tree_store_clear (store);
1536 insert_row (store, &root_iter, NULL, dv->root_dir, dv->root_dir);
1537
1538 treepath = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &root_iter);
1539
1540 gtk_tree_path_free (treepath);
1541 #endif
1542 g_free (root_dir);
1543
1544 /* restore expanded directory */
1545 for (node = expand_list; node; node = g_list_next (node)) {
1546 dirview_expand_dir (dv, node->data, FALSE);
1547 }
1548
1549 g_list_foreach (expand_list, (GFunc) g_free, NULL);
1550 g_list_free (expand_list);
1551
1552 /* adjust tree pos */
1553 selected = get_iter_from_path (dv, selected_path, &iter);
1554 if (selected)
1555 adjust_tree_idle (dv, &iter);
1556
1557 g_free (selected_path);
1558 }
1559
1560
1561 static void
dirview_popup_menu(DirView * dv,GdkEventButton * event)1562 dirview_popup_menu (DirView *dv, GdkEventButton *event)
1563 {
1564 GtkTreeModel *model;
1565 GtkTreePath *treepath;
1566 GtkTreeIter iter;
1567 gboolean success;
1568 gchar *path, *parent, *tmpstr, *label;
1569
1570 GtkItemFactory *ifactory;
1571 GtkWidget *dirview_popup, *menuitem;
1572 gint n_menu_items;
1573 guint button;
1574 guint32 time;
1575 GtkMenuPositionFunc pos_fn = NULL;
1576
1577 g_return_if_fail (dv);
1578
1579 success = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (dv->dirtree),
1580 event->x, event->y,
1581 &treepath, NULL, NULL, NULL);
1582 if (!success) return;
1583
1584 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
1585 gtk_tree_model_get_iter (model, &iter, treepath);
1586 gtk_tree_model_get (model, &iter,
1587 COLUMN_LABEL, &label,
1588 COLUMN_FULLPATH, &path,
1589 COLUMN_TERMINATOR);
1590
1591 tmpstr = remove_slash (path);
1592 parent = g_dirname (tmpstr);
1593 g_free (tmpstr);
1594
1595 if (event) {
1596 button = event->button;
1597 time = event->time;
1598 } else {
1599 button = 0;
1600 time = GDK_CURRENT_TIME;
1601 pos_fn = menu_calc_popup_position;
1602 }
1603
1604 if (dv->popup_menu) {
1605 gtk_widget_unref (dv->popup_menu);
1606 dv->popup_menu = NULL;
1607 }
1608
1609 n_menu_items = sizeof(dirview_popup_items)
1610 / sizeof(dirview_popup_items[0]) - 1;
1611 dirview_popup = menu_create_items(NULL, dirview_popup_items,
1612 n_menu_items, "<DirViewPop>", dv);
1613
1614
1615 /* set sensitive */
1616 ifactory = gtk_item_factory_from_widget (dirview_popup);
1617
1618 if (!strcmp (label, ".") || !strcmp (label, ".."))
1619 {
1620 menuitem = gtk_item_factory_get_item (ifactory, "/Refresh Tree");
1621 gtk_widget_set_sensitive (menuitem, FALSE);
1622 menuitem = gtk_item_factory_get_item (ifactory, "/Make Directory...");
1623 gtk_widget_set_sensitive (menuitem, FALSE);
1624 }
1625
1626 if (!iswritable (path)) {
1627 menuitem = gtk_item_factory_get_item (ifactory, "/Make Directory...");
1628 gtk_widget_set_sensitive (menuitem, FALSE);
1629 }
1630
1631 if (!parent || !strcmp (parent, ".") || !iswritable (parent)
1632 || !strcmp (label, ".") || !strcmp (label, ".."))
1633 {
1634 menuitem = gtk_item_factory_get_item (ifactory, "/Rename Directory...");
1635 gtk_widget_set_sensitive (menuitem, FALSE);
1636 menuitem = gtk_item_factory_get_item (ifactory, "/Delete Directory...");
1637 gtk_widget_set_sensitive (menuitem, FALSE);
1638 }
1639
1640 gtk_tree_path_free (treepath);
1641 g_free (label);
1642 g_free (path);
1643 g_free (parent);
1644
1645 /* popup menu */
1646 gtk_menu_popup(GTK_MENU (dirview_popup), NULL, NULL,
1647 pos_fn, dv->dirtree->window, button, time);
1648
1649 dv->popup_menu = dirview_popup;
1650
1651 g_object_ref (G_OBJECT (dv->popup_menu));
1652 gtk_object_sink (GTK_OBJECT (dv->popup_menu));
1653 }
1654
1655
1656 typedef struct ButtonActionData_Tag
1657 {
1658 DirView *dv;
1659 gchar *path, *label;
1660 gint action_num;
1661 } ButtonActionData;
1662
1663
1664 static void
free_button_action_data(ButtonActionData * data)1665 free_button_action_data (ButtonActionData *data)
1666 {
1667 g_free (data->path);
1668 g_free (data->label);
1669 g_free (data);
1670 }
1671
1672
1673 static gboolean
idle_dirview_button_action(gpointer data)1674 idle_dirview_button_action (gpointer data)
1675 {
1676 ButtonActionData *bdata = data;
1677 DirView *dv = bdata->dv;
1678 gchar *path = bdata->path, *label = bdata->label;
1679
1680 dv->priv->button_action_id = 0;
1681
1682 switch (abs (bdata->action_num)) {
1683 case MouseActLoadThumb:
1684 if (!strcmp (label, ".") || !strcmp (label, "..")) {
1685 dirview_change_root (dv, path);
1686 } else {
1687 open_dir_images (path, dv->tw, NULL, LOAD_CACHE, SCAN_SUB_DIR_NONE);
1688 }
1689 break;
1690 case MouseActLoadThumbRecursive:
1691 if (!strcmp (label, ".") || !strcmp (label, "..")) {
1692 dirview_change_root (dv, path);
1693 } else {
1694 open_dir_images (path, dv->tw, NULL, LOAD_CACHE, SCAN_SUB_DIR);
1695 }
1696 break;
1697 case MouseActLoadThumbRecursiveInOneTab:
1698 if (!strcmp (label, ".") || !strcmp (label, "..")) {
1699 dirview_change_root (dv, path);
1700 } else {
1701 open_dir_images (path, dv->tw, NULL, LOAD_CACHE, SCAN_SUB_DIR_ONE_TAB);
1702 }
1703 break;
1704 case MouseActChangeTop:
1705 dirview_change_root (dv, path);
1706 break;
1707 default:
1708 break;
1709 }
1710
1711 free_button_action_data (bdata);
1712
1713 return FALSE;
1714 }
1715
1716
1717 static gboolean
dirview_button_action(DirView * dv,GdkEventButton * event,gint num)1718 dirview_button_action (DirView *dv, GdkEventButton *event, gint num)
1719 {
1720 gchar *path = NULL, *label;
1721 GtkTreeSelection *selection;
1722 GtkTreeModel *model;
1723 gboolean success, retval = FALSE;
1724 GtkTreePath *treepath;
1725 GtkTreeViewColumn *treecolumn;
1726 gint cell_x, cell_y;
1727 GtkTreeIter iter;
1728
1729 success = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (dv->dirtree),
1730 event->x, event->y,
1731 &treepath, &treecolumn,
1732 &cell_x, &cell_y);
1733 if (!success) return FALSE;
1734
1735 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dv->dirtree));
1736 gtk_tree_selection_select_path (selection, treepath);
1737
1738 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
1739 gtk_tree_model_get_iter (model, &iter, treepath);
1740 gtk_tree_model_get (model, &iter,
1741 COLUMN_LABEL, &label,
1742 COLUMN_FULLPATH, &path,
1743 COLUMN_TERMINATOR);
1744
1745 switch (abs(num)) {
1746 case MouseActLoadThumb:
1747 case MouseActLoadThumbRecursive:
1748 case MouseActLoadThumbRecursiveInOneTab:
1749 case MouseActChangeTop:
1750 {
1751 ButtonActionData *data = g_new0 (ButtonActionData, 1);
1752
1753 data->dv = dv;
1754 data->path = path;
1755 data->label = label;
1756 data->action_num = num;
1757
1758 dv->priv->button_action_id
1759 = gtk_idle_add (idle_dirview_button_action, data);
1760
1761 gtk_tree_path_free (treepath);
1762
1763 return FALSE;
1764 break;
1765 }
1766 case MouseActPopupMenu:
1767 dirview_popup_menu (dv, event);
1768 if (num > 0) retval = TRUE;
1769 break;
1770 default:
1771 break;
1772 }
1773
1774 g_free (path);
1775 g_free (label);
1776 gtk_tree_path_free (treepath);
1777
1778 return retval;
1779 }
1780
1781
1782
1783 /******************************************************************************
1784 *
1785 * Public functions
1786 *
1787 ******************************************************************************/
1788 void
dirview_change_root(DirView * dv,const gchar * root_dir)1789 dirview_change_root (DirView *dv, const gchar *root_dir)
1790 {
1791 GtkTreeView *treeview;
1792 GtkTreeStore *store;
1793 GtkTreeIter root_iter;
1794 GtkTreePath *treepath;
1795 gchar *dest_dir;
1796
1797 g_return_if_fail (dv);
1798 g_return_if_fail (root_dir && *root_dir);
1799
1800 dest_dir = add_slash (root_dir);
1801
1802 if (!isdir (dest_dir)) {
1803 g_free (dest_dir);
1804 return;
1805 }
1806
1807 g_free (dv->root_dir);
1808 dv->root_dir = dest_dir;
1809
1810 treeview = GTK_TREE_VIEW (dv->dirtree);
1811
1812 store = GTK_TREE_STORE (gtk_tree_view_get_model (treeview));
1813 gtk_tree_store_clear (store);
1814 insert_row (store, &root_iter, NULL, dv->root_dir, dv->root_dir);
1815
1816 treepath = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &root_iter);
1817 gtk_tree_view_expand_row (treeview, treepath, FALSE);
1818
1819 gtk_tree_path_free (treepath);
1820
1821 adjust_tree_idle (dv, NULL);
1822 }
1823
1824
1825 void
dirview_change_root_to_parent(DirView * dv)1826 dirview_change_root_to_parent (DirView *dv)
1827 {
1828 gchar *end;
1829 gchar *root;
1830
1831 g_return_if_fail (dv);
1832
1833 root = g_strdup (dv->root_dir);
1834 end = strrchr (root, '/');
1835 if (end && end != root) *end = '\0';
1836 end = strrchr (root, '/');
1837 if (end) *(end + 1) = '\0';
1838
1839 dirview_change_dir (dv, root);
1840 g_free (root);
1841 }
1842
1843
1844 void
dirview_change_dir(DirView * dv,const gchar * str)1845 dirview_change_dir (DirView *dv, const gchar *str)
1846 {
1847 GtkTreeModel *model;
1848 GtkTreeIter iter;
1849 gchar *destpath;
1850 gboolean success;
1851
1852 g_return_if_fail (dv);
1853
1854 destpath = add_slash (str);
1855 if (!destpath) return;
1856
1857 if (!isdir (destpath)) {
1858 g_free (destpath);
1859 return;
1860 }
1861
1862 /* FIXME */
1863 /* if selected path in directory view is same as str, adjust to it */
1864 /* END FIXME */
1865
1866 success = get_iter_from_path (dv, destpath, &iter);
1867
1868 if (success) {
1869 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
1870 adjust_tree_idle (dv, &iter);
1871 } else {
1872 dirview_change_root (dv, str);
1873 }
1874
1875 g_free (destpath);
1876 }
1877
1878
1879 void
dirview_go_home(DirView * dv)1880 dirview_go_home (DirView *dv)
1881 {
1882 const gchar *home = g_getenv ("HOME");
1883
1884 dirview_change_root (dv, home);
1885 dirview_change_dir (dv, home);
1886 }
1887
1888
1889 void
dirview_refresh_list(DirView * dv)1890 dirview_refresh_list (DirView *dv)
1891 {
1892 GtkTreeModel *model;
1893 GtkTreeIter iter;
1894 gboolean success;
1895
1896 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
1897 success = gtk_tree_model_get_iter_first (model, &iter);
1898 if (!success) return;
1899
1900 refresh_dir_tree (dv, &iter);
1901 }
1902
1903
1904 gchar *
dirview_get_selected_path(DirView * dv)1905 dirview_get_selected_path (DirView *dv)
1906 {
1907 gboolean success;
1908 GtkTreeSelection *selection;
1909 GtkTreeModel *model;
1910 GtkTreeIter iter;
1911 gchar *path;
1912
1913 g_return_val_if_fail (dv, NULL);
1914 g_return_val_if_fail (dv->dirtree, NULL);
1915
1916 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dv->dirtree));
1917 g_return_val_if_fail (selection, NULL);
1918
1919 success = gtk_tree_selection_get_selected (selection, &model, &iter);
1920 if (!success) return NULL;
1921
1922 gtk_tree_model_get (model, &iter,
1923 COLUMN_FULLPATH, &path,
1924 COLUMN_TERMINATOR);
1925
1926 return path;
1927 }
1928
1929
1930 void
dirview_expand_dir(DirView * dv,const gchar * dir,gboolean open_all)1931 dirview_expand_dir (DirView *dv, const gchar *dir, gboolean open_all)
1932 {
1933 GtkTreeIter iter;
1934 GtkTreeModel *model;
1935 GtkTreePath *treepath;
1936 gboolean success;
1937
1938 success = get_iter_from_path (dv, dir, &iter);
1939 if (!success) return;
1940
1941 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dv->dirtree));
1942 treepath = gtk_tree_model_get_path (model, &iter);
1943
1944 gtk_tree_view_expand_row (GTK_TREE_VIEW (dv->dirtree), treepath, open_all);
1945
1946 gtk_tree_path_free (treepath);
1947 }
1948
1949
1950 gboolean
dirview_set_opened_mark(DirView * dv,const gchar * path)1951 dirview_set_opened_mark (DirView *dv, const gchar *path)
1952 {
1953 /* note implemented yet */
1954 return TRUE;
1955 }
1956
1957
1958 gboolean
dirview_unset_opened_mark(DirView * dv,const gchar * path)1959 dirview_unset_opened_mark (DirView *dv, const gchar *path)
1960 {
1961 /* note implemented yet */
1962 return TRUE;
1963 }
1964
1965
1966 void
dirview_show_toolbar(DirView * dv)1967 dirview_show_toolbar (DirView *dv)
1968 {
1969 g_return_if_fail (dv);
1970
1971 dv->show_toolbar = TRUE;
1972 gtk_widget_show (dv->toolbar_eventbox);
1973 }
1974
1975
1976 void
dirview_hide_toolbar(DirView * dv)1977 dirview_hide_toolbar (DirView *dv)
1978 {
1979 g_return_if_fail (dv);
1980
1981 dv->show_toolbar = FALSE;
1982 gtk_widget_hide (dv->toolbar_eventbox);
1983 }
1984
1985
1986 DirView *
dirview_create(const gchar * root_dir,GtkWidget * parent_win,GimvThumbWin * tw)1987 dirview_create (const gchar *root_dir,
1988 GtkWidget *parent_win,
1989 GimvThumbWin *tw)
1990 {
1991 DirView *dv;
1992 GtkWidget *eventbox;
1993 const gchar *home = g_getenv ("HOME");
1994
1995 dv = g_new0 (DirView, 1);
1996 dv->priv = g_new0 (DirViewPrivate,1);
1997
1998 if (root_dir)
1999 dv->root_dir = add_slash (root_dir);
2000 else
2001 dv->root_dir = add_slash (home);
2002
2003 dv->dirtree = NULL;
2004 dv->popup_menu = NULL;
2005 dv->tw = tw;
2006 dv->show_toolbar = conf.dirview_show_toolbar;
2007 dv->show_dotfile = conf.dirview_show_dotfile;
2008 dv->priv->hilit_dir = -1;
2009 dv->priv->scroll_timer_id = 0;
2010 dv->priv->drag_tree_row = NULL;
2011 dv->priv->button_action_id = 0;
2012 dv->priv->swap_com_id = 0;
2013 dv->priv->adjust_tree_id = 0;
2014
2015 /* main vbox */
2016 dv->container = gtk_vbox_new (FALSE, 0);
2017 gtk_widget_set_name (dv->container, "DirView");
2018 gtk_widget_show (dv->container);
2019
2020 dnd_dest_set (dv->container, dnd_types_component, dnd_types_component_num);
2021 g_object_set_data (G_OBJECT (dv->container),
2022 "gimv-component",
2023 GINT_TO_POINTER (GIMV_COM_DIR_VIEW));
2024 g_signal_connect (G_OBJECT (dv->container), "destroy",
2025 G_CALLBACK (cb_dirview_destroyed), dv);
2026
2027 g_signal_connect (G_OBJECT (dv->container), "drag_data_received",
2028 G_CALLBACK (cb_com_swap_drag_data_received), dv->tw);
2029
2030 /* toolbar */
2031 eventbox = dv->toolbar_eventbox = gtk_event_box_new ();
2032 gtk_container_set_border_width (GTK_CONTAINER (eventbox), 1);
2033 gtk_box_pack_start (GTK_BOX (dv->container), eventbox, FALSE, FALSE, 0);
2034 gtk_widget_show (eventbox);
2035
2036 dv->toolbar = dirview_create_toolbar (dv);
2037 gtk_container_add (GTK_CONTAINER (eventbox), dv->toolbar);
2038
2039 if (!dv->show_toolbar)
2040 gtk_widget_hide (dv->toolbar_eventbox);
2041
2042 dnd_src_set (eventbox, dnd_types_component, dnd_types_component_num);
2043 g_object_set_data (G_OBJECT (eventbox),
2044 "gimv-component",
2045 GINT_TO_POINTER (GIMV_COM_DIR_VIEW));
2046 g_signal_connect (G_OBJECT (eventbox), "drag_begin",
2047 G_CALLBACK (cb_toolbar_drag_begin), tw);
2048 g_signal_connect (G_OBJECT (eventbox), "drag_data_get",
2049 G_CALLBACK (cb_toolbar_drag_data_get), tw);
2050
2051 /* scrolled window */
2052 dv->scroll_win = gtk_scrolled_window_new (NULL, NULL);
2053 gtk_container_set_border_width (GTK_CONTAINER (dv->scroll_win), 1);
2054 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dv->scroll_win),
2055 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2056 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dv->scroll_win),
2057 GTK_SHADOW_IN);
2058 gtk_box_pack_start(GTK_BOX(dv->container), dv->scroll_win, TRUE, TRUE, 0);
2059 gtk_widget_show (dv->scroll_win);
2060
2061 /* ctree */
2062 dirview_create_treeview (dv, dv->root_dir);
2063
2064 return dv;
2065 }
2066
2067 #endif /* ENABLE_TREEVIEW */
2068