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

net.sf.cuf.ui.builder.StateHandlingBuilderDelegate Maven / Gradle / Ivy

The newest version!
package net.sf.cuf.ui.builder;

import net.sf.cuf.model.state.MinMaxState;
import org.jdom2.Element;

import java.util.List;
import java.util.Collection;
import java.lang.reflect.Constructor;
import java.awt.Color;

import net.sf.cuf.state.State;
import net.sf.cuf.state.SimpleState;
import net.sf.cuf.state.StateAdapter;
import net.sf.cuf.state.MutableState;
import net.sf.cuf.state.StateExpression;
import net.sf.cuf.state.SimpleStateExpression;
import net.sf.cuf.state.ui.SwingSelectedState;
import net.sf.cuf.state.ui.SwingEnabledAdapter;
import net.sf.cuf.state.ui.SwingEnabledState;
import net.sf.cuf.state.ui.SwingListSelectionState;
import net.sf.cuf.state.ui.SwingListModelFillState;
import net.sf.cuf.state.ui.SwingTableModelFillState;
import net.sf.cuf.state.ui.SwingTreeModelFillState;
import net.sf.cuf.state.ui.SwingTreeSelectionState;
import net.sf.cuf.state.ui.SwingEditableAdapter;
import net.sf.cuf.state.ui.SwingJTableEnabledAdapter;
import net.sf.cuf.state.ui.SwingSelectedAdapter;
import net.sf.cuf.state.ui.SwingVisibleAdapter;
import net.sf.cuf.state.ui.SwingBorderAdapter;
import net.sf.cuf.state.ui.SwingDocumentState;
import net.sf.cuf.state.ui.SwingBackgroundAdapter;
import net.sf.cuf.model.state.CollectionFilledState;
import net.sf.cuf.model.state.EqualsState;
import net.sf.cuf.model.state.NullState;
import net.sf.cuf.model.state.RegExpState;
import net.sf.cuf.model.state.ValueState;
import net.sf.cuf.model.ValueModel;

import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.JComboBox;
import javax.swing.border.Border;
import javax.swing.text.JTextComponent;

/**
 * The StateHandlingBuilderDelegate class handles the "statehandling" entry of
 * a xml2swing XML description.
 */
class StateHandlingBuilderDelegate implements SwingXMLBuilder.BuilderDelegate
{
    /**
     * Build the specific part of the delegate.
     * @param pBuilder the builder that controls the creation process
     * @param pStateHandlingElement the JDOM element the delegate should handle, "statehandling" in our case
     */
    public void build(final SwingXMLBuilder pBuilder, final Element pStateHandlingElement)
    {
        List statehandlings= pStateHandlingElement.getChildren();
        for (final Element element : statehandlings)
        {
            String objectType = element.getName();
            Object object = null;

            // get id
            String id = element.getAttributeValue(SwingXMLBuilder.ID_ATTRIBUTE);

            // 
            switch (objectType)
            {
                case SwingXMLBuilder.STATE_ELEMENT:
                    object = createState(element, id, pBuilder);
                    break;
                case SwingXMLBuilder.EXPRESSION_ELEMENT:
                    object = createStateExpression(element, id, pBuilder);
                    break;
                case SwingXMLBuilder.STATEADAPTER_ELEMENT:
                    object = createStateAdapter(element, id, pBuilder);
                    break;
                case SwingXMLBuilder.SETSTATE_ELEMENT:
                    setState(element, id, pBuilder);
                    break;
                default:
                    throw SwingXMLBuilder.createException("unknown state handling " + objectType,
                                                          element);
            }

            // put it in our builder's map
            if ((id != null) && (object != null))
            {
                if (pBuilder.getNameToNonVisual().containsKey(id))
                {
                    throw SwingXMLBuilder.createException("nonvisual with id " + id + " already defined", element);
                }
                else
                {
                    pBuilder.getNameToNonVisual().put(id, object);
                }
            }
        }

    }

