Package ketUI.responder

Source Code of ketUI.responder.AddResponder

/*
* Copyright (C) 2011  Alasdair C. Hamilton
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package ketUI.responder;

import java.util.Vector;
import java.awt.event.KeyEvent;

import geom.Position;
import ket.Cursor;
import ket.MathCollection;
import ket.Message;
import ket.RangeSelection;
import ket.Selection;
import ketUI.Ket;
import ketUI.MouseButton;
import ketUI.MouseEventHandler;
import ketUI.panel.KetPanel;

import ket.math.*;
import ket.math.purpose.*;
import ketUI.chord.*;
import ketUI.modes.*;


/**
* Some add chords are qualified with characters such as directions or
* parent-branch functions and these are handled together here.
*/
public class AddResponder extends Responder {

  final boolean ADD_INTERMEDIATE = true;
  final boolean APPEND = true;
  final boolean SLOW = true;

  final Modes modes;
  final MathCollection mathCollection;

  public AddResponder(Modes modes) {
    this.modes = modes;
    this.mathCollection = modes.getMathCollection();
  }

  @Override
  public void prepareToRespond() {
    // Do nothing.
  }

  @Override 
  public void cleanAfterRespond() {
    // Do nothing.
  }

  public void respondToChordEvent(Chord chord, Macros macros, KeyboardEventHandler keyboardEventHandler) {
    KeyPress keyPress = chord.getLastKeyPress();
    char character = chord.getKeyChar(-1);
    //- KnownArguments knownArguments = keyboardEventHandler.getDocument().getModes().getKnownArguments();
    boolean changed = false;
    switch (modes.getDocumentState()) {
      case MAP_QUICK_PARENT:
        if (getCurrent().isToken()) return;
        for (Argument child : getSelection().getCurrent().asBranch().getChildren()) {
          getSelection().setCurrent(child); //ish
          insertFromCharacter(chord, keyPress, character, ADD_INTERMEDIATE);
        }
        break;

      case QUICK_PARENT:
        insertFromCharacter(chord, keyPress, character, ADD_INTERMEDIATE);
        break;

      case QUICK_RENAME:
        insertFromCharacter(chord, keyPress, character, !ADD_INTERMEDIATE);
        break;

      case APPEND_BY_STRING:
        insertWithCharacter(chord, keyPress, character, APPEND, SLOW);
        break;

      case PREPEND_BY_STRING:    
        insertWithCharacter(chord, keyPress, character, !APPEND, SLOW);
        break;

      case APPEND_BY_LETTER:     
        insertWithCharacter(chord, keyPress, character, APPEND, !SLOW);
        break;

      case PREPEND_BY_LETTER:    
        insertWithCharacter(chord, keyPress, character, !APPEND, !SLOW);
        break;

      default:
        modes.setDocumentState(DocumentState.NORMAL);
    }
  }

  /**
   * A range of different insertions can be identified by a character
   * specifying either a direction or function.  This method inserts a
   * required argument given the direction and changes to the appropriate
   * mode, possibly awaiting further input.
   */
  private boolean insertWithCharacter(Chord chord, KeyPress keyPress, char character, boolean append, boolean slow) {
    if (Character.isDigit(character)) {
      int value = Integer.parseInt(""+character);
      IntegerValue integerValue = new IntegerValue(value);
      Function function = append ? Function.POWER : Function.TIMES;
      getSelection().addIntermediaryParent(function);
      mathCollection.setCursorSelection();
      if (append) {
        // Integer power
        Argument exponent = new Token(integerValue);
        getSelection().appendChild(exponent);
      } else {
        // Integer multiple
        Argument term = new Token(integerValue);
        getSelection().prependChild(term);
      }
      chord.setComplete(true);
      modes.setDocumentState(DocumentState.NORMAL);
      return true;
    }
    boolean success = insertByDirection(chord, keyPress, character, append, slow);
    if (success) {
      return true;
    }
    Function function = getKnownArguments().getFunctionByChar(character);
    if (function==null) {
      String letter = append ? "a" : "e";
      Ket.out.println(" !!! Unknown command: '"+letter+""+character+"' !!! ");
      return false;
    }
    boolean result = insertByFunction(chord, append, function, slow);
    getSelection().getCurrent().unfoldRoots();
    return result;
  }

