blob: cddfc5ab3315071d0a1a941027a219cc1b0e9877 [file] [log] [blame]
/*
* 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;
}
}