package sk.stuba.fiit.perconik.eclipse.jface.dialogs;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.Maps.immutableEntry;
import static sk.stuba.fiit.perconik.utilities.MorePreconditions.checkNotNullOrEmpty;
public class MapEntryDialog<K, V> extends StatusDialog {
private final EntryConverter<K, V> converter;
private Entry<K, V> entry;
private Label keyLabel;
private Text keyText;
private Label valueLabel;
private Text valueText;
public MapEntryDialog(final Shell parent) {
this(parent, StringEntryConverter.<K, V>create());
}
public MapEntryDialog(final Shell parent, final EntryConverter<K, V> converter) {
super(parent);
this.converter = checkNotNull(converter);
}
public interface EntryConverter<K, V> {
public Entry<K, V> toEntry(Entry<K, V> original, String key, String value);
public Entry<String, String> toText(K key, V value);
}
public static abstract class AbstractEntryConverter<K, V> implements EntryConverter<K, V> {
protected AbstractEntryConverter() {}
public Entry<K, V> toEntry(final Entry<K, V> original, final String key, final String value) {
return immutableEntry(this.textToKey(original.getKey(), key), this.textToValue(original.getValue(), value));
}
protected abstract K textToKey(@Nullable K original, @Nullable String text);
protected abstract V textToValue(@Nullable V original, @Nullable String text);
public Entry<String, String> toText(final K key, final V value) {
return immutableEntry(this.keyToText(key), this.valueToText(value));
}
protected abstract String keyToText(@Nullable K key);
protected abstract String valueToText(@Nullable V value);
}
public static final class StringEntryConverter extends AbstractEntryConverter<Object, Object> {
private static final StringEntryConverter INSTANCE = new StringEntryConverter();
private StringEntryConverter() {}
public static <K, V> EntryConverter<K, V> create() {
@SuppressWarnings("unchecked")
EntryConverter<K, V> converter = (EntryConverter<K, V>) StringEntryConverter.INSTANCE;
return converter;
}
@Override
protected String textToKey(@Nullable final Object original, @Nullable final String text) {
return checkNotNullOrEmpty(text);
}
@Override
protected String textToValue(@Nullable final Object original, @Nullable final String text) {
return emptyToNull(text);
}
private static String toText(@Nullable final Object value) {
return value != null ? value.toString() : "";
}
@Override
protected String keyToText(@Nullable final Object key) {
return toText(key);
}
@Override
protected String valueToText(@Nullable final Object value) {
return toText(value);
}
}
@Override
protected Control createDialogArea(final Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(4, false));
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
this.keyLabel = new Label(composite, SWT.NONE);
this.keyText = new Text(composite, SWT.BORDER);
this.keyLabel.setText("Key");
this.keyLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
this.keyText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
this.valueLabel = new Label(composite, SWT.NONE);
this.valueText = new Text(composite, SWT.BORDER);
this.valueLabel.setText("Value");
this.valueLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, true, 1, 1));
this.valueText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true, 3, 1));
ModifyListener validator = new ModifyListener() {
public void modifyText(final ModifyEvent e) {
update();
}
};
this.keyText.addModifyListener(validator);
this.valueText.addModifyListener(validator);
Dialog.applyDialogFont(composite);
this.writeToText();
this.keyText.setFocus();
return composite;
}
@Override
protected void okPressed() {
this.entry = this.readFromText();
super.okPressed();
}
private Entry<K, V> readFromText() {
return this.converter.toEntry(this.entry, this.keyText.getText(), this.valueText.getText());
}
private void writeToText() {
Entry<String, String> text = this.converter.toText(this.entry.getKey(), this.entry.getValue());
this.keyText.setText(text.getKey());
this.valueText.setText(text.getValue());
}
void update() {
try {
this.readFromText();
this.updateStatus(Status.OK_STATUS);
} catch (RuntimeException failure) {
this.updateStatus(new Status(IStatus.ERROR, Status.CANCEL_STATUS.getPlugin(), IStatus.OK, "Invalid option", failure));
}
}
public final void setEntry(final Entry<? extends K, ? extends V> entry) {
this.entry = immutableEntry((K) entry.getKey(), (V) entry.getValue());
}
public final EntryConverter<K, V> getConverter() {
return this.converter;
}
public final Entry<K, V> getEntry() {
return this.entry;
}
@Override
public boolean isHelpAvailable() {
return false;
}
@Override
protected boolean isResizable() {
return true;
}
}