package edu.brown.oltpgenerator.gui; import java.awt.Color; import java.awt.Container; 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.util.Arrays; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumnModel; import org.voltdb.VoltType; import org.voltdb.catalog.Column; import org.voltdb.catalog.Table; import edu.brown.oltpgenerator.Utils; import edu.brown.oltpgenerator.env.TableEnv; import edu.brown.oltpgenerator.env.RandomDistribution.RandomDistributionEnv; import edu.brown.oltpgenerator.gui.common.GuiConstants; import edu.brown.oltpgenerator.gui.common.LHSListPane; import edu.brown.oltpgenerator.gui.common.Notifier; import edu.brown.oltpgenerator.gui.common.UpperPane; import edu.brown.oltpgenerator.gui.common.ZListSelectionListener; import edu.brown.oltpgenerator.gui.common.RandomDistribution.RandomDistributionEditorManager; public class TableGui extends JPanel { private static final long serialVersionUID = 1L; private Container m_paneParent; private Notifier m_notifier; /* * The JComponent fields are here (rather than defined in * establishGuiTree()) because they are accessible by functions outside * establishGuiTree() */ private JButton m_btLoadSchema = new JButton("Load Schema File"); private JList m_lstTblName = new JList(); private JTextField m_txtCardinality = new JTextField(); private JTable m_tblColView = new JTable(new ColumnViewModel(null, new Column[0])); private JPanel m_paneColEdit = new JPanel(); private JCheckBox m_checkLinkCsv = new JCheckBox("Link table to CSV file"); private JTextField m_txtLinkCsvPath = new JTextField(CsvLinkStatus.UNLINKED.m_sStatus); private int m_nYOffsetInRightPane = 0; private LHSListPane m_scrollTblName; private UpperPane m_paneTblBt; private static int s_nRightPaneWidth = 600; private static int s_nOneRowPaneHeight = 40; private static JPanel s_paneDummy = new JPanel(); private static enum TableInfoColumn { NAME("Column Name"), TYPE("Type"), REFER("Foreign Key Of"); public String m_sName; private TableInfoColumn(String name) { m_sName = name; } } private static enum CsvLinkStatus { UNLINKED("No csv file linked"), LINKED("Linked to "); public String m_sStatus; private CsvLinkStatus(String sStatus) { m_sStatus = sStatus; } } public TableGui(JTabbedPane paneTab, Notifier notifier) { m_paneParent = paneTab; m_notifier = notifier; establishGuiTree(); addListeners(); } public void clearColumnEditPane() { RandomDistributionEditorManager.clear(m_paneColEdit); m_paneColEdit.add(s_paneDummy); } private static class ColumnViewModel extends AbstractTableModel { private static final long serialVersionUID = 1L; Object[][] data; public ColumnViewModel(Table tbl, Column[] cols) { data = new Object[cols.length][3]; for (int i = 0; i < cols.length; i++) { Column c = cols[i]; data[i][0] = c.getName(); String voltType = VoltType.get((byte) c.getType()).toString(); // form: // VoltType.xxx int posDot = voltType.indexOf("."); String typeName = voltType.substring(posDot + 1); data[i][1] = typeName; Column referredC = TableEnv.getReferredColumn(c); data[i][2] = referredC == null ? " " : referredC.getParent().getName() + " [" + referredC.getName() + "]"; } } @Override public int getColumnCount() { return TableInfoColumn.values().length; } public String getColumnName(int idx) { return TableInfoColumn.values()[idx].m_sName; } @Override public int getRowCount() { return data.length; } @Override public Object getValueAt(int rowIndex, int columnIndex) { return data[rowIndex][columnIndex]; } public void setValueAt(Object value, int row, int col) { data[row][col] = value; fireTableCellUpdated(row, col); } } private void addListeners() { addLoadSchemaListener(); addCardinalityListener(); addTableNameListListener(); addLinkCsvListener(); addColumnViewListener(); } private void addColumnViewListener() { m_tblColView.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); m_tblColView.getSelectionModel().addListSelectionListener(new ListSelectionListener() { int iColPrev = -2; int iTblPrev = -2; @Override public void valueChanged(ListSelectionEvent e) { int iColCur = m_tblColView.getSelectedRow(); int iTblCur = m_lstTblName.getSelectedIndex(); showTableCardinality(); if (iColCur >= 0 && (iTblCur != iTblPrev || iColCur != iColPrev)) { iColPrev = iColCur; iTblPrev = iTblCur; String sColName = (String) m_tblColView.getModel().getValueAt(iColCur, 0); Column col = getSelectedColumn(sColName); RandomDistributionEditorManager.display(m_paneColEdit, col); } } private Column getSelectedColumn(String sColName) { String sTblName = (String) m_lstTblName.getSelectedValue(); Table table = TableEnv.getTable(sTblName); return table.getColumns().get(sColName); } }); } private void addLinkCsvListener() { final JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); m_checkLinkCsv.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { String sTblName = m_lstTblName.getSelectedValue().toString(); switch (e.getStateChange()) { case ItemEvent.DESELECTED: { m_txtLinkCsvPath.setText(CsvLinkStatus.UNLINKED.m_sStatus); TableEnv.unlinkTalbe(sTblName); return; } case ItemEvent.SELECTED: { int returnVal = fc.showOpenDialog(TableGui.this); if (returnVal == JFileChooser.APPROVE_OPTION) { String sCsvPath = fc.getSelectedFile().getPath(); TableEnv.linkTableToCsv(sTblName, sCsvPath); m_txtLinkCsvPath.setText(CsvLinkStatus.LINKED.m_sStatus + sCsvPath); } else { m_checkLinkCsv.setSelected(false); } } default: return; } } }); } private void showTableColInfo(Table table) { Column[] cols = (table == null) ? new Column[0] : Utils.getNonNullElements(table.getColumns().values()); ColumnViewModel model = new ColumnViewModel(table, cols); m_tblColView.setModel(model); setTableColInfoWidth(); } private void setTableColInfoWidth() { AbstractTableModel abs_model = (AbstractTableModel) m_tblColView.getModel(); int idx_col = abs_model.findColumn(TableInfoColumn.NAME.m_sName); int idx_colType = abs_model.findColumn(TableInfoColumn.TYPE.m_sName); TableColumnModel model = m_tblColView.getColumnModel(); model.getColumn(idx_col).setPreferredWidth(1); model.getColumn(idx_colType).setPreferredWidth(1); } private void addTableNameListListener() { m_lstTblName.addListSelectionListener(new ZListSelectionListener() { @Override public void whenSelecting(String selectedItemName) { Table table = TableEnv.getTable(selectedItemName); // display selected table's column information showTableColInfo(table); // display cardinality showTableCardinality(); clearColumnEditPane(); enableTableOptions(); } }); } private void showTableCardinality() { String sSelectedTableName = m_lstTblName.getSelectedValue().toString(); m_txtCardinality.setText(TableEnv.getCardinality(sSelectedTableName).toString()); } private void addCardinalityListener() { m_txtCardinality.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String tblName = m_lstTblName.getSelectedValue().toString(); String input = m_txtCardinality.getText(); Integer oldCardinality = TableEnv.getCardinality(tblName); String oldText = oldCardinality.toString(); // System.out.println("old value: " + oldText); try { int newCardinality = Integer.parseInt(input); if (newCardinality > 0) { TableEnv.setCardinality(tblName, newCardinality); } else { m_notifier.showMsg("Cardinality should be a positive integer", false); m_txtCardinality.setText(oldText); } } catch (NumberFormatException ex) { m_notifier.showMsg("Cardinality should be an integer", false); m_txtCardinality.setText(oldText); } } }); m_txtCardinality.addFocusListener(new FocusListener() { String sOldText = null; @Override public void focusGained(FocusEvent e) { sOldText = m_txtCardinality.getText(); m_txtCardinality.setText(null); } @Override public void focusLost(FocusEvent e) { m_txtCardinality.setText(sOldText); } }); } private void addLoadSchemaListener() { final JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); // JFileChoose is in the closure of inner class m_btLoadSchema.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int returnVal = fc.showOpenDialog(TableGui.this); if (returnVal == JFileChooser.APPROVE_OPTION) { TableEnv.clear(); RandomDistributionEnv.clearColumnEdits(); String schemaPath = fc.getSelectedFile().getPath(); TableEnv.setSrcSchemaPath(schemaPath); m_notifier.showMsg("Loading from " + schemaPath, true); TableEnv.readSchema(); TableEnv.loadDefaultColumnProperty(); String[] tableNames = TableEnv.getTableNames(TableEnv.getAllTables()); Arrays.sort(tableNames); m_lstTblName.setListData(tableNames); showTableColInfo(null); clearColumnEditPane(); m_notifier.showMsg("Complete loading from " + schemaPath, false); disableTableOptions(); } } }); } private void establishGuiTree() { setLayout(null); addAllTablesPane(); addTableViewEditPane(); } private void addTableViewEditPane() { JPanel paneTableDisplayAndEdit = new JPanel(); paneTableDisplayAndEdit.setLayout(null); int nWidth = m_paneParent.getWidth(); int nHeight = m_paneParent.getHeight() - m_paneTblBt.getHeight() - 3 * GuiConstants.GAP_COMPONENT; paneTableDisplayAndEdit.setBounds(0, m_paneTblBt.getHeight(), nWidth, nHeight); add(paneTableDisplayAndEdit); // paneTableDisplayAndEdit.setBorder(BorderFactory.createLineBorder(Color.red)); m_scrollTblName = new LHSListPane(paneTableDisplayAndEdit, m_lstTblName); paneTableDisplayAndEdit.add(m_scrollTblName); paneTableDisplayAndEdit.add(createTableCSVArea()); paneTableDisplayAndEdit.add(createTableCardinalityArea()); paneTableDisplayAndEdit.add(createColumnViewArea()); paneTableDisplayAndEdit.add(createColumnEditArea()); disableTableOptions(); } private JPanel createColumnEditArea() { m_paneColEdit.setBorder(BorderFactory.createLineBorder(Color.GRAY)); /* * Hackish: this paneDummy will be removed in display() of ColumnEdit. */ JPanel paneDummy = new JPanel(); m_paneColEdit.add(paneDummy); m_paneColEdit.setBounds(m_scrollTblName.getWidth() + GuiConstants.GAP_COMPONENT, m_nYOffsetInRightPane, s_nRightPaneWidth, m_scrollTblName.getHeight() - m_nYOffsetInRightPane); return m_paneColEdit; } private JScrollPane createColumnViewArea() { JScrollPane scroll_colEdit = new JScrollPane(); scroll_colEdit.setViewportView(m_tblColView); scroll_colEdit.setBounds(m_scrollTblName.getWidth() + GuiConstants.GAP_COMPONENT, m_nYOffsetInRightPane, s_nRightPaneWidth, 300); m_nYOffsetInRightPane += (scroll_colEdit.getHeight() + GuiConstants.GAP_COMPONENT); return scroll_colEdit; } private JPanel createTableCSVArea() { JPanel paneCSV = new JPanel(); paneCSV.setLayout(new BoxLayout(paneCSV, BoxLayout.X_AXIS)); paneCSV.setBorder(BorderFactory.createLineBorder(Color.GRAY)); paneCSV.add(m_checkLinkCsv); paneCSV.add(m_txtLinkCsvPath); m_txtLinkCsvPath.setEditable(false); paneCSV.setBounds(m_scrollTblName.getWidth() + GuiConstants.GAP_COMPONENT, m_nYOffsetInRightPane, s_nRightPaneWidth, s_nOneRowPaneHeight); m_nYOffsetInRightPane += (s_nOneRowPaneHeight + GuiConstants.GAP_COMPONENT); return paneCSV; } private JPanel createTableCardinalityArea() { JPanel paneTblCardinality = new JPanel(); paneTblCardinality.setLayout(new BoxLayout(paneTblCardinality, BoxLayout.LINE_AXIS)); paneTblCardinality.setBorder(BorderFactory.createLineBorder(Color.GRAY)); JLabel lblCard = new JLabel("Table Cardinality (press \"Enter\" to confirm): "); paneTblCardinality.add(lblCard); m_txtCardinality.setColumns(5); paneTblCardinality.add(m_txtCardinality); paneTblCardinality.setBounds(m_scrollTblName.getWidth() + GuiConstants.GAP_COMPONENT, m_nYOffsetInRightPane, s_nRightPaneWidth, s_nOneRowPaneHeight); m_nYOffsetInRightPane += (s_nOneRowPaneHeight + GuiConstants.GAP_COMPONENT); return paneTblCardinality; } private void enableTableOptions() { m_checkLinkCsv.setEnabled(true); String sCsvLink = TableEnv.getTableCsvLink(m_lstTblName.getSelectedValue().toString()); if (sCsvLink != null) { m_txtLinkCsvPath.setText(CsvLinkStatus.LINKED.m_sStatus + sCsvLink); // disable check box listener for one moment ItemListener listener = m_checkLinkCsv.getItemListeners()[0]; m_checkLinkCsv.removeItemListener(listener); m_checkLinkCsv.setSelected(true); m_checkLinkCsv.addItemListener(listener); } else { m_txtLinkCsvPath.setText(CsvLinkStatus.UNLINKED.m_sStatus); m_checkLinkCsv.setSelected(false); } m_txtCardinality.setEnabled(true); } private void disableTableOptions() { m_checkLinkCsv.setEnabled(false); m_txtCardinality.setEnabled(false); m_txtCardinality.setText(null); } private void addAllTablesPane() { m_paneTblBt = new UpperPane(m_paneParent); m_paneTblBt.add(m_btLoadSchema); add(m_paneTblBt); } }