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.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
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.ListTerm;
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";
public final String OnTableChangedChannelName = "OnTableChanged";
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 DataTransferChannel onTableChangedChannel;
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);
onTableChangedChannel = (DataTransferChannel)simulator.getModel().getChannel(OnTableChangedChannelName);
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("table")) {
// 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");
MapTerm data = (MapTerm)widget.get("data");
ListTerm columnsList = (ListTerm)widget.get("columns");
Constant rowNumExp = (Constant)widget.get("rowNum");
Constant rowHeightExp = (Constant)widget.get("rowHeight");
Constant primaryKeyNameExp = (Constant) widget.get("primaryKeyName");
boolean primaryKeyVisible = !primaryKeyNameExp.getValue().equals("");
// JLabel label = new JLabel(((String) ((Constant) text).getValue()));
int colNum = columnsList.size() + (primaryKeyVisible ? 1 : 0);
String[] columns = new String[colNum];
String[][] tableDatas = new String[data.keySet().size()][colNum];
if(primaryKeyVisible) {
columns[0] = (String)primaryKeyNameExp.getValue();
for(int i = 1; i < colNum; i++) {
columns[i] = (String)((Constant)columnsList.get(i - 1)).getValue();
}
} else {
for(int i = 0; i < colNum; i++) {
columns[i] = (String)((Constant)columnsList.get(i)).getValue();
}
}
int dataCount = 0;
for(String dataKey : data.keySet()) {
JsonTerm rowData = (JsonTerm) data.get(dataKey);
if(primaryKeyVisible) {
tableDatas[dataCount][0] = dataKey;
for(int j = 1; j < columns.length; j++) {
Constant cellValue = (Constant) rowData.get(columns[j]);
if(cellValue == null) {
tableDatas[dataCount][j] = "error";
} else {
tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue();
}
}
} else {
for(int j = 0; j < columns.length; j++) {
Constant cellValue = (Constant) rowData.get(columns[j]);
if(cellValue == null) {
tableDatas[dataCount][j] = "error";
} else {
tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue();
}
}
}
dataCount++;
}
DefaultTableModel tableModel = new DefaultTableModel(tableDatas, columns);
JTable table = new JTable(tableModel) {
@Override
public boolean isCellEditable(int row, int col) {
return false;
}
};
JScrollPane scroll = new JScrollPane(table);
if (x != null && y != null) {
scroll.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString()));
}
if (width != null && height != null) {
scroll.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString()));
}
mainPanel.add(scroll);
components.put(newWid, scroll);
// Connect swing component and model.
ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(scroll); // 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);
Resource widgetXResource = widgetResource.getChildrenMap().get("x");
if (widgetXResource != null) {
ComponentXReceiver nativeXReceiver = new ComponentXReceiver(scroll); // 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(scroll); // 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(scroll); // 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(scroll); // 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);
}
Resource widgetDataResource = widgetResource.getChildrenMap().get("data");
if(widgetDataResource != null ) {
TableDataReceiver tableDataReceiver = new TableDataReceiver(tableModel, columns, (String)((Constant) primaryKeyNameExp).getValue());
simulator.addNativeReceiver(tableDataReceiver, onTableChangedChannel, widgetDataResource);
resources = channelAndResourcesForReceiving.get(onTableChangedChannel);
if(resources == null) {
resources = new HashMap<>();
channelAndResourcesForReceiving.put(onTableChangedChannel, resources);
}
resources.put(newWid, widgetDataResource);
}
} 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);
}
}
}
}
}
}