package simulator.interfaces.swing; import java.awt.Component; import java.awt.FlowLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.Term; import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.MapTerm; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferChannel; import simulator.Event; import simulator.Resource; import simulator.Simulator; import simulator.SystemState; import simulator.interfaces.INativeReceiver; public class SwingPresenter implements INativeReceiver { // Native channel names. public final String screenUpdateChannelName = "ScreenUpdate"; public final String setLayoutChannelName = "SetLayout"; public final String setVisibleChannelName = "SetVisible"; public final String setTextChannelName = "SetText"; public final String setXChannelName = "SetX"; public final String setYChannelName = "SetY"; public final String setWidthChannelName = "SetWidth"; public final String setHeightChannelName = "SetHeight"; public final String mouseEventChannelName = "MouseEvent"; public final String textEventChannelName = "TextEvent"; protected JPanel mainPanel; protected Simulator simulator; protected Map<String, Component> components; // Native channels. protected DataTransferChannel screenUpdateChannel; protected DataTransferChannel setLayoutChannel; protected DataTransferChannel setVisibleChannel; protected DataTransferChannel setTextChannel; protected DataTransferChannel setXChannel; protected DataTransferChannel setYChannel; protected DataTransferChannel setWidthChannel; protected DataTransferChannel setHeightChannel; protected DataTransferChannel mouseEventChannel; protected DataTransferChannel textEventChannel; protected Map<DataTransferChannel, Map<String, Resource>> channelAndResourcesForReceiving = new HashMap<>(); public SwingPresenter(JPanel mainPanel, Simulator simulator) { this.mainPanel = mainPanel; this.simulator = simulator; components = new HashMap<>(); screenUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenUpdateChannelName); setLayoutChannel = (DataTransferChannel) simulator.getModel().getChannel(setLayoutChannelName); setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName); setTextChannel = (DataTransferChannel) simulator.getModel().getChannel(setTextChannelName); setXChannel = (DataTransferChannel) simulator.getModel().getChannel(setXChannelName); setYChannel = (DataTransferChannel) simulator.getModel().getChannel(setYChannelName); setWidthChannel = (DataTransferChannel) simulator.getModel().getChannel(setWidthChannelName); setHeightChannel = (DataTransferChannel) simulator.getModel().getChannel(setHeightChannelName); mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); simulator.addNativeReceiver(this, screenUpdateChannel); simulator.addNativeReceiver(new SwingLayout(), setLayoutChannel); } @Override public void onReceiveFromModel(Event event, SystemState nextSystemState) { Expression message = event.getMessage(); if (message instanceof Term && ((Term) message).getChildren().size() >= 2) { Expression curScExp = ((Term) message).getChild(0); Expression nextScExp = ((Term) message).getChild(1); if (curScExp instanceof JsonTerm && nextScExp instanceof JsonTerm) { JsonTerm curSc = (JsonTerm) curScExp; JsonTerm nextSc = (JsonTerm) nextScExp; Expression newLayout = nextSc.get("layout"); if (newLayout != null) { if (newLayout.toString().equals("true")) { mainPanel.setLayout(new FlowLayout()); } else if (newLayout.toString().equals("false")) { mainPanel.setLayout(null); } } Expression oldWidgets = curSc.get("widgets"); Expression newWidgets = nextSc.get("widgets"); if (oldWidgets instanceof MapTerm && newWidgets instanceof MapTerm) { Set<String> oldWidSet = new HashSet<>(((MapTerm) oldWidgets).keySet()); Set<String> newWidSet = new HashSet<>(((MapTerm) newWidgets).keySet()); oldWidSet.removeAll(((MapTerm) newWidgets).keySet()); newWidSet.removeAll(((MapTerm) oldWidgets).keySet()); if (!oldWidSet.isEmpty() || !newWidSet.isEmpty()) { // If the set of screen components is changed. // Remove old components and their native receivers. for (String oldWid: oldWidSet) { mainPanel.remove(components.get(oldWid)); } for (DataTransferChannel channel: channelAndResourcesForReceiving.keySet()) { Map<String, Resource> widToResource = channelAndResourcesForReceiving.get(channel); for (String oldWid: oldWidSet) { Resource resource = widToResource.remove(oldWid); if (resource != null) { simulator.removeNativeReceiver(channel, resource); } } } // Add new swing components. Resource screenResource = nextSystemState.getResource(event.getInputResource().getResourceIdentifier()); Resource widgetsResource = screenResource.getChildrenMap().get("widgets"); for (String newWid: newWidSet) { Expression value = ((MapTerm) newWidgets).get(newWid); if (value instanceof JsonTerm) { JsonTerm widget = (JsonTerm) value; Resource widgetResource = widgetsResource.getChildrenMap().get(newWid); Expression type = widget.get("type"); if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("button")) { // Add a button component. Expression text = widget.get("text"); Expression x = widget.get("x"); Expression y = widget.get("y"); Expression width = widget.get("width"); Expression height = widget.get("height"); JButton button = new JButton(((String)((Constant) text).getValue())); if (x != null && y != null) { button.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); } if (width != null && height != null) { button.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); } mainPanel.add(button); components.put(newWid, button); // Connect swing component and model. ResourcePath resPath = mouseEventChannel.getOutputResources().iterator().next(); button.addMouseListener(new ComponentMouseSender(simulator, mouseEventChannel, resPath, widgetResource)); // button => widgetResource ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(button); // widgetResource => button simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setVisibleChannel, resources); } resources.put(newWid, widgetResource); ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(button); // widgetResource => button simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource.getChildrenMap().get("text")); resources = channelAndResourcesForReceiving.get(setTextChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setTextChannel, resources); } resources.put(newWid, widgetResource); Resource widgetXResource = widgetResource.getChildrenMap().get("x"); if (widgetXResource != null) { ComponentXReceiver nativeXReceiver = new ComponentXReceiver(button); // widgetResource => button simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); resources = channelAndResourcesForReceiving.get(setXChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setXChannel, resources); } resources.put(newWid, widgetXResource); } Resource widgetYResource = widgetResource.getChildrenMap().get("y"); if (widgetYResource != null) { ComponentYReceiver nativeYReceiver = new ComponentYReceiver(button); // widgetResource => button simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); resources = channelAndResourcesForReceiving.get(setYChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setYChannel, resources); } resources.put(newWid, widgetYResource); } Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); if (widgetWidthResource != null) { ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(button); // widgetResource => button simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); resources = channelAndResourcesForReceiving.get(setWidthChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setWidthChannel, resources); } resources.put(newWid, widgetWidthResource); } Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); if (widgetHeightResource != null) { ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(button); // widgetResource => button simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); resources = channelAndResourcesForReceiving.get(setHeightChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setHeightChannel, resources); } resources.put(newWid, widgetHeightResource); } } else if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("label")) { // Add a label component. Expression text = widget.get("text"); Expression x = widget.get("x"); Expression y = widget.get("y"); Expression width = widget.get("width"); Expression height = widget.get("height"); JLabel label = new JLabel(((String) ((Constant) text).getValue())); if (x != null && y != null) { label.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); } if (width != null && height != null) { label.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); } mainPanel.add(label); components.put(newWid, label); // Connect swing component and model. ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setVisibleChannel, resources); } resources.put(newWid, widgetResource); ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource.getChildrenMap().get("text")); resources = channelAndResourcesForReceiving.get(setTextChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setTextChannel, resources); } resources.put(newWid, widgetResource); Resource widgetXResource = widgetResource.getChildrenMap().get("x"); if (widgetXResource != null) { ComponentXReceiver nativeXReceiver = new ComponentXReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); resources = channelAndResourcesForReceiving.get(setXChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setXChannel, resources); } resources.put(newWid, widgetXResource); } Resource widgetYResource = widgetResource.getChildrenMap().get("y"); if (widgetYResource != null) { ComponentYReceiver nativeYReceiver = new ComponentYReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); resources = channelAndResourcesForReceiving.get(setYChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setYChannel, resources); } resources.put(newWid, widgetYResource); } Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); if (widgetWidthResource != null) { ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); resources = channelAndResourcesForReceiving.get(setWidthChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setWidthChannel, resources); } resources.put(newWid, widgetWidthResource); } Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); if (widgetHeightResource != null) { ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); resources = channelAndResourcesForReceiving.get(setHeightChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setHeightChannel, resources); } resources.put(newWid, widgetHeightResource); } } else if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("textInput")) { // Add a text input component. Expression x = widget.get("x"); Expression y = widget.get("y"); Expression width = widget.get("width"); Expression height = widget.get("height"); JTextField textField = new JTextField(10); if (x != null && y != null) { textField.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); } if (width != null && height != null) { textField.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); } mainPanel.add(textField); components.put(newWid, textField); // Connect swing component and model. ResourcePath resPath = textEventChannel.getOutputResources().iterator().next(); textField.getDocument().addDocumentListener(new ComponentTextSender(simulator, textEventChannel, resPath, widgetResource)); // textField => widgetResource ComponentVisibilityReceiver nativeReceiver = new ComponentVisibilityReceiver(textField); // widgetResource => textField simulator.addNativeReceiver(nativeReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setVisibleChannel, resources); } resources.put(newWid, widgetResource); Resource widgetXResource = widgetResource.getChildrenMap().get("x"); if (widgetXResource != null) { ComponentXReceiver nativeXReceiver = new ComponentXReceiver(textField); // widgetResource => textField simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); resources = channelAndResourcesForReceiving.get(setXChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setXChannel, resources); } resources.put(newWid, widgetXResource); } Resource widgetYResource = widgetResource.getChildrenMap().get("y"); if (widgetYResource != null) { ComponentYReceiver nativeYReceiver = new ComponentYReceiver(textField); // widgetResource => textField simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); resources = channelAndResourcesForReceiving.get(setYChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setYChannel, resources); } resources.put(newWid, widgetYResource); } Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); if (widgetWidthResource != null) { ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(textField); // widgetResource => textField simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); resources = channelAndResourcesForReceiving.get(setWidthChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setWidthChannel, resources); } resources.put(newWid, widgetWidthResource); } Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); if (widgetHeightResource != null) { ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(textField); // widgetResource => textField simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); resources = channelAndResourcesForReceiving.get(setHeightChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setHeightChannel, resources); } resources.put(newWid, widgetHeightResource); } } } } mainPanel.invalidate(); mainPanel.validate(); mainPanel.repaint(); } } } } } public class SwingLayout implements INativeReceiver { @Override public void onReceiveFromModel(Event event, SystemState nextSystemState) { Expression message = event.getMessage(); if (message instanceof Term && ((Term) message).getChildren().size() >= 1) { Expression newLayout = ((Term) message).getChild(0); if (newLayout instanceof Constant) { if (newLayout.toString().equals("true")) { mainPanel.setLayout(new FlowLayout()); } else if (newLayout.toString().equals("false")) { mainPanel.setLayout(null); } } } } } }