/** * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package wicket.contrib.groovy.builder; import groovy.lang.Closure; import groovy.util.BuilderSupport; import java.util.Collections; import java.util.HashMap; import java.util.Map; import wicket.Application; import wicket.Component; import wicket.MarkupContainer; import wicket.behavior.IBehavior; import wicket.markup.html.form.FormComponent; import wicket.markup.html.form.validation.IValidator; import wicket.model.IModel; /** * This is the core class. It takes a MarkupContainer as a context, and adds anything called to that. * Originally this took a page as context, but you can use this with more fine grained components as * needed (like a sub-classed form). * * There are several convenience 'add' methods that allow custom components, validators, and behaviors * to be added. * * @author Kevin Galligan * */ public class WicketBuilder extends BuilderSupport { HashMap objects; MarkupContainer context; boolean developmentMode = false; public WicketBuilder(MarkupContainer context) { this.context = context; setCurrent(context); try { developmentMode = context.getApplication().getConfigurationType().equals(Application.DEVELOPMENT); } catch (Exception e) { //Not a problem. } } public StringBuilder getTagTemplate() { return tagTemplate; } StringBuilder tagTemplate = new StringBuilder(); //This is pretty hacky. Should refactor the general layout at some point Map generatedComponentBuilderCache = new HashMap(); protected void nodeCompleted(Object parent, Object node) { if(node instanceof Component) { if (parent instanceof MarkupContainer) { MarkupContainer containerParent = (MarkupContainer) parent; Component componentChild = (Component) node; containerParent.add(componentChild); } WicketComponentBuilder helper = (WicketComponentBuilder) generatedComponentBuilderCache.get(node); if(developmentMode) helper.writeViewTagEnd(tagTemplate); } else if(node instanceof IModel) { ((Component)parent).setModel((IModel)node); } else if(node instanceof IBehavior) { ((Component)parent).add((IBehavior)node); } else if(node instanceof IValidator && parent instanceof FormComponent) { ((FormComponent)parent).add((IValidator)node); } } protected Object createNode(Object name, Map atts, Object value) { String sName = (String) name; //Assume component if of type String if(value instanceof String) { String key = (String)value; try { WicketComponentBuilder helper = WicketComponentBuilderFactory.generateComponentBuilder(sName, context); //If not found, try the other guys if(helper != null) { if(atts == null) atts = Collections.EMPTY_MAP; if(developmentMode) helper.writeViewTagStart(tagTemplate); Component result = helper.create(key, atts); if(result instanceof WicketComponentInitNotifier) ((WicketComponentInitNotifier)result).init(); generatedComponentBuilderCache.put(result, helper); return result; } } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new RuntimeException("Error with the builder", e); } } Object builderObj = WicketComponentBuilderFactory.getComponentAccentForName(sName); if(builderObj == null) throw new WicketComponentBuilderException("Builder for name '"+ sName +" not found"); return handleMultiTypeBuilder(builderObj, sName, value, atts); } protected Object createNode(Object name, Map atts) { String sName = (String) name; Object builderObj = WicketComponentBuilderFactory.getComponentAccentForName(sName); if(builderObj == null) throw new WicketComponentBuilderException("Builder for name '"+ sName +" not found"); return handleMultiTypeBuilder(builderObj, sName, null, atts); } private Object handleMultiTypeBuilder(Object builder, String name, Object defaultArg, Map attributes) { if(builder instanceof WicketModelBuilder) { WicketModelBuilder modelBuilder = (WicketModelBuilder) builder; try { IModel model = modelBuilder.create(defaultArg, attributes); return model; } catch(WicketComponentBuilderException e) { throw e; } catch (Exception e) { throw new WicketComponentBuilderException("Error building model", e); } } throw new WicketComponentBuilderException("No build type found"); } protected Object createNode(Object name, Object value) { return createNode(name, null, value); } protected Object createNode(Object name) { return createNode(name, null); } protected void setParent(Object parent, Object child) { } public void kickStart(MarkupContainer container, Closure closure) { setCurrent(container); // lets register the builder as the delegate setClosureDelegate(closure, container); closure.call(container); } public void add(Component component) { ((MarkupContainer)getCurrent()).add(component); } public void add(IValidator validator) { if(getCurrent() instanceof FormComponent) ((FormComponent)getCurrent()).add(validator); } public void add(IBehavior behavior) { if(getCurrent() instanceof Component) ((Component)getCurrent()).add(behavior); } }