package ilarkesto.ui.action;
import ilarkesto.base.Iconized;
import ilarkesto.base.MissingDependencyException;
import ilarkesto.base.Str;
import ilarkesto.base.StringProvider;
import ilarkesto.core.logging.Log;
import ilarkesto.di.BeanProvider;
import ilarkesto.form.BeanForm;
import ilarkesto.form.Form;
import ilarkesto.form.FormButton;
import ilarkesto.form.FormField;
import ilarkesto.form.InputAssistant;
import ilarkesto.form.ItemFormField;
import ilarkesto.form.MultiComplexFormField;
import ilarkesto.form.MultiItem;
import ilarkesto.form.MultiItemFormField;
import ilarkesto.form.TextFormField;
import ilarkesto.form.ValidationException;
import ilarkesto.id.CountingIdGenerator;
import ilarkesto.id.IdGenerator;
import ilarkesto.ui.Option;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.fileupload.FileItem;
public final class FormAction<F extends Form> extends AAction {
private static final Log LOG = Log.get(FormAction.class);
@Override
protected void assertPermissions() {}
@Override
protected void performAction() throws InterruptedException {
setAutoShowInfoDone(false);
if (form == null) throw new MissingDependencyException("form");
form.addHidden("actionId").setValue(getActionId());
for (FormField field : form.getAutoTriggerFields()) {
if (field instanceof ItemFormField) {
showSelectItemDialog((ItemFormField) field);
} else {
throw new RuntimeException("AutoTrigger not supported for field: " + field.getClass().getSimpleName());
}
}
do {
LOG.debug("Handling form:", form.getName());
showDialog(form);
} while (handleSubmit());
}
/**
* @return true, if submit handeled internally (show form again)
*/
private boolean handleSubmit() {
// inject form with current request properties
autowire(form);
// determine clicked button
for (String parameter : webRequestParametersBeanProvider.beanNames()) {
if (parameter.startsWith(Form.BUTTON_PREFIX)) {
String buttonName = parameter.substring(Form.BUTTON_PREFIX.length());
clickedButton = form.getButton(buttonName);
break;
}
}
LOG.debug("clickedButton:", clickedButton);
if (clickedButton != null) {
if (clickedButton.isUpdateFields()) {
updateForm(form);
}
// check if form validation active for this button
if (clickedButton.isValidateForm()) {
try {
form.validate();
} catch (ValidationException ex) {
LOG.debug("Form is not valid:", ex);
String message = ex.getMessage();
Throwable cause = ex.getCause();
if (cause != null) message += " " + Str.format(cause);
form.setErrorMessage(message);
return true;
}
}
try {
return handleButtonClick(clickedButton);
} catch (ValidationException ex) {
LOG.debug("Form is not valid:", ex);
form.setErrorMessage(ex.getMessage());
return true;
}
}
return true;
}
private void showSelectItemDialog(ItemFormField field) {
try {
field.setValue(showOptionDialog(form.getStringKeyPrefix() + "." + field.getName() + ".select.message",
field.getSelectableItems()));
} catch (ActionAbortedException ex) {}
}
private boolean handleButtonClick(FormButton button) throws ValidationException {
if (button instanceof ItemFormField.SelectButton) {
showSelectItemDialog(((ItemFormField.SelectButton) button).getField());
return true;
}
if (button instanceof ItemFormField.ClearButton) {
ItemFormField field = ((ItemFormField.ClearButton) button).getField();
field.setValue(null);
return true;
}
if (button instanceof MultiItemFormField.AddButton) {
MultiItemFormField field = ((MultiItemFormField.AddButton) button).getField();
MultiOptionAction action = autowire(new MultiOptionAction());
action.setMessage(string(form.getStringKeyPrefix() + "." + field.getName() + ".select.message"));
IdGenerator itemIdGenerator = new CountingIdGenerator("item");
for (Object o : field.getSelectableMultiItems()) {
MultiItem item = (MultiItem) o;
Option option = new Option(itemIdGenerator.generateId(), item.toString(), "multiItem", item);
option.setGroup(true);
option.setTooltip(item.getTooltip());
action.addOption(option);
}
StringProvider itemTooltipProvider = field.getItemTooltipProvider();
StringProvider itemLabelProvider = field.getItemLabelProvider();
for (Object item : field.getSelectableItems()) {
String icon = item instanceof Iconized ? ((Iconized) item).getIcon() : "item";
String label = itemLabelProvider == null ? item.toString() : itemLabelProvider.getString(item);
Option option = new Option(itemIdGenerator.generateId(), label, icon, item);
if (itemTooltipProvider != null) {
option.setTooltip(itemTooltipProvider.getString(item));
}
action.addOption(option);
}
try {
actionPerformer.performSubAction(action, this);
} catch (ActionAbortedException ex) {
return true;
}
Set items = action.getSelectedPayloads();
for (Object item : items) {
if (item instanceof MultiItem) {
for (Object o : ((MultiItem) item).getItems()) {
field.addValueItem(o);
}
} else {
field.addValueItem(item);
}
}
return true;
}
if (button instanceof MultiItemFormField.RemoveButton) {
MultiItemFormField field = ((MultiItemFormField.RemoveButton) button).getField();
Object item = ((MultiItemFormField.RemoveButton) button).getItem();
field.removeValueItem(item);
return true;
}
if (button instanceof MultiItemFormField.RemoveAllButton) {
MultiItemFormField field = ((MultiItemFormField.RemoveAllButton) button).getField();
field.removeAllItems();
return true;
}
if (button instanceof MultiComplexFormField.AddButton) {
MultiComplexFormField.AddButton b = (MultiComplexFormField.AddButton) button;
final MultiComplexFormField field = b.getField();
final BeanForm form = field.createSubform();
autowire(form);
form.setBean(field.getItemFactory().getBean());
FormAction action = new FormAction();
action.setForm(form);
try {
actionPerformer.performSubAction(action, this);
} catch (ActionAbortedException ex) {
return true;
}
if (!action.isClickedButtonAbort()) {
field.addValueItem(form.getBean());
}
return true;
}
if (button instanceof MultiComplexFormField.EditButton) {
MultiComplexFormField.EditButton b = (MultiComplexFormField.EditButton) button;
final MultiComplexFormField field = b.getField();
final BeanForm form = field.createSubform();
autowire(form);
form.setBean(b.getItem());
FormAction action = new FormAction();
action.setForm(form);
try {
actionPerformer.performSubAction(action, this);
} catch (ActionAbortedException ex) {}
return true;
}
if (button instanceof MultiComplexFormField.RemoveButton) {
MultiComplexFormField field = ((MultiComplexFormField.RemoveButton) button).getField();
Object item = ((MultiComplexFormField.RemoveButton) button).getItem();
field.removeValueItem(item);
return true;
}
if (button instanceof TextFormField.InputAssistantButton) {
TextFormField field = ((TextFormField.InputAssistantButton) button).getField();
InputAssistant inputAssistant = field.getInputAssistant();
Object option;
try {
option = showOptionDialog("inputAssistant.message", inputAssistant.getOptions());
} catch (ActionAbortedException ex) {
return true;
}
field.setValue(inputAssistant.applyToInput(field.getValueAsString(), option));
return true;
}
if (button.isAbort()) throw new ActionAbortedException();
// user defined button
return false;
}
private void updateForm(Form form) {
Map<String, String> data = new HashMap<String, String>();
for (String parameter : webRequestParametersBeanProvider.beanNames()) {
if (!parameter.startsWith("_")) {
data.put(parameter, (String) webRequestParametersBeanProvider.getBean(parameter));
}
}
form.update(data, uploadedFiles);
}
private FormButton clickedButton;
public FormButton getClickedButton() {
return clickedButton;
}
public F getForm() {
return form;
}
@Override
public String toString() {
return "FormAction:" + (form == null ? null : form.getName());
}
// --- helper ---
public boolean isClickedButtonAbort() {
return clickedButton == null ? false : clickedButton.isAbort();
}
// --- dependencies ---
private F form;
public void setForm(F form) {
this.form = form;
}
private Collection<FileItem> uploadedFiles;
public void setUploadedFiles(Collection<FileItem> uploadedFiles) {
this.uploadedFiles = uploadedFiles;
}
private BeanProvider webRequestParametersBeanProvider;
public void setWebRequestParametersBeanProvider(BeanProvider webRequestParametersBeanProvider) {
this.webRequestParametersBeanProvider = webRequestParametersBeanProvider;
}
}