This source file includes following definitions.
- back_ptr
- forw_ptr
- remove_callback
- save_tree
- tree_remove_entry
- tree_destroy
- load_tree
- tree_show_mini_info
- show_tree
- tree_check_focus
- tree_move_backward
- tree_move_forward
- tree_move_to_child
- tree_move_to_parent
- tree_move_to_top
- tree_move_to_bottom
- tree_chdir_sel
- maybe_chdir
- search_tree
- tree_do_search
- tree_rescan
- tree_forget
- tree_copy
- tree_move
- tree_mkdir
- tree_rmdir
- tree_move_up
- tree_move_down
- tree_move_home
- tree_move_end
- tree_move_pgup
- tree_move_pgdn
- tree_move_left
- tree_move_right
- tree_start_search
- tree_toggle_navig
- tree_help
- tree_execute_cmd
- tree_key
- tree_frame
- tree_callback
- tree_mouse_callback
- tree_new
- tree_chdir
- tree_selected_name
- sync_tree
- find_tree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 #include <config.h>
40
41 #include <errno.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <sys/types.h>
45
46 #include "lib/global.h"
47
48 #include "lib/tty/tty.h"
49 #include "lib/tty/key.h"
50 #include "lib/skin.h"
51 #include "lib/vfs/vfs.h"
52 #include "lib/fileloc.h"
53 #include "lib/strutil.h"
54 #include "lib/util.h"
55 #include "lib/widget.h"
56 #include "lib/event.h"
57
58 #include "src/setup.h"
59 #include "src/keymap.h"
60 #include "src/history.h"
61 #include "src/util.h"
62
63 #include "dir.h"
64 #include "filemanager.h"
65 #include "file.h"
66 #include "treestore.h"
67 #include "cmd.h"
68 #include "filegui.h"
69 #include "cd.h"
70
71 #include "tree.h"
72
73
74
75
76 WTree *the_tree = NULL;
77
78
79
80
81
82 gboolean xtree_mode = FALSE;
83
84
85
86 #define tlines(t) \
87 (t->is_panel ? WIDGET (t)->rect.lines - 2 - (panels_options.show_mini_info ? 2 : 0) \
88 : WIDGET (t)->rect.lines)
89
90
91
92 struct WTree
93 {
94 Widget widget;
95 struct TreeStore *store;
96 tree_entry *selected_ptr;
97 GString *search_buffer;
98 tree_entry **tree_shown;
99 gboolean is_panel;
100 gboolean searching;
101 int topdiff;
102
103 };
104
105
106
107 static void tree_rescan (void *data);
108
109
110
111
112 static gboolean tree_navigation_flag = FALSE;
113
114
115
116
117
118 static tree_entry *
119 back_ptr (tree_entry *ptr, int *count)
120 {
121 int i;
122
123 for (i = 0; ptr != NULL && ptr->prev != NULL && i < *count; ptr = ptr->prev, i++)
124 ;
125
126 *count = i;
127 return ptr;
128 }
129
130
131
132 static tree_entry *
133 forw_ptr (tree_entry *ptr, int *count)
134 {
135 int i;
136
137 for (i = 0; ptr != NULL && ptr->next != NULL && i < *count; ptr = ptr->next, i++)
138 ;
139
140 *count = i;
141 return ptr;
142 }
143
144
145
146 static void
147 remove_callback (tree_entry *entry, void *data)
148 {
149 WTree *tree = data;
150
151 if (tree->selected_ptr == entry)
152 {
153 if (tree->selected_ptr->next != NULL)
154 tree->selected_ptr = tree->selected_ptr->next;
155 else
156 tree->selected_ptr = tree->selected_ptr->prev;
157 }
158 }
159
160
161
162
163 static void
164 save_tree (WTree *tree)
165 {
166 int error;
167
168 (void) tree;
169
170 error = tree_store_save ();
171 if (error != 0)
172 {
173 char *tree_name;
174
175 tree_name = mc_config_get_full_path (MC_TREESTORE_FILE);
176 fprintf (stderr, _ ("Cannot open the %s file for writing:\n%s\n"), tree_name,
177 unix_error_string (error));
178 g_free (tree_name);
179 }
180 }
181
182
183
184 static void
185 tree_remove_entry (WTree *tree, const vfs_path_t *name_vpath)
186 {
187 (void) tree;
188 tree_store_remove_entry (name_vpath);
189 }
190
191
192
193 static void
194 tree_destroy (WTree *tree)
195 {
196 tree_store_remove_entry_remove_hook (remove_callback);
197 save_tree (tree);
198
199 MC_PTR_FREE (tree->tree_shown);
200 g_string_free (tree->search_buffer, TRUE);
201 tree->selected_ptr = NULL;
202 }
203
204
205
206
207 static void
208 load_tree (WTree *tree)
209 {
210 vfs_path_t *vpath;
211
212 tree_store_load ();
213
214 tree->selected_ptr = tree->store->tree_first;
215 vpath = vfs_path_from_str (mc_config_get_home_dir ());
216 tree_chdir (tree, vpath);
217 vfs_path_free (vpath, TRUE);
218 }
219
220
221
222 static void
223 tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
224 {
225 Widget *w = WIDGET (tree);
226 int line;
227
228
229 if (tree->is_panel)
230 {
231 if (!panels_options.show_mini_info)
232 return;
233 line = tree_lines + 2;
234 }
235 else
236 line = tree_lines + 1;
237
238 if (tree->searching)
239 {
240
241 tty_setcolor (CORE_INPUT_COLOR);
242 tty_draw_hline (w->rect.y + line, w->rect.x + 1, ' ', tree_cols);
243 widget_gotoyx (w, line, 1);
244 tty_print_char (PATH_SEP);
245 tty_print_string (str_fit_to_term (tree->search_buffer->str, tree_cols - 2, J_LEFT_FIT));
246 tty_print_char (' ');
247 }
248 else
249 {
250
251
252 const int *colors;
253
254 colors = widget_get_colors (w);
255 tty_setcolor (tree->is_panel ? CORE_NORMAL_COLOR : colors[DLG_COLOR_NORMAL]);
256 tty_draw_hline (w->rect.y + line, w->rect.x + 1, ' ', tree_cols);
257 widget_gotoyx (w, line, 1);
258 tty_print_string (
259 str_fit_to_term (vfs_path_as_str (tree->selected_ptr->name), tree_cols, J_LEFT_FIT));
260 }
261 }
262
263
264
265 static void
266 show_tree (WTree *tree)
267 {
268 Widget *w = WIDGET (tree);
269 tree_entry *current;
270 int i, j;
271 int topsublevel = 0;
272 int x = 0, y = 0;
273 int tree_lines, tree_cols;
274
275
276 tree_lines = tlines (tree);
277 tree_cols = w->rect.cols;
278
279 widget_gotoyx (w, y, x);
280 if (tree->is_panel)
281 {
282 tree_cols -= 2;
283 x = y = 1;
284 }
285
286 g_free (tree->tree_shown);
287 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
288
289 if (tree->store->tree_first != NULL)
290 topsublevel = tree->store->tree_first->sublevel;
291
292 if (tree->selected_ptr == NULL)
293 {
294 tree->selected_ptr = tree->store->tree_first;
295 tree->topdiff = 0;
296 }
297 current = tree->selected_ptr;
298
299
300 if (!tree_navigation_flag)
301 current = back_ptr (current, &tree->topdiff);
302 else
303 {
304 i = 0;
305
306 while (current->prev != NULL && i < tree->topdiff)
307 {
308 current = current->prev;
309
310 if (current->sublevel < tree->selected_ptr->sublevel)
311 {
312 if (vfs_path_equal (current->name, tree->selected_ptr->name))
313 i++;
314 }
315 else if (current->sublevel == tree->selected_ptr->sublevel)
316 {
317 const char *cname;
318
319 cname = vfs_path_as_str (current->name);
320 for (j = strlen (cname) - 1; !IS_PATH_SEP (cname[j]); j--)
321 ;
322 if (vfs_path_equal_len (current->name, tree->selected_ptr->name, j))
323 i++;
324 }
325 else if (current->sublevel == tree->selected_ptr->sublevel + 1)
326 {
327 j = vfs_path_len (tree->selected_ptr->name);
328 if (j > 1 && vfs_path_equal_len (current->name, tree->selected_ptr->name, j))
329 i++;
330 }
331 }
332 tree->topdiff = i;
333 }
334
335
336 for (i = 0; i < tree_lines; i++)
337 {
338 const int *colors;
339
340 colors = widget_get_colors (w);
341 tty_setcolor (tree->is_panel ? CORE_NORMAL_COLOR : colors[DLG_COLOR_NORMAL]);
342
343
344 tty_draw_hline (w->rect.y + y + i, w->rect.x + x, ' ', tree_cols);
345
346 if (current == NULL)
347 continue;
348
349 if (tree->is_panel)
350 {
351 gboolean selected;
352
353 selected = widget_get_state (w, WST_FOCUSED) && current == tree->selected_ptr;
354 tty_setcolor (selected ? CORE_SELECTED_COLOR : CORE_NORMAL_COLOR);
355 }
356 else
357 {
358 int idx = current == tree->selected_ptr ? DLG_COLOR_FOCUS : DLG_COLOR_NORMAL;
359
360 tty_setcolor (colors[idx]);
361 }
362
363 tree->tree_shown[i] = current;
364 if (current->sublevel == topsublevel)
365
366 tty_print_string (str_fit_to_term (vfs_path_as_str (current->name),
367 tree_cols + (tree->is_panel ? 0 : 1), J_LEFT_FIT));
368 else
369 {
370
371 for (j = 0; j < current->sublevel - topsublevel - 1; j++)
372 {
373 if (tree_cols - 8 - 3 * j < 9)
374 break;
375 tty_print_char (' ');
376 if ((current->submask & (1 << (j + topsublevel + 1))) != 0)
377 tty_print_char (mc_tty_frm[MC_TTY_FRM_VERT]);
378 else
379 tty_print_char (' ');
380 tty_print_char (' ');
381 }
382 tty_print_char (' ');
383 j++;
384 if (current->next == NULL || (current->next->submask & (1 << current->sublevel)) == 0)
385 tty_print_char (mc_tty_frm[MC_TTY_FRM_LEFTBOTTOM]);
386 else
387 tty_print_char (mc_tty_frm[MC_TTY_FRM_LEFTMIDDLE]);
388 tty_print_char (mc_tty_frm[MC_TTY_FRM_HORIZ]);
389
390
391 tty_print_char (' ');
392 tty_print_string (
393 str_fit_to_term (current->subname, tree_cols - x - 3 * j, J_LEFT_FIT));
394 }
395
396
397 current = current->next;
398 if (tree_navigation_flag)
399 for (; current != NULL; current = current->next)
400 {
401 if (current->sublevel < tree->selected_ptr->sublevel)
402 {
403 if (vfs_path_equal_len (current->name, tree->selected_ptr->name,
404 vfs_path_len (current->name)))
405 break;
406 }
407 else if (current->sublevel == tree->selected_ptr->sublevel)
408 {
409 const char *cname;
410
411 cname = vfs_path_as_str (current->name);
412 for (j = strlen (cname) - 1; !IS_PATH_SEP (cname[j]); j--)
413 ;
414 if (vfs_path_equal_len (current->name, tree->selected_ptr->name, j))
415 break;
416 }
417 else if (current->sublevel == tree->selected_ptr->sublevel + 1
418 && vfs_path_len (tree->selected_ptr->name) > 1)
419 {
420 if (vfs_path_equal_len (current->name, tree->selected_ptr->name,
421 vfs_path_len (tree->selected_ptr->name)))
422 break;
423 }
424 }
425 }
426
427 tree_show_mini_info (tree, tree_lines, tree_cols);
428 }
429
430
431
432 static void
433 tree_check_focus (WTree *tree)
434 {
435 if (tree->topdiff < 3)
436 tree->topdiff = 3;
437 else if (tree->topdiff >= tlines (tree) - 3)
438 tree->topdiff = tlines (tree) - 3 - 1;
439 }
440
441
442
443 static void
444 tree_move_backward (WTree *tree, int i)
445 {
446 if (!tree_navigation_flag)
447 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
448 else
449 {
450 tree_entry *current;
451 int j = 0;
452
453 current = tree->selected_ptr;
454 while (j < i && current->prev != NULL
455 && current->prev->sublevel >= tree->selected_ptr->sublevel)
456 {
457 current = current->prev;
458 if (current->sublevel == tree->selected_ptr->sublevel)
459 {
460 tree->selected_ptr = current;
461 j++;
462 }
463 }
464 i = j;
465 }
466
467 tree->topdiff -= i;
468 tree_check_focus (tree);
469 }
470
471
472
473 static void
474 tree_move_forward (WTree *tree, int i)
475 {
476 if (!tree_navigation_flag)
477 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
478 else
479 {
480 tree_entry *current;
481 int j = 0;
482
483 current = tree->selected_ptr;
484 while (j < i && current->next != NULL
485 && current->next->sublevel >= tree->selected_ptr->sublevel)
486 {
487 current = current->next;
488 if (current->sublevel == tree->selected_ptr->sublevel)
489 {
490 tree->selected_ptr = current;
491 j++;
492 }
493 }
494 i = j;
495 }
496
497 tree->topdiff += i;
498 tree_check_focus (tree);
499 }
500
501
502
503 static void
504 tree_move_to_child (WTree *tree)
505 {
506 tree_entry *current;
507
508
509 if (tree->selected_ptr == NULL)
510 return;
511
512
513 current = tree->selected_ptr->next;
514
515 if (current != NULL && current->sublevel > tree->selected_ptr->sublevel)
516 {
517
518 tree->selected_ptr = current;
519 tree->topdiff++;
520 tree_check_focus (tree);
521 }
522 else
523 {
524
525 tree_rescan (tree);
526 current = tree->selected_ptr->next;
527 if (current != NULL && current->sublevel > tree->selected_ptr->sublevel)
528 {
529 tree->selected_ptr = current;
530 tree->topdiff++;
531 tree_check_focus (tree);
532 }
533 }
534 }
535
536
537
538 static gboolean
539 tree_move_to_parent (WTree *tree)
540 {
541 tree_entry *current;
542 tree_entry *old;
543
544 if (tree->selected_ptr == NULL)
545 return FALSE;
546
547 old = tree->selected_ptr;
548
549 for (current = tree->selected_ptr->prev;
550 current != NULL && current->sublevel >= tree->selected_ptr->sublevel;
551 current = current->prev)
552 tree->topdiff--;
553
554 if (current == NULL)
555 current = tree->store->tree_first;
556 tree->selected_ptr = current;
557 tree_check_focus (tree);
558 return tree->selected_ptr != old;
559 }
560
561
562
563 static void
564 tree_move_to_top (WTree *tree)
565 {
566 tree->selected_ptr = tree->store->tree_first;
567 tree->topdiff = 0;
568 }
569
570
571
572 static void
573 tree_move_to_bottom (WTree *tree)
574 {
575 tree->selected_ptr = tree->store->tree_last;
576 tree->topdiff = tlines (tree) - 3 - 1;
577 }
578
579
580
581 static void
582 tree_chdir_sel (WTree *tree)
583 {
584 if (tree->is_panel)
585 {
586 WPanel *p;
587
588 p = change_panel ();
589
590 if (panel_cd (p, tree->selected_ptr->name, cd_exact))
591 select_item (p);
592 else
593 cd_error_message (vfs_path_as_str (tree->selected_ptr->name));
594
595 widget_draw (WIDGET (p));
596 (void) change_panel ();
597 show_tree (tree);
598 }
599 else
600 {
601 WDialog *h = DIALOG (WIDGET (tree)->owner);
602
603 h->ret_value = B_ENTER;
604 dlg_close (h);
605 }
606 }
607
608
609
610 static void
611 maybe_chdir (WTree *tree)
612 {
613 if (xtree_mode && tree->is_panel && is_idle ())
614 tree_chdir_sel (tree);
615 }
616
617
618
619
620 static gboolean
621 search_tree (WTree *tree, const GString *text)
622 {
623 tree_entry *current = tree->selected_ptr;
624 gboolean wrapped = FALSE;
625 gboolean found = FALSE;
626
627 while (!found && (!wrapped || current != tree->selected_ptr))
628 if (strncmp (current->subname, text->str, text->len) == 0)
629 {
630 tree->selected_ptr = current;
631 found = TRUE;
632 }
633 else
634 {
635 current = current->next;
636 if (current == NULL)
637 {
638 current = tree->store->tree_first;
639 wrapped = TRUE;
640 }
641
642 tree->topdiff++;
643 }
644
645 tree_check_focus (tree);
646 return found;
647 }
648
649
650
651 static void
652 tree_do_search (WTree *tree, int key)
653 {
654
655
656 if (tree->search_buffer->len != 0 && key == KEY_BACKSPACE)
657 g_string_set_size (tree->search_buffer, tree->search_buffer->len - 1);
658 else if (key != 0)
659 g_string_append_c (tree->search_buffer, (gchar) key);
660
661 if (!search_tree (tree, tree->search_buffer))
662 g_string_set_size (tree->search_buffer, tree->search_buffer->len - 1);
663
664 show_tree (tree);
665 maybe_chdir (tree);
666 }
667
668
669
670 static void
671 tree_rescan (void *data)
672 {
673 WTree *tree = data;
674 vfs_path_t *old_vpath;
675
676 old_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
677 if (old_vpath == NULL)
678 return;
679
680 if (tree->selected_ptr != NULL && mc_chdir (tree->selected_ptr->name) == 0)
681 {
682 int ret;
683
684 tree_store_rescan (tree->selected_ptr->name);
685 ret = mc_chdir (old_vpath);
686 (void) ret;
687 }
688 vfs_path_free (old_vpath, TRUE);
689 }
690
691
692
693 static void
694 tree_forget (void *data)
695 {
696 WTree *tree = data;
697
698 if (tree->selected_ptr != NULL)
699 tree_remove_entry (tree, tree->selected_ptr->name);
700 }
701
702
703
704 static void
705 tree_copy (WTree *tree, const char *default_dest)
706 {
707 char msg[BUF_MEDIUM];
708 char *dest;
709
710 if (tree->selected_ptr == NULL)
711 return;
712
713 g_snprintf (msg, sizeof (msg), _ ("Copy \"%s\" directory to:"),
714 str_trunc (vfs_path_as_str (tree->selected_ptr->name), 50));
715 dest = input_expand_dialog (Q_ ("DialogTitle|Copy"), msg, MC_HISTORY_FM_TREE_COPY, default_dest,
716 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
717
718 if (dest != NULL && *dest != '\0')
719 {
720 file_op_context_t *ctx;
721
722 ctx = file_op_context_new (OP_COPY);
723 file_progress_ui_create (ctx, FALSE, FILEGUI_DIALOG_MULTI_ITEM);
724 ctx->ask_overwrite = FALSE;
725 copy_dir_dir (ctx, vfs_path_as_str (tree->selected_ptr->name), dest, TRUE, FALSE, FALSE,
726 NULL);
727 file_op_context_destroy (ctx);
728 }
729
730 g_free (dest);
731 }
732
733
734
735 static void
736 tree_move (WTree *tree, const char *default_dest)
737 {
738 char msg[BUF_MEDIUM];
739 char *dest;
740
741 if (tree->selected_ptr == NULL)
742 return;
743
744 g_snprintf (msg, sizeof (msg), _ ("Move \"%s\" directory to:"),
745 str_trunc (vfs_path_as_str (tree->selected_ptr->name), 50));
746 dest = input_expand_dialog (Q_ ("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest,
747 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
748
749 if (dest != NULL && *dest != '\0')
750 {
751 vfs_path_t *dest_vpath;
752 struct stat buf;
753
754 dest_vpath = vfs_path_from_str (dest);
755
756 if (mc_stat (dest_vpath, &buf) != 0)
757 file_error_message (_ ("Cannot stat the destination\n%s"), dest);
758 else if (!S_ISDIR (buf.st_mode))
759 {
760 errno = ENOTDIR;
761 file_error_message (_ ("Destination\n%s\nmust be a directory"), dest);
762 }
763 else
764 {
765 file_op_context_t *ctx;
766
767 ctx = file_op_context_new (OP_MOVE);
768 file_progress_ui_create (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
769 move_dir_dir (ctx, vfs_path_as_str (tree->selected_ptr->name), dest);
770 file_op_context_destroy (ctx);
771 }
772
773 vfs_path_free (dest_vpath, TRUE);
774 }
775
776 g_free (dest);
777 }
778
779
780
781 #if 0
782 static void
783 tree_mkdir (WTree *tree)
784 {
785 char old_dir[MC_MAXPATHLEN];
786
787 if (tree->selected_ptr == NULL || chdir (tree->selected_ptr->name) != 0)
788 return;
789
790
791
792 tree_rescan (tree);
793 chdir (old_dir);
794 }
795 #endif
796
797
798
799 static void
800 tree_rmdir (void *data)
801 {
802 WTree *tree = data;
803 file_op_context_t *ctx;
804
805 if (tree->selected_ptr == NULL)
806 return;
807
808 if (confirm_delete)
809 {
810 char *buf;
811 int result;
812
813 buf = g_strdup_printf (_ ("Delete %s?"), vfs_path_as_str (tree->selected_ptr->name));
814
815 result = query_dialog (Q_ ("DialogTitle|Delete"), buf, D_ERROR, 2, _ ("&Yes"), _ ("&No"));
816 g_free (buf);
817 if (result != 0)
818 return;
819 }
820
821 ctx = file_op_context_new (OP_DELETE);
822 file_progress_ui_create (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
823 if (erase_dir (ctx, tree->selected_ptr->name) == FILE_CONT)
824 tree_forget (tree);
825 file_op_context_destroy (ctx);
826 }
827
828
829
830 static inline void
831 tree_move_up (WTree *tree)
832 {
833 tree_move_backward (tree, 1);
834 show_tree (tree);
835 maybe_chdir (tree);
836 }
837
838
839
840 static inline void
841 tree_move_down (WTree *tree)
842 {
843 tree_move_forward (tree, 1);
844 show_tree (tree);
845 maybe_chdir (tree);
846 }
847
848
849
850 static inline void
851 tree_move_home (WTree *tree)
852 {
853 tree_move_to_top (tree);
854 show_tree (tree);
855 maybe_chdir (tree);
856 }
857
858
859
860 static inline void
861 tree_move_end (WTree *tree)
862 {
863 tree_move_to_bottom (tree);
864 show_tree (tree);
865 maybe_chdir (tree);
866 }
867
868
869
870 static void
871 tree_move_pgup (WTree *tree)
872 {
873 tree_move_backward (tree, tlines (tree) - 1);
874 show_tree (tree);
875 maybe_chdir (tree);
876 }
877
878
879
880 static void
881 tree_move_pgdn (WTree *tree)
882 {
883 tree_move_forward (tree, tlines (tree) - 1);
884 show_tree (tree);
885 maybe_chdir (tree);
886 }
887
888
889
890 static gboolean
891 tree_move_left (WTree *tree)
892 {
893 gboolean v = FALSE;
894
895 if (tree_navigation_flag)
896 {
897 v = tree_move_to_parent (tree);
898 show_tree (tree);
899 maybe_chdir (tree);
900 }
901
902 return v;
903 }
904
905
906
907 static gboolean
908 tree_move_right (WTree *tree)
909 {
910 gboolean v = FALSE;
911
912 if (tree_navigation_flag)
913 {
914 tree_move_to_child (tree);
915 show_tree (tree);
916 maybe_chdir (tree);
917 v = TRUE;
918 }
919
920 return v;
921 }
922
923
924
925 static void
926 tree_start_search (WTree *tree)
927 {
928 if (tree->searching)
929 {
930 if (tree->selected_ptr == tree->store->tree_last)
931 tree_move_to_top (tree);
932 else
933 {
934 gboolean i;
935
936
937
938
939
940
941 i = tree_navigation_flag;
942 tree_navigation_flag = FALSE;
943 tree_move_forward (tree, 1);
944 tree_navigation_flag = i;
945 }
946 tree_do_search (tree, 0);
947 }
948 else
949 {
950 tree->searching = TRUE;
951 g_string_set_size (tree->search_buffer, 0);
952 }
953 }
954
955
956
957 static void
958 tree_toggle_navig (WTree *tree)
959 {
960 Widget *w = WIDGET (tree);
961 WButtonBar *b;
962
963 tree_navigation_flag = !tree_navigation_flag;
964
965 b = buttonbar_find (DIALOG (w->owner));
966 buttonbar_set_label (b, 4,
967 tree_navigation_flag ? Q_ ("ButtonBar|Static") : Q_ ("ButtonBar|Dynamc"),
968 w->keymap, w);
969 widget_draw (WIDGET (b));
970 }
971
972
973
974 static void
975 tree_help (void)
976 {
977 ev_help_t event_data = { NULL, "[Directory Tree]" };
978
979 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
980 }
981
982
983
984 static cb_ret_t
985 tree_execute_cmd (WTree *tree, long command)
986 {
987 cb_ret_t res = MSG_HANDLED;
988
989 if (command != CK_Search)
990 tree->searching = FALSE;
991
992 switch (command)
993 {
994 case CK_Help:
995 tree_help ();
996 break;
997 case CK_Forget:
998 tree_forget (tree);
999 break;
1000 case CK_ToggleNavigation:
1001 tree_toggle_navig (tree);
1002 break;
1003 case CK_Copy:
1004 tree_copy (tree, "");
1005 break;
1006 case CK_Move:
1007 tree_move (tree, "");
1008 break;
1009 case CK_Up:
1010 tree_move_up (tree);
1011 break;
1012 case CK_Down:
1013 tree_move_down (tree);
1014 break;
1015 case CK_Top:
1016 tree_move_home (tree);
1017 break;
1018 case CK_Bottom:
1019 tree_move_end (tree);
1020 break;
1021 case CK_PageUp:
1022 tree_move_pgup (tree);
1023 break;
1024 case CK_PageDown:
1025 tree_move_pgdn (tree);
1026 break;
1027 case CK_Enter:
1028 tree_chdir_sel (tree);
1029 break;
1030 case CK_Reread:
1031 tree_rescan (tree);
1032 break;
1033 case CK_Search:
1034 tree_start_search (tree);
1035 break;
1036 case CK_Delete:
1037 tree_rmdir (tree);
1038 break;
1039 case CK_Quit:
1040 if (!tree->is_panel)
1041 dlg_close (DIALOG (WIDGET (tree)->owner));
1042 return res;
1043 default:
1044 res = MSG_NOT_HANDLED;
1045 }
1046
1047 show_tree (tree);
1048
1049 return res;
1050 }
1051
1052
1053
1054 static cb_ret_t
1055 tree_key (WTree *tree, int key)
1056 {
1057 long command;
1058
1059 if (is_abort_char (key))
1060 {
1061 if (tree->is_panel)
1062 {
1063 tree->searching = FALSE;
1064 show_tree (tree);
1065 return MSG_HANDLED;
1066 }
1067
1068
1069 return MSG_NOT_HANDLED;
1070 }
1071
1072 if (tree->searching && ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE))
1073 {
1074 tree_do_search (tree, key);
1075 show_tree (tree);
1076 return MSG_HANDLED;
1077 }
1078
1079 command = widget_lookup_key (WIDGET (tree), key);
1080 switch (command)
1081 {
1082 case CK_IgnoreKey:
1083 break;
1084 case CK_Left:
1085 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1086 case CK_Right:
1087 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1088 default:
1089 tree_execute_cmd (tree, command);
1090 return MSG_HANDLED;
1091 }
1092
1093
1094 if (!mc_global.cmdline_visible && ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE))
1095 {
1096 tree_start_search (tree);
1097 tree_do_search (tree, key);
1098 return MSG_HANDLED;
1099 }
1100
1101 return MSG_NOT_HANDLED;
1102 }
1103
1104
1105
1106 static void
1107 tree_frame (WDialog *h, WTree *tree)
1108 {
1109 Widget *w = WIDGET (tree);
1110
1111 (void) h;
1112
1113 tty_setcolor (CORE_NORMAL_COLOR);
1114 widget_erase (w);
1115 if (tree->is_panel)
1116 {
1117 const char *title = _ ("Directory tree");
1118 const int len = str_term_width1 (title);
1119
1120 tty_setcolor (CORE_FRAME_COLOR);
1121 tty_draw_box (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, FALSE);
1122
1123 if (panels_options.show_mini_info)
1124 {
1125 int y;
1126
1127 y = w->rect.lines - 3;
1128 widget_gotoyx (w, y, 0);
1129 tty_print_char (mc_tty_frm[MC_TTY_FRM_DLEFTMIDDLE]);
1130 widget_gotoyx (w, y, w->rect.cols - 1);
1131 tty_print_char (mc_tty_frm[MC_TTY_FRM_DRIGHTMIDDLE]);
1132 tty_draw_hline (w->rect.y + y, w->rect.x + 1, mc_tty_frm[MC_TTY_FRM_HORIZ],
1133 w->rect.cols - 2);
1134 }
1135
1136 const gboolean focused = widget_get_state (w, WST_FOCUSED);
1137
1138 tty_setcolor (focused ? CORE_REVERSE_COLOR : CORE_NORMAL_COLOR);
1139 widget_gotoyx (w, 0, (w->rect.cols - len - 2) / 2);
1140 tty_printf (" %s ", title);
1141 }
1142 }
1143
1144
1145
1146 static cb_ret_t
1147 tree_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
1148 {
1149 WTree *tree = (WTree *) w;
1150 WDialog *h = DIALOG (w->owner);
1151 WButtonBar *b;
1152
1153 switch (msg)
1154 {
1155 case MSG_DRAW:
1156 tree_frame (h, tree);
1157 show_tree (tree);
1158 if (widget_get_state (w, WST_FOCUSED))
1159 {
1160 b = buttonbar_find (h);
1161 widget_draw (WIDGET (b));
1162 }
1163 return MSG_HANDLED;
1164
1165 case MSG_FOCUS:
1166 b = buttonbar_find (h);
1167 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), w->keymap, w);
1168 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Rescan"), w->keymap, w);
1169 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Forget"), w->keymap, w);
1170 buttonbar_set_label (
1171 b, 4, tree_navigation_flag ? Q_ ("ButtonBar|Static") : Q_ ("ButtonBar|Dynamc"),
1172 w->keymap, w);
1173 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Copy"), w->keymap, w);
1174 buttonbar_set_label (b, 6, Q_ ("ButtonBar|RenMov"), w->keymap, w);
1175 #if 0
1176
1177 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), w->keymap, w);
1178 #else
1179 buttonbar_clear_label (b, 7, w);
1180 #endif
1181 buttonbar_set_label (b, 8, Q_ ("ButtonBar|Rmdir"), w->keymap, w);
1182
1183 return MSG_HANDLED;
1184
1185 case MSG_UNFOCUS:
1186 tree->searching = FALSE;
1187 return MSG_HANDLED;
1188
1189 case MSG_KEY:
1190 return tree_key (tree, parm);
1191
1192 case MSG_ACTION:
1193
1194 return tree_execute_cmd (tree, parm);
1195
1196 case MSG_DESTROY:
1197 tree_destroy (tree);
1198 return MSG_HANDLED;
1199
1200 default:
1201 return widget_default_callback (w, sender, msg, parm, data);
1202 }
1203 }
1204
1205
1206
1207
1208
1209
1210 static void
1211 tree_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event)
1212 {
1213 WTree *tree = (WTree *) w;
1214 int y;
1215
1216 y = event->y;
1217 if (tree->is_panel)
1218 y--;
1219
1220 switch (msg)
1221 {
1222 case MSG_MOUSE_DOWN:
1223
1224 if (tree->is_panel && event->y == WIDGET (w->owner)->rect.y)
1225 {
1226
1227 event->result.abort = TRUE;
1228 }
1229 else if (!widget_get_state (w, WST_FOCUSED))
1230 (void) change_panel ();
1231 break;
1232
1233 case MSG_MOUSE_CLICK:
1234 {
1235 int lines;
1236
1237 lines = tlines (tree);
1238
1239 if (y < 0)
1240 {
1241 tree_move_backward (tree, lines - 1);
1242 show_tree (tree);
1243 }
1244 else if (y >= lines)
1245 {
1246 tree_move_forward (tree, lines - 1);
1247 show_tree (tree);
1248 }
1249 else if ((event->count & GPM_DOUBLE) != 0)
1250 {
1251 if (tree->tree_shown[y] != NULL)
1252 {
1253 tree->selected_ptr = tree->tree_shown[y];
1254 tree->topdiff = y;
1255 }
1256
1257 tree_chdir_sel (tree);
1258 }
1259 }
1260 break;
1261
1262 case MSG_MOUSE_SCROLL_UP:
1263 case MSG_MOUSE_SCROLL_DOWN:
1264
1265 break;
1266
1267 default:
1268 break;
1269 }
1270 }
1271
1272
1273
1274
1275
1276 WTree *
1277 tree_new (const WRect *r, gboolean is_panel)
1278 {
1279 WTree *tree;
1280 Widget *w;
1281
1282 tree = g_new (WTree, 1);
1283
1284 w = WIDGET (tree);
1285 widget_init (w, r, tree_callback, tree_mouse_callback);
1286 w->options |= WOP_SELECTABLE | WOP_TOP_SELECT;
1287 w->keymap = tree_map;
1288
1289 tree->is_panel = is_panel;
1290 tree->selected_ptr = NULL;
1291
1292 tree->store = tree_store_get ();
1293 tree_store_add_entry_remove_hook (remove_callback, tree);
1294 tree->tree_shown = NULL;
1295 tree->search_buffer = g_string_sized_new (MC_MAXPATHLEN);
1296 tree->topdiff = w->rect.lines / 2;
1297 tree->searching = FALSE;
1298
1299 load_tree (tree);
1300 return tree;
1301 }
1302
1303
1304
1305 void
1306 tree_chdir (WTree *tree, const vfs_path_t *dir)
1307 {
1308 tree_entry *current;
1309
1310 current = tree_store_whereis (dir);
1311 if (current != NULL)
1312 {
1313 tree->selected_ptr = current;
1314 tree_check_focus (tree);
1315 }
1316 }
1317
1318
1319
1320
1321 const vfs_path_t *
1322 tree_selected_name (const WTree *tree)
1323 {
1324 return tree->selected_ptr->name;
1325 }
1326
1327
1328
1329 void
1330 sync_tree (const vfs_path_t *vpath)
1331 {
1332 tree_chdir (the_tree, vpath);
1333 }
1334
1335
1336
1337 WTree *
1338 find_tree (const WDialog *h)
1339 {
1340 return (WTree *) widget_find_by_type (CONST_WIDGET (h), tree_callback);
1341 }
1342
1343