001// Copyright 2007-2013 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.tapestry5.corelib.components; 016 017import org.apache.tapestry5.Block; 018import org.apache.tapestry5.ComponentResources; 019import org.apache.tapestry5.MarkupWriter; 020import org.apache.tapestry5.PropertyOverrides; 021import org.apache.tapestry5.annotations.*; 022import org.apache.tapestry5.beanmodel.PropertyModel; 023import org.apache.tapestry5.commons.Messages; 024import org.apache.tapestry5.grid.ColumnSort; 025import org.apache.tapestry5.grid.GridModel; 026import org.apache.tapestry5.grid.GridSortModel; 027import org.apache.tapestry5.http.services.Request; 028import org.apache.tapestry5.internal.InternalConstants; 029import org.apache.tapestry5.ioc.annotations.Inject; 030 031import java.util.List; 032 033/** 034 * Renders out the column headers for the grid, including links (where appropriate) to control column sorting. 035 * 036 * @tapestrydoc 037 */ 038@SupportsInformalParameters 039@Events(InternalConstants.GRID_INPLACE_UPDATE + " (internal event)") 040public class GridColumns 041{ 042 /** 043 * The object that provides access to bean and data models, which is typically the enclosing Grid component. 044 */ 045 @Parameter(value = "componentResources.container") 046 private GridModel gridModel; 047 048 /** 049 * If true, then the CSS class on each <TH> element will be omitted, which can reduce the amount of output 050 * from the component overall by a considerable amount. Leave this as false, the default, when you are leveraging 051 * the CSS to customize the look and feel of particular columns. 052 */ 053 @Parameter 054 private boolean lean; 055 056 /** 057 * Where to look for informal parameter Blocks used to override column headers. The default is to look for such 058 * overrides in the GridColumns component itself, but this is usually overridden. 059 */ 060 @Parameter("this") 061 private PropertyOverrides overrides; 062 063 /** 064 * If not null, then each link is output as a link to update the specified zone. 065 */ 066 @Parameter 067 private String zone; 068 069 @SuppressWarnings("unused") 070 @Component( 071 parameters = {"event=sort", "disabled=sortDisabled", "context=columnModel.id", "zone=inherit:zone"}) 072 private EventLink sort; 073 074 @Inject 075 private Messages messages; 076 077 @Inject 078 private Block standardHeader; 079 080 /** 081 * Optional output parameter that stores the current column index. 082 */ 083 @Parameter 084 @Property 085 private int index; 086 087 /** 088 * Caches the index of the last column. 089 */ 090 private int lastColumnIndex; 091 092 @Property(write = false) 093 private PropertyModel columnModel; 094 095 @Inject 096 private ComponentResources resources; 097 098 @Inject 099 private Request request; 100 101 void setupRender() 102 { 103 lastColumnIndex = gridModel.getDataModel().getPropertyNames().size() - 1; 104 } 105 106 public boolean isSortDisabled() 107 { 108 return !columnModel.isSortable(); 109 } 110 111 private ColumnSort getSortForColumn() 112 { 113 GridSortModel sortModel = gridModel.getSortModel(); 114 115 String columnId = columnModel.getId(); 116 117 return sortModel.getColumnSort(columnId); 118 } 119 120 void onBeginRenderFromLoop(MarkupWriter writer) { 121 122 if (!lean) { 123 writer.attributes("data-grid-property", columnModel.getId()); 124 } 125 if(!isSortDisabled()){ 126 switch (getSortForColumn()) 127 { 128 case ASCENDING: 129 writer.attributes("data-grid-column-sort", "ascending"); 130 break; 131 132 case DESCENDING: 133 writer.attributes("data-grid-column-sort", "descending"); 134 default: 135 writer.attributes("data-grid-column-sort", "sortable"); 136 } 137 } 138 139 if (index == 0) { 140 writer.attributes("data-grid-column", "first"); 141 } 142 143 if (index == lastColumnIndex) { 144 writer.attributes("data-grid-column", "last"); 145 } 146 } 147 148 public boolean isActiveSortColumn() 149 { 150 return getSortForColumn() != ColumnSort.UNSORTED; 151 } 152 153 /** 154 * Normal, non-Ajax event handler. 155 */ 156 157 boolean onSort(String columnId) 158 { 159 gridModel.getSortModel().updateSort(columnId); 160 161 if (request.isXHR()) 162 { 163 resources.triggerEvent(InternalConstants.GRID_INPLACE_UPDATE, null, null); 164 } 165 166 return true; 167 } 168 169 170 public List<String> getColumnNames() 171 { 172 return gridModel.getDataModel().getPropertyNames(); 173 } 174 175 176 public void setColumnName(String columnName) 177 { 178 columnModel = gridModel.getDataModel().get(columnName); 179 } 180 181 182 public Block getBlockForColumn() 183 { 184 Block override = overrides.getOverrideBlock(columnModel.getId() + "Header"); 185 186 if (override != null) return override; 187 188 return standardHeader; 189 } 190 191 /** 192 * Returns null or "true", depending on whether the Grid is rendering for in-place updates or not ("true" 193 * means in-place updates). The affects whether the data-inplace-grid-links attribute will be rendered or not. 194 * 195 */ 196 public String getInplaceGridLinks() 197 { 198 return zone == null ? null : "true"; 199 } 200}