package com.himamis.retex.editor.share.input;
import com.himamis.retex.editor.share.controller.CursorController;
import com.himamis.retex.editor.share.controller.EditorState;
import com.himamis.retex.editor.share.controller.InputController;
import com.himamis.retex.editor.share.editor.MathFieldInternal;
import com.himamis.retex.editor.share.input.adapter.FunctionAdapter;
import com.himamis.retex.editor.share.input.adapter.FunctionsAdapter;
import com.himamis.retex.editor.share.input.adapter.KeyboardAdapter;
import com.himamis.retex.editor.share.input.adapter.StringCharAdapter;
import com.himamis.retex.editor.share.input.adapter.StringInput;
import java.util.ArrayList;
import java.util.List;
public class KeyboardInputAdapter {
private static final char e = '\u212f';
private static final char divide = '\u00F7';
private static final char times = '\u00D7';
private static final char minus = '\u2212';
private static final List<KeyboardAdapter> adapters;
private static final KeyboardAdapter commandAdapter;
private static final String[] allowedCharacterCategories = {
Character.DECIMAL_DIGIT_NUMBER,
Character.OTHER_NUMBER,
Character.LOWERCASE_LETTER,
Character.UPPERCASE_LETTER,
Character.OTHER_LETTER,
Character.OTHER_PUNCTUATION,
Character.START_PUNCTUATION,
Character.END_PUNCTUATION,
Character.MATH_SYMBOL,
Character.CONNECTOR_PUNCTUATION,
Character.SPACE_SEPARATOR,
Character.LETTER_NUMBER,
Character.DASH_PUNCTUATION
};
static {
adapters = new ArrayList<KeyboardAdapter>();
adapters.add(new FunctionsAdapter());
adapters.add(new StringCharAdapter(divide, '/'));
adapters.add(new StringCharAdapter(times, '*'));
adapters.add(new StringCharAdapter(minus, '-'));
adapters.add(new FunctionAdapter("|", "abs"));
adapters.add(new FunctionAdapter("log_{10}", "log10"));
adapters.add(new FunctionAdapter("random"));
adapters.add(new FunctionAdapter("nroot"));
adapters.add(new StringInput("\u00B2") {
@Override
public void commit(MathFieldInternal mfi, String input) {
typeCharacter(mfi, '^');
typeCharacter(mfi, '2');
CursorController.nextCharacter(mfi.getEditorState());
}
});
adapters.add(new StringInput("\u221A") {
@Override
public void commit(MathFieldInternal mfi, String input) {
commitFunction(mfi, "sqrt");
}
});
adapters.add(new StringInput(e + "^") {
@Override
public void commit(MathFieldInternal mfi, String input) {
typeCharacter(mfi, e);
typeCharacter(mfi, '^');
}
});
adapters.add(new StringInput("logb") {
@Override
public void commit(MathFieldInternal mfi, String input) {
typeCharacter(mfi, 'l');
typeCharacter(mfi, 'o');
typeCharacter(mfi, 'g');
typeCharacter(mfi, '_');
CursorController.nextCharacter(mfi.getEditorState());
typeCharacter(mfi, '(');
mfi.getCursorController().prevCharacter(mfi.getEditorState());
mfi.getCursorController().prevCharacter(mfi.getEditorState());
}
});
adapters.add(new StringInput("10^") {
@Override
public void commit(MathFieldInternal mfi, String input) {
typeCharacter(mfi, '1');
typeCharacter(mfi, '0');
typeCharacter(mfi, '^');
}
});
adapters.add(new StringInput("a_n") {
@Override
public void commit(MathFieldInternal mfi, String input) {
typeCharacter(mfi, '_');
}
});
// Let through all one length characters!
adapters.add(new StringInput() {
@Override
public void commit(MathFieldInternal mfi, String input) {
typeCharacter(mfi, input.charAt(0));
}
@Override
public boolean test(String input) {
return input.length() == 1;
}
});
commandAdapter = new KeyboardAdapter() {
@Override
public void commit(MathFieldInternal mfi, String commandName) {
EditorState editorState = mfi.getEditorState();
InputController inputController = mfi.getInputController();
for (int i = 0; i < commandName.length(); i++) {
inputController.newCharacter(editorState, commandName.charAt(i));
}
inputController.newBraces(editorState, '(');
}
@Override
public boolean test(String input) {
return Character.areLettersOrDigits(input);
}
};
adapters.add(commandAdapter);
}
public static void insertString(final MathFieldInternal mMathFieldInternal,
String text) {
boolean oldCreateFrac = mMathFieldInternal.getInputController()
.getCreateFrac();
mMathFieldInternal.getInputController().setCreateFrac(false);
StringBuilder stringBuilder = new StringBuilder(1);
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (KeyboardInputAdapter.isValidChar(c)) {
stringBuilder.setLength(0);
stringBuilder.append(c);
KeyboardInputAdapter.onKeyboardInput(mMathFieldInternal,
stringBuilder.toString());
}
}
mMathFieldInternal.getInputController().setCreateFrac(oldCreateFrac);
mMathFieldInternal.onInsertString();
}
public static void onKeyboardInput(MathFieldInternal mathFieldInternal, String input) {
if (input == null) {
return;
}
int i = 0;
while (i < adapters.size() && !adapters.get(i).test(input)) {
i++;
}
if (i < adapters.size()) {
KeyboardAdapter adapter = adapters.get(i);
adapter.commit(mathFieldInternal, input);
mathFieldInternal.update();
} else {
// No adapter found for input
}
}
public static void onCommandInput(MathFieldInternal mathFieldInternal, String commandName) {
commandAdapter.commit(mathFieldInternal, commandName);
mathFieldInternal.update();
}
/**
* @param c
* @return true if this char can be handled
*/
static final public boolean isValidChar(char c) {
for (int i = 0; i < allowedCharacterCategories.length; i++) {
if (Character.charIsTypeOf(c, allowedCharacterCategories[i])) {
return true;
}
}
// needs check:
// ENCLOSING_MARK, CURRENCY_SYMBOL, OTHER_SYMBOL, INITIAL_QUOTE_PUNCTUATION, FINAL_QUOTE_PUNCTUATION
return true;
}
}