/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. */ package org.thingml.compilers.java; import org.apache.commons.io.IOUtils; import org.sintef.thingml.*; import org.sintef.thingml.constraints.ThingMLHelpers; import org.sintef.thingml.helpers.AnnotatedElementHelper; import org.sintef.thingml.helpers.ConfigurationHelper; import org.thingml.compilers.Context; import org.thingml.compilers.DebugProfile; import org.thingml.compilers.configuration.CfgExternalConnectorCompiler; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by bmori on 27.01.2015. */ public class Java2Swing extends CfgExternalConnectorCompiler { @Override public void generateExternalConnector(Configuration cfg, Context ctx, String... options) { String pack = ctx.getContextAnnotation("package"); if (pack == null) pack = "org.thingml.generated"; pack = pack + ".gui"; final StringBuilder b = ctx.getNewBuilder("src/main/java/" + pack.replace(".", "/") + "/StringHelper.java"); String helper = ""; try { InputStream input = this.getClass().getClassLoader().getResourceAsStream("javatemplates/StringHelper.java"); final List<String> packLines = IOUtils.readLines(input); for (String line : packLines) { helper += line + "\n"; } input.close(); } catch (Exception e) { System.err.println("Error loading Swing template: " + e.getLocalizedMessage()); e.printStackTrace(); } b.append(helper); final StringBuilder b2 = ctx.getNewBuilder("src/main/java/" + pack.replace(".", "/") + "/Command.java"); String command = ""; try { InputStream input = this.getClass().getClassLoader().getResourceAsStream("javatemplates/Command.java"); final List<String> packLines = IOUtils.readLines(input); for (String line : packLines) { command += line + "\n"; } input.close(); } catch (Exception e) { System.err.println("Error loading Swing template: " + e.getLocalizedMessage()); e.printStackTrace(); } b2.append(command); for (Thing t : ConfigurationHelper.allThings(cfg)) { compileType(t, ctx, pack); } ctx.writeGeneratedCodeToFiles(); } protected void compileType(Thing t, Context ctx, String pack) { DebugProfile debugProfile = ctx.getCompiler().getDebugProfiles().get(t); if (!AnnotatedElementHelper.hasAnnotation(t, "mock")) return; final Map<Port, List<Message>> messageToSend = new HashMap<>(); for (Port p : ThingMLHelpers.allPorts(t)) { if (p.getSends().size() > 0) { messageToSend.put(p, new ArrayList<Message>(p.getSends())); } } final Map<Port, List<Message>> messageToReceive = new HashMap<>(); for (Port p : ThingMLHelpers.allPorts(t)) { if (p.getReceives().size() > 0) { messageToReceive.put(p, new ArrayList<Message>(p.getReceives())); } } final StringBuilder builder = ctx.getBuilder("src/main/java/" + pack.replace(".", "/") + "/" + t.getName() + "Mock.java"); String imports = ""; try { InputStream input = this.getClass().getClassLoader().getResourceAsStream("javatemplates/swing-header"); final List<String> packLines = IOUtils.readLines(input); for (String line : packLines) { imports += line + "\n"; } input.close(); } catch (Exception e) { System.err.println("Error loading Swing template: " + e.getLocalizedMessage()); e.printStackTrace(); } imports = imports.replace("$PACK$", pack); builder.append(imports); builder.append("public class " + ctx.firstToUpper(t.getName()) + "Mock extends Component implements ActionListener, ItemListener"); for (Port p : messageToReceive.keySet()) { builder.append(", I" + t.getName() + "_" + p.getName()); } builder.append("{\n\n"); builder.append("private boolean debug = false;\n"); builder.append("public boolean isDebug() {return debug;}\n"); builder.append("public void setDebug(boolean debug) {this.debug = debug;}\n"); //if (debugProfile.isActive()) { builder.append("public String instanceName;"); builder.append("public void printDebug("); builder.append("String trace");//if debugWithString builder.append(") {\n"); builder.append("if(this.isDebug()) {\n"); builder.append("System.out.println(this.instanceName + trace);\n"); builder.append("}\n"); builder.append("}\n\n"); //} for (Type ty : ThingMLHelpers.allUsedSimpleTypes(ThingMLHelpers.findContainingModel(t))) { if (ty instanceof Enumeration) { Enumeration e = (Enumeration) ty; builder.append("private static final Map<String, " + ctx.firstToUpper(e.getName()) + "_ENUM> values_" + e.getName() + " = new HashMap<String, " + ctx.firstToUpper(e.getName()) + "_ENUM>();\n"); builder.append("static {\n"); for (EnumerationLiteral l : e.getLiterals()) { builder.append("values_" + e.getName() + ".put(\"" + l.getName().toUpperCase() + "\", " + e.getName() + "_ENUM" + "." + e.getName().toUpperCase() + "_" + l.getName().toUpperCase() + ");\n"); } builder.append("}\n\n"); } } builder.append("//Message types\n"); for (Message m : ThingMLHelpers.allMessages(t)) { builder.append("private final " + ctx.firstToUpper(m.getName()) + "MessageType " + m.getName() + "Type = new " + ctx.firstToUpper(m.getName()) + "MessageType();\n"); } for (Port p : ThingMLHelpers.allPorts(t)) { builder.append("final Port " + "port_" + ctx.firstToUpper(t.getName()) + "_" + p.getName() + ";\n"); builder.append("public Port get" + ctx.firstToUpper(p.getName()) + "_port(){return port_" + ctx.firstToUpper(t.getName()) + "_" + p.getName() + ";}\n"); } for (Port p : messageToSend.keySet()) { builder.append("public java.util.List<I" + ctx.firstToUpper(t.getName()) + "_" + p.getName() + "Client> " + p.getName() + "_listeners = new java.util.LinkedList<I" + ctx.firstToUpper(t.getName()) + "_" + p.getName() + "Client>();\n"); } String template = ""; try { InputStream input = this.getClass().getClassLoader().getResourceAsStream("javatemplates/swing-component.java"); final List<String> packLines = IOUtils.readLines(input); for (String line : packLines) { template += line + "\n"; } input.close(); } catch (Exception e) { System.err.println("Error loading Swing template: " + e.getLocalizedMessage()); e.printStackTrace(); } template = template.replace("$NAME$", ctx.firstToUpper(t.getName())); StringBuilder tempBuilder = new StringBuilder(); for (Port p : ThingMLHelpers.allPorts(t)) { tempBuilder.append("port_" + ctx.firstToUpper(t.getName()) + "_" + p.getName() + " = new Port("); if (p instanceof ProvidedPort) tempBuilder.append("PortType.PROVIDED"); else tempBuilder.append("PortType.REQUIRED"); tempBuilder.append(", \"" + p.getName() + "\", this);\n"); } template = template.replace("$PORT_DECL$", tempBuilder.toString()); tempBuilder = new StringBuilder(); for (Map.Entry<Port, List<Message>> entry : messageToSend.entrySet()) { Port port = entry.getKey(); for (Message send : entry.getValue()) { tempBuilder.append("//Attributes related to " + send.getName() + " via " + port.getName() + "\n"); tempBuilder.append("public JButton send" + send.getName() + "_via_" + port.getName() + ";\n"); for (Parameter p : send.getParameters()) { if (p.getType() instanceof Enumeration) { tempBuilder.append("private JComboBox field" + send.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + ";\n"); tempBuilder.append("public JComboBox getField" + send.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "() {\n"); tempBuilder.append("return field" + send.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + ";\n"); tempBuilder.append("}\n"); } else { tempBuilder.append("private JTextField field" + send.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + ";\n"); tempBuilder.append("public JTextField getField" + send.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "() {\n"); tempBuilder.append("return field" + send.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + ";\n"); tempBuilder.append("}\n\n"); } } ////////////////////////////////////////////////////////////////// tempBuilder.append("public JButton getSend" + send.getName() + "_via_" + port.getName() + "() {\n"); tempBuilder.append("return send" + send.getName() + "_via_" + port.getName() + ";\n"); tempBuilder.append("}\n\n"); } } tempBuilder.append("public void disableAll() {\n"); for (Map.Entry<Port, List<Message>> entry : messageToSend.entrySet()) { Port port = entry.getKey(); for (Message send : entry.getValue()) { tempBuilder.append("send" + send.getName() + "_via_" + port.getName() + ".setEnabled(false);\n"); } } tempBuilder.append("}\n\n"); tempBuilder.append("public void enableAll() {\n"); for (Map.Entry<Port, List<Message>> entry : messageToSend.entrySet()) { Port port = entry.getKey(); for (Message send : entry.getValue()) { tempBuilder.append("send" + send.getName() + "_via_" + port.getName() + ".setEnabled(true);\n"); } } tempBuilder.append("}\n\n"); template = template.replace("$MESSAGE_TO_SEND_DECL$", tempBuilder.toString()); tempBuilder = new StringBuilder(); tempBuilder.append("public void addListener(ActionListener l){\n"); for (Map.Entry<Port, List<Message>> entry : messageToSend.entrySet()) { Port port = entry.getKey(); for (Message msg : entry.getValue()) { tempBuilder.append("send" + msg.getName() + "_via_" + port.getName() + ".addActionListener(l);\n"); } } tempBuilder.append("}\n\n"); template = template.replace("$LISTENERS$", tempBuilder.toString()); tempBuilder = new StringBuilder(); for (Port port : messageToSend.keySet()) { tempBuilder.append("JPanel frame_" + port.getName() + " = new JPanel();\n"); tempBuilder.append("frame_" + port.getName() + ".setLayout(new GridBagLayout());\n"); //builder append "frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n" } for (Map.Entry<Port, List<Message>> entry : messageToSend.entrySet()) { Port port = entry.getKey(); int x = 0; for (Message msg : entry.getValue()) { tempBuilder.append("//GUI related to " + port.getName() + "_via_" + port.getName() + " => " + msg.getName() + "\n"); tempBuilder.append("c.gridy = 0;\n"); tempBuilder.append("c.gridx = " + x + ";\n"); tempBuilder.append("frame_" + port.getName() + ".add(createLabel(\"" + msg.getName() + "\"), c);\n"); tempBuilder.append("c.gridy = 1;\n"); tempBuilder.append("c.gridx = " + x + ";\n"); tempBuilder.append("frame_" + port.getName() + ".add(create" + msg.getName() + "_via_" + port.getName() + "Panel(), c);\n"); tempBuilder.append("c.gridy = 2;\n"); tempBuilder.append("c.gridx = " + x + ";\n"); tempBuilder.append("c.weighty = 0;\n"); tempBuilder.append("send" + msg.getName() + "_via_" + port.getName() + " = createSendButton(\"" + port.getName() + " => " + msg.getName() + "\");\n"); tempBuilder.append("frame_" + port.getName() + ".add(send" + msg.getName() + "_via_" + port.getName() + ", c);\n"); tempBuilder.append("tabbedPane.addTab(\"" + port.getName() + "\", frame_" + port.getName() + ");\n"); x++; } } template = template.replace("$MESSAGE_TO_SEND_INIT$", tempBuilder.toString()); tempBuilder = new StringBuilder(); for (Map.Entry<Port, List<Message>> entry : messageToSend.entrySet()) { Port port = entry.getKey(); for (Message msg : entry.getValue()) { tempBuilder.append("public JPanel create" + msg.getName() + "_via_" + port.getName() + "Panel(){\n"); tempBuilder.append("GridBagConstraints c = new GridBagConstraints();\n"); tempBuilder.append("c.fill = GridBagConstraints.HORIZONTAL;\n"); tempBuilder.append("c.weightx = 0.5;\n"); tempBuilder.append("JPanel panel = new JPanel(new GridBagLayout());\n"); int y = 0; for (Parameter p : msg.getParameters()) { tempBuilder.append("JLabel label" + p.getName() + " = new JLabel();\n"); tempBuilder.append("label" + p.getName() + ".setText(\"" + p.getName() + "\");\n"); tempBuilder.append("c.gridx = 0;\n"); tempBuilder.append("c.gridy = " + y + ";\n"); tempBuilder.append("panel.add(label" + p.getName() + ", c);\n"); if (p.getType() instanceof Enumeration) { //builder append p.getType.scala_type + "[] values" + self.getName + Context.firstToUpper(p.getName) + " = {" //builder append p.getType.asInstanceOf[Enumeration].getLiterals.collect{case l => p.getType.getName + "_ENUM" + "." + p.getType.getName.toUpperCase + "_" + l.getName.toUpperCase() + "()"}.mkString(", ") + "};\n" tempBuilder.append("field" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + " = new JComboBox(values_" + p.getType().getName() + ".keySet().toArray());\n"); } else { tempBuilder.append("field" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + " = new JTextField();\n"); tempBuilder.append("field" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + ".setText(\"" + JavaHelper.getJavaType(p.getType(), p.getCardinality() != null, ctx) + "\");\n"); } tempBuilder.append("c.gridx = 1;\n"); tempBuilder.append("c.gridy = " + y + "\n;"); tempBuilder.append("panel.add(field" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + ", c);\n"); y++; } tempBuilder.append("return panel;\n"); tempBuilder.append("}\n\n"); } } template = template.replace("$MESSAGE_TO_SEND_BEHAVIOR$", tempBuilder.toString()); tempBuilder = new StringBuilder(); for (Map.Entry<Port, List<Message>> entry : messageToReceive.entrySet()) { Port port = entry.getKey(); for (Message msg : entry.getValue()) { tempBuilder.append("Style receive" + msg.getName() + "_via_" + port.getName() + "Style = doc.addStyle(\"" + msg.getName() + "_via_" + port.getName() + "\", null);\n"); tempBuilder.append("StyleConstants.setBackground(receive" + msg.getName() + "_via_" + port.getName() + "Style, new Color(" + ((255 + (Math.abs(msg.getName().hashCode()) % 255)) / 2) + ", " + ((255 + (Math.abs(port.getName().hashCode()) % 255)) / 2) + ", " + ((255 + ((Math.abs(port.getName().hashCode() + msg.getName().hashCode())) % 255)) / 2) + "));\n"); } } template = template.replace("$MESSAGE_TO_RECEIVE_BEHAVIOR$", tempBuilder.toString()); tempBuilder = new StringBuilder(); StringBuilder parseBuilder = new StringBuilder(); for (Map.Entry<Port, List<Message>> entry : messageToSend.entrySet()) { Port port = entry.getKey(); parseBuilder.append("if(params[0].equals(\"" + port.getName() + "\")) {\n"); int i = 0; for (Message msg : entry.getValue()) { if (i > 0) parseBuilder.append("else "); parseBuilder.append("if (params[1].startsWith(\"" + msg.getName() + "\")) {\n"); parseBuilder.append("params[1] = params[1].substring(\"" + msg.getName() + "\".length(), params[1].length());\n"); parseBuilder.append("if (!(params[1].startsWith(\"(\") && params[1].endsWith(\")\"))) {\n"); parseBuilder.append("cliButton.setForeground(alertColor);\n"); parseBuilder.append("cli.setText(\"port!message(param1, param2, param3)\");\n"); parseBuilder.append("return;\n"); parseBuilder.append("}\n"); parseBuilder.append("params = params[1].substring(1,params[1].length()-1).split(\",\");\n"); if (msg.getParameters().size() == 0) { parseBuilder.append("if (params[0].equals(\"\"))\n"); parseBuilder.append("params = new String[0];\n"); } parseBuilder.append("if (!(params.length == " + msg.getParameters().size() + ")) {\n"); parseBuilder.append("cliButton.setForeground(alertColor);\n"); parseBuilder.append("cli.setText(\"port!message(param1, param2, param3)\");\n"); parseBuilder.append("return;\n"); parseBuilder.append("}\n"); parseBuilder.append("try {\n"); tempBuilder.append("else if ( ae.getSource() == getSend" + msg.getName() + "_via_" + port.getName() + "()) {\n"); tempBuilder.append("try{\n"); tempBuilder.append("Map<String, Object> param = new HashMap<String, Object>();\n"); parseBuilder.append("Map<String, Object> param = new HashMap<String, Object>();\n"); for (Parameter p : msg.getParameters()) { tempBuilder.append("param.put(\"" + p.getName() + "\", "); parseBuilder.append("param.put(\"" + p.getName() + "\", "); if (p.getCardinality() == null) { if (p.getType() instanceof Enumeration) { tempBuilder.append("values_" + p.getType().getName() + ".get(getField" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "().getSelectedItem().toString())"); parseBuilder.append("values_" + p.getType().getName() + ".get(getField" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "().getSelectedItem().toString())"); } else { /*tempBuilder.append("("); parseBuilder.append("("); if (JavaHelper.getJavaType(p.getType(), false, ctx).equals("int")) { tempBuilder.append("Integer"); parseBuilder.append("Integer"); } else { tempBuilder.append(ctx.firstToUpper(JavaHelper.getJavaType(p.getType(), false, ctx))); parseBuilder.append(ctx.firstToUpper(JavaHelper.getJavaType(p.getType(), false, ctx))); }*/ tempBuilder.append("StringHelper.toObject (" + JavaHelper.getJavaType(p.getType(), false, ctx) + ".class, getField" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "().getText())"); parseBuilder.append("StringHelper.toObject (" + JavaHelper.getJavaType(p.getType(), false, ctx) + ".class, params[" + msg.getParameters().indexOf(p) + "].trim())"); } } else { builder.append("getField" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "().getText().getBytes()"); } tempBuilder.append(");\n"); parseBuilder.append(");\n"); } tempBuilder.append("Command c = new Command(port_" + ctx.firstToUpper(t.getName()) + "_" + port.getName() + ", " + msg.getName() + "Type, param);"); tempBuilder.append("c.execute();\n"); tempBuilder.append("((DefaultListModel)commands.getModel()).addElement(c);\n"); parseBuilder.append("Command c = new Command(port_" + ctx.firstToUpper(t.getName()) + "_" + port.getName() + ", " + msg.getName() + "Type, param);"); parseBuilder.append("c.execute();\n"); parseBuilder.append("((DefaultListModel)commands.getModel()).addElement(c);\n"); parseBuilder.append("cliButton.setForeground(Color.BLACK);\n"); tempBuilder.append("for(I" + ctx.firstToUpper(t.getName()) + "_" + port.getName() + "Client l : " + port.getName() + "_listeners)\n"); tempBuilder.append("l." + msg.getName() + "_from_" + port.getName() + "("); int j = 0; for (Parameter p : msg.getParameters()) { if (j > 0) tempBuilder.append(", "); if (p.getCardinality() == null) { if (p.getType() instanceof Enumeration) { tempBuilder.append("values_" + p.getType().getName() + ".get(getField" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "().getSelectedItem().toString())"); } else { tempBuilder.append("("); if (JavaHelper.getJavaType(p.getType(), false, ctx).equals("int")) tempBuilder.append("Integer"); else tempBuilder.append(ctx.firstToUpper(JavaHelper.getJavaType(p.getType(), false, ctx))); tempBuilder.append(")StringHelper.toObject (" + JavaHelper.getJavaType(p.getType(), false, ctx) + ".class, getField" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "().getText())"); } } else { tempBuilder.append("getField" + msg.getName() + "_via_" + port.getName() + "_" + ctx.firstToUpper(p.getName()) + "().getText().getBytes()"); } j++; } tempBuilder.append(");\n"); tempBuilder.append("getSend" + msg.getName() + "_via_" + port.getName() + "().setForeground(Color.BLACK);\n"); tempBuilder.append("} catch(IllegalArgumentException iae) {\n"); tempBuilder.append("System.err.println(\"Cannot parse arguments for message " + msg.getName() + " on port " + port.getName() + ". Please try again with proper parameters\");\n"); tempBuilder.append("getSend" + msg.getName() + "_via_" + port.getName() + "().setForeground(alertColor);\n"); tempBuilder.append("}\n"); tempBuilder.append("}\n"); parseBuilder.append("} catch(IllegalArgumentException iae) {\n"); parseBuilder.append("System.err.println(\"Cannot parse arguments for message " + msg.getName() + " on port " + port.getName() + ". Please try again with proper parameters\");\n"); parseBuilder.append("cliButton.setForeground(alertColor);\n"); parseBuilder.append("}\n"); parseBuilder.append("}\n"); i++; } parseBuilder.append("}\n"); } template = template.replace("$ON_ACTION$", tempBuilder.toString()); template = template.replace("$PARSE$", parseBuilder.toString()); builder.append(template); for (Map.Entry<Port, List<Message>> entry : messageToReceive.entrySet()) { Port port = entry.getKey(); for (Message m : entry.getValue()) { builder.append("@Override\n"); builder.append("public synchronized void " + m.getName() + "_via_" + port.getName() + "("); JavaHelper.generateParameter(m, builder, ctx); builder.append("){\n"); builder.append("print(\"" + m.getName() + "_via_" + port.getName() + "\", \"TODO\");\n"); builder.append("}\n"); } } builder.append("}\n"); } }