Bug 148327 - Add factory methods for enum converters
And use it in snippet.
Change-Id: I99ec7510c035cc07c68067570e0ead5bd7a7449d
Signed-off-by: Jens Lidestrom <jens@lidestrom.se>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.ui/+/155307
Tested-by: Platform Bot <platform-bot@eclipse.org>
Tested-by: Lars Vogel <Lars.Vogel@vogella.com>
Reviewed-by: Lars Vogel <Lars.Vogel@vogella.com>
diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/conversion/EnumConverters.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/conversion/EnumConverters.java
new file mode 100644
index 0000000..e837b4d
--- /dev/null
+++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/conversion/EnumConverters.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Jens Lidestrom and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Jens Lidestrom - initial API and implementation (Bug 148327)
+ ******************************************************************************/
+
+package org.eclipse.core.databinding.conversion;
+
+import java.util.Objects;
+
+/**
+ * Contains static methods the create converters for working with {@link Enum}s.
+ *
+ * @since 1.11
+ */
+public class EnumConverters {
+ /**
+ * Creates a converter which converts from {@link Enum#ordinal}s to enum values
+ * of the given type. Invalid ordinal values are converted to {@code null}.
+ *
+ * @param enumToType to type; not null
+ * @return the created converter
+ */
+ public static <T extends Enum<T>> IConverter<Integer, T> fromOrdinal(Class<T> enumToType) {
+ Objects.requireNonNull(enumToType);
+ T[] ordinals = enumToType.getEnumConstants();
+ return IConverter.create(Integer.class, enumToType,
+ i -> i == null || i < 0 || i >= ordinals.length ? null : ordinals[i]);
+ }
+
+ /**
+ * Creates a converter which converts from the {@link #toString} values of enums
+ * values to enum values themselves. Invalid string values are converted to
+ * {@code null}.
+ *
+ * @param enumToType to type; not null
+ * @return the created converter
+ */
+ public static <T extends Enum<T>> IConverter<String, T> fromString(Class<T> enumToType) {
+ Objects.requireNonNull(enumToType);
+ return IConverter.create(String.class, enumToType, text -> {
+ if (text == null) {
+ return null;
+ }
+
+ try {
+ return Enum.valueOf(enumToType, text);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Creates a converter which converts from {@link Enum#ordinal}s to enum values
+ * of the given type. {@code null} in the converter input is converted to
+ * {@code null}.
+ *
+ * @param enumFromType from type; not null
+ * @return the created converter
+ */
+ public static <T extends Enum<T>> IConverter<T, Integer> toOrdinal(Class<T> enumFromType) {
+ Objects.requireNonNull(enumFromType);
+ return IConverter.create(enumFromType, Integer.class, e -> e == null ? null : e.ordinal());
+ }
+
+ /**
+ * Creates a converter which converts to the {@link #toString} values of the
+ * enum constants. {@code null} in the converter input is converted to
+ * {@code null}.
+ *
+ * @param enumFromType from type; not null
+ * @return the created converter
+ */
+ public static <T extends Enum<T>> IConverter<T, String> toString(Class<T> enumFromType) {
+ Objects.requireNonNull(enumFromType);
+ return IConverter.create(enumFromType, String.class, e -> e == null ? null : e.toString());
+ }
+}
diff --git a/examples/org.eclipse.jface.examples.databinding/META-INF/MANIFEST.MF b/examples/org.eclipse.jface.examples.databinding/META-INF/MANIFEST.MF
index d5a1436..aff2fe3 100644
--- a/examples/org.eclipse.jface.examples.databinding/META-INF/MANIFEST.MF
+++ b/examples/org.eclipse.jface.examples.databinding/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jface.examples.databinding
-Bundle-Version: 1.2.100.qualifier
+Bundle-Version: 1.3.0.qualifier
Eclipse-BundleShape: dir
Bundle-ClassPath: .
Bundle-Vendor: %providerName
diff --git a/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet034ComboViewerAndEnum.java b/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet034ComboViewerAndEnum.java
index 0248f30..816aff8 100644
--- a/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet034ComboViewerAndEnum.java
+++ b/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet034ComboViewerAndEnum.java
@@ -15,8 +15,14 @@
package org.eclipse.jface.examples.databinding.snippets;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.beans.typed.BeanProperties;
import org.eclipse.core.databinding.beans.typed.PojoProperties;
+import org.eclipse.core.databinding.conversion.EnumConverters;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.databinding.swt.typed.WidgetProperties;
@@ -26,6 +32,7 @@
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
@@ -73,8 +80,9 @@
* need to implement the JavaBeans property change listener methods.
*/
static class Person {
- String name;
- Gender gender;
+ private String name;
+ private Gender gender;
+ private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public Person(String name, Gender gender) {
this.name = name;
@@ -85,8 +93,10 @@
return name;
}
- public void setName(String name) {
- this.name = name;
+ public void setName(String newName) {
+ String old = this.name;
+ this.name = newName;
+ propertyChangeSupport.firePropertyChange("name", old, name);
}
public Gender getGender() {
@@ -94,8 +104,19 @@
}
public void setGender(Gender newGender) {
+ Gender old = this.gender;
this.gender = newGender;
+ propertyChangeSupport.firePropertyChange("gender", old, gender);
}
+
+ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
+ }
+
+ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
+ }
+
}
/** The GUI view. */
@@ -103,6 +124,7 @@
private Person viewModel;
private Text name;
private ComboViewer gender;
+ private Label genderText;
public View(Person viewModel) {
this.viewModel = viewModel;
@@ -120,6 +142,7 @@
name = new Text(shell, SWT.BORDER);
gender = new ComboViewer(shell, SWT.READ_ONLY);
+ genderText = new Label(shell, SWT.NONE);
// Here's the first key to binding a combo to an Enum:
// First give it an ArrayContentProvider,
@@ -138,10 +161,15 @@
bindingContext.bindValue(ViewerProperties.singleSelection(Gender.class).observe(gender),
PojoProperties.value(Person.class, "gender").observe(viewModel));
+ // The EnumConverters class is convenient when binding an enum in a situation
+ // where a Viewer can not be used
+ bindingContext.bindValue(WidgetProperties.text().observe(genderText),
+ BeanProperties.value(Person.class, "gender", Gender.class).observe(viewModel), null,
+ UpdateValueStrategy.create(EnumConverters.toString(Gender.class)));
+
shell.pack();
shell.open();
return shell;
}
}
-
}
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/EnumConvertersTest.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/EnumConvertersTest.java
new file mode 100644
index 0000000..8d242f7
--- /dev/null
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/EnumConvertersTest.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Jens Lidestrom and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Jens Lidestrom - initial API and implementation (Bug 558842)
+ ******************************************************************************/
+
+package org.eclipse.core.tests.internal.databinding;
+
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.core.databinding.conversion.EnumConverters;
+import org.eclipse.core.databinding.conversion.IConverter;
+import org.junit.Test;
+
+/**
+ * Test for {@link EnumConverters}.
+ */
+public class EnumConvertersTest {
+
+ enum TestEnum {
+ A, B;
+
+ @Override
+ public String toString() {
+ // To be able to tell apart from the enum name
+ return name().toLowerCase();
+ }
+ }
+
+ @Test
+ public void testFromOrdinal() {
+ IConverter<Integer, TestEnum> fromOrdinal = EnumConverters.fromOrdinal(TestEnum.class);
+ assertEquals(TestEnum.A, fromOrdinal.convert(0));
+ assertEquals(null, fromOrdinal.convert(null));
+ assertEquals(null, fromOrdinal.convert(100));
+ assertEquals(Integer.class, fromOrdinal.getFromType());
+ assertEquals(TestEnum.class, fromOrdinal.getToType());
+ }
+
+ @Test
+ public void testFromString() {
+ IConverter<String, TestEnum> fromOrdinal = EnumConverters.fromString(TestEnum.class);
+ assertEquals(TestEnum.A, fromOrdinal.convert("A"));
+ assertEquals(null, fromOrdinal.convert("a"));
+ assertEquals(null, fromOrdinal.convert(null));
+ assertEquals(String.class, fromOrdinal.getFromType());
+ assertEquals(TestEnum.class, fromOrdinal.getToType());
+ }
+
+ @Test
+ public void testToString() {
+ IConverter<TestEnum, String> fromOrdinal = EnumConverters.toString(TestEnum.class);
+ assertEquals("a", fromOrdinal.convert(TestEnum.A));
+ assertEquals(null, fromOrdinal.convert(null));
+ assertEquals(TestEnum.class, fromOrdinal.getFromType());
+ assertEquals(String.class, fromOrdinal.getToType());
+ }
+
+ @Test
+ public void testToOrdinal() {
+ IConverter<TestEnum, Integer> converter = EnumConverters.toOrdinal(TestEnum.class);
+ assertEquals(0, (int) converter.convert(TestEnum.A));
+ assertEquals(null, converter.convert(null));
+ assertEquals(TestEnum.class, converter.getFromType());
+ assertEquals(Integer.class, converter.getToType());
+ }
+}