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