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 // fix for jsf 1.1.01 230 columnLayout = null; 231 rowLayout = null; 232 Object[] saveState = new Object[10]; 233 saveState[0] = super.saveState(context); 234 saveState[1] = rows; 235 saveState[2] = columns; 236 saveState[3] = margin; 237 saveState[4] = marginLeft; 238 saveState[5] = marginRight; 239 saveState[6] = marginTop; 240 saveState[7] = marginBottom; 241 saveState[8] = border; 242 saveState[9] = cellspacing; 243 return saveState; 244 } 245 246 public void restoreState(FacesContext context, Object savedState) { 247 Object[] values = (Object[]) savedState; 248 super.restoreState(context, values[0]); 249 rows = (String) values[1]; 250 columns = (String) values[2]; 251 margin = (String) values[3]; 252 marginLeft = (String) values[4]; 253 marginRight = (String) values[5]; 254 marginTop = (String) values[6]; 255 marginBottom = (String) values[7]; 256 border = (String) values[8]; 257 cellspacing = (String) values[9]; 258 } 259 260 @Override 261 public String getFamily() { 262 return COMPONENT_FAMILY; 263 } 264 265 @Override 266 public boolean getRendersChildren() { 267 return false; 268 } 269 270 @Override 271 public void encodeChildren(FacesContext context) 272 throws IOException { 273 // do nothing here 274 } 275 276 @Override 277 public void encodeChildrenOfComponent( 278 FacesContext facesContext, UIComponent component) throws IOException { 279 super.encodeChildrenOfComponent(facesContext, component); 280 clearRows(); 281 // fix for jsf 1.1.01 282 columnLayout = null; 283 rowLayout = null; 284 } 285 286 private void clearRows() { 287 layoutRows = null; 288 } 289 290 public int getColumnCount() { 291 return getColumnLayout().getSize(); 292 } 293 294 public List<Row> ensureRows() { 295 if (layoutRows == null) { 296 layoutRows = createRows(); 297 } 298 return layoutRows; 299 } 300 301 private List<Row> createRows() { 302 List<Row> rows = new ArrayList<Row>(); 303 int columnCount = getColumnCount(); 304 List<UIComponent> children 305 = LayoutUtil.addChildren(new ArrayList<UIComponent>(), getParent()); 306 307 for (UIComponent component : children) { 308 int spanX = getSpanX(component); 309 int spanY = getSpanY(component); 310 311 int r = nextFreeRow(rows); 312 if (r == rows.size()) { 313 rows.add(new Row(columnCount)); 314 } 315 int c = rows.get(r).nextFreeColumn(); 316 rows.get(r).addControl(component, spanX); 317 rows.get(r).fill(c + 1, c + spanX, component.isRendered()); 318 319 for (int i = r + 1; i < r + spanY; i++) { 320 321 if (i == rows.size()) { 322 rows.add(new Row(columnCount)); 323 } 324 rows.get(i).fill(c, c + spanX, component.isRendered()); 325 } 326 } 327 return rows; 328 } 329 330 private int nextFreeRow(List rows) { 331 int i = 0; 332 for (; i < rows.size(); i++) { 333 if (((Row) rows.get(i)).nextFreeColumn() != -1) { 334 return i; 335 } 336 } 337 return i; 338 } 339 340 public static int getSpanX(UIComponent component) { 341 return ComponentUtil.getIntAttribute( 342 component, ATTR_SPAN_X, 1); 343 } 344 345 public static int getSpanY(UIComponent component) { 346 return ComponentUtil.getIntAttribute( 347 component, ATTR_SPAN_Y, 1); 348 } 349 350 public boolean isIgnoreFree() { 351 return ignoreFree; 352 } 353 354 public void setIgnoreFree(boolean ignoreFree) { 355 this.ignoreFree = ignoreFree; 356 } 357 358 public static class Row implements Serializable { 359 private static final long serialVersionUID = 1511693677519052045L; 360 private int columns; 361 private List cells; 362 private boolean hidden; 363 364 public Row(int columns) { 365 setColumns(columns); 366 } 367 368 private void addControl(UIComponent component, int spanX) { 369 370 int i = nextFreeColumn(); 371 372 cells.set(i, component); 373 fill(i + 1, i + spanX, component.isRendered()); 374 } 375 376 private void fill(int start, int end, boolean rendered) { 377 378 if (end > columns) { 379 LOG.error("Error in Jsp (end > columns). " 380 + "Try to insert more spanX as possible."); 381 LOG.error("start: " + start); 382 LOG.error("end: " + end); 383 LOG.error("columns: " + columns); 384 LOG.error("Actual cells:"); 385 for (Object component : cells) { 386 if (component instanceof UIComponent) { 387 LOG.error("Cell-ID: " + ((UIComponent) component).getId() 388 + " " + ((UIComponent) component).getRendererType()); 389 } else { 390 LOG.error("Cell: " + component); // e.g. marker 391 } 392 } 393 394 end = columns; // fix the "end" parameter to continue the processing. 395 } 396 397 for (int i = start; i < end; i++) { 398 cells.set(i, new Marker(USED, rendered)); 399 } 400 } 401 402 private int nextFreeColumn() { 403 for (int i = 0; i < columns; i++) { 404 if (FREE.equals(cells.get(i))) { 405 return i; 406 } 407 } 408 return -1; 409 } 410 411 public List getElements() { 412 return cells; 413 } 414 415 public int getColumns() { 416 return columns; 417 } 418 419 private void setColumns(int columns) { 420 this.columns = columns; 421 cells = new ArrayList(columns); 422 for (int i = 0; i < columns; i++) { 423 cells.add(FREE); 424 } 425 } 426 427 public boolean isHidden() { 428 return hidden; 429 } 430 431 public void setHidden(boolean hidden) { 432 this.hidden = hidden; 433 } 434 } 435 436 public static class Marker implements Serializable { 437 private static final long serialVersionUID = 2505999420762504893L; 438 private final String name; 439 private boolean rendered; 440 441 private Marker(String name) { 442 this.name = name; 443 } 444 445 public Marker(String name, boolean rendered) { 446 this.name = name; 447 this.rendered = rendered; 448 } 449 450 @Override 451 public String toString() { 452 return name; 453 } 454 455 public boolean isRendered() { 456 return rendered; 457 } 458 } 459 }