All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.jaxx.application.swing.AbstractApplicationFormUIModel Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-1
Show newest version
package org.nuiton.jaxx.application.swing;

/*
 * #%L
 * JAXX :: Application Swing
 * %%
 * Copyright (C) 2008 - 2014 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdesktop.beans.AbstractSerializableBean;
import org.nuiton.jaxx.application.ApplicationTechnicalException;
import org.nuiton.jaxx.application.bean.BinderCache;
import org.nuiton.jaxx.application.bean.JavaBeanObject;
import org.nuiton.util.beans.Binder;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Set;

/**
 * A ui form model.
 *
 * Created on 8/15/14.
 *
 * @author Tony Chemit - [email protected]
 * @since 2.10
 */
public abstract class AbstractApplicationFormUIModel> extends AbstractSerializableBean implements JavaBeanObject {

    private static final long serialVersionUID = 1L;

    /** Logger. */
    private static final Log log = LogFactory.getLog(AbstractApplicationFormUIModel.class);

    public static final String PROPERTY_MODIFY = "modify";

    public static final String PROPERTY_VALID = "valid";

    public static final String PROPERTY_CREATE = "create";

    public static final ImmutableSet MODIFY_IGNORE_PROPERTIES =
            ImmutableSet.copyOf(Sets.newHashSet(
                    PROPERTY_MODIFY,
                    PROPERTY_VALID,
                    PROPERTY_CREATE));

    /**
     * Modify state of the form.
     */
    private boolean modify;

    /**
     * Valid state of the form.
     */
    private boolean valid;

    /**
     * Create state of the form (at true when editing a new object).
     */
    private boolean create;

    /**
     * To bind for incoming object inside the form.
     */
    private final Binder fromBeanBinder;

    /**
     * To bind fro the from to outside world.
     */
    private final Binder toBeanBinder;

    /**
     * Used to copy the form to outside world.
     *
     * @return a new instance of outisde world object.
     */
    protected abstract E newEntity();

    protected AbstractApplicationFormUIModel() {
        fromBeanBinder = null;
        toBeanBinder = null;
    }

    protected AbstractApplicationFormUIModel(Class entityType,
                                             Class uiModelType) {
        this(BinderCache.getBinder(entityType, uiModelType),
             BinderCache.getBinder(uiModelType, entityType));
    }

    protected AbstractApplicationFormUIModel(Binder fromBeanBinder,
                                             Binder toBeanBinder) {
        this.fromBeanBinder = fromBeanBinder;
        this.toBeanBinder = toBeanBinder;
    }

    /**
     * Method to override the copy of incoming entity into the form.
     *
     * By default, invoke the simple binder copy (method {@link #fromBean(Object)}.
     *
     * @param entity incoming entity to copy inside the form
     */
    public void fromEntity(E entity) {
        fromBean(entity);
    }

    /**
     * Method to override the copy of the form to outside world ({@code entity}).
     *
     * By default, invoke the simple binder copy (method {@link #toBean(Object)}.
     *
     * @param entity the outside world object to fill
     */
    public void toEntity(E entity) {
        toBean(entity);
    }

    /**
     * Note: the method is {@code final}, if you need to customize something, do it in the
     * {@link #toEntity(Object)} method.
     *
     * @return a new instance of object to persist from this form
     */
    public final E toEntity() {
        E result = newEntity();
        toEntity(result);
        return result;
    }

    /**
     * @param bean object to copy into form using the {@link #fromBeanBinder} binder
     */
    public final void fromBean(E bean) {
        fromBeanBinder.copy(bean, (B) this);
    }

    /**
     * @return the new instance of bean binded from form to outside world
     */
    public final E toBean() {
        E result = newEntity();
        toBean(result);
        return result;
    }

    /**
     * @param bean the bean to bind
     * @return the binded form to the given {@code result}
     */
    public final E toBean(E bean) {
        toBeanBinder.copy((B) this, bean);
        return bean;
    }

    public boolean isModify() {
        return modify;
    }

    public void setModify(boolean modify) {
        Object oldValue = isModify();
        this.modify = modify;
        firePropertyChange(PROPERTY_MODIFY, oldValue, modify);
    }

    public boolean isValid() {
        return valid;
    }

    public void setValid(boolean valid) {
        Object oldValue = isValid();
        this.valid = valid;
        firePropertyChange(PROPERTY_VALID, oldValue, valid);
    }

    public boolean isCreate() {
        return create;
    }

    public void setCreate(boolean create) {
        Object oldValue = isCreate();
        this.create = create;
        firePropertyChange(PROPERTY_CREATE, oldValue, create);
    }


    /**
     * @return set of property names that will not change the modify state.
     */
    protected Set getModifyIgnorePropertyNames() {
        return MODIFY_IGNORE_PROPERTIES;
    }

    //------------------------------------------------------------------------//
    //-- PropagatePropertyChangeListener methods                            --//
    //------------------------------------------------------------------------//

    @Override
    public void firePropertyChanged(String propertyName,
                                    Object oldValue,
                                    Object newValue) {
        firePropertyChange(propertyName, oldValue, newValue);
    }

    //------------------------------------------------------------------------//
    //-- To listen bean changes and reflect it to the modifiy state         --//
    //------------------------------------------------------------------------//

    public final  void listenModelIsModify(B... javaBeanObjects) {

        ModifyPropertyChangeListener listener = new ModifyPropertyChangeListener(this, getModifyIgnorePropertyNames());
        for (B javaBeanObject : javaBeanObjects) {
            javaBeanObject.addPropertyChangeListener(listener);
        }

    }

    protected  void listenAndModifyModel(Iterable javaBeanObjects) {

        ModifyPropertyChangeListener listener = new ModifyPropertyChangeListener(this, getModifyIgnorePropertyNames());
        for (B javaBeanObject : javaBeanObjects) {
            javaBeanObject.addPropertyChangeListener(listener);
        }

    }

    //------------------------------------------------------------------------//
    //-- Transform methods                                                  --//
    //------------------------------------------------------------------------//

    protected static > Function modelToEntity() {
        return new Function() {
            @Override
            public E apply(B model) {
                return model.toEntity();
            }
        };
    }

    protected static > Function entityToModel(final Class modelType) {
        return new Function() {
            @Override
            public B apply(E entity) {
                try {
                    B model = modelType.newInstance();
                    model.fromEntity(entity);
                    return model;
                } catch (Exception e) {
                    throw new ApplicationTechnicalException("Can't create new model " + modelType.getName(), e);
                }

            }
        };
    }

    protected static class ModifyPropertyChangeListener implements PropertyChangeListener {

        private AbstractApplicationFormUIModel consumer;

        private Set propertiesToIgnore;

        public ModifyPropertyChangeListener(AbstractApplicationFormUIModel consumer, Set propertiesToIgnore) {
            this.consumer = consumer;
            this.propertiesToIgnore = propertiesToIgnore;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            String propertyName = evt.getPropertyName();
            if (!propertiesToIgnore.contains(propertyName)) {
                if (log.isInfoEnabled()) {
                    log.info("A property changed: " + evt);
                }
                consumer.setModify(true);
            }
        }
    }
}