001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.myfaces.tobago.component;
021
022 import org.apache.commons.logging.Log;
023 import org.apache.commons.logging.LogFactory;
024 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_COLUMNS;
025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SPAN_X;
026 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SPAN_Y;
027 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_BORDER;
028 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_CELLSPACING;
029 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_MARGIN;
030 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_MARGIN_BOTTOM;
031 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_MARGIN_LEFT;
032 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_MARGIN_RIGHT;
033 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_MARGIN_TOP;
034 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ROWS;
035 import org.apache.myfaces.tobago.util.LayoutUtil;
036
037 import javax.faces.component.UIComponent;
038 import javax.faces.context.FacesContext;
039 import javax.faces.el.ValueBinding;
040 import java.io.IOException;
041 import java.io.Serializable;
042 import java.util.ArrayList;
043 import java.util.List;
044
045 public class UIGridLayout extends UILayout {
046
047 private static final Log LOG = LogFactory.getLog(UIGridLayout.class);
048
049 public static final String COMPONENT_TYPE = "org.apache.myfaces.tobago.GridLayout";
050 public static final String COMPONENT_FAMILY = "org.apache.myfaces.tobago.GridLayout";
051
052 public static final Marker FREE = new Marker("free");
053 public static final String USED = "used";
054
055 private String border;
056 private String cellspacing;
057
058 private String margin;
059 private String marginTop;
060 private String marginRight;
061 private String marginBottom;
062 private String marginLeft;
063 private String columns;
064 private String rows;
065 private boolean ignoreFree;
066 private transient LayoutTokens columnLayout;
067 private transient LayoutTokens rowLayout;
068
069 private List<Row> layoutRows;
070
071 public LayoutTokens getRowLayout() {
072 if (rowLayout == null) {
073 rowLayout = LayoutTokens.parse(getRows());
074 }
075 return rowLayout;
076 }
077
078 public LayoutTokens getColumnLayout() {
079 if (columnLayout == null) {
080 columnLayout = LayoutTokens.parse(getColumns());
081 }
082 return columnLayout;
083 }
084
085 public String getMarginTop() {
086 if (marginTop != null) {
087 return marginTop;
088 }
089 ValueBinding vb = getValueBinding(ATTR_MARGIN_TOP);
090 if (vb != null) {
091 return (String) vb.getValue(getFacesContext());
092 } else {
093 return getMargin();
094 }
095 }
096
097 public String getMarginRight() {
098 if (marginRight != null) {
099 return marginRight;
100 }
101 ValueBinding vb = getValueBinding(ATTR_MARGIN_RIGHT);
102 if (vb != null) {
103 return (String) vb.getValue(getFacesContext());
104 } else {
105 return getMargin();
106 }
107 }
108
109 public String getMarginBottom() {
110 if (marginBottom != null) {
111 return marginBottom;
112 }
113 ValueBinding vb = getValueBinding(ATTR_MARGIN_BOTTOM);
114 if (vb != null) {
115 return (String) vb.getValue(getFacesContext());
116 } else {
117 return getMargin();
118 }
119 }
120
121 public String getMarginLeft() {
122 if (marginLeft != null) {
123 return marginLeft;
124 }
125 ValueBinding vb = getValueBinding(ATTR_MARGIN_LEFT);
126 if (vb != null) {
127 return (String) vb.getValue(getFacesContext());
128 } else {
129 return getMargin();
130 }
131 }
132
133 public String getMargin() {
134 if (margin != null) {
135 return margin;
136 }
137 ValueBinding vb = getValueBinding(ATTR_MARGIN);
138 if (vb != null) {
139 return (String) vb.getValue(getFacesContext());
140 } else {
141 return margin;
142 }
143 }
144
145 public String getRows() {
146 if (rows != null) {
147 return rows;
148 }
149 ValueBinding vb = getValueBinding(ATTR_ROWS);
150 if (vb != null) {
151 return (String) vb.getValue(getFacesContext());
152 } else {
153 return "1*";
154 }
155 }
156
157 public String getColumns() {
158 if (columns != null) {
159 return columns;
160 }
161 ValueBinding vb = getValueBinding(ATTR_COLUMNS);
162 if (vb != null) {
163 return (String) vb.getValue(getFacesContext());
164 } else {
165 return "1*";
166 }
167 }
168
169 public String getCellspacing() {
170 if (cellspacing != null) {
171 return cellspacing;
172 }
173 ValueBinding vb = getValueBinding(ATTR_CELLSPACING);
174 if (vb != null) {
175 return (String) vb.getValue(getFacesContext());
176 } else {
177 return cellspacing;
178 }
179 }
180
181 public String getBorder() {
182 if (border != null) {
183 return border;
184 }
185 ValueBinding vb = getValueBinding(ATTR_BORDER);
186 if (vb != null) {
187 return (String) vb.getValue(getFacesContext());
188 } else {
189 return border;
190 }
191 }
192
193 public void setBorder(String border) {
194 this.border = border;
195 }
196
197 public void setCellspacing(String cellspacing) {
198 this.cellspacing = cellspacing;
199 }
200
201 public void setMargin(String margin) {
202 this.margin = margin;
203 }
204
205 public void setMarginTop(String marginTop) {
206 this.marginTop = marginTop;
207 }
208
209 public void setMarginRight(String marginRight) {
210 this.marginRight = marginRight;
211 }
212
213 public void setMarginBottom(String marginBottom) {
214 this.marginBottom = marginBottom;
215 }
216
217 public void setMarginLeft(String marginLeft) {
218 this.marginLeft = marginLeft;
219 }
220
221 public void setColumns(String columns) {
222 this.columns = columns;
223 }
224
225 public void setRows(String rows) {
226 this.rows = rows;
227 }
228
229 public Object saveState(FacesContext context) {
230 clearRows();
231 // fix for jsf 1.1.01
232 columnLayout = null;
233 rowLayout = null;
234 Object[] saveState = new Object[10];
235 saveState[0] = super.saveState(context);
236 saveState[1] = rows;
237 saveState[2] = columns;
238 saveState[3] = margin;
239 saveState[4] = marginLeft;
240 saveState[5] = marginRight;
241 saveState[6] = marginTop;
242 saveState[7] = marginBottom;
243 saveState[8] = border;
244 saveState[9] = cellspacing;
245 return saveState;
246 }
247
248 public void restoreState(FacesContext context, Object savedState) {
249 Object[] values = (Object[]) savedState;
250 super.restoreState(context, values[0]);
251 rows = (String) values[1];
252 columns = (String) values[2];
253 margin = (String) values[3];
254 marginLeft = (String) values[4];
255 marginRight = (String) values[5];
256 marginTop = (String) values[6];
257 marginBottom = (String) values[7];
258 border = (String) values[8];
259 cellspacing = (String) values[9];
260 }
261
262 @Override
263 public String getFamily() {
264 return COMPONENT_FAMILY;
265 }
266
267 @Override
268 public boolean getRendersChildren() {
269 return false;
270 }
271
272 @Override
273 public void encodeChildren(FacesContext context)
274 throws IOException {
275 // do nothing here
276 }
277
278 @Override
279 public void encodeChildrenOfComponent(
280 FacesContext facesContext, UIComponent component) throws IOException {
281 super.encodeChildrenOfComponent(facesContext, component);
282 clearRows();
283 // fix for jsf 1.1.01
284 columnLayout = null;
285 rowLayout = null;
286 }
287
288 private void clearRows() {
289 layoutRows = null;
290 }
291
292 public int getColumnCount() {
293 return getColumnLayout().getSize();
294 }
295
296 public List<Row> ensureRows() {
297 if (layoutRows == null) {
298 layoutRows = createRows();
299 }
300 return layoutRows;
301 }
302
303 private List<Row> createRows() {
304 List<Row> rows = new ArrayList<Row>();
305 int columnCount = getColumnCount();
306 List<UIComponent> children
307 = LayoutUtil.addChildren(new ArrayList<UIComponent>(), getParent());
308
309 for (UIComponent component : children) {
310 int spanX = getSpanX(component);
311 int spanY = getSpanY(component);
312
313 int r = nextFreeRow(rows);
314 if (r == rows.size()) {
315 rows.add(new Row(columnCount));
316 }
317 int c = rows.get(r).nextFreeColumn();
318 rows.get(r).addControl(component, spanX);
319 rows.get(r).fill(c + 1, c + spanX, component.isRendered());
320
321 for (int i = r + 1; i < r + spanY; i++) {
322
323 if (i == rows.size()) {
324 rows.add(new Row(columnCount));
325 }
326 rows.get(i).fill(c, c + spanX, component.isRendered());
327 }
328 }
329 return rows;
330 }
331
332 private int nextFreeRow(List rows) {
333 int i = 0;
334 for (; i < rows.size(); i++) {
335 if (((Row) rows.get(i)).nextFreeColumn() != -1) {
336 return i;
337 }
338 }
339 return i;
340 }
341
342 public static int getSpanX(UIComponent component) {
343 return ComponentUtil.getIntAttribute(
344 component, ATTR_SPAN_X, 1);
345 }
346
347 public static int getSpanY(UIComponent component) {
348 return ComponentUtil.getIntAttribute(
349 component, ATTR_SPAN_Y, 1);
350 }
351
352 public boolean isIgnoreFree() {
353 return ignoreFree;
354 }
355
356 public void setIgnoreFree(boolean ignoreFree) {
357 this.ignoreFree = ignoreFree;
358 }
359
360 public static class Row implements Serializable {
361 private static final long serialVersionUID = 1511693677519052045L;
362 private int columns;
363 private List cells;
364 private boolean hidden;
365
366 public Row(int columns) {
367 setColumns(columns);
368 }
369
370 private void addControl(UIComponent component, int spanX) {
371
372 int i = nextFreeColumn();
373
374 cells.set(i, component);
375 fill(i + 1, i + spanX, component.isRendered());
376 }
377
378 private void fill(int start, int end, boolean rendered) {
379
380 if (end > columns) {
381 LOG.error("Error in Jsp (end > columns). "
382 + "Try to insert more spanX as possible.");
383 LOG.error("start: " + start);
384 LOG.error("end: " + end);
385 LOG.error("columns: " + columns);
386 LOG.error("Actual cells:");
387 for (Object component : cells) {
388 if (component instanceof UIComponent) {
389 LOG.error("Cell-ID: " + ((UIComponent) component).getId()
390 + " " + ((UIComponent) component).getRendererType());
391 } else {
392 LOG.error("Cell: " + component); // e.g. marker
393 }
394 }
395
396 end = columns; // fix the "end" parameter to continue the processing.
397 }
398
399 for (int i = start; i < end; i++) {
400 cells.set(i, new Marker(USED, rendered));
401 }
402 }
403
404 private int nextFreeColumn() {
405 for (int i = 0; i < columns; i++) {
406 if (FREE.equals(cells.get(i))) {
407 return i;
408 }
409 }
410 return -1;
411 }
412
413 public List getElements() {
414 return cells;
415 }
416
417 public int getColumns() {
418 return columns;
419 }
420
421 private void setColumns(int columns) {
422 this.columns = columns;
423 cells = new ArrayList(columns);
424 for (int i = 0; i < columns; i++) {
425 cells.add(FREE);
426 }
427 }
428
429 public boolean isHidden() {
430 return hidden;
431 }
432
433 public void setHidden(boolean hidden) {
434 this.hidden = hidden;
435 }
436 }
437
438 public static class Marker implements Serializable {
439 private static final long serialVersionUID = 2505999420762504893L;
440 private final String name;
441 private boolean rendered;
442
443 private Marker(String name) {
444 this.name = name;
445 }
446
447 public Marker(String name, boolean rendered) {
448 this.name = name;
449 this.rendered = rendered;
450 }
451
452 @Override
453 public String toString() {
454 return name;
455 }
456
457 public boolean isRendered() {
458 return rendered;
459 }
460 }
461 }