/** * L2FProd Common v9.2 License. * * Copyright 2005 - 2009 L2FProd.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.l2fprod.common.propertysheet; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; import java.awt.Rectangle; import java.beans.PropertyDescriptor; import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; import java.io.File; import java.lang.reflect.Constructor; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Date; import java.util.HashMap; import java.util.Map; import com.github.sarxos.l2fprod.sheet.editor.BooleanEditor; import com.github.sarxos.l2fprod.sheet.editor.CharacterEditor; import com.github.sarxos.l2fprod.sheet.editor.ColorEditor; import com.github.sarxos.l2fprod.sheet.editor.DimensionEditor; import com.github.sarxos.l2fprod.sheet.editor.EnumEditor; import com.github.sarxos.l2fprod.sheet.editor.FileEditor; import com.github.sarxos.l2fprod.sheet.editor.NumberEditor; import com.l2fprod.common.beans.editor.InsetsPropertyEditor; import com.l2fprod.common.beans.editor.JCalendarDatePropertyEditor; import com.l2fprod.common.beans.editor.RectanglePropertyEditor; import com.l2fprod.common.beans.editor.StringPropertyEditor; /** * Mapping between Properties, Property Types and Property Editors. */ public class PropertyEditorRegistry implements PropertyEditorFactory { private Map<Class<?>, Object> typeToEditor; private Map<Property, Object> propertyToEditor; public PropertyEditorRegistry() { typeToEditor = new HashMap<Class<?>, Object>(); propertyToEditor = new HashMap<Property, Object>(); registerDefaults(); } @Override public PropertyEditor createPropertyEditor(Property property) { return getEditor(property); } /** * Gets an editor for the given property. The lookup is as follow: * <ul> * <li>if propertyDescriptor.getPropertyEditorClass() returns a valid value, * it is returned, else, * <li>if an editor was registered with * {@link #registerEditor(Property, PropertyEditor)}, it is returned, else</li> * <li>if an editor class was registered with * {@link #registerEditor(Property, Class)}, it is returned, else * <li> * <li>look for editor for the property type using {@link #getEditor(Class)} * .it is returned, else</li> * <li>look for editor using PropertyEditorManager.findEditor(Class);</li> * </ul> * * @param property * @return an editor suitable for the Property. */ public synchronized PropertyEditor getEditor(Property property) { PropertyEditor editor = null; if (property instanceof PropertyDescriptorAdapter) { PropertyDescriptor descriptor = ((PropertyDescriptorAdapter) property).getDescriptor(); if (descriptor != null) { Class<?> clz = descriptor.getPropertyEditorClass(); if (clz != null) { editor = descriptor.createPropertyEditor(property); } } } if (editor == null) { Object value = propertyToEditor.get(property); if (value instanceof PropertyEditor) { editor = (PropertyEditor) value; } else if (value instanceof Class) { editor = loadPropertyEditor((Class<?>) value); } else { editor = createEditor(property); } } if ((editor == null) && (property instanceof PropertyDescriptorAdapter)) { PropertyDescriptor descriptor = ((PropertyDescriptorAdapter) property).getDescriptor(); Class<?> clz = descriptor.getPropertyType(); editor = PropertyEditorManager.findEditor(clz); } return editor; } /** * Load PropertyEditor from clazz through reflection. * * @param clazz Class to load from. * @return Loaded propertyEditor */ private PropertyEditor loadPropertyEditor(Class<?> clazz) { PropertyEditor editor = null; try { editor = (PropertyEditor) clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } return editor; } /** * Gets an editor for the given property type. The lookup is as follow: * <ul> * <li>if an editor was registered with * {@link #registerEditor(Class, PropertyEditor)}, it is returned, else</li> * <li>if an editor class was registered with * {@link #registerEditor(Class, Class)}, it is returned, else * <li> * <li>it returns null.</li> * </ul> * * @param clazz * @return an editor suitable for the Property type or null if none found */ public synchronized PropertyEditor createEditor(Property property) { Class<?> clazz = property.getType(); PropertyEditor editor = null; Object value = typeToEditor.get(clazz); if (value instanceof PropertyEditor) { editor = (PropertyEditor) value; } else if (value instanceof Class) { Class<?> cls = (Class<?>) value; Constructor<?> ctor = null; try { ctor = cls.getConstructor(new Class[] { Object.class }); } catch (Exception ex) { // fall through } try { if (ctor == null) { editor = (PropertyEditor) cls.newInstance(); } else { editor = (PropertyEditor) ctor.newInstance(new Object[] { property }); } } catch (Exception e) { throw new RuntimeException("PropertyEditor not instantiated", e); } } if (editor == null) { if (clazz.isEnum()) { editor = new EnumEditor(property); } } return editor; } public synchronized void registerEditor(Class<?> type, Class<?> editorClass) { typeToEditor.put(type, editorClass); } public synchronized void registerEditor(Class<?> type, PropertyEditor editor) { typeToEditor.put(type, editor); } public synchronized void unregisterEditor(Class<?> type) { typeToEditor.remove(type); } public synchronized void registerEditor(Property property, Class<?> editorClass) { propertyToEditor.put(property, editorClass); } public synchronized void registerEditor(Property property, PropertyEditor editor) { propertyToEditor.put(property, editor); } public synchronized void unregisterEditor(Property property) { propertyToEditor.remove(property); } /** * Adds default editors. This method is called by the constructor but may be * called later to reset any customizations made through the * <code>registerEditor</code> methods. <b>Note: if overriden, * <code>super.registerDefaults()</code> must be called before plugging * custom defaults. </b> */ public void registerDefaults() { typeToEditor.clear(); propertyToEditor.clear(); // our editors registerEditor(String.class, StringPropertyEditor.class); registerEditor(char.class, CharacterEditor.class); registerEditor(Character.class, CharacterEditor.class); registerEditor(double.class, NumberEditor.class); registerEditor(Double.class, NumberEditor.class); registerEditor(float.class, NumberEditor.class); registerEditor(Float.class, NumberEditor.class); registerEditor(int.class, NumberEditor.class); registerEditor(Integer.class, NumberEditor.class); registerEditor(long.class, NumberEditor.class); registerEditor(Long.class, NumberEditor.class); registerEditor(short.class, NumberEditor.class); registerEditor(Short.class, NumberEditor.class); registerEditor(byte.class, NumberEditor.class); registerEditor(Byte.class, NumberEditor.class); registerEditor(BigInteger.class, NumberEditor.class); registerEditor(BigDecimal.class, NumberEditor.class); registerEditor(boolean.class, BooleanEditor.class); registerEditor(Boolean.class, BooleanEditor.class); registerEditor(File.class, FileEditor.class); // awt object editors registerEditor(Color.class, ColorEditor.class); registerEditor(Dimension.class, DimensionEditor.class); registerEditor(Insets.class, InsetsPropertyEditor.class); registerEditor(Rectangle.class, RectanglePropertyEditor.class); registerEditor(Date.class, JCalendarDatePropertyEditor.class); try { Class<?> fontEditor = Class.forName("com.l2fprod.common.beans.editor.FontPropertyEditor"); registerEditor(Font.class, fontEditor); } catch (Exception e) { // FontPropertyEditor might not be there when using the split jars } } }