  public KetPanel getKetPanel() {
    return modes.getDocument().getKetPanel();
  }

  /**
   * If the given character is recognised as a 'direction' such as left,
   * right, in, up, equation; then a new argument is added as
   * appropriate.
   */
  public boolean insertByDirection(Chord chord, KeyPress keyPress, char character, boolean isSiblingAppended, boolean slow) {
    String code = keyPress.getCode();
      switch (code) {
        // INFORMAL: Should be 'a<Shift-Left>' but 'feels' wrong.
        case "<Left>": // p<Left> Add a new left sibling.
          getAddMode().prependNewSibling(chord);
          if ( ! slow ) {
            modes.setDocumentState(DocumentState.QUICK_RENAME);
          }
          return true;
        case "<Right>": // p<Right> Add a new right sibling.
          getAddMode().appendNewSibling(chord);
          if ( ! slow ) {
            modes.setDocumentState(DocumentState.QUICK_RENAME);
          }
          return true;


        case "<Up>": // p<Up> Add a new equation before the current equation.
          getAddMode().prependUp(chord);
          if ( ! slow ) {
            modes.setDocumentState(DocumentState.QUICK_RENAME);
          }
          return true;
        case "<Down>": // p<Up> Append a new equation.
          getAddMode().appendDown(chord);
          if ( ! slow ) {
            modes.setDocumentState(DocumentState.QUICK_RENAME);
          }
          return true;
        case "<Space>": // 'a<Space>' Add blank line.
          Token token = new Token(new Text(""));
          Equation equation = new Equation(token);
          if (isSiblingAppended) {
            getSelection().appendEquation(equation);
          } else {
            getSelection().prependEquation(equation);
          }
          chord.setComplete(true);
          modes.setDocumentState(DocumentState.NORMAL);
          return true;
      }
    // Cases where the choice of 'a...' or 'e...' matters.
    if (isSiblingAppended) { // Append ('a...').
      switch(character) {
        case 'e': // 'ae' Append a new equation.
          getAddMode().appendEquation(chord);
          if ( ! slow ) {
            modes.setDocumentState(DocumentState.QUICK_RENAME);
          }
          return true;

        case 't': // 'at' Append a line of text.
          return getAddMode().appendTextLine(chord);

        case 'm': // 'am' Append children with an intermediate branch.
          return getAddMode().mapAppend(chord);

        case 'n': // 'an' Append grandchildren.
          return getAddMode().map2Append(chord);

        case 'p': // Add parent.
          //- return getAddMode().addIntermediaryParent(chord);
          getAddMode().appendPurpose(chord); // <--- !slow?
          return true;
      }
    } else { // Prepend ('e...').
      switch(character) {
        case 'e': // 'ee' Prepend a new equation.
          getAddMode().prependEquation(chord);
          if ( ! slow ) {
            modes.setDocumentState(DocumentState.QUICK_RENAME);
          }
          return true;

        case 't': // 'at' Append a line of text.
          return getAddMode().prependTextLine(chord);

        case 'm': // 'em' Prepend children with an intermediate branch.
          return getAddMode().mapPrepend(chord); // <--- !slow?
        case 'n': // 'en' Prepend grandchildren.
          return getAddMode().map2Prepend(chord);

        case 'p': // Add parent.
          return getAddMode().prependPurpose(chord); // <--- !slow?
      }
    }

    // TODO: Split this into 'a...' and 'e...' apart for specific commands.
    switch(character) {
      case '"': // 'a"' Replace selection as text.
        return getAddMode().replaceTextLine(chord);

      case '.': // 'a." Replace current argument.
        return getNormalMode().replaceCurrentArgument(chord);

      case 'a': // 'aa" Replace current equation.
        getCursor().selectVisibleRoot();
        return getNormalMode().replaceCurrentArgument(chord);

      case 'j': // 'aj' Append a new equation.
        getAddMode().appendDown(chord);
        if ( ! slow ) {
          modes.setDocumentState(DocumentState.QUICK_RENAME);
        }
        return true;

      case 'k': // 'ak' Add a new equation before the current equation.
        getAddMode().prependUp(chord);
        if ( ! slow ) {
          modes.setDocumentState(DocumentState.QUICK_RENAME);
        }
        return true;

      case 'h': // 'ah' Add a new left sibling.
        getAddMode().prependNewSibling(chord);
        if ( ! slow ) {
          modes.setDocumentState(DocumentState.QUICK_RENAME);
        }
        return true;

      case 'l': // 'al' Add a new right sibling.
        getAddMode().appendNewSibling(chord);
        if ( ! slow ) {
          modes.setDocumentState(DocumentState.QUICK_RENAME);
        }
        return true;

      case 'i': // 'ai' Add a new left child to the current function.
        getAddMode().prependNewChild(chord);
        if ( ! slow ) {
          modes.setDocumentState(DocumentState.QUICK_RENAME);
        }
        return true;

      case 'o': // 'ao' Append a new child to the right of the current argument.
        getAddMode().appendNewChild(chord);
        if ( ! slow ) {
          modes.setDocumentState(DocumentState.QUICK_RENAME);
        }
        return true;

      default:
        // This is an exception: the chord need not be
        // complete on leaving this method!
        return false;
    }
  }


