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 }