package simulator.interfaces.swing; import java.awt.Component; import java.awt.Toolkit; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtilities; 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 { public final String screenUpdateChannelName = "ScreenUpdate"; public final String setVisibleChannelName = "SetVisible"; public final String setTextChannelName = "SetText"; public final String mouseEventChannelName = "MouseEvent"; public final String textEventChannelName = "TextEvent"; protected JPanel mainPanel; protected Simulator simulator; protected Map<String, Component> components; protected DataTransferChannel screenUpdateChannel; protected DataTransferChannel setVisibleChannel; protected DataTransferChannel setTextChannel; 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); setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName); setTextChannel = (DataTransferChannel) simulator.getModel().getChannel(setTextChannelName); mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); simulator.addNativeReceiver(this, screenUpdateChannel); } @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 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.toString().equals("\"button\"")) { // Add a button component. Expression text = widget.get("\"text\""); JButton button = new JButton(text.toString().replace("\"", "")); 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); Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setVisibleChannel, resources); } resources.put(newWid, widgetsResource); ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(button); // widgetResource => button simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource); resources = channelAndResourcesForReceiving.get(setTextChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setTextChannel, resources); } resources.put(newWid, widgetsResource); } else if (type.toString().equals("\"label\"")) { // Add a label component. Expression text = widget.get("\"text\""); JLabel label = new JLabel(text.toString().replace("\"", "")); mainPanel.add(label); components.put(newWid, label); // Connect swing component and model. ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource); Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setVisibleChannel, resources); } resources.put(newWid, widgetsResource); ComponentTextReceiver nativeTextReceiver = new ComponentTextReceiver(label); // widgetResource => label simulator.addNativeReceiver(nativeTextReceiver, setTextChannel, widgetResource); resources = channelAndResourcesForReceiving.get(setTextChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setTextChannel, resources); } resources.put(newWid, widgetsResource); } else if (type.toString().equals("\"textInput\"")) { // Add a text input component. JTextField textField = new JTextField(10); 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); Map<String, Resource> resources = channelAndResourcesForReceiving.get(setVisibleChannel); if (resources == null) { resources = new HashMap<>(); channelAndResourcesForReceiving.put(setVisibleChannel, resources); } resources.put(newWid, widgetsResource); } } } mainPanel.invalidate(); mainPanel.validate(); mainPanel.repaint(); } } } } } }