  /**
   * Add a new intermediate parent branch of the given function and
   * append/prepend a new sibling to be specified as a string (slow) or
   * character (otherwise).
   */
  public boolean insertByFunction(Chord chord, boolean isSiblingAppended, Function function, boolean slow) {
    boolean multiple = mathCollection.isRangeSelectionSet();
    if (multiple) {
      Parent currentParent = getCurrent().getParent();
      if (currentParent instanceof Branch) {
        Branch parentBranch = (Branch) currentParent;
        Function parentFunction = parentBranch.getFunction();
        getSelection().addIntermediaryParent(parentFunction);
      }
    }
    getSelection().addIntermediaryParent(function);
    mathCollection.setCursorSelection();
    if (isSiblingAppended) {
      getSelection().appendNewChild();
    } else {
      getSelection().prependNewChild();
    }
    if (slow) {
      modes.setDocumentState(DocumentState.UPDATE_REPLACE);
    } else {
      modes.setDocumentState(DocumentState.QUICK_RENAME);
    }
    chord.setComplete(false);
    return true;
  }

  /**
   * Insert a new branch with the function type specified by character.
   */
  private boolean insertFromCharacter(Chord chord, KeyPress keyPress, char character, boolean addIntermediate) {
    chord.setComplete(true);
    boolean multiple = mathCollection.isRangeSelectionSet();
   
    if (character=='"' && multiple) {
      RangeSelection range = (RangeSelection) getSelection();
      Vector<Argument> roots = range.getSubbranchRoots();
      String string = "";
      for (Argument a : roots) {
        Purpose p = getCurrent().getPurpose();
        if (p instanceof Value) {
          string += ((Value) p).getValue(); // i.e. unquoted
        } else {
          string += p.toString();
        }
      }
      Token replacement = new Token(new Text(string));
      if (range.areMultipleEquationsSelected()) {
        // Remove all but one equation and replace it.
        Vector<Equation> selectedEquations = range.getSelectedEquations();
        range.setOnly(selectedEquations.firstElement().getRoot());
        for (int i=1; i<selectedEquations.size(); i++) {
          selectedEquations.get(i).removeEquation();
        }
      } else {
        // Remove all but one roots and replace it with:
        Vector<Argument> subbranchRoots = range.getSubbranchRoots();
        range.setOnly(subbranchRoots.firstElement());
        for (int i=1; i<subbranchRoots.size(); i++) {
          subbranchRoots.get(i).remove();
        }
      }
      getSelection().replace(replacement); // Now a cursor selection.
      return true;
    }
    // Replace a token's state?
    if (getCurrent() instanceof Token && !multiple && !addIntermediate) {
      return quickReplaceState(chord, character);
    }
    // Otherwise replace the function of a branch:
    Branch original = null;
    Function replacement = replaceBySpecialCharacter(character, addIntermediate, multiple);
    if (addIntermediate || multiple) {
      // Adds intermediate as requested or to ensures a common parent.
      // TODO: In multiple selection model use the first root's parent function.
      original = getSelection().addIntermediaryParent(null);
    } else {
      original = getCursor().asBranch();
    }
    if (replacement==null) {
      // Be clearer when you use '_' to replace an argument with a letter.
      Argument substitution = new Token(new Word("" + character));
      original.replace(substitution);
      setOnly(substitution);
      return true;
    }
    original.unfoldRoots();
    if (original!=null) {
      original.setFunction(replacement);
      return true;
    } else {
      Ket.out.println(" !!! Can't add modify a token's function !!!");
      return false;
    }
  }

