package causation.lab; // packages import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.util.*; import stats.*; import java.beans.*; import causation.lab.DistributionChooser; /** * This JInternalFrame holds a DataTable, and acts both as a wrapper, * and controlling the JButton associated with a Data Table, if there * is one. * * @see DataTable * @version 0.9 Aug 18, 1999 * @author Joel Smith * @author David Danks */ public class DataTableFrame extends JInternalFrame implements ActionListener, PropertyChangeListener{ /////////////////// Static Class Variables /////////////////// public static final int SPLIT_PANE_DISPLAY = 0; public static final int SINGLE_PANE_DISPLAY = 1; public static final int FINITE_DATASET = 100; public static final int INFINITE_DATASET = 101; private static final Dimension DEFAULT_SIZE = new Dimension(400, 400); /////////////////// Instance Variables /////////////////// int currentNextDataModelIndex = 0; int currentDataModelIndex = 0; DataTable currentDataTable; JButton imageButton; int panelTypeFlag; JSplitPane currentDisplayPane; /////////////////// Constructors /////////////////// /** * The null constructor creates a single pane (i.e., no button) * DataTableFrame */ public DataTableFrame() { this(SINGLE_PANE_DISPLAY, DEFAULT_SIZE); } /** * This constructor creates a DataTableFrame of type panelType. * @param panelType The type of DataTableFrame to construct */ public DataTableFrame(int panelType) { this(panelType, DEFAULT_SIZE); } /** * This constructor creates a DataTableFrame of type panelType, and of * the given Dimension. * @param panelType The type of DataTableFrame to construct * @param dim The size of the DataTableFrame */ public DataTableFrame(int panelType, Dimension dim){ super("Data display", true, false, true, true); currentDataModelIndex = 0; setSize(dim.width,dim.height); currentDataTable = new DataTable(); if(panelType == SINGLE_PANE_DISPLAY){ panelTypeFlag = SINGLE_PANE_DISPLAY; getContentPane().add(currentDataTable, "Center"); } if(panelType == SPLIT_PANE_DISPLAY){ panelTypeFlag = SPLIT_PANE_DISPLAY; currentDisplayPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, currentDataTable, null); getContentPane().add(currentDisplayPane, "Center"); } constructMenus(); } /////////////////// Instance Methods /////////////////// /** * This method adds a DataTableModel to the DataTable in this * DataTableFrame. displayImage can be null. * @param dataModel The DataTableModel to display * @param tableName The name of the table * @param displayImage The (possibly null) Image to display * @param datasetType The type ("size") of the dataset */ public void addDataTable(DataTableModel dataModel, String tableName, Image displayImage, int datasetType){ if ((datasetType != INFINITE_DATASET) && (datasetType != FINITE_DATASET)) { System.err.println("Bad dataset type"); return; } if(displayImage == null && panelTypeFlag == SINGLE_PANE_DISPLAY){ currentDataTable.addDataTable(dataModel, tableName, null, datasetType); currentDataTable.addPropertyChangeListener(this); currentDataTable.setSelectedIndex(currentNextDataModelIndex); getContentPane().setLayout(new BorderLayout()); getContentPane().add(currentDataTable, "Center"); } else if(displayImage != null && panelTypeFlag == SPLIT_PANE_DISPLAY ){ Dimension imageDimension; imageDimension = new Dimension(displayImage.getWidth(this), displayImage.getHeight(this)); Icon icon = new ImageIcon(displayImage); imageButton = new JButton(icon); imageButton.addActionListener(this); currentDataTable.addDataTable(dataModel, tableName, displayImage, datasetType); currentDataTable.addPropertyChangeListener(this); currentDataTable.setSelectedIndex(currentNextDataModelIndex); currentDisplayPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, imageButton, currentDataTable); currentDisplayPane.setDividerLocation(displayImage.getWidth(this)); getContentPane().removeAll(); getContentPane().add(currentDisplayPane, "Center"); } else{ System.out.println("mismatch of panel types"); } currentDataModelIndex = currentNextDataModelIndex; currentNextDataModelIndex = currentNextDataModelIndex + 1; setMenus(datasetType); } /** * This is a helper method that constructs the menus and menu bar. */ public void constructMenus(){ JMenuBar menuBar = new JMenuBar(); this.setJMenuBar(menuBar); JMenu graphMenu = new JMenu("Chart"); JMenu indepMenu = new JMenu("Independence Tests"); // straight graphs JMenuItem histogramItem = new JMenuItem("Add histogram"); JMenuItem pieChartItem = new JMenuItem("Add pie chart"); JMenuItem tallyChartItem = new JMenuItem("Add tally chart"); // conditional graphs JMenuItem condHistogramItem = new JMenuItem("Add conditional histogram"); JMenuItem condPieChartItem = new JMenuItem("Add conditional pie chart"); JMenuItem condTallyItem = new JMenuItem("Add conditional tally chart"); // independence tests JMenuItem oracleItem = new JMenuItem("Oracle"); JMenuItem contItem = new JMenuItem("Continuous Data"); JMenuItem discItem = new JMenuItem("Discrete Data"); // create the graph menu // graphMenu.add(histogramItem); // graphMenu.add(pieChartItem); // graphMenu.add(tallyChartItem); // graphMenu.addSeparator(); graphMenu.add(condHistogramItem); // graphMenu.add(condPieChartItem); // graphMenu.add(condTallyItem); // create the independence test menu indepMenu.add(oracleItem); indepMenu.add(contItem); contItem.setEnabled(false); indepMenu.add(discItem); discItem.setEnabled(false); histogramItem.addActionListener(this); pieChartItem.addActionListener(this); tallyChartItem.addActionListener(this); condHistogramItem.addActionListener(this); condTallyItem.addActionListener(this); oracleItem.addActionListener(this); contItem.addActionListener(this); discItem.addActionListener(this); menuBar.add(graphMenu); menuBar.add(indepMenu); } /** * Called by the button, or menu commands * @param evt The ActionEvent to respond to */ public void actionPerformed(ActionEvent evt){ /* For Richard's demo, we want to disable this functionality. It doesn't work right, since Swing screws up the event handling on the JDesktop if(evt.getSource() instanceof JButton){ // if the button is pressed, find out whether we should reset // the workbench int ret = JOptionPane.showInternalConfirmDialog(this, "Do you want to reset the workbench to this experimental setup?", "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (ret == JOptionPane.NO_OPTION) return; this.firePropertyChange("Reset Workbench", null, new Integer(currentDataModelIndex)); return; } */ if(evt.getSource() instanceof JMenuItem){ String arg = evt.getActionCommand(); if(arg.equals("Oracle")) { // fire off the PCE to request the oracle display firePropertyChange("Oracle", null, new Integer(currentDataModelIndex)); return; } // we don't have these tests yet else if (arg.equals("Continuous Data")) { return; } else if (arg.equals("Discrete Data")) { return; } } // Graph requests are the only evts that would get through the previous // if() block, so IF IT GETS HERE, IT MUST BE A GRAPH REQUEST ACTION // As of right now, we don't actually distinguish between the // conditional and unconditional cases. That needs to be added in. DataTableModel tabin = currentDataTable.getCurrentDataTableModel(); Tabulator tab = new Tabulator(tabin); // Build a chooser and put it in an option pane. ContingencyTableModel model = tab.getDataOut(); DistributionChooser chooser = new DistributionChooser( model, DistributionChooser.CONDITIONING_VARIABLES); int option = JOptionPane.showInternalOptionDialog( getDesktopPane(), chooser, "Distribution Chooser", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null); // Store the user-provided distribution specification. int[] independents = chooser.getSelectedIndependents(); int dependent = chooser.getSelectedDependent(); int[][] conditioningStates = chooser.getSelectedConditioningStates(); // Return if the user cancels. S/he can do this either by pressing // 'Cancel' explicitly, or by pressing 'Ok' but not selecting any // independent variables. if (option == JOptionPane.CANCEL_OPTION || independents.length == 0) { return; } // User hasn't cancelled, so let's build the charts. Vector charts = new Vector(); for (int i = 0; i < conditioningStates.length; i++) { charts.add(new BarChart(model, independents, dependent, conditioningStates[i])); } // now we want to display the charts Iterator it = charts.iterator(); int offset = 0; while (it.hasNext()) { BarChart bc = (BarChart)it.next(); ChartWrapper wrap = new ChartWrapper(bc); JInternalFrame chartFrame = new JInternalFrame("Conditional Histogram", true, true, false, true); chartFrame.getContentPane().add(wrap); getDesktopPane().add(chartFrame); chartFrame.setBounds(offset, offset, 200, 200); chartFrame.show(); offset += 30; } } /** * Enables or disables menu items as appropriate for the "size" of the * dataset * @param code The "size" of the dataset */ private void setMenus(int code) { boolean inf = (code == INFINITE_DATASET); MenuElement[] menus = getMenuBar().getSubElements(); // first, fix the entire chart menu ((JMenu)menus[0]).setEnabled(!(inf)); // then, fix the independence menu Component[] menuItems = ((JMenu)menus[1]).getMenuComponents(); menuItems[0].setEnabled(inf); // Oracle == infinite? // menuItems[1].setEnabled(!(inf)); // Cont. data == !(infinite?) // menuItems[2].setEnabled(!(inf)); // Disc. data == !(infinite?) } /** * Called whenever the tab changes in the DataTable * @param evt The PCE encoding the tab change */ public void propertyChange(PropertyChangeEvent evt){ String tempString = new String("Tab Number"); if(evt.getPropertyName().compareTo(tempString) == 0){ // adjust the parameters int tempInt = ((Integer)evt.getNewValue()).intValue(); // this line is here since multiple PCEs get sent on one // tab click if (currentDataModelIndex == tempInt) return; currentDataModelIndex = tempInt; // check the data size type (finite or infinite), and adjust // the menus appropriately if (currentDataTable.isSampleInfinite(currentDataModelIndex)) setMenus(INFINITE_DATASET); // infinite sample else setMenus(FINITE_DATASET); // finite sample // change the button in the split pane, if there is one if(panelTypeFlag == SPLIT_PANE_DISPLAY){ Icon icon = new ImageIcon(currentDataTable.getTableImage(tempInt)); JButton imageButton = new JButton(icon); imageButton.addActionListener(this); currentDisplayPane.setLeftComponent(imageButton); currentDisplayPane.setDividerLocation (currentDataTable.getTableImage(tempInt).getWidth(this)); } } } // this bracket closes DataTableFrame }