/** * @file .java * @author Anderson Antunes <anderson.utf@gmail.com> * *seu nome* <*seu email*> * @version 1.0 * * @section LICENSE * * Copyright (C) 2013 by Anderson Antunes <anderson.utf@gmail.com> * *seu nome* <*seu email*> * * RobotInterface 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. * * RobotInterface 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 * RobotInterface. If not, see <http://www.gnu.org/licenses/>. * */ package robotinterface.algorithm.procedure; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import robotinterface.algorithm.Command; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JTextField; import org.nfunk.jep.JEP; import org.nfunk.jep.SymbolTable; import robotinterface.algorithm.parser.parameterparser.Argument; import robotinterface.drawable.swing.DrawableProcedureBlock; import robotinterface.drawable.GraphicObject; import robotinterface.drawable.swing.MutableWidgetContainer; import robotinterface.drawable.swing.component.Component; import robotinterface.drawable.swing.component.SubLineBreak; import robotinterface.drawable.swing.component.Space; import robotinterface.drawable.swing.component.WidgetLine; import robotinterface.drawable.swing.component.TextLabel; import robotinterface.drawable.swing.component.Widget; import robotinterface.drawable.util.QuickFrame; import robotinterface.gui.panels.sidepanel.Classifiable; import robotinterface.gui.panels.sidepanel.Item; import robotinterface.robot.Robot; import robotinterface.interpreter.ExecutionException; import robotinterface.interpreter.Expression; import robotinterface.interpreter.ResourceManager; import robotinterface.util.trafficsimulator.Clock; /** * Comando genérico com suporte à variaveis. */ public class Procedure extends Command implements Classifiable { private static Object nill = new Object(); private static Color myColor = Color.decode("#ACD630"); private ArrayList<String> names; private ArrayList<Object> values; private ArrayList<Argument> myArgs; private String procedure; private boolean varArgs; private Pattern p = Pattern.compile("(\\S+)(\\+\\+)"); public Procedure() { //tornar private varArgs = true; procedure = ""; names = new ArrayList<>(); values = new ArrayList<>(); myArgs = new ArrayList<>(); } /** * Uso restrito ao parser. * * @param procedure * @deprecated */ @Deprecated public Procedure(String procedure) { this(); setProcedure(procedure); } public Procedure(Procedure p) { this(p.procedure); } protected Procedure(boolean varArgs) { this(); this.varArgs = varArgs; } protected Procedure(Argument... args) { this(); varArgs = true; this.myArgs.addAll(Arrays.asList(args)); } public final String getProcedure() { return procedure; } public final void setProcedure(String procedure) { this.procedure = procedure; updateVariables(); } @Override public boolean perform(ResourceManager rm) throws ExecutionException { evaluate(rm); return true; } private void updateVariables() { names.clear(); values.clear(); for (String str : procedure.split(";")) { str = str.trim(); if (str.startsWith("var")) { str = str.replaceFirst("var ", ""); String varName; Object varValue; for (String declaration : str.split(",")) { int eq = declaration.indexOf("="); if (eq > 0) { varName = declaration.substring(0, eq).trim(); varValue = declaration.substring(eq + 1); } else { varName = declaration.trim(); varValue = null; } names.add(varName); values.add(varValue); } } } } //usado pelos descendentes dessa classe para executar expressoes protected final Object execute(String procedure, ResourceManager rm) throws ExecutionException { Object o = null; updateVariables(); JEP parser = rm.getResource(JEP.class); SymbolTable st = parser.getSymbolTable(); for (int i = 0; i < names.size(); i++) { String varName = names.get(i); Object varValue = values.get(i); if (st.getVar(varName) != null && st.getVar(varName).hasValidValue()) { throw new ExecutionException("Variable already exists!"); } else { if (!names.contains(varName)) { names.add(varName); values.add(varValue); } Object v = null; if (varValue != null) { parser.parseExpression(varValue.toString()); v = parser.getValueAsObject(); } st.makeVarIfNeeded(varName, v); } } for (String str : procedure.split(";")) { str = str.trim(); if (!(str.startsWith("var") || str.isEmpty())) { Matcher m = p.matcher(str); if (m.find()) { String valid = m.group(1) + " = " + m.group(1) + " + 1"; if (this.procedure.equals(procedure)) { this.procedure = procedure.replace(str, valid); } str = valid; } parser.parseExpression(str); o = parser.getValueAsObject(); if (parser.hasError()) { throw new ExecutionException(parser.getErrorInfo() + " in \"" + str + "\""); } } } // parser.parseExpression(procedure); return o; } //usado pelos descendentes dessa classe para executar expressoes simples (true/false) protected final boolean evaluate(String procedure, ResourceManager rm) throws ExecutionException { Object o = execute(procedure, rm); if (o instanceof Number) { Double d = ((Number) o).doubleValue(); return (d != 0 && !d.isNaN()); } return false; } //retorna o valor da expressão desse objeto protected final boolean evaluate(ResourceManager rm) throws ExecutionException { return evaluate(procedure, rm); } // protected final Variable newVariable(String name, Object value) { // return parser.getSymbolTable().makeVarIfNeeded(name, value); // } @Deprecated //ainda não funciona, falta criar a variavel na tabela de simbolos ^ protected final void addVariable(String name, Object value) { names.add(name); values.add(value); } protected Collection<String> getVariableNames() { return names; } protected Collection<Object> getVariableValues() { return values; } public Collection<String> getDeclaredVariables() { ArrayList<String> vars = new ArrayList<>(); Command it = this; while (it != null) { Command up = it.getPrevious(); while (up != null) { if (up instanceof Procedure) { vars.addAll(((Procedure) up).getVariableNames()); } up = up.getPrevious(); } it = it.getParent(); } return vars; } @Override public void toString(String ident, StringBuilder sb) { if (!procedure.equals("0")) { for (String p : procedure.split(";")) { sb.append(ident).append(p.trim()).append(";\n"); } } else { sb.append(ident).append(toString()).append(";\n"); } } @Override public Item getItem() { Area myShape = new Area(); myShape.add(new Area(new Rectangle2D.Double(0, 0, 20, 12))); myShape.subtract(new Area(new Rectangle2D.Double(4, 4, 12, 4))); return new Item("Procedimento", myShape, myColor, "Usado para declarar e atualizar o valor de variáveis, criando formulas e expreções algébricas"); } @Override public Object createInstance() { return new Procedure("var x = 1"); } public Argument addLineArg(int index, int type, Object data) { if (myArgs.size() > index) { if (index == -1) { throw new IndexOutOfBoundsException(); } } else { while (myArgs.size() <= index) { myArgs.add(new Argument("", type)); } } Argument arg = myArgs.get(index); if (data != nill) { arg.set(data, type); } return arg; } protected Argument addLineArg(int index, int type) { return addLineArg(index, type, nill); } @Deprecated protected Argument addLineArg(int index) { return addLineArg(index, Argument.UNDEFINED); } @Deprecated protected void resetArgs(Argument... args) { myArgs.clear(); myArgs.addAll(Arrays.asList(args)); } protected Argument getArg(int index) { return addLineArg(index); } protected Collection<Argument> getArgs() { return myArgs; } protected int getArgSize() { return myArgs.size(); } private void removeLineArg() { if (myArgs.size() > 0) { myArgs.remove(myArgs.size() - 1); } } private GraphicObject resource = null; @Override public GraphicObject getDrawableResource() { if (resource == null) { resource = createDrawableProcedure(this); } return resource; } public static MutableWidgetContainer createDrawableProcedure(final Procedure p) { final int TEXTFIELD_WIDTH = 110; final int TEXTFIELD_HEIGHT = 25; final int BUTTON_WIDTH = 25; //HEADER LINE final WidgetLine headerLine = new WidgetLine() { @Override public void createRow(Collection<Component> components, MutableWidgetContainer container, int index) { components.add(new TextLabel("Procedimento:", true)); } }; //TEXTFIELD LINES final WidgetLine textFieldLine = new WidgetLine() { @Override public void createRow(Collection<Component> components, MutableWidgetContainer container, int index) { JTextField textField = new JTextField(); Widget wTextField = new Widget(textField, TEXTFIELD_WIDTH, TEXTFIELD_HEIGHT); container.entangle(p.addLineArg(index - 1), wTextField); components.add(new Space(BUTTON_WIDTH)); components.add(wTextField); // textField.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { //// updateProcedure(); // } // }); } @Override public void toString(StringBuilder sb, ArrayList<Argument> arguments, MutableWidgetContainer container) { if (arguments.size() > 0) { String str = arguments.get(0).toString(); if (!str.endsWith(";")) { str += ";"; } sb.append(str); } } // @Override // public String getString(Collection<Widget> widgets, Collection<TextLabel> labels, final MutableWidgetContainer container) { // if (widgets.size() > 0) { // Widget widget = widgets.iterator().next(); // JComponent jComponent = widget.getJComponent(); // if (jComponent instanceof JTextField) { // String str = ((JTextField) jComponent).getText(); // if (!str.endsWith(";")) { // str += ";"; // } // return str; // } // } // return ""; // } }; //END LINE final WidgetLine endLine = new WidgetLine(true) { private Widget addButton; private Widget remButton; @Override public void createRow(Collection<Component> components, final MutableWidgetContainer container, int index) { JButton bTmp = new JButton(new ImageIcon(getClass().getResource("/resources/tango/16x16/actions/list-add.png"))); bTmp.setFocusable(false); bTmp.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { container.addLine(textFieldLine); //desconta headerLine e endLine int size = container.getSize() - 2; if (size > 1) { JButton btn = (JButton) remButton.getJComponent(); btn.setEnabled(true); } } }); addButton = new Widget(bTmp, BUTTON_WIDTH, TEXTFIELD_HEIGHT); bTmp = new JButton(new ImageIcon(getClass().getResource("/resources/tango/16x16/actions/list-remove.png"))); bTmp.setEnabled(false); bTmp.setFocusable(false); bTmp.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //desconta headerLine e endLine int size = container.getSize() - 2; if (size > 1) { container.removeLine(size); p.removeLineArg(); } if (size - 1 == 1) { JButton btn = (JButton) remButton.getJComponent(); btn.setEnabled(false); } } }); remButton = new Widget(bTmp, BUTTON_WIDTH, TEXTFIELD_HEIGHT); components.add(addButton); components.add(new Space(TEXTFIELD_WIDTH)); components.add(remButton); components.add(new SubLineBreak(true)); } }; DrawableProcedureBlock dcb = new DrawableProcedureBlock(p, myColor) { { boxLabel = p.getProcedure(); updateStructure(); getBoxLabel(); } @Override public void updateStructure() { clear(); addLine(headerLine); boolean empty = true; int index = 0; for (String str : boxLabel.split(";")) { Argument arg = p.addLineArg(index); arg.set(str, Argument.EXPRESSION); index++; addLine(textFieldLine); empty = false; } if (empty) { addLine(textFieldLine); } addLine(endLine); } @Override public String getBoxLabel() { String str = super.getBoxLabel(); p.setProcedure(str); return str; } }; return dcb; } public Procedure copy(Procedure copy) { if (copy != null) { copy.procedure = procedure; copy.names.addAll(names); copy.values.addAll(values); copy.myArgs.clear(); for (int i = 0; i < myArgs.size(); i++) { copy.myArgs.add(new Argument(myArgs.get(i))); } } return copy; } public static Procedure copyAll(Procedure p) { Procedure start = p.copy((Procedure) p.createInstance()); Procedure old = start; Procedure newCopy; Command it = p.getNext(); int i = 0; while (it != null) { if (it instanceof Procedure) { newCopy = ((Procedure) it).copy((Procedure) ((Procedure) it).createInstance()); i++; // System.out.println(it.getClass().getSimpleName() + " -> " + newCopy.getClass().getSimpleName()); if (old != null) { old.setNext(newCopy); newCopy.setPrevious(old); } old = newCopy; } else { if (!(it instanceof Block.BlockEnd)) { System.out.println("Erro ao copiar: "); it.print(); break; } } it = it.getNext(); } return start; } public static void main(String[] args) { Procedure p = new Procedure("var x,y,z; x = 2 + 2;"); QuickFrame.applyLookAndFeel(); QuickFrame.drawTest(p.getDrawableResource()); } public void append(String string) { if (procedure.endsWith(";")) { procedure += string; } else { procedure += "; " + string; } } }