New launcher class to start all 3 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
7da41ecd
NR
8import be.nikiroo.jvcard.launcher.Main;
9import be.nikiroo.jvcard.resources.StringUtils;
10import be.nikiroo.jvcard.resources.Trans.StringId;
a3b510ab
NR
11import be.nikiroo.jvcard.tui.KeyAction.Mode;
12import be.nikiroo.jvcard.tui.UiColors.Element;
f04d8b1c 13import be.nikiroo.jvcard.tui.panes.ContactDetails;
296a0b75 14import be.nikiroo.jvcard.tui.panes.ContactDetailsRaw;
fae07ea7
NR
15import be.nikiroo.jvcard.tui.panes.ContactList;
16import be.nikiroo.jvcard.tui.panes.MainContent;
a3b510ab
NR
17
18import com.googlecode.lanterna.TerminalSize;
19import com.googlecode.lanterna.gui2.BasicWindow;
20import com.googlecode.lanterna.gui2.BorderLayout;
21import com.googlecode.lanterna.gui2.Direction;
22import com.googlecode.lanterna.gui2.Interactable;
23import com.googlecode.lanterna.gui2.Label;
24import com.googlecode.lanterna.gui2.LinearLayout;
25import com.googlecode.lanterna.gui2.Panel;
26import com.googlecode.lanterna.gui2.TextBox;
a3b510ab
NR
27import com.googlecode.lanterna.gui2.Window;
28import com.googlecode.lanterna.input.KeyStroke;
29import com.googlecode.lanterna.input.KeyType;
30
31/**
0b0b2b0f
NR
32 * This is the main "window" of the program. It can show up to one
33 * {@link MainContent} at any one time, but keeps a stack of contents.
a3b510ab
NR
34 *
35 * @author niki
36 *
37 */
f720df72 38
a3b510ab
NR
39public class MainWindow extends BasicWindow {
40 private List<KeyAction> defaultActions = new LinkedList<KeyAction>();
41 private List<KeyAction> actions = new LinkedList<KeyAction>();
0b0b2b0f 42 private List<MainContent> contentStack = new LinkedList<MainContent>();
f720df72 43 private UserQuestion userQuestion;
bcb54330 44 private String titleCache;
a3b510ab
NR
45 private Panel titlePanel;
46 private Panel mainPanel;
47 private Panel contentPanel;
48 private Panel actionPanel;
49 private Panel messagePanel;
50 private TextBox text;
51
f720df72
NR
52 /**
53 * Information about a question to ask the user and its answer.
54 *
55 * @author niki
56 *
57 */
58 private class UserQuestion {
59 private boolean oneKeyAnswer;
60 private KeyAction action;
61 private String answer;
62
63 /**
64 * Create a new {@link UserQuestion}.
65 *
66 * @param action
67 * the action that triggered the question
68 * @param oneKeyAnswer
69 * TRUE if we expect a one-key answer
70 */
71 public UserQuestion(KeyAction action, boolean oneKeyAnswer) {
72 this.action = action;
73 this.oneKeyAnswer = oneKeyAnswer;
74 }
75
76 /**
77 * Return the {@link KeyAction} that triggered the question.
78 *
79 * @return the {@link KeyAction}
80 */
81 public KeyAction getAction() {
82 return action;
83 }
84
85 /**
86 * Check if a one-key answer is expected.
87 *
88 * @return TRUE if a one-key answer is expected
89 */
90 public boolean isOneKeyAnswer() {
91 return oneKeyAnswer;
92 }
93
94 /**
95 * Return the user answer.
96 *
97 * @return the user answer
98 */
99 public String getAnswer() {
100 return answer;
101 }
102
103 /**
104 * Set the user answer.
105 *
106 * @param answer
107 * the new answer
108 */
109 public void setAnswer(String answer) {
110 this.answer = answer;
111 }
112 }
113
0b0b2b0f
NR
114 /**
115 * Create a new, empty window.
116 */
a3b510ab
NR
117 public MainWindow() {
118 this(null);
119 }
120
0b0b2b0f
NR
121 /**
122 * Create a new window hosting the given content.
123 *
124 * @param content
125 * the content to host
126 */
a3b510ab
NR
127 public MainWindow(MainContent content) {
128 super(content == null ? "" : content.getTitle());
129
130 setHints(Arrays.asList(Window.Hint.FULL_SCREEN,
131 Window.Hint.NO_DECORATIONS, Window.Hint.FIT_TERMINAL_WINDOW));
132
133 defaultActions.add(new KeyAction(Mode.BACK, 'q',
134 StringId.KEY_ACTION_BACK));
135 defaultActions.add(new KeyAction(Mode.BACK, KeyType.Escape,
136 StringId.NULL));
137 defaultActions.add(new KeyAction(Mode.HELP, 'h',
138 StringId.KEY_ACTION_HELP));
139 defaultActions.add(new KeyAction(Mode.HELP, KeyType.F1, StringId.NULL));
140
141 actionPanel = new Panel();
142 contentPanel = new Panel();
143 mainPanel = new Panel();
144 messagePanel = new Panel();
145 titlePanel = new Panel();
146
147 Panel actionMessagePanel = new Panel();
148
149 LinearLayout llayout = new LinearLayout(Direction.HORIZONTAL);
150 llayout.setSpacing(0);
151 actionPanel.setLayoutManager(llayout);
152
0b0b2b0f
NR
153 BorderLayout blayout = new BorderLayout();
154 titlePanel.setLayoutManager(blayout);
a3b510ab
NR
155
156 llayout = new LinearLayout(Direction.VERTICAL);
157 llayout.setSpacing(0);
158 messagePanel.setLayoutManager(llayout);
159
0b0b2b0f 160 blayout = new BorderLayout();
a3b510ab
NR
161 mainPanel.setLayoutManager(blayout);
162
163 blayout = new BorderLayout();
164 contentPanel.setLayoutManager(blayout);
165
166 blayout = new BorderLayout();
167 actionMessagePanel.setLayoutManager(blayout);
168
169 actionMessagePanel
170 .addComponent(messagePanel, BorderLayout.Location.TOP);
171 actionMessagePanel.addComponent(actionPanel,
172 BorderLayout.Location.CENTER);
173
174 mainPanel.addComponent(titlePanel, BorderLayout.Location.TOP);
175 mainPanel.addComponent(contentPanel, BorderLayout.Location.CENTER);
176 mainPanel
177 .addComponent(actionMessagePanel, BorderLayout.Location.BOTTOM);
178
179 pushContent(content);
180
181 setComponent(mainPanel);
182 }
183
0b0b2b0f
NR
184 /**
185 * "push" some content to the window stack.
186 *
187 * @param content
188 * the new top-of-the-stack content
189 */
a3b510ab
NR
190 public void pushContent(MainContent content) {
191 List<KeyAction> actions = null;
a3b510ab
NR
192
193 contentPanel.removeAllComponents();
194 if (content != null) {
a3b510ab
NR
195 actions = content.getKeyBindings();
196 contentPanel.addComponent(content, BorderLayout.Location.CENTER);
0b0b2b0f 197 this.contentStack.add(content);
9c8baf0c
NR
198
199 Interactable focus = content.nextFocus(null);
200 if (focus != null)
201 focus.takeFocus();
a3b510ab
NR
202 }
203
bcb54330 204 setTitle();
0b0b2b0f 205 setActions(actions, true);
a3b510ab
NR
206 }
207
0b0b2b0f
NR
208 /**
209 * "pop" the latest, top-of-the-stack content from the window stack.
210 *
211 * @return the removed content if any
212 */
9c8baf0c
NR
213 public MainContent popContent() {
214 MainContent removed = null;
215 MainContent prev = null;
9c8baf0c 216
0b0b2b0f
NR
217 MainContent content = getContent();
218 if (content != null)
219 removed = contentStack.remove(contentStack.size() - 1);
9c8baf0c 220
0b0b2b0f
NR
221 if (contentStack.size() > 0)
222 prev = contentStack.remove(contentStack.size() - 1);
a3b510ab 223
0b0b2b0f 224 pushContent(prev);
a3b510ab 225
0b0b2b0f 226 return removed;
a3b510ab
NR
227 }
228
9c8baf0c
NR
229 /**
230 * Show the given message on screen. It will disappear at the next action.
231 *
232 * @param mess
233 * the message to display
234 * @param error
235 * TRUE for an error message, FALSE for an information message
bcb54330
NR
236 *
237 * @return TRUE if changes were performed
9c8baf0c 238 */
bcb54330
NR
239 public boolean setMessage(String mess, boolean error) {
240 if (mess != null || messagePanel.getChildCount() > 0) {
241 messagePanel.removeAllComponents();
242 if (mess != null) {
243 Element element = (error ? UiColors.Element.LINE_MESSAGE_ERR
244 : UiColors.Element.LINE_MESSAGE);
245 Label lbl = element.createLabel(" " + mess + " ");
246 messagePanel.addComponent(lbl, LinearLayout
247 .createLayoutData(LinearLayout.Alignment.Center));
248 }
249 return true;
250 }
251
252 return false;
253 }
254
255 /**
256 * Show a question to the user and switch to "ask for answer" mode see
257 * {@link MainWindow#handleQuestion}. The user will be asked to enter some
258 * answer and confirm with ENTER.
259 *
296a0b75
NR
260 * @param action
261 * the related action
bcb54330
NR
262 * @param question
263 * the question to ask
264 * @param initial
265 * the initial answer if any (to be edited by the user)
266 */
296a0b75
NR
267 public void setQuestion(KeyAction action, String question, String initial) {
268 setQuestion(action, question, initial, false);
bcb54330
NR
269 }
270
271 /**
272 * Show a question to the user and switch to "ask for answer" mode see
273 * {@link MainWindow#handleQuestion}. The user will be asked to hit one key
274 * as an answer.
275 *
296a0b75
NR
276 * @param action
277 * the related action
bcb54330
NR
278 * @param question
279 * the question to ask
280 */
296a0b75
NR
281 public void setQuestion(KeyAction action, String question) {
282 setQuestion(action, question, null, true);
9c8baf0c
NR
283 }
284
0b0b2b0f
NR
285 /**
286 * Show a question to the user and switch to "ask for answer" mode see
287 * {@link MainWindow#handleQuestion}.
288 *
296a0b75
NR
289 * @param action
290 * the related action
bcb54330
NR
291 * @param question
292 * the question to ask
293 * @param initial
294 * the initial answer if any (to be edited by the user)
0b0b2b0f
NR
295 * @param oneKey
296 * TRUE for a one-key answer, FALSE for a text answer validated
297 * by ENTER
298 */
296a0b75 299 private void setQuestion(KeyAction action, String question, String initial,
bcb54330 300 boolean oneKey) {
f720df72 301 userQuestion = new UserQuestion(action, oneKey);
0b0b2b0f 302
9c8baf0c 303 messagePanel.removeAllComponents();
9c8baf0c 304
0b0b2b0f
NR
305 Panel hpanel = new Panel();
306 LinearLayout llayout = new LinearLayout(Direction.HORIZONTAL);
307 llayout.setSpacing(0);
308 hpanel.setLayoutManager(llayout);
9c8baf0c 309
0b0b2b0f 310 Label lbl = UiColors.Element.LINE_MESSAGE_QUESTION.createLabel(" "
bcb54330 311 + question + " ");
296a0b75
NR
312 text = new TextBox(new TerminalSize(getSize().getColumns()
313 - lbl.getSize().getColumns(), 1));
f720df72
NR
314
315 if (initial != null) {
316 // add all chars one by one so the caret is at the end
317 for (int index = 0; index < initial.length(); index++) {
318 text.handleInput(new KeyStroke(initial.charAt(index), false,
319 false));
320 }
321 }
9c8baf0c 322
bcb54330
NR
323 hpanel.addComponent(lbl,
324 LinearLayout.createLayoutData(LinearLayout.Alignment.Beginning));
325 hpanel.addComponent(text,
326 LinearLayout.createLayoutData(LinearLayout.Alignment.Fill));
9c8baf0c 327
bcb54330
NR
328 messagePanel
329 .addComponent(hpanel, LinearLayout
330 .createLayoutData(LinearLayout.Alignment.Beginning));
9c8baf0c 331
0b0b2b0f 332 text.takeFocus();
9c8baf0c
NR
333 }
334
296a0b75
NR
335 /**
336 * Refresh the window and the empty-space handling. You should call this
337 * method when the window size changed.
338 *
339 * @param size
340 * the new size of the window
341 */
342 public void refresh(TerminalSize size) {
343 if (size == null)
344 return;
345
346 if (getSize() == null || !getSize().equals(size))
347 setSize(size);
348
349 setTitle();
350
351 if (actions != null)
352 setActions(new ArrayList<KeyAction>(actions), false);
353
354 invalidate();
355 }
356
357 @Override
358 public void invalidate() {
359 super.invalidate();
360 for (MainContent content : contentStack) {
361 content.invalidate();
362 }
363 }
364
365 @Override
366 public boolean handleInput(KeyStroke key) {
367 boolean handled = false;
368
f720df72
NR
369 if (userQuestion != null) {
370 handled = handleQuestion(userQuestion, key);
371 if (handled) {
372 if (userQuestion.getAnswer() != null) {
373 handleAction(userQuestion.getAction(),
374 userQuestion.getAnswer());
296a0b75 375
f720df72
NR
376 userQuestion = null;
377 }
296a0b75
NR
378 }
379 } else {
380 handled = handleKey(key);
381 }
382
f720df72 383 if (!handled) {
296a0b75 384 handled = super.handleInput(key);
f720df72 385 }
296a0b75
NR
386
387 return handled;
388 }
389
bcb54330
NR
390 /**
391 * Actually set the title <b>inside</b> the window. Will also call
296a0b75 392 * {@link BasicWindow#setTitle} with the computed parameters.
bcb54330
NR
393 */
394 private void setTitle() {
0b0b2b0f
NR
395 String prefix = " " + Main.APPLICATION_TITLE + " (version "
396 + Main.APPLICATION_VERSION + ")";
397
bcb54330 398 String title = null;
0b0b2b0f 399 int count = -1;
bcb54330 400
0b0b2b0f 401 MainContent content = getContent();
bcb54330
NR
402 if (content != null) {
403 title = content.getTitle();
0b0b2b0f 404 count = content.getCount();
bcb54330
NR
405 }
406
407 if (title == null)
408 title = "";
0b0b2b0f 409
bcb54330 410 if (title.length() > 0) {
0b0b2b0f 411 prefix = prefix + ": ";
7da41ecd 412 title = StringUtils.sanitize(title, Main.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) {
668268fc 500 String trans = " " + Main.trans(action.getStringId()) + " ";
a3b510ab
NR
501
502 if (" ".equals(trans))
503 continue;
504
7da41ecd 505 String keyTrans = KeyAction.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}