001/*
002 * $Id$
003 *
004 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 * 
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 * Lesser General Public License for more details.
016 * 
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020 *
021 */
022package org.jdesktop.swingx.sort;
023
024import java.util.HashMap;
025import java.util.Map;
026import java.util.logging.Logger;
027
028import org.jdesktop.swingx.renderer.StringValue;
029import org.jdesktop.swingx.renderer.StringValues;
030
031/**
032 * A writable implemenation of StringValueProvider. Typically, this is created and
033 * maintained by a collection view and then passed over to interested parties. It is
034 * modeled/implemented after the default renderer maintenance in a JTable.<p>
035 * 
036 * PENDING JW: for safety - better not implement but return a provider. We probably don't want 
037 * readers to frickle around here?.
038 * 
039 * @author Jeanette Winzenburg
040 */
041public final class StringValueRegistry implements StringValueProvider {
042
043    @SuppressWarnings("unused")
044    private static final Logger LOG = Logger
045            .getLogger(StringValueRegistry.class.getName());
046    
047    private Map<Class<?>, StringValue> perClass;
048    private HashMap<Integer, StringValue> perColumn;
049    private HashMap<Integer, Class<?>> classPerColumn;
050    
051    /**
052     * {@inheritDoc} <p>
053     */
054    @Override
055    public StringValue getStringValue(int row, int column) {
056        StringValue sv = getPerColumnMap().get(column);
057        if (sv == null) {
058            sv = getStringValueByClass(getClass(row, column));
059        }
060        if (sv == null) {
061            sv = getStringValueByClass(Object.class);
062        }
063        return sv != null ? sv : StringValues.TO_STRING;
064    }
065
066//-------------------- manage     
067    /**
068     * Sets a StringValue to use for the given column. If the converter is null,
069     * the mapping is removed.
070     * 
071     * @param sv the StringValue to use for the given column.
072     * @param column the column index in model coordinates.
073     * 
074     */
075    public void setStringValue(StringValue sv, int column) {
076        // PENDING really remove mapping if sv null
077        getPerColumnMap().put(column, sv);
078    }
079
080    /**
081     * Removes all per-column mappings of StringValues.
082     * 
083     */
084    public void clearColumnStringValues() {
085        getPerColumnMap().clear();
086    }
087    
088    /**
089     * Sets the StringValue to use for the given class. If the converter is null,
090     * the mapping is removed.
091     * 
092     * @param sv the StringValue to use for the given column.
093     * @param clazz the class 
094     */
095    public void setStringValue(StringValue sv, Class<?> clazz) {
096        // PENDING really remove mapping if sv null
097        getPerClassMap().put(clazz, sv);
098    }
099    
100    /**
101     * Returns the StringValue registered for the given class. <p>
102     * 
103     * <b>This is temporarily exposed for testing only - do not use, it will
104     * be removed very soon!</b>
105     * 
106     * @param clazz the class to find the registered StringValue for
107     * @return the StringValue registered for the class, or null if not directly
108     *   registered.
109     */
110    public StringValue getStringValue(Class<?> clazz) {
111        return getPerClassMap().get(clazz);
112    }
113    /**
114     * Sets the column class.
115     * 
116     * @param clazz 
117     * @param column index in model coordinates
118     */
119    public void setColumnClass(Class<?> clazz, int column) {
120        getColumnClassMap().put(column, clazz);
121    }
122    
123    /**
124     * @param classPerColumn
125     */
126    public void setColumnClasses(Map<Integer, Class<?>> classPerColumn) {
127        this.classPerColumn = classPerColumn != null ? 
128                new HashMap<Integer, Class<?>>(classPerColumn) : null;
129    }
130
131    /**
132     * 
133     * @param clazz
134     * @return
135     */
136    private StringValue getStringValueByClass(Class<?> clazz) {
137        if (clazz == null) return null;
138        StringValue sv = getPerClassMap().get(clazz);
139        if (sv != null) return sv;
140        return getStringValueByClass(clazz.getSuperclass());
141    }
142
143    /**
144     * Returns the Class of the column.
145     * 
146     * @param row
147     * @param column
148     * @return
149     */
150    private Class<?> getClass(int row, int column) {
151        Class<?> clazz = getColumnClassMap().get(column);
152        return clazz != null ? clazz : Object.class;
153    }
154
155    /**
156     * Returns the Map which stores the per-column Class, lazily 
157     * creates one if null.
158     * 
159     * @return the per-column storage map of Class
160     */
161     private Map<Integer, Class<?>> getColumnClassMap() {
162         if (classPerColumn == null) {
163             classPerColumn = new HashMap<Integer, Class<?>>();
164         }
165         return classPerColumn;
166     }
167
168     /**
169     * Returns the Map which stores the per-class StringValues, lazily 
170     * creates one if null.
171     * 
172     * @return the per-class storage map of StringValues
173     */
174    private Map<Class<?>, StringValue> getPerClassMap() {
175        if (perClass == null) {
176            perClass = new HashMap<Class<?>, StringValue>();
177        }
178        return perClass;
179    }
180
181    /**
182     * Returns the Map which stores the per-column StringValues, lazily 
183     * creates one if null.
184     * 
185     * @return the per-column storage map of StringValues
186     */
187    private Map<Integer, StringValue> getPerColumnMap() {
188        if (perColumn == null) {
189            perColumn = new HashMap<Integer, StringValue>();
190        }
191        return perColumn;
192    }
193}