/*
* SK's Minecraft Launcher
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
* Please see LICENSE.txt for license information.
*/
package com.skcraft.launcher.swing;
import com.google.common.base.Strings;
import lombok.NonNull;
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class ObjectSwingMapper {
private final List<FieldMapping> mappings = new ArrayList<FieldMapping>();
private final Object object;
public ObjectSwingMapper(@NonNull Object object) {
this.object = object;
}
public void copyFromObject() {
for (FieldMapping mapping : mappings) {
mapping.copyFromObject();
}
}
public void copyFromSwing() {
for (FieldMapping mapping : mappings) {
mapping.copyFromSwing();
}
}
private void add(@NonNull FieldMapping mapping) {
mappings.add(mapping);
}
private <V> MutatorAccessorField<V> getField(@NonNull String field, Class<V> clazz) {
return new MutatorAccessorField<V>(object, field, clazz);
}
public void map(@NonNull final JTextComponent textComponent, String name) {
final MutatorAccessorField<String> field = getField(name, String.class);
add(new FieldMapping() {
@Override
public void copyFromObject() {
textComponent.setText(field.get());
}
@SuppressWarnings("unchecked")
@Override
public void copyFromSwing() {
field.set(Strings.emptyToNull(textComponent.getText()));
}
});
}
public void map(@NonNull final JSpinner spinner, String name) {
final MutatorAccessorField<Integer> field = getField(name, int.class);
add(new FieldMapping() {
@Override
public void copyFromObject() {
spinner.setValue(field.get());
}
@SuppressWarnings("unchecked")
@Override
public void copyFromSwing() {
field.set((Integer) spinner.getValue());
}
});
}
public void map(@NonNull final JCheckBox check, String name) {
final MutatorAccessorField<Boolean> field = getField(name, boolean.class);
add(new FieldMapping() {
@Override
public void copyFromObject() {
check.setSelected(field.get());
}
@SuppressWarnings("unchecked")
@Override
public void copyFromSwing() {
field.set(check.isSelected());
}
});
}
public static interface FieldMapping {
void copyFromObject();
void copyFromSwing();
}
public static class MutatorAccessorField<V> {
private final Class<V> clazz;
private final Object object;
private final Method mutator;
private final Method accessor;
public MutatorAccessorField(Object object, String name, Class<V> clazz) {
this.object = object;
this.clazz = clazz;
Method mutator = null;
Method accessor = null;
for (Method method : object.getClass().getMethods()) {
if (isAccessor(method, name)) {
accessor = method;
} else if (isMutator(method, name)) {
mutator = method;
}
}
if (accessor == null) {
throw new NoSuchMethodError("Failed to find accessor pair on " +
object.getClass().getCanonicalName() + " for " + name);
}
if (mutator == null) {
throw new NoSuchMethodError("Failed to find mutator pair on " +
object.getClass().getCanonicalName() + " for " + name);
}
this.mutator = mutator;
this.accessor = accessor;
}
private boolean isAccessor(Method method, String name) {
String methodName = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
Class<?> returnType = method.getReturnType();
return (methodName.equalsIgnoreCase("get" + name) ||
methodName.equalsIgnoreCase("is" + name)) &&
paramTypes.length == 0 &&
clazz.isAssignableFrom(returnType);
}
private boolean isMutator(Method method, String name) {
String methodName = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
return methodName.equalsIgnoreCase("set" + name) &&
paramTypes.length == 1 &&
paramTypes[0].isAssignableFrom(clazz);
}
@SuppressWarnings("unchecked")
public V get() {
try {
Object value = accessor.invoke(object);
return (V) value;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
public void set(V value) {
try {
mutator.invoke(object, value);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}