package org.aperteworkflow.util.dict.ui;
import com.vaadin.Application;
import com.vaadin.data.Validator;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.ui.*;
import org.aperteworkflow.util.dict.wrappers.DictionaryItemExtensionWrapper;
import org.aperteworkflow.util.dict.wrappers.DictionaryItemValueWrapper;
import org.aperteworkflow.util.dict.wrappers.DictionaryItemWrapper;
import org.aperteworkflow.util.vaadin.VaadinUtility;
import org.aperteworkflow.util.vaadin.ui.table.LocalizedPagedTable;
import pl.net.bluesoft.rnd.util.i18n.I18NSource;
import pl.net.bluesoft.util.lang.Strings;
import java.text.DateFormat;
import java.util.*;
import static org.aperteworkflow.util.vaadin.VaadinUtility.*;
/**
* User: POlszewski
* Date: 2012-12-03
* Time: 11:16
*/
public abstract class DictionaryItemTableBuilder<
WrappedItemType,
ItemValueWrapperType extends DictionaryItemValueWrapper,
DictionaryItemWrapperType extends DictionaryItemWrapper<WrappedItemType, ItemValueWrapperType>
> {
private static final String EMPTY_VALID_DATE = "...";
public static final String _KEY = "key";
public static final String _DESCRIPTION = "description";
public static final String GEN_VALUE = "value";
public static final String GEN_EXTENSIONS = "extensions";
public static final String GEN_DELETE = "delete";
private DictionaryItemModificationHandler<DictionaryItemWrapperType> handler;
private Window detailsWindow = null;
public DictionaryItemTableBuilder(DictionaryItemModificationHandler<DictionaryItemWrapperType> handler) {
this.handler = handler;
}
public interface SaveCallback<DictionaryItemWrapperType extends DictionaryItemWrapper> {
void onSave(BeanItem<DictionaryItemWrapperType> item);
}
public interface DictionaryItemModificationHandler<DictionaryItemWrapperType extends DictionaryItemWrapper> {
void handleItemSave(DictionaryItemWrapperType item);
void handleItemDelete(DictionaryItemWrapperType item);
}
private class DictPopupView extends PopupView {
private Label info;
public DictPopupView(final String smallTitle, DictPopupVisibilityListener listener) {
super(smallTitle, null);
this.info = new Label("", Label.CONTENT_XHTML);
this.info.setWidth(400, UNITS_PIXELS);
setContent(new Content() {
@Override
public String getMinimizedValueAsHTML() {
return smallTitle;
}
@Override
public Component getPopupComponent() {
return info;
}
});
listener.setLargeView(info);
addListener(listener);
setHideOnMouseOut(true);
addStyleName("bubble");
}
}
private abstract class DictPopupVisibilityListener<
WrappedItemType,
ItemValueWrapperType extends DictionaryItemValueWrapper,
DictionaryItemWrapperType extends DictionaryItemWrapper<WrappedItemType, ItemValueWrapperType>
> implements PopupView.PopupVisibilityListener {
private final BeanItemContainer<DictionaryItemWrapperType> container;
private final Object itemId;
private Label largeView;
public DictPopupVisibilityListener(BeanItemContainer<DictionaryItemWrapperType> container, Object itemId) {
this.container = container;
this.itemId = itemId;
}
public void setLargeView(Label largeView) {
this.largeView = largeView;
}
public abstract String getEmptyDescription();
public abstract String getItemRepresentation(ItemValueWrapperType item);
@Override
public void popupVisibilityChange(PopupView.PopupVisibilityEvent event) {
if (event.isPopupVisible()) {
DictionaryItemWrapperType item = container.getItem(itemId).getBean();
List<ItemValueWrapperType> values = new ArrayList<ItemValueWrapperType>(item.getValues());
StringBuilder sb = new StringBuilder();
if (values.isEmpty()) {
sb.append(getEmptyDescription());
}
else {
sb.append("<ul>");
Collections.sort(values, new Comparator<ItemValueWrapperType>() {
@Override
public int compare(ItemValueWrapperType o1, ItemValueWrapperType o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
for (ItemValueWrapperType value : values) {
sb.append("<li>").append(getItemRepresentation(value)).append("</li>");
}
sb.append("</ul>");
}
sb.append("</b>");
largeView.setValue(sb.toString());
}
}
}
public Component createTable(final BeanItemContainer<DictionaryItemWrapperType> container) {
Map<String, Table.ColumnGenerator> customColumns = new HashMap<String, Table.ColumnGenerator>();
customColumns.put(GEN_VALUE, createValueColumn(container));
customColumns.put(GEN_EXTENSIONS, createAdditionalValuesColumn(container));
customColumns.put(GEN_DELETE, createDeleteColumn(container));
String[] visibleColumns = new String[] { _KEY, _DESCRIPTION, GEN_VALUE, GEN_EXTENSIONS, GEN_DELETE };
String[] columnHeaders = new String[] {
getMessage("dict.item.key"), getMessage("dict.item.description"),
getMessage("dict.item.values"), getMessage("dict.item.extensions"),
getMessage("pagedtable.delete")
};
LocalizedPagedTable table = pagedTable(container, visibleColumns, columnHeaders, customColumns, new ItemClickEvent.ItemClickListener() {
@Override
public void itemClick(ItemClickEvent event) {
showItemDetails(container.getItem(event.getItemId()), new SaveCallback<DictionaryItemWrapperType>() {
@Override
public void onSave(BeanItem<DictionaryItemWrapperType> item) {
handler.handleItemSave(item.getBean());
closeDetailsWindow();
}
});
}
});
return wrapPagedTable(getI18NSource(), table);
}
private Table.ColumnGenerator createValueColumn(final BeanItemContainer<DictionaryItemWrapperType> container) {
return new Table.ColumnGenerator() {
@Override
public Component generateCell(Table source, final Object itemId, Object columnId) {
return new DictPopupView(getMessage("dict.showValues"), new DictPopupVisibilityListener<WrappedItemType, ItemValueWrapperType, DictionaryItemWrapperType>(container, itemId) {
@Override
public String getEmptyDescription() {
return getMessage("dict.item.novalues");
}
@Override
public String getItemRepresentation(ItemValueWrapperType item) {
DateFormat dateFormat = VaadinUtility.simpleDateFormat();
StringBuilder sb = new StringBuilder().append("<b>").append(item.getValue()).append("</b>").append(" (").append("<i>");
if (item.hasFullDatesRange()) {
sb.append(getMessage("dict.full.range"));
}
else {
sb.append(item.getValidStartDate() != null ? dateFormat.format(item.getValidStartDate()) : EMPTY_VALID_DATE)
.append(" - ")
.append(item.getValidEndDate() != null ? dateFormat.format(item.getValidEndDate()) : EMPTY_VALID_DATE);
}
sb.append("</i>)");
return sb.toString();
}
});
}
};
}
private Table.ColumnGenerator createAdditionalValuesColumn(final BeanItemContainer<DictionaryItemWrapperType> container) {
return new Table.ColumnGenerator() {
@Override
public Component generateCell(Table source, final Object itemId, Object columnId) {
return new DictPopupView(getMessage("dict.showExtensions"), new DictPopupVisibilityListener<WrappedItemType, ItemValueWrapperType, DictionaryItemWrapperType>(container, itemId) {
@Override
public String getEmptyDescription() {
return getMessage("dict.item.noextensions");
}
@Override
public String getItemRepresentation(ItemValueWrapperType item) {
StringBuilder sb = new StringBuilder().append("<b>").append(item.getValue()).append("</b>").append("<ul>");
List<String> extensionNames = new ArrayList<String>(item.getExtensionNames());
if (extensionNames.isEmpty()) {
sb.append("<li>").append(getMessage("dict.item.noextensions")).append("</li>");
}
else {
Collections.sort(extensionNames);
for (String extensionName : extensionNames) {
DictionaryItemExtensionWrapper ext = item.getExtensionByName(extensionName);
sb.append("<li>")
.append("<b>").append(ext.getName()).append("</b>")
.append(Strings.hasText(ext.getDescription())
? " (" + ext.getDescription() + ")" : "")
.append(": ")
.append(Strings.hasText(ext.getValue()) ? "<b>" + ext.getValue() + "</b>"
: getMessage("dict.item.extensions.novalue"))
.append("</li>");
}
}
sb.append("</ul>");
return sb.toString();
}
});
}
};
}
private Table.ColumnGenerator createDeleteColumn(final BeanItemContainer<DictionaryItemWrapperType> container) {
return new Table.ColumnGenerator() {
@Override
public Component generateCell(Table source, final Object itemId, Object columnId) {
Button b = smallButton(getMessage("pagedtable.delete"));
b.addListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
DictionaryItemWrapperType item = container.getItem(itemId).getBean();
container.removeItem(itemId);
handler.handleItemDelete(item);
}
});
return b;
}
};
}
public void showItemDetails(final BeanItem<DictionaryItemWrapperType> item, final SaveCallback<DictionaryItemWrapperType> callback) {
if (getDetailsWindow() != null) {
return;
}
final DictionaryItemForm form = createDictionaryItemForm(getApplication(), getI18NSource(), item);
form.setWidth("100%");
form.addSaveClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
Map<Field, String> messages = new LinkedHashMap<Field, String>();
for (Object propertyId : form.getItemPropertyIds()) {
Field field = form.getField(propertyId);
try {
field.validate();
}
catch (Validator.InvalidValueException e) {
messages.put(field, e.getMessage());
}
}
if (messages.isEmpty()) {
form.commit();
callback.onSave(item);
}
else {
StringBuilder sb = new StringBuilder();
for (String msg : messages.values()) {
sb.append(msg).append("<br/>");
}
validationNotification(getApplication(), getI18NSource(), sb.toString());
}
}
});
form.addCancelClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
form.discard();
closeDetailsWindow();
}
});
wrapWithModalWindow(form);
showDetailsWindow();
}
protected abstract DictionaryItemForm createDictionaryItemForm(Application application, I18NSource source, BeanItem<DictionaryItemWrapperType> item);
public void showDetailsWindow() {
getApplication().getMainWindow().addWindow(getDetailsWindow());
}
public void closeDetailsWindow() {
getApplication().getMainWindow().removeWindow(getDetailsWindow());
setDetailsWindow(null);
}
private void wrapWithModalWindow(Form form) {
Panel panel = new Panel();
panel.setWidth("800px");
panel.setScrollable(true);
panel.addComponent(form);
setDetailsWindow(modalWindow(getMessage("dict.item"), panel));
}
private String getMessage(String key) {
return getI18NSource().getMessage(key);
}
protected abstract Application getApplication();
protected abstract I18NSource getI18NSource();
private Window getDetailsWindow() {
return detailsWindow;
}
private void setDetailsWindow(Window detailsWindow) {
this.detailsWindow = detailsWindow;
}
}