001 // Copyright 2007, 2008, 2009, 2011 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.tapestry5.corelib.components;
016
017 import org.apache.tapestry5.*;
018 import org.apache.tapestry5.annotations.*;
019 import org.apache.tapestry5.beaneditor.PropertyModel;
020 import org.apache.tapestry5.grid.ColumnSort;
021 import org.apache.tapestry5.grid.GridConstants;
022 import org.apache.tapestry5.grid.GridModel;
023 import org.apache.tapestry5.grid.GridSortModel;
024 import org.apache.tapestry5.internal.InternalConstants;
025 import org.apache.tapestry5.internal.TapestryInternalUtils;
026 import org.apache.tapestry5.ioc.Messages;
027 import org.apache.tapestry5.ioc.annotations.Inject;
028 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
029
030 import java.util.List;
031
032 /**
033 * Renders out the column headers for the grid, including links (where appropriate) to control column sorting.
034 *
035 * @tapestrydoc
036 */
037 @SupportsInformalParameters
038 @Events(InternalConstants.GRID_INPLACE_UPDATE + " (internal event)")
039 public class GridColumns
040 {
041 /**
042 * The object that provides access to bean and data models, which is typically the enclosing Grid component.
043 */
044 @Parameter(value = "componentResources.container")
045 private GridModel gridModel;
046
047 /**
048 * If true, then the CSS class on each <TH> element will be omitted, which can reduce the amount of output
049 * from the component overall by a considerable amount. Leave this as false, the default, when you are leveraging
050 * the CSS to customize the look and feel of particular columns.
051 */
052 @Parameter
053 private boolean lean;
054
055 /**
056 * Where to look for informal parameter Blocks used to override column headers. The default is to look for such
057 * overrides in the GridColumns component itself, but this is usually overridden.
058 */
059 @Parameter("this")
060 private PropertyOverrides overrides;
061
062 /**
063 * If not null, then each link is output as a link to update the specified zone.
064 */
065 @Parameter
066 private String zone;
067
068 @SuppressWarnings("unused")
069 @Component(
070 parameters = { "event=sort", "disabled=sortDisabled", "context=columnContext", "class=sortLinkClass",
071 "zone=inherit:zone" })
072 private EventLink sort, sort2;
073
074 @Inject
075 @Path("${" + ComponentParameterConstants.GRIDCOLUMNS_ASCENDING_ASSET + "}")
076 private Asset ascendingAsset;
077
078 @Inject
079 @Path("${" + ComponentParameterConstants.GRIDCOLUMNS_DESCENDING_ASSET + "}")
080 private Asset descendingAsset;
081
082 @Inject
083 @Path("${" + ComponentParameterConstants.GRIDCOLUMNS_SORTABLE_ASSET + "}")
084 private Asset sortableAsset;
085
086 @Inject
087 private Messages messages;
088
089 @Inject
090 private Block standardHeader;
091
092 /**
093 * Optional output parameter that stores the current column index.
094 */
095 @Parameter
096 @Property
097 private int index;
098
099 /**
100 * Caches the index of the last column.
101 */
102 private int lastColumnIndex;
103
104 @Property(write = false)
105 private PropertyModel columnModel;
106
107 @Inject
108 private ComponentResources resources;
109
110 void setupRender()
111 {
112 lastColumnIndex = gridModel.getDataModel().getPropertyNames().size() - 1;
113 }
114
115 public boolean isSortDisabled()
116 {
117 return !columnModel.isSortable();
118 }
119
120 public String getSortLinkClass()
121 {
122 switch (getSortForColumn())
123 {
124 case ASCENDING:
125 return GridConstants.SORT_ASCENDING_CLASS;
126
127 case DESCENDING:
128 return GridConstants.SORT_DESCENDING_CLASS;
129
130 default:
131 return null;
132 }
133 }
134
135 private ColumnSort getSortForColumn()
136 {
137 GridSortModel sortModel = gridModel.getSortModel();
138
139 String columnId = columnModel.getId();
140
141 return sortModel.getColumnSort(columnId);
142 }
143
144 public String getHeaderClass()
145 {
146 List<String> classes = CollectionFactory.newList();
147
148 if (!lean) classes.add(columnModel.getId());
149
150 String sort = getSortLinkClass();
151
152 if (sort != null) classes.add(sort);
153
154 if (index == 0) classes.add(GridConstants.FIRST_CLASS);
155
156 if (index == lastColumnIndex) classes.add(GridConstants.LAST_CLASS);
157
158 return TapestryInternalUtils.toClassAttributeValue(classes);
159 }
160
161 public boolean isActiveSortColumn()
162 {
163 return getSortForColumn() != ColumnSort.UNSORTED;
164 }
165
166 /**
167 * Normal, non-Ajax event handler.
168 */
169
170 void onSort(String columnId)
171 {
172 gridModel.getSortModel().updateSort(columnId);
173 }
174
175 /**
176 * Ajax event handler, which carries the zone id.
177 */
178 boolean onSort(String columnId, String zone)
179 {
180 onSort(columnId);
181
182 resources.triggerEvent(InternalConstants.GRID_INPLACE_UPDATE, new Object[] { zone }, null);
183
184 // Event is handled, don't trigger further event handler methods.
185
186 return true;
187 }
188
189 public Asset getIcon()
190 {
191 switch (getSortForColumn())
192 {
193 case ASCENDING:
194 return ascendingAsset;
195
196 case DESCENDING:
197 return descendingAsset;
198
199 default:
200 return sortableAsset;
201 }
202 }
203
204 public Object getColumnContext()
205 {
206 if (zone == null) return columnModel.getId();
207
208 return new Object[] { columnModel.getId(), zone };
209 }
210
211 public String getIconLabel()
212 {
213 switch (getSortForColumn())
214 {
215 case ASCENDING:
216 return messages.get("ascending");
217 case DESCENDING:
218 return messages.get("descending");
219 default:
220 return messages.get("sortable");
221 }
222 }
223
224 public List<String> getColumnNames()
225 {
226 return gridModel.getDataModel().getPropertyNames();
227 }
228
229
230 public void setColumnName(String columnName)
231 {
232 columnModel = gridModel.getDataModel().get(columnName);
233 }
234
235
236 public Block getBlockForColumn()
237 {
238 Block override = overrides.getOverrideBlock(columnModel.getId() + "Header");
239
240 if (override != null) return override;
241
242 return standardHeader;
243 }
244 }