grafthistory: support curl
[elinks/elinks-j605.git] / src / bfu / hierbox.c
blob15187e9906ceb14fc9ae6abff5f41778a2e4534f
1 /* Hiearchic listboxes browser dialog commons */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdarg.h>
9 #include "elinks.h"
11 #include "bfu/button.h"
12 #include "bfu/dialog.h"
13 #include "bfu/hierbox.h"
14 #include "bfu/inpfield.h"
15 #include "bfu/listbox.h"
16 #include "bfu/msgbox.h"
17 #include "bfu/text.h"
18 #include "config/kbdbind.h"
19 #include "intl/gettext/libintl.h"
20 #include "protocol/uri.h"
21 #include "session/task.h"
22 #include "terminal/screen.h"
23 #include "terminal/tab.h"
24 #include "terminal/terminal.h"
27 void
28 update_hierbox_browser(struct hierbox_browser *browser)
30 struct hierbox_dialog_list_item *item;
32 foreach (item, browser->dialogs) {
33 redraw_from_window(item->dlg_data->win->next);
38 /* Common backend for listbox adding */
39 struct listbox_item *
40 add_listbox_item(struct hierbox_browser *browser, struct listbox_item *root,
41 enum listbox_item_type type, void *data, int add_position)
43 struct listbox_item *item;
45 if (!root) {
46 assertm(browser, "Nowhere to add new list box item");
47 root = &browser->root;
50 item = mem_calloc(1, sizeof(*item));
51 if (!item) return NULL;
53 init_list(item->child);
54 item->visible = 1;
56 item->udata = data;
57 item->type = type;
58 item->depth = root->depth + 1;
60 /* TODO: Possibility to sort by making add_position into a flag */
61 if (add_position < 0)
62 add_to_list_end(root->child, item);
63 else
64 add_to_list(root->child, item);
66 if (browser) update_hierbox_browser(browser);
68 return item;
72 /* Find a listbox item to replace @item. This is done by trying first to
73 * traverse down then up, and if both traversals end up returning the @item
74 * (that is, it is the last item in the box), return NULL. */
75 static inline struct listbox_item *
76 replace_listbox_item(struct listbox_item *item, struct listbox_data *data)
78 struct listbox_item *new_item;
80 new_item = traverse_listbox_items_list(item, data, 1, 1, NULL, NULL);
81 if (item != new_item) return new_item;
83 new_item = traverse_listbox_items_list(item, data, -1, 1, NULL, NULL);
84 return (item == new_item) ? NULL : new_item;
87 void
88 done_listbox_item(struct hierbox_browser *browser, struct listbox_item *box_item)
90 struct listbox_data *box_data;
92 assert(box_item && list_empty(box_item->child));
94 /* The option dialog needs this test */
95 if (box_item->next) {
96 /* If we are removing the top or the selected box
97 * we have to figure out a replacement. */
99 foreach (box_data, browser->boxes) {
100 if (box_data->sel == box_item)
101 box_data->sel = replace_listbox_item(box_item,
102 box_data);
104 if (box_data->top == box_item)
105 box_data->top = replace_listbox_item(box_item,
106 box_data);
109 del_from_list(box_item);
111 update_hierbox_browser(browser);
114 mem_free(box_item);
118 static void
119 recursively_set_expanded(struct listbox_item *item, int expanded)
121 struct listbox_item *child;
123 if (item->type != BI_FOLDER)
124 return;
126 item->expanded = expanded;
128 foreach (child, item->child)
129 recursively_set_expanded(child, expanded);
132 static widget_handler_status_T
133 hierbox_ev_kbd(struct dialog_data *dlg_data)
135 struct hierbox_browser *browser = dlg_data->dlg->udata2;
136 struct widget_data *widget_data = dlg_data->widgets_data;
137 struct widget *widget = widget_data->widget;
138 struct listbox_data *box;
139 struct listbox_item *selected;
140 enum menu_action action_id;
141 struct term_event *ev = dlg_data->term_event;
143 /* Check if listbox has something to say to this */
144 if (widget->ops->kbd
145 && widget->ops->kbd(dlg_data, widget_data)
146 == EVENT_PROCESSED)
147 return EVENT_PROCESSED;
149 box = get_dlg_listbox_data(dlg_data);
150 selected = box->sel;
151 action_id = kbd_action(KEYMAP_MENU, ev, NULL);
153 if (action_id == ACT_MENU_SELECT) {
154 if (!selected) return EVENT_PROCESSED;
155 if (selected->type != BI_FOLDER)
156 return EVENT_NOT_PROCESSED;
157 selected->expanded = !selected->expanded;
159 } else if (action_id == ACT_MENU_UNEXPAND) {
160 /* Recursively unexpand all folders */
161 if (!selected) return EVENT_PROCESSED;
163 /* Special trick: if the folder is already
164 * folded, jump to the parent folder, so the
165 * next time when user presses the key, the
166 * whole parent folder will be closed. */
167 if (list_empty(selected->child)
168 || !selected->expanded) {
169 struct listbox_item *root = box->ops->get_root(selected);
171 if (root) {
172 listbox_sel(widget_data, root);
175 } else if (selected->type == BI_FOLDER) {
176 recursively_set_expanded(selected, 0);
179 } else if (action_id == ACT_MENU_EXPAND) {
180 /* Recursively expand all folders */
182 if (!selected || box->sel->type != BI_FOLDER)
183 return EVENT_PROCESSED;
185 recursively_set_expanded(box->sel, 1);
187 } else if (action_id == ACT_MENU_SEARCH) {
188 if (!box->ops->match)
189 return EVENT_NOT_PROCESSED;
191 push_hierbox_search_button(dlg_data, NULL);
192 return EVENT_PROCESSED;
194 } else {
195 return EVENT_NOT_PROCESSED;
199 if (browser->expansion_callback)
200 browser->expansion_callback();
202 display_widget(dlg_data, widget_data);
204 return EVENT_PROCESSED;
207 static widget_handler_status_T
208 hierbox_ev_init(struct dialog_data *dlg_data)
210 struct hierbox_browser *browser = dlg_data->dlg->udata2;
211 struct hierbox_dialog_list_item *item;
212 struct listbox_item *litem;
214 /* If we fail here it only means automatic updating
215 * will not be possible so no need to panic. */
216 item = mem_alloc(sizeof(*item));
217 if (item) {
218 item->dlg_data = dlg_data;
219 add_to_list(browser->dialogs, item);
222 foreach (litem, browser->root.child) {
223 litem->visible = 1;
226 return EVENT_NOT_PROCESSED; /* FIXME: is this correct ? --Zas */
229 static widget_handler_status_T
230 hierbox_ev_abort(struct dialog_data *dlg_data)
232 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
233 struct hierbox_browser *browser = dlg_data->dlg->udata2;
234 struct hierbox_dialog_list_item *item;
236 /* Save state and delete the box structure */
237 if (!browser->do_not_save_state)
238 copy_struct(&browser->box_data, box);
239 del_from_list(box);
241 /* Delete the dialog list entry */
242 foreach (item, browser->dialogs) {
243 if (item->dlg_data == dlg_data) {
244 del_from_list(item);
245 mem_free(item);
246 break;
250 return EVENT_NOT_PROCESSED; /* FIXME: is this correct ? --Zas */
254 /* We install own dialog event handler, so that we can give the listbox widget
255 * an early chance to catch the event. Basically, the listbox widget is itself
256 * unselectable, instead one of the buttons below is always active. So, we
257 * always first let the listbox catch the keypress and handle it, and if it
258 * doesn't care, we pass it on to the button. */
259 static widget_handler_status_T
260 hierbox_dialog_event_handler(struct dialog_data *dlg_data)
262 struct term_event *ev = dlg_data->term_event;
264 switch (ev->ev) {
265 case EVENT_KBD:
266 return hierbox_ev_kbd(dlg_data);
268 case EVENT_INIT:
269 return hierbox_ev_init(dlg_data);
271 case EVENT_RESIZE:
272 case EVENT_REDRAW:
273 case EVENT_MOUSE:
274 return EVENT_NOT_PROCESSED;
276 case EVENT_ABORT:
277 return hierbox_ev_abort(dlg_data);
280 return EVENT_NOT_PROCESSED;
284 struct dialog_data *
285 hierbox_browser(struct hierbox_browser *browser, struct session *ses)
287 struct terminal *term = ses->tab->term;
288 struct listbox_data *listbox_data;
289 struct dialog *dlg;
290 int button = browser->buttons_size + 2;
291 int anonymous = get_cmd_opt_bool("anonymous");
293 assert(ses);
295 dlg = calloc_dialog(button, sizeof(*listbox_data));
296 if (!dlg) return NULL;
298 listbox_data = (struct listbox_data *) get_dialog_offset(dlg, button);
300 dlg->title = _(browser->title, term);
301 dlg->layouter = generic_dialog_layouter;
302 dlg->layout.maximize_width = 1;
303 dlg->layout.padding_top = 1;
304 dlg->handle_event = hierbox_dialog_event_handler;
305 dlg->udata = ses;
306 dlg->udata2 = browser;
308 add_dlg_listbox(dlg, 12, listbox_data);
310 for (button = 0; button < browser->buttons_size; button++) {
311 struct hierbox_browser_button *but = &browser->buttons[button];
313 /* Skip buttons that should not be displayed in anonymous mode */
314 if (anonymous && !but->anonymous) {
315 anonymous++;
316 continue;
319 add_dlg_button(dlg, _(but->label, term), B_ENTER, but->handler, NULL);
322 add_dlg_button(dlg, _("Close", term), B_ESC, cancel_dialog, NULL);
324 /* @anonymous was initially 1 if we are running in anonymous mode so we
325 * have to subtract one. */
326 add_dlg_end(dlg, button + 2 - (anonymous ? anonymous - 1 : 0));
328 return do_dialog(term, dlg, getml(dlg, NULL));
332 /* Action info management */
334 static int
335 scan_for_marks(struct listbox_item *item, void *info_, int *offset)
337 if (item->marked) {
338 struct listbox_context *context = info_;
340 context->item = NULL;
341 *offset = 0;
344 return 0;
347 static int
348 scan_for_used(struct listbox_item *item, void *info_, int *offset)
350 struct listbox_context *context = info_;
352 if (context->box->ops->is_used(item)) {
353 context->item = item;
354 *offset = 0;
357 return 0;
361 static struct listbox_context *
362 init_listbox_context(struct listbox_data *box, struct terminal *term,
363 struct listbox_item *item,
364 int (*scanner)(struct listbox_item *, void *, int *))
366 struct listbox_context *context;
368 context = mem_calloc(1, sizeof(*context));
369 if (!context) return NULL;
371 context->item = item;
372 context->term = term;
373 context->box = box;
375 if (!scanner) return context;
377 /* Look if it wouldn't be more interesting to blast off the marked
378 * item. */
379 assert(!list_empty(*box->items));
380 traverse_listbox_items_list(box->items->next, box, 0, 0,
381 scanner, context);
383 return context;
386 static void
387 done_listbox_context(void *context_)
389 struct listbox_context *context = context_;
391 if (context->item)
392 context->box->ops->unlock(context->item);
396 /* Info action */
398 widget_handler_status_T
399 push_hierbox_info_button(struct dialog_data *dlg_data, struct widget_data *button)
401 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
402 struct terminal *term = dlg_data->win->term;
403 struct listbox_context *context;
404 unsigned char *msg;
406 if (!box->sel) return EVENT_PROCESSED;
408 assert(box->ops);
410 context = init_listbox_context(box, term, box->sel, NULL);
411 if (!context) return EVENT_PROCESSED;
413 msg = box->ops->get_info(context->item, term);
414 if (!msg) {
415 mem_free(context);
416 if (box->sel->type == BI_FOLDER) {
417 info_box(term, 0, N_("Info"), ALIGN_CENTER,
418 N_("Press space to expand this folder."));
420 return EVENT_PROCESSED;
423 box->ops->lock(context->item);
425 msg_box(term, getml(context, NULL), MSGBOX_FREE_TEXT /* | MSGBOX_SCROLLABLE */,
426 N_("Info"), ALIGN_LEFT,
427 msg,
428 context, 1,
429 N_("~OK"), done_listbox_context, B_ESC | B_ENTER);
431 return EVENT_PROCESSED;
435 /* Goto action */
437 static void
438 recursively_goto_listbox(struct session *ses, struct listbox_item *root,
439 struct listbox_data *box)
441 struct listbox_item *item;
443 foreach (item, root->child) {
444 if (item->type == BI_FOLDER) {
445 recursively_goto_listbox(ses, item, box);
446 continue;
448 } else if (item->type == BI_LEAF) {
449 struct uri *uri = box->ops->get_uri(item);
451 if (!uri) continue;
453 open_uri_in_new_tab(ses, uri, 1, 0);
454 done_uri(uri);
459 static int
460 goto_marked(struct listbox_item *item, void *data_, int *offset)
462 struct listbox_context *context = data_;
464 if (item->marked) {
465 struct session *ses = context->dlg_data->dlg->udata;
466 struct listbox_data *box = context->box;
468 if (item->type == BI_FOLDER) {
469 recursively_goto_listbox(ses, item, box);
470 return 0;
472 } else if (item->type == BI_LEAF) {
473 struct uri *uri = box->ops->get_uri(item);
475 if (!uri) return 0;
477 open_uri_in_new_tab(ses, uri, 1, 0);
478 done_uri(uri);
482 return 0;
485 widget_handler_status_T
486 push_hierbox_goto_button(struct dialog_data *dlg_data,
487 struct widget_data *button)
489 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
490 struct session *ses = dlg_data->dlg->udata;
491 struct terminal *term = dlg_data->win->term;
492 struct listbox_context *context;
494 /* Do nothing with a folder */
495 if (!box->sel) return EVENT_PROCESSED;
497 context = init_listbox_context(box, term, box->sel, scan_for_marks);
498 if (!context) return EVENT_PROCESSED;
500 if (!context->item) {
501 context->dlg_data = dlg_data;
502 traverse_listbox_items_list(context->box->items->next,
503 context->box, 0, 0,
504 goto_marked, context);
506 } else if (box->sel->type == BI_FOLDER) {
507 recursively_goto_listbox(ses, box->sel, box);
509 } else if (box->sel->type == BI_LEAF) {
510 struct uri *uri = box->ops->get_uri(box->sel);
512 if (uri) {
513 goto_uri(ses, uri);
514 done_uri(uri);
517 } else {
518 mem_free(context);
519 return EVENT_PROCESSED;
522 mem_free(context);
524 /* Close the dialog */
525 delete_window(dlg_data->win);
526 return EVENT_PROCESSED;
530 /* Delete action */
532 enum delete_error {
533 DELETE_IMPOSSIBLE = 0,
534 DELETE_LOCKED,
535 DELETE_ERRORS,
538 unsigned char *delete_messages[2][DELETE_ERRORS] = {
540 N_("Sorry, but the item \"%s\" cannot be deleted."),
541 N_("Sorry, but the item \"%s\" is being used by something else."),
544 N_("Sorry, but the folder \"%s\" cannot be deleted."),
545 N_("Sorry, but the folder \"%s\" is being used by something else."),
549 static void
550 print_delete_error(struct listbox_item *item, struct terminal *term,
551 struct listbox_ops *ops, enum delete_error err)
553 struct string msg;
554 unsigned char *errmsg;
555 unsigned char *text;
557 switch (err) {
558 case DELETE_IMPOSSIBLE:
559 if (item->type == BI_FOLDER) {
560 if (ops->messages && ops->messages->cant_delete_folder)
561 errmsg = ops->messages->cant_delete_folder;
562 else
563 errmsg = delete_messages[1][DELETE_IMPOSSIBLE];
564 } else {
565 if (ops->messages && ops->messages->cant_delete_item)
566 errmsg = ops->messages->cant_delete_item;
567 else
568 errmsg = delete_messages[0][DELETE_IMPOSSIBLE];
570 break;
572 case DELETE_LOCKED:
573 if (item->type == BI_FOLDER) {
574 if (ops->messages && ops->messages->cant_delete_used_folder)
575 errmsg = ops->messages->cant_delete_used_folder;
576 else
577 errmsg = delete_messages[1][DELETE_LOCKED];
578 } else {
579 if (ops->messages && ops->messages->cant_delete_used_item)
580 errmsg = ops->messages->cant_delete_used_item;
581 else
582 errmsg = delete_messages[0][DELETE_LOCKED];
584 break;
586 default:
587 INTERNAL("Bad delete error code (%d)!", err);
588 return;
591 text = ops->get_text(item, term);
593 if (!text || !init_string(&msg)) {
594 mem_free_if(text);
595 return;
598 add_format_to_string(&msg, _(errmsg, term), text);
599 mem_free(text);
601 if (item->type == BI_LEAF) {
602 unsigned char *info = ops->get_info(item, term);
604 if (info) {
605 add_format_to_string(&msg, "\n\n%s", info);
606 mem_free(info);
610 info_box(term, MSGBOX_FREE_TEXT, N_("Delete error"), ALIGN_LEFT,
611 msg.source);
614 static void
615 do_delete_item(struct listbox_item *item, struct listbox_context *info,
616 int last)
618 struct listbox_ops *ops = info->box->ops;
620 assert(item);
622 if (!ops->can_delete(item)) {
623 print_delete_error(item, info->term, ops, DELETE_IMPOSSIBLE);
624 return;
627 if (ops->is_used(item)) {
628 print_delete_error(item, info->term, ops, DELETE_LOCKED);
629 return;
632 ops->delete(item, last);
635 static int
636 delete_marked(struct listbox_item *item, void *data_, int *offset)
638 struct listbox_context *context = data_;
640 if (item->marked && !context->box->ops->is_used(item)) {
641 /* Save the first marked so it can be deleted last */
642 if (!context->item) {
643 context->item = item;
644 } else {
645 do_delete_item(item, context, 0);
648 return 1;
651 return 0;
654 static void
655 push_ok_delete_button(void *context_)
657 struct listbox_context *context = context_;
658 struct listbox_item *root;
659 int last = 0;
661 if (context->item) {
662 context->box->ops->unlock(context->item);
663 } else {
664 traverse_listbox_items_list(context->box->items->next,
665 context->box, 0, 0,
666 delete_marked, context);
667 if (!context->item) return;
670 root = context->box->ops->get_root(context->item);
671 if (root) {
672 last = context->item == root->child.prev;
675 /* Delete the last one (traversal should save one to delete) */
676 do_delete_item(context->item, context, 1);
678 /* If removing the last item in a folder move focus to previous item in
679 * the folder or the root. */
680 if (last)
681 listbox_sel_move(context->widget_data, -1);
684 widget_handler_status_T
685 push_hierbox_delete_button(struct dialog_data *dlg_data,
686 struct widget_data *button)
688 struct terminal *term = dlg_data->win->term;
689 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
690 struct listbox_context *context;
691 unsigned char *text;
692 enum delete_error delete;
694 if (!box->sel) return EVENT_PROCESSED;
696 assert(box->ops && box->ops->can_delete && box->ops->delete);
698 context = init_listbox_context(box, term, box->sel, scan_for_marks);
699 if (!context) return EVENT_PROCESSED;
701 context->widget_data = dlg_data->widgets_data;
703 if (!context->item) {
704 unsigned char *title = N_("Delete marked items");
705 unsigned char *message = N_("Delete marked items?");
707 if (box->ops->messages) {
708 if (box->ops->messages->delete_marked_items)
709 message = box->ops->messages->delete_marked_items;
710 if (box->ops->messages->delete_marked_items_title)
711 title = box->ops->messages->delete_marked_items_title;
714 msg_box(term, getml(context, NULL), 0,
715 title, ALIGN_CENTER,
716 message,
717 context, 2,
718 N_("~Yes"), push_ok_delete_button, B_ENTER,
719 N_("~No"), done_listbox_context, B_ESC);
720 return EVENT_PROCESSED;
723 delete = box->ops->can_delete(context->item)
724 ? DELETE_LOCKED : DELETE_IMPOSSIBLE;
726 if (delete == DELETE_IMPOSSIBLE || box->ops->is_used(context->item)) {
727 print_delete_error(context->item, term, box->ops, delete);
728 mem_free(context);
729 return EVENT_PROCESSED;
732 text = box->ops->get_text(context->item, term);
733 if (!text) {
734 mem_free(context);
735 return EVENT_PROCESSED;
738 if (context->item->type == BI_FOLDER) {
739 unsigned char *title = N_("Delete folder");
740 unsigned char *message = N_("Delete the folder \"%s\" and its content?");
742 if (box->ops->messages) {
743 if (box->ops->messages->delete_folder)
744 message = box->ops->messages->delete_folder;
745 if (box->ops->messages->delete_folder_title)
746 title = box->ops->messages->delete_folder_title;
749 box->ops->lock(context->item);
750 msg_box(term, getml(context, NULL), MSGBOX_FREE_TEXT,
751 title, ALIGN_CENTER,
752 msg_text(term, message, text),
753 context, 2,
754 N_("~Yes"), push_ok_delete_button, B_ENTER,
755 N_("~No"), done_listbox_context, B_ESC);
756 } else {
757 unsigned char *title = N_("Delete item");
758 unsigned char *message = N_("Delete \"%s\"?\n\n%s");
759 unsigned char *msg;
761 if (box->ops->messages) {
762 if (box->ops->messages->delete_item)
763 message = box->ops->messages->delete_item;
764 if (box->ops->messages->delete_item_title)
765 title = box->ops->messages->delete_item_title;
768 msg = box->ops->get_info(context->item, term);
769 box->ops->lock(context->item);
771 msg_box(term, getml(context, NULL), MSGBOX_FREE_TEXT,
772 title, ALIGN_LEFT,
773 msg_text(term, message, text, empty_string_or_(msg)),
774 context, 2,
775 N_("~Yes"), push_ok_delete_button, B_ENTER,
776 N_("~No"), done_listbox_context, B_ESC);
777 mem_free_if(msg);
779 mem_free(text);
781 return EVENT_PROCESSED;
785 /* Clear action */
787 static int
788 delete_unused(struct listbox_item *item, void *data_, int *offset)
790 struct listbox_context *context = data_;
792 if (context->box->ops->is_used(item)) return 0;
794 do_delete_item(item, context, 0);
795 return 1;
798 static void
799 do_clear_browser(void *context_)
801 struct listbox_context *context = context_;
803 traverse_listbox_items_list(context->box->items->next,
804 context->box, 0, 0,
805 delete_unused, context);
808 widget_handler_status_T
809 push_hierbox_clear_button(struct dialog_data *dlg_data,
810 struct widget_data *button)
812 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
813 struct terminal *term = dlg_data->win->term;
814 struct listbox_context *context;
815 unsigned char *title = N_("Clear all items");
816 unsigned char *message = N_("Do you really want to remove all items?");
818 if (!box->sel) return EVENT_PROCESSED;
820 assert(box->ops);
822 context = init_listbox_context(box, term, NULL, scan_for_used);
823 if (!context) return EVENT_PROCESSED;
825 if (context->item) {
826 /* FIXME: If the clear button should be used for browsers where
827 * not all items can be deleted scan_for_used() should also can
828 * for undeletable and we should be able to pass either delete
829 * error types. */
830 print_delete_error(context->item, term, box->ops, DELETE_LOCKED);
831 mem_free(context);
832 return EVENT_PROCESSED;
835 if (box->ops->messages) {
836 if (box->ops->messages->clear_all_items)
837 message = box->ops->messages->clear_all_items;
838 if (box->ops->messages->clear_all_items_title)
839 title = box->ops->messages->clear_all_items_title;
842 msg_box(term, getml(context, NULL), 0,
843 title, ALIGN_CENTER,
844 message,
845 context, 2,
846 N_("~Yes"), do_clear_browser, B_ENTER,
847 N_("~No"), NULL, B_ESC);
849 return EVENT_PROCESSED;
853 /* Search action */
855 static int
856 scan_for_matches(struct listbox_item *item, void *info_, int *offset)
858 struct listbox_context *context = info_;
859 unsigned char *text = (unsigned char *) context->widget_data;
861 if (!*text) {
862 item->visible = 1;
863 return 0;
866 switch (context->box->ops->match(item, context->term, text)) {
867 case LISTBOX_MATCH_OK:
868 /* Mark that we have a match by setting the item to non-NULL */
869 context->item = item;
870 item->visible = 1;
871 break;
873 case LISTBOX_MATCH_NO:
874 item->visible = 0;
875 break;
877 case LISTBOX_MATCH_IMPOSSIBLE:
878 break;
881 return 0;
884 static int
885 mark_visible(struct listbox_item *item, void *xxx, int *offset)
887 item->visible = 1;
888 return 0;
892 static void
893 search_hierbox_browser(void *data, unsigned char *text)
895 struct dialog_data *dlg_data = data;
896 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
897 struct terminal *term = dlg_data->win->term;
898 struct listbox_context *context;
900 context = init_listbox_context(box, term, NULL, NULL);
901 if (!context) return;
903 /* Eeew :/ */
904 context->widget_data = (void *) text;
906 traverse_listbox_items_list(box->items->next, box, 0, 0,
907 scan_for_matches, context);
909 if (!context->item && *text) {
910 switch (get_opt_int("document.browse.search.show_not_found")) {
911 case 2:
912 info_box(term, MSGBOX_FREE_TEXT,
913 N_("Search"), ALIGN_CENTER,
914 msg_text(term,
915 N_("Search string '%s' not found"),
916 text));
917 break;
919 case 1:
920 beep_terminal(term);
922 default:
923 break;
926 traverse_listbox_items_list(box->items->next, box, 0, 0,
927 mark_visible, NULL);
930 mem_free(context);
933 widget_handler_status_T
934 push_hierbox_search_button(struct dialog_data *dlg_data,
935 struct widget_data *button)
937 struct terminal *term = dlg_data->win->term;
938 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
940 if (!box->sel) return EVENT_PROCESSED;
942 assert(box->ops->match);
944 input_dialog(term, NULL, N_("Search"), N_("Name"),
945 dlg_data, NULL,
946 MAX_STR_LEN, "", 0, 0, NULL,
947 search_hierbox_browser, NULL);
949 return EVENT_PROCESSED;