  // Look for special function types:
  public Function replaceBySpecialCharacter(char character, boolean addIntermediate, boolean multiple) {
    switch (character) {
      case '~':
        Function function = getReferenceFunction(addIntermediate, multiple);
        //- return function!=null ? function.getInverse() : null;
        return function!=null ? Type.getInverse(function) : null;

      case ' ':
        return getReferenceFunction(addIntermediate, multiple);

      default:
        return getKnownArguments().getFunctionByChar(character);
    }
  }

  // Identify an original function for future reference.
  private Function getReferenceFunction(boolean addIntermediate, boolean multiple) {
    if (multiple) {
      // TODO: Move this part to multiple selection model?
      RangeSelection msm = mathCollection.getRangeSelection();
      ArgumentRange argumentRange = msm.getArgumentRange();
      Vector<Argument> roots = argumentRange.getSubbranchRoots();
      if (roots!=null && roots.size()>=1) {
        Argument first = roots.firstElement();
        Parent parent = first.getParent();
        if (parent instanceof Branch) {
          return ((Branch) parent).getFunction();
        }
      }
      return null;
    } else {
      Branch branch = getCursor().asBranch();
      return branch!=null ? branch.getFunction() : null;
    }
  }

  public boolean quickReplaceState(Chord chord, char character) {
    // Replace token with a number, letter or a symbol.
    if (Character.isDigit(character)) {
      // TODO: This code isn't reachable as
      // all normal-mode numbers are
      // interpreted as part of the count
      // rather than only those preceding
      // non-numbers:  Fix this.
      int value = Integer.parseInt(""+character);
      IntegerValue integerValue = new IntegerValue(value);
      //- currentToken.setState(integerValue);
      getSelection().replace(new Token(integerValue));
      return true;
    } else if (Character.isLetter(character)) {
      Word word = new Word(""+character);
      getSelection().replace(new VariableToken(word));
      //- getCursor().validate();
      return true;
    } else {
      getSelection().replace(new VariableToken(Symbol.UNKNOWN));
      return true;
    }
  }

  @Override 
  public void respondToMouseClick(MouseButton mouseButton, boolean singleClick, Position p) {
  }
 
  @Override
  public void respondToMouseDrag(MouseButton mouseButton, Position initial, Position release) {
  } 

 
  // --------------------------- KEEP THE FOLLOWING? ---------------------------

  private KnownArguments getKnownArguments() {
    return mathCollection.getKnownArguments();
  }

  private Argument getCurrent() {
    return getSelection().getCurrent();
  }

  private void setOnly(Argument selection) {
    getSelection().setOnly(selection);
  }

  private Selection getSelection() {
    return modes.getSelection();
  }

  private AddMode getAddMode() {
    return modes.getAddMode();
  }
 
  private NormalMode getNormalMode() {
    return modes.getNormalMode();
  }

  private Cursor getCursor() {
    return mathCollection.getCursor();
  }
}
TOP

Related Classes of ketUI.responder.AddResponder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.