package ui.view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.OverlayLayout; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import org.knowm.xchart.CategoryChart; import org.knowm.xchart.CategoryChartBuilder; import org.knowm.xchart.PieChart; import org.knowm.xchart.PieChartBuilder; import org.knowm.xchart.PieSeries.PieSeriesRenderStyle; import org.knowm.xchart.XChartPanel; import org.knowm.xchart.style.CategoryStyler; import org.knowm.xchart.style.PieStyler; import org.knowm.xchart.style.PieStyler.LabelType; import classes.AbstractCanvasObject; import classes.Flexibility; import classes.GroupNode; import classes.HolonElement; import classes.HolonObject; import preferences.ColorPreference; import ui.controller.Control; import ui.controller.FlexManager; import ui.controller.FlexManager.FlexWrapper; import ui.model.Consumer; import ui.model.DecoratedGroupNode; import ui.model.DecoratedGroupNode.PriorityCounts; import ui.model.DecoratedHolonObject; import ui.model.DecoratedHolonObject.HolonObjectState; import ui.model.Model; import ui.model.Passiv; import ui.model.Supplier; import util.StringFormat; public class HolonInformationPanel extends JPanel { private final int defaultWidth = 50; private final int defaultHeight = 200; private PieChart supplyChart = createSupplyStateChart(); private PieChart priorityChart = createPriorityChart(); private PieChart flexibilityChart = createFlexibilityChart(); private PieChart energyChart = createProductionChart(); private PieChart activeChart = createActiveChart(); private XChartPanel panelHolonObject; private XChartPanel panelPriority; private XChartPanel panelFlexibility; private XChartPanel panelEnergy; private XChartPanel panelActive; // TODO is this needed to be fields private JPanel graphPanel = new JPanel(new GridLayout(0, 2)); private JPanel titlePanel = new JPanel(new BorderLayout(0, 0)); private Control control; private JTextField titleTextField; private JLabel differenceEnergyLabelAmount; public static void main(String[] args) { HolonInformationPanel exampleChart = new HolonInformationPanel(new Control(new Model())); JFrame frame = new JFrame(); frame.setContentPane(exampleChart); frame.pack(); frame.setBounds(0, 0, 540, 600); frame.setLocationRelativeTo(null); frame.setVisible(true); } public void updateCharts() { DecoratedGroupNode decoratedGroupNode; switch (control.getModel().getSelectedCpsObjects().size()) { case 0: return; case 1: titleTextField.setText(control.getModel().getSelectedCpsObjects().get(0).getName()); decoratedGroupNode = multiSelectionToDecoratedGroupNode(); break; default: titleTextField.setText(getMultiSelectionName()); decoratedGroupNode = multiSelectionToDecoratedGroupNode(); break; } // UPDATE SUPPLY STATE int producerAmount = decoratedGroupNode.getAmountOfSupplier(); int overSuppliedAmount = decoratedGroupNode.getAmountOfConsumerWithState(HolonObjectState.OVER_SUPPLIED); int suppliedAmount = decoratedGroupNode.getAmountOfConsumerWithState(HolonObjectState.SUPPLIED); int partiallySuppliedAmount = decoratedGroupNode .getAmountOfConsumerWithState(HolonObjectState.PARTIALLY_SUPPLIED); int notSuppliedAmount = decoratedGroupNode.getAmountOfConsumerWithState(HolonObjectState.NOT_SUPPLIED); int noEnergyAmount = decoratedGroupNode.getAmountOfPassiv(); supplyChart.updatePieSeries("Producer", producerAmount); supplyChart.updatePieSeries("Over supplied", overSuppliedAmount); supplyChart.updatePieSeries("Supplied", suppliedAmount); supplyChart.updatePieSeries("Partial supplied", partiallySuppliedAmount); supplyChart.updatePieSeries("Not supplied", notSuppliedAmount); supplyChart.updatePieSeries("No energy", noEnergyAmount); panelHolonObject.updateToolTips(); // UPDATE PRIORITYS PriorityCounts priorityCounts = decoratedGroupNode.getPriorityCounts(); priorityChart.updatePieSeries("Essential", priorityCounts.essential); priorityChart.updatePieSeries("High", priorityCounts.high); priorityChart.updatePieSeries("Medium", priorityCounts.medium); priorityChart.updatePieSeries("Low", priorityCounts.low); boolean hasPriority = priorityCounts.essential + priorityCounts.high + priorityCounts.medium + priorityCounts.low > 0; priorityChart.updatePieSeries("No Data", hasPriority ? 0 : 1); panelPriority.updateToolTips(); // UPDATE PRODUCTION float production = decoratedGroupNode.getProductionFromSupplier(); float consumption = decoratedGroupNode.getConsumptionFromConsumer(); float difference = Math.abs(production - consumption); energyChart.updatePieSeries("Production", production); energyChart.updatePieSeries("Consumption", consumption); differenceEnergyLabelAmount.setText(StringFormat.doubleFixedPlaces(1, difference)); panelEnergy.updateToolTips(); // UPDATE FLEXIBILITIES int inUse = 0; int offered = 0; int onCooldown = 0; int notOffered = 0; int unavailable = 0; // FlexManager manager = control.getSimManager().getActualFlexManager(); // Stream flexWrapperStream = decoratedGroupNode.getFlexibilitiesStream() // .map(flex -> manager.getFlexWrapperFromFlexibility(flex)); // List wrapperList = flexWrapperStream.collect(Collectors.toList()); List wrapperList = control.getModel().getHolonsByID().values().stream() .map(h -> h.getParent() != null ? h.holonControlUnit.getFlexMan().getFlexManager(control.getModel().getCurIteration()).getAllFlexWrapper() : new ArrayList()) .flatMap(List::stream) .collect(Collectors.toList()); for (FlexWrapper wrapper : wrapperList) { switch (wrapper.getState()) { case IN_USE: inUse++; break; case NOT_OFFERED: notOffered++; break; case OFFERED: offered++; break; case ON_COOLDOWN: onCooldown++; break; case UNAVAILABLE: unavailable++; break; default: break; } } flexibilityChart.updatePieSeries("Offered", offered); flexibilityChart.updatePieSeries("In use", inUse); flexibilityChart.updatePieSeries("On cooldown", onCooldown); flexibilityChart.updatePieSeries("Not offered", notOffered); flexibilityChart.updatePieSeries("Unavailable", unavailable); boolean hasFlex = offered + inUse + onCooldown + notOffered + unavailable > 0; flexibilityChart.updatePieSeries("No Data", hasFlex ? 0 : 1); panelFlexibility.updateToolTips(); // UPDATE ActiveInActive int activeAmount = decoratedGroupNode.getAmountOfAktiveElemntsFromHolonObjects(); int inactiveAmounts = decoratedGroupNode.getAmountOfElemntsFromHolonObjects() - activeAmount; activeChart.updatePieSeries("Active", activeAmount); activeChart.updatePieSeries("Inactive", inactiveAmounts); panelActive.updateToolTips(); this.revalidate(); this.repaint(); } private String getMultiSelectionName() { String name = control.getModel().getSelectedCpsObjects().stream().map(AbstractCanvasObject::getName) .collect(Collectors.joining(", ")); if(name.length() > 25) { name = name.substring(0, 25); name += "..."; } return name; } private DecoratedGroupNode multiSelectionToDecoratedGroupNode() { // TODO Create DecoratedGroupNode DecoratedGroupNode temp = new DecoratedGroupNode(new GroupNode("Temp")); // TODO get consumer, supplier, passiv // GroupNodes HashMap accessMapGroupNode = control.getSimManager() .getActualVisualRepresentationalState().getCreatedGroupNodes(); List groupNodeList = control.getModel().getSelectedCpsObjects().stream() .filter(object -> object instanceof GroupNode).map(object -> accessMapGroupNode.get(object)) .collect(Collectors.toList()); temp.getGroupNodeList().addAll(groupNodeList); // HolonObjects HashMap accessMapHolonObject = control.getSimManager() .getActualVisualRepresentationalState().createdHolonObjects; List holonObjectList = control.getModel().getSelectedCpsObjects().stream() .filter(object -> object instanceof HolonObject).map(object -> accessMapHolonObject.get(object)) .collect(Collectors.toList()); for (DecoratedHolonObject object : holonObjectList) { switch (object.getState()) { case NO_ENERGY: temp.getPassivList().add((Passiv) object); break; case PRODUCER: temp.getSupplierList().add((Supplier) object); break; default: temp.getConsumerList().add((Consumer) object); break; } } return temp; } public HolonInformationPanel(Control control) { control.OnSelectionUpdate.addListener(() -> updateCharts()); this.control = control; this.setLayout(new BorderLayout()); initGraphPanel(); initTitlePanel(); this.setBackground(ColorPreference.Panel.Background); this.add(titlePanel, BorderLayout.PAGE_START); this.add(graphPanel, BorderLayout.CENTER); } public void initGraphPanel() { graphPanel.setBackground(ColorPreference.Panel.Background); panelHolonObject = new XChartPanel(supplyChart); panelHolonObject.setBackground(ColorPreference.Panel.Background); graphPanel.add(panelHolonObject); panelPriority = new XChartPanel(priorityChart); panelPriority.setBackground(ColorPreference.Panel.Background); graphPanel.add(panelPriority); panelFlexibility = new XChartPanel(flexibilityChart); panelFlexibility.setBackground(ColorPreference.Panel.Background); graphPanel.add(panelFlexibility); Component panel = initEnergyChart(); graphPanel.add(panel); panelActive = new XChartPanel(activeChart); panelActive.setBackground(ColorPreference.Panel.Background); panelActive.setLayout(new GridBagLayout()); graphPanel.add(panelActive); graphPanel.setBorder(BorderFactory.createLineBorder(Color.lightGray)); } private JLayeredPane initEnergyChart() { JLayeredPane panel = new JLayeredPane(); JPanel panelMiddle = new JPanel(new GridBagLayout()); panelEnergy = new XChartPanel(energyChart); panelEnergy.setBackground(ColorPreference.Panel.Background); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; c.insets = new Insets(15, 0, 0, 0); // top padding JLabel difference = new JLabel("Difference:"); difference.setHorizontalAlignment(JLabel.CENTER); difference.setAlignmentX(Component.CENTER_ALIGNMENT); difference.setForeground(ColorPreference.Panel.Title); difference.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 10)); panelMiddle.add(difference, c); differenceEnergyLabelAmount = new JLabel(""); differenceEnergyLabelAmount.setHorizontalAlignment(JLabel.CENTER); differenceEnergyLabelAmount.setForeground(Color.red); differenceEnergyLabelAmount.setAlignmentX(Component.CENTER_ALIGNMENT); differenceEnergyLabelAmount.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 12)); c.insets = new Insets(0, 0, 0, 0); c.gridy = 1; panelMiddle.add(differenceEnergyLabelAmount, c); panel.setLayout(new OverlayLayout(panel)); panelEnergy.setOpaque(false); panelMiddle.setOpaque(false); panel.add(panelMiddle, Integer.valueOf(0)); panel.add(panelEnergy, Integer.valueOf(1)); return panel; } public void initTitlePanel() { titleTextField = new JTextField(""); titleTextField.setFont(new Font("Arial", Font.BOLD, 24)); titleTextField.setForeground(ColorPreference.Panel.Title); titleTextField.setBackground(ColorPreference.Panel.Background); titleTextField.setBackground(null); titleTextField.setBorder(null); titlePanel.setBackground(ColorPreference.Panel.Background); titlePanel.setBorder(new EmptyBorder(5, 5, 2, 0)); titlePanel.add(titleTextField, BorderLayout.CENTER); } public void setDefaultPieChartSettings(PieChart chart) { PieStyler styler = chart.getStyler(); styler.setChartTitleVisible(true); styler.setDefaultSeriesRenderStyle(PieSeriesRenderStyle.Donut); styler.setLabelsFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 14)); styler.setLabelType(LabelType.Percentage); styler.setLabelsFontColor(Color.black); styler.setLabelsFontColorAutomaticEnabled(false); styler.setLabelsDistance(0.8); styler.setChartFontColor(ColorPreference.Panel.Title); styler.setToolTipsEnabled(true); styler.setPlotContentSize(0.9); styler.setPlotBackgroundColor(ColorPreference.Panel.Transparent); styler.setPlotBorderColor(ColorPreference.Panel.Transparent); styler.setLegendVisible(false); styler.setChartBackgroundColor(ColorPreference.Panel.Transparent); } public PieChart createSupplyStateChart() { PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Holon Objects").build(); setDefaultPieChartSettings(chart); Color[] sliceColors = new Color[] { ColorPreference.HolonObject.Producer, ColorPreference.HolonObject.OverSupplied, ColorPreference.HolonObject.Supplied, ColorPreference.HolonObject.PartiallySupplied, ColorPreference.HolonObject.NotSupplied, ColorPreference.HolonObject.NoEnergy }; chart.getStyler().setSeriesColors(sliceColors); // Series chart.addSeries("Producer", 0); chart.addSeries("Over supplied", 0); chart.addSeries("Supplied", 0); chart.addSeries("Partial supplied", 0); chart.addSeries("Not supplied", 0); chart.addSeries("No energy", 0); return chart; } public PieChart createPriorityChart() { // Create Chart PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Priotities").build(); setDefaultPieChartSettings(chart); // Customize Chart Color[] sliceColors = new Color[] { ColorPreference.Element.Priority.Essential, ColorPreference.Element.Priority.High, ColorPreference.Element.Priority.Medium, ColorPreference.Element.Priority.Low, ColorPreference.Element.Priority.NoData }; chart.getStyler().setSeriesColors(sliceColors); // Series chart.addSeries("Essential", 0); chart.addSeries("High", 0); chart.addSeries("Medium", 0); chart.addSeries("Low", 0); chart.addSeries("No Data", 0); return chart; } public PieChart createFlexibilityChart() { // IN_USE, ON_COOLDOWN, OFFERED, NOT_OFFERED, UNAVAILABLE // Create Chart PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Flexibilities").build(); setDefaultPieChartSettings(chart); // Customize Chart Color[] sliceColors = new Color[] { ColorPreference.Flexibility.Offered, ColorPreference.Flexibility.InUse, ColorPreference.Flexibility.OnCooldown, ColorPreference.Flexibility.NotOffered, ColorPreference.Flexibility.Unavailable, ColorPreference.Element.Priority.NoData }; chart.getStyler().setSeriesColors(sliceColors); // Series chart.addSeries("Offered", 0); chart.addSeries("In use", 0); chart.addSeries("On cooldown", 0); chart.addSeries("Not offered", 0); chart.addSeries("Unavailable", 0); chart.addSeries("No Data", 0); return chart; } public PieChart createProductionChart() { // Create Chart PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight) .title("Production vs. Consumption").build(); setDefaultPieChartSettings(chart); // Customize Chart // Customize Chart Color[] barColors = new Color[] { ColorPreference.Energy.Production, ColorPreference.Energy.Consumption }; chart.getStyler().setSeriesColors(barColors); // Series chart.addSeries("Production", 0); chart.addSeries("Consumption", 0); return chart; } public PieChart createActiveChart() { // Create Chart PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Active").build(); setDefaultPieChartSettings(chart); // Customize Chart // Customize Chart Color[] barColors = new Color[] { ColorPreference.Element.Active, ColorPreference.Element.Inactive }; chart.getStyler().setSeriesColors(barColors); // Series chart.addSeries("Active", 0); chart.addSeries("Inactive", 0); return chart; } }