/*
* ------------------------------------------------------------------------
*
* Copyright (C) 2003 - 2013
* University of Konstanz, Germany and
* KNIME GmbH, Konstanz, Germany
* Website: http://www.knime.org; Email: contact@knime.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 3, as
* published by the Free Software Foundation.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*
* Additional permission under GNU GPL version 3 section 7:
*
* KNIME interoperates with ECLIPSE solely via ECLIPSE's plug-in APIs.
* Hence, KNIME and ECLIPSE are both independent programs and are not
* derived from each other. Should, however, the interpretation of the
* GNU GPL Version 3 ("License") under any applicable laws result in
* KNIME and ECLIPSE being a combined program, KNIME GMBH herewith grants
* you the additional permission to use and propagate KNIME together with
* ECLIPSE with only the license terms in place for ECLIPSE applying to
* ECLIPSE and the GNU GPL Version 3 applying for KNIME, provided the
* license terms of ECLIPSE themselves allow for the respective use and
* propagation of ECLIPSE together with KNIME.
*
* Additional permission relating to nodes for KNIME that extend the Node
* Extension (and in particular that are based on subclasses of NodeModel,
* NodeDialog, and NodeView) and that only interoperate with KNIME through
* standard APIs ("Nodes"):
* Nodes are deemed to be separate and independent programs and to not be
* covered works. Notwithstanding anything to the contrary in the
* License, the License does not apply to Nodes, you are not required to
* license Nodes under the License, and you are granted a license to
* prepare and propagate Nodes, in each case even if such Nodes are
* propagated with or for interoperation with KNIME. The owner of a Node
* may freely choose the license terms applicable to such Node, including
* when such Node is propagated with or for interoperation with KNIME.
* --------------------------------------------------------------------- *
*
*/
package org.knime.knip.base.node.dialog;
import java.awt.Dimension;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.knime.core.node.InvalidSettingsException;
import org.knime.core.node.NotConfigurableException;
import org.knime.core.node.defaultnodesettings.DialogComponent;
import org.knime.core.node.defaultnodesettings.SettingsModelString;
import org.knime.core.node.port.PortObjectSpec;
/**
*
* @author <a href="mailto:dietzc85@googlemail.com">Christian Dietz</a>
* @author <a href="mailto:horn_martin@gmx.de">Martin Horn</a>
* @author <a href="mailto:michael.zinsmaier@googlemail.com">Michael Zinsmaier</a>
* @author daniel
*/
abstract class AbstractSimpleJTextfieldDialogComponent extends DialogComponent {
// the min/max and default width of the editfield, if not set explicitly
private static final int FIELD_MINWIDTH = 5;
private static final int FIELD_DEFWIDTH = 15;
private static final int FIELD_MAXWIDTH = 30;
private final JTextField m_valueField;
private final JLabel m_label;
private final boolean m_disallowEmtpy;
/**
* Constructor put label and JTextField into panel. It will accept empty strings as legal input.
*
* @param stringModel the model that stores the value for this component.
* @param label label for dialog in front of JTextField
*/
public AbstractSimpleJTextfieldDialogComponent(final SettingsModelString stringModel, final String label) {
this(stringModel, label, false, calcDefaultWidth(stringModel.getStringValue()));
}
/**
* Constructor put label and JTextField into panel.
*
* @param stringModel the model that stores the value for this component.
* @param label label for dialog in front of JTextField
* @param disallowEmptyString if set true, the component request a non-empty string from the user.
* @param compWidth the width of the edit field (in columns/characters)
*/
public AbstractSimpleJTextfieldDialogComponent(final SettingsModelString stringModel, final String label,
final boolean disallowEmptyString, final int compWidth) {
super(stringModel);
m_disallowEmtpy = disallowEmptyString;
m_label = new JLabel(label);
getComponentPanel().add(m_label);
m_valueField = new JTextField();
m_valueField.setColumns(compWidth);
m_valueField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(final DocumentEvent e) {
try {
updateModel();
} catch (final InvalidSettingsException ise) {
// Ignore it here.
}
}
@Override
public void insertUpdate(final DocumentEvent e) {
try {
updateModel();
} catch (final InvalidSettingsException ise) {
// Ignore it here.
}
}
@Override
public void changedUpdate(final DocumentEvent e) {
try {
updateModel();
} catch (final InvalidSettingsException ise) {
// Ignore it here.
}
}
});
getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent arg0) {
updateComponent();
}
});
getComponentPanel().add(m_valueField);
//call this method to be in sync with the settings model
updateComponent();
}
/**
* @param defaultValue the default value in the component
* @return the width of the spinner, derived from the defaultValue.
*/
private static int calcDefaultWidth(final String defaultValue) {
if ((defaultValue == null) || (defaultValue.length() == 0)) {
// no default value, return the default width of 15
return FIELD_DEFWIDTH;
}
if (defaultValue.length() < FIELD_MINWIDTH) {
// the editfield should be at least 15 columns wide
return FIELD_MINWIDTH;
}
if (defaultValue.length() > FIELD_MAXWIDTH) {
return FIELD_MAXWIDTH;
}
return defaultValue.length();
}
/**
* {@inheritDoc}
*/
@Override
protected void updateComponent() {
clearError(m_valueField);
// update component only if values are out of sync
final String str = ((SettingsModelString)getModel()).getStringValue();
if (!m_valueField.getText().equals(str)) {
m_valueField.setText(str);
}
setEnabledComponents(getModel().isEnabled());
}
/**
* Transfers the current value from the component into the model.
*
* @throws InvalidSettingsException if the string was not accepted.
*/
private void updateModel() throws InvalidSettingsException {
if (m_disallowEmtpy && ((m_valueField.getText() == null) || (m_valueField.getText().length() == 0))) {
showError(m_valueField);
throw new InvalidSettingsException("Please enter a string value.");
}
// we transfer the value from the field into the model
((SettingsModelString)getModel()).setStringValue(m_valueField.getText());
}
/**
* {@inheritDoc}
*/
@Override
protected void validateSettingsBeforeSave() throws InvalidSettingsException {
updateModel();
}
/**
* {@inheritDoc}
*/
@Override
protected void checkConfigurabilityBeforeLoad(final PortObjectSpec[] specs) throws NotConfigurableException {
// we are always good.
}
/**
* {@inheritDoc}
*/
@Override
protected void setEnabledComponents(final boolean enabled) {
m_valueField.setEnabled(enabled);
}
/**
* Sets the preferred size of the internal component.
*
* @param width The width.
* @param height The height.
*/
public void setSizeComponents(final int width, final int height) {
m_valueField.setPreferredSize(new Dimension(width, height));
}
/**
* {@inheritDoc}
*/
@Override
public void setToolTipText(final String text) {
m_label.setToolTipText(text);
m_valueField.setToolTipText(text);
}
}