Resources system rewrite + new "--save-config DIR" option
[jvcard.git] / src / be / nikiroo / jvcard / tui / MainWindow.java
index 24e97e841f35e54db30bdda139e03cd56b1855ad..1cbc01412a77f9e7163862e85b007f07e6d3a5b5 100644 (file)
@@ -6,13 +6,11 @@ import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
-import be.nikiroo.jvcard.Card;
-import be.nikiroo.jvcard.Contact;
-import be.nikiroo.jvcard.Data;
-import be.nikiroo.jvcard.i18n.Trans;
-import be.nikiroo.jvcard.i18n.Trans.StringId;
+import be.nikiroo.jvcard.launcher.Main;
+import be.nikiroo.jvcard.resources.StringUtils;
+import be.nikiroo.jvcard.resources.enums.ColorOption;
+import be.nikiroo.jvcard.resources.enums.StringId;
 import be.nikiroo.jvcard.tui.KeyAction.Mode;
-import be.nikiroo.jvcard.tui.UiColors.Element;
 import be.nikiroo.jvcard.tui.panes.ContactDetails;
 import be.nikiroo.jvcard.tui.panes.ContactDetailsRaw;
 import be.nikiroo.jvcard.tui.panes.ContactList;
@@ -38,12 +36,12 @@ import com.googlecode.lanterna.input.KeyType;
  * @author niki
  * 
  */
