zkbind/src/main/java/org/zkoss/bind/proxy/ListModelSetProxy.java

Summary

Maintainability
F
3 days
Test Coverage
/** ListModelSetProxy.java.

    Purpose:

    Description:

    History:
        Mon Jun 08 11:30:22 CST 2021, Created by jameschu

    Copyright (C) 2021 Potix Corporation. All Rights Reserved.
 */
package org.zkoss.bind.proxy;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;

import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.Proxy;

import org.zkoss.bind.BindContext;
import org.zkoss.bind.annotation.ImmutableElements;
import org.zkoss.bind.sys.FormBinding;
import org.zkoss.bind.sys.SavePropertyBinding;
import org.zkoss.lang.Objects;
import org.zkoss.util.Pair;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zul.ListModelSet;
import org.zkoss.zul.event.ListDataListener;
import org.zkoss.zul.event.PagingListener;
import org.zkoss.zul.ext.SelectionControl;

/**
 * A ListModelSet Proxy
 *
 * @author jameschu
 * @since 9.6.0
 */
public class ListModelSetProxy<E> extends ListModelSet<E> implements Proxy, FormProxyObject, Serializable {
    private static final long serialVersionUID = 20210608113022L;
    private ListModelSet<E> _cache;
    private ListModelSet<E> _origin;
    private boolean _dirty;
    private boolean isImmutableElements;
    private ProxyNode _node;

    public ListModelSetProxy(ListModelSet<E> origin, Annotation[] callerAnnots) {
        _origin = origin;
        _cache = initCache();
        if (callerAnnots != null) {
            for (Annotation annot : callerAnnots) {
                if (annot.annotationType().isAssignableFrom(ImmutableElements.class)) {
                    isImmutableElements = true;
                    break;
                }
            }
        }
        resetFromOrigin();
    }

    private ListModelSet<E> initCache() {
        ListModelSet<E> cache = new ListModelSet<>(getOriginObject().size());
        return cache;
    }

    private ListModelSet<E> getCache() {
        return _cache;
    }

    public void onDirtyChange() {
        ProxyHelper.callOnDirtyChange(_node);
    }

    public void onDataChange(Object o) {
        ProxyHelper.callOnDataChange(_node, new Object[]{o, "."});
    }

    protected void setDirty(boolean d) {
        if (_dirty != d) {
            _dirty = d;
            onDirtyChange();
        }
        if (d)
            onDataChange(this);
    }

    //-- AbstractListModel --//
    public void addListDataListener(ListDataListener l) {
        getCache().addListDataListener(l); //initial setting
    }
    public void removeListDataListener(ListDataListener l) {
        getCache().removeListDataListener(l); //initial setting
    }

    public Set<E> getSelection() {
        return getCache().getSelection();
    }

    public void setSelection(Collection<? extends E> selection) {
        getCache().setSelection(selection);
        setDirty(true);
    }

    public boolean isSelected(Object obj) {
        return getCache().isSelected(obj);
    }

    public boolean isSelectionEmpty() {
        return getCache().isSelectionEmpty();
    }

    public boolean addToSelection(E obj) {
        boolean result = getCache().addToSelection(obj);
        if (result)
            setDirty(true);
        return result;
    }

    public boolean removeFromSelection(Object obj) {
        boolean result = getCache().removeFromSelection(obj);
        if (result)
            setDirty(true);
        return result;
    }

    public void clearSelection() {
        if (!getCache().getSelection().isEmpty()) {
            getCache().clearSelection();
            setDirty(true);
        }
    }

    public void setMultiple(boolean multiple) {
        if (getCache().isMultiple() != multiple) {
            getCache().setMultiple(multiple);
            setDirty(true);
        }
    }

    public void setSelectionControl(SelectionControl ctrl) {
        getCache().setSelectionControl(ctrl); //initial setting
    }

    public SelectionControl getSelectionControl() {
        return getCache().getSelectionControl(); //initial setting
    }

    public int getPageSize() {
        return getCache().getPageSize();
    }

    public void setPageSize(int size) throws WrongValueException {
        getCache().setPageSize(size);
        setDirty(true);
    }

    public int getPageCount() {
        return getCache().getPageCount();
    }

    public int getActivePage() {
        return getCache().getActivePage();
    }

    public void setActivePage(int pg) throws WrongValueException {
        getCache().setActivePage(pg);
        setDirty(true);
    }

    public void addPagingEventListener(PagingListener l) {
        getCache().addPagingEventListener(l); //initial setting
    }

    public void removePagingEventListener(PagingListener l) {
        getCache().removePagingEventListener(l); //initial setting
    }

    //-- ListModelSet --//
    public Set<E> getInnerSet() {
        return getCache().getInnerSet();
    }

    public int getSize() {
        return getCache().getSize();
    }

    public E getElementAt(int j) {
        return getCache().getElementAt(j);
    }

    public boolean notifyChange(E element) {
        return getCache().notifyChange(element);
    }

    //-- Set --//
    public boolean add(E o) {
        if (getCache().add(createProxyObject(o))) {
            setDirty(true);
            return true;
        }
        return false;
    }

