Java tutorial
//============================================================================== // // Copyright (c) 2002- // Authors: // * Andrew Hinton <ug60axh@cs.bham.ac.uk> (University of Birmingham) // * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford, formerly University of Birmingham) // //------------------------------------------------------------------------------ // // This file is part of PRISM. // // PRISM 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. // // PRISM 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 PRISM; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //============================================================================== package userinterface.properties; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.Desktop; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Vector; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; import org.jfree.chart.ChartPanel; import com.orsoncharts.graphics3d.ExportUtils; import com.orsoncharts.graphics3d.ViewPoint3D; import cern.jet.math.Functions; import param.Function; import parser.Values; import parser.ast.Expression; import parser.ast.ExpressionConstant; import parser.ast.ExpressionIdent; import parser.type.TypeDouble; import parser.visitor.ASTTraverseModify; import prism.PrismException; import prism.PrismLangException; import userinterface.GUIPlugin; import userinterface.GUIPrism; import userinterface.graph.GUIImageExportDialog; import userinterface.graph.Graph; import userinterface.graph.Graph3D; import userinterface.graph.GraphException; import userinterface.graph.GraphOptions; import userinterface.graph.Histogram; import userinterface.graph.ParametricGraph; import userinterface.graph.ParametricGraph3D; import userinterface.graph.PrismXYDataItem; import userinterface.graph.SeriesKey; @SuppressWarnings("serial") public class GUIGraphHandler extends JPanel implements MouseListener { private boolean canDelete; private JTabbedPane theTabs; private JPopupMenu backMenu, graphMenu; private java.util.List<JPanel> models; private java.util.List<GraphOptions> options; private GUIPlugin plug; private Action graphOptions, zoomIn, zoomOut, zoomDefault; private Action printGraph, deleteGraph; private Action exportImageJPG, exportImagePNG, exportPDF, exportImageEPS, exportXML, exportMatlab, exportGnuplot; private Action importXML, addFunction; private JMenu zoomMenu, exportMenu, importMenu; private FileFilter pngFilter, jpgFilter, pdfFilter, epsFilter, graFilter, matlabFilter, gnuplotFilter; public GUIGraphHandler(JFrame parent, GUIPlugin plug, boolean canDelete) { this.plug = plug; this.canDelete = canDelete; this.graphMenu = new JPopupMenu(); this.backMenu = new JPopupMenu(); initComponents(); pngFilter = new FileNameExtensionFilter("PNG files (*.png)", "png"); jpgFilter = new FileNameExtensionFilter("JPEG files (*.jpg, *.jpeg)", "jpg", "jpeg"); pdfFilter = new FileNameExtensionFilter("PDF files(*.pdf)", "pdf"); epsFilter = new FileNameExtensionFilter("Encapsulated PostScript files (*.eps)", "eps"); graFilter = new FileNameExtensionFilter("PRISM graph files (*.gra, *.xml)", "gra", "xml"); matlabFilter = new FileNameExtensionFilter("Matlab files (*.m)", "m"); gnuplotFilter = new FileNameExtensionFilter("GNU plot files (*gnuplot , *.gplot , *.gp , *.plt , *.gpi)", "gnuplot"); models = new ArrayList<JPanel>(); options = new ArrayList<GraphOptions>(); } private void initComponents() { theTabs = new JTabbedPane() { @Override public String getTitleAt(int index) { try { TabClosePanel panel = (TabClosePanel) getTabComponentAt(index); return panel.getTitle(); } catch (Exception e) { return ""; } } @Override public String getToolTipTextAt(int index) { return ((TabClosePanel) getTabComponentAt(index)).getToolTipText(); } @Override public void setTitleAt(int index, String title) { if (((TabClosePanel) getTabComponentAt(index)) == null) { return; } ((TabClosePanel) getTabComponentAt(index)).setTitle(title); } @Override public void setIconAt(int index, Icon icon) { ((TabClosePanel) getTabComponentAt(index)).setIcon(icon); } @Override public void setToolTipTextAt(int index, String toolTipText) { ((TabClosePanel) getTabComponentAt(index)).setToolTip(toolTipText); } }; theTabs.addMouseListener(this); theTabs.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getPreciseWheelRotation() > 0.0) { if (theTabs.getSelectedIndex() != (theTabs.getTabCount() - 1)) theTabs.setSelectedIndex(theTabs.getSelectedIndex() + 1); } else { if (theTabs.getSelectedIndex() != 0) theTabs.setSelectedIndex(theTabs.getSelectedIndex() - 1); } } }); setLayout(new BorderLayout()); add(theTabs, BorderLayout.CENTER); graphOptions = new AbstractAction() { public void actionPerformed(ActionEvent e) { GraphOptions graphOptions = options.get(theTabs.getSelectedIndex()); graphOptions.setVisible(true); } }; graphOptions.putValue(Action.NAME, "Graph options"); graphOptions.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_G)); graphOptions.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallOptions.png")); graphOptions.putValue(Action.LONG_DESCRIPTION, "Displays the options dialog for the graph."); zoomIn = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel mgm = models.get(theTabs.getSelectedIndex()); if (mgm instanceof ChartPanel) ((ChartPanel) mgm).zoomInBoth(-1, -1); else if (mgm instanceof Graph3D) { double rho = ((Graph3D) mgm).getChart3DPanel().getViewPoint().getRho(); ((Graph3D) mgm).getChart3DPanel().getViewPoint().setRho(rho - 5); ((Graph3D) mgm).getChart3DPanel().repaint(); } } }; zoomIn.putValue(Action.NAME, "In"); zoomIn.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_I)); zoomIn.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallPlayerFwd.png")); zoomIn.putValue(Action.LONG_DESCRIPTION, "Zoom in on the graph."); zoomOut = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel mgm = models.get(theTabs.getSelectedIndex()); if (mgm instanceof ChartPanel) ((ChartPanel) mgm).zoomOutBoth(-1, -1); else if (mgm instanceof Graph3D) { double rho = ((Graph3D) mgm).getChart3DPanel().getViewPoint().getRho(); ((Graph3D) mgm).getChart3DPanel().getViewPoint().setRho(rho + 5); ((Graph3D) mgm).getChart3DPanel().repaint(); } } }; zoomOut.putValue(Action.NAME, "Out"); zoomOut.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_O)); zoomOut.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallPlayerRew.png")); zoomOut.putValue(Action.LONG_DESCRIPTION, "Zoom out of the graph."); zoomDefault = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel mgm = models.get(theTabs.getSelectedIndex()); if (mgm instanceof ChartPanel) ((ChartPanel) mgm).restoreAutoBounds(); else if (mgm instanceof Graph3D) { ((Graph3D) mgm).getChart3DPanel().zoomToFit(); ((Graph3D) mgm).getChart3DPanel().getDrawable() .setViewPoint(new ViewPoint3D(-Math.PI / 2, Math.PI * 1.124, 70.0, 0.0)); ((Graph3D) mgm).getChart3DPanel().repaint(); } } }; zoomDefault.putValue(Action.NAME, "Default"); zoomDefault.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_D)); zoomDefault.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallPlayerStart.png")); zoomDefault.putValue(Action.LONG_DESCRIPTION, "Set the default zoom for the graph."); importXML = new AbstractAction() { public void actionPerformed(ActionEvent e) { if (plug.showOpenFileDialog(graFilter) != JFileChooser.APPROVE_OPTION) return; try { Graph mgm = Graph.load(plug.getChooserFile()); addGraph(mgm); } catch (GraphException ex) { plug.error("Could not import PRISM graph file:\n" + ex.getMessage()); } } }; importXML.putValue(Action.NAME, "PRISM graph (*.gra)"); importXML.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_I)); importXML.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFileGraph.png")); importXML.putValue(Action.LONG_DESCRIPTION, "Imports a saved PRISM graph from a file."); addFunction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { plotNewFunction(); } }; addFunction.putValue(Action.NAME, "Plot function"); addFunction.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P)); addFunction.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFunction.png")); addFunction.putValue(Action.LONG_DESCRIPTION, "Plots a new specified function on the current graph"); exportXML = new AbstractAction() { public void actionPerformed(ActionEvent e) { if (plug.showSaveFileDialog(graFilter) != JFileChooser.APPROVE_OPTION) return; Graph mgm = (Graph) models.get(theTabs.getSelectedIndex()); try { mgm.save(plug.getChooserFile()); } catch (PrismException ex) { plug.error("Could not export PRISM graph file:\n" + ex.getMessage()); } } }; exportXML.putValue(Action.NAME, "PRISM graph (*.gra)"); exportXML.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X)); exportXML.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFileGraph.png")); exportXML.putValue(Action.LONG_DESCRIPTION, "Export graph as a PRISM graph file."); exportImageJPG = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel model = getModel(theTabs.getSelectedIndex()); GUIImageExportDialog imageDialog = new GUIImageExportDialog(plug.getGUI(), model, GUIImageExportDialog.JPEG); saveImage(imageDialog); } }; exportImageJPG.putValue(Action.NAME, "JPEG Interchange Format (*.jpg, *.jpeg)"); exportImageJPG.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_J)); exportImageJPG.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFileImage.png")); exportImageJPG.putValue(Action.LONG_DESCRIPTION, "Export graph as a JPEG file."); exportImagePNG = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel model = getModel(theTabs.getSelectedIndex()); GUIImageExportDialog imageDialog = new GUIImageExportDialog(plug.getGUI(), model, GUIImageExportDialog.PNG); saveImage(imageDialog); } }; exportImagePNG.putValue(Action.NAME, "Portable Network Graphics (*.png)"); exportImagePNG.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P)); exportImagePNG.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFileImage.png")); exportImagePNG.putValue(Action.LONG_DESCRIPTION, "Export graph as a Portable Network Graphics file."); exportPDF = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (plug.showSaveFileDialog(pdfFilter) != JFileChooser.APPROVE_OPTION) return; JPanel mgm = models.get(theTabs.getSelectedIndex()); if (mgm instanceof ChartPanel) Graph.exportToPDF(plug.getChooserFile(), ((ChartPanel) mgm).getChart()); else if (mgm instanceof Graph3D) { Graph3D.exportToPDF(plug.getChooserFile(), ((Graph3D) mgm).getChart3DPanel()); } } }; exportPDF.putValue(Action.NAME, "Portable document format (*.pdf)"); exportPDF.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P)); exportPDF.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFilePdf.png")); exportPDF.putValue(Action.LONG_DESCRIPTION, "Export the graph as a Portable document format file."); exportImageEPS = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel model = getModel(theTabs.getSelectedIndex()); if (model instanceof ChartPanel) { GUIImageExportDialog imageDialog = new GUIImageExportDialog(plug.getGUI(), (ChartPanel) model, GUIImageExportDialog.EPS); saveImage(imageDialog); } } }; exportImageEPS.putValue(Action.NAME, "Encapsulated PostScript (*.eps)"); exportImageEPS.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_E)); exportImageEPS.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFilePdf.png")); exportImageEPS.putValue(Action.LONG_DESCRIPTION, "Export graph as an Encapsulated PostScript file."); exportMatlab = new AbstractAction() { public void actionPerformed(ActionEvent e) { if (plug.showSaveFileDialog(matlabFilter) != JFileChooser.APPROVE_OPTION) return; JPanel mgm = models.get(theTabs.getSelectedIndex()); if (mgm instanceof Graph) { try { ((Graph) mgm).exportToMatlab(plug.getChooserFile()); } catch (IOException ex) { plug.error("Could not export Matlab file:\n" + ex.getMessage()); } } else if (mgm instanceof Graph3D) { try { ((Graph3D) mgm).exportToMatlab(plug.getChooserFile()); } catch (IOException e1) { plug.error("Could not export Matlab file:\n" + e1.getMessage()); e1.printStackTrace(); } } } }; exportMatlab.putValue(Action.NAME, "Matlab file (*.m)"); exportMatlab.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_M)); exportMatlab.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallFileMatlab.png")); exportMatlab.putValue(Action.LONG_DESCRIPTION, "Export graph as a Matlab file."); exportGnuplot = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (plug.showSaveFileDialog(gnuplotFilter) != JFileChooser.APPROVE_OPTION) return; JPanel mgm = models.get(theTabs.getSelectedIndex()); if (mgm instanceof ChartPanel) { try { if (mgm instanceof Graph && !(mgm instanceof ParametricGraph)) { ((Graph) mgm).exportToGnuplot(plug.getChooserFile()); } else if (mgm instanceof ParametricGraph) { ((ParametricGraph) mgm).exportToGnuplot(plug.getChooserFile()); } else if (mgm instanceof Histogram) { ((Histogram) mgm).exportToGnuplot(plug.getChooserFile()); } } catch (IOException ex) { plug.error("Could not export Gnuplot file:\n" + ex.getMessage()); } } else if (mgm instanceof Graph3D) { try { ((Graph3D) mgm).exportToGnuplot(plug.getChooserFile()); } catch (IOException ex) { plug.error("Could not export Gnuplot file:\n" + ex.getMessage()); ex.printStackTrace(); } } } }; exportGnuplot.putValue(Action.NAME, "GNU Plot file(*.gnuplot)"); exportGnuplot.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_G)); exportGnuplot.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallgnuplot.png")); exportGnuplot.putValue(Action.LONG_DESCRIPTION, "Export graph as a GNU plot file."); printGraph = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel graph = models.get(theTabs.getSelectedIndex()); if (graph instanceof ChartPanel) { if (graph instanceof Graph) { if (!((Graph) graph).getDisplaySettings().getBackgroundColor().equals(Color.white)) { if (plug.questionYesNo( "Your graph has a coloured background, this background will show up on the \n" + "printout. Would you like to make the current background colour white?") == 0) { ((Graph) graph).getDisplaySettings().setBackgroundColor(Color.white); } } } else if (graph instanceof Histogram) { if (!((Histogram) graph).getDisplaySettings().getBackgroundColor().equals(Color.white)) { if (plug.questionYesNo( "Your graph has a coloured background, this background will show up on the \n" + "printout. Would you like to make the current background colour white?") == 0) { ((Histogram) graph).getDisplaySettings().setBackgroundColor(Color.white); } } } ((ChartPanel) graph).createChartPrintJob(); } if (graph instanceof Graph3D) { ((Graph3D) graph).createPrintJob(); } } }; printGraph.putValue(Action.NAME, "Print graph"); printGraph.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P)); printGraph.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallPrint.png")); printGraph.putValue(Action.LONG_DESCRIPTION, "Print the graph to a printer or file"); deleteGraph = new AbstractAction() { public void actionPerformed(ActionEvent e) { JPanel graph = models.get(theTabs.getSelectedIndex()); models.remove(theTabs.getSelectedIndex()); options.remove(theTabs.getSelectedIndex()); theTabs.remove(graph); } }; deleteGraph.putValue(Action.NAME, "Delete graph"); deleteGraph.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_D)); deleteGraph.putValue(Action.SMALL_ICON, GUIPrism.getIconFromImage("smallDelete.png")); deleteGraph.putValue(Action.LONG_DESCRIPTION, "Deletes the graph."); zoomMenu = new JMenu("Zoom"); zoomMenu.setMnemonic('Z'); zoomMenu.setIcon(GUIPrism.getIconFromImage("smallView.png")); zoomMenu.add(zoomIn); zoomMenu.add(zoomOut); zoomMenu.add(zoomDefault); exportMenu = new JMenu("Export graph"); exportMenu.setMnemonic('E'); exportMenu.setIcon(GUIPrism.getIconFromImage("smallExport.png")); exportMenu.add(exportXML); exportMenu.add(exportImagePNG); exportMenu.add(exportPDF); exportMenu.add(exportImageEPS); exportMenu.add(exportImageJPG); exportMenu.add(exportMatlab); exportMenu.add(exportGnuplot); importMenu = new JMenu("Import graph"); importMenu.setMnemonic('I'); importMenu.setIcon(GUIPrism.getIconFromImage("smallImport.png")); importMenu.add(importXML); graphMenu.add(graphOptions); graphMenu.add(zoomMenu); graphMenu.addSeparator(); graphMenu.add(printGraph); graphMenu.add(deleteGraph); graphMenu.addSeparator(); graphMenu.add(exportMenu); graphMenu.add(importMenu); graphMenu.add(addFunction); /* Tab context menu */ backMenu.add(importXML); } public void saveImage(GUIImageExportDialog imageDialog) { if (!imageDialog.isCancelled()) { JPanel graph = getModel(theTabs.getSelectedIndex()); if (graph instanceof ChartPanel) { if (graph instanceof Graph) { /* If background is not white, and it will show up, then lets warn everyone. */ if (!((Graph) graph).getDisplaySettings().getBackgroundColor().equals(Color.white) && (imageDialog.getImageType() != GUIImageExportDialog.PNG || !imageDialog.getAlpha())) { if (plug.questionYesNo( "Your graph has a coloured background, this background will show up on the \n" + "exported image. Would you like to make the current background colour white?") == 0) { ((Graph) graph).getDisplaySettings().setBackgroundColor(Color.white); } } } else if (graph instanceof Histogram) { /* If background is not white, and it will show up, then lets warn everyone. */ if (!((Histogram) graph).getDisplaySettings().getBackgroundColor().equals(Color.white) && (imageDialog.getImageType() != GUIImageExportDialog.PNG || !imageDialog.getAlpha())) { if (plug.questionYesNo( "Your graph has a coloured background, this background will show up on the \n" + "exported image. Would you like to make the current background colour white?") == 0) { ((Histogram) graph).getDisplaySettings().setBackgroundColor(Color.white); } } } if (imageDialog.getImageType() == GUIImageExportDialog.JPEG) { if (plug.showSaveFileDialog(jpgFilter) != JFileChooser.APPROVE_OPTION) return; try { Graph.exportToJPEG(plug.getChooserFile(), ((ChartPanel) graph).getChart(), imageDialog.getExportWidth(), imageDialog.getExportHeight()); } catch (GraphException ex) { plug.error("Could not export JPEG file:\n" + ex.getMessage()); } catch (IOException ex) { plug.error("Could not export JPEG file:\n" + ex.getMessage()); } } else if (imageDialog.getImageType() == GUIImageExportDialog.PNG) { if (plug.showSaveFileDialog(pngFilter) != JFileChooser.APPROVE_OPTION) return; try { Graph.exportToPNG(plug.getChooserFile(), ((ChartPanel) graph).getChart(), imageDialog.getExportWidth(), imageDialog.getExportHeight(), imageDialog.getAlpha()); } catch (GraphException ex) { plug.error("Could not export PNG file:\n" + ex.getMessage()); } catch (IOException ex) { plug.error("Could not export PNG file:\n" + ex.getMessage()); } } else if (imageDialog.getImageType() == GUIImageExportDialog.EPS) { if (plug.showSaveFileDialog(epsFilter) != JFileChooser.APPROVE_OPTION) return; try { Graph.exportToEPS(plug.getChooserFile(), imageDialog.getExportWidth(), imageDialog.getExportHeight(), ((ChartPanel) graph).getChart()); } catch (GraphException ex) { plug.error("Could not export EPS file:\n" + ex.getMessage()); } catch (IOException ex) { plug.error("Could not export EPS file:\n" + ex.getMessage()); } } } else if (graph instanceof Graph3D) { Graph3D g3d = (Graph3D) graph; if (imageDialog.getImageType() == GUIImageExportDialog.JPEG) { if (plug.showSaveFileDialog(jpgFilter) != JFileChooser.APPROVE_OPTION) return; try { File file = null; if (!plug.getChooserFile().getName().contains(".jpg") || !plug.getChooserFile().getName().contains(".jpeg")) { file = new File(plug.getChooserFile().getAbsolutePath() + ".jpg"); } else { file = plug.getChooserFile(); } ExportUtils.writeAsJPEG(g3d.getChart3DPanel().getDrawable(), imageDialog.getExportWidth(), imageDialog.getExportHeight(), file); } catch (IOException e) { JOptionPane.showMessageDialog(this, e, "Error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } else if (imageDialog.getImageType() == GUIImageExportDialog.PNG) { if (plug.showSaveFileDialog(pngFilter) != JFileChooser.APPROVE_OPTION) return; File file = null; try { if (!plug.getChooserFile().getName().contains(".png")) { file = new File(plug.getChooserFile().getAbsolutePath() + ".png"); } else { file = plug.getChooserFile(); } ExportUtils.writeAsPNG(g3d.getChart3DPanel().getDrawable(), imageDialog.getExportWidth(), imageDialog.getHeight(), file); } catch (IOException e) { JOptionPane.showMessageDialog(this, e, "Error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } } } } public Action getPrintGraph() { return printGraph; } public Action getDeleteGraph() { if (canDelete) return deleteGraph; return null; } public int addGraph(JPanel m) { String name = ""; boolean nameNew; int counter = 1; while (true) { name = "Graph " + (counter); nameNew = true; for (int i = 0; i < theTabs.getComponentCount(); i++) { if (theTabs.getTitleAt(i).equals(name)) nameNew = false; } if (nameNew) return addGraph(m, name); counter++; } } public int addGraph(JPanel m, String tabName) { // add the model to the list of models models.add(m); // make the graph appear as a tab theTabs.add(m); options.add(new GraphOptions(plug, m, plug.getGUI(), "Options for graph " + tabName)); if (m instanceof ChartPanel) // anything that happens to the graph should propagate m.addMouseListener(this); else if (m instanceof Graph3D) ((Graph3D) m).addMouseListener(this); // get the index of this model in the model list int index = models.indexOf(m); // increase the graph count and title the tab theTabs.setTitleAt(index, tabName); //set the tabclosepanel component so we see the close button TabClosePanel closePanel = new TabClosePanel(tabName); closePanel.addMouseListener(this); theTabs.setTabComponentAt(index, closePanel); // make this new tab the default selection theTabs.setSelectedIndex(theTabs.indexOfComponent(m)); // return the index of the component return index; } public void jumpToGraph(ChartPanel m) { for (int i = 0; i < models.size(); i++) { if (m == models.get(i)) { theTabs.setSelectedComponent(m); break; } } } public JPanel getModel(int i) { return models.get(i); } public JPanel getModel(String tabHeader) { for (int i = 0; i < theTabs.getComponentCount(); i++) { if (theTabs.getTitleAt(i).equals(tabHeader)) { return getModel(i); } } return null; } public int getNumModels() { return models.size(); } public String getGraphName(int i) { return theTabs.getTitleAt(i); } // User right clicked on a tab public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) { popUpTriggered(e); } } public void mouseClicked(MouseEvent e) { // Zoom out on double click if (e.getClickCount() == 2) { if (e.getSource() instanceof Graph) { ((Graph) e.getSource()).restoreAutoBounds(); } } } public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) { popUpTriggered(e); } } private void popUpTriggered(MouseEvent e) { if (e.getSource() == theTabs)//just show the background popup { int index = theTabs.indexAtLocation(e.getX(), e.getY()); if (index != -1) { graphOptions.setEnabled(true); zoomMenu.setEnabled(true); exportMenu.setEnabled(true); importMenu.setEnabled(true); printGraph.setEnabled(true); deleteGraph.setEnabled(true); theTabs.setSelectedIndex(index); this.graphMenu.show(theTabs, e.getX(), e.getY()); } else { graphOptions.setEnabled(false); zoomMenu.setEnabled(false); exportMenu.setEnabled(false); importMenu.setEnabled(true); printGraph.setEnabled(false); deleteGraph.setEnabled(false); this.graphMenu.show(theTabs, e.getX(), e.getY()); } return; } for (int i = 0; i < models.size(); i++) { if (e.getSource() == models.get(i)) { graphOptions.setEnabled(true); zoomMenu.setEnabled(true); exportMenu.setEnabled(true); importMenu.setEnabled(true); printGraph.setEnabled(true); deleteGraph.setEnabled(true); exportImageEPS.setEnabled(true); exportMatlab.setEnabled(getModel(i) instanceof Graph); exportXML.setEnabled(getModel(i) instanceof Graph); theTabs.setSelectedIndex(i); this.graphMenu.show(models.get(i), e.getX(), e.getY()); return; } } } public void doGraph3DEnables() { exportImageEPS.setEnabled(false); exportXML.setEnabled(false); printGraph.setEnabled(false); } public void paintComponent(Graphics g) { super.paintComponent(g); g.clearRect(0, 0, this.getWidth(), this.getHeight()); } // don't implement these for tabs //public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public JPopupMenu getGraphMenu() { return this.graphMenu; } public void plotNewFunction() { JDialog dialog; JRadioButton radio2d, radio3d, newGraph, existingGraph; JTextField functionField, seriesName; JButton ok, cancel; JComboBox<String> chartOptions; JLabel example; //init all the fields of the dialog dialog = new JDialog(GUIPrism.getGUI()); radio2d = new JRadioButton("2D"); radio3d = new JRadioButton("3D"); newGraph = new JRadioButton("New Graph"); existingGraph = new JRadioButton("Exisiting"); chartOptions = new JComboBox<String>(); functionField = new JTextField(); ok = new JButton("Plot"); cancel = new JButton("Cancel"); seriesName = new JTextField(); example = new JLabel("<html><font size=3 color=red>Example:</font><font size=3>x/2 + 5</font></html>"); example.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { example.setCursor(new Cursor(Cursor.HAND_CURSOR)); example.setForeground(Color.BLUE); } @Override public void mouseExited(MouseEvent e) { example.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); example.setForeground(Color.BLACK); } @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { if (radio2d.isSelected()) { functionField.setText("x/2 + 5"); } else { functionField.setText("x+y+5"); } functionField.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15)); functionField.setForeground(Color.BLACK); } } }); //set dialog properties dialog.setSize(400, 350); dialog.setTitle("Plot a new function"); dialog.setModal(true); dialog.setLayout(new BoxLayout(dialog.getContentPane(), BoxLayout.Y_AXIS)); dialog.setLocationRelativeTo(GUIPrism.getGUI()); //add every component to their dedicated panels JPanel graphTypePanel = new JPanel(new FlowLayout()); graphTypePanel.setBorder(BorderFactory .createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), "Function type")); graphTypePanel.add(radio2d); graphTypePanel.add(radio3d); JPanel functionFieldPanel = new JPanel(new BorderLayout()); functionFieldPanel.setBorder(BorderFactory .createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), "Function")); functionFieldPanel.add(functionField, BorderLayout.CENTER); functionFieldPanel.add(example, BorderLayout.SOUTH); JPanel chartSelectPanel = new JPanel(); chartSelectPanel.setLayout(new BoxLayout(chartSelectPanel, BoxLayout.Y_AXIS)); chartSelectPanel.setBorder(BorderFactory .createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), "Plot function to")); JPanel radioPlotPanel = new JPanel(new FlowLayout()); radioPlotPanel.add(newGraph); radioPlotPanel.add(existingGraph); JPanel chartOptionsPanel = new JPanel(new FlowLayout()); chartOptionsPanel.add(chartOptions); chartSelectPanel.add(radioPlotPanel); chartSelectPanel.add(chartOptionsPanel); JPanel bottomControlPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); bottomControlPanel.add(ok); bottomControlPanel.add(cancel); JPanel seriesNamePanel = new JPanel(new BorderLayout()); seriesNamePanel.setBorder(BorderFactory .createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), "Series name")); seriesNamePanel.add(seriesName, BorderLayout.CENTER); // add all the panels to the dialog dialog.add(graphTypePanel); dialog.add(functionFieldPanel); dialog.add(chartSelectPanel); dialog.add(seriesNamePanel); dialog.add(bottomControlPanel); // do all the enables and set properties radio2d.setSelected(true); newGraph.setSelected(true); chartOptions.setEnabled(false); functionField.setText("Add function expression here...."); functionField.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 15)); functionField.setForeground(Color.GRAY); seriesName.setText("New function"); ok.setMnemonic('P'); cancel.setMnemonic('C'); example.setToolTipText("click to try out"); ok.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "ok"); ok.getActionMap().put("ok", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { ok.doClick(); } }); cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel"); cancel.getActionMap().put("cancel", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { cancel.doClick(); } }); boolean found = false; for (int i = 0; i < theTabs.getTabCount(); i++) { if (theTabs.getComponentAt(i) instanceof Graph) { chartOptions.addItem(getGraphName(i)); found = true; } } if (!found) { existingGraph.setEnabled(false); chartOptions.setEnabled(false); } //add all the action listeners radio2d.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (radio2d.isSelected()) { radio3d.setSelected(false); if (chartOptions.getItemCount() > 0) { existingGraph.setEnabled(true); chartOptions.setEnabled(true); } example.setText( "<html><font size=3 color=red>Example:</font><font size=3>x/2 + 5</font></html>"); } } }); radio3d.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (radio3d.isSelected()) { radio2d.setSelected(false); newGraph.setSelected(true); existingGraph.setEnabled(false); chartOptions.setEnabled(false); example.setText("<html><font size=3 color=red>Example:</font><font size=3>x+y+5</font></html>"); } } }); newGraph.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (newGraph.isSelected()) { existingGraph.setSelected(false); chartOptions.setEnabled(false); } } }); existingGraph.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (existingGraph.isSelected()) { newGraph.setSelected(false); chartOptions.setEnabled(true); } } }); ok.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String function = functionField.getText(); Expression expr = null; try { expr = GUIPrism.getGUI().getPrism().parseSingleExpressionString(function); expr = (Expression) expr.accept(new ASTTraverseModify() { @Override public Object visit(ExpressionIdent e) throws PrismLangException { return new ExpressionConstant(e.getName(), TypeDouble.getInstance()); } }); expr.typeCheck(); expr.semanticCheck(); } catch (PrismLangException e1) { // for copying style JLabel label = new JLabel(); // html content in our case the error we want to show JEditorPane ep = new JEditorPane("text/html", "<html> There was an error parsing the function. To read about what built-in" + " functions are supported <br>and some more information on the functions, visit " + "<a href='http://www.prismmodelchecker.org/manual/ThePRISMLanguage/Expressions'>Prism expressions site</a>." + "<br><br><font color=red>Error: </font>" + e1.getMessage() + " </html>"); // handle link events ep.addHyperlinkListener(new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { try { Desktop.getDesktop().browse(e.getURL().toURI()); } catch (IOException | URISyntaxException e1) { e1.printStackTrace(); } } } }); ep.setEditable(false); ep.setBackground(label.getBackground()); // show the error dialog JOptionPane.showMessageDialog(dialog, ep, "Parse Error", JOptionPane.ERROR_MESSAGE); return; } if (radio2d.isSelected()) { ParametricGraph graph = null; if (newGraph.isSelected()) { graph = new ParametricGraph(""); } else { for (int i = 0; i < theTabs.getComponentCount(); i++) { if (theTabs.getTitleAt(i).equals(chartOptions.getSelectedItem())) { graph = (ParametricGraph) theTabs.getComponent(i); } } } dialog.dispose(); defineConstantsAndPlot(expr, graph, seriesName.getText(), newGraph.isSelected(), true); } else if (radio3d.isSelected()) { try { expr = (Expression) expr.accept(new ASTTraverseModify() { @Override public Object visit(ExpressionIdent e) throws PrismLangException { return new ExpressionConstant(e.getName(), TypeDouble.getInstance()); } }); expr.semanticCheck(); expr.typeCheck(); } catch (PrismLangException e1) { e1.printStackTrace(); } if (expr.getAllConstants().size() < 2) { JOptionPane.showMessageDialog(dialog, "There are not enough variables in the function to plot a 3D chart!", "Error", JOptionPane.ERROR_MESSAGE); return; } // its always a new graph ParametricGraph3D graph = new ParametricGraph3D(expr); dialog.dispose(); defineConstantsAndPlot(expr, graph, seriesName.getText(), true, false); } dialog.dispose(); } }); cancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dialog.dispose(); } }); // we will show info about the function when field is out of focus functionField.addFocusListener(new FocusListener() { @Override public void focusLost(FocusEvent e) { if (!functionField.getText().equals("")) { return; } functionField.setText("Add function expression here...."); functionField.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 15)); functionField.setForeground(Color.GRAY); } @Override public void focusGained(FocusEvent e) { if (!functionField.getText().equals("Add function expression here....")) { return; } functionField.setForeground(Color.BLACK); functionField.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15)); functionField.setText(""); } }); // show the dialog dialog.setVisible(true); } public void defineConstantsAndPlot(Expression expr, JPanel graph, String seriesName, Boolean isNewGraph, boolean is2D) { JDialog dialog; JButton ok, cancel; JScrollPane scrollPane; ConstantPickerList constantList; JComboBox<String> xAxis, yAxis; //init everything dialog = new JDialog(GUIPrism.getGUI()); dialog.setTitle("Define constants and select axes"); dialog.setSize(500, 400); dialog.setLocationRelativeTo(GUIPrism.getGUI()); dialog.setLayout(new BoxLayout(dialog.getContentPane(), BoxLayout.Y_AXIS)); dialog.setModal(true); constantList = new ConstantPickerList(); scrollPane = new JScrollPane(constantList); xAxis = new JComboBox<String>(); yAxis = new JComboBox<String>(); ok = new JButton("Ok"); ok.setMnemonic('O'); cancel = new JButton("Cancel"); cancel.setMnemonic('C'); //add all components to their dedicated panels JPanel exprPanel = new JPanel(new FlowLayout()); exprPanel.setBorder(new TitledBorder("Function")); exprPanel.add(new JLabel(expr.toString())); JPanel axisPanel = new JPanel(); axisPanel.setBorder(new TitledBorder("Select axis constants")); axisPanel.setLayout(new BoxLayout(axisPanel, BoxLayout.Y_AXIS)); JPanel xAxisPanel = new JPanel(new FlowLayout()); xAxisPanel.add(new JLabel("X axis:")); xAxisPanel.add(xAxis); JPanel yAxisPanel = new JPanel(new FlowLayout()); yAxisPanel.add(new JLabel("Y axis:")); yAxisPanel.add(yAxis); axisPanel.add(xAxisPanel); axisPanel.add(yAxisPanel); JPanel constantPanel = new JPanel(new BorderLayout()); constantPanel.setBorder(new TitledBorder("Please define the following constants")); constantPanel.add(scrollPane, BorderLayout.CENTER); constantPanel.add(new ConstantHeader(), BorderLayout.NORTH); JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); bottomPanel.add(ok); bottomPanel.add(cancel); //fill the axes components for (int i = 0; i < expr.getAllConstants().size(); i++) { xAxis.addItem(expr.getAllConstants().get(i)); if (!is2D) yAxis.addItem(expr.getAllConstants().get(i)); } if (!is2D) { yAxis.setSelectedIndex(1); } //fill the constants table for (int i = 0; i < expr.getAllConstants().size(); i++) { ConstantLine line = new ConstantLine(expr.getAllConstants().get(i), TypeDouble.getInstance()); constantList.addConstant(line); if (!is2D) { if (line.getName().equals(xAxis.getSelectedItem().toString()) || line.getName().equals(yAxis.getSelectedItem().toString())) { line.doFuncEnables(false); } else { line.doFuncEnables(true); } } } //do enables if (is2D) { yAxis.setEnabled(false); } ok.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "ok"); ok.getActionMap().put("ok", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { ok.doClick(); } }); cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel"); cancel.getActionMap().put("cancel", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { cancel.doClick(); } }); //add action listeners xAxis.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (is2D) { return; } String item = xAxis.getSelectedItem().toString(); if (item.equals(yAxis.getSelectedItem().toString())) { int index = yAxis.getSelectedIndex(); if (index != yAxis.getItemCount() - 1) { yAxis.setSelectedIndex(++index); } else { yAxis.setSelectedIndex(--index); } } for (int i = 0; i < constantList.getNumConstants(); i++) { ConstantLine line = constantList.getConstantLine(i); if (line.getName().equals(xAxis.getSelectedItem().toString()) || line.getName().equals(yAxis.getSelectedItem().toString())) { line.doFuncEnables(false); } else { line.doFuncEnables(true); } } } }); yAxis.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String item = yAxis.getSelectedItem().toString(); if (item.equals(xAxis.getSelectedItem().toString())) { int index = xAxis.getSelectedIndex(); if (index != xAxis.getItemCount() - 1) { xAxis.setSelectedIndex(++index); } else { xAxis.setSelectedIndex(--index); } } for (int i = 0; i < constantList.getNumConstants(); i++) { ConstantLine line = constantList.getConstantLine(i); if (line.getName().equals(xAxis.getSelectedItem().toString()) || line.getName().equals(yAxis.getSelectedItem().toString())) { line.doFuncEnables(false); } else { line.doFuncEnables(true); } } } }); ok.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { constantList.checkValid(); } catch (PrismException e2) { JOptionPane.showMessageDialog(dialog, "<html> One or more of the defined constants are invalid. <br><br> <font color=red>Error: </font>" + e2.getMessage() + "</html>", "Parse Error", JOptionPane.ERROR_MESSAGE); return; } if (is2D) { // it will always be a parametric graph in 2d case ParametricGraph pGraph = (ParametricGraph) graph; ConstantLine xAxisConstant = constantList.getConstantLine(xAxis.getSelectedItem().toString()); if (xAxisConstant == null) { //should never happen JOptionPane.showMessageDialog(dialog, "The selected axis is invalid.", "Error", JOptionPane.ERROR_MESSAGE); return; } double xStartValue = Double.parseDouble(xAxisConstant.getStartValue()); double xEndValue = Double.parseDouble(xAxisConstant.getEndValue()); double xStepValue = Double.parseDouble(xAxisConstant.getStepValue()); int seriesCount = 0; for (int i = 0; i < constantList.getNumConstants(); i++) { ConstantLine line = constantList.getConstantLine(i); if (line.getName().equals(xAxis.getSelectedItem().toString())) { seriesCount++; } else { seriesCount += line.getTotalNumOfValues(); } } // if there will be too many series to be plotted, ask the user if they are sure they know what they are doing if (seriesCount > 10) { int res = JOptionPane.showConfirmDialog(dialog, "This configuration will create " + seriesCount + " series. Continue?", "Confirm", JOptionPane.YES_NO_OPTION); if (res == JOptionPane.NO_OPTION) { return; } } Values singleValuesGlobal = new Values(); //add the single values to a global values list for (int i = 0; i < constantList.getNumConstants(); i++) { ConstantLine line = constantList.getConstantLine(i); if (line.getTotalNumOfValues() == 1) { double singleValue = Double.parseDouble(line.getSingleValue()); singleValuesGlobal.addValue(line.getName(), singleValue); } } // we just have one variable so we can plot directly if (constantList.getNumConstants() == 1 || singleValuesGlobal.getNumValues() == constantList.getNumConstants() - 1) { SeriesKey key = pGraph.addSeries(seriesName); pGraph.hideShape(key); pGraph.getXAxisSettings().setHeading(xAxis.getSelectedItem().toString()); pGraph.getYAxisSettings().setHeading("function"); for (double x = xStartValue; x <= xEndValue; x += xStepValue) { double ans = -1; Values vals = new Values(); vals.addValue(xAxis.getSelectedItem().toString(), x); for (int ii = 0; ii < singleValuesGlobal.getNumValues(); ii++) { try { vals.addValue(singleValuesGlobal.getName(ii), singleValuesGlobal.getDoubleValue(ii)); } catch (PrismLangException e1) { e1.printStackTrace(); } } try { ans = expr.evaluateDouble(vals); } catch (PrismLangException e1) { e1.printStackTrace(); } pGraph.addPointToSeries(key, new PrismXYDataItem(x, ans)); } if (isNewGraph) { addGraph(pGraph); } dialog.dispose(); return; } for (int i = 0; i < constantList.getNumConstants(); i++) { ConstantLine line = constantList.getConstantLine(i); if (line == xAxisConstant || singleValuesGlobal.contains(line.getName())) { continue; } double lineStart = Double.parseDouble(line.getStartValue()); double lineEnd = Double.parseDouble(line.getEndValue()); double lineStep = Double.parseDouble(line.getStepValue()); for (double j = lineStart; j < lineEnd; j += lineStep) { SeriesKey key = pGraph.addSeries(seriesName); pGraph.hideShape(key); for (double x = xStartValue; x <= xEndValue; x += xStepValue) { double ans = -1; Values vals = new Values(); vals.addValue(xAxis.getSelectedItem().toString(), x); vals.addValue(line.getName(), j); for (int ii = 0; ii < singleValuesGlobal.getNumValues(); ii++) { try { vals.addValue(singleValuesGlobal.getName(ii), singleValuesGlobal.getDoubleValue(ii)); } catch (PrismLangException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } for (int ii = 0; ii < constantList.getNumConstants(); ii++) { if (constantList.getConstantLine(ii) == xAxisConstant || singleValuesGlobal .contains(constantList.getConstantLine(ii).getName()) || constantList.getConstantLine(ii) == line) { continue; } ConstantLine temp = constantList.getConstantLine(ii); double val = Double.parseDouble(temp.getStartValue()); vals.addValue(temp.getName(), val); } try { ans = expr.evaluateDouble(vals); } catch (PrismLangException e1) { e1.printStackTrace(); } pGraph.addPointToSeries(key, new PrismXYDataItem(x, ans)); } } } if (isNewGraph) { addGraph(graph); } } else { // this will always be a parametric graph for the 3d case ParametricGraph3D pGraph = (ParametricGraph3D) graph; //add the graph to the gui addGraph(pGraph); //Get the constants we want to put on the x and y axis ConstantLine xAxisConstant = constantList.getConstantLine(xAxis.getSelectedItem().toString()); ConstantLine yAxisConstant = constantList.getConstantLine(yAxis.getSelectedItem().toString()); //add the single values to a global values list Values singleValuesGlobal = new Values(); for (int i = 0; i < constantList.getNumConstants(); i++) { ConstantLine line = constantList.getConstantLine(i); if (line.getTotalNumOfValues() == 1) { double singleValue = Double.parseDouble(line.getSingleValue()); singleValuesGlobal.addValue(line.getName(), singleValue); } } pGraph.setGlobalValues(singleValuesGlobal); pGraph.setAxisConstants(xAxis.getSelectedItem().toString(), yAxis.getSelectedItem().toString()); pGraph.setBounds(xAxisConstant.getStartValue(), xAxisConstant.getEndValue(), yAxisConstant.getStartValue(), yAxisConstant.getEndValue()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { //plot the graph pGraph.plot(expr.toString(), xAxis.getSelectedItem().toString(), "Function", yAxis.getSelectedItem().toString()); //calculate the sampling rates from the step sizes as given by the user int xSamples = (int) ((Double.parseDouble(xAxisConstant.getEndValue()) - Double.parseDouble(xAxisConstant.getStartValue())) / Double.parseDouble(xAxisConstant.getStepValue())); int ySamples = (int) ((Double.parseDouble(xAxisConstant.getEndValue()) - Double.parseDouble(xAxisConstant.getStartValue())) / Double.parseDouble(xAxisConstant.getStepValue())); pGraph.setSamplingRates(xSamples, ySamples); } }); } dialog.dispose(); } }); cancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dialog.dispose(); } }); //add everything to the dialog show the dialog dialog.add(exprPanel); dialog.add(axisPanel); dialog.add(constantPanel); dialog.add(bottomPanel); dialog.setVisible(true); } /** * Class for adding a close button to the tabs * @author Muhammad Omer Saeed */ private class TabClosePanel extends JPanel { private static final long serialVersionUID = 3375988660604064366L; private JLabel label; private JButton close; public TabClosePanel(String title) { init(title); addToPanel(); addListeners(); addActions(); } public void init(String title) { setOpaque(false); label = new JLabel(title); label.setOpaque(false); close = new JButton("<html><font size=2><b>X</b></font></html>"); close.setContentAreaFilled(false); close.setPreferredSize(new Dimension(20, 10)); close.setBorderPainted(false); close.setToolTipText("close this tab"); } public void addToPanel() { setLayout(new BorderLayout()); add(label, BorderLayout.CENTER); add(close, BorderLayout.EAST); setPreferredSize(getPreferredSize()); validate(); } public void addActions() { close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { String title = label.getText(); int index = -1; for (int i = 0; i < theTabs.getComponentCount(); i++) { if (theTabs.getTitleAt(i).equals(title)) { index = i; } } if (index == -1) { return; } JPanel graph = models.get(index); models.remove(index); options.remove(index); theTabs.remove(graph); } }); } public void addListeners() { close.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { close.setForeground(Color.red); } @Override public void mouseExited(MouseEvent e) { close.setForeground(Color.BLACK); } }); } @Override public void addMouseListener(MouseListener l) { } public void setIcon(Icon icon) { label.setIcon(icon); } public void setTitle(String title) { label.setText(title); } public void setToolTip(String tip) { label.setToolTipText(tip); } public String getTitle() { return label.getText(); } @Override public String getToolTipText() { return label.getToolTipText(); } } }