+
 public class MainWindow extends BasicWindow {
        private List<KeyAction> defaultActions = new LinkedList<KeyAction>();
        private List<KeyAction> actions = new LinkedList<KeyAction>();
        private List<MainContent> contentStack = new LinkedList<MainContent>();
-       private boolean waitForOneKeyAnswer;
-       private KeyAction questionAction;
+       private UserQuestion userQuestion;
        private String titleCache;
        private Panel titlePanel;
        private Panel mainPanel;
@@ -52,6 +50,68 @@ public class MainWindow extends BasicWindow {
        private Panel messagePanel;
        private TextBox text;
 
+       /**
+        * Information about a question to ask the user and its answer.
+        * 
+        * @author niki
+        *
+        */
+       private class UserQuestion {
+               private boolean oneKeyAnswer;
+               private KeyAction action;
+               private String answer;
+
+               /**
+                * Create a new {@link UserQuestion}.
+                * 
+                * @param action
+                *            the action that triggered the question
+                * @param oneKeyAnswer
+                *            TRUE if we expect a one-key answer
+                */
+               public UserQuestion(KeyAction action, boolean oneKeyAnswer) {
+                       this.action = action;
+                       this.oneKeyAnswer = oneKeyAnswer;
+               }
+
+               /**
+                * Return the {@link KeyAction} that triggered the question.
+                * 
+                * @return the {@link KeyAction}
+                */
+               public KeyAction getAction() {
+                       return action;
+               }
+
+               /**
+                * Check if a one-key answer is expected.
+                * 
+                * @return TRUE if a one-key answer is expected
+                */
+               public boolean isOneKeyAnswer() {
+                       return oneKeyAnswer;
+               }
+
+               /**
+                * Return the user answer.
+                * 
+                * @return the user answer
+                */
+               public String getAnswer() {
+                       return answer;
+               }
+
+               /**
+                * Set the user answer.
+                * 
+                * @param answer
+                *            the new answer
+                */
+               public void setAnswer(String answer) {
+                       this.answer = answer;
+               }
+       }
+
        /**
         * Create a new, empty window.
         */
@@ -162,6 +222,16 @@ public class MainWindow extends BasicWindow {
                if (contentStack.size() > 0)
                        prev = contentStack.remove(contentStack.size() - 1);
 
+               if (prev != null) {
+                       try {
+                               String mess = prev.wakeup();
+                               if (mess != null)
+                                       setMessage(mess, false);
+                       } catch (IOException e) {
+                               setMessage(e.getMessage(), true);
+                       }
+               }
+
                pushContent(prev);
 
                return removed;
@@ -181,9 +251,9 @@ public class MainWindow extends BasicWindow {
                if (mess != null || messagePanel.getChildCount() > 0) {
                        messagePanel.removeAllComponents();
                        if (mess != null) {
-                               Element element = (error ? UiColors.Element.LINE_MESSAGE_ERR
-                                               : UiColors.Element.LINE_MESSAGE);
-                               Label lbl = element.createLabel(" " + mess + " ");
+                               ColorOption element = (error ? ColorOption.LINE_MESSAGE_ERR
+                                               : ColorOption.LINE_MESSAGE);
+                               Label lbl = UiColors.createLabel(element, " " + mess + " ");
                                messagePanel.addComponent(lbl, LinearLayout
                                                .createLayoutData(LinearLayout.Alignment.Center));
                        }
@@ -239,8 +309,7 @@ public class MainWindow extends BasicWindow {
         */
        private void setQuestion(KeyAction action, String question, String initial,
                        boolean oneKey) {
-               questionAction = action;
-               waitForOneKeyAnswer = oneKey;
+               userQuestion = new UserQuestion(action, oneKey);
 
                messagePanel.removeAllComponents();
 
@@ -249,12 +318,18 @@ public class MainWindow extends BasicWindow {
                llayout.setSpacing(0);
                hpanel.setLayoutManager(llayout);
 
-               Label lbl = UiColors.Element.LINE_MESSAGE_QUESTION.createLabel(" "
+               Label lbl = UiColors.createLabel(ColorOption.LINE_MESSAGE_QUESTION, " "
                                + question + " ");
                text = new TextBox(new TerminalSize(getSize().getColumns()
                                - lbl.getSize().getColumns(), 1));
-               if (initial != null)
-                       text.setText(initial);
+
+               if (initial != null) {
+                       // add all chars one by one so the caret is at the end
+                       for (int index = 0; index < initial.length(); index++) {
+                               text.handleInput(new KeyStroke(initial.charAt(index), false,
+                                               false));
+                       }
+               }
 
                hpanel.addComponent(lbl,
                                LinearLayout.createLayoutData(LinearLayout.Alignment.Beginning));
@@ -302,20 +377,23 @@ public class MainWindow extends BasicWindow {
        public boolean handleInput(KeyStroke key) {
                boolean handled = false;
 
-               if (questionAction != null) {
-                       String answer = handleQuestion(key);
-                       if (answer != null) {
-                               handled = true;
+               if (userQuestion != null) {
+                       handled = handleQuestion(userQuestion, key);
+                       if (handled) {
+                               if (userQuestion.getAnswer() != null) {
+                                       handleAction(userQuestion.getAction(),
+                                                       userQuestion.getAnswer());
 
-                               handleAction(questionAction, answer);
-                               questionAction = null;
+                                       userQuestion = null;
+                               }
                        }
                } else {
                        handled = handleKey(key);
                }
 
-               if (!handled)
+               if (!handled) {
                        handled = super.handleInput(key);
+               }
 
                return handled;
        }
@@ -342,8 +420,7 @@ public class MainWindow extends BasicWindow {
 
                if (title.length() > 0) {
                        prefix = prefix + ": ";
-                       title = StringUtils.sanitize(title, UiColors.getInstance()
-                                       .isUnicode());
+                       title = StringUtils.sanitize(title, Main.isUnicode());
                }
 
                String countStr = "";
@@ -374,18 +451,18 @@ public class MainWindow extends BasicWindow {
                        super.setTitle(prefix);
 
                        Label lblPrefix = new Label(prefix);
-                       UiColors.Element.TITLE_MAIN.themeLabel(lblPrefix);
+                       UiColors.themeLabel(ColorOption.TITLE_MAIN, lblPrefix);
 
                        Label lblTitle = null;
                        if (title.length() > 0) {
                                lblTitle = new Label(title);
-                               UiColors.Element.TITLE_VARIABLE.themeLabel(lblTitle);
+                               UiColors.themeLabel(ColorOption.TITLE_VARIABLE, lblTitle);
                        }
 
                        Label lblCount = null;
                        if (countStr != null) {
                                lblCount = new Label(countStr);
-                               UiColors.Element.TITLE_COUNT.themeLabel(lblCount);
+                               UiColors.themeLabel(ColorOption.TITLE_COUNT, lblCount);
                        }
 
                        titlePanel.removeAllComponents();
@@ -431,21 +508,21 @@ public class MainWindow extends BasicWindow {
 
                actionPanel.removeAllComponents();
                for (KeyAction action : this.actions) {
-                       String trans = " " + action.getStringId().trans() + " ";
+                       String trans = " " + Main.trans(action.getStringId()) + " ";
 
                        if ("  ".equals(trans))
                                continue;
 
-                       String keyTrans = Trans.getInstance().trans(action.getKey());
+                       String keyTrans = KeyAction.trans(action.getKey());
 
                        Panel kPane = new Panel();
                        LinearLayout layout = new LinearLayout(Direction.HORIZONTAL);
                        layout.setSpacing(0);
                        kPane.setLayoutManager(layout);
 
-                       kPane.addComponent(UiColors.Element.ACTION_KEY
-                                       .createLabel(keyTrans));
-                       kPane.addComponent(UiColors.Element.ACTION_DESC.createLabel(trans));
+                       kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_KEY,
+                                       keyTrans));
+                       kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC, trans));
 
                        actionPanel.addComponent(kPane);
                }
@@ -457,47 +534,69 @@ public class MainWindow extends BasicWindow {
                }
 
                if (width > 0) {
-                       actionPanel.addComponent(UiColors.Element.ACTION_DESC
-                                       .createLabel(StringUtils.padString("", width)));
+                       actionPanel.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC,
+                                       StringUtils.padString("", width)));
                }
        }
 
        /**
         * Handle user input when in "ask for question" mode (see
-        * {@link MainWindow#questionKey}).
+        * {@link MainWindow#userQuestion}).
         * 
+        * @param userQuestion
+        *            the question data
         * @param key
         *            the key that has been pressed by the user
         * 
-        * @return the user's answer if done
+        * @return TRUE if the {@link KeyStroke} was handled
         */
-       private String handleQuestion(KeyStroke key) {
-               String answer = null;
+       private boolean handleQuestion(UserQuestion userQuestion, KeyStroke key) {
+               userQuestion.setAnswer(null);
 
-               // TODO: support ^H (backspace)
-               // TODO: start at end of initial question, not start
-
-               if (waitForOneKeyAnswer) {
-                       answer = "" + key.getCharacter();
+               if (userQuestion.isOneKeyAnswer()) {
+                       userQuestion.setAnswer("" + key.getCharacter());
                } else {
-                       if (key.getKeyType() == KeyType.Enter) {
+                       // ^h == Backspace
+                       if (key.isCtrlDown() && key.getCharacter() == 'h') {
+                               key = new KeyStroke(KeyType.Backspace);
+                       }
+
+                       switch (key.getKeyType()) {
+                       case Enter:
                                if (text != null)
-                                       answer = text.getText();
+                                       userQuestion.setAnswer(text.getText());
                                else
-                                       answer = "";
+                                       userQuestion.setAnswer("");
+                               break;
+                       case Backspace:
+                               int pos = text.getCaretPosition().getColumn();
+                               if (pos > 0) {
+                                       String current = text.getText();
+                                       // force caret one space before:
+                                       text.setText(current.substring(0, pos - 1));
+                                       // re-add full text:
+                                       text.setText(current.substring(0, pos - 1)
+                                                       + current.substring(pos));
+                               }
+                               return true;
+                       default:
+                               // Do nothing (continue entering text)
+                               break;
                        }
                }
 
-               if (answer != null) {
+               if (userQuestion.getAnswer() != null) {
                        Interactable focus = null;
                        MainContent content = getContent();
                        if (content != null)
                                focus = content.nextFocus(null);
 
                        focus.takeFocus();
+
+                       return true;
                }
 
-               return answer;
+               return false;
        }
 
        /**
@@ -522,6 +621,12 @@ public class MainWindow extends BasicWindow {
 
                        handled = true;
 
+                       action.getObject(); // see {@link KeyAction#getMessage()}
+                       String mess = action.getMessage();
+                       if (mess != null) {
+                               setMessage(mess, action.isError());
+                       }
+
                        if (action.onAction()) {
                                handleAction(action, null);
                        }
@@ -570,6 +675,10 @@ public class MainWindow extends BasicWindow {
                case CONTACT_LIST:
                        if (action.getCard() != null) {
                                pushContent(new ContactList(action.getCard()));
+                       } else if (action.getObject() != null
+                                       && action.getObject() instanceof MainContent) {
+                               MainContent mergeContent = (MainContent) action.getObject();
+                               pushContent(mergeContent);
                        }
                        break;
                case CONTACT_DETAILS:
@@ -585,12 +694,7 @@ public class MainWindow extends BasicWindow {
                // mode interpreted by MainWindow:
                case HELP:
                        // TODO
-                       // setMessage("Help! I need somebody! Help!", false);
-                       if (answer == null) {
-                               setQuestion(action, "Test question?", "[initial]");
-                       } else {
-                               setMessage("You answered: " + answer, false);
-                       }
+                       setMessage("Help! I need somebody! Help!", false);
 
                        break;
                case BACK: