swingx-master/swingx-core/src/main/java/org/jdesktop/swingx/plaf/synth/SynthXListUI.java
/*
 * $Id$
 *
 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 * 
 * This 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdesktop.swingx.plaf.synth;

import java.awt.Color;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.synth.ColorType;
import javax.swing.plaf.synth.Region;
import javax.swing.plaf.synth.SynthConstants;
import javax.swing.plaf.synth.SynthContext;
import javax.swing.plaf.synth.SynthLookAndFeel;
import javax.swing.plaf.synth.SynthStyle;

import org.jdesktop.swingx.SwingXUtilities;
import org.jdesktop.swingx.plaf.basic.core.BasicXListUI;

/**
 * TODO add type doc
 * 
 * @author Jeanette Winzenburg
 */
public class SynthXListUI extends BasicXListUI 
    // PENDING JW: SynthUI is sun package (here: used by c&p'ed SynthBorder) - replace?
    // maybe not: SynthLookUp looks up styles from delegates of type SynthUI only
    implements SynthConstants,  SynthUI  /*, PropertyChangeListener */{

    private SynthStyle style;
    @SuppressWarnings("unused")
    private boolean useListColors;
    @SuppressWarnings("unused")
    private boolean useUIBorder;

    /**
     * Returns a new instance of SynthXListUI.  SynthXListUI delegates are
     * allocated one per JList.
     *
     * @return A new ListUI implementation for the Synth look and feel.
     */
    public static ComponentUI createUI(JComponent list) {
        return new SynthXListUI();
    }

    /**
     * {@inheritDoc} <p>
     * Overridden to fill background, Synth-style.
     */
    @Override
    public void update(Graphics g, JComponent c) {
        SynthContext context = getContext(c);
        SynthUtils.update(context, g);
        paintBorder(context, g, 0, 0, c.getWidth(), c.getHeight());
        paint(g, c);
    }


    /**
     * {@inheritDoc} <p>
     * Overridden to update style if appropriate.
     */
    @Override
    protected PropertyChangeListener createPropertyChangeListener() {
        PropertyChangeListener l = new PropertyChangeHandler() {

            @Override
            public void propertyChange(PropertyChangeEvent e) {
                if (SynthUtils.shouldUpdateStyle(e)) {
                    updateStyle();
                }
                super.propertyChange(e);
            }
            
        };
        return l;
    }

    /**
     * {@inheritDoc} <p>
     * Overridden to install properties, Synth-style.
     */
    @Override
    protected void installDefaults() {
        // never happens - the delegate renderer is always not-null and
        // not a ui-resource
//        if (list.getCellRenderer() == null ||
//                 (list.getCellRenderer() instanceof UIResource)) {
//            list.setCellRenderer(new SynthListCellRenderer());
//        }
        updateStyle();
    }

    private void updateStyle() {
        // compare local reference to style from factory
        // nothing to do if same
        if (style == getStyle()) return;
        // check if this is called from init or from later update
        // if from later updates, need to cleanup old
        boolean refresh = style != null;
        if (refresh) {
            style.uninstallDefaults(getContext(ENABLED));
        }
        // update local reference
        style = getStyle();
        // special case border
        installSynthBorder();
        // install defaults 
        style.installDefaults(getContext(ENABLED));
        // install selected properties
        SynthContext selectedContext = getContext(SELECTED);
        Color sbg = list.getSelectionBackground();
        if (sbg == null || sbg instanceof UIResource) {
            list.setSelectionBackground(style.getColor(
                    selectedContext, ColorType.TEXT_BACKGROUND));
        }
        
        Color sfg = list.getSelectionForeground();
        if (sfg == null || sfg instanceof UIResource) {
            list.setSelectionForeground(style.getColor(
                    selectedContext, ColorType.TEXT_FOREGROUND));
        }
        // install cell height
        int height = style.getInt(selectedContext, "List.cellHeight", -1);
        if (height != -1) {
            list.setFixedCellHeight(height);
        }
        // we do this because ... ??
        if (refresh) {
            uninstallKeyboardActions();
            installKeyboardActions();
        }
        // install currently unused properties of this delegate
        useListColors = style.getBoolean(selectedContext,
                "List.rendererUseListColors", true);
        useUIBorder = style.getBoolean(selectedContext,
                "List.rendererUseUIBorder", true);
        
    }

    /**
     * Installs a SynthBorder from the current style, if ui-installable.
     * 
     * @param context the context 
     */
    protected void installSynthBorder() {
        if (SwingXUtilities.isUIInstallable(list.getBorder())) {
            list.setBorder(new SynthBorder(this, style.getInsets(getContext(ENABLED), null)));
        }
    }

    /**
     * {@inheritDoc} <p>
     * Overridden to uninstall properties, Synth-style, after calling super.
     */
    @Override
    protected void uninstallDefaults() {
        super.uninstallDefaults();
        style.uninstallDefaults(getContext(ENABLED));
        style = null;
    }

    
    /**
     * Paints border with the context's style's painter.
     * Implemented for SynthUI interface.
     */
    @Override
    public void paintBorder(SynthContext context, Graphics g, int x, int y,
            int w, int h) {
        SynthUtils.getPainter(context).paintListBorder(context, g, x, y, w, h);
    }

    /**
     * {@inheritDoc} <p>
     * 
     * Returns a context for the component's current state.
     * Implemented for SynthUI interface. <p>
     * 
     * PENDING JW: not entirely sure if allowed ... but need to replace SynthUI anyway?.
     * 
     * @throws IllegalArgumentException if the component is not controlled by this 
     *    delegate
     */
    @Override
    public SynthContext getContext(JComponent c) {
        if (c != list) throw new IllegalArgumentException("must be ui-delegate for component");
        return getContext();
    }

    /**
     * Returns the context based on current state.
     * @return
     */
    private SynthContext getContext() {
        return getContext(getComponentState());
    }
    
    /**
     * Returns the current component state for the controlled list.
     * @return
     */
    private int getComponentState() {
        return SynthUtils.getComponentState(list);
    }

    /**
     * Returns a Context with the given component state.
     * 
     * @param state
     * @return
     */
    private SynthContext getContext(int state) {
        return SynthUtils.getContext(list, getRegion(), style, state);
    }
    
    private Region getRegion() {
        return XRegion.getXRegion(list, true);
    }


    /**
     * Returns the style for this component from the style factory.
     * @return
     */
    private SynthStyle getStyle() {
        return SynthLookAndFeel.getStyleFactory().getStyle(list, getRegion());
    }


//    private class SynthListCellRenderer extends DefaultListCellRenderer.UIResource {
//        public String getName() {
//            return "List.cellRenderer";
//        }
//
//        public void setBorder(Border b) {
//            if (useUIBorder || b instanceof SynthBorder) {
//                super.setBorder(b);
//            }
//        }
//
//        public Component getListCellRendererComponent(JList list, Object value,
//                  int index, boolean isSelected, boolean cellHasFocus) {
//            if (!useListColors && (isSelected || cellHasFocus)) {
//                SynthLookAndFeel.setSelectedUI((SynthLabelUI)SynthLookAndFeel.
//                             getUIOfType(getUI(), SynthLabelUI.class),
//                                   isSelected, cellHasFocus, list.isEnabled(), false);
//            }
//            else {
//                SynthLookAndFeel.resetSelectedUI();
//            }
//            
//            super.getListCellRendererComponent(list, value, index,
//                                               isSelected, cellHasFocus);
//            return this;
//        }
//
//        public void paint(Graphics g) {
//            super.paint(g);
//            SynthLookAndFeel.resetSelectedUI();
//        }
//    }


}
