📄 graphpanel.java
字号:
/**
* Copyright (C) 2006, Laboratorio di Valutazione delle Prestazioni - Politecnico di Milano
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package jmt.gui.exact.panels;
import jmt.gui.wizard.WizardPanel;
import jmt.gui.exact.ExactModel;
import jmt.gui.exact.ExactConstants;
import jmt.gui.exact.utils.WhatIfPlot;
import jmt.gui.exact.utils.ArrayUtils;
import jmt.gui.common.editors.ColorCellEditor;
import jmt.gui.common.editors.ComboBoxCellEditor;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.*;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.util.Arrays;
/**
* <p>Title: Graph Panel</p>
* <p>Description: This panelis used to display JMVA what-if analysis
* results in a graph. Number of allowed lines in graph is determined
* by <code>graph.getColors().length</code>. Modify it to allow more lines.</p>
*
* @author Bertoli Marco
* Date: 1-giu-2006
* Time: 11.01.29
*/
public class GraphPanel extends WizardPanel implements ExactConstants {
// Data structure
private ExactModel model;
// Plot
private WhatIfPlot graph;
// Performance index selector
private JComboBox index;
// Bounds for graph
private JSpinner Xmin, Xmax, Ymin, Ymax;
// Tells if spinner update is forced. This is needed to avoid that updates made by
// code will be interpreted as updated made by user.
private boolean forcedUpdate = false;
// Table used to select performance indices to be plotted
private LinesTable table;
// Scrollpane used for table
private JScrollPane tableScrollPane;
// Dimension of bounds spinners
final static Dimension DIM_SPINNER = new Dimension(60,20);
// Current performance index
private String currentIndex = "none";
// Selected performance indices
private int[] classes;
private int[] stations;
// Aggregate special value
private static final String AGGREGATE = "<html><b><i>Aggregate</i></b></html>";
/**
* Builds a new GraphPanel, given an exact model data structure
* @param model reference to data structure
*/
public GraphPanel(ExactModel model) {
this.model = model;
initGraphics();
}
/**
* Initialize GUI of this panel
*/
private void initGraphics() {
setLayout(new BorderLayout(10,10));
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
JPanel mainPanel = new JPanel(new BorderLayout(5,5));
mainPanel.setBorder(BorderFactory.createEtchedBorder());
// Adds description label
JLabel descrLabel = new JLabel(DESCRIPTION_GRAPH);
add(descrLabel, BorderLayout.NORTH);
add(mainPanel, BorderLayout.CENTER);
// Creates left panel with options
JPanel left = new JPanel(new BorderLayout(3,3));
// Adds performance index selection
JPanel indexPanel = new JPanel();
JLabel pIndex = new JLabel("Performance index: ");
index = new JComboBox(ExactModel.INDICES_TYPES);
// Adds aggregate types
for (int i=0; i<AGGREGATE_TYPES.length; i++)
index.addItem(AGGREGATE_TYPES[i]);
pIndex.setLabelFor(index);
indexPanel.add(pIndex);
indexPanel.add(index);
left.add(indexPanel, BorderLayout.NORTH);
// Adds panel for bounds selection
JPanel boundsPanel = new JPanel(new GridLayout(2, 4,1,1));
boundsPanel.add(new JLabel("Xmin: ", JLabel.RIGHT));
Xmin = new JSpinner(new SpinnerNumberModel(0.0, 0.0, 1e10, 0.01));
Xmin.setPreferredSize(DIM_SPINNER);
boundsPanel.add(Xmin);
boundsPanel.add(new JLabel("Xmax: ", JLabel.RIGHT));
Xmax = new JSpinner(new SpinnerNumberModel(0.0, 0.0, 1e10, 0.01));
Xmax.setPreferredSize(DIM_SPINNER);
boundsPanel.add(Xmax);
boundsPanel.add(new JLabel("Ymin: ", JLabel.RIGHT));
Ymin = new JSpinner(new SpinnerNumberModel(0.0, 0.0, 1e10, 0.01));
Ymin.setPreferredSize(DIM_SPINNER);
boundsPanel.add(Ymin);
boundsPanel.add(new JLabel("Ymax: ", JLabel.RIGHT));
Ymax = new JSpinner(new SpinnerNumberModel(0.0, 0.0, 1e10, 0.01));
Ymax.setPreferredSize(DIM_SPINNER);
boundsPanel.add(Ymax);
left.add(boundsPanel, BorderLayout.SOUTH);
mainPanel.add(left, BorderLayout.WEST);
// Puts graph in the right panel
// Creates label for X-axis
String xLabel= "";
if (model.getWhatIfClass() >= 0) {
graph = new WhatIfPlot(model.getWhatIfValues());
if (model.getWhatIfType().equals(ExactModel.WHAT_IF_ARRIVAL))
xLabel = "Arrival rate \u03bbi for "+ model.getClassNames()[model.getWhatIfClass()] + " [job/s]";
else if (model.getWhatIfType().equals(ExactModel.WHAT_IF_CUSTOMERS))
xLabel = "Number of customers Ni for " + model.getClassNames()[model.getWhatIfClass()];
else if (model.getWhatIfType().equals(ExactModel.WHAT_IF_DEMANDS))
xLabel = "Service demand Di for "+
model.getClassNames()[model.getWhatIfClass()]+
" at "+ model.getStationNames()[model.getWhatIfStation()]+" [s]";
else if (model.getWhatIfType().equals(ExactModel.WHAT_IF_MIX))
xLabel = "Population mix \u03b2i for "+model.getClassNames()[model.getWhatIfClass()];
}
else {
graph = new WhatIfPlot(ArrayUtils.multiply(model.getWhatIfValues(), 100.0));
if (model.getWhatIfType().equals(ExactModel.WHAT_IF_ARRIVAL))
xLabel = "% of arrival rates \u03bbi w.r.t. initial values";
else if (model.getWhatIfType().equals(ExactModel.WHAT_IF_CUSTOMERS))
xLabel = "% of customers Ni w.r.t. initial values";
else if (model.getWhatIfType().equals(ExactModel.WHAT_IF_DEMANDS))
xLabel = "% of Service demands Di at "
+model.getStationNames()[model.getWhatIfStation()]+
" w.r.t. initial values";
}
graph.setXLabel(xLabel);
mainPanel.add(graph, BorderLayout.CENTER);
// Adds table and inits data structure for it.
classes = new int[graph.getColors().length];
if (model.isMultiClass()) // If model is single-class, select first class by default
Arrays.fill(classes, -10);
stations = new int[graph.getColors().length];
Arrays.fill(stations, -10);
table = new LinesTable();
tableScrollPane = new JScrollPane(table);
tableScrollPane.setPreferredSize(new Dimension(160, tableScrollPane.getPreferredSize().height));
left.add(tableScrollPane, BorderLayout.CENTER);
updateSpinners();
addActions();
updateIndex();
}
/**
* Updates values in spinners used to select ranges to be shown in graph
*/
private void updateSpinners() {
// Check for special value used if graph is empty
if (graph.getXRange()[0] != Double.MAX_VALUE) {
Xmin.setValue(new Double(graph.getXRange()[0]));
Xmax.setValue(new Double(graph.getXRange()[1]));
Ymin.setValue(new Double(graph.getYRange()[0]));
Ymax.setValue(new Double(graph.getYRange()[1]));
}
else {
Xmin.setValue(new Double(0.0));
Xmax.setValue(new Double(0.0));
Ymin.setValue(new Double(0.0));
Ymax.setValue(new Double(0.0));
}
}
/**
* Used when a spinne value is updated
*/
private void setBounds() {
double xmin, xmax, ymin, ymax;
Object val = Xmin.getValue();
if (val instanceof Number)
xmin = ((Number)val).doubleValue();
else
xmin = graph.getXRange()[0];
val = Xmax.getValue();
if (val instanceof Number)
xmax = ((Number)val).doubleValue();
else
xmax = graph.getXRange()[1];
val = Ymin.getValue();
if (val instanceof Number)
ymin = ((Number)val).doubleValue();
else
ymin = graph.getYRange()[0];
val = Ymax.getValue();
if (val instanceof Number)
ymax = ((Number)val).doubleValue();
else
ymax = graph.getYRange()[1];
// Sets bounds
graph.setXRange(xmin, xmax);
graph.setYRange(ymin, ymax);
graph.repaint();
}
/**
* This function must be called each time selected performance
* index changes
*/
private void updateIndex() {
String current = (String)index.getSelectedItem();
if (!current.equals(currentIndex)) {
currentIndex = current;
// System Response time
if (currentIndex.equals(AGGREGATE_TYPES[0])) {
tableScrollPane.setVisible(false);
graph.clear(false);
graph.draw(0, model.getGlobalR());
graph.fillPlot();
}
// System throughput
else if (currentIndex.equals(AGGREGATE_TYPES[1])) {
tableScrollPane.setVisible(false);
graph.clear(false);
graph.draw(0, model.getGlobalX());
graph.fillPlot();
}
// Number of customers
else if (currentIndex.equals(AGGREGATE_TYPES[2])) {
tableScrollPane.setVisible(false);
graph.clear(false);
graph.draw(0, model.getGlobalQ());
graph.fillPlot();
}
// otherwise
else {
tableScrollPane.setVisible(true);
// Removes incorrect utilization measures
if (table.getCellEditor() != null)
table.getCellEditor().stopCellEditing();
if (currentIndex.equals(ExactModel.INDICES_TYPES[3])) {
for (int i=0; i<stations.length; i++)
if (stations[i] == -1)
stations[i] = -2;
}
table.repaint();
paintAllIndices();
}
// Updates graph
graph.setYLabel(current);
graph.repaint();
}
}
/**
* Adds action listeners to GUI components
*/
private void addActions() {
// Listener used for bounds spinners
ChangeListener boundsListener = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (!forcedUpdate) {
setBounds();
updateSpinners();
}
}
};
Xmin.addChangeListener(boundsListener);
Xmax.addChangeListener(boundsListener);
Ymin.addChangeListener(boundsListener);
Ymax.addChangeListener(boundsListener);
// Listener for index selection comboBox
index.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateIndex();
}
});
// Adds a listener to the graph to detect zoom events
graph.addRescaleListener(new WhatIfPlot.RescaleListener() {
public void Rescaled() {
forcedUpdate = true;
updateSpinners();
forcedUpdate = false;
}
});
}
/**
* Paints performance index at specified row
* @param rowNum row number of index to be painted
*/
private void paintIndexAtRow(int rowNum) {
// Clears previous graph
graph.clear(rowNum);
int classNum = classes[rowNum];
int statNum = stations[rowNum];
if (classNum < -1 || statNum < -1) {
// Resets view
autosizeGraph();
return;
}
// Throughput
if (currentIndex.equals(ExactModel.INDICES_TYPES[0])) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -