Package com.alee.managers.style.data

Source Code of com.alee.managers.style.data.ComponentStyleConverter

/*
* This file is part of WebLookAndFeel library.
*
* WebLookAndFeel library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* WebLookAndFeel library 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WebLookAndFeel library.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.alee.managers.style.data;

import com.alee.managers.style.StyleException;
import com.alee.managers.style.SupportedComponent;
import com.alee.utils.ReflectUtils;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;

import java.lang.reflect.Method;
import java.util.*;

/**
* Custom XStream converter for ComponentStyle class.
*
* @author Mikle Garin
* @see <a href="https://github.com/mgarin/weblaf/wiki/How-to-use-StyleManager">How to use StyleManager</a>
* @see com.alee.managers.style.StyleManager
* @see com.alee.managers.style.data.ComponentStyle
*/

public class ComponentStyleConverter extends ReflectionConverter
{
    /**
     * Converter constants.
     */
    public static final String STYLE_NODE = "style";
    public static final String STYLE_ID_ATTRIBUTE = "id";
    public static final String COMPONENT_TYPE_ATTRIBUTE = "type";
    public static final String EXTENDS_ID_ATTRIBUTE = "extends";
    public static final String COMPONENT_NODE = "component";
    public static final String UI_NODE = "ui";
    public static final String PAINTER_NODE = "painter";
    public static final String PAINTER_ID_ATTRIBUTE = "id";
    public static final String PAINTER_CLASS_ATTRIBUTE = "class";
    public static final String IGNORED_ATTRIBUTE = "ignored";

    /**
     * Default component style ID.
     */
    public static final String DEFAULT_STYLE_ID = "default";

