package org.nocket.gen.page.visitor.bind.builder;
import gengui.util.SevereGUIException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.apache.wicket.Component;
import org.nocket.gen.page.element.ButtonElement;
import org.nocket.gen.page.element.CheckboxInputElement;
import org.nocket.gen.page.element.DivElement;
import org.nocket.gen.page.element.FeedbackElement;
import org.nocket.gen.page.element.FileDownloadElement;
import org.nocket.gen.page.element.FileInputElement;
import org.nocket.gen.page.element.FormElement;
import org.nocket.gen.page.element.GroupTabbedPanelElement;
import org.nocket.gen.page.element.ImageElement;
import org.nocket.gen.page.element.LabelElement;
import org.nocket.gen.page.element.LinkElement;
import org.nocket.gen.page.element.ModalElement;
import org.nocket.gen.page.element.PageElementI;
import org.nocket.gen.page.element.PasswordInputElement;
import org.nocket.gen.page.element.PromptElement;
import org.nocket.gen.page.element.RadioInputElement;
import org.nocket.gen.page.element.RepeatingPanelElement;
import org.nocket.gen.page.element.SelectElement;
import org.nocket.gen.page.element.TableElement;
import org.nocket.gen.page.element.TextAreaElement;
import org.nocket.gen.page.element.TextInputElement;
import org.nocket.gen.page.element.UnknownPageElementI;
import org.nocket.gen.page.inject.PageComponentInjection;
import org.nocket.gen.page.visitor.bind.builder.components.GeneratedDateTextField;
import org.nocket.gen.page.visitor.bind.builder.components.GeneratedNumberTextField;
/**
* This class tries to find custom-built components from the page class'
* members. This is the opposite of what class {@link PageComponentInjection}
* does, so to speak. While PageComponentInjections injects auto-generated
* Wicket components into the Page class' members after the binding process,
* this class here interprets the page class as a component <i>provider</i>. It
* looks for non-null members providing components with wicket IDs which match
* the required components wicket IDs and uses these components avoiding the
* internal auto-creation. This allows developers to provide components with
* special instrumentation. The components could as well be provided by
* self-written binding interceptors, but providing by members is much more
* convenient (as long as it is suitable ;-)
*
* The framework's pre-defined components like {@link GeneratedNumberTextField}
* and {@link GeneratedDateTextField} provide simplified constructors to
* instanciate them with minimal parameterization as a member and
* post-initialize them later by this binding builder here.
*
* @author less02
*/
public class CustomBindingBuilder implements BindingBuilderI {
protected Map<String, Field> potentialProviderMembers = null;
protected Component findCustomComponent(PageElementI<?> forElement) {
try {
Map<String, Field> potentialProviders = getPotentialProviderMembers(forElement);
Field provider = potentialProviders.get(forElement.getWicketId());
if (provider != null) {
provider.setAccessible(true);
Component customComponent = (Component) provider.get(forElement.getContext().getPage());
// Do we have to perform a general type check here, if the provided component
// looks somehow suitable for the type of page element to represent? Custom
// components may be something totally unknown, so we don't check anything at all.
if (customComponent.getDefaultModel() == null)
customComponent.setDefaultModel(forElement.getModel());
return customComponent;
}
return null;
} catch (IllegalAccessException iax) {
throw new SevereGUIException(iax);
}
}
protected Map<String, Field> getPotentialProviderMembers(PageElementI<?> forElement) throws IllegalAccessException {
if (potentialProviderMembers == null) {
potentialProviderMembers = new HashMap<String, Field>();
Class<?> pageClass = forElement.getContext().getPage().getClass();
addComponentFields(forElement.getContext().getPage(), pageClass);
}
return potentialProviderMembers;
}
protected void addComponentFields(Object page, Class<?> clazz) throws IllegalAccessException {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Object content = field.get(page);
if (content instanceof Component) {
Component component = (Component) content;
potentialProviderMembers.put(component.getId(), field);
}
}
Class<?> superClass = clazz.getSuperclass();
if (superClass != null) {
addComponentFields(page, superClass);
}
}
@Override
public Component createModal(ModalElement e) {
return findCustomComponent(e);
}
@Override
public Component createFeedback(FeedbackElement e) {
return findCustomComponent(e);
}
@Override
public Component createForm(FormElement e) {
return findCustomComponent(e);
}
@Override
public Component createLabel(LabelElement e) {
return findCustomComponent(e);
}
@Override
public Component createPrompt(PromptElement e) {
return findCustomComponent(e);
}
@Override
public Component createTextInput(TextInputElement e) {
Component component = findCustomComponent(e);
if (component instanceof GeneratedNumberTextField) {
((GeneratedNumberTextField) component).postInit(e);
} else if (component instanceof GeneratedDateTextField) {
((GeneratedDateTextField) component).postInit(e);
}
return component;
}
@Override
public Component createFileInput(FileInputElement e) {
return findCustomComponent(e);
}
@Override
public Component createPasswordInput(PasswordInputElement e) {
return findCustomComponent(e);
}
@Override
public Component createFileDownload(FileDownloadElement e) {
return findCustomComponent(e);
}
@Override
public Component createTextArea(TextAreaElement e) {
return findCustomComponent(e);
}
@Override
public Component createCheckboxInput(CheckboxInputElement e) {
return findCustomComponent(e);
}
@Override
public Component createRadioInput(RadioInputElement e) {
return findCustomComponent(e);
}
@Override
public Component createSelect(SelectElement e) {
return findCustomComponent(e);
}
@Override
public Component createImage(ImageElement e) {
return findCustomComponent(e);
}
@Override
public Component createLink(LinkElement e) {
return findCustomComponent(e);
}
@Override
public Component createTable(TableElement e) {
return findCustomComponent(e);
}
@Override
public Component createButton(ButtonElement e) {
return findCustomComponent(e);
}
@Override
public Component createUnknown(UnknownPageElementI<?> e) {
return findCustomComponent(e);
}
@Override
public Component createListView(RepeatingPanelElement e) {
return findCustomComponent(e);
}
@Override
public Component createGroupTabbedPanel(GroupTabbedPanelElement e) {
return findCustomComponent(e);
}
@Override
public Component createDiv(DivElement e) {
return findCustomComponent(e);
}
}