package org.dashbuilder.common.client.editor.map; import com.google.gwt.editor.client.EditorError; import com.google.gwt.editor.client.HasEditorErrors; import com.google.gwt.editor.client.LeafValueEditor; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; import org.dashbuilder.common.client.editor.LeafAttributeEditor; import org.dashbuilder.common.client.event.ValueChangeEvent; import org.dashbuilder.common.client.resources.i18n.DashbuilderCommonConstants; import org.uberfire.client.mvp.UberView; import javax.annotation.PostConstruct; import javax.enterprise.context.Dependent; import javax.enterprise.event.Event; import javax.inject.Inject; import java.util.*; /** * <p>Provides an editor for a Map instance of String values.</p> * * @since 0.4.0 */ @Dependent public class MapEditor implements IsWidget, LeafAttributeEditor<Map<String, String>> { public interface View extends UberView<MapEditor> { View setEmptyText(String text); View setAddText(String text); View addTextColumn(int columnIndex, String header, boolean isSortable, int width); View addButtonColumn(int columnIndex, String header, int width); View removeColumn(int index); View setRowCount(int count); View setData(List<Map.Entry<String, String>> data); View showError(SafeHtml message); View clearError(); } Event<org.dashbuilder.common.client.event.ValueChangeEvent<Map<String, String>>> valueChangeEvent; public View view; Map<String, String> value; @Inject public MapEditor(final View view, final Event<org.dashbuilder.common.client.event.ValueChangeEvent<Map<String, String>>> valueChangeEvent) { this.view = view; this.valueChangeEvent = valueChangeEvent; } @PostConstruct public void init() { view.init(this); view.setAddText(DashbuilderCommonConstants.INSTANCE.add()); initDataGrid(); } /************************************************************* ** GWT EDITOR CONTRACT METHODS ** *************************************************************/ @Override public void showErrors(final List<EditorError> errors) { StringBuilder sb = new StringBuilder(); for (EditorError error : errors) { if (error.getEditor() == this) { sb.append("\n").append(error.getMessage()); } } boolean hasErrors = sb.length() > 0; if (!hasErrors) { view.clearError(); return; } // Show the errors. view.showError(new SafeHtmlBuilder().appendEscaped(sb.substring(1)).toSafeHtml()); } @Override public Widget asWidget() { return view.asWidget(); } @Override public void setValue(final Map<String, String> value) { setValue(value, false); } @Override public Map<String, String> getValue() { return value; } /************************************************************* ** VIEW CALLBACK METHODS ** *************************************************************/ void addEntry() { onAddEntry(); } String getValue(final int columnIndex, final Map.Entry<String, String> object) { // Key updated. if (columnIndex == 0) { return object.getKey(); } // Value updated. if (columnIndex == 1) { return object.getValue(); } return null; } void update(final int columnIndex, final int index, final Map.Entry<String, String> object, final String value) { // Key updated. if (columnIndex == 0) { onKeyUpdated(index, object, value); // Value updated. } else if (columnIndex == 1) { onValueUpdated(index, object, value); // Remove action. } else if (columnIndex == 2) { onRemoveEntry(object); } } /************************************************************* ** PRIVATE EDITOR METHODS ** *************************************************************/ private void onKeyUpdated(final int index, final Map.Entry<String, String> object, final String value) { final HashMap<String, String> _m = new LinkedHashMap<String, String>(getValue()); final String lastKeyValue = object.getKey(); String mapValue = ""; if (lastKeyValue != null) { mapValue = _m.remove(lastKeyValue); } _m.put(value, mapValue); setValue(_m, true); } private void onValueUpdated(final int index, final Map.Entry<String, String> object, final String value) { // Look for the entry. final String key = getKeyParameter(index); final HashMap<String, String> _m = new LinkedHashMap<String, String>(getValue()); _m.put(key, value); setValue(_m, true); } private void onRemoveEntry(final Map.Entry<String, String> object) { if (getValue() != null) { final HashMap<String, String> _m = new LinkedHashMap<String, String>(getValue()); _m.remove(object.getKey()); setValue(_m, true); } } private void onAddEntry() { final String key = DashbuilderCommonConstants.INSTANCE.newValue(); final String value = DashbuilderCommonConstants.INSTANCE.newValue(); final HashMap<String, String> _m = new LinkedHashMap<String, String>();; _m.put(key, value); if (getValue() != null) { _m.putAll(getValue()); } // New value. setValue(_m, true); } private void setValue(final Map<String, String> value, final boolean fireEvents) { // Disable current error markers, if present. view.clearError(); final Map<String, String> before = this.value; this.value = value; // Fill grid values. redraw(); // Fire events, if necessary. if (fireEvents) { valueChangeEvent.fire(new ValueChangeEvent<Map<String, String>>(this, before, value)); } } private void initDataGrid() { view.setEmptyText(DashbuilderCommonConstants.INSTANCE.noData()); addColumns(); } private void addColumns() { // Key column. view.addTextColumn(0, DashbuilderCommonConstants.INSTANCE.key(), false, 20); // Value column. view.addTextColumn(1, DashbuilderCommonConstants.INSTANCE.value(), false, 20); // Remove action column. view.addButtonColumn(2, DashbuilderCommonConstants.INSTANCE.actions(), 20); } private String getKeyParameter(final int index) { if (getValue() != null && !getValue().isEmpty() && index > -1) { int x = 0; for (Map.Entry<String, String> entry : getValue().entrySet()) { if (index == x) return entry.getKey(); x++; } } return null; } private void redraw() { // NOTE: If not removing and re-adding columns, grid tow data refresh is not well done. view.removeColumn(0); view.removeColumn(0); view.removeColumn(0); // Rebuild grid columns. initDataGrid(); // Set new data. final int count = value != null ? value.size() : 0; final List<Map.Entry<String, String>> list = value != null ? new LinkedList<Map.Entry<String, String>>(value.entrySet()) : new LinkedList<Map.Entry<String, String>>(); view.setRowCount(count); view.setData(list); } }