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 }