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