package holeg.algorithm.example; import holeg.api.AddOn; import holeg.model.AbstractCanvasObject; import holeg.model.GroupNode; import holeg.model.HolonElement; import holeg.model.HolonObject; import holeg.model.HolonSwitch; import holeg.model.HolonSwitch.SwitchMode; import holeg.model.HolonSwitch.SwitchState; import holeg.model.Model; import holeg.ui.controller.Control; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.image.BufferedImage; import java.text.NumberFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.text.NumberFormatter; public class DemoAlgo implements AddOn { //Parameter for Algo with default Values: int counter; //Settings For GroupNode using and cancel private boolean useGroupNode = false; private Optional groupNode = Optional.empty(); private boolean cancel = false; //Parameter defined by Algo private HashMap access; private List initialState; private List switchList; private List objectList; //Gui Part: private Control control; private JTextArea textArea; private JPanel content = new JPanel(); private long startTime; private Thread runThread; //Windrad private HolonObject windrad; private int waitDurationWindradStep = 400; private int waitDurationEnd = 1000; public DemoAlgo() { content.setLayout(new BorderLayout()); textArea = new JTextArea(); textArea.setEditable(false); JScrollPane scrollPane = new JScrollPane(textArea); JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, createOptionPanel(), scrollPane); splitPane.setResizeWeight(0.0); content.add(splitPane, BorderLayout.CENTER); content.setPreferredSize(new Dimension(800, 800)); } public static void main(String[] args) { JFrame newFrame = new JFrame("exampleWindow"); DemoAlgo instance = new DemoAlgo(); newFrame.setContentPane(instance.getPanel()); newFrame.pack(); newFrame.setVisible(true); newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public JPanel createOptionPanel() { JPanel optionPanel = new JPanel(new BorderLayout()); JScrollPane scrollPane = new JScrollPane(createParameterPanel()); scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter")); optionPanel.add(scrollPane, BorderLayout.CENTER); optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END); return optionPanel; } private Component createParameterPanel() { JPanel parameterPanel = new JPanel(null); parameterPanel.setPreferredSize(new Dimension(510, 300)); // JLabel showDiagnosticsLabel = new JLabel("Set all switches closed:"); // showDiagnosticsLabel.setBounds(200, 60, 170, 20); // parameterPanel.add(showDiagnosticsLabel); JPanel borderPanel = new JPanel(null); borderPanel.setBounds(200, 85, 185, 50); borderPanel.setBorder(BorderFactory.createTitledBorder("")); parameterPanel.add(borderPanel); JLabel showGroupNodeLabel = new JLabel("Use Group Node:"); showGroupNodeLabel.setBounds(10, 1, 170, 20); borderPanel.add(showGroupNodeLabel); JButton selectGroupNodeButton = new JButton("Select GroupNode"); selectGroupNodeButton.setEnabled(false); selectGroupNodeButton.setBounds(10, 25, 165, 20); selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode()); borderPanel.add(selectGroupNodeButton); JCheckBox useGroupNodeCheckBox = new JCheckBox(); useGroupNodeCheckBox.setSelected(false); useGroupNodeCheckBox.setBounds(155, 1, 25, 20); useGroupNodeCheckBox.addActionListener(actionEvent -> { useGroupNode = useGroupNodeCheckBox.isSelected(); selectGroupNodeButton.setEnabled(useGroupNode); }); borderPanel.add(useGroupNodeCheckBox); // JCheckBox switchesCheckBox = new JCheckBox(); // switchesCheckBox.setSelected(closeSwitches); // switchesCheckBox.setBounds(370, 60, 25, 20); // switchesCheckBox.addActionListener(actionEvent -> closeSwitches = switchesCheckBox.isSelected()); // parameterPanel.add(switchesCheckBox); JButton selectRoom1Button = new JButton("Select"); selectRoom1Button.setBounds(10, 300, 90, 20); selectRoom1Button.addActionListener(actionEvent -> this.selectHolonObject()); parameterPanel.add(selectRoom1Button); NumberFormat format = NumberFormat.getIntegerInstance(); format.setGroupingUsed(false); format.setParseIntegerOnly(true); NumberFormatter integerFormatter = new NumberFormatter(format); integerFormatter.setMinimum(0); integerFormatter.setCommitsOnValidEdit(true); JLabel portLabel = new JLabel("between:"); portLabel.setBounds(10, 330, 70, 30); parameterPanel.add(portLabel); JFormattedTextField betweenTF = new JFormattedTextField(integerFormatter); betweenTF.setText("" + waitDurationWindradStep); betweenTF.setBounds(80, 330, 80, 30); betweenTF.addPropertyChangeListener(propertyChange -> { String text = betweenTF.getValue().toString(); text = text.replaceAll("\\s", ""); waitDurationWindradStep = Integer.parseInt((text)); }); parameterPanel.add(betweenTF); JLabel afterLabel = new JLabel("after:"); afterLabel.setBounds(10, 360, 70, 30); parameterPanel.add(afterLabel); JFormattedTextField afterTF = new JFormattedTextField(integerFormatter); afterTF.setText("" + waitDurationEnd); afterTF.setBounds(80, 360, 80, 30); afterTF.addPropertyChangeListener(propertyChange -> { String text = afterTF.getValue().toString(); text = text.replaceAll("\\s", ""); waitDurationEnd = Integer.parseInt((text)); }); parameterPanel.add(afterTF); return parameterPanel; } public JPanel createButtonPanel() { JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); JButton cancelButton = new JButton("Cancel Run"); cancelButton.addActionListener(actionEvent -> cancel()); buttonPanel.add(cancelButton); JButton clearButton = new JButton("Clear Console"); clearButton.addActionListener(actionEvent -> clear()); buttonPanel.add(clearButton); JButton resetButton = new JButton("Reset"); resetButton.setToolTipText("Resets the State to before the Algorithm has runed."); resetButton.addActionListener(actionEvent -> reset()); buttonPanel.add(resetButton); JButton runButton = new JButton("Run"); runButton.addActionListener(actionEvent -> { Runnable task = () -> run(); runThread = new Thread(task); runThread.start(); }); buttonPanel.add(runButton); return buttonPanel; } private void cancel() { if (runThread.isAlive()) { println(""); println("Cancel run."); cancel = true; } else { println("Nothing to cancel."); } } private void run() { cancel = false; disableGuiInput(true); startTimer(); executeDemoAlgo(); if (cancel) { reset(); disableGuiInput(false); return; } printElapsedTime(); disableGuiInput(false); } private void reset() { if (initialState != null) { println("Resetting.."); resetState(); updateVisual(); } else { println("No run inistialized."); } } private void disableGuiInput(boolean bool) { control.guiSetEnabled(bool); } @Override public JPanel getPanel() { return content; } @Override public void setController(Control control) { this.control = control; } private void clear() { textArea.setText(""); } private void println(String message) { textArea.append(message + "\n"); } private void selectGroupNode() { Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive() .toArray(); GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:", "GroupNode?", JOptionPane.OK_OPTION, new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, ""); if (selected != null) { println("Selected: " + selected); groupNode = Optional.of(selected); } } private void startTimer() { startTime = System.currentTimeMillis(); } private void printElapsedTime() { long elapsedMilliSeconds = System.currentTimeMillis() - startTime; println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds); } //Algo Part: private void executeDemoAlgo() { extractPositionAndAccess(); counter = 0; int actualIteration = control.getModel().getCurrentIteration(); deactivateWindrad(); setAllSwitchesClosed(); updateVisual(); try { //Schalte Slow das Windrad Ein if (windrad == null) { return; } windrad.elementsStream().forEach(hE -> { hE.active = true; try { TimeUnit.MILLISECONDS.sleep(waitDurationWindradStep); } catch (InterruptedException e) { } updateVisual(); }); TimeUnit.MILLISECONDS.sleep(waitDurationEnd); } catch (InterruptedException e) { } setHolonElemntsAktiv(actualIteration); println("Changed Elements: " + counter); updateVisual(); } private void deactivateWindrad() { if (windrad == null) { return; } windrad.elementsStream().forEach(ele -> ele.active = false); } private void setHolonElemntsAktiv(int actualIteration) { for (int i = 0; i < access.size(); i++) { AccessWrapper aw = access.get(i); if (aw.getState(actualIteration) == false) { counter++; } if (aw.getType() == AccessWrapper.HOLONELEMENT) { aw.setState(true); } } } private void setAllSwitchesClosed() { for (HolonSwitch hSwitch : switchList) { if (hSwitch.getManualState().isOpen()) { counter++; } hSwitch.setMode(SwitchMode.Manual); hSwitch.setManualState(SwitchState.Closed); } } /** * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects * on the Canvas. Also initialize the Access Hashmap to swap faster positions. * * @return */ private List extractPositionAndAccess() { Model model = control.getModel(); switchList = new ArrayList(); objectList = new ArrayList(); initialState = new ArrayList(); access = new HashMap(); rollOutNodes((useGroupNode && groupNode.isPresent()) ? groupNode.get().getObjectsInThisLayer() : model.getCanvas().getObjectsInThisLayer(), initialState, model.getCurrentIteration()); return initialState; } /** * Method to extract the Informations recursively out of the Model. * * @param nodes * @param positionToInit * @param timeStep */ private void rollOutNodes(Stream nodes, List positionToInit, int timeStep) { nodes.forEach(aCps -> { if (aCps instanceof HolonObject hO) { hO.elementsStream().forEach(hE -> { positionToInit.add(hE.active); access.put(positionToInit.size() - 1, new AccessWrapper(hE)); }); objectList.add(hO); } else if (aCps instanceof HolonSwitch sw) { positionToInit.add(sw.getState().isClosed()); switchList.add(sw); access.put(positionToInit.size() - 1, new AccessWrapper(sw)); } else if (aCps instanceof GroupNode groupnode) { rollOutGroupNode(groupnode, positionToInit, timeStep); } }); } private void rollOutGroupNode(GroupNode groupNode, List positionToInit, int timeStep) { groupNode.getAllHolonObjectsRecursive().forEach(hObject -> { hObject.elementsStream().forEach(hE -> { positionToInit.add(hE.active); access.put(positionToInit.size() - 1, new AccessWrapper(hE)); }); objectList.add(hObject); }); groupNode.getAllSwitchObjectsRecursive().forEach(sw -> { positionToInit.add(sw.getState().isClosed()); switchList.add(sw); access.put(positionToInit.size() - 1, new AccessWrapper(sw)); }); } /** * To let the User See the current state without touching the Canvas. */ private void updateVisual() { control.calculateStateForCurrentIteration(); } /** * Sets the Model back to its original State before the LAST run. */ private void resetState() { setState(initialState); } /** * Sets the State out of the given position for calculation or to show the user. * * @param position */ private void setState(List position) { for (int i = 0; i < position.size(); i++) { access.get(i).setState(position.get(i)); } } private void selectHolonObject() { List holonObjectList = new ArrayList(); addObjectToList(control.getModel().getCanvas().getObjectsInThisLayer().toList(), holonObjectList); Object[] possibilities = holonObjectList.stream().map(aCps -> new Handle(aCps)) .toArray(); @SuppressWarnings("unchecked") Handle selected = (Handle) JOptionPane.showInputDialog(content, "Select HolonObject:", "HolonObject?", JOptionPane.OK_OPTION, new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, ""); if (selected != null) { //println("Selected: " + selected); windrad = selected.object; } } private void addObjectToList(List listToSearch, List listToAdd) { for (AbstractCanvasObject aCps : listToSearch) { if (aCps instanceof HolonObject hO) { listToAdd.add(hO); } else if (aCps instanceof GroupNode groupNode) { listToAdd.addAll(groupNode.getAllHolonObjectsRecursive().toList()); } } } /** * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split * the List. */ private class AccessWrapper { public static final int HOLONELEMENT = 0; public static final int SWITCH = 1; private int type; private HolonSwitch hSwitch; private HolonElement hElement; public AccessWrapper(HolonSwitch hSwitch) { type = SWITCH; this.hSwitch = hSwitch; } public AccessWrapper(HolonElement hElement) { type = HOLONELEMENT; this.hElement = hElement; } public void setState(boolean state) { if (type == HOLONELEMENT) { hElement.active = state; } else {//is switch hSwitch.setMode(SwitchMode.Manual); hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open); } } public boolean getState(int timeStep) { return (type == HOLONELEMENT) ? hElement.active : hSwitch.getState().isClosed(); } public int getType() { return type; } } private class Handle { public T object; Handle(T object) { this.object = object; } public String toString() { return object.toString(); } } }