package org.nocket.gen.page.element.synchronizer;
import gengui.annotations.Modal;
import gengui.annotations.Prompt;
import gengui.domain.DomainObjectReference;
import gengui.guiadapter.AbstractMethodActivator;
import gengui.util.AnnotationHelper;
import java.io.File;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.MissingResourceException;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.mutable.MutableBoolean;
import org.apache.wicket.Component;
import org.apache.wicket.Localizer;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.IModel;
import org.nocket.NocketSession;
import org.nocket.gen.domain.element.MultivalueButtonElement;
import org.nocket.gen.i18n.I18NLabelModel;
import org.nocket.gen.page.DMDWebGenPageContext;
import org.nocket.gen.page.element.FormElement;
import org.nocket.gen.page.element.synchronizer.error.MethodExceptionHandlerI;
import org.nocket.gen.page.guiservice.DMDWebGenGuiServiceProvider;
import org.nocket.util.Assert;
/**
* The Class TableButtonCallback.
*/
public class TableButtonCallback extends TableCallback implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The is remover. */
private final boolean isRemover;
/** The is closer. */
private final boolean isCloser;
/** The Constant ICON_ENABLED. */
private static final String ICON_ENABLED = "{0}.icon.enabled";
/** The Constant ICON_DISABLED. */
private static final String ICON_DISABLED = "{0}.icon.disabled";
/**
* Instantiates a new table button callback.
*
* @param context the context
* @param element the element
*/
public TableButtonCallback(DMDWebGenPageContext context, MultivalueButtonElement<DomainObjectReference> element) {
super(context, element);
this.isRemover = element.isRemover();
//Same performance improvement as in ButtonCallback's constructor. See details there!
Boolean isCloserMethod = context.isPage() ? Boolean.FALSE :
AbstractMethodActivator.isCloserMethod(helper.getRef(), helper.getButtonMethod());
// TODO: according to gengui a method which is not clearly detected as being a closer
// derives its closing behavior from the start of the modal operation.
// This is not yet supported by web gengui. However, as closers are currently only
// supported for modal dialogs at all, the behavior simply defaults to true
isCloser = !BooleanUtils.isFalse(isCloserMethod);
}
/**
* Gets the wicket id.
*
* @return the wicket id
*/
public String getWicketId() {
return propertiesWicketId;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
if (isRemover) {
return helper.getRemoverButtonMethod().getName();
} else {
return helper.getButtonMethod().getName();
}
}
/**
* Gets the prompt.
*
* @return the prompt
*/
public String getPrompt() {
return prompt;
}
/**
* Checks if is enabled.
*
* @param targetObject the target object
* @return true, if is enabled
*/
public boolean isEnabled(Object targetObject) {
if (isRemover) {
return helper.isEnabled();
} else {
try {
helper.setForcedMethodTargetObject(targetObject);
return helper.isEnabled();
} finally {
helper.setForcedMethodTargetObject(null);
}
}
}
/**
* Checks if is forced.
*
* @param targetObject the target object
* @return true, if is forced
*/
public boolean isForced(Object targetObject) {
if (isRemover) {
return helper.isForced();
} else {
try {
helper.setForcedMethodTargetObject(targetObject);
return helper.isForced();
} finally {
helper.setForcedMethodTargetObject(null);
}
}
}
/**
* On submit.
*
* @param target the target
* @param model the model
*/
public void onSubmit(AjaxRequestTarget target, final IModel model) {
DMDWebGenGuiServiceProvider webGuiServiceProvider = NocketSession.get().getDMDWebGenGuiServiceProvider();
try {
webGuiServiceProvider.registerAjaxRequestTarget(helper.getContext(), target);
if (isRemover) {
helper.invokeRemoverButtonMethod(newMethodExceptionHanlder(), model.getObject());
} else {
try {
helper.setForcedMethodTargetObject(model.getObject());
Object result = helper.invokeButtonMethod(newMethodExceptionHanlder());
boolean hasModalAnnotation = helper.getAnnotationOnButtonMethode(Modal.class) != null;
Assert.test(!hasModalAnnotation || !webGuiServiceProvider.isModalPanelActive(),
"One generic modal dialog over another is still not implemented. Button name = "
+ this.helper.getButtonMethod().getName());
boolean modalPanelActive = webGuiServiceProvider.isModalPanelActive();
if (!modalPanelActive && !hasModalAnnotation) {
webGuiServiceProvider.showPage(result);
} else if (isCloser) {
Assert.test(isCloser && webGuiServiceProvider.isModalPanelActive(),
"Found a Closer, but there is no active modal panel. Button name = "
+ this.helper.getButtonMethod().getName());
webGuiServiceProvider.closeModalPanel();
webGuiServiceProvider.showPage(result);
} else {
// if it is not a closer but a result of null, do nothing
if (result != null) {
/*
* While showing a modal dialog wicket will do no
* serialization of the models. So, it is possible
* to put a reference of data from the page to the
* dialog and let the dialog change it.
*/
webGuiServiceProvider.showModalPanel(result);
if (modalPanelActive) {
webGuiServiceProvider.closeModalPanel();
}
}
}
} finally {
helper.setForcedMethodTargetObject(null);
}
}
} finally {
webGuiServiceProvider.unregisterAjaxRequestTarget(helper.getContext(), target);
}
}
/**
* New method exception hanlder.
*
* @return the method exception handler i
*/
private MethodExceptionHandlerI newMethodExceptionHanlder() {
final MutableBoolean exceptionOccured = new MutableBoolean(false);
return new MethodExceptionHandlerI() {
@Override
public void displayError(Object domainObject, Throwable exception, String title, String message) {
exceptionOccured.setValue(true);
helper.getContext().getMethodExceptionHandler()
.displayError(domainObject, exception, title, message);
}
@Override
public void exceptionSwallowed(Object domainObject, Throwable exception) {
exceptionOccured.setValue(true);
helper.getContext().getMethodExceptionHandler().exceptionSwallowed(domainObject, exception);
}
};
}
/**
* Gets the tooltip.
*
* @param targetObject the target object
* @return the tooltip
*/
public String getTooltip(Object targetObject) {
if (isRemover) {
return helper.getButtonTooltip();
} else {
try {
helper.setForcedMethodTargetObject(targetObject);
return helper.getButtonTooltip();
} finally {
helper.setForcedMethodTargetObject(null);
}
}
}
/**
* Update all forms.
*
* @param target the target
*/
public void updateAllForms(AjaxRequestTarget target) {
helper.updateAllForms(target);
}
/**
* Gets the form.
*
* @return the form
*/
public Form<?> getForm() {
return (Form<?>) helper.getContext().getComponentRegistry().getComponent(FormElement.DEFAULT_WICKET_ID);
}
/**
* Gets the method.
*
* @return the method
*/
public Method getMethod() {
return helper.getButtonMethod();
}
/**
* Gets the icon resource name.
*
* @param targetObject the target object
* @return the icon resource name
*/
public String getIconResourceName(Object targetObject) {
if (helper.getContext().getConfiguration().isLocalizationWicket()) {
String key = isEnabled(targetObject) ? getIconTableKey(ICON_ENABLED, this.getWicketId()) :
getIconTableKey(ICON_DISABLED, this.getWicketId());
return localizeLikeWicket(key, getForm());
}
String key = null;
Class<?> domainClass = helper.getRef().getDomainClass();
Method buttonMethod = helper.getButtonMethod();
Prompt prompt = new AnnotationHelper(buttonMethod).getAnnotation(Prompt.class);
if (prompt != null) {
key = isEnabled(targetObject) ? getIconTableKey(ICON_ENABLED, prompt.value()) :
getIconTableKey(ICON_DISABLED, prompt.value());
} else {
key = isEnabled(targetObject) ? getIconTableKey(ICON_ENABLED, buttonMethod.getName()) :
getIconTableKey(ICON_DISABLED, buttonMethod.getName());
}
return new I18NLabelModel(domainClass, key).getObject();
}
/**
* Gets the icon table key.
*
* @param pattern the pattern
* @param baseKey the base key
* @return the icon table key
*/
private String getIconTableKey(String pattern, String baseKey) {
return MessageFormat.format(pattern, baseKey);
}
/**
* Localize like wicket.
*
* @param key the key
* @param c the c
* @return the string
*/
private String localizeLikeWicket(String key, Component c) {
try {
// Wicket should recursively search for the property in the component's properties-file and those of its parents down to the application
return Localizer.get().getString(key, c);
} catch (MissingResourceException e) {
return null;
}
}
/**
* Checks if is download method.
*
* @return true if the method return file. In such case, the
*/
public boolean isDownloadMethod() {
Class<?> returnType = getMethod().getReturnType();
return java.io.File.class.isAssignableFrom(returnType);
}
/**
* On download method.
*
* @param model the model
* @return Returns file to download from the method of the domain object.
*/
public File onDownloadMethod(IModel<?> model) {
helper.setForcedMethodTargetObject(model.getObject());
return (File) helper.invokeButtonMethod(newMethodExceptionHanlder());
}
}