/*
* Copyright (C) 2011 Nicolas Peransin. All rights reserved.
* Use is subject to license terms.
*/
package org.mypsycho.swing.app.reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.border.Border;
import org.mypsycho.beans.converter.AbstractTypeConverter;
import org.mypsycho.beans.converter.TypeConverter;
/**
* Create border using javax.swing.BorderFactory syntax
* <p>
* Use BorderFactory factory call without 'create' prefix.
* </p>
*
* @author Peransin Nicolas
*
*/
public class BorderConverter extends AbstractTypeConverter {
TypeConverter delegate;
public BorderConverter(TypeConverter d) {
super(Border.class);
delegate = d;
}
@Override
public Object convert(Class<?> expected, String value, Object context)
throws IllegalArgumentException {
List<String> call = decode(value);
if ("titled".equals(call.get(0)) && call.size() == 2) {
// Ambiguous case
return BorderFactory.createTitledBorder(call.get(1));
}
Method create = findCreateMethod(call);
Class<?>[] argTypes = create.getParameterTypes();
Object[] args = new Object[argTypes.length];
for (int i = 0; i < args.length; i++) {
args[i] = delegate.convert(argTypes[i], call.get(i + 1), context);
}
try {
return create.invoke(null, args);
} catch (Exception e) {
return reThrow("Cannot create border " + value, e);
}
}
protected Method findCreateMethod(List<String> call) {
String methodName = call.get(0);
methodName = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
methodName = "create" + methodName + "Border";
for (Method method : BorderFactory.class.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())
|| !Modifier.isPublic(method.getModifiers())
|| !methodName.equals(method.getName())) {
continue;
}
if (method.getParameterTypes().length == call.size() - 1) {
return method;
}
}
throw new IllegalArgumentException("Unknown Border method " + methodName);
}
protected List<String> decode(String pattern) {
List<String> invocation = new ArrayList<String>();
StringBuilder buf = new StringBuilder();
int braceStack = 0;
for (int i = 0; i < pattern.length(); ++i) {
char ch = pattern.charAt(i);
if (ch == '(') {
if (invocation.isEmpty()) {
invocation.add(buf.toString().trim());
buf.setLength(0);
} else {
braceStack++;
buf.append(ch);
}
} else if (ch == ',') {
if (invocation.isEmpty()) {
throw new IllegalArgumentException("unexpected separator at " + i);
}
if (braceStack == 0) {
invocation.add(buf.toString().trim());
buf.setLength(0);
} else {
buf.append(ch);
}
} else if (ch == ')') {
if (braceStack == 0) {
String end = pattern.substring(i).trim();
if (invocation.isEmpty() && !end.isEmpty()) {
throw new IllegalArgumentException("unexpected end: " + end);
}
invocation.add(buf.toString().trim());
buf.setLength(0);
} else {
braceStack--;
buf.append(ch);
}
} else {
buf.append(ch);
}
}
if (invocation.isEmpty()) {
invocation.add(buf.toString().trim());
buf.setLength(0);
}
if ((braceStack > 0) || (buf.length() > 0)) {
throw new IllegalArgumentException("unexpected end");
}
for (int i = 1; i < invocation.size(); i++) {
String arg = invocation.get(i);
if ((arg.charAt(0) == '(') && (arg.charAt(arg.length() - 1) == ')')) {
arg = arg.substring(1, arg.length() - 1);
}
invocation.set(i, arg);
}
return invocation;
}
}