com.esotericsoftware.tablelayout.Toolkit Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2011, Nathan Sweet
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package com.esotericsoftware.tablelayout;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import static com.esotericsoftware.tablelayout.BaseTableLayout.*;
/** @author Nathan Sweet */
public abstract class Toolkit {
static private final ArrayList classPrefixes = new ArrayList();
/** Adds a child to the specified parent.
* @param layoutString May be null. */
abstract public void addChild (C parent, C child, String layoutString);
abstract public void removeChild (C parent, C child);
abstract public int getMinWidth (C widget);
abstract public int getMinHeight (C widget);
abstract public int getPrefWidth (C widget);
abstract public int getPrefHeight (C widget);
abstract public int getMaxWidth (C widget);
abstract public int getMaxHeight (C widget);
/** Clears all debugging rectangles. */
abstract public void clearDebugRectangles (L layout);
/** Adds a rectangle that should be drawn for debugging.
* @param type {@value #DEBUG_ALL}, {@value #DEBUG_TABLE}, {@value #DEBUG_CELL}, {@value #DEBUG_WIDGET}, or
* {@value #DEBUG_NONE} */
abstract public void addDebugRectangle (L layout, int type, int x, int y, int w, int h);
/** Returns a new widget that sizes all of its children to its size. */
abstract public C newStack ();
/** Returns the layout for a table. */
abstract public L getLayout (T table);
/** Returns a new table that will be nested under the specified table. */
abstract public T newTable (T parent);
public void setWidget (L layout, Cell cell, C widget) {
removeChild((T)layout.table, (C)cell.widget);
layout.widgetToCell.remove(cell.widget);
cell.widget = widget;
if (cell.name != null) layout.nameToWidget.put(cell.name, widget);
layout.widgetToCell.put(widget, cell);
addChild((T)layout.table, widget, null);
}
/** Returns the value as {@link #width(BaseTableLayout, String)} unless it is one of the special values representing
* {@value #MIN}, {@value #PREF}, or {@value #MAX} width. */
int getWidgetWidth (L layout, C widget, String value) {
if (value.equals(MIN)) return getMinWidth(widget);
if (value.equals(PREF)) return getPrefWidth(widget);
if (value.equals(MAX)) return getMaxWidth(widget);
return width(layout, value);
}
/** Returns the value as {@link #height(BaseTableLayout, String)} unless it is one of the special values representing
* {@value #MIN}, {@value #PREF}, or {@value #MAX} height. */
int getWidgetHeight (L layout, C widget, String value) {
if (value.equals(MIN)) return getMinHeight(widget);
if (value.equals(PREF)) return getPrefHeight(widget);
if (value.equals(MAX)) return getMaxHeight(widget);
return height(layout, value);
}
/** Validates the specified size is properly formatted. A size is valid if it can be parsed by
* {@link #width(BaseTableLayout, String)} and {@link #height(BaseTableLayout, String)}. All sizes that are stored as strings
* pass through this method, providing a hook to validate sizes at parse time rather than layout time. The default
* implementation just returns the specified string. If the specified String is invalid, an exception should be thrown. */
protected String validateSize (String size) {
return size;
}
/** Creates a new widget from the specified class name. This can be overriden to create widgets using shortcut names (eg,
* "button"). The default implementation creates an instance of the class and calls {@link #wrap(BaseTableLayout, Object)}.
* @see #addClassPrefix(String)
* @throws RuntimeException if the class could be found or otherwise failed to be instantiated. */
public C newWidget (L layout, String className) {
try {
return wrap(layout, newInstance(layout, className));
} catch (Exception ex) {
for (int i = 0, n = classPrefixes.size(); i < n; i++) {
String prefix = classPrefixes.get(i);
try {
return newInstance(layout, prefix + className);
} catch (InvocationTargetException ex2) {
throw new RuntimeException(ex2);
} catch (Exception ignored) {
}
}
throw new RuntimeException("Error creating instance of class: " + className, ex);
}
}
/** Returns an instance of the specified class. This can be overidden to control what constructor and what classloader to use.
* The default implementation uses Class.forName(className).newInstance().
* @throws Exception if the class cannot be found or instantiated. */
protected C newInstance (L layout, String className) throws Exception {
return (C)Class.forName(className).newInstance();
}
/** Wraps the specified object in a widget. The default implementation handles the object being a TableLayout or widget. If the
* object is null, a placeholder widget to use for empty cells must be returned. If the object is a string, a label widget must
* be returned. Otherwise, the object can be any other class that was added to the table (eg, a Swing LayoutManager would be
* wrapped in a JPanel).
* @throws RuntimeException if the object could not be wrapped. */
public C wrap (L layout, Object object) {
if (object instanceof BaseTableLayout) return (C)((BaseTableLayout)object).getTable();
try {
return (C)object;
} catch (ClassCastException ex) {
throw new RuntimeException("Unknown object type: " + object.getClass());
}
}
/** Sets a property on the widget. This is called for widget properties specified in the table description. The default
* implementation attempts to find a method, bean setter method, or field that will accept the specified values.
* @throws RuntimeException if the property could not be set. */
public void setProperty (L layout, C object, String name, List values) {
try {
invokeMethod(layout, object, name, values);
} catch (NoSuchMethodException ex1) {
try {
invokeMethod(layout, object, "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1), values);
} catch (NoSuchMethodException ex2) {
try {
Field field = object.getClass().getField(name);
Object value = convertType(layout, object, field.getType(), name, values.get(0));
if (value != null)
field.set(object, value);
else
throw ex1;
} catch (Exception ex3) {
throw new RuntimeException("No method, bean property, or field found: " + name + "\nClass: " + object.getClass()
+ "\nValues: " + values);
}
}
}
}
/** Sets a property on the table. This is called for table properties specified in the table description.
* @throws RuntimeException if the property could not be set. */
public void setTableProperty (L layout, String name, List values) {
name = name.toLowerCase();
for (int i = 0, n = values.size(); i < n; i++)
values.set(i, values.get(i).toLowerCase());
try {
String value;
if (name.equals("size")) {
switch (values.size()) {
case 2:
value = values.get(0);
if (value.length() > 0) layout.width = validateSize(value);
value = values.get(1);
if (value.length() > 0) layout.height = validateSize(value);
return;
case 1:
value = values.get(0);
if (value.length() > 0) {
value = validateSize(value);
layout.width = value;
layout.height = value;
}
return;
}
} else if (name.equals("width") || name.equals("w")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) layout.width = validateSize(value);
return;
}
} else if (name.equals("height") || name.equals("h")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) layout.height = validateSize(value);
return;
}
} else if (name.equals("padding") || name.equals("pad")) {
switch (values.size()) {
case 4:
value = values.get(0);
if (value.length() > 0) layout.padTop = validateSize(value);
value = values.get(1);
if (value.length() > 0) layout.padLeft = validateSize(value);
value = values.get(2);
if (value.length() > 0) layout.padBottom = validateSize(value);
value = values.get(3);
if (value.length() > 0) layout.padRight = validateSize(value);
return;
case 1:
value = values.get(0);
if (value.length() > 0) layout.padTop = layout.padLeft = layout.padBottom = layout.padRight = validateSize(value);
return;
}
} else if (name.startsWith("padding") || name.startsWith("pad")) {
name = name.replace("padding", "").replace("pad", "");
if (values.size() == 1 && values.get(0).length() > 0) {
value = validateSize(values.get(0));
if (name.equals("top") || name.equals("t"))
layout.padTop = value;
else if (name.equals("left") || name.equals("l"))
layout.padLeft = value;
else if (name.equals("bottom") || name.equals("b"))
layout.padBottom = value;
else if (name.equals("right") || name.equals("r"))
layout.padRight = value;
else
throw new IllegalArgumentException("Unknown table padding property: " + name);
return;
}
} else if (name.equals("center")) {
if (values.size() == 0) {
layout.align |= CENTER;
return;
}
} else if (name.equals("left")) {
if (values.size() == 0) {
layout.align |= LEFT;
return;
}
} else if (name.equals("right")) {
if (values.size() == 0) {
layout.align |= RIGHT;
return;
}
} else if (name.equals("top")) {
if (values.size() == 0) {
layout.align |= TOP;
return;
}
} else if (name.equals("bottom")) {
if (values.size() == 0) {
layout.align |= BOTTOM;
return;
}
}
else if (name.equals("align")) {
layout.align = 0;
for (int i = 0, n = values.size(); i < n; i++) {
value = values.get(i);
if (value.equals("center") || value.equals("c"))
layout.align |= CENTER;
else if (value.equals("left") || value.equals("l"))
layout.align |= LEFT;
else if (value.equals("right") || value.equals("r"))
layout.align |= RIGHT;
else if (value.equals("top") || value.equals("t"))
layout.align |= TOP;
else if (value.equals("bottom") || value.equals("b"))
layout.align |= BOTTOM;
else
throw new IllegalArgumentException("Invalid table align value: " + value);
}
if (values.size() > 0) return;
} else if (name.equals("debug")) {
layout.debug = 0;
if (values.size() == 0) layout.debug = DEBUG_ALL;
for (int i = 0, n = values.size(); i < n; i++) {
value = values.get(i);
if (value.equalsIgnoreCase("all"))
layout.debug |= DEBUG_ALL;
else if (value.equalsIgnoreCase("cell"))
layout.debug |= DEBUG_CELL;
else if (value.equalsIgnoreCase("table"))
layout.debug |= DEBUG_TABLE;
else if (value.equalsIgnoreCase("widget"))
layout.debug |= DEBUG_WIDGET;
else if (value.equalsIgnoreCase("none"))
layout.debug = DEBUG_NONE;
else
throw new IllegalArgumentException("Invalid table debug value: " + value);
}
return;
} else
throw new IllegalArgumentException("Unknown table property: " + name);
throw new IllegalArgumentException("Invalid number of table property values (" + values.size() + "): " + values);
} catch (Exception ex) {
throw new RuntimeException("Error setting table property: " + name, ex);
}
}
// BOZO - Use name: table property instead of [name:{}]?
// BOZO - Make DSL properties consistent with cell methods.
// BOZO - Remove widget properties and children?
/** Sets a property on the cell. This is called for cell properties specified in the table description.
* @throws RuntimeException if the property could not be set. */
public void setCellProperty (Cell c, String name, List values) {
name = name.toLowerCase();
for (int i = 0, n = values.size(); i < n; i++)
values.set(i, values.get(i).toLowerCase());
try {
String value;
if (name.equals("expand")) {
switch (values.size()) {
case 0:
c.expandX = c.expandY = 1;
return;
case 1:
value = values.get(0);
if (value.equals("x"))
c.expandX = 1;
else if (value.equals("y")) //
c.expandY = 1;
else
c.expandX = c.expandY = Integer.parseInt(value);
return;
case 2:
value = values.get(0);
if (value.length() > 0) c.expandX = Integer.parseInt(value);
value = values.get(1);
if (value.length() > 0) c.expandY = Integer.parseInt(value);
return;
}
} else if (name.equals("expandx")) {
if (values.size() == 0) {
c.expandX = 1;
return;
}
} else if (name.equals("expandy")) {
if (values.size() == 0) {
c.expandY = 1;
return;
}
} else if (name.equals("fillx")) {
if (values.size() == 0) {
c.fillX = 1f;
return;
}
} else if (name.equals("filly")) {
if (values.size() == 0) {
c.fillY = 1f;
return;
}
} else if (name.equals("fill")) {
switch (values.size()) {
case 0:
c.fillX = c.fillY = 1f;
return;
case 1:
value = values.get(0);
if (value.equals("x"))
c.fillX = 1f;
else if (value.equals("y")) //
c.fillY = 1f;
else
c.fillX = c.fillY = Integer.parseInt(value) / 100f;
return;
case 2:
value = values.get(0);
if (value.length() > 0) c.fillX = Integer.parseInt(value) / 100f; // BOZO - Use float?
value = values.get(1);
if (value.length() > 0) c.fillY = Integer.parseInt(value) / 100f;
return;
}
} else if (name.equals("scale") || name.equals("scaling")) {
if (values.size() == 1) {
value = values.get(0);
if (value.equals("fit"))
c.scaling = SCALE_FIT;
else if (value.equals("fill"))
c.scaling = SCALE_FILL;
else if (value.equals("stretch"))
c.scaling = SCALE_STRETCH;
else
throw new IllegalArgumentException("Invalid value: " + value);
return;
}
} else if (name.equals("size")) {
switch (values.size()) {
case 2:
value = values.get(0);
if (value.length() > 0) c.minWidth = c.prefWidth = c.maxWidth = validateSize(value);
value = values.get(1);
if (value.length() > 0) c.minHeight = c.prefHeight = c.maxHeight = validateSize(value);
return;
case 1:
value = values.get(0);
if (value.length() > 0)
c.minWidth = c.minHeight = c.prefWidth = c.prefHeight = c.maxWidth = c.maxHeight = validateSize(value);
return;
}
} else if (name.equals("width") || name.equals("w")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.minWidth = c.prefWidth = c.maxWidth = validateSize(value);
return;
}
} else if (name.equals("height") || name.equals("h")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.minHeight = c.prefHeight = c.maxHeight = validateSize(value);
return;
}
} else if (name.equals("minsize") || name.equals("min")) {
switch (values.size()) {
case 1:
value = values.get(0);
if (value.length() > 0) c.minWidth = c.minHeight = validateSize(value);
return;
case 2:
value = values.get(0);
if (value.length() > 0) c.minWidth = validateSize(value);
value = values.get(1);
if (value.length() > 0) c.minHeight = validateSize(value);
return;
}
} else if (name.equals("minwidth") || name.equals("minw")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.minWidth = validateSize(value);
return;
}
} else if (name.equals("minheight") || name.equals("minh")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.minHeight = validateSize(value);
return;
}
} else if (name.equals("prefsize") || name.equals("pref")) {
switch (values.size()) {
case 1:
value = values.get(0);
if (value.length() > 0) c.prefWidth = c.prefHeight = validateSize(value);
return;
case 2:
value = values.get(0);
if (value.length() > 0) c.prefWidth = validateSize(value);
value = values.get(1);
if (value.length() > 0) c.prefHeight = validateSize(value);
return;
}
} else if (name.equals("prefwidth") || name.equals("prefw")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.prefWidth = validateSize(value);
return;
}
} else if (name.equals("prefheight") || name.equals("prefh")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.prefHeight = validateSize(value);
return;
}
} else if (name.equals("maxsize") || name.equals("max")) {
switch (values.size()) {
case 1:
value = values.get(0);
if (value.length() > 0) c.maxWidth = c.maxHeight = validateSize(value);
return;
case 2:
value = values.get(0);
if (value.length() > 0) c.maxWidth = validateSize(value);
value = values.get(1);
if (value.length() > 0) c.maxHeight = validateSize(value);
return;
}
} else if (name.equals("maxwidth") || name.equals("maxw")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.maxWidth = validateSize(value);
return;
}
} else if (name.equals("maxheight") || name.equals("maxh")) {
if (values.size() == 1) {
value = values.get(0);
if (value.length() > 0) c.maxHeight = validateSize(value);
return;
}
} else if (name.equals("padding") || name.equals("pad")) {
switch (values.size()) {
case 4:
value = values.get(0);
if (value.length() > 0) c.padTop = validateSize(value);
value = values.get(1);
if (value.length() > 0) c.padLeft = validateSize(value);
value = values.get(2);
if (value.length() > 0) c.padBottom = validateSize(value);
value = values.get(3);
if (value.length() > 0) c.padRight = validateSize(value);
return;
case 1:
value = values.get(0);
if (value.length() > 0) c.padTop = c.padLeft = c.padBottom = c.padRight = validateSize(value);
return;
}
} else if (name.startsWith("padding") || name.startsWith("pad")) {
name = name.replace("padding", "").replace("pad", "");
if (values.size() == 1 && values.get(0).length() > 0) {
value = validateSize(values.get(0));
if (name.equals("top") || name.equals("t"))
c.padTop = value;
else if (name.equals("left") || name.equals("l"))
c.padLeft = value;
else if (name.equals("bottom") || name.equals("b"))
c.padBottom = value;
else if (name.equals("right") || name.equals("r"))
c.padRight = value;
else
throw new IllegalArgumentException("Unknown cell padding property: " + name);
return;
}
} else if (name.equals("spacing") || name.equals("space")) {
switch (values.size()) {
case 4:
value = values.get(0);
if (value.length() > 0) c.spaceTop = validateSize(value);
value = values.get(1);
if (value.length() > 0) c.spaceLeft = validateSize(value);
value = values.get(2);
if (value.length() > 0) c.spaceBottom = validateSize(value);
value = values.get(3);
if (value.length() > 0) c.spaceRight = validateSize(value);
return;
case 1:
value = values.get(0);
if (value.length() > 0) c.spaceTop = c.spaceLeft = c.spaceBottom = c.spaceRight = validateSize(value);
return;
}
} else if (name.startsWith("spacing") || name.startsWith("space")) {
name = name.replace("spacing", "").replace("space", "");
if (values.size() == 1 && values.get(0).length() > 0) {
value = validateSize(values.get(0));
if (name.equals("top") || name.equals("t"))
c.spaceTop = value;
else if (name.equals("left") || name.equals("l"))
c.spaceLeft = value;
else if (name.equals("bottom") || name.equals("b"))
c.spaceBottom = value;
else if (name.equals("right") || name.equals("r"))
c.spaceRight = value;
else
throw new IllegalArgumentException("Unknown cell spacing property: " + name);
return;
}
} else if (name.equals("center")) {
if (values.size() == 0) {
c.align |= CENTER;
return;
}
} else if (name.equals("left")) {
if (values.size() == 0) {
c.align |= LEFT;
return;
}
} else if (name.equals("right")) {
if (values.size() == 0) {
c.align |= RIGHT;
return;
}
} else if (name.equals("top")) {
if (values.size() == 0) {
c.align |= TOP;
return;
}
} else if (name.equals("bottom")) {
if (values.size() == 0) {
c.align |= BOTTOM;
return;
}
}
else if (name.equals("align")) {
c.align = 0;
for (int i = 0, n = values.size(); i < n; i++) {
value = values.get(i);
if (value.equals("center") || value.equals("c"))
c.align |= CENTER;
else if (value.equals("left") || value.equals("l"))
c.align |= LEFT;
else if (value.equals("right") || value.equals("r"))
c.align |= RIGHT;
else if (value.equals("top") || value.equals("t"))
c.align |= TOP;
else if (value.equals("bottom") || value.equals("b"))
c.align |= BOTTOM;
else
throw new IllegalArgumentException("Invalid table align value: " + value);
}
if (values.size() > 0) return;
} else if (name.equals("ignore")) {
switch (values.size()) {
case 1:
c.ignore = Boolean.valueOf(values.get(0));
return;
case 0:
c.ignore = true;
return;
}
} else if (name.equals("colspan")) {
switch (values.size()) {
case 1:
c.colspan = Integer.parseInt(values.get(0));
return;
}
} else if (name.equals("uniform")) {
if (values.size() == 0) c.uniformX = c.uniformY = true;
for (int i = 0, n = values.size(); i < n; i++) {
value = values.get(i);
if (value.equals("x"))
c.uniformX = true;
else if (value.equals("y"))
c.uniformY = true;
else if (value.equals("true"))
c.uniformY = c.uniformY = true;
else if (value.equals("false"))
c.uniformY = c.uniformY = null;
else
throw new IllegalArgumentException("Invalid value: " + value);
}
return;
} else
throw new IllegalArgumentException("Unknown cell property.");
throw new IllegalArgumentException("Invalid number of cell property values (" + values.size() + "): " + values);
} catch (Exception ex) {
throw new RuntimeException("Error setting cell property: " + name, ex);
}
}
/** Interprets the specified value as a width. This can be used to scale all sizes applied to a cell, implement size units (eg,
* 23px or 23em), etc. The default implementation converts to an int and calls {@link #width(float)}. Zero is used for null and
* empty string. If the suffix is "%", the value is converted to an int, divided by 100, and multiplied by
* {@link BaseTableLayout#getLayoutWidth()}. If the suffix is "px", the value is converted to int without the suffix and
* returned unscaled.
* @param value May be null. */
public int width (L layout, String value) {
int length;
if (value == null || (length = value.length()) == 0) return width(0);
if (value.charAt(length - 1) == '%' && length > 1)
return (int)(layout.getLayoutWidth() * Integer.parseInt(value.substring(0, length - 1)) / 100f);
if (value.endsWith("px")) return Integer.parseInt(value.substring(0, value.length() - 2));
return width(value == null ? 0 : Integer.parseInt(value));
}
/** Interprets the specified value as a size. This can be used to scale all sizes applied to a cell. The default implementation
* just casts to int. */
public int width (float value) {
return (int)value;
}
/** Interprets the specified value as a height. This can be used to scale all sizes applied to a cell, implement size units (eg,
* 23px or 23em), etc. The default implementation converts to an int and calls {@link #height(float)}. Zero is used for null
* and empty string. If the suffix is "%", the value is converted to an int, divided by 100, and multiplied by
* {@link BaseTableLayout#getLayoutHeight()}. If the suffix is "px", the value is converted to int without the suffix and
* returned unscaled.
* @param value May be null. */
public int height (L layout, String value) {
int length;
if (value == null || (length = value.length()) == 0) return height(0);
if (value.charAt(length - 1) == '%' && length > 1)
return (int)(layout.getLayoutHeight() * Integer.parseInt(value.substring(0, length - 1)) / 100f);
if (value.endsWith("px")) return Integer.parseInt(value.substring(0, value.length() - 2));
return height(value == null ? 0 : Integer.parseInt(value));
}
/** Interprets the specified value as a size. This can be used to scale all sizes applied to a cell. The default implementation
* just casts to int. */
public int height (float value) {
return (int)value;
}
private void invokeMethod (L layout, Object object, String name, List values) throws NoSuchMethodException {
Object[] params = values.toArray();
// Prefer methods with string parameters.
Class[] stringParamTypes = new Class[params.length];
Method method = null;
try {
for (int i = 0, n = params.length; i < n; i++)
stringParamTypes[i] = String.class;
method = object.getClass().getMethod(name, stringParamTypes);
} catch (NoSuchMethodException ignored) {
try {
for (int i = 0, n = params.length; i < n; i++)
stringParamTypes[i] = CharSequence.class;
method = object.getClass().getMethod(name, stringParamTypes);
} catch (NoSuchMethodException ignored2) {
}
}
if (method != null) {
try {
method.invoke(object, params);
} catch (Exception ex) {
throw new RuntimeException("Error invoking method: " + name, ex);
}
return;
}
// Try to convert the strings to match a method's parameters.
Method[] methods = object.getClass().getMethods();
outer:
for (int i = 0, n = methods.length; i < n; i++) {
method = methods[i];
if (!method.getName().equalsIgnoreCase(name)) continue;
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != values.size()) continue;
params = values.toArray();
for (int ii = 0, nn = paramTypes.length; ii < nn; ii++) {
Object value = convertType(layout, object, paramTypes[ii], name, (String)params[ii]);
if (value == null) continue outer;
params[ii] = value;
}
try {
method.invoke(object, params);
return;
} catch (Exception ex) {
throw new RuntimeException("Error invoking method: " + name, ex);
}
}
// BOZO - Try to pass values as an array of strings or objects.
throw new NoSuchMethodException();
}
/** Attempts to convert a string value to a type to match a field or method on the specified parentObject. The default
* implementation tries all primitive type wrappers and looks for a static field with the name on both the specified type and
* the parentObject's type.
* @return the converted type, or null if it could not be converted. */
protected Object convertType (L layout, Object parentObject, Class memberType, String memberName, String value) {
if (memberType == String.class || memberType == CharSequence.class) return value;
try {
if (memberType == int.class || memberType == Integer.class) return Integer.valueOf(value);
if (memberType == float.class || memberType == Float.class) return Float.valueOf(value);
if (memberType == long.class || memberType == Long.class) return Long.valueOf(value);
if (memberType == double.class || memberType == Double.class) return Double.valueOf(value);
} catch (NumberFormatException ignored) {
}
if (memberType == boolean.class || memberType == Boolean.class) return Boolean.valueOf(value);
if (memberType == char.class || memberType == Character.class) return value.charAt(0);
if (memberType == short.class || memberType == Short.class) return Short.valueOf(value);
if (memberType == byte.class || memberType == Byte.class) return Byte.valueOf(value);
// Look for a static field.
try {
Field field = getField(memberType, value);
if (field != null && memberType == field.getType()) return field.get(null);
} catch (Exception ignored) {
}
try {
Field field = getField(parentObject.getClass(), value);
if (field != null && memberType == field.getType()) return field.get(null);
} catch (Exception ignored) {
}
return null;
}
static public Field getField (Class type, String name) {
try {
Field field = type.getField(name);
if (field != null) return field;
} catch (Exception ignored) {
}
while (type != null && type != Object.class) {
Field[] fields = type.getDeclaredFields();
for (int i = 0, n = fields.length; i < n; i++)
if (fields[i].getName().equalsIgnoreCase(name)) return fields[i];
type = type.getSuperclass();
}
return null;
}
/** Used by {@link #newWidget(BaseTableLayout, String)} to resolve class names. */
static public void addClassPrefix (String prefix) {
classPrefixes.add(prefix);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy