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