    /**
     * Constructs ComponentStyleConverter with the specified mapper and reflection provider.
     *
     * @param mapper             mapper
     * @param reflectionProvider reflection provider
     */
    public ComponentStyleConverter ( final Mapper mapper, final ReflectionProvider reflectionProvider )
    {
        super ( mapper, reflectionProvider );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean canConvert ( final Class type )
    {
        return type.equals ( ComponentStyle.class );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void marshal ( final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context )
    {
        final ComponentStyle componentStyle = ( ComponentStyle ) source;

        // Component style ID
        final String componentStyleId = componentStyle.getId ();
        writer.addAttribute ( STYLE_ID_ATTRIBUTE, componentStyleId != null ? componentStyleId : DEFAULT_STYLE_ID );

        // Style component type
        writer.addAttribute ( COMPONENT_TYPE_ATTRIBUTE, componentStyle.getType ().toString () );

        // Extended style ID
        final String extendsId = componentStyle.getExtendsId ();
        if ( extendsId != null )
        {
            writer.addAttribute ( EXTENDS_ID_ATTRIBUTE, extendsId );
        }

        // Component properties
        final Map<String, Object> componentProperties = componentStyle.getComponentProperties ();
        if ( componentProperties != null )
        {
            writer.startNode ( COMPONENT_NODE );
            for ( final Map.Entry<String, Object> property : componentProperties.entrySet () )
            {
                writer.startNode ( property.getKey () );
                context.convertAnother ( property.getValue () );
                writer.endNode ();
            }
            writer.endNode ();
        }

        // UI properties
        final Map<String, Object> uiProperties = componentStyle.getUIProperties ();
        if ( uiProperties != null )
        {
            writer.startNode ( UI_NODE );
            for ( final Map.Entry<String, Object> property : uiProperties.entrySet () )
            {
                writer.startNode ( property.getKey () );
                context.convertAnother ( property.getValue () );
                writer.endNode ();
            }
            writer.endNode ();
        }

        // Painters
        final List<PainterStyle> painters = componentStyle.getPainters ();
        if ( painters != null )
        {
            for ( final PainterStyle painterStyle : painters )
            {
                writer.startNode ( PAINTER_NODE );
                writer.addAttribute ( PAINTER_ID_ATTRIBUTE, painterStyle.getId () );
                writer.addAttribute ( PAINTER_CLASS_ATTRIBUTE, painterStyle.getPainterClass () );
                for ( final Map.Entry<String, Object> property : painterStyle.getProperties ().entrySet () )
                {
                    writer.startNode ( property.getKey () );
                    context.convertAnother ( property.getValue () );
                    writer.endNode ();
                }
                writer.endNode ();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Object unmarshal ( final HierarchicalStreamReader reader, final UnmarshallingContext context )
    {
        // Creating component style
        final ComponentStyle componentStyle = new ComponentStyle ();

        // Reading style ID
        final String componentStyleId = reader.getAttribute ( STYLE_ID_ATTRIBUTE );
        componentStyle.setId ( componentStyleId != null ? componentStyleId : DEFAULT_STYLE_ID );

        // Reading style component type
        final SupportedComponent type = SupportedComponent.valueOf ( reader.getAttribute ( COMPONENT_TYPE_ATTRIBUTE ) );
        componentStyle.setType ( type );

        // Reading extended style ID
        componentStyle.setExtendsId ( reader.getAttribute ( EXTENDS_ID_ATTRIBUTE ) );

        // Reading component style properties and painters
        // Using LinkedHashMap to keep properties order intact
        final Map<String, Object> componentProperties = new LinkedHashMap<String, Object> ();
        final Map<String, Object> uiProperties = new LinkedHashMap<String, Object> ();
        final List<PainterStyle> painters = new ArrayList<PainterStyle> ();
        while ( reader.hasMoreChildren () )
        {
            // Read next node
            reader.moveDown ();
            final String nodeName = reader.getNodeName ();
            if ( nodeName.equals ( COMPONENT_NODE ) )
            {
                // Reading component property
                final Class componentClass = type.getComponentClass ();
                while ( reader.hasMoreChildren () )
                {
                    reader.moveDown ();
                    final String propName = reader.getNodeName ();
                    readProperty ( reader, context, componentStyleId, componentProperties, componentClass, propName );
                    reader.moveUp ();
                }
            }
            else if ( nodeName.equals ( UI_NODE ) )
            {
                // Reading UI property
                final Class uiClass = type.getUIClass ();
                while ( reader.hasMoreChildren () )
                {
                    reader.moveDown ();
                    final String propName = reader.getNodeName ();
                    readProperty ( reader, context, componentStyleId, uiProperties, uiClass, propName );
                    reader.moveUp ();
                }
            }
            else if ( nodeName.equals ( PAINTER_NODE ) )
            {
                // Collecting style IDs
                final String indicesString = reader.getAttribute ( PAINTER_ID_ATTRIBUTE );
                final List<String> indices = new ArrayList<String> ( 1 );
                if ( indicesString.contains ( "," ) )
                {
                    final StringTokenizer st = new StringTokenizer ( indicesString, ",", false );
                    while ( st.hasMoreTokens () )
                    {
                        indices.add ( st.nextToken () );
                    }
                }
                else
                {
                    indices.add ( indicesString );
                }

                // Creating separate painter styles for each style ID
                // This might be the case when the same style scheme applied to more than one painter
                final String painterClassName = reader.getAttribute ( PAINTER_CLASS_ATTRIBUTE );
                final List<PainterStyle> separateStyles = new ArrayList<PainterStyle> ( indices.size () );
                for ( final String id : indices )
                {
                    final PainterStyle painterStyle = new PainterStyle ();
                    painterStyle.setId ( id );
                    painterStyle.setPainterClass ( painterClassName );
                    separateStyles.add ( painterStyle );
                }
                context.put ( PAINTER_CLASS_ATTRIBUTE, painterClassName );

                // Reading painter style properties
                // Using LinkedHashMap to keep properties order
                final Map<String, Object> painterProperties = new LinkedHashMap<String, Object> ();
                final Class painterClass = ReflectUtils.getClassSafely ( painterClassName );
                if ( painterClass != null )
                {
                    while ( reader.hasMoreChildren () )
                    {
                        reader.moveDown ();
                        final String propName = reader.getNodeName ();
                        readProperty ( reader, context, componentStyleId, painterProperties, painterClass, propName );
                        reader.moveUp ();
                    }
                }
                for ( final PainterStyle painterStyle : separateStyles )
                {
                    painterStyle.setProperties ( painterProperties );
                }

                // Adding read painter style
                painters.addAll ( separateStyles );
            }
            reader.moveUp ();
        }

        // Marking base painter
        if ( componentStyle.getExtendsId () == null )
        {
            if ( painters.size () == 1 )
            {
                painters.get ( 0 ).setBase ( true );
            }
            else
            {
                boolean baseSet = false;
                for ( final PainterStyle painter : painters )
                {
                    if ( painter.isBase () )
                    {
                        baseSet = true;
                        break;
                    }
                }
                if ( !baseSet && painters.size () > 0 )
                {
                    painters.get ( 0 ).setBase ( true );
                }
            }
        }

        // Updating values we have just read
        componentStyle.setComponentProperties ( componentProperties );
        componentStyle.setUIProperties ( uiProperties );
        componentStyle.setPainters ( painters );

        return componentStyle;
    }

    /**
     * Parses single style property into properties map.
     *
     * @param reader           hierarchical stream reader
     * @param context          unmarshalling context
     * @param componentStyleId component style ID
     * @param properties       properties
     * @param propertyClass    property class
     * @param propertyName     property name
     */
    protected void readProperty ( final HierarchicalStreamReader reader, final UnmarshallingContext context, final String componentStyleId,
                                  final Map<String, Object> properties, final Class propertyClass, final String propertyName )
    {
        final String ignored = reader.getAttribute ( IGNORED_ATTRIBUTE );
        if ( ignored != null && Boolean.parseBoolean ( ignored ) )
        {
            properties.put ( propertyName, IgnoredValue.VALUE );
        }
        else
        {
            final Class fieldClass = ReflectUtils.getFieldTypeSafely ( propertyClass, propertyName );
            if ( fieldClass != null )
            {
                properties.put ( propertyName, context.convertAnother ( properties, fieldClass ) );
            }
            else
            {
                final Method getter = ReflectUtils.getFieldGetter ( propertyClass, propertyName );
                if ( getter != null )
                {
                    final Class<?> rClass = getter.getReturnType ();
                    properties.put ( propertyName, context.convertAnother ( properties, rClass ) );
                }
                else
                {
                    throw new StyleException ( "Component property \"" + propertyName + "\" type from style \"" + componentStyleId +
                            "\" cannot be determined! Make sure it points to existing field or getter method." );
                }
            }
        }
    }
}
TOP

Related Classes of com.alee.managers.style.data.ComponentStyleConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.