isac-java/src/java/isac/gui/mawen/editor/EditingUtil.scala
author Walther Neuper <wneuper@ist.tugraz.at>
Wed, 06 Sep 2017 13:45:58 +0200
changeset 5199 3799cb07f123
parent 5183 a85c7ff660d9
child 5203 8fcdb69044d9
permissions -rw-r--r--
reformat package isac.gui.mawen.editor
     1 package isac.gui.mawen.editor
     2 
     3 import isac.gui.mawen.syntax.Ast._
     4 import isac.gui.mawen.syntax.Ast
     5 import java.awt.event.KeyEvent
     6 
     7 /**
     8  * Edit a formulas listening to key events
     9  * according to a state-transition-system
    10  * described in mmahringer Fig.TODO.TODOWN.
    11  */
    12 object EditingUtil {
    13   
    14   def parse(c: AstContainer, inputCode: Int) : Unit =  {
    15     val cursorAst = AstInfoUtil.FindCursor(c.getAst()) 
    16     val cursorAstElem = AstInfoUtil.AstOfCursor(cursorAst)
    17     findState(c, cursorAst, inputCode) match {
    18       case Some(ast) => c.setAst(TransformAstUtil.Update(c.getAst(), cursorAst, TransformAstUtil.ReplaceCursor(ast)))
    19       case None => {}
    20     }
    21   }
    22   def findState(c: AstContainer, cursorAst: Ast, inputCode: Int) : Option[Ast] = cursorAst match {
    23     case Appl(List(Variable(str), Constant("CURSOR"))) if str forall Character.isDigit  => numberState(AstInfoUtil.AstOfCursor(cursorAst), inputCode) match {
    24       case Some(ast) => Some(ast)
    25       case None => startState(c, inputCode, cursorAst)
    26     }
    27     case Appl(List(a, Constant("CURSOR"))) => identState(AstInfoUtil.AstOfCursor(cursorAst), inputCode) match {
    28       case Some(ast) => Some(ast)
    29       case None => startState(c, inputCode, cursorAst)
    30     }case Appl(List(Constant("CURSOR"), Constant("GAP"))) => identState(AstInfoUtil.AstOfCursor(cursorAst), inputCode)
    31     case _ => startState(c, inputCode, cursorAst)
    32   }
    33   
    34   def startState(c: AstContainer, inputCode: Int, cursorAst: Ast) : Option[Ast] = {
    35     println("startstate")
    36     if (isActionCode(inputCode)) {
    37       println("action")
    38       return ActionState(c, -inputCode, cursorAst)
    39     } else if (isDelim(inputCode) ) {
    40       return delimerState(c, inputCode.toChar , cursorAst)
    41     }
    42     return None
    43   }
    44   def identState(cursorAstElem: Ast, inputCode: Int) = cursorAstElem match {
    45     case Variable(str) if isIdentifier(inputCode) || isNumber(inputCode) => Some(Appl(List(Variable(str + inputCode.toChar), Constant("CURSOR"))))
    46     case Constant("GAP") if isIdentifier(inputCode) || isNumber(inputCode) => Some(Appl(List(Variable("" + inputCode.toChar), Constant("CURSOR"))))
    47     case Variable(str) if inputCode == -KeyEvent.VK_BACK_SPACE && str.length() == 1 => Some(Appl(List(Constant("CURSOR"), Constant("GAP"))))
    48     case Variable(str) if inputCode == -KeyEvent.VK_BACK_SPACE => Some(Appl(List(Variable(str.slice(0, str.length - 1)), Constant("CURSOR"))))
    49     case _ => None
    50   }
    51   def numberState(cursorAstElem: Ast, inputCode: Int) : Option[Ast] = cursorAstElem match {
    52     case Variable(str) if (isNumber(inputCode.toChar))                             =>  Some(Appl(List(Variable(str + inputCode.toChar), Constant("CURSOR"))))
    53     case Constant("GAP") if isIdentifier(inputCode) || isNumber(inputCode)         => Some(Appl(List(Variable("" + inputCode.toChar), Constant("CURSOR"))))
    54     case Variable(str) if inputCode == -KeyEvent.VK_BACK_SPACE && str.length() == 1 => Some(Appl(List(Constant("CURSOR"), Constant("GAP"))))
    55     case Variable(str) if inputCode == -KeyEvent.VK_BACK_SPACE                      => Some(Appl(List(Variable(str.slice(0, str.length - 1)), Constant("CURSOR"))))
    56     case _ => {
    57       println("none")
    58       None
    59     }
    60   }
    61   def ActionState(c: AstContainer, code: Int, cursorAst: Ast) : Option[Ast] = code match {
    62     case KeyEvent.VK_RIGHT => TransformAstUtil.CursorNextChild(c); None
    63     case KeyEvent.VK_LEFT => TransformAstUtil.CursorPrevChild(c); None
    64     case KeyEvent.VK_UP => TransformAstUtil.CursorParent(c); None
    65     case KeyEvent.VK_DOWN => TransformAstUtil.CursorChild(c); None
    66     case KeyEvent.VK_ENTER => cursorAst match {
    67       case Appl(List(Constant("CURSOR"), a)) => Some(a)
    68       case Appl(List(a, Constant("CURSOR"))) => Some(a)
    69       case _ => None
    70     }
    71     case KeyEvent.VK_DELETE => Some(Appl(List(Constant("CURSOR"),Constant("GAP"))))
    72     case KeyEvent.VK_F2 => {
    73       val b = AstInfoUtil.FindBox(c.getAst())
    74       if (b == null) {
    75         return None
    76       }
    77       println(b)
    78       c.setAst(TransformAstUtil.Update(c.getAst(), b, (a) => a match {
    79         case Appl(List(Constant(str), ast)) if str.startsWith("BOX") => Appl(List(Constant("CURSOR"), ast))
    80       }))
    81       None
    82     }
    83   }
    84   def delimerState(c: AstContainer, input: Character, cursorAst: Ast) : Option[Ast] =  AstInfoUtil.AstOfCursor(cursorAst) match {
    85     case Variable(str)   if input == '(' && isLongDelim(str)
    86       => Some(ReplaceFirstGap(
    87            Settings.OperatorToAst(str),
    88            Appl(List(Constant("CURSOR"), Constant("GAP")))))
    89     case Variable(str)
    90       => Some(ReplaceFirstGap(
    91            ReplaceFirstGap(
    92              Settings.OperatorToAst(input.toString()),
    93              Variable(str)),
    94            Appl(List(Constant("CURSOR"), Constant("GAP")))))
    95     case Appl(asts)
    96       => Some(ReplaceFirstGap(
    97            ReplaceFirstGap(
    98              Settings.OperatorToAst(input.toString()),
    99              Appl(asts)),
   100            Appl(List(Constant("CURSOR"), Constant("GAP")))))
   101     case Constant("GAP") => Some(Settings.OperatorToAst(input.toString()))
   102     case Constant(str) => {
   103       val operatorParams = AstInfoUtil.Parent(c.getAst(), cursorAst).asInstanceOf[Appl].name.tail
   104       var newOperatorAst = Settings.OperatorToAst(input.toString())
   105       for(a <- operatorParams) {
   106         newOperatorAst = ReplaceFirstGap(newOperatorAst, a)
   107       }
   108       newOperatorAst = newOperatorAst match { 
   109         case Appl(c::a) => Appl(Appl(List(c, Constant("CURSOR"))) :: a) 
   110         case _ => Constant("GAP")
   111         } 
   112       c.setAst(TransformAstUtil.Update(c.getAst(), AstInfoUtil.Parent(c.getAst(), cursorAst), (a) =>  newOperatorAst))
   113       None
   114     }
   115                         
   116   }
   117   
   118 
   119   
   120   
   121   
   122   def isNumber(ch: Integer) : Boolean = ch >= '0' && ch <= '9'
   123   def isIdentifier(ch: Integer) : Boolean = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') 
   124   def isDelim(ch: Integer) : Boolean=  List('+', '-', '*', '/', '(', '=').contains(ch)
   125   def isActionCode(code: Integer) : Boolean = code == -KeyEvent.VK_ENTER ||
   126                                            code == -KeyEvent.VK_LEFT ||
   127                                            code == -KeyEvent.VK_UP ||
   128                                            code == -KeyEvent.VK_RIGHT || 
   129                                            code == -KeyEvent.VK_DOWN || 
   130                                            code == -KeyEvent.VK_DELETE ||
   131                                            code == -KeyEvent.VK_F2
   132   //TODOWN rename to isLongOp
   133   def isLongDelim(ch: String) : Boolean=  Settings.layout.keys.filter(x => x.length() > 1).toList.contains(ch)
   134   
   135   //TODOWN delete
   136   def OperatorToAst(ch: Character) : Ast = Settings.OperatorToAst(ch.toString())
   137     
   138 
   139 
   140   
   141   def ReplaceFirstGap(ast: Ast, replace: Ast) : Ast = ast match {
   142     case Appl(Constant("GAP") :: asts)      => Appl(replace :: asts)
   143     case Appl(a :: Constant("GAP") :: asts) => Appl(a :: replace :: asts)
   144     case Appl(Appl(iasts):: oasts)          => Appl(ReplaceFirstGap(Appl(iasts), replace) :: oasts)
   145     case Appl(a :: asts)                    => Appl(a :: ReplaceFirstGap(Appl(asts), replace).asInstanceOf[Appl].name)
   146     case a                                  => a
   147   }
   148   
   149   
   150   
   151 }