Java tutorial
/* * Copyright (C) 2011 University of Washington. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.opendatakit.briefcase.ui; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JButton; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumnModel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bushe.swing.event.annotation.AnnotationProcessor; import org.bushe.swing.event.annotation.EventSubscriber; import org.opendatakit.briefcase.model.FormStatus; import org.opendatakit.briefcase.model.FormStatus.TransferType; import org.opendatakit.briefcase.model.FormStatusEvent; import org.opendatakit.briefcase.model.RetrieveAvailableFormsSucceededEvent; public class FormTransferTable extends JTable { /** * */ private static final long serialVersionUID = 8511088963758308085L; public class JTableButtonRenderer implements TableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JButton button = (JButton) value; if (isSelected) { button.setForeground(table.getSelectionForeground()); button.setBackground(table.getSelectionBackground()); } else { button.setForeground(table.getForeground()); button.setBackground(UIManager.getColor("Button.background")); } return button; } } public class JTableButtonMouseListener implements MouseListener { public JTableButtonMouseListener() { } @Override public void mouseClicked(MouseEvent e) { int column = FormTransferTable.this.getColumnModel().getColumnIndexAtX(e.getX()); int row = e.getY() / FormTransferTable.this.getRowHeight(); if (row < FormTransferTable.this.getRowCount() && row >= 0 && column < FormTransferTable.this.getColumnCount() && column >= 0) { Object value = FormTransferTable.this.getValueAt(row, column); if (value instanceof JButton) { ((JButton) value).doClick(); } } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } } public static class DetailButton extends JButton implements ActionListener { /** * */ private static final long serialVersionUID = -5106458166776020642L; private static final Log logger = LogFactory.getLog(DetailButton.class); public static final String LABEL = "Details..."; final FormStatus status; DetailButton(FormStatus status) { super(LABEL); this.status = status; this.addActionListener(this); logger.info("creating details button"); } @Override public void actionPerformed(ActionEvent e) { try { final String history = status.getStatusHistory(); final String formName = status.getFormName(); setEnabled(false); ScrollingStatusListDialog.showDialog(JOptionPane.getFrameForComponent(this), formName, history); } finally { setEnabled(true); } } } static class FormTransferTableModel extends AbstractTableModel { /** * */ private static final long serialVersionUID = 7108326237416622721L; public static final int BUTTON_COLUMN = 3; private static final Log logger = LogFactory.getLog(FormTransferTableModel.class); final String[] columnNames; final JButton btnSelectOrClearAllForms; final TransferType transferType; final JButton btnTransfer; List<FormStatus> formStatuses = new ArrayList<FormStatus>(); private Map<FormStatus, DetailButton> buttonMap = new HashMap<FormStatus, DetailButton>(); public FormTransferTableModel(JButton btnSelectOrClearAllForms, TransferType transferType, JButton btnTransfer) { super(); AnnotationProcessor.process(this);// if not using AOP this.columnNames = new String[] { "Selected", "Form Name", ((transferType == TransferType.UPLOAD) ? PushTransferPanel.TAB_NAME : PullTransferPanel.TAB_NAME) + " Status", DetailButton.LABEL }; this.btnSelectOrClearAllForms = btnSelectOrClearAllForms; this.transferType = transferType; this.btnTransfer = btnTransfer; // initially the transfer button is disabled. btnTransfer.setEnabled(false); btnSelectOrClearAllForms.setText("Clear all"); btnSelectOrClearAllForms.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { boolean anyDeselected = false; for (FormStatus f : formStatuses) { anyDeselected = anyDeselected || !f.isSelected(); } // clear-all if all were selected, otherwise, select-all... for (FormStatus f : formStatuses) { f.setSelected(anyDeselected); } FormTransferTableModel.this.updateButtonsAfterStatusChange(); FormTransferTableModel.this.fireTableDataChanged(); } }); } private void updateButtonsAfterStatusChange() { boolean anyDeselected = false; boolean anySelected = false; for (FormStatus f : formStatuses) { anyDeselected = anyDeselected || !f.isSelected(); anySelected = anySelected || f.isSelected(); } btnTransfer.setEnabled(anySelected); if (!anyDeselected) { FormTransferTableModel.this.btnSelectOrClearAllForms.setText("Clear all"); } else { FormTransferTableModel.this.btnSelectOrClearAllForms.setText("Select all"); } } public TransferType getTransferType() { return transferType; } public void setFormStatusList(List<FormStatus> statuses) { formStatuses = statuses; updateButtonsAfterStatusChange(); fireTableDataChanged(); } public List<FormStatus> getSelectedForms() { List<FormStatus> selected = new ArrayList<FormStatus>(); for (FormStatus s : formStatuses) { if (s.isSelected()) { selected.add(s); } } return selected; } @Override public int getRowCount() { return formStatuses.size(); } public String getColumnName(int col) { return columnNames[col]; } @Override public int getColumnCount() { return columnNames.length; } /* * JTable uses this method to determine the default renderer/ editor for * each cell. If we didn't implement this method, then the boolean column would * contain text ("true"/"false"), rather than a check box. */ @SuppressWarnings({ "rawtypes", "unchecked" }) public Class getColumnClass(int c) { switch (c) { case 0: return Boolean.class; case 1: return String.class; case 2: return String.class; case 3: return JButton.class; default: throw new IllegalStateException("unexpected column choice"); } } public boolean isCellEditable(int row, int col) { return col == 0; // only the checkbox... } public void setValueAt(Object value, int row, int col) { FormStatus status = formStatuses.get(row); switch (col) { case 0: status.setSelected((Boolean) value); updateButtonsAfterStatusChange(); break; case 2: status.setStatusString((String) value, true); break; case 3: logger.warn("attempting to set button value"); break; default: throw new IllegalStateException("unexpected column choice"); } fireTableCellUpdated(row, col); } @Override public Object getValueAt(int rowIndex, int columnIndex) { FormStatus status = formStatuses.get(rowIndex); switch (columnIndex) { case 0: return status.isSelected(); case 1: return status.getFormName(); case 2: return status.getStatusString(); case 3: DetailButton button = buttonMap.get(status); if (button == null) { button = new DetailButton(status); buttonMap.put(status, button); } return button; default: throw new IllegalStateException("unexpected column choice"); } } @EventSubscriber(eventClass = FormStatusEvent.class) public void fireStatusChange(FormStatusEvent fse) { FormStatus fs = fse.getStatus(); if (fs.getTransferType() == transferType) { for (int rowIndex = 0; rowIndex < formStatuses.size(); ++rowIndex) { FormStatus status = formStatuses.get(rowIndex); if (status.equals(fs)) { fireTableRowsUpdated(rowIndex, rowIndex); return; } } } } } public FormTransferTable(JButton btnSelectOrClearAllForms, FormStatus.TransferType transferType, JButton btnTransfer) { super(new FormTransferTableModel(btnSelectOrClearAllForms, transferType, btnTransfer)); AnnotationProcessor.process(this);// if not using AOP // set the button column renderer to a custom renderer getColumn(getColumnName(FormTransferTableModel.BUTTON_COLUMN)).setCellRenderer(new JTableButtonRenderer()); addMouseListener(new JTableButtonMouseListener()); TableColumnModel columns = this.getColumnModel(); // determine width of "Selected" column header TableCellRenderer headerRenderer = this.getTableHeader().getDefaultRenderer(); Component comp = headerRenderer.getTableCellRendererComponent(null, columns.getColumn(0).getHeaderValue(), false, false, 0, 0); int headerWidth = comp.getPreferredSize().width; columns.getColumn(0).setMinWidth(headerWidth); columns.getColumn(0).setMaxWidth(headerWidth); columns.getColumn(0).setPreferredWidth(headerWidth); // create a detail button (that we'll throw away) // so we can get the needed column and row dimensions. comp = new DetailButton(null); int buttonWidth = comp.getPreferredSize().width; int buttonHeight = comp.getPreferredSize().height; columns.getColumn(FormTransferTableModel.BUTTON_COLUMN).setMinWidth(buttonWidth); columns.getColumn(FormTransferTableModel.BUTTON_COLUMN).setMaxWidth(buttonWidth); columns.getColumn(FormTransferTableModel.BUTTON_COLUMN).setPreferredWidth(buttonWidth); // set the row height to be big enough to include a button and have space above and below it setRowHeight(buttonHeight); // btn used is arbitrary... // and scale the others to be wider... columns.getColumn(1).setPreferredWidth(5 * headerWidth); columns.getColumn(2).setPreferredWidth(5 * headerWidth); this.setFillsViewportHeight(true); } public void setFormStatusList(List<FormStatus> statuses) { FormTransferTableModel model = (FormTransferTableModel) this.dataModel; model.setFormStatusList(statuses); } @EventSubscriber(eventClass = RetrieveAvailableFormsSucceededEvent.class) public void formsAvailableFromServer(RetrieveAvailableFormsSucceededEvent event) { FormTransferTableModel model = (FormTransferTableModel) this.dataModel; if (event.getTransferType() == model.getTransferType()) { setFormStatusList(event.getFormsToTransfer()); } } public List<FormStatus> getSelectedForms() { FormTransferTableModel model = (FormTransferTableModel) this.dataModel; return model.getSelectedForms(); } }