/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2013 ZAP development team
*
* 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.zaproxy.zap.view;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileFilter;
import org.apache.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.extension.AbstractDialog;
import org.parosproxy.paros.model.SiteNode;
import org.parosproxy.paros.view.View;
import org.zaproxy.zap.extension.help.ExtensionHelp;
import org.zaproxy.zap.model.Context;
import org.zaproxy.zap.model.Target;
import org.zaproxy.zap.utils.ZapNumberSpinner;
import org.zaproxy.zap.utils.ZapTextArea;
import org.zaproxy.zap.utils.ZapTextField;
import org.zaproxy.zap.view.widgets.ContextSelectComboBox;
/**
* An abstract class which allows simple 'Field = Value' dialogs to be created with
* the minimal amount of 'boiler plate' code.
* @author psiinon
*
*/
public abstract class StandardFieldsDialog extends AbstractDialog {
private static final Logger logger = Logger.getLogger(StandardFieldsDialog.class);
private static final long serialVersionUID = 1L;
private static final EmptyBorder FULL_BORDER = new EmptyBorder(8, 8, 8, 8);
private static final EmptyBorder TOP_BOTTOM_BORDER = new EmptyBorder(8, 0, 8, 0);
private JPanel mainPanel = null;
private List<JPanel> tabPanels = null;
private List<Integer> tabOffsets = null;
private JTabbedPane tabbedPane = null;
private double labelWeight = 0;
private double fieldWeight = 1.0D;
private JButton helpButton = null;
private JButton cancelButton = null;
private JButton saveButton = null;
private List<Component> fieldList = new ArrayList<>();
private Map<String, Component> fieldMap = new HashMap<> ();
private Map<String, JPanel> tabNameMap = new HashMap<String, JPanel>();
/**
* Flag that indicates whether or not the dialogue is automatically hidden when {@link #save() saved}.
*
* @see #isHideOnSave()
*/
private boolean hideOnSave;
/**
* Constructs a {@code StandardFieldsDialog} with the given owner, title and dimensions.
*
* @param owner the owner of the dialogue
* @param titleLabel the title of the dialogue
* @param dim the dimensions of the dialogue
*/
public StandardFieldsDialog(Frame owner, String titleLabel, Dimension dim) {
this((Window)owner, titleLabel, dim);
}
/**
* Constructs a {@code StandardFieldsDialog} with the given owner, title, dimensions and whether or not it's modal.
*
* @param owner the owner of the dialogue
* @param titleLabel the title of the dialogue
* @param dim the dimensions of the dialogue
* @param modal {@code true} if the dialogue should be modal, {@code false} otherwise
*/
public StandardFieldsDialog(Window owner, String titleLabel, Dimension dim, boolean modal) {
this(owner, titleLabel, dim, null, modal);
}
/**
* Constructs a {@code StandardFieldsDialog} with the given owner, title and dimensions.
*
* @param owner the owner of the dialogue
* @param titleLabel the title of the dialogue
* @param dim the dimensions of the dialogue
*/
public StandardFieldsDialog(Window owner, String titleLabel, Dimension dim) {
this(owner, titleLabel, dim, null);
}
/**
* Constructs a {@code StandardFieldsDialog} with the given owner, title, dimensions and tab names.
*
* @param owner the owner of the dialogue
* @param titleLabel the title of the dialogue
* @param dim the dimensions of the dialogue
* @param tabLabels the names of the tabs
*/
public StandardFieldsDialog(Frame owner, String titleLabel, Dimension dim, String[] tabLabels) {
this((Window)owner, titleLabel, dim, tabLabels);
}
/**
* Constructs a {@code StandardFieldsDialog} with the given owner, title, dimensions and tab names.
*
* @param owner the owner of the dialogue
* @param titleLabel the title of the dialogue
* @param dim the dimensions of the dialogue
* @param tabLabels the names of the tabs
*/
public StandardFieldsDialog(Window owner, String titleLabel, Dimension dim, String[] tabLabels) {
this(owner, titleLabel, dim, tabLabels, false);
}
/**
* Constructs a {@code StandardFieldsDialog} with the given owner, title, dimensions, tab names and whether or not it's
* modal.
*
* @param owner the owner of the dialogue
* @param titleLabel the title of the dialogue
* @param dim the dimensions of the dialogue
* @param tabLabels the names of the tabs
* @param modal {@code true} if the dialogue should be modal, {@code false} otherwise
*/
public StandardFieldsDialog(Window owner, String titleLabel, Dimension dim, String[] tabLabels, boolean modal) {
super(owner, modal);
this.setTitle(Constant.messages.getString(titleLabel));
this.setXWeights(0.4D, 0.6D); // Looks a bit better..
this.initialize(dim, tabLabels);
this.hideOnSave = true;
}
/**
* Tells whether or not the dialogue is automatically hidden when {@link #save() saved}.
* <p>
* The default is {@code true}.
*
* @return {@code true} if the dialogue should be hidden, {@code false} otherwise.
* @since 2.6.0
* @see #setHideOnSave(boolean)
*/
protected boolean isHideOnSave() {
return hideOnSave;
}
/**
* Sets whether or not the dialogue is automatically hidden when {@link #save() saved}.
*
* @param hideOnSave {@code true} if the dialogue should be hidden, {@code false} otherwise.
* @since 2.6.0
* @see #isHideOnSave()
*/
protected void setHideOnSave(boolean hideOnSave) {
this.hideOnSave = hideOnSave;
}
private boolean isTabbed() {
return tabPanels != null;
}
private void initialize(Dimension dim, String[] tabLabels) {
this.setLayout(new GridBagLayout());
this.setSize(dim);
if (tabLabels == null) {
this.initializeSinglePane(dim);
} else {
this.initializeTabbed(dim, tabLabels);
}
// Handle escape key to close the dialog
KeyStroke escape = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
AbstractAction escapeAction = new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
if (hasCancelSaveButtons()) {
cancelPressed();
return;
}
savePressed();
}
};
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escape, "ESCAPE");
getRootPane().getActionMap().put("ESCAPE",escapeAction);
}
public void setXWeights(double labelWeight, double fieldWeight) {
this.labelWeight = labelWeight;
this.fieldWeight = fieldWeight;
}
private void initializeTabbed(Dimension dim, String[] tabLabels) {
this.tabPanels = new ArrayList<>();
this.tabOffsets = new ArrayList<>();
JPanel contentPanel = new JPanel();
contentPanel.setLayout(new GridBagLayout());
contentPanel.setBorder(TOP_BOTTOM_BORDER);
contentPanel.setPreferredSize(dim);
this.setContentPane(contentPanel);
tabbedPane = new JTabbedPane();
initContentPanel(contentPanel, tabbedPane, getExtraButtons(), getHelpIndex());
for (String label : tabLabels) {
JPanel tabPanel = new JPanel();
tabPanel.setLayout(new GridBagLayout());
tabPanel.setBorder(FULL_BORDER);
tabbedPane.addTab(Constant.messages.getString(label), tabPanel);
this.tabNameMap.put(label, tabPanel);
this.tabPanels.add(tabPanel);
this.tabOffsets.add(0);
}
}
private void initContentPanel(JPanel contentPanel, JComponent component, JButton[] extraButtons, String helpIndex) {
if (extraButtons == null) {
contentPanel.add(component, LayoutHelper.getGBC(0, 0, 4, 1.0D, 1.0D));
if (helpIndex != null) {
contentPanel.add(getHelpButton(helpIndex), LayoutHelper.getGBC(0, 1, 1, 0.0D));
}
contentPanel.add(new JLabel(), LayoutHelper.getGBC(1, 1, 1, 1.0D)); // spacer
if (hasCancelSaveButtons()) {
contentPanel.add(getCancelButton(), LayoutHelper.getGBC(2, 1, 1, 0.0D));
}
contentPanel.add(getSaveButton(), LayoutHelper.getGBC(3, 1, 1, 0.0D));
} else {
contentPanel.add(component, LayoutHelper.getGBC(0, 0, 4 + extraButtons.length, 1.0D, 1.0D));
if (helpIndex != null) {
contentPanel.add(getHelpButton(helpIndex), LayoutHelper.getGBC(0, 1, 1, 0.0D));
}
contentPanel.add(new JLabel(), LayoutHelper.getGBC(1, 1, 1, 1.0D)); // spacer
if (hasCancelSaveButtons()) {
contentPanel.add(getCancelButton(), LayoutHelper.getGBC(2, 1, 1, 0.0D));
}
int x=3;
for (JButton button : extraButtons) {
contentPanel.add(button, LayoutHelper.getGBC(x, 1, 1, 0.0D));
x++;
}
contentPanel.add(getSaveButton(), LayoutHelper.getGBC(x, 1, 1, 0.0D));
}
}
/*
* Always returns true, meaning that by default the dialog will have Cancel and Save buttons.
* Override to return false for one Close button instead - the save() method will still be called
*/
public boolean hasCancelSaveButtons() {
return true;
}
/*
* Always returns null, meaning there is no associated help page.
* Change to return the help index for a help button to be added to the dialog.
*/
public String getHelpIndex() {
return null;
}
private void initializeSinglePane(Dimension dim) {
JPanel contentPanel = new JPanel();
contentPanel.setLayout(new GridBagLayout());
contentPanel.setBorder(FULL_BORDER);
contentPanel.setPreferredSize(dim);
this.setContentPane(contentPanel);
initContentPanel(contentPanel, getMainPanel(), getExtraButtons(), getHelpIndex());
}
public String getSaveButtonText() {
if (hasCancelSaveButtons()) {
return Constant.messages.getString("all.button.save");
}
return Constant.messages.getString("all.button.close");
}
/**
* Override if you need to add extra buttons inbetween the Cancel and Save ones
* @return an array with the extra buttons, or {@code null} if none needed.
*/
public JButton[] getExtraButtons () {
return null;
}
private JButton getSaveButton() {
if (saveButton == null) {
saveButton = new JButton();
saveButton.setText(this.getSaveButtonText());
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
savePressed();
}
});
}
return saveButton;
}
private void savePressed() {
if (!validateFieldsCustomMessage()) {
return;
}
String errorMsg = validateFields();
if (errorMsg != null) {
View.getSingleton().showWarningDialog(this, errorMsg);
return;
}
save();
if (isHideOnSave()) {
setVisible(false);
}
}
/**
* Called when the dialogue is saved, allowing to validate the fields and show custom error messages (as opposed to
* validations using the method {@code validateFields()}, which only allows to show a simple message). If this method
* returns {@code false} no further action is taken, if it returns {@code true} the normal validation is performed by
* calling {@code validateFields()}.
* <p>
* By default returns {@code true}.
*
* @return {@code true} if the fields are valid, {@code false} otherwise.
* @see #validateFields()
* @see #save()
* @since 2.4.0
*/
protected boolean validateFieldsCustomMessage() {
return true;
}
public String getCancelButtonText() {
return Constant.messages.getString("all.button.cancel");
}
/**
* Gets called when the cancel button is pressed - override to do anything other than just close the window
*/
public void cancelPressed() {
setVisible(false);
}
private JButton getCancelButton() {
if (cancelButton == null) {
cancelButton = new JButton();
cancelButton.setText(this.getCancelButtonText());
cancelButton.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
cancelPressed();
}
});
}
return cancelButton;
}
private JButton getHelpButton(final String helpIndex) {
if (helpButton == null) {
helpButton = new JButton();
helpButton.setIcon(ExtensionHelp.HELP_ICON);
helpButton.setToolTipText(Constant.messages.getString("help.dialog.button.tooltip"));
helpButton.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
ExtensionHelp.showHelp(helpIndex);
}
});
}
return helpButton;
}
private JPanel getMainPanel() {
if (mainPanel == null) {
mainPanel = new JPanel();
mainPanel.setLayout(new GridBagLayout());
}
return mainPanel;
}
private void addPadding(JPanel panel, int indexy) {
panel.add(new JLabel(""),
LayoutHelper.getGBC(0, indexy, 1, 0.0D, 1.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
}
public void addPadding() {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
this.addPadding(this.getMainPanel(), this.fieldList.size());
}
private void incTabOffset(int tabIndex) {
int next = this.tabOffsets.get(tabIndex)+1;
this.tabOffsets.remove(tabIndex);
this.tabOffsets.add(tabIndex, next);
}
public void addPadding(int tabIndex) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
this.addPadding(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex));
incTabOffset(tabIndex);
}
private void addField(JPanel panel, int indexy, String fieldLabel, Component field, Component wrapper, double weighty) {
if (this.fieldList.contains(field)) {
throw new IllegalArgumentException("Field already added: " + field);
}
JLabel label = new JLabel(Constant.messages.getString(fieldLabel));
label.setLabelFor(field);
label.setVerticalAlignment(JLabel.TOP);
panel.add(label,
LayoutHelper.getGBC(0, indexy, 1, labelWeight, weighty, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
panel.add(wrapper,
LayoutHelper.getGBC(1, indexy, 1, fieldWeight, weighty, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.fieldList.add(field);
this.fieldMap.put(fieldLabel, field);
if (indexy == 0 && panel.equals(this.getMainPanel())) {
// First field, always grab focus
field.requestFocusInWindow();
}
}
private void addField(String fieldLabel, Component field, Component wrapper, double weighty) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
this.addField(this.getMainPanel(), this.fieldList.size(), fieldLabel, field, wrapper, weighty);
}
public void addTextField(String fieldLabel, String value) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
ZapTextField field = new ZapTextField();
if (value != null) {
field.setText(value);
}
this.addField(fieldLabel, field, field, 0.0D);
}
public void addTextField(int tabIndex, String fieldLabel, String value) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
ZapTextField field = new ZapTextField();
if (value != null) {
field.setText(value);
}
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
incTabOffset(tabIndex);
}
/**
* Adds a {@link JPasswordField} field, with the given label and, optionally, the given value.
*
* @param fieldLabel the label of the field
* @param value the value of the field, might be {@code null}
* @throws IllegalArgumentException if the dialogue is a tabbed dialogue
* @since 2.6.0
* @see #addPasswordField(int, String, String)
* @see #getPasswordValue(String)
*/
public void addPasswordField(String fieldLabel, String value) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JPasswordField field = new JPasswordField();
if (value != null) {
field.setText(value);
}
this.addField(fieldLabel, field, field, 0.0D);
}
/**
* Adds a {@link JPasswordField} field to the tab with the given index, with the given label and, optionally, the given
* value.
*
* @param tabIndex the index of the tab
* @param fieldLabel the label of the field
* @param value the value of the field, might be {@code null}
* @throws IllegalArgumentException if the dialogue is not a tabbed dialogue or if the index does not correspond to an
* existing tab
* @since 2.6.0
* @see #addPasswordField(String, String)
* @see #getPasswordValue(String)
*/
public void addPasswordField(int tabIndex, String fieldLabel, String value) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
JPasswordField field = new JPasswordField();
if (value != null) {
field.setText(value);
}
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
incTabOffset(tabIndex);
}
public void addMultilineField(String fieldLabel, String value) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
ZapTextArea field = new ZapTextArea();
field.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setViewportView(field);
if (value != null) {
field.setText(value);
}
this.addField(fieldLabel, field, scrollPane, 1.0D);
}
public void addMultilineField(int tabIndex, String fieldLabel, String value) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
ZapTextArea field = new ZapTextArea();
field.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setViewportView(field);
if (value != null) {
field.setText(value);
}
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, scrollPane, 1.0D);
this.incTabOffset(tabIndex);
}
public void addComboField(String fieldLabel, String[] choices, String value) {
this.addComboField(fieldLabel, choices, value, false);
}
public void addComboField(String fieldLabel, String[] choices, String value, boolean editable) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JComboBox<String> field = new JComboBox<>();
field.setEditable(editable);
for (String label : choices) {
field.addItem(label);
}
if (value != null) {
field.setSelectedItem(value);
}
this.addField(fieldLabel, field, field, 0.0D);
}
public void addComboField(String fieldLabel, List<String> choices, String value) {
this.addComboField(fieldLabel, choices, value, false);
}
public void addComboField(String fieldLabel, List<String> choices, String value, boolean editable) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JComboBox<String> field = new JComboBox<>();
field.setEditable(editable);
for (String label : choices) {
field.addItem(label);
}
if (value != null) {
field.setSelectedItem(value);
}
this.addField(fieldLabel, field, field, 0.0D);
}
public void addComboField(int tabIndex, String fieldLabel, String[] choices, String value) {
this.addComboField(tabIndex, fieldLabel, choices, value, false);
}
public void addComboField(int tabIndex, String fieldLabel, String[] choices, String value, boolean editable) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
JComboBox<String> field = new JComboBox<>();
field.setEditable(editable);
for (String label : choices) {
field.addItem(label);
}
if (value != null) {
field.setSelectedItem(value);
}
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
this.incTabOffset(tabIndex);
}
public void addComboField(int tabIndex, String fieldLabel, List<String> choices, String value) {
this.addComboField(tabIndex, fieldLabel, choices, value, false);
}
public void addComboField(int tabIndex, String fieldLabel, List<String> choices, String value, boolean editable) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
JComboBox<String> field = new JComboBox<>();
field.setEditable(editable);
for (String label : choices) {
field.addItem(label);
}
if (value != null) {
field.setSelectedItem(value);
}
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
this.incTabOffset(tabIndex);
}
public void addComboField(String fieldLabel, int[] choices, int value) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JComboBox<Integer> field = new JComboBox<>();
for (int label : choices) {
field.addItem(label);
}
if (value >= 0) {
field.setSelectedItem(value);
}
this.addField(fieldLabel, field, field, 0.0D);
}
/**
* Adds a combo box field with the given label and model, to the tab with the given index.
* <p>
* Control of selection state (i.e. set/get selected item) is done through the combo box model.
*
* @param <E> the type of the elements of the combo box model.
* @param tabIndex the index of the tab where the combo box should be added.
* @param fieldLabel the name of the label of the combo box field.
* @param comboBoxModel the model to set into the combo box.
* @since 2.6.0
* @throws IllegalArgumentException if any of the following conditions is true:
* <ul>
* <li>the dialogue does not have tabs;</li>
* <li>the dialogue has tabs but the given tab index is not valid;</li>
* <li>a field with the given label already exists.</li>
* </ul>
* @see #addComboField(String, ComboBoxModel)
* @see #addComboField(int, String, ComboBoxModel, boolean)
* @see #setComboBoxModel(String, ComboBoxModel)
*/
public <E> void addComboField(int tabIndex, String fieldLabel, ComboBoxModel<E> comboBoxModel) {
addComboField(tabIndex, fieldLabel, comboBoxModel, false);
}
/**
* Adds a combo box field, possibly editable, with the given label and model, to the tab with the given index.
* <p>
* Control of selection state (i.e. set/get selected item) is done through the combo box model.
*
* @param <E> the type of the elements of the combo box model.
* @param tabIndex the index of the tab where the combo box should be added.
* @param fieldLabel the name of the label of the combo box field.
* @param comboBoxModel the model to set into the combo box.
* @param editable {@code true} if the combo box should be editable, {@code false} otherwise.
* @since 2.6.0
* @throws IllegalArgumentException if any of the following conditions is true:
* <ul>
* <li>the dialogue does not have tabs;</li>
* <li>the dialogue has tabs but the given tab index is not valid;</li>
* <li>a field with the given label already exists.</li>
* </ul>
* @see #addComboField(String, ComboBoxModel, boolean)
* @see #addComboField(int, String, ComboBoxModel)
* @see #setComboBoxModel(String, ComboBoxModel)
*/
public <E> void addComboField(int tabIndex, String fieldLabel, ComboBoxModel<E> comboBoxModel, boolean editable) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
JComboBox<E> field = new JComboBox<>(comboBoxModel);
field.setEditable(editable);
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
this.incTabOffset(tabIndex);
}
/**
* Adds a combo box field with the given label and model.
* <p>
* Control of selection state (i.e. set/get selected item) is done through the combo box model.
*
* @param <E> the type of the elements of the combo box model.
* @param fieldLabel the name of the label of the combo box field.
* @param comboBoxModel the model to set into the combo box.
* @throws IllegalArgumentException if any of the following conditions is true:
* <ul>
* <li>the dialogue has tabs;</li>
* <li>a field with the given label already exists.</li>
* </ul>
* @since 2.6.0
* @see #addComboField(String, ComboBoxModel, boolean)
* @see #addComboField(int, String, ComboBoxModel)
* @see #setComboBoxModel(String, ComboBoxModel)
*/
public <E> void addComboField(String fieldLabel, ComboBoxModel<E> comboBoxModel) {
addComboField(fieldLabel, comboBoxModel, false);
}
/**
* Adds a combo box field, possibly editable, with the given label and model.
* <p>
* Control of selection state (i.e. set/get selected item) is done through the combo box model.
*
* @param <E> the type of the elements of the combo box model.
* @param fieldLabel the name of the label of the combo box field.
* @param comboBoxModel the model to set into the combo box.
* @param editable {@code true} if the combo box should be editable, {@code false} otherwise.
* @throws IllegalArgumentException if any of the following conditions is true:
* <ul>
* <li>the dialogue has tabs;</li>
* <li>a field with the given label already exists.</li>
* </ul>
* @since 2.6.0
* @see #addComboField(String, ComboBoxModel)
* @see #addComboField(int, String, ComboBoxModel, boolean)
* @see #setComboBoxModel(String, ComboBoxModel)
*/
public <E> void addComboField(String fieldLabel, ComboBoxModel<E> comboBoxModel, boolean editable) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JComboBox<E> field = new JComboBox<>(comboBoxModel);
field.setEditable(editable);
this.addField(fieldLabel, field, field, 0.0D);
}
public void addTableField(String fieldLabel, JTable field) {
this.addTableField(fieldLabel, field, null);
}
public void addTableField(JTable field, List<JButton> buttons) {
this.addTableField(null, field, buttons);
}
/**
* Add a table field.
* @param fieldLabel If null then the table will be full width
* @param field the table field
* @param buttons if not null then the buttons will be added to the right of the table
*/
public void addTableField(String fieldLabel, JTable field, List<JButton> buttons) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JScrollPane scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setViewportView(field);
field.setFillsViewportHeight(true);
// Tables are a special case - they dont have labels and are accessed via the model
if (this.fieldList.contains(field)) {
throw new IllegalArgumentException("Field already added: " + field);
}
if (buttons == null || buttons.size() == 0) {
if (fieldLabel == null) {
this.getMainPanel().add(scrollPane,
LayoutHelper.getGBC(1, this.fieldList.size(), 1, fieldWeight, 1.0D,
GridBagConstraints.BOTH, new Insets(4,4,4,4)));
} else {
this.addField(fieldLabel, field, scrollPane, 1.0D);
}
} else {
JPanel tablePanel = new JPanel();
tablePanel.setLayout(new GridBagLayout());
tablePanel.add(scrollPane,
LayoutHelper.getGBC(0, 0, 1, 1.0D, 1.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridBagLayout());
int buttonId = 0;
for (JButton button : buttons) {
buttonPanel.add(button,
LayoutHelper.getGBC(0, buttonId++, 1, 0D, 0D, GridBagConstraints.BOTH, new Insets(2,2,2,2)));
}
// Add spacer to force buttons to the top
buttonPanel.add(new JLabel(),
LayoutHelper.getGBC(0, buttonId++, 1, 0D, 1.0D, GridBagConstraints.BOTH, new Insets(2,2,2,2)));
tablePanel.add(buttonPanel,
LayoutHelper.getGBC(1, 0, 1, 0D, 0D, GridBagConstraints.BOTH, new Insets(2,2,2,2)));
if (fieldLabel == null) {
this.getMainPanel().add(tablePanel,
LayoutHelper.getGBC(1, this.fieldList.size(), 1, fieldWeight, 1.0D,
GridBagConstraints.BOTH, new Insets(4,4,4,4)));
} else {
this.addField(fieldLabel, field, tablePanel, 1.0D);
}
}
this.fieldList.add(field);
}
public void addTableField(int tabIndex, JTable field) {
this.addTableField(tabIndex, field, null);
}
public void addTableField(int tabIndex, JTable field, List<JButton> buttons) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
JScrollPane scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setViewportView(field);
field.setFillsViewportHeight(true);
// Tables are a special case - they dont have labels and are accessed via the model
if (this.fieldList.contains(field)) {
throw new IllegalArgumentException("Field already added: " + field);
}
if (buttons == null || buttons.size() == 0) {
this.tabPanels.get(tabIndex).add(scrollPane,
LayoutHelper.getGBC(1, this.tabOffsets.get(tabIndex), 1, 1.0D, 1.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
} else {
JPanel tablePanel = new JPanel();
tablePanel.setLayout(new GridBagLayout());
tablePanel.add(scrollPane,
LayoutHelper.getGBC(0, 0, 1, 1.0D, 1.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridBagLayout());
int buttonId = 0;
for (JButton button : buttons) {
buttonPanel.add(button,
LayoutHelper.getGBC(0, buttonId++, 1, 0D, 0D, GridBagConstraints.BOTH, new Insets(2,2,2,2)));
}
// Add spacer to force buttons to the top
buttonPanel.add(new JLabel(),
LayoutHelper.getGBC(0, buttonId++, 1, 0D, 1.0D, GridBagConstraints.BOTH, new Insets(2,2,2,2)));
tablePanel.add(buttonPanel,
LayoutHelper.getGBC(1, 0, 1, 0D, 0D, GridBagConstraints.BOTH, new Insets(2,2,2,2)));
this.tabPanels.get(tabIndex).add(tablePanel,
LayoutHelper.getGBC(1, this.tabOffsets.get(tabIndex), 1, 1.0D, 1.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
}
this.fieldList.add(field);
this.incTabOffset(tabIndex);
}
public void setComboFields(String fieldLabel, String[] choices, String value) {
Component c = this.fieldMap.get(fieldLabel);
if (c instanceof JComboBox) {
@SuppressWarnings("unchecked")
JComboBox<String> comboBox = (JComboBox<String>)c;
comboBox.removeAllItems();
for (String str : choices) {
comboBox.addItem(str);
}
if (value != null) {
comboBox.setSelectedItem(value);
}
} else if (c == null) {
// Ignore - could be during init
logger.debug("No field for " + fieldLabel);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
public void setComboFields(String fieldLabel, List<String> choices, String value) {
Component c = this.fieldMap.get(fieldLabel);
if (c instanceof JComboBox) {
@SuppressWarnings("unchecked")
JComboBox<String> comboBox = (JComboBox<String>)c;
comboBox.removeAllItems();
for (String str : choices) {
comboBox.addItem(str);
}
if (value != null) {
comboBox.setSelectedItem(value);
}
} else if (c == null) {
// Ignore - could be during init
logger.debug("No field for " + fieldLabel);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
/**
* Sets the given combo box model into the combo box with the given label.
* <p>
* Control of selection state (i.e. set/get selected item) is done through the combo box model.
*
* @param <E> the type of the elements of the combo box model.
* @param fieldLabel the name of the label of the combo box field
* @param comboBoxModel the model to set into the combo box
* @since 2.6.0
* @see #addComboField(String, ComboBoxModel)
* @see #addComboField(int, String, ComboBoxModel)
*/
public <E> void setComboBoxModel(String fieldLabel, ComboBoxModel<E> comboBoxModel) {
Component c = this.fieldMap.get(fieldLabel);
if (c instanceof JComboBox) {
@SuppressWarnings("unchecked")
JComboBox<E> comboBox = (JComboBox<E>) c;
comboBox.setModel(comboBoxModel);
} else if (c == null) {
// Ignore - could be during init
logger.debug("No field for " + fieldLabel);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
public void addNumberField(String fieldLabel, Integer min, Integer max, int value) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
ZapNumberSpinner field = new ZapNumberSpinner(min, value, max);
this.addField(fieldLabel, field, field, 0.0D);
}
public void addNumberField(int tabIndex, String fieldLabel, Integer min, Integer max, int value) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
ZapNumberSpinner field = new ZapNumberSpinner(min, value, max);
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
this.incTabOffset(tabIndex);
}
public void addCheckBoxField(String fieldLabel, boolean value) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JCheckBox field = new JCheckBox();
field.setSelected(value);
this.addField(fieldLabel, field, field, 0.0D);
}
public void addCheckBoxField(int tabIndex, String fieldLabel, boolean value) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
JCheckBox field = new JCheckBox();
field.setSelected(value);
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
this.incTabOffset(tabIndex);
}
/*
* Add a 'node select' field which provides a button for showing a Node Select Dialog and a
* non editable field for showing the node selected
*/
public void addNodeSelectField(final String fieldLabel, final SiteNode value,
final boolean editable, final boolean allowRoot) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
final ZapTextField text = new ZapTextField();
text.setEditable(editable);
if (value != null) {
text.setText(getNodeText(value));
}
JButton selectButton = new JButton(Constant.messages.getString("all.button.select"));
selectButton.setIcon(new ImageIcon(View.class.getResource("/resource/icon/16/094.png"))); // Globe icon
selectButton.addActionListener(new java.awt.event.ActionListener() {
// Keep a local copy so that we can always select the last node chosen
SiteNode node = value;
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
NodeSelectDialog nsd = new NodeSelectDialog(StandardFieldsDialog.this);
nsd.setAllowRoot(allowRoot);
SiteNode node = nsd.showDialog(this.node);
if (node != null) {
text.setText(getNodeText(node));
this.node = node;
siteNodeSelected(fieldLabel, node);
}
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.add(text, LayoutHelper.getGBC(0, 0, 1, 1.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
panel.add(selectButton, LayoutHelper.getGBC(1, 0, 1, 0.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.addField(fieldLabel, text, panel, 0.0D);
}
/*
* Add a 'node select' field which provides a button for showing a Node Select Dialog and a
* non editable field for showing the node selected
*/
public void addNodeSelectField(int tabIndex, final String fieldLabel, final SiteNode value,
final boolean editable, final boolean allowRoot) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
final ZapTextField text = new ZapTextField();
text.setEditable(editable);
if (value != null) {
text.setText(getNodeText(value));
}
JButton selectButton = new JButton(Constant.messages.getString("all.button.select"));
selectButton.setIcon(new ImageIcon(View.class.getResource("/resource/icon/16/094.png"))); // Globe icon
selectButton.addActionListener(new java.awt.event.ActionListener() {
// Keep a local copy so that we can always select the last node chosen
SiteNode node = value;
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
NodeSelectDialog nsd = new NodeSelectDialog(StandardFieldsDialog.this);
nsd.setAllowRoot(allowRoot);
SiteNode node = nsd.showDialog(this.node);
if (node != null) {
text.setText(getNodeText(node));
this.node = node;
siteNodeSelected(fieldLabel, node);
}
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.add(text, LayoutHelper.getGBC(0, 0, 1, 1.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
panel.add(selectButton, LayoutHelper.getGBC(1, 0, 1, 0.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, text, panel, 0.0D);
this.incTabOffset(tabIndex);
}
/*
* Add a 'node select' field which provides a button for showing a Node Select Dialog and a
* non editable field for showing the node selected
*/
public void addTargetSelectField(int tabIndex, final String fieldLabel, final Target value,
final boolean editable, final boolean allowRoot) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
final ZapTextField text = new ZapTextField();
text.setEditable(editable);
this.setTextTarget(text, value);
JButton selectButton = new JButton(Constant.messages.getString("all.button.select"));
selectButton.setIcon(new ImageIcon(View.class.getResource("/resource/icon/16/094.png"))); // Globe icon
selectButton.addActionListener(new java.awt.event.ActionListener() {
// Keep a local copy so that we can always select the last node chosen
Target target = value;
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
NodeSelectDialog nsd = new NodeSelectDialog(StandardFieldsDialog.this);
nsd.setAllowRoot(allowRoot);
target = nsd.showDialog(target);
setTextTarget(text, target);
targetSelected(fieldLabel, target);
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.add(text, LayoutHelper.getGBC(0, 0, 1, 1.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
panel.add(selectButton, LayoutHelper.getGBC(1, 0, 1, 0.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, text, panel, 0.0D);
this.incTabOffset(tabIndex);
}
private void setTextTarget(ZapTextField field, Target target) {
String text = getTargetText(target);
if (text != null) {
field.setText(text);
}
}
/**
* Returns the text representation of the given {@code target}.
* <p>
* If the {@code target} is not {@code null} it returns:
* <ol>
* <li>the URI, if it has a start node with an history reference;</li>
* <li>"Context: " followed by context's name, if it has a context;</li>
* <li>"Everything in scope", if it's only in scope.</li>
* </ol>
* For remaining cases it returns {@code null}.
*
* @param target the target whose text representation will be returned
* @return the text representation of the given {@code target}, might be {@code null}
* @since 2.4.2
* @see Target#getStartNode()
* @see Target#getContext()
* @see Target#isInScopeOnly()
*/
protected static String getTargetText(Target target) {
if (target != null) {
if (target.getStartNode() != null) {
return getNodeText(target.getStartNode());
} else if (target.getContext() != null) {
return Constant.messages.getString("context.prefixName", target.getContext().getName());
} else if (target.isInScopeOnly()) {
return Constant.messages.getString("context.allInScope");
}
}
return null;
}
private static String getNodeText(SiteNode node) {
if (node != null && node.getHistoryReference() != null) {
String url = node.getHistoryReference().getURI().toString();
if (node.isLeaf() && url.endsWith("/")) {
// String off the slash so we dont match a non leaf
// node with the same name
url = url.substring(0, url.length()-1);
} else if (! node.isLeaf() && ! url.endsWith("/")) {
// Add the slash to show its a non leaf node
url = url + "/";
}
return url;
}
return "";
}
public void addContextSelectField(String fieldLabel, Context selectedContext){
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
ContextSelectComboBox field = new ContextSelectComboBox();
if (selectedContext != null) {
field.setSelectedItem(selectedContext);
}
this.addField(fieldLabel, field, field, 0.0D);
}
public void addContextSelectField(int tabIndex, String fieldLabel, Context selectedContext){
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
ContextSelectComboBox field = new ContextSelectComboBox();
if (selectedContext != null) {
field.setSelectedItem(selectedContext);
}
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
incTabOffset(tabIndex);
}
public void addFileSelectField(String fieldLabel, final File dir, final int mode, final FileFilter filter) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
final ZapTextField text = new ZapTextField();
text.setEditable(false);
if (dir != null) {
text.setText(dir.getAbsolutePath());
}
final StandardFieldsDialog sfd = this;
JButton selectButton = new JButton("...");
selectButton.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
JFileChooser chooser = new JFileChooser(dir);
chooser.setFileSelectionMode(mode);
if (filter != null) {
chooser.setFileFilter(filter);
}
int rc = chooser.showSaveDialog(sfd);
if(rc == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
if (file == null) {
return;
}
text.setText(file.getAbsolutePath());
}
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.add(text, LayoutHelper.getGBC(0, 0, 1, 1.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
panel.add(selectButton, LayoutHelper.getGBC(1, 0, 1, 0.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.addField(fieldLabel, text, panel, 0.0D);
}
public void addFileSelectField(int tabIndex, final String fieldLabel, final File dir, final int mode, final FileFilter filter) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
final ZapTextField text = new ZapTextField();
text.setEditable(false);
if (dir != null) {
text.setText(dir.getAbsolutePath());
}
final StandardFieldsDialog sfd = this;
JButton selectButton = new JButton("...");
selectButton.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
JFileChooser chooser = new JFileChooser(dir);
chooser.setFileSelectionMode(mode);
if (filter != null) {
chooser.setFileFilter(filter);
}
int rc = chooser.showSaveDialog(sfd);
if(rc == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
if (file == null) {
return;
}
text.setText(file.getAbsolutePath());
}
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.add(text, LayoutHelper.getGBC(0, 0, 1, 1.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
panel.add(selectButton, LayoutHelper.getGBC(1, 0, 1, 0.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, text, panel, 0.0D);
this.incTabOffset(tabIndex);
}
/**
* Notifies that a site node was selected.
* <p>
* By default it does nothing.
*
* @param field the name of the field that triggered the selection
* @param node the node selected
* @see #addNodeSelectField(String, SiteNode, boolean, boolean)
*/
public void siteNodeSelected(String field, SiteNode node) {
}
/**
* Notifies that a target was selected.
* <p>
* By default it does nothing.
*
* @param field the name of the field that triggered the selection
* @param target the target selected
* @see #addTargetSelectField(int, String, Target, boolean, boolean)
*/
public void targetSelected(String field, Target target) {
}
/**
* Allow the caller to get the field component in order to, for example, change its properties
* @param fieldLabel the name of the field
* @return the field, or {@code null} if there's no field with the given name
*/
public Component getField(String fieldLabel) {
return this.fieldMap.get(fieldLabel);
}
public String getStringValue(String fieldLabel) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ZapTextField) {
return ((ZapTextField)c).getText();
} else if (c instanceof ZapTextArea) {
return ((ZapTextArea)c).getText();
} else if (c instanceof JComboBox) {
return (String)((JComboBox<?>)c).getSelectedItem();
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
return null;
}
/**
* Gets the contents of a {@link JPasswordField} field.
* <p>
* For stronger security, it is recommended that the returned character array be cleared after use by setting each character
* to zero.
*
* @param fieldLabel the label of the field
* @return the contents of the field, {@code null} if not a {@code JPassword} field.
* @since 2.6.0
* @see #setFieldValue(String, String)
* @see #addPasswordField(String, String)
*/
public char[] getPasswordValue(String fieldLabel) {
Component c = this.fieldMap.get(fieldLabel);
if (!(c instanceof JPasswordField)) {
return null;
}
return ((JPasswordField) c).getPassword();
}
public Context getContextValue(String fieldLabel) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ContextSelectComboBox) {
return ((ContextSelectComboBox)c).getSelectedContext();
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
return null;
}
/**
* Sets the (selected) context of a {@link ContextSelectComboBox} field.
* <p>
* The call to this method has no effect it the context is not present in the combo box.
*
* @param fieldLabel the label of the field
* @param context the context to be set/selected, {@code null} to clear the selection.
* @since 2.6.0
* @see #getContextValue(String)
* @see #addContextSelectField(String, Context)
*/
public void setContextValue(String fieldLabel, Context context) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ContextSelectComboBox) {
((ContextSelectComboBox) c).setSelectedItem(context);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
}
public void setFieldValue(String fieldLabel, String value) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ZapTextField) {
((ZapTextField)c).setText(value);
} else if (c instanceof JPasswordField) {
((JPasswordField)c).setText(value);
} else if (c instanceof ZapTextArea) {
((ZapTextArea)c).setText(value);
} else if (c instanceof JComboBox) {
((JComboBox<?>)c).setSelectedItem(value);
} else if (c instanceof JLabel) {
((JLabel)c).setText(value);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
}
public void setFieldValue(String fieldLabel, boolean value) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof JCheckBox) {
((JCheckBox)c).setSelected(value);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
}
public boolean isEmptyField(String fieldLabel) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
Object value = null;
if (c instanceof ZapTextField) {
value = ((ZapTextField)c).getText();
} else if (c instanceof JPasswordField) {
return ((JPasswordField) c).getDocument().getLength() == 0;
} else if (c instanceof ZapTextArea) {
value = ((ZapTextArea)c).getText();
} else if (c instanceof JComboBox) {
value = ((JComboBox<?>)c).getSelectedItem();
} else if (c instanceof ZapNumberSpinner) {
value = ((ZapNumberSpinner)c).getValue();
if ((Integer)value < 0) {
value = null;
}
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
return value == null || value.toString().length() == 0;
}
return true;
}
public int getIntValue(String fieldLabel) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ZapNumberSpinner) {
return ((ZapNumberSpinner)c).getValue();
} else if (c instanceof JComboBox) {
return (Integer)((JComboBox<?>)c).getSelectedItem();
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
return -1;
}
public void setFieldValue(String fieldLabel, int value) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ZapNumberSpinner) {
((ZapNumberSpinner)c).setValue(value);
} else if (c instanceof JComboBox) {
((JComboBox<?>)c).setSelectedItem(value);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
}
public void addReadOnlyField(String fieldLabel, String value, boolean doubleWidth) {
if (isTabbed()) {
throw new IllegalArgumentException("Initialised as a tabbed dialog - must use method with tab parameters");
}
JLabel field = new JLabel();
if (value != null) {
field.setText(value);
}
if (doubleWidth) {
this.getMainPanel().add(field,
LayoutHelper.getGBC(0, this.fieldList.size(), 2, 0.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.fieldList.add(field);
this.fieldMap.put(fieldLabel, field);
} else {
this.addField(fieldLabel, field, field, 0.0D);
}
}
public void addReadOnlyField(int tabIndex, String fieldLabel, String value, boolean doubleWidth) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
JLabel field = new JLabel();
if (value != null) {
field.setText(value);
}
if (doubleWidth) {
JPanel panel = this.tabPanels.get(tabIndex);
panel.add(field,
LayoutHelper.getGBC(0, this.tabOffsets.get(tabIndex), 2, 1.0D, 0.0D, GridBagConstraints.BOTH, new Insets(4,4,4,4)));
this.fieldList.add(field);
this.fieldMap.put(fieldLabel, field);
incTabOffset(tabIndex);
} else {
this.addField(this.tabPanels.get(tabIndex), this.tabOffsets.get(tabIndex), fieldLabel, field, field, 0.0D);
}
incTabOffset(tabIndex);
}
public void setCustomTabPanel(int i, JComponent panel) {
this.tabPanels.get(i).add(panel, LayoutHelper.getGBC(0, 0, 1, 1.0D, 1.0D, GridBagConstraints.BOTH));
}
public Boolean getBoolValue(String fieldLabel) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof JCheckBox) {
return ((JCheckBox)c).isSelected();
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
return null;
}
public void addFieldListener(String fieldLabel, ActionListener listener) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ZapTextField) {
((ZapTextField)c).addActionListener(listener);
} else if (c instanceof JPasswordField) {
((JPasswordField)c).addActionListener(listener);
} else if (c instanceof JComboBox) {
((JComboBox<?>)c).addActionListener(listener);
} else if (c instanceof JCheckBox) {
((JCheckBox)c).addActionListener(listener);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
}
public void addFieldListener(String fieldLabel, MouseAdapter listener) {
Component c = this.fieldMap.get(fieldLabel);
if (c != null) {
if (c instanceof ZapTextField) {
((ZapTextField)c).addMouseListener(listener);
} else if (c instanceof ZapTextArea) {
((ZapTextArea)c).addMouseListener(listener);
} else if (c instanceof JPasswordField) {
((JPasswordField)c).addMouseListener(listener);
} else if (c instanceof JComboBox) {
((JComboBox<?>)c).addMouseListener(listener);
} else {
logger.error("Unrecognised field class " + fieldLabel + ": " + c.getClass().getCanonicalName());
}
}
}
public void removeAllFields() {
if (this.isTabbed()) {
for (JPanel panel : this.tabPanels) {
panel.removeAll();
}
} else {
this.getMainPanel().removeAll();
}
this.fieldList.clear();
this.fieldMap.clear();
}
public void requestTabFocus(int tabIndex) {
if (!isTabbed()) {
throw new IllegalArgumentException("Not initialised as a tabbed dialog - must use method without tab parameters");
}
if (tabIndex < 0 || tabIndex >= this.tabPanels.size()) {
throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
}
tabbedPane.setSelectedComponent(this.tabPanels.get(tabIndex));
}
/**
* Set the visibility of the specified tabs.
* The labels must have been used to create the tabs in the constructor
* @param tabLabels the names of the tabs
* @param visible {@code true} if the tabs should be visible, {@code false} otherwise
*/
public void setTabsVisible(String[] tabLabels, boolean visible) {
if (visible) {
for (String label : tabLabels) {
String name = Constant.messages.getString(label);
JPanel tabPanel = this.tabNameMap.get(label);
tabbedPane.addTab(name, tabPanel);
this.tabPanels.add(tabPanel);
}
} else {
for (String label : tabLabels) {
JPanel tabPanel = this.tabNameMap.get(label);
this.tabbedPane.remove(tabPanel);
}
}
}
/**
* Called when the dialogue is saved and after all validations have finished, to conclude the saving process.
* <p>
* Whether or not the dialogue is automatically hidden depends on the value returned by {@link #isHideOnSave()}.
*
* @see #validateFields()
* @see #validateFieldsCustomMessage()
* @see #getSaveButtonText()
*/
public abstract void save();
/**
* Called when the dialogue is {@link #save() saved}, allowing to validate the fields and show an error message (as opposed
* to validations using the method {@link #validateFieldsCustomMessage()}, which allow to show custom/complex information or
* warning dialogues).
* <p>
* If no message is returned (that is, {@code null}), the saving process continues, otherwise it is shown a warning dialogue
* with the message.
*
* @return a {@code String} containing the error message to be shown to the user, or {@code null} if there are no errors.
*/
public abstract String validateFields();
}