org.libreplan.web.orders.DynamicDatebox.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.web.orders.DynamicDatebox.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundacin para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolxico de Galicia
 * Copyright (C) 2010-2012 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.libreplan.web.orders;

import static org.libreplan.web.I18nHelper._;

import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.libreplan.web.common.Util;
import org.zkoss.ganttz.util.ComponentsFinder;
import org.zkoss.util.Locales;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Textbox;

/**
 * Textbox component which is transformed into a Datebox picker on demand.
 * <br />
 *
 * @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
 * @author Lorenzo Tilve ?lvaro <ltilve@igalia.com>
 * @author Manuel Rego Casasnovas <mrego@igalia.com>
 * @author Jacobo Aragunde Prez <jaragunde@igalia.com>
 */
public class DynamicDatebox extends GenericForwardComposer {

    final Getter<Date> getter;

    final Setter<Date> setter;

    private Textbox dateTextBox;

    private Datebox dateBox;

    private DateFormat dateFormat;

    private boolean disabled = false;

    public DynamicDatebox(Getter<Date> getter, Setter<Date> setter) {
        this.setter = setter;
        this.getter = getter;
        this.dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locales.getCurrent());
    }

    private Datebox createDateBox() {
        dateBox = new Datebox();
        dateBox.setFormat("short");
        dateBox.setValue(getter.get());
        registerOnEnterOpenDateBox(dateBox);
        registerBlurListener(dateBox);
        registerOnChange(dateBox);
        dateTextBox.getParent().appendChild(dateBox);
        return dateBox;
    }

    private Datebox getDateBox() {
        return dateBox;
    }

    /**
     * When a text box associated to a datebox is requested to show the datebox, the corresponding datebox is shown.
     *
     * @param component
     *            the component that has received focus
     */
    private void userWantsDateBox(Component component) {
        if (component == dateTextBox) {
            showDateBox(dateTextBox);
        }
    }

    private void showDateBox(Textbox associatedTextBox) {
        associatedTextBox.setVisible(false);
        getDateBox();
        createDateBox();
        dateBox.setFocus(true);
        dateBox.setOpen(true);
    }

    /**
     * When the dateBox loses focus the corresponding textbox is shown instead.
     *
     * @param currentDateBox
     *            the component that has lost focus
     */
    private void dateBoxHasLostFocus(Datebox currentDateBox) {
        if (currentDateBox == dateBox) {
            hideDateBox(dateTextBox);
        }
    }

    private void hideDateBox(Textbox associatedTextBox) {
        dateBox.detach();
        associatedTextBox.setVisible(true);
    }

    public void doAfterCompose(Component component) throws Exception {
        findComponents((Hbox) component);
        registerListeners();
        updateComponents();
        applyDisabledToElements(disabled);
    }

    private void registerListeners() {
        registerOnEnterListener(dateTextBox);

        Util.bind(dateTextBox, new Util.Getter<String>() {
            @Override
            public String get() {
                return asString(getter.get());
            }
        }, new Util.Setter<String>() {
            @Override
            public void set(String string) {
                try {
                    setter.set(fromString(string));
                } catch (ParseException e) {
                    throw new WrongValueException(dateTextBox,
                            _("Date format is wrong. Please, use the following format: {0}", asString(new Date())));
                }
            }
        });

    }

    private void findComponents(Hbox hbox) {
        List<Component> children = hbox.getChildren();
        assert children.size() == 1;
        dateTextBox = findTextBoxOfCell(children);
    }

    private static Textbox findTextBoxOfCell(List<Component> children) {
        return ComponentsFinder.findComponentsOfType(Textbox.class, children).get(0);
    }

    private void registerOnChange(Component component) {
        component.addEventListener("onChange", new EventListener() {
            @Override
            public void onEvent(Event event) {
                updateBean();
                updateComponents();
            }
        });
    }

    private void registerOnEnterListener(final Textbox textBox) {
        textBox.addEventListener("onOK", new EventListener() {
            @Override
            public void onEvent(Event event) {
                userWantsDateBox(textBox);
            }
        });
    }

    private void registerOnEnterOpenDateBox(final Datebox currentDatebox) {
        currentDatebox.addEventListener("onOK", new EventListener() {
            @Override
            public void onEvent(Event event) {
                currentDatebox.setOpen(true);
            }
        });
    }

    private void registerBlurListener(final Datebox currentDatebox) {
        currentDatebox.addEventListener("onBlur", new EventListener() {
            @Override
            public void onEvent(Event event) {
                dateBoxHasLostFocus(currentDatebox);
            }
        });
    }

    public interface Getter<Date> {
        /**
         * Typical get method that returns a variable.
         *
         * @return A variable of type Date.
         */
        Date get();
    }

    public interface Setter<Date> {
        /**
         * Typical set method to store a variable.
         *
         * @param value
         *            A variable of type Date to be set.
         */
        void set(Date value);
    }

    private void updateBean() {
        Date date = getDateBox().getValue();
        setter.set(date);
    }

    public void updateComponents() {
        getDateTextBox().setValue(asString(getter.get()));
    }

    private String asString(Date date) {
        if (date == null) {
            return "";
        }
        return dateFormat.format(date);
    }

    private Date fromString(String string) throws ParseException {
        if (StringUtils.isBlank(string)) {
            return null;
        }
        return dateFormat.parse(StringUtils.trim(string));
    }

    public Textbox getDateTextBox() {
        return dateTextBox;
    }

    public void setDateTextBox(Textbox dateTextBox) {
        this.dateTextBox = dateTextBox;
    }

    public boolean isDisabled() {
        return disabled;
    }

    public void setDisabled(boolean disabled) {
        this.disabled = disabled;
        applyDisabledToElements(disabled);
    }

    private void applyDisabledToElements(boolean disabled) {
        if (dateTextBox != null) {
            dateTextBox.setDisabled(disabled);
        }
    }
}