    public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        Iterator<? extends E> e = c.iterator();
        while (e.hasNext()) {
            if (add(e.next()))
                modified = true;
        }
        if (modified)
            setDirty(true);
        return modified;
    }

    public void clear() {
        getCache().clear();
        setDirty(true);
    }

    public boolean contains(Object o) {
        Iterator<E> e = iterator();
        if (o == null) {
            while (e.hasNext())
                if (testEquals(e.next(), null))
                    return true;
        } else {
            while (e.hasNext())
                if (testEquals(o, e.next()))
                    return true;
        }
        return false;
    }

    public boolean containsAll(Collection<?> c) {
        Iterator<?> e = c.iterator();
        while (e.hasNext())
            if (!contains(e.next()))
                return false;
        return true;
    }

    public boolean equals(Object o) {
        return getCache().equals(o);
    }

    public int hashCode() {
        return getCache().hashCode();
    }

    public boolean isEmpty() {
        return getCache().isEmpty();
    }

    public String toString() {
        return getCache().toString();
    }

    public Iterator<E> iterator() {
        return getCache().iterator();
    }

    public boolean remove(Object o) {
        if (getCache().remove(createProxyObject(o))) {
            setDirty(true);
            return true;
        }
        return false;
    }

    public int indexOf(Object o) {
        return getCache().indexOf(o);
    }

    public boolean removeAll(Collection<?> c) {
        boolean modified = false;
        Iterator<?> e = iterator();
        c = createProxyObject(c); // use a proxy object to compare
        while (e.hasNext()) {
            if (c.contains(e.next())) {
                e.remove();
                modified = true;
            }
        }
        if (modified)
            setDirty(true);
        return modified;
    }

    public boolean retainAll(Collection<?> c) {
        boolean modified = false;
        Iterator<E> e = iterator();
        c = createProxyObject(c); // use a proxy object to compare
        while (e.hasNext()) {
            if (!c.contains(e.next())) {
                e.remove();
                modified = true;
            }
        }
        if (modified)
            setDirty(true);
        return modified;
    }

    public int size() {
        return getCache().size();
    }

    public Object[] toArray() {
        return getCache().toArray();
    }

    public <T> T[] toArray(T[] a) {
        return getCache().toArray(a);
    }

    //-- Sortable --//
    public void sort(Comparator<E> cmpr, final boolean ascending) {
        getCache().sort(cmpr, ascending);
        setDirty(true);
    }

    public void sort() {
        getCache().sort();
        setDirty(true);
    }

    public String getSortDirection(Comparator<E> cmpr) {
        return getCache().getSortDirection(cmpr);
    }

    public Object clone() {
        return getCache().clone();
    }

    //For Backward Compatibility//
    public void addSelection(E obj) {
        addToSelection(obj);
    }

    public void removeSelection(Object obj) {
        removeFromSelection(obj);
    }

    //-- Proxy --//
    public void setHandler(MethodHandler mi) {
        throw new UnsupportedOperationException("Not support!");
    }

    //-- FormProxyObject --//
    public ListModelSet<E> getOriginObject() {
        return _origin;
    }

    public void resetFromOrigin() {
        getCache().clear();
        setDirty(false);
        for (E e : getOriginObject()) {
            getCache().add(createProxyObject(e));
        }
    }

    public void submitToOrigin(BindContext ctx) {
        Collection<E> origin = ((Collection<E>) getOriginObject());
        origin.clear();
        for (E e : _cache) {
            if (e instanceof FormProxyObject) {
                FormProxyObject proxy = (FormProxyObject) e;
                proxy.submitToOrigin(ctx);
                origin.add((E) proxy.getOriginObject());
            } else {
                origin.add(e);
            }
        }
        setDirty(false);
    }

    public boolean isFormDirty() {
        if (_dirty)
            return true;
        Iterator<?> e = iterator();
        while (e.hasNext()) {
            Object o = e.next();
            if (o instanceof FormProxyObject) {
                if (((FormProxyObject) o).isFormDirty())
                    return true;
            }
        }
        return false;
    }

    public void setFormOwner(Object owner, FormBinding binding) {
        throw new IllegalAccessError("Not supported");
    }

    public void setPath(String property, ProxyNode parent) {
        if (property == null && _node != null) { // means update
            _node.setParent(parent);
        } else {
            _node = new ProxyNodeImpl(property, parent);
            for (E e : _cache) {
                if (e instanceof FormProxyObject)
                    ((FormProxyObject) e).setPath("[$INDEX$]", _node);
            }
        }
    }

    public void cacheSavePropertyBinding(String property, SavePropertyBinding s) {
        ProxyHelper.cacheSavePropertyBinding(_node, _node.getProperty() + property, s);
    }

    public Set<Pair<String, SavePropertyBinding>> collectCachedSavePropertyBinding() {
        throw new UnsupportedOperationException("Not support!");
    }

    protected static boolean testEquals(Object e, Object o) {
        if (e == o) {
            return true;
        }
        if (e instanceof FormProxyObject) {
            Object eo = ((FormProxyObject) e).getOriginObject();
            Object oo = o;
            if (o instanceof FormProxyObject) {
                oo = ((FormProxyObject) o).getOriginObject();
            }
            if (Objects.equals(eo, oo))
                return true;
        } else if (o instanceof FormProxyObject) {
            if (Objects.equals(e, ((FormProxyObject) o).getOriginObject()))
                return true;
        } else {
            if (Objects.equals(e, o))
                return true;
        }
        return false;
    }

    protected <T extends Object> T createProxyObject(T t) {
        T p = isImmutableElements ? t : ProxyHelper.createProxyIfAny(t);
        if (p instanceof FormProxyObject)
            ((FormProxyObject) p).setPath("[$INDEX$]", _node);
        return p;
    }
}