com.ocs.dynamo.ui.component.TimeField.java Source code

Java tutorial

Introduction

Here is the source code for com.ocs.dynamo.ui.component.TimeField.java

Source

/*
   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 com.ocs.dynamo.ui.component;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import com.vaadin.data.Property;
import com.vaadin.shared.ui.datefield.Resolution;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomField;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.NativeSelect;

/**
 * A custom field for displaying a time - renders an hour combo box and a minute combo box
 * 
 * @author bas.rutten
 */
public class TimeField extends CustomField<Date> {

    private static final long serialVersionUID = -676425827861766118L;

    private boolean use24HourClock = true;
    private Locale givenLocale = null;

    private final NativeSelect hourSelect;
    private final NativeSelect minuteSelect;
    private final NativeSelect secondSelect;

    private Resolution resolution = Resolution.MINUTE;
    private int intervalMinutes = 1;
    private int minHours = 0;
    private int maxHours = 23;

    private boolean maskInternalValueChange = false;

    private HorizontalLayout root;

    public TimeField(String caption) {
        this();
        setCaption(caption);
    }

    public TimeField() {

        hourSelect = getSelect();
        minuteSelect = getSelect();
        secondSelect = getSelect();

        root = new HorizontalLayout();
        root.setHeight(null);
        root.setWidth(null);

        fillHours();
        root.addComponent(hourSelect);

        fillMinutes();
        root.addComponent(minuteSelect);

        fillSeconds();
        root.addComponent(secondSelect);

        // when setValue() is called, update selects
        addValueChangeListener(new Property.ValueChangeListener() {

            private static final long serialVersionUID = 3383351188340627219L;

            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                if (maskInternalValueChange) {
                    return;
                }
                updateFields();
            }
        });

        addStyleName("timefield");
        setSizeUndefined();

