/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.web.wicket.bootstrap;
import java.util.HashSet;
import java.util.Set;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.projectforge.core.PropUtils;
import org.projectforge.web.HtmlHelper;
import org.projectforge.web.wicket.flowlayout.AbstractGridBuilder;
import org.projectforge.web.wicket.flowlayout.DivPanel;
import org.projectforge.web.wicket.flowlayout.DivTextPanel;
import org.projectforge.web.wicket.flowlayout.FieldProperties;
import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
import org.projectforge.web.wicket.flowlayout.FormHeadingPanel;
/**
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
public class GridBuilder extends AbstractGridBuilder<FieldsetPanel>
{
private static final long serialVersionUID = 4323077384391963834L;
public static final int MAX_LEVEL = 2;
private final DivPanel mainContainer;
private final DivPanel[] rowPanel = new DivPanel[MAX_LEVEL + 1];
private final DivPanel[] gridPanel = new DivPanel[MAX_LEVEL + 1];
private int currentLevel = 0;
private int splitDepth = 1;
// Counts the length of grid panels of current row. After reaching full length, a new row will be created automatically.
private final int lengthCounter[] = new int[MAX_LEVEL + 1];
private Set<String> rowsPanelHelperSet;
public GridBuilder(final MarkupContainer parent, final String id)
{
this(parent, id, true);
}
/**
* @param parent
* @param id
* @param fluid Default is true.
*/
public GridBuilder(final MarkupContainer parent, final String id, final boolean fluid)
{
super();
this.parent = parent;
mainContainer = new DivPanel(id, fluid == true ? GridType.CONTAINER_FLUID : GridType.CONTAINER);
parent.add(mainContainer);
}
public GridBuilder newGridPanel(final GridType... gridTypes)
{
return newGridPanel(0, GridSize.SPAN12, gridTypes);
}
public GridBuilder newSplitPanel(final GridSize size, final GridType... gridTypes)
{
return newSplitPanel(size, false, gridTypes);
}
public GridBuilder newSplitPanel(final GridSize size, final boolean hasSubSplitPanel, GridType... gridTypes)
{
if (hasSubSplitPanel == true) {
splitDepth = 2;
if (gridTypes == null) {
gridTypes = new GridType[] { GridType.HAS_CHILDS};
} else {
final GridType[] types = new GridType[gridTypes.length + 1];
for (int i = 0; i < gridTypes.length; i++) {
types[i] = gridTypes[i];
}
types[gridTypes.length] = GridType.HAS_CHILDS;
gridTypes = types;
}
} else {
splitDepth = 1;
}
newGridPanel(0, size, gridTypes);
if (hasSubSplitPanel == true) {
// Set the class attribute "row-has-childs":
if (rowsPanelHelperSet == null) {
rowsPanelHelperSet = new HashSet<String>();
rowPanel[0].addCssClasses(GridType.ROW_HAS_CHILDS);
rowsPanelHelperSet.add(rowPanel[0].getMarkupId());
} else {
if (rowsPanelHelperSet.contains(rowPanel[0].getMarkupId()) == false) {
rowPanel[0].addCssClasses(GridType.ROW_HAS_CHILDS);
rowsPanelHelperSet.add(rowPanel[0].getMarkupId());
}
}
}
return this;
}
public GridBuilder newSubSplitPanel(final GridSize size, final GridType... gridTypes)
{
if (splitDepth < 2) {
throw new IllegalArgumentException("Dear developer: please call gridBuilder.newSplitPanel(GridSize, true, ...) first!");
}
return newGridPanel(1, size, gridTypes);
}
/**
* Sets the gridPanel of the given level as current level. You can only set a lower level than current level, otherwise an exception will
* be thrown.
* @param level the currentLevel to set
* @return this for chaining.
*/
public GridBuilder setCurrentLevel(final int level)
{
if (level > this.currentLevel) {
throw new IllegalArgumentException("You can only set a lower level than current level, current level is "
+ this.currentLevel
+ ", desired level is "
+ level);
}
if (level < 0) {
throw new IllegalArgumentException("Level must be a positive value: " + level);
}
this.currentLevel = level;
setNullPanel(level, level + 1);
return this;
}
public GridBuilder clear()
{
lengthCounter[currentLevel] = 1000;
return this;
}
/**
* If row panel of this level doesn't exist it will be created.
* @param level
* @param size
* @param gridTypes
* @return this for chaining.
*/
private GridBuilder newGridPanel(final int level, final GridSize size, final GridType... gridTypes)
{
validateGridPanelLevel(level);
currentLevel = level;
if (rowPanel[level] == null) {
newRowPanel(level);
}
boolean firstPanelOfRow = false;
if (lengthCounter[level] == 0) {
firstPanelOfRow = true;
}
lengthCounter[level] += size.getLength();
if (lengthCounter[level] > 12) {
newRowPanel(level);
lengthCounter[level] = size.getLength();
firstPanelOfRow = true;
} else {
if (firstPanelOfRow == false && gridPanel[level] != null) {
gridPanel[level].addCssClasses(GridType.HAS_SIBLINGS);
}
}
final DivPanel divPanel = new DivPanel(rowPanel[level].newChildId(), size, gridTypes);
if (firstPanelOfRow == false) {
divPanel.addCssClasses(GridType.NOT_FIRST);
} else {
divPanel.addCssClasses(GridType.FIRST);
}
return addGridPanel(level, divPanel);
}
/**
* If you use this method, the lengthCounter won't be incremented and you use to call setCurrentLevel(level -1) manually.
* @param level
* @param divPanel
* @return
*/
private GridBuilder addGridPanel(final int level, final DivPanel divPanel)
{
validateGridPanelLevel(level);
currentLevel = level;
if (rowPanel[level] == null) {
newRowPanel(level);
}
gridPanel[level] = divPanel;
rowPanel[level].add(divPanel);
setNullPanel(level + 1, level + 1);
return this;
}
private String newRowPanelId(final int level)
{
validateRowPanelLevel(level);
if (level > 0) {
return gridPanel[level - 1].newChildId();
} else {
return mainContainer.newChildId();
}
}
private GridBuilder newRowPanel(final int level, final GridType... gridTypes)
{
validateRowPanelLevel(level);
final DivPanel rowPanel = new DivPanel(newRowPanelId(level), GridType.ROW);
rowPanel.addCssClasses(gridTypes);
return addRowPanel(level, rowPanel);
}
private GridBuilder addRowPanel(final int level, final DivPanel rowPanel)
{
validateRowPanelLevel(level);
this.rowPanel[level] = rowPanel;
lengthCounter[level] = 0;
if (level > 0) {
gridPanel[level - 1].add(rowPanel);
} else {
mainContainer.add(rowPanel);
}
setNullPanel(level + 1, level);
return this;
}
/**
* @return new child id (Wicket id) of the current grid panel.
*/
public String newRowId()
{
return rowPanel[currentLevel].newChildId();
}
/**
* @return new child id (Wicket id) of the current row panel.
*/
public String newGridPanelId()
{
return gridPanel[currentLevel].newChildId();
}
/**
* @see org.projectforge.web.wicket.flowlayout.GridBuilderInterface#getPanel()
*/
public DivPanel getPanel()
{
if (currentLevel == 0 && gridPanel[currentLevel] == null) {
newGridPanel(0, GridSize.SPAN12);
}
return gridPanel[currentLevel];
}
public DivPanel getRowPanel()
{
return rowPanel[currentLevel];
}
/**
* @see org.projectforge.web.wicket.flowlayout.GridBuilderInterface#newFormHeading(java.lang.String)
*/
public FormHeadingPanel newFormHeading(final String label)
{
final FormHeadingPanel formHeading = new FormHeadingPanel(getPanel().newChildId(), label);
getPanel().add(formHeading);
return formHeading;
}
@SuppressWarnings("serial")
public DivTextPanel newSecurityAdviceBox(final IModel<String> content)
{
final DivTextPanel hintBox = new DivTextPanel(getPanel().newChildId(), new Model<String>() {
@Override
public String getObject()
{
return "<h4>" + getString("securityAdvice") + "</h4>" + HtmlHelper.escapeHtml(content.getObject(), true);
}
});
hintBox.getDiv().add(AttributeModifier.append("class", "alert alert-danger"));
hintBox.getLabel().setEscapeModelStrings(false);
getPanel().add(hintBox);
return hintBox;
}
public RepeatingView newRepeatingView()
{
final RepeatingView repeater = new RepeatingView(getPanel().newChildId());
getPanel().add(repeater);
return repeater;
}
/**
* @see org.projectforge.web.wicket.flowlayout.AbstractGridBuilder#newFieldset(org.projectforge.web.wicket.flowlayout.FieldProperties)
*/
@Override
public FieldsetPanel newFieldset(final FieldProperties< ? > fieldProperties)
{
return new FieldsetPanel(getPanel(), fieldProperties);
}
/**
* @see org.projectforge.web.wicket.flowlayout.GridBuilderInterface#newFieldset(java.lang.String)
*/
@Override
public FieldsetPanel newFieldset(final Class< ? > clazz, final String property)
{
return new FieldsetPanel(getPanel(), getString(PropUtils.getI18nKey(clazz, property)));
}
/**
* @see org.projectforge.web.wicket.flowlayout.GridBuilderInterface#newFieldset(java.lang.String)
*/
@Override
public FieldsetPanel newFieldset(final String label)
{
return new FieldsetPanel(getPanel(), label);
}
/**
* @see org.projectforge.web.wicket.flowlayout.GridBuilderInterface#newFieldset(java.lang.String, java.lang.String)
*/
@Override
public FieldsetPanel newFieldset(final String labelText, final String labelDescription)
{
return new FieldsetPanel(getPanel(), labelText, labelDescription);
}
private void validateRowPanelLevel(final int level)
{
if (level < 0 || level > MAX_LEVEL) {
throw new IllegalArgumentException("Level '" + "' not supported. Value must be between 1 and " + MAX_LEVEL);
}
if (level > 0 && gridPanel[level - 1] == null) {
throw new IllegalArgumentException("Can't add row panel of level '"
+ level
+ "'. Grid panel of level "
+ (level - 1)
+ " doesn't exist!");
}
}
private void validateGridPanelLevel(final int level)
{
if (level < 0 || level > MAX_LEVEL) {
throw new IllegalArgumentException("Level '" + level + "' not supported. Value must be between 0 and " + MAX_LEVEL);
}
}
private void setNullPanel(final int rowFromLevel, final int gridFromLevel)
{
for (int i = rowFromLevel; i <= MAX_LEVEL; i++) {
rowPanel[i] = null;
lengthCounter[i] = 0;
}
for (int i = gridFromLevel; i <= MAX_LEVEL; i++) {
gridPanel[i] = null;
}
}
}