/* * Main.java * */ package com.imsl.demo.SeriesAnalysis; import java.util.ArrayList; import java.util.StringTokenizer; import java.awt.Color; import com.imsl.chart.*; import com.imsl.demo.gallery.Describe; /** * * @author bmiller * @created November 18, 2002 */ public class SeriesAnalysis extends javax.swing.JFrame { private ArrayList data; private ArrayList params; private Chart chart; private boolean useSingleY = false; private final Function functionList[]; private final static Color colorList[] = {Color.blue, Color.magenta, Color.black, Color.red, Color.gray, Color.green, Color.yellow, Color.darkGray, Color.cyan, Color.orange, Color.pink, Color.white}; /** Creates new SeriesAnalysis */ public SeriesAnalysis(boolean exitOnClose) { if (!exitOnClose) { // remove the WindowListener, installed by JFrame, that // exits the application when the window is closed. Object l[] = getListeners(java.awt.event.WindowListener.class); for (int k = 0; k < l.length; k++) { removeWindowListener((java.awt.event.WindowListener)l[k]); } } functionList = Binding.getFunctions(); initComponents(); chart = new Chart(); jPanelChart.setChart(chart); chart.getBackground().setFillColor(new Color(205,205,205)); jMenuItemOpen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.ActionEvent.CTRL_MASK)); for (int k=0; k<functionList.length; k++) { javax.swing.JMenuItem m = new javax.swing.JMenuItem(functionList[k].text); m.setMnemonic(functionList[k].mnemonic); final String name = functionList[k].fullname; m.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { analyze(name); } }); jMenuAnalyze.add(m); } Describe des = new Describe(this, "/com/imsl/demo/SeriesAnalysis/SeriesAnalysis.html"); des.show(); java.awt.Dimension ds = des.getSize(); java.awt.Dimension ss = getToolkit().getScreenSize(); int h = Math.min(ss.width/2, ss.height-ds.height-32); int w = (int)(h/0.65); setSize(w, h); setLocation(ss.width-ds.width, ds.height); setup("flight_test.csv"); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jPanel1 = new javax.swing.JPanel(); jPanel4 = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); jList = new javax.swing.JList(); jPanel3 = new javax.swing.JPanel(); jButtonDraw = new javax.swing.JButton(); jCheckBoxY = new javax.swing.JCheckBox(); jPanel2 = new javax.swing.JPanel(); jPanelChart = new com.imsl.chart.JPanelChart(); jMenuBar = new javax.swing.JMenuBar(); jMenuFile = new javax.swing.JMenu(); jMenuItemOpen = new javax.swing.JMenuItem(); jMenuItemReadFlight = new javax.swing.JMenuItem(); jMenuItemReadTurb = new javax.swing.JMenuItem(); jMenuCopy = new javax.swing.JMenuItem(); jSeparator = new javax.swing.JSeparator(); jMenuItemExit = new javax.swing.JMenuItem(); jMenuAnalyze = new javax.swing.JMenu(); jMenuHelp = new javax.swing.JMenu(); jMenuItemAbout = new javax.swing.JMenuItem(); getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.X_AXIS)); setTitle("Time Series Analysis"); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.Y_AXIS)); jPanel1.setPreferredSize(new java.awt.Dimension(100, 600)); jPanel4.setLayout(new java.awt.BorderLayout()); jPanel4.setMaximumSize(new java.awt.Dimension(200, 1000)); jScrollPane1.setToolTipText("Use Shift and Control keys to make multiple selections"); jScrollPane1.setMaximumSize(new java.awt.Dimension(200, 1000)); jScrollPane1.setPreferredSize(new java.awt.Dimension(150, 350)); jList.setToolTipText("Use Shift and Control keys to make multiple selections"); jList.setFixedCellHeight(18); jList.setMaximumSize(new java.awt.Dimension(200, 1000)); jList.setPreferredSize(new java.awt.Dimension(150, 350)); jList.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { jListMouseClicked(evt); } }); jScrollPane1.setViewportView(jList); jPanel4.add(jScrollPane1, java.awt.BorderLayout.CENTER); jPanel1.add(jPanel4); jPanel3.setLayout(new java.awt.BorderLayout()); jPanel3.setMaximumSize(new java.awt.Dimension(150, 150)); jPanel3.setMinimumSize(new java.awt.Dimension(0, 0)); jPanel3.setPreferredSize(new java.awt.Dimension(150, 150)); jButtonDraw.setText("<html><center>Draw<br>Chart</center></html>"); jButtonDraw.setToolTipText("Update the chart"); jButtonDraw.setMaximumSize(new java.awt.Dimension(200, 75)); jButtonDraw.setMinimumSize(new java.awt.Dimension(81, 26)); jButtonDraw.setPreferredSize(new java.awt.Dimension(150, 75)); jButtonDraw.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButtonDrawActionPerformed(evt); } }); jPanel3.add(jButtonDraw, java.awt.BorderLayout.CENTER); jCheckBoxY.setText("<html><center>Use Single<br>Y Axis</center></html>" ); jCheckBoxY.setToolTipText("Set Y axis method"); jCheckBoxY.setMaximumSize(new java.awt.Dimension(150, 50)); jCheckBoxY.setPreferredSize(new java.awt.Dimension(150, 50)); jCheckBoxY.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jCheckBoxYActionPerformed(evt); } }); jPanel3.add(jCheckBoxY, java.awt.BorderLayout.SOUTH); jPanel1.add(jPanel3); getContentPane().add(jPanel1); jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.X_AXIS)); jPanel2.setMaximumSize(new java.awt.Dimension(1500, 975)); jPanel2.setMinimumSize(new java.awt.Dimension(0, 0)); jPanel2.setPreferredSize(new java.awt.Dimension(700, 455)); jPanelChart.setPreferredSize(new java.awt.Dimension(700, 600)); jPanel2.add(jPanelChart); getContentPane().add(jPanel2); jMenuFile.setMnemonic('F'); jMenuFile.setText("File"); jMenuFile.setToolTipText("Open a csv file or Exit"); jMenuItemOpen.setMnemonic('O'); jMenuItemOpen.setText("Open..."); jMenuItemOpen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/imsl/demo/SeriesAnalysis/Open16.gif"))); jMenuItemOpen.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItemOpenActionPerformed(evt); } }); jMenuFile.add(jMenuItemOpen); jMenuItemReadFlight.setText("Load Flight Data"); jMenuItemReadFlight.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItemReadFlightActionPerformed(evt); } }); jMenuFile.add(jMenuItemReadFlight); jMenuItemReadTurb.setText("Load Turbulence Data"); jMenuItemReadTurb.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItemReadTurbActionPerformed(evt); } }); jMenuFile.add(jMenuItemReadTurb); jMenuCopy.setText("Copy"); jMenuCopy.setToolTipText("Copy image to clipboard"); jMenuCopy.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuCopyActionPerformed(evt); } }); jMenuFile.add(jMenuCopy); jMenuFile.add(jSeparator); jMenuItemExit.setMnemonic('x'); jMenuItemExit.setText("Exit"); jMenuItemExit.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItemExitActionPerformed(evt); } }); jMenuFile.add(jMenuItemExit); jMenuBar.add(jMenuFile); jMenuAnalyze.setMnemonic('A'); jMenuAnalyze.setText("Analyze"); jMenuAnalyze.setToolTipText("Choose an analysis method"); jMenuBar.add(jMenuAnalyze); jMenuHelp.setMnemonic('H'); jMenuHelp.setText("Help"); jMenuHelp.setToolTipText("Get help"); jMenuItemAbout.setMnemonic('A'); jMenuItemAbout.setText("About"); jMenuItemAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/imsl/demo/SeriesAnalysis/Help16.gif"))); jMenuItemAbout.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItemAboutActionPerformed(evt); } }); jMenuHelp.add(jMenuItemAbout); jMenuBar.add(jMenuHelp); setJMenuBar(jMenuBar); pack(); }//GEN-END:initComponents private void jMenuCopyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuCopyActionPerformed // File -> Copy java.awt.datatransfer.Clipboard clip = getToolkit().getSystemClipboard(); java.awt.Dimension sz = chart.getScreenSize(); /* create and Image from the chart */ java.awt.Image image = chart.getComponent().createImage((int)sz.getWidth(), (int)sz.getHeight()); chart.paintChart(image.getGraphics()); ImageSelection selection = new ImageSelection(image); /* This method could use a BufferedImage instead */ //java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage((int)sz.getWidth(), (int)sz.getHeight(), java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE); //chart.paintChart(bi.getGraphics()); //ImageSelection selection = new ImageSelection(bi); clip.setContents(selection, null); }//GEN-LAST:event_jMenuCopyActionPerformed private void jCheckBoxYActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxYActionPerformed useSingleY = !useSingleY; draw(); }//GEN-LAST:event_jCheckBoxYActionPerformed private void jMenuItemReadTurbActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemReadTurbActionPerformed // File -> Load turbulence data setup("turbulence.csv"); draw(); }//GEN-LAST:event_jMenuItemReadTurbActionPerformed private void jMenuItemReadFlightActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemReadFlightActionPerformed // File -> Load flight test data setup("flight_test.csv"); draw(); }//GEN-LAST:event_jMenuItemReadFlightActionPerformed private void jMenuItemOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemOpenActionPerformed // File -> Open javax.swing.JFileChooser fileChooser = new javax.swing.JFileChooser(); fileChooser.setFileSelectionMode(javax.swing.JFileChooser.FILES_AND_DIRECTORIES); fileChooser.setCurrentDirectory(new java.io.File(".")); CSVFileFilter filter = new CSVFileFilter(); fileChooser.setFileFilter(filter); int result = fileChooser.showOpenDialog(this); if (result == javax.swing.JFileChooser.CANCEL_OPTION) return; java.io.File file = fileChooser.getSelectedFile(); String fileName = file.getPath(); if (fileName == null || fileName.equals("")) { javax.swing.JOptionPane.showMessageDialog(this,"Invalid File Name","Invalid File Name",javax.swing.JOptionPane.ERROR_MESSAGE); } else { try { readData(new java.io.BufferedReader(new java.io.FileReader(file))); updateList(); } catch (Exception e) { javax.swing.JOptionPane.showMessageDialog(this, e.getMessage(), "Exception", javax.swing.JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } }//GEN-LAST:event_jMenuItemOpenActionPerformed private void jListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jListMouseClicked if (evt.getClickCount() == 2) { draw(); } }//GEN-LAST:event_jListMouseClicked private void jMenuItemAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemAboutActionPerformed // Help -> About String about = "This demonstration extends javax.swing.JFrame instead \n" + "of com.imsl.chart.JFrameChart like most of the other \n" + "demos. Therefore, you do not have access to the standard \n" + "About menus that JFrameChart provides. However, that \n" + "functionality is easily duplicated, as it is here."; javax.swing.JOptionPane.showMessageDialog(this, about, "About", javax.swing.JOptionPane.INFORMATION_MESSAGE); }//GEN-LAST:event_jMenuItemAboutActionPerformed private void jButtonDrawActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDrawActionPerformed draw(); }//GEN-LAST:event_jButtonDrawActionPerformed private void jMenuItemExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemExitActionPerformed // File -> Exit System.exit(0); }//GEN-LAST:event_jMenuItemExitActionPerformed /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm setVisible(false); dispose(); }//GEN-LAST:event_exitForm private void draw() { jPanelChart.setChart(new Chart()); chart = jPanelChart.getChart(); chart.getBackground().setFillColor(new Color(205,205,205)); if (jList.isSelectionEmpty() == false) { chart.getChartTitle().setTitle("Magnitude vs. Sample Index"); chart.getChartTitle().setFontStyle(java.awt.Font.BOLD); chart.getLegend().setPaint(true); chart.getLegend().setViewport(0.85,0.98,0.05,0.25); chart.getLegend().setFillOutlineColor(Color.black); chart.getLegend().setTitle("Legend"); if (useSingleY) { drawSingle(chart); } else { drawMulti(chart); } } jPanelChart.repaint(); } private double[] computeX(int num) { double[] xx = new double[num]; for (int k=0; k<num; k++) { xx[k] = k; } return xx; } private void drawSingle(Chart chart) { int[] index = jList.getSelectedIndices(); AxisXY axis = new AxisXY(chart); axis.setViewport(0.1, 0.85, 0.1, 0.9); double globalMin = 1e28; double globalMax = -1e28; for (int i=0; i<index.length; i++) { int n = ((double[])data.get(index[i])).length; double x[] = computeX(n); double y[] = new double[n]; y = (double[])data.get(index[i]); Color color = nextColor(i); Data selectData = new Data(axis, x, y); String t = (String) params.get(index[i]); int ix = t.indexOf("_"); if (ix != -1) { t = t.substring(0,ix) + "\n " + t.substring(ix); } selectData.setTitle(t); selectData.setDataType(Data.DATA_TYPE_LINE); selectData.setLineColor(color); double ymin = y[getMinimumIndex(y)]; double ymax = y[getMaximumIndex(y)]; globalMin = Math.min(globalMin, ymin); globalMax = Math.max(globalMax, ymax); } axis.getAxisX().getAxisLabel().setTextFormat(new java.text.DecimalFormat("####")); axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisY().setWindow(globalMin,globalMax); axis.getAxisY().getAxisLabel().setTextFormat(new java.text.DecimalFormat("0.00")); } private void drawMulti(Chart chart) { int[] index = jList.getSelectedIndices(); for (int i = 0; i < index.length; i++) { createLine(chart, index[i], i, index.length); } } private void createLine(Chart chart, int index, int c, int num) { int n = ((double[]) data.get(index)).length; double tCross = 0.0; double x[] = new double[n]; double y[] = new double[n]; x = computeX(n); y = (double[]) data.get(index); Color color = nextColor(c); AxisXY axis = new AxisXY(chart); Data selectData = new Data(axis, x, y); double x0 = 0.1 + Math.sqrt(num-1)*0.17; axis.setViewport(x0, 0.85, 0.1, 0.9); axis.getAxisY().setTextColor(color); selectData.setDataType(Data.DATA_TYPE_LINE); selectData.setLineColor(color); tCross = (double) c * (x[n-1] * -.20); double ymin = y[getMinimumIndex(y)]; double ymax = y[getMaximumIndex(y)]; double buffer = (ymax-ymin)*.05; axis.setCross(tCross, ymin-buffer); axis.getAxisX().getAxisLabel().setTextFormat(new java.text.DecimalFormat("####")); axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisY().setWindow(ymin-buffer,ymax+buffer); axis.getAxisY().getAxisLabel().setTextFormat(new java.text.DecimalFormat("0.00")); // only draw the X axis once if (c != 0) { axis.getAxisX().setPaint(false); } // add title to axis //axis.getAxisY().getAxisUnit().setTitle((String) params.get(index)); // add title in legend //selectData.setTitle((String) params.get(index)); // add title, but split new lines on the _ character String t = (String) params.get(index); int ix = t.indexOf("_"); if (ix != -1) { t = t.substring(0,ix) + "\n " + t.substring(ix); } selectData.setTitle(t); } /** This method takes the name of a class to be used to analyze the data. * The class itself exists in the package com.imsl.demo.SeriesAnalysis.Lib * Since reflection isn't everyday Java knowledge, here is what's going on: * * a) a Class is created (classMain) from the String parameter. This is a * fully qualified name like com.imsl.demo.SeriesAnalysis.Lib.Abs * * b) a Cunstructor is created with a Class[] parameter of the type required * by the class we're instantiating (a JFrame here) * * c) an Object is created using this Constructor. So far, we've executed * this line of code: Abs o = new Abs(this); * * d) next we make two method calls by creating a Method, which takes * a String name parameter and a Class[] containing the parameters to pass. * And then the method is invoked for the Object just instantiated. These * lines are equivalent to: o.setData(params,data); o.show(); * * This code block can throw ClassNotFoundException, NoSuchMethodException, * InstantiationException, and IllegalAccessException exceptions. Instead * of treating each, we'll just report them. */ private void analyze(String main) { try { Class classMain = Class.forName(main); java.lang.reflect.Constructor co = classMain.getConstructor(new Class[] {javax.swing.JFrame.class}); Object o = co.newInstance(new Object[] {this}); java.lang.reflect.Method methodSetData = classMain.getMethod("setData", new Class[]{ArrayList.class, ArrayList.class}); methodSetData.invoke(o, new Object[]{params, data}); java.lang.reflect.Method methodShow = classMain.getMethod("show", (Class[])null); methodShow.invoke(o, new Object[]{}); } catch (Exception e) { String name = e.toString().substring(10,e.toString().indexOf(':')); javax.swing.JOptionPane.showMessageDialog(this, e.getMessage(), name, javax.swing.JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } /** This method is called by analysis functions to update the main list * of parameters when a new vector as been added by the function. */ public void updateList() { jList.setVisibleRowCount(params.size()); jList.setPreferredSize(jList.getPreferredScrollableViewportSize()); jList.setListData(params.toArray()); } public void setData(ArrayList dataList) { this.data = dataList; } public void setParams(ArrayList paramList) { this.params = paramList; } private int getMinimumIndex(double[] array){ int j = 0; for (int i = 0; i < array.length; i++) { if (array[i] < array[j]) j = i; } return j; } private int getMaximumIndex(double[] array){ int j = 0; for (int i = 0; i < array.length; i++) { if (array[i] > array[j]) j = i; } return j; } private void setup(String fileName) { // Read the file try { java.io.InputStream is = getClass().getResourceAsStream(fileName); readData(new java.io.BufferedReader(new java.io.InputStreamReader(is))); } catch (Exception e) { javax.swing.JOptionPane.showMessageDialog(this, e.getMessage(), "Exception", javax.swing.JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } // set up the user interface updateList(); } private void readData(java.io.BufferedReader in) throws java.io.IOException, java.text.ParseException { // Read a csv file String line; ArrayList tmpArrayList = null; double[] tmpArray; if ((line = in.readLine()) != null) { StringTokenizer st = new StringTokenizer(line, ","); params = new ArrayList(); while (st.hasMoreTokens()) { params.add((String) st.nextToken().trim()); } data = new ArrayList(params.size()); for (int i = 0; i < params.size(); i++) { data.add(new ArrayList()); } while((line = in.readLine()) != null) { StringTokenizer datalistSt = new StringTokenizer(line, ","); for (int i = 0; i < params.size(); i++) { tmpArrayList = (ArrayList)data.get(i); tmpArrayList.add(new Double(datalistSt.nextToken())); data.set(i,(ArrayList)tmpArrayList); } } for (int i = 0; i < params.size(); i++) { tmpArrayList = (ArrayList)data.get(i); tmpArrayList.trimToSize(); tmpArray = new double[tmpArrayList.size()]; for (int j = 0; j < tmpArray.length; j++) { tmpArray[j]= ((Double)tmpArrayList.get(j)).doubleValue(); } data.set(i,tmpArray); } } in.close(); } private Color nextColor(int i) { Color c = colorList[i%colorList.length]; return c; } /** * @param args the command line arguments */ public static void main(String args[]) { boolean exitOnClose = true; if (args.length > 0 && args[0].equals("-noexit")) { exitOnClose = false; } new SeriesAnalysis(exitOnClose).show(); } class CSVFileFilter extends javax.swing.filechooser.FileFilter { public boolean accept(java.io.File f) { boolean b = false; if (f.getName().toLowerCase().endsWith(".csv") || f.isDirectory()) { b = true; } return b; } public String getDescription() { return "Comma Separated Values (.csv)"; } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButtonDraw; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JPanel jPanel4; private javax.swing.JSeparator jSeparator; private javax.swing.JMenuItem jMenuItemAbout; private javax.swing.JMenuItem jMenuItemReadTurb; private javax.swing.JPanel jPanel3; private javax.swing.JMenu jMenuAnalyze; private com.imsl.chart.JPanelChart jPanelChart; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel1; private javax.swing.JMenuItem jMenuItemOpen; private javax.swing.JMenuBar jMenuBar; private javax.swing.JCheckBox jCheckBoxY; private javax.swing.JList jList; private javax.swing.JMenu jMenuFile; private javax.swing.JMenu jMenuHelp; private javax.swing.JMenuItem jMenuCopy; private javax.swing.JMenuItem jMenuItemReadFlight; private javax.swing.JMenuItem jMenuItemExit; // End of variables declaration//GEN-END:variables class ImageSelection implements java.awt.datatransfer.Transferable { public ImageSelection(java.awt.Image image) { theImage = image; } public java.awt.datatransfer.DataFlavor[] getTransferDataFlavors() { return new java.awt.datatransfer.DataFlavor[] { java.awt.datatransfer.DataFlavor.imageFlavor }; } public boolean isDataFlavorSupported(java.awt.datatransfer.DataFlavor flavor) { return flavor.equals(java.awt.datatransfer.DataFlavor.imageFlavor); } public Object getTransferData(java.awt.datatransfer.DataFlavor flavor) throws java.awt.datatransfer.UnsupportedFlavorException { if (flavor.equals(java.awt.datatransfer.DataFlavor.imageFlavor)) { return theImage; } else { throw new java.awt.datatransfer.UnsupportedFlavorException(flavor); } } private java.awt.Image theImage; } }