001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry.contrib.table.model.simple;
016
017import java.io.Serializable;
018import java.util.Comparator;
019
020import org.apache.tapestry.IComponent;
021import org.apache.tapestry.contrib.table.model.ITableRendererSource;
022import org.apache.tapestry.contrib.table.model.common.AbstractTableColumn;
023
024/**
025 * A simple minimal implementation of the
026 * {@link org.apache.tapestry.contrib.table.model.ITableColumn}interface that provides all the
027 * basic services for displaying a column.
028 * 
029 * @author mindbridge
030 */
031public class SimpleTableColumn extends AbstractTableColumn
032{
033        private static final long serialVersionUID = 1L;
034
035        // TODO: Unify SimpleTableColumnRendererSource and SimpleTableColumnFormRendererSource
036        // and implement the configuration with HiveMind
037        
038    public static final ITableRendererSource DEFAULT_COLUMN_RENDERER_SOURCE = new SimpleTableColumnRendererSource();
039
040    public static final ITableRendererSource FORM_COLUMN_RENDERER_SOURCE = new SimpleTableColumnFormRendererSource();
041
042    public static final ITableRendererSource DEFAULT_VALUE_RENDERER_SOURCE = new SimpleTableValueRendererSource();
043
044    private String m_strDisplayName;
045
046    private ITableColumnEvaluator m_objEvaluator;
047
048    /**
049     * Creates a SimpleTableColumn
050     * 
051     * @param strColumnName
052     *            the identifying name and display name of the column
053     */
054    public SimpleTableColumn(String strColumnName)
055    {
056        this(strColumnName, strColumnName);
057    }
058
059    /**
060     * Creates a SimpleTableColumn
061     * 
062     * @param strColumnName
063     *            the identifying name and display name of the column
064     * @param bSortable
065     *            whether the column is sortable
066     */
067    public SimpleTableColumn(String strColumnName, boolean bSortable)
068    {
069        this(strColumnName, strColumnName, bSortable);
070    }
071
072    /**
073     * Creates a SimpleTableColumn
074     * 
075     * @param strColumnName
076     *            the identifying name and display name of the column
077     * @param bSortable
078     *            whether the column is sortable
079     * @param objEvaluator
080     *            the evaluator to extract the column value from the row
081     */
082    public SimpleTableColumn(String strColumnName, ITableColumnEvaluator objEvaluator,
083            boolean bSortable)
084    {
085        this(strColumnName, strColumnName, objEvaluator, bSortable);
086    }
087
088    /**
089     * Creates a SimpleTableColumn
090     * 
091     * @param strColumnName
092     *            the identifying name of the column
093     * @param strDisplayName
094     *            the display name of the column
095     */
096    public SimpleTableColumn(String strColumnName, String strDisplayName)
097    {
098        this(strColumnName, strDisplayName, false);
099    }
100
101    /**
102     * Creates a SimpleTableColumn
103     * 
104     * @param strColumnName
105     *            the identifying name of the column
106     * @param strDisplayName
107     *            the display name of the column
108     * @param bSortable
109     *            whether the column is sortable
110     */
111    public SimpleTableColumn(String strColumnName, String strDisplayName, boolean bSortable)
112    {
113        this(strColumnName, strDisplayName, null, bSortable);
114    }
115
116    /**
117     * Creates a SimpleTableColumn
118     * 
119     * @param strColumnName
120     *            the identifying name of the column
121     * @param strDisplayName
122     *            the display name of the column
123     * @param bSortable
124     *            whether the column is sortable
125     * @param objEvaluator
126     *            the evaluator to extract the column value from the row
127     */
128    public SimpleTableColumn(String strColumnName, String strDisplayName,
129            ITableColumnEvaluator objEvaluator, boolean bSortable)
130    {
131        super(strColumnName, bSortable, null);
132        setComparator(new DefaultTableComparator());
133        setDisplayName(strDisplayName);
134        setColumnRendererSource(DEFAULT_COLUMN_RENDERER_SOURCE);
135        setValueRendererSource(DEFAULT_VALUE_RENDERER_SOURCE);
136        setEvaluator(objEvaluator);
137    }
138
139    /**
140     * Returns the display name of the column that will be used in the table header. Override for
141     * internationalization.
142     * 
143     * @return String the display name of the column
144     */
145    public String getDisplayName()
146    {
147        return m_strDisplayName;
148    }
149    
150    /**
151     * Sets the displayName.
152     * 
153     * @param displayName
154     *            The displayName to set
155     */
156    public void setDisplayName(String displayName)
157    {
158        m_strDisplayName = displayName;
159    }
160
161    /**
162     * Returns the evaluator.
163     * 
164     * @return ITableColumnEvaluator
165     */
166    public ITableColumnEvaluator getEvaluator()
167    {
168        return m_objEvaluator;
169    }
170
171    /**
172     * Sets the evaluator.
173     * 
174     * @param evaluator
175     *            The evaluator to set
176     */
177    public void setEvaluator(ITableColumnEvaluator evaluator)
178    {
179        m_objEvaluator = evaluator;
180    }
181
182    /**
183     * Sets a comparator that compares the values of this column rather than the objects
184     * representing the full rows. <br>
185     * This method allows easier use of standard comparators for sorting the column. It simply wraps
186     * the provided comparator with a row-to-column convertor and invokes the setComparator()
187     * method.
188     * 
189     * @param comparator
190     *            The column value comparator
191     */
192    public void setColumnComparator(Comparator comparator)
193    {
194        setComparator(new ColumnComparator(this, comparator));
195    }
196
197    /**
198     * Extracts the value of the column from the row object
199     * 
200     * @param objRow
201     *            the row object
202     * @return Object the column value
203     */
204    public Object getColumnValue(Object objRow)
205    {
206        ITableColumnEvaluator objEvaluator = getEvaluator();
207        if (objEvaluator != null)
208            return objEvaluator.getColumnValue(this, objRow);
209
210        // default fallback
211        return objRow.toString();
212    }
213
214    /**
215     * Use the column name to get the display name, as well as the column and value renderer sources
216     * from the provided component.
217     * 
218     * @param objSettingsContainer
219     *            the component from which to get the settings
220     */
221    public void loadSettings(IComponent objSettingsContainer)
222    {
223        String strDisplayName = objSettingsContainer.getMessages().getMessage(getColumnName());
224
225        // Hack! the Messages inteface needs to restore the getMessage(key, default), or needs
226        // to add a containsKey(key) method. Looking for the '[' used with invalid/unknown keys.
227
228        if (!strDisplayName.startsWith("["))
229            setDisplayName(strDisplayName);
230
231        super.loadSettings(objSettingsContainer);
232    }
233
234    public class DefaultTableComparator implements Comparator, Serializable
235    {
236        private static final long serialVersionUID = 1L;
237        
238        public int compare(Object objRow1, Object objRow2)
239        {
240            Object objValue1 = getColumnValue(objRow1);
241            Object objValue2 = getColumnValue(objRow2);
242
243            if (objValue1 == objValue2)
244                return 0;
245
246            boolean bComparable1 = objValue1 instanceof Comparable;
247            boolean bComparable2 = objValue2 instanceof Comparable;
248
249            // non-comparable values are considered equal
250            if (!bComparable1 && !bComparable2)
251                return 0;
252
253            // non-comparable values (null included) are considered smaller
254            // than the comparable ones
255            if (!bComparable1)
256                return -1;
257
258            if (!bComparable2)
259                return 1;
260
261            return ((Comparable) objValue1).compareTo(objValue2);
262        }
263    }
264
265}