/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.gwt.client.gfx.paintable;
import java.util.ArrayList;
import java.util.List;
import org.geomajas.gwt.client.gfx.Paintable;
import org.geomajas.gwt.client.gfx.PaintableGroup;
import org.geomajas.gwt.client.gfx.PainterVisitor;
import org.geomajas.gwt.client.spatial.Bbox;
/**
* A {@link Paintable} that contains other {@link Paintable}s,
* allowing you to create complex {@link Paintable}s (composite like pattern).
*
* <p>Children are visited (painted) in the order they were added.
* <p>{@link Paintable}s are not aware of parents, so all positioning is absolute.
*
* @author Kristof Heirwegh
*/
public class Composite implements PaintableGroup {
/**
* A preferably unique ID that identifies the object even after it is
* painted. This can later be used to update or delete it from the
* <code>GraphicsContext</code>.
*/
private String groupName;
protected final List<Paintable> children = new ArrayList<Paintable>();
public Composite() {
}
/**
* Construct a composite with the specified name.
*
* @param groupName a nice group name for the paintable to use in the DOM, not necessarily unique
*/
public Composite(String groupName) {
this.groupName = groupName;
}
// ----------------------------------------------------------
public void accept(PainterVisitor visitor, Object group, Bbox bounds, boolean recursive) {
for (Paintable p : children) {
visitor.visit(p, group);
}
}
/**
* Returns a nice name for the group to use in the DOM, not necessarily unique.
*
* @return name
*/
public String getGroupName() {
return groupName;
}
/**
* Add a {@link Paintable} to this composite.
*
* @param p
* the <code>Paintable</code> to add to this composite
*/
public void addChild(Paintable p) {
if (null == p) {
throw new IllegalArgumentException("Please provide a paintable.");
}
if (this.equals(p)) {
throw new IllegalArgumentException("Cannot add itself as a child.");
}
if (children.contains(p)) {
return;
} // nothing changes, no exception
if (p instanceof Composite && ((Composite) p).contains(this)) {
throw new IllegalArgumentException("Cannot add this Paintable (circular reference).");
}
children.add(p);
}
/**
* Remove child {@link Paintable} object.
*
* @param p paintable to remove
* @return true when object was removed (false when not found as child)
*/
public boolean removeChild(Paintable p) {
return children.remove(p);
}
/**
* Recursively checks children to find p.
*
* @param p
* Paintable to search for
* @return true when the composite contains the passed object
*/
public boolean contains(Paintable p) {
if (children.contains(p)) {
return true;
}
for (Paintable t : children) {
if (t instanceof Composite) {
if (((Composite) t).contains(p)) {
return true;
}
}
}
return false;
}
}