        updateFields();
    }

    /**
     * Returns hour value in 24-hour format (0-23)
     */
    @SuppressWarnings("deprecation")
    public int getHours() {
        Date d = getValue();
        return d.getHours();
    }

    /**
     * Set hour in 24-hour format (0-23).
     * 
     * @param hours
     * @throws IllegalArgumentException
     *             If the hour parameter is outside the bounds marked by {@link #getHourMin()} and
     *             {@link #getHourMax()}
     */
    public void setHours(int hours) {

        if (hours < minHours || hours > maxHours) {
            throw new IllegalArgumentException(
                    "Value '" + hours + "' is outside bounds '" + minHours + "' - '" + maxHours + "'");
        }

        hourSelect.setValue(hours);
    }

    @SuppressWarnings("deprecation")
    public int getMinutes() {
        Date d = getValue();
        return d.getMinutes();
    }

    /**
     * @param minutes
     * @throws IllegalArgumentException
     *             If the minute parameter is not compatible with {@link #getMinuteInterval()}
     */
    public void setMinutes(int minutes) {
        if (minutes % intervalMinutes != 0) {
            throw new IllegalArgumentException(
                    "Value '" + minutes + "' is not compatible with interval '" + intervalMinutes + "'");
        }
        minuteSelect.setValue(minutes);
    }

    @SuppressWarnings("deprecation")
    public int getSeconds() {
        Date d = getValue();
        return d.getSeconds();
    }

    public void setSeconds(int seconds) {
        secondSelect.setValue(seconds);
    }

    private void fillHours() {

        hourSelect.removeAllItems();

        for (int i = minHours; i <= maxHours; i++) {
            hourSelect.addItem(i);
            if (!use24HourClock) {
                Integer val = i == 0 || i == 12 ? 12 : i % 12;

                String suffix;
                if (i < 12) {
                    suffix = " am";
                } else {
                    suffix = " pm";
                }
                hourSelect.setItemCaption(i, val + suffix);
            }
        }
    }

    private void fillMinutes() {

        minuteSelect.removeAllItems();
        for (int i = 0; i < 60; i++) {
            if (i % intervalMinutes == 0) {
                minuteSelect.addItem(i);
                minuteSelect.setItemCaption(i, i < 10 ? "0" + i : i + "");
            }
        }
    }

    private void fillSeconds() {

        secondSelect.removeAllItems();
        for (int i = 0; i < 60; i++) {
            secondSelect.addItem(i);
            secondSelect.setItemCaption(i, i < 10 ? "0" + i : i + "");
        }
    }

    private NativeSelect getSelect() {
        NativeSelect select = new NativeSelect();
        select.setImmediate(true);
        select.setNullSelectionAllowed(false);
        select.addValueChangeListener(new Property.ValueChangeListener() {

            private static final long serialVersionUID = 3383351188340627219L;

            @Override
            public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
                if (maskInternalValueChange) {
                    return;
                }
                maskInternalValueChange = true;
                updateValue();
                TimeField.this.fireValueChange(true);
                maskInternalValueChange = false;

            }
        });
        return select;
    }

    /**
     * This method gets called when any of the internal Select components are called.
     */
    @SuppressWarnings("deprecation")
    private void updateValue() {

        // if the value of any select is null at this point, we need to init it
        // to zero to prevent exceptions.

        if (secondSelect.getValue() == null) {
            secondSelect.setValue(0);
        }
        if (minuteSelect.getValue() == null) {
            minuteSelect.setValue(0);
        }
        if (hourSelect.getValue() == null) {
            hourSelect.setValue(0);
        }

        Date newDate = new Date(0);
        newDate.setSeconds(0);
        newDate.setMinutes(0);
        newDate.setHours(0);

        int val;
        if (resolution.ordinal() <= Resolution.HOUR.ordinal()) {
            val = (Integer) hourSelect.getValue();

            newDate.setHours(val);
        }
        if (resolution.ordinal() < Resolution.HOUR.ordinal()) {
            val = (Integer) minuteSelect.getValue();
            newDate.setMinutes(val);
        }
        if (resolution.ordinal() < Resolution.MINUTE.ordinal()) {
            val = (Integer) secondSelect.getValue();
            newDate.setSeconds(val);
        }

        setValue(newDate);
    }

    /**
     * This method gets called when we update the actual value (Date) of this TimeField.
     */
    @SuppressWarnings("deprecation")
    private void updateFields() {

        maskInternalValueChange = true;

        minuteSelect.setVisible(resolution.ordinal() < Resolution.HOUR.ordinal());
        secondSelect.setVisible(resolution.ordinal() < Resolution.MINUTE.ordinal());

        Date val = getValue();

        // make sure to update alternatives, wont spoil value above
        fillHours();
        fillMinutes();

        if (val == null) {
            // clear values
            hourSelect.setValue(null);
            minuteSelect.setValue(null);
            secondSelect.setValue(null);

            maskInternalValueChange = false;
            return;
        }

        // check hour bounds
        if (val.getHours() < minHours) {
            // guess
            int compatibleVal = val.getHours();
            while (compatibleVal < 24) {
                if (compatibleVal >= minHours) {
                    break;
                }
                compatibleVal++;
            }
            if (compatibleVal >= minHours) {
                val.setHours(compatibleVal);
            }
        } else if (val.getHours() > maxHours) {
            // guess
            int compatibleVal = val.getHours();
            while (compatibleVal > 0) {
                if (compatibleVal <= maxHours) {
                    break;
                }
                compatibleVal--;
            }
            if (compatibleVal <= maxHours) {
                val.setHours(compatibleVal);
            }
        }
        hourSelect.setValue(val.getHours());

        // check minute interval
        if (val.getMinutes() % intervalMinutes != 0) {
            // guess
            int compatibleVal = val.getMinutes();
            while (compatibleVal > 0) {
                if (compatibleVal % intervalMinutes == 0) {
                    break;
                }
                compatibleVal--;
            }
            val.setMinutes(compatibleVal);
        }
        minuteSelect.setValue(val.getMinutes());

        secondSelect.setValue(val.getSeconds());

        maskInternalValueChange = false;
    }

    /**
     * Sets locale that is used for time format detection. Defaults to browser locale.
     */
    @Override
    public void setLocale(Locale l) {
        givenLocale = l;

        DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT, givenLocale);
        String time = df.format(new Date());

        if (time.contains("am") || time.contains("AM") || time.contains("pm") || time.contains("PM")) {
            use24HourClock = false;
        } else {
            use24HourClock = true;
        }
        updateFields();
    }

    /**
     * Only resolutions of HOUR, MIN, SECOND are supported. Default is {@link Resolution#MINUTE}
     * 
     * @see {@link com.vaadin.ui.DateField#getResolution()}
     * @param resolution
     */
    public void setResolution(Resolution resolution) {

        if (this.resolution.ordinal() < resolution.ordinal()) {
            if (resolution.ordinal() > Resolution.SECOND.ordinal()) {
                secondSelect.setValue(0);
            }
            if (resolution.ordinal() > Resolution.MINUTE.ordinal()) {
                minuteSelect.setValue(0);
            }
        }
        this.resolution = resolution;
        updateFields();
    }

    /**
     * @see {@link com.vaadin.ui.DateField#getResolution()}
     * @return
     */
    public Resolution getResolution() {
        return resolution;
    }

    @Override
    public void attach() {
        super.attach();

        // if there isn't a given locale at this point, use the one from the
        // browser
        if (givenLocale == null) {
            // we have access to application after attachment
            @SuppressWarnings("deprecation")
            Locale locale = getUI().getSession().getBrowser().getLocale();
            givenLocale = locale;
        }
    }

    public void set24HourClock(boolean use24hourclock) {
        use24HourClock = use24hourclock;
        updateFields();
    }

    public boolean is24HourClock() {
        return use24HourClock;
    }

    @Override
    public Class<? extends Date> getType() {
        return Date.class;
    }

    @Override
    protected Component initContent() {

        return root;
    }

    @Override
    public void setTabIndex(int tabIndex) {
        hourSelect.setTabIndex(tabIndex);
        minuteSelect.setTabIndex(tabIndex);
        secondSelect.setTabIndex(tabIndex);
    }

    @Override
    public int getTabIndex() {
        return hourSelect.getTabIndex();
    }

    @Override
    public void setReadOnly(boolean readOnly) {
        hourSelect.setReadOnly(readOnly);
        minuteSelect.setReadOnly(readOnly);
        secondSelect.setReadOnly(readOnly);
        super.setReadOnly(readOnly);
    }

    public int getMinuteInterval() {
        return intervalMinutes;
    }

    /**
     * Set the interval to be used in minute select. Default is 1 minute intervals.
     * 
     * @param interval
     */
    public void setMinuteInterval(int interval) {
        if (interval < 0) {
            interval = 0;
        }
        intervalMinutes = interval;
        updateFields();
    }

    public int getHourMin() {
        return minHours;
    }

    /**
     * Set the minimum allowed value for the hour, in 24h format. Defaults to 0.
     * <p>
     * Changing this setting so that the field has a value outside the new bounds will lead to the
     * field resetting its value to the first bigger value that is valid.
     */
    public void setHourMin(int minHours) {

        if (minHours < 0) {
            minHours = 0;
        }
        if (minHours > 23) {
            minHours = 23;
        }

        this.minHours = minHours;
        updateFields();
    }

    public int getHourMax() {
        return maxHours;
    }

    /**
     * Set the maximum allowed value for the hour, in 24h format. Defaults to 23.
     * <p>
     * Changing this setting so that the field has a value outside the new bounds will lead to the
     * field resetting its value to the first smaller value that is valid.
     */
    public void setHourMax(int maxHours) {

        if (maxHours < 0) {
            maxHours = 0;
        }
        if (maxHours > 23) {
            maxHours = 23;
        }

        this.maxHours = maxHours;
        updateFields();
    }
}