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