package org.atdl4j.ui.swing.widget; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.plaf.basic.BasicArrowButton; import org.atdl4j.data.converter.DecimalConverter; import org.atdl4j.data.converter.IntegerConverter; import org.atdl4j.fixatdl.layout.DoubleSpinnerT; import org.atdl4j.fixatdl.layout.SingleSpinnerT; import org.atdl4j.ui.impl.ControlHelper; import org.atdl4j.ui.swing.SwingListener; import org.atdl4j.ui.swing.widget.SwingNullableSpinner.SpinnerNumberModelNull; public class SwingSpinnerWidget extends AbstractSwingWidget<BigDecimal> { private SwingNullableSpinner spinner; private JLabel label; private JButton buttonUp; private JButton buttonDown; private static final BigDecimal DEFAULT_INNER_INCREMENT = new BigDecimal(1); private static final BigDecimal DEFAULT_OUTER_INCREMENT = new BigDecimal(1); private int digits = 0; private JPanel wrapper; /** * SelectionListener that implements the dual spinner behavior. * */ public class DoubleSpinnerListener implements ActionListener { private JSpinner spinner; private BigDecimal increment; public DoubleSpinnerListener(JSpinner spinner, BigDecimal increment) { this.spinner = spinner; this.increment = increment; } public void actionPerformed(ActionEvent arg0) { Object value = spinner.getValue(); if (value == null) { value = BigDecimal.ZERO; } spinner.setValue(((BigDecimal) value).add(increment)); } } public void setVisible(boolean visible){ if (wrapper != null) wrapper.setVisible(visible); else super.setVisible(visible); } public void createWidget(JPanel parent) { List< ? extends Component> components = getBrickComponents(); if (!components.isEmpty()) { if (components.size()>1 ){ wrapper = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 0; c.gridy = 0; c.weightx = 1.0; c.weighty = 1.0; c.insets = new Insets(0, 0, 0, 0); wrapper.add( components.get(0), c); c.gridx = 1; c.gridy = 0; c.insets = new Insets(0, 0, 0, 0); wrapper.add( components.get(1), c); parent.add(wrapper); } else { parent.add(components.get(0)); } } } private void doButtonsLayout(JPanel buttonPanel) { buttonPanel.setBorder(BorderFactory.createLoweredBevelBorder()); GridBagConstraints gc = new GridBagConstraints(); gc.gridx=0; buttonUp = new BasicArrowButtonFixedSize(BasicArrowButton.NORTH); buttonDown = new BasicArrowButtonFixedSize(BasicArrowButton.SOUTH); buttonPanel.add(buttonUp, gc); buttonPanel.add(buttonDown, gc); } public BigDecimal getControlValueRaw() { BigDecimal val = (BigDecimal)spinner.getValue(); if (val != null) { val = val.setScale(digits, RoundingMode.HALF_UP ); } return val; } public void setValue(BigDecimal value) { spinner.setValue(value); } /* * (non-Javadoc) * * @see org.atdl4j.ui.ControlUI#reinit() */ @Override public void processReinit(Object aControlInitValue) { if (spinner != null) { applyInitialValue(); } } /** * Invokes spinner.setSelection() assigning - Control/@initValue if non-null * - Parameter/@minValue if non-null - otherwise 0 */ protected void applyInitialValue() { Double initValue = (Double) ControlHelper.getInitValue(control, getAtdl4jOptions()); if (initValue != null) { setValue(new BigDecimal(initValue)); } else { setValue(null); } } protected void processNullValueIndicatorChange(Boolean aOldNullValueInd, Boolean aNewNullValueInd) { } public List<Component> getComponents() { List<Component> widgets = new ArrayList<Component>(); widgets.add(label); widgets.add(spinner); if (control instanceof DoubleSpinnerT) { widgets.add(buttonUp); widgets.add(buttonDown); } return widgets; } public List<Component> getComponentsExcludingLabel() { List<Component> widgets = new ArrayList<Component>(); widgets.add(spinner); if (control instanceof DoubleSpinnerT) { widgets.add(buttonUp); widgets.add(buttonDown); } return widgets; } public void addListener(SwingListener listener) { spinner.addChangeListener(listener); if (control instanceof DoubleSpinnerT) { buttonUp.addActionListener(listener); buttonDown.addActionListener(listener); } } public void removeListener(SwingListener listener) { spinner.removeChangeListener(listener); if (control instanceof DoubleSpinnerT) { buttonUp.removeActionListener(listener); buttonDown.removeActionListener(listener); } } private static class BasicArrowButtonFixedSize extends BasicArrowButton { private static final long serialVersionUID = 20140226L; public BasicArrowButtonFixedSize(int direction, Color background, Color shadow, Color darkShadow, Color highlight) { super(direction, background, shadow, darkShadow, highlight); } public BasicArrowButtonFixedSize(int direction) { super(direction); } @Override public Dimension getPreferredSize() { return new Dimension(16, 9); } } @Override public List< ? extends Component> createBrickComponents() { List<Component> components = new ArrayList<Component>(); String tooltip = getTooltip(); // label if (control.getLabel() != null) { label = new JLabel(); label.setName(getName()+"/label"); label.setText(control.getLabel()); if (tooltip != null) label.setToolTipText(tooltip); components.add(label); } Component comp = null; if (control instanceof SingleSpinnerT) { // spinner spinner = new SwingNullableSpinner(); spinner.setName(getName()+"/spinner"); // tooltip if (tooltip != null) spinner.setToolTipText(tooltip); comp = spinner; } else if (control instanceof DoubleSpinnerT) { // doubleSpinnerGrid JPanel w = new JPanel(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.fill = GridBagConstraints.HORIZONTAL; gc.weightx = 1; gc.gridx = 0; gc.gridy = 0; // doubleSpinner spinner = new SwingNullableSpinner(); JPanel buttonPanel = new JPanel(new GridBagLayout()); doButtonsLayout(buttonPanel); // tooltip if (tooltip != null) { spinner.setToolTipText(tooltip); buttonUp.setToolTipText(tooltip); buttonDown.setToolTipText(tooltip); } // layout w.add(spinner, gc); gc.weightx = 0; gc.gridx = 1; gc.gridy = 0; w.add(buttonPanel, gc); comp = w; } components.add(comp); // number model SpinnerNumberModelNull model = (SpinnerNumberModelNull)spinner.getModel(); // Set min/max/precision if a parameter is attached if ( parameterConverter != null && parameterConverter instanceof DecimalConverter ) { DecimalConverter tempDecimalConverter = (DecimalConverter) parameterConverter; if ( tempDecimalConverter.getPrecision() != null ) { digits = tempDecimalConverter.getPrecision().intValue(); } else { digits = ControlHelper.getDefaultDigitsForSpinnerControl( parameterConverter.getParameter(), getAtdl4jOptions()); } if ( tempDecimalConverter.getMinValue() != null ) { // -- need to handle Percentage ("control value" representation) -- BigDecimal tempParameterMin = tempDecimalConverter.getMinValue(); BigDecimal tempControlMin = tempDecimalConverter.convertParameterValueToControlValue( tempParameterMin ); model.setMinimum( tempControlMin.setScale( digits, RoundingMode.HALF_UP ) ); } if ( tempDecimalConverter.getMaxValue() != null ) { // -- need to handle Percentage ("control value" representation) -- BigDecimal tempParameterMax = tempDecimalConverter.getMaxValue(); BigDecimal tempControlMax = tempDecimalConverter.convertParameterValueToControlValue( tempParameterMax ); model.setMaximum( tempControlMax.setScale( digits, RoundingMode.HALF_UP ) ); } } else if ( parameterConverter != null && parameterConverter instanceof IntegerConverter ) { IntegerConverter tempIntegerConverter = (IntegerConverter) parameterConverter; // -- Integer always has 0 digits -- digits = 0; if ( tempIntegerConverter.getMinValue() != null ) { BigInteger tempParameterMin = tempIntegerConverter.getMinValue(); BigInteger tempControlMin = tempIntegerConverter.convertParameterValueToControlValue( tempParameterMin ); model.setMinimum( new BigDecimal( tempControlMin ) ); } else { model.setMinimum( SwingNullableSpinner.MIN_INTEGER_VALUE_AS_BIG_DECIMAL ); } if ( tempIntegerConverter.getMaxValue() != null ) { BigInteger tempParameterMax = tempIntegerConverter.getMaxValue(); BigInteger tempControlMax = tempIntegerConverter.convertParameterValueToControlValue( tempParameterMax ); model.setMaximum( new BigDecimal( tempControlMax ) ); } else { model.setMaximum( SwingNullableSpinner.MAX_INTEGER_VALUE_AS_BIG_DECIMAL ); } } if ( control instanceof DoubleSpinnerT ) { BigDecimal tempInnerIncrement = ControlHelper.getInnerIncrementValue( control, getAtdl4jOptions(), digits ); if ( tempInnerIncrement != null ) { // -- Handle initValue="2.5" and ensure that we don't wind up using BigDecimal unscaled and end up with "25" -- model.setStepSize( tempInnerIncrement ); } BigDecimal outerStepSize = new BigDecimal( "1" ); BigDecimal tempOuterIncrement = ControlHelper.getOuterIncrementValue( control, getAtdl4jOptions() ); if ( tempOuterIncrement != null ) { outerStepSize = tempOuterIncrement; } buttonUp.addActionListener( new DoubleSpinnerListener( spinner, outerStepSize ) ); buttonDown.addActionListener( new DoubleSpinnerListener( spinner, outerStepSize.negate() ) ); } else if ( control instanceof SingleSpinnerT ) { BigDecimal tempIncrement = ControlHelper.getIncrementValue( control, getAtdl4jOptions(), digits ); if ( tempIncrement != null ) { // -- Handle initValue="2.5" and ensure that we don't wind up using BigDecimal unscaled and end up with "25" -- model.setStepSize( tempIncrement ); } else // tempIncrement is null { if ( digits != 0 ) { // -- Set the increment to the precision associated with digits (eg ".01" when digits=2, ".001" when digits=3) -- model.setStepSize( new BigDecimal( Math.pow( 10, -digits ) ).setScale( digits, RoundingMode.HALF_UP ) ); } else { model.setStepSize( new BigDecimal( "1" ) ); } } } spinner.setPreferredSize(new Dimension(100, 22)); spinner.revalidate(); applyInitialValue(); return components; } }