package com.himamis.retex.editor.share.controller; import java.util.ArrayList; import com.himamis.retex.editor.share.model.MathArray; import com.himamis.retex.editor.share.model.MathCharacter; import com.himamis.retex.editor.share.model.MathComponent; import com.himamis.retex.editor.share.model.MathContainer; import com.himamis.retex.editor.share.model.MathFunction; import com.himamis.retex.editor.share.model.MathSequence; public class CursorController { /** Next character -> key. */ public static boolean nextCharacter(EditorState editorState) { int currentOffset = editorState.getCurrentOffset(); MathSequence currentField = editorState.getCurrentField(); if (currentOffset < currentField.size() && currentField.getArgument(currentOffset) != null && currentField.getArgument(currentOffset) instanceof MathContainer && ((MathContainer) currentField.getArgument(currentOffset)).hasChildren()) { MathComponent component = currentField.getArgument(currentOffset); firstField(editorState, (MathContainer) component); return true; } else if (currentOffset < currentField.size()) { editorState.incCurrentOffset(); return true; } else { return nextField(editorState); } } /** Previous character <- key. */ public void prevCharacter(EditorState editorState) { int currentOffset = editorState.getCurrentOffset(); MathSequence currentField = editorState.getCurrentField(); if (currentOffset - 1 >= 0 && currentField.getArgument(currentOffset - 1) != null && currentField.getArgument(currentOffset - 1) instanceof MathContainer && ((MathContainer) currentField.getArgument(currentOffset - 1)).hasChildren()) { MathComponent component = currentField.getArgument(currentOffset - 1); lastField(editorState, (MathContainer) component); } else if (currentOffset > 0) { editorState.decCurrentOffset(); } else { prevField(editorState); } } public static void firstField(EditorState editorState) { firstField(editorState, editorState.getRootComponent()); } public static void firstField(EditorState editorState, MathContainer component0) { MathContainer component = component0; // surface to first symbol while (!(component instanceof MathSequence)) { int current = component.first(); component = (MathContainer) component.getArgument(current); } editorState.setCurrentField((MathSequence) component); editorState.setCurrentOffset(0); } public static void lastField(EditorState editorState) { lastField(editorState, editorState.getRootComponent()); } public static void lastField(EditorState editorState, MathContainer component0) { MathContainer component = component0; // surface to last symbol while (!(component instanceof MathSequence)) { int current = component.last(); component = (MathContainer) component.getArgument(current); } editorState.setCurrentField((MathSequence) component); editorState.setCurrentOffset(component.size()); } public static boolean nextField(EditorState editorState) { return nextField(editorState, editorState.getCurrentField()); } public static boolean nextField(EditorState editorState, MathContainer component) { // retrieve parent MathContainer container = component.getParent(); int current = component.getParentIndex(); if (container == null) { // this component has no parent // previous component doesn't exist // no-op return false; } else if (container instanceof MathSequence) { editorState.setCurrentField((MathSequence) container); editorState.setCurrentOffset(component.getParentIndex() + 1); return container.size() > component.getParentIndex(); // try to find next sibling } else if (container.hasNext(current)) { current = container.next(current); MathContainer component1 = (MathContainer) container .getArgument(current); firstField(editorState, component1); return true; // try to delve down the tree } else { return nextField(editorState, container); } } /** Find previous field. */ public void prevField(EditorState editorState) { prevField(editorState, editorState.getCurrentField()); } /* Search for previous component */ private void prevField(EditorState editorState, MathContainer component) { // retrieve parent MathContainer container = component.getParent(); int current = component.getParentIndex(); if (container == null) { // this component has no parent // previous component doesn't exist // no-op // try sequence } else if (container instanceof MathSequence) { editorState.setCurrentField((MathSequence) container); editorState.setCurrentOffset(component.getParentIndex()); // try to find previous sibling } else if (container.hasPrev(current)) { current = container.prev(current); MathContainer component1 = (MathContainer) container .getArgument(current); lastField(editorState, component1); // delve down the tree } else { prevField(editorState, container); } } /** Up field. */ public boolean upField(EditorState editorState) { return upField(editorState, editorState.getCurrentField()); } /** Down field. */ public boolean downField(EditorState editorState) { return downField(editorState, editorState.getCurrentField()); } /** Up field. */ private boolean upField(EditorState editorState, MathContainer component) { if (component instanceof MathSequence) { if (component.getParent() instanceof MathFunction) { MathFunction function = (MathFunction) component.getParent(); int upIndex = function.getUpIndex(component.getParentIndex()); if (upIndex >= 0) { editorState.setCurrentField(function.getArgument(upIndex)); editorState.setCurrentOffset(0); return true; } } } if (checkMoveArray(component, editorState, -1)) { return true; } if (component.getParent() != null) { return upField(editorState, component.getParent()); } return false; } /** Down field. */ private boolean downField(EditorState editorState, MathContainer component) { if (component instanceof MathSequence) { if (component.getParent() instanceof MathFunction) { MathFunction function = (MathFunction) component.getParent(); int downIndex = function.getDownIndex(component.getParentIndex()); if (downIndex >= 0) { editorState.setCurrentField(function.getArgument(downIndex)); editorState.setCurrentOffset(0); return true; } } // matrix goes here } if (checkMoveArray(component, editorState, +1)) { return true; } if (component.getParent() != null) { return downField(editorState, component.getParent()); } return false; } private static boolean checkMoveArray(MathComponent component, EditorState editorState, int rowChange) { if (component.getParent() instanceof MathArray) { MathArray function = (MathArray) component.getParent(); if (function.rows() > 1) { int downIndex = component.getParentIndex() + function.columns() * rowChange; if (downIndex < function.size()) { editorState .setCurrentField(function.getArgument(downIndex)); editorState.setCurrentOffset(0); return true; } } } return false; } /** * set position in editor state from tree path * * @param list * tree path * @param ct * starting container * @param editorState */ public static void setPath(ArrayList<Integer> list, MathContainer ct, EditorState editorState) { MathContainer current = ct; int i = list.size() - 1; while (i >=0) { int index = list.get(i); if (index < current.size()) { MathComponent child = current.getArgument(index); if (child instanceof MathCharacter){ editorState.setCurrentField((MathSequence) current); editorState.setCurrentOffset(index); return; }else if (child instanceof MathSequence) { current = (MathSequence) child; i--; } else { i--; current = (MathSequence) ((MathContainer) child).getArgument(list.get(i)); i--; } } else if (index == current.size()){ editorState.setCurrentField((MathSequence) current); editorState.setCurrentOffset(index); return; } else { return; } } } /** * set position in editor state from tree path, starting at root component * @param list tree path * @param editorState */ public static void setPath(ArrayList<Integer> list, EditorState editorState) { editorState.setCurrentOffset(0); setPath(list, editorState.getRootComponent(), editorState); } public static ArrayList<Integer> getPath(EditorState editorState){ ArrayList<Integer> path = new ArrayList<Integer>(); path.add(editorState.getCurrentOffset()); MathContainer field = editorState.getCurrentField(); MathContainer parent = field.getParent(); while (parent != null){ path.add(field.getParentIndex()); field = parent; parent = field.getParent(); } return path; } public void update() { // TODO Auto-generated method stub } }