/**
* Copyright (C) 2011 BonitaSoft S.A.
* BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program 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, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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.bonitasoft.web.toolkit.client.ui.component.containers;
import static com.google.gwt.query.client.GQuery.$;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.bonitasoft.web.toolkit.client.ui.JsId;
import org.bonitasoft.web.toolkit.client.ui.component.DoubleSection;
import org.bonitasoft.web.toolkit.client.ui.component.Section;
import org.bonitasoft.web.toolkit.client.ui.component.core.Component;
import org.bonitasoft.web.toolkit.client.ui.component.core.Node;
import org.bonitasoft.web.toolkit.client.ui.html.HTML;
import org.bonitasoft.web.toolkit.client.ui.html.HTMLClass;
import org.bonitasoft.web.toolkit.client.ui.html.XML;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
/**
* @author Séverin Moussel
*/
public class Container<T extends Node> extends Component {
private final HashMap<String, T> componentsIndexes = new HashMap<String, T>();
protected final LinkedList<T> components = new LinkedList<T>();
protected String rootTagName = "div";
protected String rootTagClass = null;
protected String wrapTagName = null;
protected String wrapTagClass = null;
private Integer incrementDefaultId = 0;
private int evenOddCounter = 0;
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public Container() {
super(null);
this.initTagNames();
}
public Container(final JsId jsid) {
super(jsid);
this.initTagNames();
}
public Container(final T... components) {
this(null, components);
}
public Container(final JsId jsid, final T... components) {
this(jsid);
this.append(components);
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MANAGE CONTENT
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public Container<T> empty() {
for (final T item : this.components) {
if (item instanceof KnowsContainer) {
((KnowsContainer) item).setContainer(null);
}
}
this.components.clear();
if (isGenerated()) {
$(element).empty();
this.incrementDefaultId = 0;
}
return this;
}
public Container<T> append(final T... components) {
for (final T component : components) {
if (component == null) {
continue;
}
if (component instanceof DoubleSection) {
evenOddCounter = 0;
} else if (component instanceof Section) {
if (evenOddCounter % 2 == 0) {
((Section) component).addClass("even");
} else {
((Section) component).addClass("odd");
}
evenOddCounter++;
}
if (component.getJsId() == null) {
this.componentsIndexes.put("componentUID" + this.incrementDefaultId.toString(), component);
this.incrementDefaultId++;
} else {
this.componentsIndexes.put(component.getJsId().toString(), component);
}
this.components.add(component);
if (component instanceof KnowsContainer) {
((KnowsContainer) component).setContainer(this);
}
if (isGenerated()) {
this.appendItemToHtml(component);
removeClass("empty");
}
}
return this;
}
public Container<T> prepend(final T... components) {
for (final T component : components) {
if (component.getJsId() == null) {
this.componentsIndexes.put("componentUID" + this.incrementDefaultId.toString(), component);
this.incrementDefaultId++;
} else {
this.componentsIndexes.put(component.getJsId().toString(), component);
}
this.components.addFirst(component);
if (component instanceof KnowsContainer) {
((KnowsContainer) component).setContainer(this);
}
if (isGenerated()) {
this.prependItemToHtml(component);
}
}
return this;
}
public Container<T> insert(final int index, final T... components) {
if (index <= 0) {
return this.prepend(components);
}
int nextIndex = index;
Element prev = null;
if (isGenerated()) {
prev = (Element) $(element).children().get(index - 1);
}
for (final T component : components) {
if (component == null) {
continue;
}
if (component.getJsId() == null) {
this.componentsIndexes.put("componentUID" + this.incrementDefaultId.toString(), component);
this.incrementDefaultId++;
} else {
this.componentsIndexes.put(component.getJsId().toString(), component);
}
this.components.add(nextIndex++, component);
if (component instanceof KnowsContainer) {
((KnowsContainer) component).setContainer(this);
}
if (isGenerated()) {
this.insertItemAfter(component, prev);
}
}
return this;
}
public final LinkedList<T> getComponents() {
return this.components;
}
public final T getLast() {
return this.components.get(this.components.size() - 1);
}
public final int size() {
return this.components.size();
}
public final T get(final JsId jsid) {
return this.componentsIndexes.get(jsid.toString());
}
public final T get(final int index) {
return this.components.get(index);
}
@Override
public void resetGeneration() {
super.resetGeneration();
for (final T component : this.components) {
component.resetGeneration();
}
}
public Container<T> move(final JsId jsid, final int index) {
final T item = this.get(jsid);
int oldPos = this.components.indexOf(item);
if (oldPos >= index) {
oldPos++;
}
this.components.add(index, item);
this.components.remove(oldPos);
if (isGenerated()) {
// TODO Move corresponding wrapper
}
return this;
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PRESENTATION
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public final void setRootTag(final String name, final String classes) {
this.rootTagName = name;
this.rootTagClass = classes;
}
public final void setRootTagName(final String rootTagName) {
this.rootTagName = rootTagName;
}
public final void setRootTagClass(final String rootTagClass) {
this.rootTagClass = rootTagClass;
}
public final void setWrapTag(final String name, final String classes) {
this.wrapTagName = name;
this.wrapTagClass = classes;
}
public final void setWrapTagName(final String wrapTagName) {
this.wrapTagName = wrapTagName;
}
public final void setWrapTagClass(final String wrapTagClass) {
this.wrapTagClass = wrapTagClass;
}
public final String getRootTagName() {
return this.rootTagName;
}
public final String getRootTagClass() {
return this.rootTagClass;
}
public final String getWrapTagName() {
return this.wrapTagName;
}
public final String getWrapTagClass() {
return this.wrapTagClass;
}
protected void initTagNames() {
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DISPLAY
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* /**
* Add the wrap around the item if necessary
*
* @return This method returns the element itself if no wrap is needed, or the Wrapper element.
*/
protected List<Element> prepareItem(final List<Element> elements) {
if (this.wrapTagName != null) {
final LinkedList<Element> res = new LinkedList<Element>();
final Element wrap = XML.makeElement(XML.openTag(this.wrapTagName, new HTMLClass(this.wrapTagClass)));
for (final Element e : elements) {
wrap.appendChild(e);
}
res.add(wrap);
return res;
}
return elements;
}
/*
* Add an item directly in the HTML before the first existing item
* @param item
* The item to prepend
*/
protected final void prependItemToHtml(final T item) {
// this.element.removeClassName("empty");
HTML.prepend(element, this.prepareItem(item.getElements()));
}
/**
* Add an item directly in the HTML after the last existing item
*
* @param item
* The item to append
*/
protected final void appendItemToHtml(final T item) {
// this.element.removeClassName("empty");
HTML.append(element, this.prepareItem(item.getElements()));
}
/**
* Add an item directly in the HTML after the last existing item
*
* @param item
* The item to append
*/
protected final void insertItemAfter(final T item, final Element e) {
// TODO Insert element
// for (final Element e2 : this.prepareItem(item.getElements())) {
// $(e).after(e2);
// }
}
@Override
protected Element makeElement() {
element = DOM.createElement(this.rootTagName);
if (this.rootTagClass != null) {
element.addClassName(this.rootTagClass);
}
if (getJsId() != null) {
element.addClassName(getJsId().toString());
}
if (this.components.size() == 0) {
element.addClassName("empty");
} else {
for (final T next : this.components) {
this.appendItemToHtml(next);
}
}
return element;
}
@Override
public String toString() {
return this.getClass().toString().replaceAll(".*\\.", "") + this.components.toString();
}
}