com.haulmont.cuba.web.gui.components.WebTimeField.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.web.gui.components.WebTimeField.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * 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.haulmont.cuba.web.gui.components;

import com.google.common.base.Preconditions;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.UserSessionSource;
import com.haulmont.cuba.gui.components.DateField;
import com.haulmont.cuba.gui.components.TimeField;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.theme.ThemeConstants;
import com.haulmont.cuba.web.App;
import com.haulmont.cuba.web.gui.data.ItemWrapper;
import com.haulmont.cuba.web.gui.data.PropertyWrapper;
import com.haulmont.cuba.web.toolkit.ui.CubaMaskedTextField;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.server.UserError;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;

import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;

public class WebTimeField extends WebAbstractField<CubaMaskedTextField> implements TimeField {

    protected boolean showSeconds;

    protected String placeholder;
    protected String timeFormat;
    protected DateField.Resolution resolution;

    public WebTimeField() {
        UserSessionSource uss = AppBeans.get(UserSessionSource.NAME);

        timeFormat = Datatypes.getFormatStringsNN(uss.getLocale()).getTimeFormat();
        resolution = DateField.Resolution.MIN;

        component = new CubaMaskedTextField();
        component.setMaskedMode(true);
        component.setImmediate(true);
        component.setTimeMask(true);
        setShowSeconds(timeFormat.contains("ss"));

        component.setInvalidAllowed(false);
        component.setInvalidCommitted(true);
        component.addValidator(value -> {
            if (!(!(value instanceof String) || checkStringValue((String) value))) {
                component.markAsDirty();
                throw new com.vaadin.data.Validator.InvalidValueException("Unable to parse value: " + value);
            }
        });
        attachListener(component);

        component.setConverter(new Converter<String, Date>() {
            @Override
            public Date convertToModel(String formattedValue, Class<? extends Date> targetType, Locale locale)
                    throws ConversionException {
                if (StringUtils.isNotEmpty(formattedValue) && !formattedValue.equals(placeholder)) {
                    try {
                        SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
                        sdf.setLenient(false);

                        Date date = sdf.parse(formattedValue);
                        if (component.getComponentError() != null)
                            component.setComponentError(null);
                        if (targetType == java.sql.Time.class) {
                            return new Time(date.getTime());
                        }
                        if (targetType == java.sql.Date.class) {
                            LoggerFactory.getLogger(WebTimeField.class)
                                    .warn("Do not use java.sql.Date with time field");
                            return new java.sql.Date(date.getTime());
                        }
                        return date;
                    } catch (Exception e) {
                        LoggerFactory.getLogger(WebTimeField.class)
                                .debug("Unable to parse value of component {}:\n{}", getId(), e.getMessage());
                        throw new ConversionException("Invalid value");
                    }
                } else
                    return null;
            }

            @Override
            public String convertToPresentation(Date value, Class<? extends String> targetType, Locale locale)
                    throws ConversionException {
                if (value != null) {
                    SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
                    return sdf.format(value);
                } else
                    return null;
            }

            @Override
            public Class<Date> getModelType() {
                return Date.class;
            }

            @Override
            public Class<String> getPresentationType() {
                return String.class;
            }
        });
    }

    public boolean isAmPmUsed() {
        return timeFormat.contains("a");
    }

    protected void updateWidth() {
        if (!App.isBound()) {
            return;
        }

        App app = App.getInstance();

        ThemeConstants theme = app.getThemeConstants();
        int digitWidth = theme.getInt("cuba.web.WebTimeField.digitWidth");
        int digitPadding = theme.getInt("cuba.web.WebTimeField.digitPadding");
        int separatorWidth = theme.getInt("cuba.web.WebTimeField.separatorWidth");

        int partsCount = isAmPmUsed() ? 1 : 0;
        int newWidth = isAmPmUsed() ? digitWidth + digitPadding : digitPadding;
        if (showSeconds) {
            newWidth = newWidth + digitWidth;
            partsCount += 1;
        }
        switch (resolution) {
        case HOUR:
            partsCount += 1;
            newWidth = digitWidth + newWidth;
            break;
        case MIN:
        case SEC:
            partsCount += 2;
            newWidth = digitWidth * 2 + newWidth;
            break;
        }

        newWidth += (partsCount - 1) * separatorWidth;

        component.setWidth(newWidth + "px");
    }

    private boolean checkStringValue(String value) {
        if (value.equals(placeholder) || StringUtils.isEmpty(value))
            return true;
        SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
        sdf.setLenient(false);
        try {
            sdf.parse(value);
            return true;
        } catch (ParseException e) {
            return false;
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public Date getValue() {
        Object value = super.getValue();
        if (value instanceof String) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
                return sdf.parse((String) value);
            } catch (ParseException e) {
                LoggerFactory.getLogger(WebTimeField.class).debug("Unable to parse value of component {}\n{}",
                        getId(), e.getMessage());
                return null;
            }
        } else {
            return (Date) value;
        }
    }

