package org.aperteworkflow.util.dict.ui.fields; import com.vaadin.Application; import com.vaadin.data.Item; import com.vaadin.data.Validator.InvalidValueException; import com.vaadin.data.util.BeanItem; import com.vaadin.ui.*; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import org.aperteworkflow.util.dict.wrappers.DictionaryItemExtensionWrapper; import org.vaadin.addon.customfield.CustomField; import pl.net.bluesoft.rnd.util.i18n.I18NSource; import java.util.*; import static org.aperteworkflow.util.dict.wrappers.DictionaryItemExtensionWrapper._NAME; import static org.aperteworkflow.util.dict.wrappers.DictionaryItemExtensionWrapper._VALUE; import static org.aperteworkflow.util.vaadin.VaadinUtility.addIcon; import static org.aperteworkflow.util.vaadin.VaadinUtility.deleteIcon; public abstract class DictionaryItemExtensionField extends CustomField { private I18NSource source; private Application application; private Button addButton; private VerticalLayout itemsLayout; private Label noExtensionsLabel; private Map<String, DictionaryItemExtensionWrapper> originalValue = new HashMap<String, DictionaryItemExtensionWrapper>(); private List<DictionaryItemExtensionWrapper> modifiedValue; public DictionaryItemExtensionField(Application application, I18NSource source) { this.source = source; this.application = application; initView(); } private void initView() { VerticalLayout root = new VerticalLayout(); root.setStyleName("borderless light"); root.setWidth("100%"); root.setMargin(false); noExtensionsLabel = new Label("<i>" + getMessage("dict.item.noextensions") + "</i>", Label.CONTENT_XHTML); itemsLayout = new VerticalLayout(); itemsLayout.setWidth("100%"); addButton = addIcon(application); addButton.setDescription(getMessage("dict.add.extension")); addButton.setCaption(getMessage("dict.add.extension")); addButton.addListener(new ClickListener() { @Override public void buttonClick(ClickEvent event) { DictionaryItemExtensionWrapper itemExtension = createDictionaryItemExtensionWrapper(); modifiedValue.add(itemExtension); createExtensionRow(itemExtension); } }); Label caption = new Label("<b>" + getMessage("dict.item.extensions") + "</b>", Label.CONTENT_XHTML); caption.setWidth("100%"); HorizontalLayout captionLayout = new HorizontalLayout(); captionLayout.setWidth("100%"); captionLayout.setSpacing(true); captionLayout.addComponent(caption); captionLayout.setComponentAlignment(caption, Alignment.MIDDLE_LEFT); captionLayout.addComponent(addButton); captionLayout.setComponentAlignment(addButton, Alignment.MIDDLE_RIGHT); root.addComponent(captionLayout); root.addComponent(itemsLayout); setCompositionRoot(root); } protected abstract DictionaryItemExtensionWrapper createDictionaryItemExtensionWrapper(); public String getMessage(String key) { return source.getMessage(key); } public String getMessage(String key, String defaultValue) { return source.getMessage(key, defaultValue); } private void loadData() { itemsLayout.removeAllComponents(); createModifiedListFromOriginal(); if (modifiedValue.isEmpty()) { itemsLayout.addComponent(noExtensionsLabel); } else { for (DictionaryItemExtensionWrapper itemExtension : modifiedValue) { createExtensionRow(itemExtension); } } } private void createModifiedListFromOriginal() { modifiedValue = new ArrayList<DictionaryItemExtensionWrapper>(); for (DictionaryItemExtensionWrapper ext : originalValue.values()) { modifiedValue.add(ext.exactCopy()); } Collections.sort(modifiedValue, new Comparator<DictionaryItemExtensionWrapper>() { @Override public int compare(DictionaryItemExtensionWrapper o1, DictionaryItemExtensionWrapper o2) { return o1.getName().compareTo(o2.getName()); } }); } private void createExtensionRow(final DictionaryItemExtensionWrapper ext) { final ItemExtensionForm form = new ItemExtensionForm(ext); form.setWidth("100%"); form.addDeleteButton(new ClickListener() { @Override public void buttonClick(ClickEvent event) { itemsLayout.removeComponent(form); modifiedValue.remove(ext); if (modifiedValue.isEmpty()) { itemsLayout.addComponent(noExtensionsLabel); } } }); if (itemsLayout.getComponentIndex(noExtensionsLabel) != -1) { itemsLayout.removeComponent(noExtensionsLabel); } itemsLayout.addComponent(form); } @Override protected void setInternalValue(Object newValue) { if (newValue != null && !(newValue instanceof Map)) { throw new IllegalArgumentException("Unable to handle non-map values"); } originalValue = (Map<String, DictionaryItemExtensionWrapper>) newValue; loadData(); super.setInternalValue(newValue); } @Override public Object getValue() { validateInternal(); Map<String, DictionaryItemExtensionWrapper> value = new HashMap<String, DictionaryItemExtensionWrapper>(); for (DictionaryItemExtensionWrapper ext : modifiedValue) { value.put(ext.getName(), ext); } return value; } @Override public void validate() throws InvalidValueException { validateInternal(); super.validate(); } public void validateInternal() { if (!modifiedValue.isEmpty()) { for (Iterator<Component> it = itemsLayout.getComponentIterator(); it.hasNext(); ) { ItemExtensionForm form = (ItemExtensionForm) it.next(); form.commit(); } for (DictionaryItemExtensionWrapper ext : modifiedValue) { for (DictionaryItemExtensionWrapper otherExt : modifiedValue) { if (ext != otherExt && ext.getName().equals(otherExt.getName())) { throw new InvalidValueException(getMessage("validate.item.ext.name.duplicate").replaceFirst("%s", ext.getName())); } } } } } @Override public Class<?> getType() { return Map.class; } @Override public void setReadOnly(boolean readOnly) { for (Iterator<Component> it = itemsLayout.getComponentIterator(); it.hasNext(); ) { it.next().setReadOnly(readOnly); } addButton.setVisible(!readOnly); super.setReadOnly(readOnly); } @Override public void discard() throws SourceException { super.discard(); createModifiedListFromOriginal(); } private class ItemExtensionForm extends Form { private HorizontalLayout layout; private Button deleteButton; private ItemExtensionForm(DictionaryItemExtensionWrapper ext) { layout = new HorizontalLayout(); layout.setSpacing(true); layout.setWidth("100%"); setLayout(layout); setValidationVisible(false); setValidationVisibleOnCommit(false); setWriteThrough(false); setImmediate(true); setInvalidCommitted(false); setFormFieldFactory(new ItemExtensionFormFieldFactory()); setVisibleItemProperties(new String[] { _NAME, _VALUE }); setItemDataSource(new BeanItem<DictionaryItemExtensionWrapper>(ext)); deleteButton = deleteIcon(application); deleteButton.setCaption(getMessage("dict.delete.ext")); deleteButton.setDescription(getMessage("dict.delete.ext")); layout.addComponent(deleteButton); layout.setComponentAlignment(deleteButton, Alignment.MIDDLE_RIGHT); layout.setExpandRatio(deleteButton, 1.0F); } public void addDeleteButton(ClickListener listener) { deleteButton.addListener(listener); } @Override public void setReadOnly(boolean readOnly) { super.setReadOnly(readOnly); if (deleteButton != null) { deleteButton.setVisible(!readOnly); } } } private class ItemExtensionFormFieldFactory extends DefaultFieldFactory { @Override public Field createField(Item item, Object propertyId, Component uiContext) { Field field = null; if (propertyId.equals(_NAME) || propertyId.equals(_VALUE)) { TextField textField = new TextField(); textField.setNullRepresentation(""); if (_NAME.equals(propertyId)) { textField.setRequired(true); textField.setRequiredError(getMessage("validate.item.ext.name.empty")); textField.setCaption(getMessage("dict.item.extensions.name")); } else { textField.setCaption(getMessage("dict.item.extensions.value")); } field = textField; } return field; } } }