    /**
     * Creates a new state.
     * @param pElement element describing the object
     * @param pId value of the id attribute of pElement
     * @param pBuilder our builder
     * @throws IllegalArgumentException if we have a problem (parameters, ...)
     * @return the new state, never null
     */
    @SuppressWarnings({"ConstantConditions"})
    private Object createState(final Element pElement, final String pId, final SwingXMLBuilder pBuilder) throws IllegalArgumentException
    {
        if (pId==null)
            throw SwingXMLBuilder.createException("id of "+pElement.getName()+" must not be null",
                                                  pElement);

        // get needed attributes
        String  type = pElement.getAttributeValue(SwingXMLBuilder.TYPE_ATTRIBUTE);
        String  refId= pElement.getAttributeValue(SwingXMLBuilder.REF_ATTRIBUTE);

        State state= null;
        if ("simple".equals(type))
        {
            state= new SimpleState();
        }
        else if ("custom".equals(type))
        {
            Class customClass= SwingXMLBuilder.getClass(pElement);
            if (refId==null)
            {
                // use default constructor
                try
                {
                    state= (State)customClass.newInstance();
                }
                catch (Exception e)
                {
                    throw SwingXMLBuilder.createException("could not create state for class "+customClass,
                                                          e, pElement);
                }
            }
            else
            {
                // use single argument constructor
                Object ref= pBuilder.getNonVisualObject(refId);
                if (ref == null)
                {
                    ref= pBuilder.getComponentByAnyName(refId);
                }
                if (ref==null)
                {
                    throw SwingXMLBuilder.createException(refId+ " doesn't map to an object",
                                                          pElement);
                }

                try
                {
                    Constructor[] constructors= customClass.getConstructors();
                    for (final Constructor constructor : constructors)
                    {
                        Class[] parameters = constructor.getParameterTypes();
                        if (parameters.length != 1)
                            continue;
                        if (parameters[0].isAssignableFrom(ref.getClass()))
                        {
                            Object[] args = {ref};
                            state = (State) constructor.newInstance(args);
                        }
                    }
                }
                catch (Exception e)
                {
                    throw SwingXMLBuilder.createException("could not create state for class "+customClass+
                                                          " with argument "+ref, e, pElement);
                }
                if (state==null)
                {
                    throw SwingXMLBuilder.createException("could not create state for class "+customClass+
                                                          " with argument "+ref, pElement);
                }
            }
        }
        else if ("value".equals(type))
        {
            Object ref= pBuilder.getNonVisualObject(refId);
            if (!(ref instanceof ValueModel))
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+")is no ValueModel",
                                                      pElement);
            }
            state= new ValueState((ValueModel)ref);
        }
        else if ("enabled".equals(type))
        {
            Object ref= pBuilder.getNonVisualObject(refId);
            if (ref instanceof Action)
            {
                state= new SwingEnabledState((Action)ref);
            }
            else
            {
                ref= pBuilder.getComponentByAnyName(refId);
                if (ref instanceof JComponent)
                {
                    state= new SwingEnabledState((JComponent)ref);
                }
            }
            if (state==null)
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not known",
                                                      pElement);
            }
        }
        else if ("selected".equals(type))
        {
            Object ref= pBuilder.getComponentByAnyName(refId);
            if (!(ref instanceof AbstractButton))
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is no AbstractButton",
                                                      pElement);
            }
            state= new SwingSelectedState((AbstractButton)ref);
        }
        else if ("document".equals(type))
        {
            Object ref= pBuilder.getComponentByAnyName(refId);
            if (!(ref instanceof JTextComponent))
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is no JTextComponent",
                                                      pElement);
            }
            state= new SwingDocumentState((JTextComponent)ref);
        }
        else if ("listSelection".equals(type))
        {
            Object  ref         = pBuilder.getComponentByAnyName(refId);
            int     index       = SwingListSelectionState.NO_SELECTION;
            boolean reverseIndex= false;
            String  refId2      = pElement.getAttributeValue(SwingXMLBuilder.REF2_ATTRIBUTE);
            if (refId2!=null)
            {
                String stringIndex= refId2;
                if (refId2.startsWith("r"))
                {
                    reverseIndex= true;
                    stringIndex= refId2.substring(1);
                }
                try
                {
                    index= Integer.parseInt(stringIndex);
                }
                catch (NumberFormatException e)
                {
                    throw SwingXMLBuilder.createException("ref2 index ("+refId2+") is not an integer",
                                                          pElement);
                }
            }
            if (ref==null)
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not known",
                                                      pElement);
            }
            else if (ref instanceof JList)
            {
                state= new SwingListSelectionState((JList)ref, index, reverseIndex);
            }
            else if (ref instanceof JTable)
            {
                state= new SwingListSelectionState((JTable)ref, index, reverseIndex);
            }
            else if (ref instanceof JComboBox)
            {
                state= new SwingListSelectionState((JComboBox)ref, index, reverseIndex);
            }
            else
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a JList/JTable/JComboBox",
                                                      pElement);
            }
        }
        else if ("listFill".equals(type))
        {
            Object ref= pBuilder.getComponentByAnyName(refId);
            int threshold = getThreshold(pElement);
            if (ref instanceof JList)
            {
                state= new SwingListModelFillState((JList)ref, threshold);
            }
            else
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a JList",
                                                      pElement);
            }
        }
        else if ("tableFill".equals(type))
        {
            Object ref= pBuilder.getComponentByAnyName(refId);
            int threshold = getThreshold(pElement);
            if (ref instanceof JTable)
            {
                state= new SwingTableModelFillState((JTable)ref, threshold);
            }
            else
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a JTable",
                                                      pElement);
            }
        }
        else if ("treeFill".equals(type))
        {
            Object ref= pBuilder.getComponentByAnyName(refId);
            int threshold = getThreshold(pElement);
            if (ref instanceof JTree)
            {
                state= new SwingTreeModelFillState(((JTree)ref).getModel(), false, threshold);
            }
            else
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a JTree",
                                                      pElement);
            }
        }
        else if ("collectionFill".equals(type))
        {
            Object ref= pBuilder.getNonVisualObject(refId);
            if (ref instanceof ValueModel)
            {
                state= new CollectionFilledState((ValueModel>)ref);
            }
            else
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a ValueModel",
                                                      pElement);
            }
        }
        else if ("treeSelection".equals(type))
        {
            Object ref= pBuilder.getComponentByAnyName(refId);
            if (ref instanceof JTree)
            {
                state= new SwingTreeSelectionState((JTree)ref);
            }
            else
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a JTree",
                                                      pElement);
            }
        }
        else if ("nullState".equals(type))
        {
            Object ref= pBuilder.getNonVisualObject(refId);
            if (ref instanceof ValueModel)
            {
                state = new NullState((ValueModel)ref);
            }
            else
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a ValueModel",
                                                                  pElement);
            }            
        }
        else if ("equals".equals(type))
        {
            Object ref    = pBuilder.getNonVisualObject(refId);
            String refId2 = pElement.getAttributeValue(SwingXMLBuilder.REF2_ATTRIBUTE);
            String value  = pElement.getAttributeValue(SwingXMLBuilder.VALUE_ATTRIBUTE);
            Object ref2   = pBuilder.getNonVisualObject(refId2);
            if (!(ref instanceof ValueModel))
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a ValueModel",
                                                                  pElement);
            }
            if (refId2!=null)
            {
                if (ref2 instanceof ValueModel)
                {
                    state = new EqualsState( (ValueModel)ref, (ValueModel)ref2);
                }
                else
                {
                    state = new EqualsState( (ValueModel)ref, ref2);
                }
            } 
            else
            {
                state = new EqualsState( (ValueModel)ref, value);
            }
        }
        else if ("regexp".equals(type))
        {
            Object ref    = pBuilder.getNonVisualObject(refId);
            String value  = pElement.getAttributeValue(SwingXMLBuilder.VALUE_ATTRIBUTE);
            if (!(ref instanceof ValueModel))
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a ValueModel",
                                                      pElement);
            }
            if (value==null)
            {
                throw SwingXMLBuilder.createException("selected state value must not be null", pElement);
            }
            state = new RegExpState( (ValueModel)ref, value);
        }
        else if ("minmax".equals(type))
        {
            Object ref     = pBuilder.getNonVisualObject(refId);
            String minValue= pElement.getAttributeValue(SwingXMLBuilder.MIN_ATTRIBUTE);
            String maxValue= pElement.getAttributeValue(SwingXMLBuilder.MAX_ATTRIBUTE);
            String inverted= pElement.getAttributeValue(SwingXMLBuilder.INVERT_ATTRIBUTE);
            if (!(ref instanceof ValueModel))
            {
                throw SwingXMLBuilder.createException("selected state ref ("+refId+") is not a ValueModel",
                                                      pElement);
            }
            if (minValue==null && maxValue==null)
            {
                throw SwingXMLBuilder.createException("either min or max must be set", pElement);
            }
            Integer minIntValue;
            try
            {
                minIntValue= (minValue!=null?Integer.parseInt(minValue):null);
            }
            catch (NumberFormatException e)
            {
                throw SwingXMLBuilder.createException("min value ("+minValue+") is not an integer",
                                                      pElement);
            }
            Integer maxIntValue;
            try
            {
                maxIntValue= (maxValue!=null?Integer.parseInt(maxValue):null);
            }
            catch (NumberFormatException e)
            {
                throw SwingXMLBuilder.createException("max value ("+maxValue+") is not an integer",
                                                      pElement);
            }

            state = new MinMaxState( (ValueModel)ref, minIntValue, maxIntValue, Boolean.valueOf(inverted));
        }

        if (state==null)
        {
            throw SwingXMLBuilder.createException("unknown state type "+type, pElement);
        }
        state.setName(pId);
        return state;
    }

    /**
     * Small helper to extract the threshold from the REF2 attribute.
     * @param pElement the element we check, must not be null
     * @return the threshold or 1 if no one is defined
     */
    private int getThreshold(Element pElement)
    {
        int threshold= 1;
        String refId2 = pElement.getAttributeValue(SwingXMLBuilder.REF2_ATTRIBUTE);
        if (refId2!=null)
        {
            try
            {
                threshold= Integer.parseInt(refId2);
            }
            catch (NumberFormatException e)
            {
                throw SwingXMLBuilder.createException("ref2 threshold ("+refId2+") is not an integer",
                                                      pElement);
            }
        }
        return threshold;
    }

    /**
     * Creates a new state expression.
     * @param pElement element describing the object
     * @param pId value of the id attribute of pElement
     * @param pBuilder our builder
     * @throws IllegalArgumentException if we have a problem (parameters, ...)
     * @return the new state expression, never null
     */
    private Object createStateExpression(final Element pElement, final String pId, final SwingXMLBuilder pBuilder) throws IllegalArgumentException
    {
        if (pId==null)
            throw SwingXMLBuilder.createException("id of "+pElement.getName()+" must not be null", pElement);

        State           startState     = getState     (pElement, pBuilder, SwingXMLBuilder.REF_ATTRIBUTE);
        boolean         invert         = getInvertFlag(pElement);
        StateExpression stateExpression= new SimpleStateExpression(startState, invert);

        List conditions= pElement.getChildren();
        for (final Element element : conditions)
        {
            String  elementName= element.getName();
            State   state      = getState(element, pBuilder, SwingXMLBuilder.REF_ATTRIBUTE);
            invert             = getInvertFlag(element);
            if ("and".equals(elementName))
                stateExpression.and(state, invert);
            else if ("andNot".equals(elementName))
                stateExpression.andNot(state);
            else if ("or".equals(elementName))
                stateExpression.or(state, invert);
            else if ("orNot".equals(elementName))
                stateExpression.orNot(state);
            else if ("xor".equals(elementName))
                stateExpression.xor(state, invert);
            else if ("xorNot".equals(elementName))
                stateExpression.xorNot(state);
        }
        return stateExpression;
    }

    /**
     * Creates a new state adapter.
     * @param pElement element describing the object
     * @param pId value of the id attribute of pElement
     * @param pBuilder our builder
     * @throws IllegalArgumentException if we have a problem (parameters, ...)
     * @return the new state adapter, never null
     */
    private Object createStateAdapter(final Element pElement, final String pId, final SwingXMLBuilder pBuilder) throws IllegalArgumentException
    {
        // get needed attributes
        String  type  = pElement.getAttributeValue(SwingXMLBuilder.TYPE_ATTRIBUTE);
        State   state = getState(pElement, pBuilder, SwingXMLBuilder.REF_ATTRIBUTE);

        StateAdapter stateAdapter= null;
        if ("custom".equals(type))
        {
            Class customClass= SwingXMLBuilder.getClass(pElement);
            try
            {
                Class[]     params     = {State.class};
                Constructor constructor= customClass.getConstructor(params);
                Object[]       args       = {state};
                stateAdapter= (StateAdapter)constructor.newInstance(args);
            }
            catch (Exception e)
            {
                throw SwingXMLBuilder.createException("could not create StateAdapter for class "+customClass+
                                                      " with state argument "+state, e, pElement);
            }
        }
        else if ("editable".equals(type))
        {
            stateAdapter= new SwingEditableAdapter(state);
        }
        else if ("enabled".equals(type))
        {
            boolean deep= Boolean.valueOf(
                    pElement.getAttributeValue(SwingXMLBuilder.DEEP_ATTRIBUTE));
            boolean handleOpaque= Boolean.valueOf(
                    pElement.getAttributeValue(SwingXMLBuilder.OPAQUE_ATTRIBUTE));
            stateAdapter= new SwingEnabledAdapter(state, deep, handleOpaque);
        }
        else if ("tableEnabled".equals(type))
        {
            stateAdapter= new SwingJTableEnabledAdapter(state);
        }
        else if ("selected".equals(type))
        {
            stateAdapter= new SwingSelectedAdapter(state);
        }
        else if ("visible".equals(type))
        {
            stateAdapter= new SwingVisibleAdapter(state);
        }
        else if ("border".equals(type))
        {
            Border border= VisualBuilderDelegate.getBorder(pElement.getChild("border"));
            if (border==null)
                stateAdapter= new SwingBorderAdapter(state);
            else
                stateAdapter= new SwingBorderAdapter(state, border);
        }
        else if ("background".equals(type))
        {
            Color color= VisualBuilderDelegate.getColor(pElement, 0);
            if (color==null)
                stateAdapter= new SwingBackgroundAdapter(state);
            else
                stateAdapter= new SwingBackgroundAdapter(state, color);
        }

        if (stateAdapter==null)
        {
            throw SwingXMLBuilder.createException("unknown state adapter type "+type, pElement);
        }

        // attach all adaptees to the adapter
        List adaptees= pElement.getChildren(SwingXMLBuilder.ADAPTEE_ELEMENT);
        for (final Element element : adaptees)
        {
            String  id     = element.getAttributeValue(SwingXMLBuilder.REF_ATTRIBUTE);
            Object  adaptee= pBuilder.getComponentByAnyName(id);
            if (adaptee==null)
            {
                adaptee= pBuilder.getNonVisualObject(id);
            }
            if (adaptee==null)
            {
                throw SwingXMLBuilder.createException("unknown adaptee "+id, pElement);
            }

            boolean invert = getInvertFlag(element);
            stateAdapter.add(adaptee, invert);
        }

        if (pId!=null)
        {
            stateAdapter.setName(pId);
        }

        return stateAdapter;
    }

    /**
     * Checks the invert attribute.
     * @param pElement element describing the object
     * @return true if the invert attribute is available and is "true", false otherwise
     */
    private boolean getInvertFlag(final Element pElement)
    {
        boolean invert= false;
        if (pElement.getAttribute(SwingXMLBuilder.INVERT_ATTRIBUTE)!=null)
        {
            invert= "true".equals(
                    pElement.getAttributeValue(SwingXMLBuilder.INVERT_ATTRIBUTE));
        }
        return invert;
    }

    /**
     * Gets a state from the non visual map.
     * @param pElement element describing the object
     * @param pBuilder our builder
     * @param pAttributeName name of the id attribute
     * @throws IllegalArgumentException if we have a problem (parameters, ...)
     * @return the state, never null
     */
    private State getState(final Element pElement, final SwingXMLBuilder pBuilder, final String pAttributeName)
    {
        String  refId= pElement.getAttributeValue(pAttributeName);
        Object  ref  = pBuilder.getNonVisualObject(refId);
        if (!(ref instanceof State))
        {
            throw SwingXMLBuilder.createException("ref "+refId+" is no state", pElement);
        }
        return (State)ref;
    }

    /**
     * Sets a state to a value.
     * @param pElement element describing the object
     * @param pId value of the id attribute of pElement
     * @param pBuilder our builder
     * @throws IllegalArgumentException if we have a problem (parameters, ...)
     */
    private void setState(final Element pElement, final String pId, final SwingXMLBuilder pBuilder) throws IllegalArgumentException
    {
        Object ref= pBuilder.getNonVisualObject(pId);
        if (!(ref instanceof MutableState))
        {
            throw SwingXMLBuilder.createException("state "+pId+" is not a mutable state", pElement);
        }

        // get needed attributes
        String enabled= pElement.getAttributeValue(SwingXMLBuilder.ENABLED_ATTRIBUTE);

        MutableState mutableState= (MutableState)ref;
        mutableState.setEnabled("true".equals(enabled));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy