Resources system rewrite + new "--save-config DIR" option
[jvcard.git] / src / be / nikiroo / jvcard / tui / MainWindow.java
CommitLineData
a3b510ab
NR
1package be.nikiroo.jvcard.tui;
2
5ad0e17e 3import java.io.IOException;
bcb54330 4import java.util.ArrayList;
a3b510ab
NR
5import java.util.Arrays;
6import java.util.LinkedList;
7import java.util.List;
8
7da41ecd
NR
9import be.nikiroo.jvcard.launcher.Main;
10import be.nikiroo.jvcard.resources.StringUtils;
e119a1c1
NR
11import be.nikiroo.jvcard.resources.enums.ColorOption;
12import be.nikiroo.jvcard.resources.enums.StringId;
a3b510ab 13import be.nikiroo.jvcard.tui.KeyAction.Mode;
f04d8b1c 14import be.nikiroo.jvcard.tui.panes.ContactDetails;
296a0b75 15import be.nikiroo.jvcard.tui.panes.ContactDetailsRaw;
fae07ea7
NR
16import be.nikiroo.jvcard.tui.panes.ContactList;
17import be.nikiroo.jvcard.tui.panes.MainContent;
a3b510ab
NR
18
19import com.googlecode.lanterna.TerminalSize;
20import com.googlecode.lanterna.gui2.BasicWindow;
21import com.googlecode.lanterna.gui2.BorderLayout;
22import com.googlecode.lanterna.gui2.Direction;
23import com.googlecode.lanterna.gui2.Interactable;
24import com.googlecode.lanterna.gui2.Label;
25import com.googlecode.lanterna.gui2.LinearLayout;
26import com.googlecode.lanterna.gui2.Panel;
27import com.googlecode.lanterna.gui2.TextBox;
a3b510ab
NR
28import com.googlecode.lanterna.gui2.Window;
29import com.googlecode.lanterna.input.KeyStroke;
30import com.googlecode.lanterna.input.KeyType;
31
32/**
0b0b2b0f
NR
33 * This is the main "window" of the program. It can show up to one
34 * {@link MainContent} at any one time, but keeps a stack of contents.
a3b510ab
NR
35 *
36 * @author niki
37 *
38 */
f720df72 39
a3b510ab
NR
40public class MainWindow extends BasicWindow {
41 private List<KeyAction> defaultActions = new LinkedList<KeyAction>();
42 private List<KeyAction> actions = new LinkedList<KeyAction>();
0b0b2b0f 43 private List<MainContent> contentStack = new LinkedList<MainContent>();
f720df72 44 private UserQuestion userQuestion;
bcb54330 45 private String titleCache;
a3b510ab
NR
46 private Panel titlePanel;
47 private Panel mainPanel;
48 private Panel contentPanel;
49 private Panel actionPanel;
50 private Panel messagePanel;
51 private TextBox text;
52
f720df72
NR
53 /**
54 * Information about a question to ask the user and its answer.
55 *
56 * @author niki
57 *
58 */
59 private class UserQuestion {
60 private boolean oneKeyAnswer;
61 private KeyAction action;
62 private String answer;
63
64 /**
65 * Create a new {@link UserQuestion}.
66 *
67 * @param action
68 * the action that triggered the question
69 * @param oneKeyAnswer
70 * TRUE if we expect a one-key answer
71 */
72 public UserQuestion(KeyAction action, boolean oneKeyAnswer) {
73 this.action = action;
74 this.oneKeyAnswer = oneKeyAnswer;
75 }
76
77 /**
78 * Return the {@link KeyAction} that triggered the question.
79 *
80 * @return the {@link KeyAction}
81 */
82 public KeyAction getAction() {
83 return action;
84 }
85
86 /**
87 * Check if a one-key answer is expected.
88 *
89 * @return TRUE if a one-key answer is expected
90 */
91 public boolean isOneKeyAnswer() {
92 return oneKeyAnswer;
93 }
94
95 /**
96 * Return the user answer.
97 *
98 * @return the user answer
99 */
100 public String getAnswer() {
101 return answer;
102 }
103
104 /**
105 * Set the user answer.
106 *
107 * @param answer
108 * the new answer
109 */
110 public void setAnswer(String answer) {
111 this.answer = answer;
112 }
113 }
114
0b0b2b0f
NR
115 /**
116 * Create a new, empty window.
117 */
a3b510ab
NR
118 public MainWindow() {
119 this(null);
120 }
121
0b0b2b0f
NR
122 /**
123 * Create a new window hosting the given content.
124 *
125 * @param content
126 * the content to host
127 */
a3b510ab
NR
128 public MainWindow(MainContent content) {
129 super(content == null ? "" : content.getTitle());
130
131 setHints(Arrays.asList(Window.Hint.FULL_SCREEN,
132 Window.Hint.NO_DECORATIONS, Window.Hint.FIT_TERMINAL_WINDOW));
133
134 defaultActions.add(new KeyAction(Mode.BACK, 'q',
135 StringId.KEY_ACTION_BACK));
136 defaultActions.add(new KeyAction(Mode.BACK, KeyType.Escape,
137 StringId.NULL));
138 defaultActions.add(new KeyAction(Mode.HELP, 'h',
139 StringId.KEY_ACTION_HELP));
140 defaultActions.add(new KeyAction(Mode.HELP, KeyType.F1, StringId.NULL));
141
142 actionPanel = new Panel();
143 contentPanel = new Panel();
144 mainPanel = new Panel();
145 messagePanel = new Panel();
146 titlePanel = new Panel();
147
148 Panel actionMessagePanel = new Panel();
149
150 LinearLayout llayout = new LinearLayout(Direction.HORIZONTAL);
151 llayout.setSpacing(0);
152 actionPanel.setLayoutManager(llayout);
153
0b0b2b0f
NR
154 BorderLayout blayout = new BorderLayout();
155 titlePanel.setLayoutManager(blayout);
a3b510ab
NR
156
157 llayout = new LinearLayout(Direction.VERTICAL);
158 llayout.setSpacing(0);
159 messagePanel.setLayoutManager(llayout);
160
0b0b2b0f 161 blayout = new BorderLayout();
a3b510ab
NR
162 mainPanel.setLayoutManager(blayout);
163
164 blayout = new BorderLayout();
165 contentPanel.setLayoutManager(blayout);
166
167 blayout = new BorderLayout();
168 actionMessagePanel.setLayoutManager(blayout);
169
170 actionMessagePanel
171 .addComponent(messagePanel, BorderLayout.Location.TOP);
172 actionMessagePanel.addComponent(actionPanel,
173 BorderLayout.Location.CENTER);
174
175 mainPanel.addComponent(titlePanel, BorderLayout.Location.TOP);
176 mainPanel.addComponent(contentPanel, BorderLayout.Location.CENTER);
177 mainPanel
178 .addComponent(actionMessagePanel, BorderLayout.Location.BOTTOM);
179
180 pushContent(content);
181
182 setComponent(mainPanel);
183 }
184
0b0b2b0f
NR
185 /**
186 * "push" some content to the window stack.
187 *
188 * @param content
189 * the new top-of-the-stack content
190 */
a3b510ab
NR
191 public void pushContent(MainContent content) {
192 List<KeyAction> actions = null;
a3b510ab
NR
193
194 contentPanel.removeAllComponents();
195 if (content != null) {
a3b510ab
NR
196 actions = content.getKeyBindings();
197 contentPanel.addComponent(content, BorderLayout.Location.CENTER);
0b0b2b0f 198 this.contentStack.add(content);
9c8baf0c
NR
199
200 Interactable focus = content.nextFocus(null);
201 if (focus != null)
202 focus.takeFocus();
a3b510ab
NR
203 }
204
bcb54330 205 setTitle();
0b0b2b0f 206 setActions(actions, true);
a3b510ab
NR
207 }
208
0b0b2b0f
NR
209 /**
210 * "pop" the latest, top-of-the-stack content from the window stack.
211 *
212 * @return the removed content if any
213 */
9c8baf0c
NR
214 public MainContent popContent() {
215 MainContent removed = null;
216 MainContent prev = null;
9c8baf0c 217
0b0b2b0f
NR
218 MainContent content = getContent();
219 if (content != null)
220 removed = contentStack.remove(contentStack.size() - 1);
9c8baf0c 221
0b0b2b0f
NR
222 if (contentStack.size() > 0)
223 prev = contentStack.remove(contentStack.size() - 1);
a3b510ab 224
5ad0e17e
NR
225 if (prev != null) {
226 try {
227 String mess = prev.wakeup();
228 if (mess != null)
229 setMessage(mess, false);
230 } catch (IOException e) {
231 setMessage(e.getMessage(), true);
232 }
233 }
234
0b0b2b0f 235 pushContent(prev);
a3b510ab 236
0b0b2b0f 237 return removed;
a3b510ab
NR
238 }
239
9c8baf0c
NR
240 /**
241 * Show the given message on screen. It will disappear at the next action.
242 *
243 * @param mess
244 * the message to display
245 * @param error
246 * TRUE for an error message, FALSE for an information message
bcb54330
NR
247 *
248 * @return TRUE if changes were performed
9c8baf0c 249 */
bcb54330
NR
250 public boolean setMessage(String mess, boolean error) {
251 if (mess != null || messagePanel.getChildCount() > 0) {
252 messagePanel.removeAllComponents();
253 if (mess != null) {
e119a1c1
NR
254 ColorOption element = (error ? ColorOption.LINE_MESSAGE_ERR
255 : ColorOption.LINE_MESSAGE);
256 Label lbl = UiColors.createLabel(element, " " + mess + " ");
bcb54330
NR
257 messagePanel.addComponent(lbl, LinearLayout
258 .createLayoutData(LinearLayout.Alignment.Center));
259 }
260 return true;
261 }
262
263 return false;
264 }
265
266 /**
267 * Show a question to the user and switch to "ask for answer" mode see
268 * {@link MainWindow#handleQuestion}. The user will be asked to enter some
269 * answer and confirm with ENTER.
270 *
296a0b75
NR
271 * @param action
272 * the related action
bcb54330
NR
273 * @param question
274 * the question to ask
275 * @param initial
276 * the initial answer if any (to be edited by the user)
277 */
296a0b75
NR
278 public void setQuestion(KeyAction action, String question, String initial) {
279 setQuestion(action, question, initial, false);
bcb54330
NR
280 }
281
282 /**
283 * Show a question to the user and switch to "ask for answer" mode see
284 * {@link MainWindow#handleQuestion}. The user will be asked to hit one key
285 * as an answer.
286 *
296a0b75
NR
287 * @param action
288 * the related action
bcb54330
NR
289 * @param question
290 * the question to ask
291 */
296a0b75
NR
292 public void setQuestion(KeyAction action, String question) {
293 setQuestion(action, question, null, true);
9c8baf0c
NR
294 }
295
0b0b2b0f
NR
296 /**
297 * Show a question to the user and switch to "ask for answer" mode see
298 * {@link MainWindow#handleQuestion}.
299 *
296a0b75
NR
300 * @param action
301 * the related action
bcb54330
NR
302 * @param question
303 * the question to ask
304 * @param initial
305 * the initial answer if any (to be edited by the user)
0b0b2b0f
NR
306 * @param oneKey
307 * TRUE for a one-key answer, FALSE for a text answer validated
308 * by ENTER
309 */
296a0b75 310 private void setQuestion(KeyAction action, String question, String initial,
bcb54330 311 boolean oneKey) {
f720df72 312 userQuestion = new UserQuestion(action, oneKey);
0b0b2b0f 313
9c8baf0c 314 messagePanel.removeAllComponents();
9c8baf0c 315
0b0b2b0f
NR
316 Panel hpanel = new Panel();
317 LinearLayout llayout = new LinearLayout(Direction.HORIZONTAL);
318 llayout.setSpacing(0);
319 hpanel.setLayoutManager(llayout);
9c8baf0c 320
e119a1c1 321 Label lbl = UiColors.createLabel(ColorOption.LINE_MESSAGE_QUESTION, " "
bcb54330 322 + question + " ");
296a0b75
NR
323 text = new TextBox(new TerminalSize(getSize().getColumns()
324 - lbl.getSize().getColumns(), 1));
f720df72
NR
325
326 if (initial != null) {
327 // add all chars one by one so the caret is at the end
328 for (int index = 0; index < initial.length(); index++) {
329 text.handleInput(new KeyStroke(initial.charAt(index), false,
330 false));
331 }
332 }
9c8baf0c 333
bcb54330
NR
334 hpanel.addComponent(lbl,
335 LinearLayout.createLayoutData(LinearLayout.Alignment.Beginning));
336 hpanel.addComponent(text,
337 LinearLayout.createLayoutData(LinearLayout.Alignment.Fill));
9c8baf0c 338
bcb54330
NR
339 messagePanel
340 .addComponent(hpanel, LinearLayout
341 .createLayoutData(LinearLayout.Alignment.Beginning));
9c8baf0c 342
0b0b2b0f 343 text.takeFocus();
9c8baf0c
NR
344 }
345
296a0b75
NR
346 /**
347 * Refresh the window and the empty-space handling. You should call this
348 * method when the window size changed.
349 *
350 * @param size
351 * the new size of the window
352 */
353 public void refresh(TerminalSize size) {
354 if (size == null)
355 return;
356
357 if (getSize() == null || !getSize().equals(size))
358 setSize(size);
359
360 setTitle();
361
362 if (actions != null)
363 setActions(new ArrayList<KeyAction>(actions), false);
364
365 invalidate();
366 }
367
368 @Override
369 public void invalidate() {
370 super.invalidate();
371 for (MainContent content : contentStack) {
372 content.invalidate();
373 }
374 }
375
376 @Override
377 public boolean handleInput(KeyStroke key) {
378 boolean handled = false;
379
f720df72
NR
380 if (userQuestion != null) {
381 handled = handleQuestion(userQuestion, key);
382 if (handled) {
383 if (userQuestion.getAnswer() != null) {
384 handleAction(userQuestion.getAction(),
385 userQuestion.getAnswer());
296a0b75 386
f720df72
NR
387 userQuestion = null;
388 }
296a0b75
NR
389 }
390 } else {
391 handled = handleKey(key);
392 }
393
f720df72 394 if (!handled) {
296a0b75 395 handled = super.handleInput(key);
f720df72 396 }
296a0b75
NR
397
398 return handled;
399 }
400
bcb54330
NR
401 /**
402 * Actually set the title <b>inside</b> the window. Will also call
296a0b75 403 * {@link BasicWindow#setTitle} with the computed parameters.
bcb54330
NR
404 */
405 private void setTitle() {
0b0b2b0f
NR
406 String prefix = " " + Main.APPLICATION_TITLE + " (version "
407 + Main.APPLICATION_VERSION + ")";
408
bcb54330 409 String title = null;
0b0b2b0f 410 int count = -1;
bcb54330 411
0b0b2b0f 412 MainContent content = getContent();
bcb54330
NR
413 if (content != null) {
414 title = content.getTitle();
0b0b2b0f 415 count = content.getCount();
bcb54330
NR
416 }
417
418 if (title == null)
419 title = "";
0b0b2b0f 420
bcb54330 421 if (title.length() > 0) {
0b0b2b0f 422 prefix = prefix + ": ";
7da41ecd 423 title = StringUtils.sanitize(title, Main.isUnicode());
0b0b2b0f
NR
424 }
425
bcb54330
NR
426 String countStr = "";
427 if (count > -1) {
428 countStr = "[" + count + "]";
429 }
430
296a0b75
NR
431 int width = -1;
432 if (getSize() != null) {
433 width = getSize().getColumns();
434 }
435
bcb54330
NR
436 if (width > 0) {
437 int padding = width - prefix.length() - title.length()
438 - countStr.length();
439 if (padding > 0) {
440 if (title.length() > 0)
441 title = StringUtils.padString(title, title.length()
442 + padding);
443 else
444 prefix = StringUtils.padString(prefix, prefix.length()
445 + padding);
446 }
0b0b2b0f 447 }
0b0b2b0f 448
bcb54330
NR
449 String titleCache = prefix + title + count;
450 if (!titleCache.equals(this.titleCache)) {
451 super.setTitle(prefix);
0b0b2b0f
NR
452
453 Label lblPrefix = new Label(prefix);
e119a1c1 454 UiColors.themeLabel(ColorOption.TITLE_MAIN, lblPrefix);
0b0b2b0f
NR
455
456 Label lblTitle = null;
bcb54330 457 if (title.length() > 0) {
0b0b2b0f 458 lblTitle = new Label(title);
e119a1c1 459 UiColors.themeLabel(ColorOption.TITLE_VARIABLE, lblTitle);
0b0b2b0f
NR
460 }
461
462 Label lblCount = null;
bcb54330
NR
463 if (countStr != null) {
464 lblCount = new Label(countStr);
e119a1c1 465 UiColors.themeLabel(ColorOption.TITLE_COUNT, lblCount);
0b0b2b0f
NR
466 }
467
468 titlePanel.removeAllComponents();
a3b510ab 469
0b0b2b0f
NR
470 titlePanel.addComponent(lblPrefix, BorderLayout.Location.LEFT);
471 if (lblTitle != null)
472 titlePanel.addComponent(lblTitle, BorderLayout.Location.CENTER);
473 if (lblCount != null)
474 titlePanel.addComponent(lblCount, BorderLayout.Location.RIGHT);
0b0b2b0f
NR
475 }
476 }
477
478 /**
479 * Return the current {@link MainContent} from the stack if any.
480 *
481 * @return the current {@link MainContent}
482 */
483 private MainContent getContent() {
484 if (contentStack.size() > 0) {
485 return contentStack.get(contentStack.size() - 1);
486 }
487
488 return null;
489 }
490
491 /**
492 * Update the list of actions and refresh the action panel.
493 *
494 * @param actions
495 * the list of actions to support
496 * @param enableDefaultactions
497 * TRUE to enable the default actions
498 */
499 private void setActions(List<KeyAction> actions,
500 boolean enableDefaultactions) {
a3b510ab 501 this.actions.clear();
9c8baf0c 502
a3b510ab
NR
503 if (enableDefaultactions)
504 this.actions.addAll(defaultActions);
505
506 if (actions != null)
507 this.actions.addAll(actions);
508
509 actionPanel.removeAllComponents();
510 for (KeyAction action : this.actions) {
668268fc 511 String trans = " " + Main.trans(action.getStringId()) + " ";
a3b510ab
NR
512
513 if (" ".equals(trans))
514 continue;
515
7da41ecd 516 String keyTrans = KeyAction.trans(action.getKey());
a3b510ab
NR
517
518 Panel kPane = new Panel();
519 LinearLayout layout = new LinearLayout(Direction.HORIZONTAL);
520 layout.setSpacing(0);
521 kPane.setLayoutManager(layout);
522
e119a1c1
NR
523 kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_KEY,
524 keyTrans));
525 kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC, trans));
a3b510ab
NR
526
527 actionPanel.addComponent(kPane);
528 }
bcb54330
NR
529
530 // fill with "desc" colour
296a0b75
NR
531 int width = -1;
532 if (getSize() != null) {
533 width = getSize().getColumns();
534 }
535
bcb54330 536 if (width > 0) {
e119a1c1
NR
537 actionPanel.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC,
538 StringUtils.padString("", width)));
bcb54330 539 }
a3b510ab
NR
540 }
541
0b0b2b0f
NR
542 /**
543 * Handle user input when in "ask for question" mode (see
f720df72 544 * {@link MainWindow#userQuestion}).
0b0b2b0f 545 *
f720df72
NR
546 * @param userQuestion
547 * the question data
0b0b2b0f
NR
548 * @param key
549 * the key that has been pressed by the user
550 *
f720df72 551 * @return TRUE if the {@link KeyStroke} was handled
0b0b2b0f 552 */
f720df72
NR
553 private boolean handleQuestion(UserQuestion userQuestion, KeyStroke key) {
554 userQuestion.setAnswer(null);
ae22c247 555
f720df72
NR
556 if (userQuestion.isOneKeyAnswer()) {
557 userQuestion.setAnswer("" + key.getCharacter());
a3b510ab 558 } else {
f720df72
NR
559 // ^h == Backspace
560 if (key.isCtrlDown() && key.getCharacter() == 'h') {
561 key = new KeyStroke(KeyType.Backspace);
562 }
563
564 switch (key.getKeyType()) {
565 case Enter:
a3b510ab 566 if (text != null)
f720df72 567 userQuestion.setAnswer(text.getText());
a3b510ab 568 else
f720df72
NR
569 userQuestion.setAnswer("");
570 break;
571 case Backspace:
572 int pos = text.getCaretPosition().getColumn();
573 if (pos > 0) {
574 String current = text.getText();
575 // force caret one space before:
576 text.setText(current.substring(0, pos - 1));
577 // re-add full text:
578 text.setText(current.substring(0, pos - 1)
579 + current.substring(pos));
580 }
581 return true;
582 default:
583 // Do nothing (continue entering text)
584 break;
a3b510ab
NR
585 }
586 }
587
f720df72 588 if (userQuestion.getAnswer() != null) {
a3b510ab 589 Interactable focus = null;
0b0b2b0f
NR
590 MainContent content = getContent();
591 if (content != null)
592 focus = content.nextFocus(null);
a3b510ab 593
fae07ea7 594 focus.takeFocus();
f720df72
NR
595
596 return true;
a3b510ab
NR
597 }
598
f720df72 599 return false;
a3b510ab
NR
600 }
601
0b0b2b0f
NR
602 /**
603 * Handle the input in case of "normal" (not "ask for answer") mode.
604 *
605 * @param key
606 * the key that was pressed
607 * @param answer
608 * the answer given for this key
609 *
bcb54330 610 * @return if the window handled the input
0b0b2b0f 611 */
296a0b75 612 private boolean handleKey(KeyStroke key) {
a3b510ab
NR
613 boolean handled = false;
614
296a0b75
NR
615 if (setMessage(null, false))
616 return true;
a3b510ab 617
0b0b2b0f
NR
618 for (KeyAction action : actions) {
619 if (!action.match(key))
620 continue;
a3b510ab 621
0b0b2b0f
NR
622 handled = true;
623
5ad0e17e
NR
624 action.getObject(); // see {@link KeyAction#getMessage()}
625 String mess = action.getMessage();
626 if (mess != null) {
627 setMessage(mess, action.isError());
628 }
629
0b0b2b0f 630 if (action.onAction()) {
296a0b75
NR
631 handleAction(action, null);
632 }
0b0b2b0f 633
296a0b75
NR
634 break;
635 }
0b0b2b0f 636
296a0b75
NR
637 return handled;
638 }
639
640 /**
641 * Handle the input in case of "normal" (not "ask for answer") mode.
642 *
643 * @param key
644 * the key that was pressed
645 * @param answer
646 * the answer given for this key
647 *
648 * @return if the window handled the input
649 */
650 private void handleAction(KeyAction action, String answer) {
651 MainContent content = getContent();
652
296a0b75
NR
653 switch (action.getMode()) {
654 case MOVE:
655 int x = 0;
656 int y = 0;
657
658 if (action.getKey().getKeyType() == KeyType.ArrowUp)
659 x = -1;
660 if (action.getKey().getKeyType() == KeyType.ArrowDown)
661 x = 1;
662 if (action.getKey().getKeyType() == KeyType.ArrowLeft)
663 y = -1;
664 if (action.getKey().getKeyType() == KeyType.ArrowRight)
665 y = 1;
666
667 if (content != null) {
668 String err = content.move(x, y);
669 if (err != null)
670 setMessage(err, true);
671 }
672
673 break;
674 // mode with windows:
675 case CONTACT_LIST:
ae22c247
NR
676 if (action.getCard() != null) {
677 pushContent(new ContactList(action.getCard()));
5ad0e17e
NR
678 } else if (action.getObject() != null
679 && action.getObject() instanceof MainContent) {
680 MainContent mergeContent = (MainContent) action.getObject();
681 pushContent(mergeContent);
296a0b75
NR
682 }
683 break;
684 case CONTACT_DETAILS:
ae22c247
NR
685 if (action.getContact() != null) {
686 pushContent(new ContactDetails(action.getContact()));
f04d8b1c
NR
687 }
688 break;
689 case CONTACT_DETAILS_RAW:
ae22c247
NR
690 if (action.getContact() != null) {
691 pushContent(new ContactDetailsRaw(action.getContact()));
296a0b75
NR
692 }
693 break;
694 // mode interpreted by MainWindow:
695 case HELP:
696 // TODO
f720df72 697 setMessage("Help! I need somebody! Help!", false);
296a0b75
NR
698
699 break;
700 case BACK:
701 String warning = content.getExitWarning();
702 if (warning != null) {
703 if (answer == null) {
704 setQuestion(action, warning);
705 } else {
706 setMessage(null, false);
707 if (answer.equalsIgnoreCase("y")) {
bcb54330 708 popContent();
a3b510ab 709 }
296a0b75
NR
710 }
711 } else {
712 popContent();
713 }
0b0b2b0f 714
296a0b75
NR
715 if (contentStack.size() == 0) {
716 close();
717 }
bcb54330 718
296a0b75
NR
719 break;
720 // action modes:
ae22c247 721 case ASK_USER:
296a0b75 722 if (answer == null) {
ae22c247
NR
723 setQuestion(action, action.getQuestion(),
724 action.getDefaultAnswer());
296a0b75 725 } else {
ae22c247
NR
726 setMessage(action.callback(answer), true);
727 content.refreshData();
728 invalidate();
729 setTitle();
296a0b75
NR
730 }
731 break;
ae22c247 732 case ASK_USER_KEY:
296a0b75 733 if (answer == null) {
ae22c247 734 setQuestion(action, action.getQuestion());
296a0b75 735 } else {
ae22c247
NR
736 setMessage(action.callback(answer), true);
737 content.refreshData();
738 invalidate();
739 setTitle();
0b0b2b0f 740 }
296a0b75
NR
741 break;
742 default:
743 case NONE:
0b0b2b0f
NR
744 break;
745 }
a3b510ab
NR
746 }
747}