| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * 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.intellij.uiDesigner.lw; |
| |
| import com.intellij.uiDesigner.core.GridConstraints; |
| import com.intellij.uiDesigner.UIFormXmlConstants; |
| import org.jdom.Element; |
| |
| import java.awt.*; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List;/** |
| * @author Anton Katilin |
| * @author Vladimir Kondratyev |
| */ |
| public abstract class LwComponent implements IComponent{ |
| /** |
| * Component's ID. Cannot be null. |
| */ |
| private String myId; |
| /** |
| * may be null |
| */ |
| private String myBinding; |
| /** |
| * Component class |
| */ |
| private final String myClassName; |
| /** |
| * Parent LwContainer. This field is always not <code>null</code> |
| * is the component is in hierarchy. But the root of hierarchy |
| * has <code>null</code> parent indeed. |
| */ |
| private LwContainer myParent; |
| /** |
| * never <code>null</code> |
| */ |
| private final GridConstraints myConstraints; |
| |
| private Object myCustomLayoutConstraints; |
| /** |
| * Bounds in XY layout |
| */ |
| private final Rectangle myBounds; |
| |
| private final HashMap myIntrospectedProperty2Value; |
| /** |
| * if class is unknown (cannot be loaded), properties tag is stored as is |
| */ |
| private Element myErrorComponentProperties; |
| protected final HashMap myClientProperties; |
| protected final HashMap myDelegeeClientProperties; |
| private boolean myCustomCreate = false; |
| private boolean myDefaultBinding = false; |
| |
| public LwComponent(final String className){ |
| if (className == null){ |
| throw new IllegalArgumentException("className cannot be null"); |
| } |
| myBounds = new Rectangle(); |
| myConstraints = new GridConstraints(); |
| myIntrospectedProperty2Value = new HashMap(); |
| myClassName = className; |
| myClientProperties = new HashMap(); |
| myDelegeeClientProperties = new HashMap(); |
| } |
| |
| public final String getId() { |
| return myId; |
| } |
| |
| public final void setId(final String id){ |
| if (id == null) { |
| throw new IllegalArgumentException("id cannot be null"); |
| } |
| myId = id; |
| } |
| |
| public final String getBinding(){ |
| return myBinding; |
| } |
| |
| public final void setBinding(final String binding){ |
| myBinding = binding; |
| } |
| |
| public final Object getCustomLayoutConstraints(){ |
| return myCustomLayoutConstraints; |
| } |
| |
| public final void setCustomLayoutConstraints(final Object customLayoutConstraints){ |
| myCustomLayoutConstraints = customLayoutConstraints; |
| } |
| |
| /** |
| * @return never null |
| */ |
| public final String getComponentClassName(){ |
| return myClassName; |
| } |
| |
| public IProperty[] getModifiedProperties() { |
| return getAssignedIntrospectedProperties(); |
| } |
| |
| /** |
| * @return component's constraints in XY layout. This method rever |
| * returns <code>null</code>. |
| */ |
| public final Rectangle getBounds(){ |
| return (Rectangle)myBounds.clone(); |
| } |
| |
| /** |
| * @return component's constraints in GridLayoutManager. This method never |
| * returns <code>null</code>. |
| */ |
| public final GridConstraints getConstraints(){ |
| return myConstraints; |
| } |
| |
| public boolean isCustomCreate() { |
| return myCustomCreate; |
| } |
| |
| public boolean isDefaultBinding() { |
| return myDefaultBinding; |
| } |
| |
| public boolean accept(ComponentVisitor visitor) { |
| return visitor.visit(this); |
| } |
| |
| public boolean areChildrenExclusive() { |
| return false; |
| } |
| |
| public final LwContainer getParent(){ |
| return myParent; |
| } |
| |
| public IContainer getParentContainer() { |
| return myParent; |
| } |
| |
| protected final void setParent(final LwContainer parent){ |
| myParent = parent; |
| } |
| |
| public final void setBounds(final Rectangle bounds) { |
| myBounds.setBounds(bounds); |
| } |
| |
| public final Object getPropertyValue(final LwIntrospectedProperty property){ |
| return myIntrospectedProperty2Value.get(property); |
| } |
| |
| public final void setPropertyValue(final LwIntrospectedProperty property, final Object value){ |
| myIntrospectedProperty2Value.put(property, value); |
| } |
| |
| /** |
| * @return <code>null</code> only if component class is not valid. |
| * Class validation is performed with {@link com.intellij.uiDesigner.compiler.Utils#validateJComponentClass(ClassLoader,String,boolean)} |
| */ |
| public final Element getErrorComponentProperties(){ |
| return myErrorComponentProperties; |
| } |
| |
| public final LwIntrospectedProperty[] getAssignedIntrospectedProperties() { |
| final LwIntrospectedProperty[] properties = new LwIntrospectedProperty[myIntrospectedProperty2Value.size()]; |
| final Iterator iterator = myIntrospectedProperty2Value.keySet().iterator(); |
| //noinspection ForLoopThatDoesntUseLoopVariable |
| for (int i=0; iterator.hasNext(); i++) { |
| properties[i] = (LwIntrospectedProperty)iterator.next(); |
| } |
| return properties; |
| } |
| |
| /** |
| * 'id' is required attribute |
| * 'binding' is optional attribute |
| */ |
| protected final void readBase(final Element element) { |
| setId(LwXmlReader.getRequiredString(element, UIFormXmlConstants.ATTRIBUTE_ID)); |
| setBinding(element.getAttributeValue(UIFormXmlConstants.ATTRIBUTE_BINDING)); |
| myCustomCreate = LwXmlReader.getOptionalBoolean(element, UIFormXmlConstants.ATTRIBUTE_CUSTOM_CREATE, false); |
| myDefaultBinding = LwXmlReader.getOptionalBoolean(element, UIFormXmlConstants.ATTRIBUTE_DEFAULT_BINDING, false); |
| } |
| |
| /** |
| * 'properties' is not required subtag |
| * @param provider can be null if no properties should be read |
| */ |
| protected final void readProperties(final Element element, final PropertiesProvider provider) { |
| if (provider == null) { |
| // do not read properties |
| return; |
| } |
| |
| Element propertiesElement = LwXmlReader.getChild(element, UIFormXmlConstants.ELEMENT_PROPERTIES); |
| if(propertiesElement == null){ |
| propertiesElement = new Element(UIFormXmlConstants.ELEMENT_PROPERTIES, element.getNamespace()); |
| } |
| |
| final HashMap name2property = provider.getLwProperties(getComponentClassName()); |
| if (name2property == null) { |
| myErrorComponentProperties = (Element)propertiesElement.clone(); |
| return; |
| } |
| |
| final List propertyElements = propertiesElement.getChildren(); |
| for (int i = 0; i < propertyElements.size(); i++) { |
| final Element t = (Element)propertyElements.get(i); |
| final String name = t.getName(); |
| final LwIntrospectedProperty property = (LwIntrospectedProperty)name2property.get(name); |
| if (property == null){ |
| continue; |
| } |
| try { |
| final Object value = property.read(t); |
| setPropertyValue(property, value); |
| } |
| catch (final Exception exc) { |
| // Skip non readable properties |
| } |
| } |
| |
| readClientProperties(element); |
| } |
| |
| private void readClientProperties(final Element element) { |
| Element propertiesElement = LwXmlReader.getChild(element, UIFormXmlConstants.ELEMENT_CLIENT_PROPERTIES); |
| if (propertiesElement == null) return; |
| final List clientPropertyList = propertiesElement.getChildren(); |
| for(int i=0; i<clientPropertyList.size(); i++) { |
| final Element prop = (Element) clientPropertyList.get(i); |
| final String propName = prop.getName(); |
| final String className = LwXmlReader.getRequiredString(prop, UIFormXmlConstants.ATTRIBUTE_CLASS); |
| |
| LwIntrospectedProperty lwProp; |
| if (className.equals(Integer.class.getName())) { |
| lwProp = new LwIntroIntProperty(propName); |
| } |
| else if (className.equals(Boolean.class.getName())) { |
| lwProp = new LwIntroBooleanProperty(propName); |
| } |
| else if (className.equals(Double.class.getName())) { |
| lwProp = new LwIntroPrimitiveTypeProperty(propName, Double.class); |
| } |
| else { |
| Class propClass; |
| try { |
| propClass = Class.forName(className); |
| } |
| catch (ClassNotFoundException e) { |
| continue; |
| } |
| lwProp = CompiledClassPropertiesProvider.propertyFromClass(propClass, propName); |
| } |
| |
| if (lwProp != null) { |
| final Object value; |
| try { |
| value = lwProp.read(prop); |
| } |
| catch (Exception e) { |
| continue; |
| } |
| myDelegeeClientProperties.put(propName, value); |
| } |
| } |
| } |
| |
| /** |
| * Delegates reading of constraints to the parent container |
| */ |
| protected final void readConstraints(final Element element){ |
| final LwContainer parent = getParent(); |
| if(parent == null){ |
| throw new IllegalStateException("component must be in LW tree: "+this); |
| } |
| parent.readConstraintsForChild(element, this); |
| } |
| |
| /** |
| * @param provider can be null if no component classes should not be created |
| */ |
| public abstract void read(Element element, PropertiesProvider provider) throws Exception; |
| |
| /** |
| * @see javax.swing.JComponent#getClientProperty(Object) |
| */ |
| public final Object getClientProperty(final Object key){ |
| if (key == null) { |
| throw new IllegalArgumentException("key cannot be null"); |
| } |
| return myClientProperties.get(key); |
| } |
| |
| /** |
| * @see javax.swing.JComponent#putClientProperty(Object, Object) |
| */ |
| public final void putClientProperty(final Object key, final Object value){ |
| if (key == null) { |
| throw new IllegalArgumentException("key cannot be null"); |
| } |
| myClientProperties.put(key, value); |
| } |
| |
| public HashMap getDelegeeClientProperties() { |
| return myDelegeeClientProperties; |
| } |
| } |