    @Override
    public void setValue(Object value) {
        Preconditions.checkArgument(value == null || value instanceof Date, "Value must be an instance of Date");
        if (value != null) {
            SimpleDateFormat sdf = new SimpleDateFormat(this.timeFormat);
            sdf.setLenient(false);

            super.setValue(sdf.format(value));
        } else {
            super.setValue(null);
        }
    }

    @Override
    public boolean getShowSeconds() {
        return showSeconds;
    }

    @Override
    public void setFormat(String format) {
        timeFormat = format;
        showSeconds = timeFormat.contains("ss");
        updateTimeFormat();
        updateWidth();
    }

    @Override
    public String getFormat() {
        return timeFormat;
    }

    public void setResolution(DateField.Resolution resolution) {
        this.resolution = resolution;
        if (resolution.ordinal() <= DateField.Resolution.SEC.ordinal()) {
            setShowSeconds(true);
        } else if (resolution.ordinal() <= DateField.Resolution.MIN.ordinal()) {
            setShowSeconds(false);
        } else if (resolution.ordinal() <= DateField.Resolution.HOUR.ordinal()) {
            StringBuilder builder = new StringBuilder(timeFormat);
            if (timeFormat.contains("mm")) {
                int minutesIndex = builder.indexOf("mm");
                builder.delete(minutesIndex > 0 ? --minutesIndex : minutesIndex, minutesIndex + 3);
                timeFormat = builder.toString();
            }
            setShowSeconds(false);
        }
    }

    @Override
    public void setShowSeconds(boolean showSeconds) {
        this.showSeconds = showSeconds;
        if (showSeconds) {
            if (!timeFormat.contains("ss")) {
                int minutesIndex = timeFormat.indexOf("mm");
                StringBuilder builder = new StringBuilder(timeFormat);
                builder.insert(minutesIndex + 2, ":ss");
                timeFormat = builder.toString();
            }
        } else {
            if (timeFormat.contains("ss")) {
                int secondsIndex = timeFormat.indexOf("ss");
                StringBuilder builder = new StringBuilder(timeFormat);
                builder.delete(secondsIndex > 0 ? --secondsIndex : secondsIndex, secondsIndex + 3);
                timeFormat = builder.toString();
            }
        }
        updateTimeFormat();
        updateWidth();
    }

    protected void updateTimeFormat() {
        String mask = StringUtils.replaceChars(timeFormat, "Hhmsa", "####U");
        placeholder = StringUtils.replaceChars(mask, "#U", "__");
        component.setMask(mask);
        component.setNullRepresentation(placeholder);
    }

    @Override
    protected ItemWrapper createDatasourceWrapper(Datasource datasource,
            Collection<MetaPropertyPath> propertyPaths) {
        return new ItemWrapper(datasource, datasource.getMetaClass(), propertyPaths) {
            private static final long serialVersionUID = 1729450322469573679L;

            @Override
            protected PropertyWrapper createPropertyWrapper(Object item, MetaPropertyPath propertyPath) {
                return new PropertyWrapper(item, propertyPath) {
                    private static final long serialVersionUID = -4481934193197224070L;

                    @Override
                    public String getFormattedValue() {
                        Object value = this.getValue();
                        if (value instanceof Date) {
                            SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
                            return sdf.format(value);
                        }

                        return super.getFormattedValue();
                    }

                    @Override
                    protected Object valueOf(Object newValue) throws Converter.ConversionException {
                        if (newValue instanceof String) {
                            if (StringUtils.isNotEmpty((String) newValue) && !newValue.equals(placeholder)) {
                                try {
                                    SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
                                    Date date = sdf.parse((String) newValue);
                                    if (component.getComponentError() != null) {
                                        component.setComponentError(null);
                                    }
                                    return date;
                                } catch (Exception e) {
                                    LoggerFactory.getLogger(WebTimeField.class)
                                            .debug("Unable to parse value of component " + getId() + "\n"
                                                    + e.getMessage());
                                    component.setComponentError(new UserError("Invalid value"));
                                    return null;
                                }
                            } else
                                return null;
                        } else
                            return newValue;
                    }
                };
            }
        };
    }

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

    @Override
    public void setTabIndex(int tabIndex) {
        component.setTabIndex(tabIndex);
    }

    @Override
    public void commit() {
        super.commit();
    }

    @Override
    public void discard() {
        super.discard();
    }

    @Override
    public boolean isBuffered() {
        return super.isBuffered();
    }

    @Override
    public void setBuffered(boolean buffered) {
        super.setBuffered(buffered);
    }

    @Override
    public boolean isModified() {
        return super.isModified();
    }
}