package org.korsakow.ide.resources.widget;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import org.korsakow.domain.interf.IDynamicProperties;
import org.korsakow.domain.interf.IKeyword;
import org.korsakow.ide.resources.WidgetType;
import org.korsakow.ide.resources.property.AbstractProperty;
import org.korsakow.ide.util.EventDispatcher;
import org.korsakow.ide.util.Util;
public abstract class WidgetModel implements IDynamicProperties
{
private static class PropertyChangeForwarder implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent event) {
WidgetComponent comp = (WidgetComponent)event.getSource();
comp.getWidget().firePropertyChange(event.getPropertyName(), event.getOldValue(), event.getNewValue());
}
};
private static PropertyChangeForwarder propertyChangeForwarder = new PropertyChangeForwarder();
protected Hashtable<String, AbstractProperty> abstractProperties = new Hashtable<String, AbstractProperty>();
protected void addProperty(AbstractProperty p) { abstractProperties.put(p.getId(), p); }
protected void removeProperty(String id) { abstractProperties.remove(id); }
protected EventDispatcher<PropertyChangeListener> dispatcher = new EventDispatcher<PropertyChangeListener>(PropertyChangeListener.class);
protected HashSet<String> propertiesBeingUpdated = new HashSet<String>();
private WidgetType widgetType;
protected WidgetPersistCondition persistCondition = WidgetPersistCondition.Never;
protected WidgetPersistAction persistAction = WidgetPersistAction.Replace;
private WidgetComponent component;
private WidgetPropertiesEditor widgetEditor;
private Long id;
private String name;
private Collection<IKeyword> keywords = new ArrayList<IKeyword>();
public WidgetModel(WidgetType widgetType)
{
this.widgetType = widgetType;
}
public void setWidgetType(WidgetType type)
{
widgetType = type;
}
public WidgetType getWidgetType()
{
return widgetType;
}
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setKeywords(Collection<IKeyword> keywords)
{
this.keywords = keywords;
}
public Collection<IKeyword> getKeywords()
{
return keywords;
}
public void setPersistCondition(WidgetPersistCondition condition)
{
persistCondition = condition;
}
public WidgetPersistCondition getPersistCondition()
{
return persistCondition;
}
public void setPersistAction(WidgetPersistAction action)
{
persistAction = action;
}
public WidgetPersistAction getPersistAction()
{
return persistAction;
}
public Collection<String> getDynamicPropertyIds()
{
return abstractProperties.keySet();
}
public Collection<Object> getPropertyValues()
{
List<Object> values = new ArrayList<Object>();
for (AbstractProperty value : abstractProperties.values())
values.add(value.getValue());
return values;
}
public void setDynamicProperty(String id, Object value)
{
if (!abstractProperties.containsKey(id)) {
try {
// bit of a hack for now... until merger of app/domain objects
if (id.equals("version"))
return;
String m = "get" + id.toUpperCase().charAt(0) + id.substring(1);
getClass().getMethod(m);
return;
} catch (SecurityException e) {
throw new IllegalArgumentException(e);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("no such property: " + id + " for " + getClass().getCanonicalName());
}
}
abstractProperties.get(id).setValue(value);
}
public Object getDynamicProperty(String id)
{
return abstractProperties.get(id).getValue();
}
public Class getPropertyType(String id)
{
return Object.class;
}
protected WidgetPropertiesEditor createWidgetEditor()
{
return new AbstractWidgetPropertiesEditor(Util.list(WidgetModel.class, this));
}
public WidgetPropertiesEditor getWidgetEditor()
{
if (widgetEditor == null) {
widgetEditor = createWidgetEditor();
}
return widgetEditor;
}
public void disposeWidgetEditor()
{
widgetEditor = null;
}
protected abstract WidgetComponent createComponent();
public WidgetComponent getComponent()
{
if (component == null) {
component = createComponent();
component.addPropertyChangeListener("x", propertyChangeForwarder);
component.addPropertyChangeListener("y", propertyChangeForwarder);
component.addPropertyChangeListener("width", propertyChangeForwarder);
component.addPropertyChangeListener("height", propertyChangeForwarder);
}
return component;
}
public void setX(int x)
{
getComponent().setLocation(x, getComponent().getY());
}
public void setY(int y)
{
getComponent().setLocation(getComponent().getX(), y);
}
public int getX()
{
return getComponent().getX();
}
public int getY()
{
return getComponent().getY();
}
public int getWidth()
{
return getComponent().getWidth();
}
public int getHeight()
{
return getComponent().getHeight();
}
public void setWidth(int width)
{
getComponent().setSize(width, getComponent().getHeight());
}
public void setHeight(int height)
{
getComponent().setSize(getComponent().getWidth(), height);
}
public void addPropertyChangeListener(PropertyChangeListener listener)
{
dispatcher.add(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener)
{
dispatcher.remove(listener);
}
/**
* Set to true to suspend firing of property change events.
* @param propertyName
* @param updating
*/
public void setPropertyUpdating(String propertyName, boolean updating)
{
if (updating)
propertiesBeingUpdated.add(propertyName);
else
propertiesBeingUpdated.remove(propertyName);
}
/**
* Also fires a change event. Even if oldValue==newValue or oldValue.equals(newValue).
* @param propertyName
* @param updating
* @param oldValue
* @param newValue
*/
public void setPropertyUpdating(String propertyName, boolean updating, Object oldValue, Object newValue)
{
setPropertyUpdating(propertyName, updating);
PropertyChangeEvent event = new PropertyChangeEvent(this, propertyName, oldValue, newValue);
dispatcher.notify("propertyChange", event);
}
/**
* Does nothing if oldValue==newValue or oldValue.equals(newValue).
* @param propertyName
* @param oldValue
* @param newValue
*/
public void firePropertyChange(String propertyName, Object oldValue, Object newValue)
{
if (oldValue == newValue)
return;
if (oldValue != null && newValue != null && oldValue.equals(newValue))
return;
if (propertiesBeingUpdated.contains(propertyName))
return;
PropertyChangeEvent event = new PropertyChangeEvent(this, propertyName, oldValue, newValue);
dispatcher.notify("propertyChange", event);
}
/**
* Beans say this is how to go. Ignores any properties being updates.
*/
public void fireBatchPropertyChange()
{
PropertyChangeEvent event = new PropertyChangeEvent(this, null, null, null);
dispatcher.notify("propertyChange", event);
}
}