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 tty_set_alt_charset (TRUE);
373
374
375 for (j = 0; j < current->sublevel - topsublevel - 1; j++)
376 {
377 if (tree_cols - 8 - 3 * j < 9)
378 break;
379 tty_print_char (' ');
380 if ((current->submask & (1 << (j + topsublevel + 1))) != 0)
381 tty_print_char (ACS_VLINE);
382 else
383 tty_print_char (' ');
384 tty_print_char (' ');
385 }
386 tty_print_char (' ');
387 j++;
388 if (current->next == NULL || (current->next->submask & (1 << current->sublevel)) == 0)
389 tty_print_char (ACS_LLCORNER);
390 else
391 tty_print_char (ACS_LTEE);
392 tty_print_char (ACS_HLINE);
393 tty_set_alt_charset (FALSE);
394
395
396 tty_print_char (' ');
397 tty_print_string (
398 str_fit_to_term (current->subname, tree_cols - x - 3 * j, J_LEFT_FIT));
399 }
400
401
402 current = current->next;
403 if (tree_navigation_flag)
404 for (; current != NULL; current = current->next)
405 {
406 if (current->sublevel < tree->selected_ptr->sublevel)
407 {
408 if (vfs_path_equal_len (current->name, tree->selected_ptr->name,
409 vfs_path_len (current->name)))
410 break;
411 }
412 else if (current->sublevel == tree->selected_ptr->sublevel)
413 {
414 const char *cname;
415
416 cname = vfs_path_as_str (current->name);
417 for (j = strlen (cname) - 1; !IS_PATH_SEP (cname[j]); j--)
418 ;
419 if (vfs_path_equal_len (current->name, tree->selected_ptr->name, j))
420 break;
421 }
422 else if (current->sublevel == tree->selected_ptr->sublevel + 1
423 && vfs_path_len (tree->selected_ptr->name) > 1)
424 {
425 if (vfs_path_equal_len (current->name, tree->selected_ptr->name,
426 vfs_path_len (tree->selected_ptr->name)))
427 break;
428 }
429 }
430 }
431
432 tree_show_mini_info (tree, tree_lines, tree_cols);
433 }
434
435
436
437 static void
438 tree_check_focus (WTree *tree)
439 {
440 if (tree->topdiff < 3)
441 tree->topdiff = 3;
442 else if (tree->topdiff >= tlines (tree) - 3)
443 tree->topdiff = tlines (tree) - 3 - 1;
444 }
445
446
447
448 static void
449 tree_move_backward (WTree *tree, int i)
450 {
451 if (!tree_navigation_flag)
452 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
453 else
454 {
455 tree_entry *current;
456 int j = 0;
457
458 current = tree->selected_ptr;
459 while (j < i && current->prev != NULL
460 && current->prev->sublevel >= tree->selected_ptr->sublevel)
461 {
462 current = current->prev;
463 if (current->sublevel == tree->selected_ptr->sublevel)
464 {
465 tree->selected_ptr = current;
466 j++;
467 }
468 }
469 i = j;
470 }
471
472 tree->topdiff -= i;
473 tree_check_focus (tree);
474 }
475
476
477
478 static void
479 tree_move_forward (WTree *tree, int i)
480 {
481 if (!tree_navigation_flag)
482 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
483 else
484 {
485 tree_entry *current;
486 int j = 0;
487
488 current = tree->selected_ptr;
489 while (j < i && current->next != NULL
490 && current->next->sublevel >= tree->selected_ptr->sublevel)
491 {
492 current = current->next;
493 if (current->sublevel == tree->selected_ptr->sublevel)
494 {
495 tree->selected_ptr = current;
496 j++;
497 }
498 }
499 i = j;
500 }
501
502 tree->topdiff += i;
503 tree_check_focus (tree);
504 }
505
506
507
508 static void
509 tree_move_to_child (WTree *tree)
510 {
511 tree_entry *current;
512
513
514 if (tree->selected_ptr == NULL)
515 return;
516
517
518 current = tree->selected_ptr->next;
519
520 if (current != NULL && current->sublevel > tree->selected_ptr->sublevel)
521 {
522
523 tree->selected_ptr = current;
524 tree->topdiff++;
525 tree_check_focus (tree);
526 }
527 else
528 {
529
530 tree_rescan (tree);
531 current = tree->selected_ptr->next;
532 if (current != NULL && current->sublevel > tree->selected_ptr->sublevel)
533 {
534 tree->selected_ptr = current;
535 tree->topdiff++;
536 tree_check_focus (tree);
537 }
538 }
539 }
540
541
542
543 static gboolean
544 tree_move_to_parent (WTree *tree)
545 {
546 tree_entry *current;
547 tree_entry *old;
548
549 if (tree->selected_ptr == NULL)
550 return FALSE;
551
552 old = tree->selected_ptr;
553
554 for (current = tree->selected_ptr->prev;
555 current != NULL && current->sublevel >= tree->selected_ptr->sublevel;
556 current = current->prev)
557 tree->topdiff--;
558
559 if (current == NULL)
560 current = tree->store->tree_first;
561 tree->selected_ptr = current;
562 tree_check_focus (tree);
563 return tree->selected_ptr != old;
564 }
565
566
567
568 static void
569 tree_move_to_top (WTree *tree)
570 {
571 tree->selected_ptr = tree->store->tree_first;
572 tree->topdiff = 0;
573 }
574
575
576
577 static void
578 tree_move_to_bottom (WTree *tree)
579 {
580 tree->selected_ptr = tree->store->tree_last;
581 tree->topdiff = tlines (tree) - 3 - 1;
582 }
583
584
585
586 static void
587 tree_chdir_sel (WTree *tree)
588 {
589 if (tree->is_panel)
590 {
591 WPanel *p;
592
593 p = change_panel ();
594
595 if (panel_cd (p, tree->selected_ptr->name, cd_exact))
596 select_item (p);
597 else
598 cd_error_message (vfs_path_as_str (tree->selected_ptr->name));
599
600 widget_draw (WIDGET (p));
601 (void) change_panel ();
602 show_tree (tree);
603 }
604 else
605 {
606 WDialog *h = DIALOG (WIDGET (tree)->owner);
607
608 h->ret_value = B_ENTER;
609 dlg_close (h);
610 }
611 }
612
613
614
615 static void
616 maybe_chdir (WTree *tree)
617 {
618 if (xtree_mode && tree->is_panel && is_idle ())
619 tree_chdir_sel (tree);
620 }
621
622
623
624
625 static gboolean
626 search_tree (WTree *tree, const GString *text)
627 {
628 tree_entry *current = tree->selected_ptr;
629 gboolean wrapped = FALSE;
630 gboolean found = FALSE;
631
632 while (!found && (!wrapped || current != tree->selected_ptr))
633 if (strncmp (current->subname, text->str, text->len) == 0)
634 {
635 tree->selected_ptr = current;
636 found = TRUE;
637 }
638 else
639 {
640 current = current->next;
641 if (current == NULL)
642 {
643 current = tree->store->tree_first;
644 wrapped = TRUE;
645 }
646
647 tree->topdiff++;
648 }
649
650 tree_check_focus (tree);
651 return found;
652 }
653
654
655
656 static void
657 tree_do_search (WTree *tree, int key)
658 {
659
660
661 if (tree->search_buffer->len != 0 && key == KEY_BACKSPACE)
662 g_string_set_size (tree->search_buffer, tree->search_buffer->len - 1);
663 else if (key != 0)
664 g_string_append_c (tree->search_buffer, (gchar) key);
665
666 if (!search_tree (tree, tree->search_buffer))
667 g_string_set_size (tree->search_buffer, tree->search_buffer->len - 1);
668
669 show_tree (tree);
670 maybe_chdir (tree);
671 }
672
673
674
675 static void
676 tree_rescan (void *data)
677 {
678 WTree *tree = data;
679 vfs_path_t *old_vpath;
680
681 old_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
682 if (old_vpath == NULL)
683 return;
684
685 if (tree->selected_ptr != NULL && mc_chdir (tree->selected_ptr->name) == 0)
686 {
687 int ret;
688
689 tree_store_rescan (tree->selected_ptr->name);
690 ret = mc_chdir (old_vpath);
691 (void) ret;
692 }
693 vfs_path_free (old_vpath, TRUE);
694 }
695
696
697
698 static void
699 tree_forget (void *data)
700 {
701 WTree *tree = data;
702
703 if (tree->selected_ptr != NULL)
704 tree_remove_entry (tree, tree->selected_ptr->name);
705 }
706
707
708
709 static void
710 tree_copy (WTree *tree, const char *default_dest)
711 {
712 char msg[BUF_MEDIUM];
713 char *dest;
714
715 if (tree->selected_ptr == NULL)
716 return;
717
718 g_snprintf (msg, sizeof (msg), _ ("Copy \"%s\" directory to:"),
719 str_trunc (vfs_path_as_str (tree->selected_ptr->name), 50));
720 dest = input_expand_dialog (Q_ ("DialogTitle|Copy"), 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 = input_expand_dialog (Q_ ("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest,
752 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
753
754 if (dest != NULL && *dest != '\0')
755 {
756 vfs_path_t *dest_vpath;
757 struct stat buf;
758
759 dest_vpath = vfs_path_from_str (dest);
760
761 if (mc_stat (dest_vpath, &buf) != 0)
762 file_error_message (_ ("Cannot stat the destination\n%s"), dest);
763 else if (!S_ISDIR (buf.st_mode))
764 {
765 errno = ENOTDIR;
766 file_error_message (_ ("Destination\n%s\nmust be a directory"), dest);
767 }
768 else
769 {
770 file_op_context_t *ctx;
771
772 ctx = file_op_context_new (OP_MOVE);
773 file_progress_ui_create (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
774 move_dir_dir (ctx, vfs_path_as_str (tree->selected_ptr->name), dest);
775 file_op_context_destroy (ctx);
776 }
777
778 vfs_path_free (dest_vpath, TRUE);
779 }
780
781 g_free (dest);
782 }
783
784
785
786 #if 0
787 static void
788 tree_mkdir (WTree *tree)
789 {
790 char old_dir[MC_MAXPATHLEN];
791
792 if (tree->selected_ptr == NULL || chdir (tree->selected_ptr->name) != 0)
793 return;
794
795
796
797 tree_rescan (tree);
798 chdir (old_dir);
799 }
800 #endif
801
802
803
804 static void
805 tree_rmdir (void *data)
806 {
807 WTree *tree = data;
808 file_op_context_t *ctx;
809
810 if (tree->selected_ptr == NULL)
811 return;
812
813 if (confirm_delete)
814 {
815 char *buf;
816 int result;
817
818 buf = g_strdup_printf (_ ("Delete %s?"), vfs_path_as_str (tree->selected_ptr->name));
819
820 result = query_dialog (Q_ ("DialogTitle|Delete"), buf, D_ERROR, 2, _ ("&Yes"), _ ("&No"));
821 g_free (buf);
822 if (result != 0)
823 return;
824 }
825
826 ctx = file_op_context_new (OP_DELETE);
827 file_progress_ui_create (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
828 if (erase_dir (ctx, tree->selected_ptr->name) == FILE_CONT)
829 tree_forget (tree);
830 file_op_context_destroy (ctx);
831 }
832
833
834
835 static inline void
836 tree_move_up (WTree *tree)
837 {
838 tree_move_backward (tree, 1);
839 show_tree (tree);
840 maybe_chdir (tree);
841 }
842
843
844
845 static inline void
846 tree_move_down (WTree *tree)
847 {
848 tree_move_forward (tree, 1);
849 show_tree (tree);
850 maybe_chdir (tree);
851 }
852
853
854
855 static inline void
856 tree_move_home (WTree *tree)
857 {
858 tree_move_to_top (tree);
859 show_tree (tree);
860 maybe_chdir (tree);
861 }
862
863
864
865 static inline void
866 tree_move_end (WTree *tree)
867 {
868 tree_move_to_bottom (tree);
869 show_tree (tree);
870 maybe_chdir (tree);
871 }
872
873
874
875 static void
876 tree_move_pgup (WTree *tree)
877 {
878 tree_move_backward (tree, tlines (tree) - 1);
879 show_tree (tree);
880 maybe_chdir (tree);
881 }
882
883
884
885 static void
886 tree_move_pgdn (WTree *tree)
887 {
888 tree_move_forward (tree, tlines (tree) - 1);
889 show_tree (tree);
890 maybe_chdir (tree);
891 }
892
893
894
895 static gboolean
896 tree_move_left (WTree *tree)
897 {
898 gboolean v = FALSE;
899
900 if (tree_navigation_flag)
901 {
902 v = tree_move_to_parent (tree);
903 show_tree (tree);
904 maybe_chdir (tree);
905 }
906
907 return v;
908 }
909
910
911
912 static gboolean
913 tree_move_right (WTree *tree)
914 {
915 gboolean v = FALSE;
916
917 if (tree_navigation_flag)
918 {
919 tree_move_to_child (tree);
920 show_tree (tree);
921 maybe_chdir (tree);
922 v = TRUE;
923 }
924
925 return v;
926 }
927
928
929
930 static void
931 tree_start_search (WTree *tree)
932 {
933 if (tree->searching)
934 {
935 if (tree->selected_ptr == tree->store->tree_last)
936 tree_move_to_top (tree);
937 else
938 {
939 gboolean i;
940
941
942
943
944
945
946 i = tree_navigation_flag;
947 tree_navigation_flag = FALSE;
948 tree_move_forward (tree, 1);
949 tree_navigation_flag = i;
950 }
951 tree_do_search (tree, 0);
952 }
953 else
954 {
955 tree->searching = TRUE;
956 g_string_set_size (tree->search_buffer, 0);
957 }
958 }
959
960
961
962 static void
963 tree_toggle_navig (WTree *tree)
964 {
965 Widget *w = WIDGET (tree);
966 WButtonBar *b;
967
968 tree_navigation_flag = !tree_navigation_flag;
969
970 b = buttonbar_find (DIALOG (w->owner));
971 buttonbar_set_label (b, 4,
972 tree_navigation_flag ? Q_ ("ButtonBar|Static") : Q_ ("ButtonBar|Dynamc"),
973 w->keymap, w);
974 widget_draw (WIDGET (b));
975 }
976
977
978
979 static void
980 tree_help (void)
981 {
982 ev_help_t event_data = { NULL, "[Directory Tree]" };
983
984 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
985 }
986
987
988
989 static cb_ret_t
990 tree_execute_cmd (WTree *tree, long command)
991 {
992 cb_ret_t res = MSG_HANDLED;
993
994 if (command != CK_Search)
995 tree->searching = FALSE;
996
997 switch (command)
998 {
999 case CK_Help:
1000 tree_help ();
1001 break;
1002 case CK_Forget:
1003 tree_forget (tree);
1004 break;
1005 case CK_ToggleNavigation:
1006 tree_toggle_navig (tree);
1007 break;
1008 case CK_Copy:
1009 tree_copy (tree, "");
1010 break;
1011 case CK_Move:
1012 tree_move (tree, "");
1013 break;
1014 case CK_Up:
1015 tree_move_up (tree);
1016 break;
1017 case CK_Down:
1018 tree_move_down (tree);
1019 break;
1020 case CK_Top:
1021 tree_move_home (tree);
1022 break;
1023 case CK_Bottom:
1024 tree_move_end (tree);
1025 break;
1026 case CK_PageUp:
1027 tree_move_pgup (tree);
1028 break;
1029 case CK_PageDown:
1030 tree_move_pgdn (tree);
1031 break;
1032 case CK_Enter:
1033 tree_chdir_sel (tree);
1034 break;
1035 case CK_Reread:
1036 tree_rescan (tree);
1037 break;
1038 case CK_Search:
1039 tree_start_search (tree);
1040 break;
1041 case CK_Delete:
1042 tree_rmdir (tree);
1043 break;
1044 case CK_Quit:
1045 if (!tree->is_panel)
1046 dlg_close (DIALOG (WIDGET (tree)->owner));
1047 return res;
1048 default:
1049 res = MSG_NOT_HANDLED;
1050 }
1051
1052 show_tree (tree);
1053
1054 return res;
1055 }
1056
1057
1058
1059 static cb_ret_t
1060 tree_key (WTree *tree, int key)
1061 {
1062 long command;
1063
1064 if (is_abort_char (key))
1065 {
1066 if (tree->is_panel)
1067 {
1068 tree->searching = FALSE;
1069 show_tree (tree);
1070 return MSG_HANDLED;
1071 }
1072
1073
1074 return MSG_NOT_HANDLED;
1075 }
1076
1077 if (tree->searching && ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE))
1078 {
1079 tree_do_search (tree, key);
1080 show_tree (tree);
1081 return MSG_HANDLED;
1082 }
1083
1084 command = widget_lookup_key (WIDGET (tree), key);
1085 switch (command)
1086 {
1087 case CK_IgnoreKey:
1088 break;
1089 case CK_Left:
1090 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1091 case CK_Right:
1092 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1093 default:
1094 tree_execute_cmd (tree, command);
1095 return MSG_HANDLED;
1096 }
1097
1098
1099 if (!command_prompt && ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE))
1100 {
1101 tree_start_search (tree);
1102 tree_do_search (tree, key);
1103 return MSG_HANDLED;
1104 }
1105
1106 return MSG_NOT_HANDLED;
1107 }
1108
1109
1110
1111 static void
1112 tree_frame (WDialog *h, WTree *tree)
1113 {
1114 Widget *w = WIDGET (tree);
1115
1116 (void) h;
1117
1118 tty_setcolor (NORMAL_COLOR);
1119 widget_erase (w);
1120 if (tree->is_panel)
1121 {
1122 const char *title = _ ("Directory tree");
1123 const int len = str_term_width1 (title);
1124
1125 tty_draw_box (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, FALSE);
1126
1127 widget_gotoyx (w, 0, (w->rect.cols - len - 2) / 2);
1128 tty_printf (" %s ", title);
1129
1130 if (panels_options.show_mini_info)
1131 {
1132 int y;
1133
1134 y = w->rect.lines - 3;
1135 widget_gotoyx (w, y, 0);
1136 tty_print_alt_char (ACS_LTEE, FALSE);
1137 widget_gotoyx (w, y, w->rect.cols - 1);
1138 tty_print_alt_char (ACS_RTEE, FALSE);
1139 tty_draw_hline (w->rect.y + y, w->rect.x + 1, ACS_HLINE, w->rect.cols - 2);
1140 }
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