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