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.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.DecoratedGroupNode; import ui.model.DecoratedGroupNode.PriorityCounts; import ui.model.DecoratedHolonObject.HolonObjectState; import ui.model.Model; 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() { // TODO check for a method without instanceof and cast List list = control.getModel().getSelectedCpsObjects().stream() .filter(object -> object instanceof GroupNode).map(object -> (GroupNode) object) .collect(Collectors.toList()); if (list.size() != 1) { return; } GroupNode groupNode = list.get(0); DecoratedGroupNode decoratedGroupNode = control.getSimManager().getActualVisualRepresentationalState() .getCreatedGroupNodes().get(groupNode); // UPDATE NAME titleTextField.setText(groupNode.getName()); // 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()); 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(); } 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; } }