| /******************************************************************************* |
| * Copyright (C) 2009 The University of Manchester |
| * |
| * Modifications to the initial code base are copyright of their |
| * respective authors, or their employers as appropriate. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public License |
| * as published by the Free Software Foundation; either version 2.1 of |
| * the License, or (at your option) any later version. |
| * |
| * This program 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 |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| ******************************************************************************/ |
| package net.sf.taverna.t2.activities.spreadsheet.views; |
| |
| import java.awt.BorderLayout; |
| import java.awt.CardLayout; |
| import java.awt.Color; |
| import java.awt.Component; |
| import java.awt.Dimension; |
| import java.awt.FlowLayout; |
| import java.awt.Font; |
| import java.awt.Graphics; |
| import java.awt.GridBagConstraints; |
| import java.awt.GridBagLayout; |
| import java.awt.Insets; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.ItemEvent; |
| import java.awt.event.ItemListener; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| import java.util.Stack; |
| |
| import javax.swing.ButtonGroup; |
| import javax.swing.DefaultCellEditor; |
| import javax.swing.JButton; |
| import javax.swing.JCheckBox; |
| import javax.swing.JComponent; |
| import javax.swing.JLabel; |
| import javax.swing.JPanel; |
| import javax.swing.JRadioButton; |
| import javax.swing.JScrollPane; |
| import javax.swing.JTable; |
| import javax.swing.JTextField; |
| import javax.swing.SwingConstants; |
| import javax.swing.border.Border; |
| import javax.swing.border.CompoundBorder; |
| import javax.swing.border.EmptyBorder; |
| import javax.swing.event.DocumentEvent; |
| import javax.swing.event.DocumentListener; |
| import javax.swing.table.DefaultTableColumnModel; |
| import javax.swing.table.TableCellEditor; |
| import javax.swing.table.TableColumn; |
| import javax.swing.text.AttributeSet; |
| import javax.swing.text.BadLocationException; |
| import javax.swing.text.JTextComponent; |
| import javax.swing.text.PlainDocument; |
| |
| import net.sf.taverna.t2.activities.spreadsheet.Range; |
| import net.sf.taverna.t2.activities.spreadsheet.SpreadsheetUtils; |
| import net.sf.taverna.t2.activities.spreadsheet.il8n.SpreadsheetImportUIText; |
| import net.sf.taverna.t2.lang.ui.DialogTextArea; |
| import net.sf.taverna.t2.lang.ui.icons.Icons; |
| import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationPanel; |
| |
| import org.apache.commons.lang.StringEscapeUtils; |
| import org.apache.log4j.Logger; |
| |
| import uk.org.taverna.commons.services.ServiceRegistry; |
| import uk.org.taverna.scufl2.api.activity.Activity; |
| |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.fasterxml.jackson.databind.node.ArrayNode; |
| import com.fasterxml.jackson.databind.node.ObjectNode; |
| |
| /** |
| * Configuration panel for the spreadsheet import activity. |
| * |
| * @author David Withers |
| */ |
| @SuppressWarnings("serial") |
| public class SpreadsheetImportConfigView extends ActivityConfigurationPanel { |
| |
| private static final String INCONSISTENT_ROW_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.INCONSISTENT_ROW_MESSAGE"); |
| |
| private static final String INCONSISTENT_COLUMN_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.INCONSISTENT_COLUMN_MESSAGE"); |
| |
| private static final String FROM_COLUMN_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.FROM_COLUMN_ERROR_MESSAGE"); |
| |
| private static final String TO_COLUMN_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.TO_COLUMN_ERROR_MESSAGE"); |
| |
| private static final String FROM_ROW_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.FROM_ROW_ERROR_MESSAGE"); |
| |
| private static final String TO_ROW_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.TO_ROW_ERROR_MESSAGE"); |
| |
| private static final String DEFAULT_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.DEFAULT_MESSAGE"); |
| |
| private static final String EMPTY_FROM_ROW_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.EMPTY_FROM_ROW_ERROR_MESSAGE"); |
| |
| private static final String EMPTY_FROM_COLUMN_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.EMPTY_FROM_COLUMN_ERROR_MESSAGE"); |
| |
| private static final String EMPTY_TO_COLUMN_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.EMPTY_TO_COLUMN_ERROR_MESSAGE"); |
| |
| private static final String DUPLICATE_PORT_NAME_ERROR_MESSAGE = SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.DUPLICATE_PORT_NAME_ERROR_MESSAGE"); |
| |
| private static Logger logger = Logger.getLogger(SpreadsheetImportConfigView.class); |
| |
| private JPanel titlePanel, contentPanel, buttonPanel, page1, page2; |
| |
| private JLabel titleLabel, titleIcon, rowLabel, columnLabel; |
| |
| private JLabel emptyCellLabel, outputFormatLabel, outputFormatDelimiterLabel, columnMappingLabel; |
| |
| private DialogTextArea titleMessage; |
| |
| private JTextField columnFromValue, columnToValue, rowFromValue, rowToValue; |
| |
| private JTextField emptyCellUserDefinedValue, outputFormatDelimiter; |
| |
| private JCheckBox rowSelectAllOption, rowExcludeFirstOption, rowIgnoreBlankRows; |
| |
| private ButtonGroup emptyCellButtonGroup, outputFormatButtonGroup; |
| |
| private JRadioButton emptyCellEmptyStringOption, emptyCellUserDefinedOption, |
| emptyCellErrorValueOption; |
| |
| private JRadioButton outputFormatMultiplePort, outputFormatSinglePort; |
| |
| private JTable columnMappingTable; |
| |
| private SpreadsheetImportConfigTableModel columnMappingTableModel; |
| |
| private JButton nextButton, backButton; |
| |
| private CardLayout cardLayout = new CardLayout(); |
| |
| private Stack<String> warningMessages = new Stack<String>(); |
| |
| private Stack<String> errorMessages = new Stack<String>(); |
| |
| private ObjectNode newConfiguration; |
| |
| private final ServiceRegistry serviceRegistry; |
| |
| /** |
| * Constructs a configuration view for an SpreadsheetImport Activity. |
| * |
| * @param activity |
| */ |
| public SpreadsheetImportConfigView(Activity activity, ServiceRegistry serviceRegistry) { |
| super(activity); |
| this.serviceRegistry = serviceRegistry; |
| initialise(); |
| } |
| |
| @Override |
| protected void initialise() { |
| super.initialise(); |
| newConfiguration = getJson().deepCopy(); |
| |
| // title |
| titlePanel = new JPanel(new BorderLayout()); |
| titlePanel.setBackground(Color.WHITE); |
| addDivider(titlePanel, SwingConstants.BOTTOM, true); |
| |
| titleLabel = new JLabel(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.panelTitle")); |
| titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 13.5f)); |
| titleIcon = new JLabel(""); |
| titleMessage = new DialogTextArea(DEFAULT_MESSAGE); |
| titleMessage.setMargin(new Insets(5, 10, 10, 10)); |
| // titleMessage.setMinimumSize(new Dimension(0, 30)); |
| titleMessage.setFont(titleMessage.getFont().deriveFont(11f)); |
| titleMessage.setEditable(false); |
| titleMessage.setFocusable(false); |
| // titleMessage.setFont(titleLabel.getFont().deriveFont(Font.PLAIN, |
| // 12f)); |
| |
| // column range |
| columnLabel = new JLabel(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.columnSectionLabel")); |
| |
| JsonNode columnRange = newConfiguration.get("columnRange"); |
| columnFromValue = new JTextField(new UpperCaseDocument(), SpreadsheetUtils.getColumnLabel(columnRange.get("start").intValue()), 4); |
| columnFromValue.setMinimumSize(columnFromValue.getPreferredSize()); |
| columnToValue = new JTextField(new UpperCaseDocument(), SpreadsheetUtils.getColumnLabel(columnRange.get("end").intValue()), 4); |
| columnToValue.setMinimumSize(columnToValue.getPreferredSize()); |
| |
| columnFromValue.getDocument().addDocumentListener(new DocumentListener() { |
| public void changedUpdate(DocumentEvent e) { |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| checkValue(columnFromValue.getText()); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| checkValue(columnFromValue.getText()); |
| } |
| |
| private void checkValue(String text) { |
| if (text.trim().equals("")) { |
| addErrorMessage(EMPTY_FROM_COLUMN_ERROR_MESSAGE); |
| } else if (text.trim().matches("[A-Za-z]+")) { |
| String fromColumn = columnFromValue.getText().toUpperCase(); |
| String toColumn = columnToValue.getText().toUpperCase(); |
| int fromColumnIndex = SpreadsheetUtils.getColumnIndex(fromColumn); |
| int toColumnIndex = SpreadsheetUtils.getColumnIndex(toColumn); |
| if (checkColumnRange(fromColumnIndex, toColumnIndex)) { |
| columnMappingTableModel.setFromColumn(fromColumnIndex); |
| columnMappingTableModel.setToColumn(toColumnIndex); |
| newConfiguration.set("columnRange", newConfiguration.objectNode().put("start", fromColumnIndex).put("end", toColumnIndex)); |
| validatePortNames(); |
| } |
| removeErrorMessage(FROM_COLUMN_ERROR_MESSAGE); |
| removeErrorMessage(EMPTY_FROM_COLUMN_ERROR_MESSAGE); |
| } else { |
| addErrorMessage(FROM_COLUMN_ERROR_MESSAGE); |
| removeErrorMessage(EMPTY_FROM_COLUMN_ERROR_MESSAGE); |
| } |
| } |
| |
| }); |
| |
| columnToValue.getDocument().addDocumentListener(new DocumentListener() { |
| public void changedUpdate(DocumentEvent e) { |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| checkValue(columnToValue.getText()); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| checkValue(columnToValue.getText()); |
| } |
| |
| private void checkValue(String text) { |
| if (text.trim().equals("")) { |
| addErrorMessage(EMPTY_TO_COLUMN_ERROR_MESSAGE); |
| } else if (text.trim().matches("[A-Za-z]+")) { |
| String fromColumn = columnFromValue.getText().toUpperCase(); |
| String toColumn = columnToValue.getText().toUpperCase(); |
| int fromColumnIndex = SpreadsheetUtils.getColumnIndex(fromColumn); |
| int toColumnIndex = SpreadsheetUtils.getColumnIndex(toColumn); |
| if (checkColumnRange(fromColumnIndex, toColumnIndex)) { |
| columnMappingTableModel.setFromColumn(fromColumnIndex); |
| columnMappingTableModel.setToColumn(toColumnIndex); |
| newConfiguration.set("columnRange", newConfiguration.objectNode().put("start", fromColumnIndex).put("end", toColumnIndex)); |
| validatePortNames(); |
| } |
| removeErrorMessage(TO_COLUMN_ERROR_MESSAGE); |
| removeErrorMessage(EMPTY_TO_COLUMN_ERROR_MESSAGE); |
| |
| } else { |
| addErrorMessage(TO_COLUMN_ERROR_MESSAGE); |
| removeErrorMessage(EMPTY_TO_COLUMN_ERROR_MESSAGE); |
| } |
| } |
| }); |
| |
| // row range |
| rowLabel = new JLabel(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.rowSectionLabel")); |
| addDivider(rowLabel, SwingConstants.TOP, false); |
| |
| rowSelectAllOption = new JCheckBox(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.selectAllRowsOption")); |
| rowExcludeFirstOption = new JCheckBox(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.excludeHeaderRowOption")); |
| rowIgnoreBlankRows = new JCheckBox(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.ignoreBlankRowsOption")); |
| rowSelectAllOption.setFocusable(false); |
| rowExcludeFirstOption.setFocusable(false); |
| |
| JsonNode rowRange = newConfiguration.get("rowRange"); |
| rowFromValue = new JTextField(new NumericDocument(), String.valueOf(rowRange.get("start").intValue() + 1), 4); |
| if (rowRange.get("end").intValue() == -1) { |
| rowToValue = new JTextField(new NumericDocument(), "", 4); |
| } else { |
| rowToValue = new JTextField(new NumericDocument(), String.valueOf(rowRange.get("end").intValue() + 1), 4); |
| } |
| rowFromValue.setMinimumSize(rowFromValue.getPreferredSize()); |
| rowToValue.setMinimumSize(rowToValue.getPreferredSize()); |
| |
| if (newConfiguration.get("allRows").booleanValue()) { |
| rowSelectAllOption.setSelected(true); |
| rowFromValue.setEditable(false); |
| rowFromValue.setEnabled(false); |
| rowToValue.setEditable(false); |
| rowToValue.setEnabled(false); |
| } else { |
| rowExcludeFirstOption.setEnabled(false); |
| } |
| rowExcludeFirstOption.setSelected(newConfiguration.get("excludeFirstRow").booleanValue()); |
| rowIgnoreBlankRows.setSelected(newConfiguration.get("ignoreBlankRows").booleanValue()); |
| |
| rowFromValue.getDocument().addDocumentListener(new DocumentListener() { |
| public void changedUpdate(DocumentEvent e) { |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| checkValue(rowFromValue.getText()); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| checkValue(rowFromValue.getText()); |
| } |
| |
| private void checkValue(String text) { |
| if (text.trim().equals("")) { |
| addErrorMessage(EMPTY_FROM_ROW_ERROR_MESSAGE); |
| } else if (text.trim().matches("[1-9][0-9]*")) { |
| checkRowRange(rowFromValue.getText(), rowToValue.getText()); |
| int fromRow = Integer.parseInt(rowFromValue.getText()); |
| ((ObjectNode) newConfiguration.get("rowRange")).put("start", fromRow - 1); |
| removeErrorMessage(FROM_ROW_ERROR_MESSAGE); |
| removeErrorMessage(EMPTY_FROM_ROW_ERROR_MESSAGE); |
| } else { |
| addErrorMessage(FROM_ROW_ERROR_MESSAGE); |
| removeErrorMessage(EMPTY_FROM_ROW_ERROR_MESSAGE); |
| } |
| } |
| }); |
| |
| rowToValue.getDocument().addDocumentListener(new DocumentListener() { |
| public void changedUpdate(DocumentEvent e) { |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| checkValue(rowToValue.getText()); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| checkValue(rowToValue.getText()); |
| } |
| |
| private void checkValue(String text) { |
| if (text.trim().equals("")) { |
| ((ObjectNode) newConfiguration.get("rowRange")).put("end", -1); |
| removeErrorMessage(TO_ROW_ERROR_MESSAGE); |
| removeErrorMessage(INCONSISTENT_ROW_MESSAGE); |
| } else if (text.trim().matches("[0-9]+")) { |
| checkRowRange(rowFromValue.getText(), rowToValue.getText()); |
| int toRow = Integer.parseInt(rowToValue.getText()); |
| ((ObjectNode) newConfiguration.get("rowRange")).put("end", toRow - 1); |
| removeErrorMessage(TO_ROW_ERROR_MESSAGE); |
| } else { |
| addErrorMessage(TO_ROW_ERROR_MESSAGE); |
| } |
| } |
| }); |
| |
| rowSelectAllOption.addItemListener(new ItemListener() { |
| public void itemStateChanged(ItemEvent e) { |
| if (e.getStateChange() == ItemEvent.SELECTED) { |
| newConfiguration.put("allRows", true); |
| rowExcludeFirstOption.setEnabled(true); |
| if (rowExcludeFirstOption.isSelected()) { |
| rowFromValue.setText("2"); |
| } else { |
| rowFromValue.setText("1"); |
| } |
| rowToValue.setText(""); |
| rowFromValue.setEditable(false); |
| rowFromValue.setEnabled(false); |
| rowToValue.setEditable(false); |
| rowToValue.setEnabled(false); |
| } else { |
| newConfiguration.put("allRows", false); |
| rowExcludeFirstOption.setEnabled(false); |
| rowFromValue.setEditable(true); |
| rowFromValue.setEnabled(true); |
| rowToValue.setEditable(true); |
| rowToValue.setEnabled(true); |
| } |
| } |
| }); |
| |
| rowExcludeFirstOption.addItemListener(new ItemListener() { |
| public void itemStateChanged(ItemEvent e) { |
| if (e.getStateChange() == ItemEvent.SELECTED) { |
| newConfiguration.put("excludeFirstRow", true); |
| rowFromValue.setText("2"); |
| ((ObjectNode) newConfiguration.get("rowRange")).put("start", 1); |
| } else { |
| newConfiguration.put("excludeFirstRow", false); |
| rowFromValue.setText("1"); |
| ((ObjectNode) newConfiguration.get("rowRange")).put("start", 0); |
| } |
| } |
| }); |
| |
| rowIgnoreBlankRows.addItemListener(new ItemListener() { |
| public void itemStateChanged(ItemEvent e) { |
| newConfiguration.put("ignoreBlankRows", e.getStateChange() == ItemEvent.SELECTED); |
| } |
| }); |
| |
| // empty cells |
| emptyCellLabel = new JLabel(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.emptyCellSectionLabel")); |
| addDivider(emptyCellLabel, SwingConstants.TOP, false); |
| |
| emptyCellButtonGroup = new ButtonGroup(); |
| emptyCellEmptyStringOption = new JRadioButton(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.emptyStringOption")); |
| emptyCellUserDefinedOption = new JRadioButton(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.userDefinedOption")); |
| emptyCellErrorValueOption = new JRadioButton(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.generateErrorOption")); |
| emptyCellEmptyStringOption.setFocusable(false); |
| emptyCellUserDefinedOption.setFocusable(false); |
| emptyCellErrorValueOption.setFocusable(false); |
| |
| emptyCellUserDefinedValue = new JTextField(newConfiguration.get("emptyCellValue").textValue()); |
| |
| emptyCellButtonGroup.add(emptyCellEmptyStringOption); |
| emptyCellButtonGroup.add(emptyCellUserDefinedOption); |
| emptyCellButtonGroup.add(emptyCellErrorValueOption); |
| |
| if (newConfiguration.get("emptyCellPolicy").textValue().equals("GENERATE_ERROR")) { |
| emptyCellErrorValueOption.setSelected(true); |
| emptyCellUserDefinedValue.setEnabled(false); |
| emptyCellUserDefinedValue.setEditable(false); |
| } else if (newConfiguration.get("emptyCellPolicy").textValue().equals("EMPTY_STRING")) { |
| emptyCellEmptyStringOption.setSelected(true); |
| emptyCellUserDefinedValue.setEnabled(false); |
| emptyCellUserDefinedValue.setEditable(false); |
| } else { |
| emptyCellUserDefinedOption.setSelected(true); |
| emptyCellUserDefinedValue.setText(newConfiguration.get("emptyCellValue").textValue()); |
| emptyCellUserDefinedValue.setEnabled(true); |
| emptyCellUserDefinedValue.setEditable(true); |
| } |
| |
| emptyCellEmptyStringOption.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| newConfiguration.put("emptyCellPolicy", "EMPTY_STRING"); |
| emptyCellUserDefinedValue.setEnabled(false); |
| emptyCellUserDefinedValue.setEditable(false); |
| } |
| }); |
| emptyCellUserDefinedOption.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| newConfiguration.put("emptyCellPolicy", "USER_DEFINED"); |
| emptyCellUserDefinedValue.setEnabled(true); |
| emptyCellUserDefinedValue.setEditable(true); |
| emptyCellUserDefinedValue.requestFocusInWindow(); |
| } |
| }); |
| emptyCellErrorValueOption.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| newConfiguration.put("emptyCellPolicy", "GENERATE_ERROR"); |
| emptyCellUserDefinedValue.setEnabled(false); |
| emptyCellUserDefinedValue.setEditable(false); |
| } |
| }); |
| |
| emptyCellUserDefinedValue.getDocument().addDocumentListener(new DocumentListener() { |
| public void changedUpdate(DocumentEvent e) { |
| newConfiguration.put("emptyCellValue", emptyCellUserDefinedValue.getText()); |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| newConfiguration.put("emptyCellValue", emptyCellUserDefinedValue.getText()); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| newConfiguration.put("emptyCellValue", emptyCellUserDefinedValue.getText()); |
| } |
| }); |
| |
| // column mappings |
| columnMappingLabel = new JLabel(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.columnMappingSectionLabel")); |
| addDivider(columnMappingLabel, SwingConstants.TOP, false); |
| |
| Map<String, String> columnToPortMapping = new HashMap<>(); |
| if (newConfiguration.has("columnNames")) { |
| for (JsonNode columnName : newConfiguration.get("columnNames")) { |
| columnToPortMapping.put(columnName.get("column").textValue(), columnName.get("port").textValue()); |
| } |
| } |
| columnMappingTableModel = new SpreadsheetImportConfigTableModel(columnFromValue.getText(), |
| columnToValue.getText(), columnToPortMapping); |
| |
| columnMappingTable = new JTable(); |
| columnMappingTable.setRowSelectionAllowed(false); |
| columnMappingTable.getTableHeader().setReorderingAllowed(false); |
| columnMappingTable.setGridColor(Color.LIGHT_GRAY); |
| // columnMappingTable.setFocusable(false); |
| |
| columnMappingTable.setColumnModel(new DefaultTableColumnModel() { |
| public TableColumn getColumn(int columnIndex) { |
| TableColumn column = super.getColumn(columnIndex); |
| if (columnIndex == 0) { |
| column.setMaxWidth(100); |
| } |
| return column; |
| } |
| }); |
| |
| TableCellEditor defaultEditor = columnMappingTable.getDefaultEditor(String.class); |
| if (defaultEditor instanceof DefaultCellEditor) { |
| DefaultCellEditor defaultCellEditor = (DefaultCellEditor) defaultEditor; |
| defaultCellEditor.setClickCountToStart(1); |
| Component editorComponent = defaultCellEditor.getComponent(); |
| if (editorComponent instanceof JTextComponent) { |
| final JTextComponent textField = (JTextComponent) editorComponent; |
| textField.getDocument().addDocumentListener(new DocumentListener() { |
| public void changedUpdate(DocumentEvent e) { |
| updateModel(textField.getText()); |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| updateModel(textField.getText()); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| updateModel(textField.getText()); |
| } |
| |
| private void updateModel(String text) { |
| int row = columnMappingTable.getEditingRow(); |
| int column = columnMappingTable.getEditingColumn(); |
| columnMappingTableModel.setValueAt(text, row, column); |
| |
| ArrayNode columnNames = newConfiguration.arrayNode(); |
| Map<String, String> columnToPortMapping = columnMappingTableModel.getColumnToPortMapping(); |
| for (Entry<String,String> entry : columnToPortMapping.entrySet()) { |
| columnNames.add(newConfiguration.objectNode().put("column", entry.getKey()).put("port", entry.getValue())); |
| } |
| newConfiguration.put("columnNames", columnNames); |
| validatePortNames(); |
| } |
| |
| }); |
| } |
| } |
| |
| columnMappingTable.setModel(columnMappingTableModel); |
| |
| // output format |
| outputFormatLabel = new JLabel(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.outputFormatSectionLabel")); |
| |
| outputFormatMultiplePort = new JRadioButton(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.multiplePortOption")); |
| outputFormatSinglePort = new JRadioButton(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.singlePortOption")); |
| outputFormatMultiplePort.setFocusable(false); |
| outputFormatSinglePort.setFocusable(false); |
| |
| outputFormatDelimiterLabel = new JLabel(SpreadsheetImportUIText |
| .getString("SpreadsheetImportConfigView.userDefinedCsvDelimiter")); |
| outputFormatDelimiter = new JTextField(newConfiguration.get("csvDelimiter").textValue(), 5); |
| |
| outputFormatButtonGroup = new ButtonGroup(); |
| outputFormatButtonGroup.add(outputFormatMultiplePort); |
| outputFormatButtonGroup.add(outputFormatSinglePort); |
| |
| if (newConfiguration.get("outputFormat").textValue().equals("PORT_PER_COLUMN")) { |
| outputFormatMultiplePort.setSelected(true); |
| outputFormatDelimiterLabel.setEnabled(false); |
| outputFormatDelimiter.setEnabled(false); |
| } else { |
| outputFormatSinglePort.setSelected(true); |
| columnMappingLabel.setEnabled(false); |
| enableTable(columnMappingTable, false); |
| } |
| |
| outputFormatMultiplePort.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| outputFormatDelimiterLabel.setEnabled(false); |
| outputFormatDelimiter.setEnabled(false); |
| columnMappingLabel.setEnabled(true); |
| enableTable(columnMappingTable, true); |
| newConfiguration.put("outputFormat", "PORT_PER_COLUMN"); |
| } |
| }); |
| outputFormatSinglePort.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| outputFormatDelimiterLabel.setEnabled(true); |
| outputFormatDelimiter.setEnabled(true); |
| columnMappingLabel.setEnabled(false); |
| enableTable(columnMappingTable, false); |
| newConfiguration.put("outputFormat", "SINGLE_PORT"); |
| } |
| |
| }); |
| outputFormatDelimiter.getDocument().addDocumentListener(new DocumentListener() { |
| public void changedUpdate(DocumentEvent e) { |
| handleUpdate(); |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| handleUpdate(); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| handleUpdate(); |
| } |
| |
| private void handleUpdate() { |
| String text = null; |
| try { |
| text = StringEscapeUtils.unescapeJava(outputFormatDelimiter.getText()); |
| } catch (RuntimeException re) {} |
| if (text == null || text.length() == 0) { |
| newConfiguration.put("csvDelimiter", ","); |
| } else { |
| newConfiguration.put("csvDelimiter", text.substring(0, 1)); |
| } |
| } |
| |
| }); |
| |
| // buttons |
| nextButton = new JButton(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.nextButton")); |
| nextButton.setFocusable(false); |
| nextButton.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| backButton.setVisible(true); |
| nextButton.setVisible(false); |
| cardLayout.last(contentPanel); |
| } |
| }); |
| |
| backButton = new JButton(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.backButton")); |
| backButton.setFocusable(false); |
| backButton.setVisible(false); |
| backButton.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| nextButton.setVisible(true); |
| backButton.setVisible(false); |
| cardLayout.first(contentPanel); |
| } |
| }); |
| |
| buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); |
| addDivider(buttonPanel, SwingConstants.TOP, true); |
| |
| removeAll(); |
| layoutPanel(); |
| } |
| |
| @Override |
| public void noteConfiguration() { |
| setJson(newConfiguration); |
| configureInputPorts(serviceRegistry); |
| configureOutputPorts(serviceRegistry); |
| } |
| |
| @Override |
| public boolean checkValues() { |
| return errorMessages.isEmpty(); |
| } |
| |
| private void layoutPanel() { |
| setPreferredSize(new Dimension(450, 400)); |
| setLayout(new BorderLayout()); |
| |
| page1 = new JPanel(new GridBagLayout()); |
| page2 = new JPanel(new GridBagLayout()); |
| |
| contentPanel = new JPanel(cardLayout); |
| contentPanel.add(page1, "page1"); |
| contentPanel.add(page2, "page2"); |
| add(contentPanel, BorderLayout.CENTER); |
| |
| // title |
| titlePanel.setBorder(new CompoundBorder(titlePanel.getBorder(), new EmptyBorder(10, 10, 0, 10))); |
| add(titlePanel, BorderLayout.NORTH); |
| titlePanel.add(titleLabel, BorderLayout.NORTH); |
| titlePanel.add(titleIcon, BorderLayout.WEST); |
| titlePanel.add(titleMessage, BorderLayout.CENTER); |
| |
| GridBagConstraints c = new GridBagConstraints(); |
| c.anchor = GridBagConstraints.WEST; |
| c.fill = GridBagConstraints.HORIZONTAL; |
| c.weightx = 1; |
| c.gridx = 0; |
| c.gridwidth = GridBagConstraints.REMAINDER; |
| |
| // column range |
| c.insets = new Insets(10, 10, 0, 10); |
| page1.add(columnLabel, c); |
| |
| c.insets = new Insets(10, 25, 0, 0); |
| c.gridwidth = 1; |
| c.weightx = 0; |
| page1.add(new JLabel(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.from")), c); |
| c.insets = new Insets(10, 0, 0, 0); |
| c.gridx = 1; |
| page1.add(columnFromValue, c); |
| c.gridx = 2; |
| page1.add(new JLabel(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.to")), c); |
| c.gridx = 3; |
| page1.add(columnToValue, c); |
| |
| c.gridx = 0; |
| c.weightx = 1; |
| c.insets = new Insets(10, 10, 0, 10); |
| c.gridwidth = GridBagConstraints.REMAINDER; |
| |
| // row range |
| page1.add(rowLabel, c); |
| |
| c.insets = new Insets(10, 25, 0, 0); |
| c.gridwidth = 1; |
| c.gridx = 0; |
| c.weightx = 0; |
| page1.add(new JLabel(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.from")), c); |
| c.insets = new Insets(10, 0, 0, 0); |
| c.gridx = 1; |
| page1.add(rowFromValue, c); |
| c.gridx = 2; |
| page1.add(new JLabel(SpreadsheetImportUIText.getString("SpreadsheetImportConfigView.to")), c); |
| c.gridx = 3; |
| page1.add(rowToValue, c); |
| c.gridx = 4; |
| page1.add(rowSelectAllOption, c); |
| c.gridx = 5; |
| c.gridwidth = GridBagConstraints.REMAINDER; |
| c.insets = new Insets(10, 0, 0, 10); |
| page1.add(rowExcludeFirstOption, c); |
| c.insets = new Insets(10, 25, 0, 0); |
| c.gridx = 0; |
| page1.add(rowIgnoreBlankRows, c); |
| |
| c.gridx = 0; |
| |
| // empty cells |
| c.insets = new Insets(10, 10, 10, 10); |
| page1.add(emptyCellLabel, c); |
| |
| c.insets = new Insets(0, 25, 0, 10); |
| page1.add(emptyCellEmptyStringOption, c); |
| JPanel userDefinedPanel = new JPanel(new BorderLayout()); |
| userDefinedPanel.add(emptyCellUserDefinedOption, BorderLayout.WEST); |
| userDefinedPanel.add(emptyCellUserDefinedValue, BorderLayout.CENTER); |
| page1.add(userDefinedPanel, c); |
| c.weighty = 1; |
| c.anchor = GridBagConstraints.NORTHWEST; |
| page1.add(emptyCellErrorValueOption, c); |
| |
| // output format |
| c.insets = new Insets(10, 10, 10, 10); |
| c.weighty = 0; |
| c.weightx = 1; |
| page2.add(outputFormatLabel, c); |
| |
| c.insets = new Insets(0, 25, 0, 10); |
| page2.add(outputFormatMultiplePort, c); |
| page2.add(outputFormatSinglePort, c); |
| |
| c.insets = new Insets(0, 50, 0, 10); |
| JPanel outputFormatDelimiterPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); |
| outputFormatDelimiterPanel.add(outputFormatDelimiterLabel); |
| outputFormatDelimiterPanel.add(outputFormatDelimiter); |
| page2.add(outputFormatDelimiterPanel, c); |
| |
| // column mapping |
| c.insets = new Insets(10, 10, 0, 10); |
| page2.add(columnMappingLabel, c); |
| |
| c.insets = new Insets(10, 10, 10, 10); |
| c.fill = GridBagConstraints.BOTH; |
| c.weighty = 1; |
| page2.add(new JScrollPane(columnMappingTable), c); |
| |
| buttonPanel.add(backButton); |
| buttonPanel.add(nextButton); |
| add(buttonPanel, BorderLayout.SOUTH); |
| } |
| |
| /** |
| * Displays the message with no icon. |
| * |
| * @param message |
| * the message to display |
| */ |
| public void setMessage(String message) { |
| titleIcon.setIcon(null); |
| titleMessage.setText(message); |
| } |
| |
| /** |
| * Adds the message to the top of the warning message stack. If the message is already in the |
| * stack it is moved to the top. If there are no error messages the message is displayed. |
| * |
| * @param message |
| * the warning message to add |
| */ |
| public void addWarningMessage(String message) { |
| if (warningMessages.contains(message)) { |
| warningMessages.remove(message); |
| } |
| warningMessages.push(message); |
| if (errorMessages.isEmpty()) { |
| setWarningMessage(message); |
| } |
| } |
| |
| /** |
| * Removes the message from the warning message stack. If there are no error messages the next |
| * warning message is displayed. If there are no warning messages the default message is |
| * displayed. |
| * |
| * @param message |
| * the warning message to remove |
| */ |
| public void removeWarningMessage(String message) { |
| warningMessages.remove(message); |
| if (errorMessages.isEmpty()) { |
| if (warningMessages.isEmpty()) { |
| setMessage(DEFAULT_MESSAGE); |
| } else { |
| setWarningMessage(warningMessages.peek()); |
| } |
| } |
| } |
| |
| /** |
| * Displays the message and a warning icon. |
| * |
| * @param message |
| * the warning message to display |
| */ |
| public void setWarningMessage(String message) { |
| titleIcon.setIcon(Icons.warningIcon); |
| titleMessage.setText(message); |
| } |
| |
| /** |
| * Adds the message to the top of the error message stack. If the message is already in the |
| * stack it is moved to the top. The message is then displayed. |
| * |
| * @param message |
| * the error message to add |
| */ |
| public void addErrorMessage(String message) { |
| if (errorMessages.contains(message)) { |
| errorMessages.remove(message); |
| } |
| errorMessages.push(message); |
| setErrorMessage(message); |
| } |
| |
| /** |
| * Removes the message from the error message stack and displays the next error message. If |
| * there are no error messages the next warning message is displayed. If there are no warning |
| * messages the default message is displayed. |
| * |
| * @param message |
| * the error message to remove |
| */ |
| public void removeErrorMessage(String message) { |
| errorMessages.remove(message); |
| if (errorMessages.isEmpty()) { |
| if (warningMessages.isEmpty()) { |
| setMessage(DEFAULT_MESSAGE); |
| } else { |
| setWarningMessage(warningMessages.peek()); |
| } |
| } else { |
| setErrorMessage(errorMessages.peek()); |
| } |
| } |
| |
| /** |
| * Displays the message and an error icon. |
| * |
| * @param message |
| * the error message to display |
| */ |
| public void setErrorMessage(String message) { |
| titleIcon.setIcon(Icons.severeIcon); |
| titleMessage.setText(message); |
| } |
| |
| protected boolean validatePortNames() { |
| boolean isValid = true; |
| Range columnRange = SpreadsheetUtils.getRange(newConfiguration.get("columnRange")); |
| Map<String, String> mapping = new HashMap<>(); |
| if (newConfiguration.has("columnNames")) { |
| for (JsonNode columnName : newConfiguration.get("columnNames")) { |
| mapping.put(columnName.get("column").textValue(), columnName.get("port").textValue()); |
| } |
| } |
| Set<String> usedNames = new HashSet<String>(); |
| for (Entry<String, String> entry : mapping.entrySet()) { |
| if (columnRange.contains(SpreadsheetUtils.getColumnIndex(entry.getKey()))) { |
| String portName = entry.getValue(); |
| if (!usedNames.add(portName)) { |
| isValid = false; |
| break; |
| } |
| if (portName.matches("[A-Z]+")) { |
| if (!mapping.containsKey(portName)) { |
| int columnIndex = SpreadsheetUtils.getColumnIndex(portName); |
| if (columnRange.contains(columnIndex)) { |
| isValid = false; |
| break; |
| } |
| } |
| } |
| } |
| } |
| if (isValid) { |
| removeErrorMessage(DUPLICATE_PORT_NAME_ERROR_MESSAGE); |
| } else { |
| addErrorMessage(DUPLICATE_PORT_NAME_ERROR_MESSAGE); |
| } |
| return isValid; |
| } |
| |
| protected boolean checkRowRange(String from, String to) { |
| boolean result = false; |
| try { |
| int fromRow = Integer.parseInt(from); |
| int toRow = Integer.parseInt(to); |
| if (toRow < fromRow) { |
| addErrorMessage(INCONSISTENT_ROW_MESSAGE); |
| } else { |
| removeErrorMessage(INCONSISTENT_ROW_MESSAGE); |
| result = true; |
| } |
| } catch (NumberFormatException e) { |
| logger.warn("Problem checking row range", e); |
| } |
| return result; |
| } |
| |
| protected boolean checkColumnRange(int fromColumn, int toColumn) { |
| boolean result = false; |
| if (toColumn < fromColumn) { |
| addErrorMessage(INCONSISTENT_COLUMN_MESSAGE); |
| } else { |
| removeErrorMessage(INCONSISTENT_COLUMN_MESSAGE); |
| result = true; |
| } |
| return result; |
| } |
| |
| /** |
| * Adds a light gray or etched border to the top or bottom of a JComponent. |
| * |
| * @param component |
| */ |
| protected void addDivider(JComponent component, final int position, final boolean etched) { |
| component.setBorder(new Border() { |
| private final Color borderColor = new Color(.6f, .6f, .6f); |
| |
| public Insets getBorderInsets(Component c) { |
| if (position == SwingConstants.TOP) { |
| return new Insets(5, 0, 0, 0); |
| } else { |
| return new Insets(0, 0, 5, 0); |
| } |
| } |
| |
| public boolean isBorderOpaque() { |
| return false; |
| } |
| |
| public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { |
| if (position == SwingConstants.TOP) { |
| if (etched) { |
| g.setColor(borderColor); |
| g.drawLine(x, y, x + width, y); |
| g.setColor(Color.WHITE); |
| g.drawLine(x, y + 1, x + width, y + 1); |
| } else { |
| g.setColor(Color.LIGHT_GRAY); |
| g.drawLine(x, y, x + width, y); |
| } |
| } else { |
| if (etched) { |
| g.setColor(borderColor); |
| g.drawLine(x, y + height - 2, x + width, y + height - 2); |
| g.setColor(Color.WHITE); |
| g.drawLine(x, y + height - 1, x + width, y + height - 1); |
| } else { |
| g.setColor(Color.LIGHT_GRAY); |
| g.drawLine(x, y + height - 1, x + width, y + height - 1); |
| } |
| } |
| } |
| |
| }); |
| } |
| |
| private void enableTable(JTable table, boolean enabled) { |
| table.setEnabled(enabled); |
| Component editor = table.getEditorComponent(); |
| if (editor != null) { |
| editor.setEnabled(enabled); |
| } |
| if (enabled) { |
| table.setForeground(Color.BLACK); |
| table.getTableHeader().setForeground(Color.BLACK); |
| } else { |
| table.setForeground(Color.LIGHT_GRAY); |
| table.getTableHeader().setForeground(Color.LIGHT_GRAY); |
| } |
| } |
| |
| static class UpperCaseDocument extends PlainDocument { |
| @Override |
| public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException { |
| if (text.matches("[A-Za-z]+")) { |
| text = text.toUpperCase(); |
| super.replace(offset, length, text, attrs); |
| } |
| } |
| } |
| |
| static class NumericDocument extends PlainDocument { |
| @Override |
| public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException { |
| if (text.length() == 0 || text.matches("[0-9]+")) { |
| text = text.toUpperCase(); |
| super.replace(offset, length, text, attrs); |
| } |
| } |
| } |
| |
| /** |
| * Main method for testing the panel. |
| * |
| * @param args |
| * @throws ActivityConfigurationException |
| */ |
| // public static void main(String[] args) throws ActivityConfigurationException { |
| // final JFrame frame = new JFrame(); |
| // SpreadsheetImportActivity activity = new SpreadsheetImportActivity(); |
| // activity.configure(new SpreadsheetImportConfiguration()); |
| // final SpreadsheetImportConfigView config = new SpreadsheetImportConfigView(activity); |
| // config.setOkAction(new AbstractAction("Finish") { |
| // public void actionPerformed(ActionEvent arg0) { |
| // Range columnRange = config.getConfiguration().getColumnRange(); |
| // String fromColumn = SpreadsheetUtils.getColumnLabel(columnRange.getStart()); |
| // String toColumn = SpreadsheetUtils.getColumnLabel(columnRange.getEnd()); |
| // System.out.printf("%s (%s) - %s (%s)", fromColumn, columnRange.getStart(), |
| // toColumn, columnRange.getEnd()); |
| // frame.setVisible(false); |
| // frame.dispose(); |
| // } |
| // }); |
| // config.setCancelAction(new AbstractAction("Cancel") { |
| // public void actionPerformed(ActionEvent arg0) { |
| // frame.setVisible(false); |
| // frame.dispose(); |
| // } |
| // }); |
| // frame.add(config); |
| // frame.pack(); |
| // frame.setVisible(true); |
| // } |
| |
| } |