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