in subprojects/groovy-swing/src/main/groovy/groovy/swing/factory/BindFactory.groovy [122:240]
Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) throws InstantiationException, IllegalAccessException {
Object source = attributes.remove("source")
Object target = attributes.remove("target")
Object update = attributes.get("update")
Map bindContext = builder.context.get(CONTEXT_DATA_KEY) ?: [:]
if (bindContext.isEmpty()) {
builder.context.put(CONTEXT_DATA_KEY, bindContext)
}
TargetBinding tb = null
if (target != null) {
Object targetProperty = attributes.remove("targetProperty") ?: value
if (!(targetProperty instanceof CharSequence)) {
throw new IllegalArgumentException("Invalid value for targetProperty: (or node value)." +
" Value for this attribute must be a String but it is " + (targetProperty != null ? targetProperty.getClass().getName() : null))
}
tb = new PropertyBinding(target, targetProperty.toString(), update)
if (source == null) {
// if we have a target but no source assume the build context is the source and return
def result
if (attributes.remove("mutual")) {
result = new MutualPropertyBinding(null, null, tb, this.&getTriggerBinding)
} else {
result = tb
}
def newAttributes = [:]
newAttributes.putAll(attributes)
bindContext.put(result, newAttributes)
attributes.clear()
return result
}
}
FullBinding fb
boolean sea = attributes.containsKey("sourceEvent")
boolean sva = attributes.containsKey("sourceValue")
boolean spa = attributes.containsKey("sourceProperty") || value
if (sea && sva && !spa) {
// entirely event triggered binding
Closure queryValue = (Closure) attributes.remove("sourceValue")
ClosureSourceBinding csb = new ClosureSourceBinding(queryValue)
String trigger = (String) attributes.remove("sourceEvent")
EventTriggerBinding etb = new EventTriggerBinding(source, trigger)
fb = etb.createBinding(csb, tb)
} else if (spa && !(sea && sva)) {
// partially property driven binding
Object property = attributes.remove("sourceProperty") ?: value
if (!(property instanceof CharSequence)) {
throw new IllegalArgumentException("Invalid value for sourceProperty: (or node value). " +
"Value for this attribute must be a String but it is " + (property != null ? property.getClass().getName() : null))
}
if (source == null) {
// if we have a sourceProperty but no source then we're in trouble
throw new IllegalArgumentException("Missing value for source: even though sourceProperty: (or node value) " +
"was specified. Please check you didn't write bind(model.someProperty) instead of bind{ model.someProperty }")
}
PropertyBinding pb = new PropertyBinding(source, property.toString(), update)
TriggerBinding trigger
if (sea) {
// source trigger comes from an event
String triggerName = (String) attributes.remove("sourceEvent")
trigger = new EventTriggerBinding(source, triggerName)
} else {
// source trigger comes from a property change
// this method will also check for synthetic properties
trigger = getTriggerBinding(pb)
}
SourceBinding sb
if (sva) {
// source value comes from a value closure
Closure queryValue = (Closure) attributes.remove("sourceValue")
sb = new ClosureSourceBinding(queryValue)
} else {
// source value is the property value
sb = pb
}
// check for a mutual binding (bi-directional)
if (attributes.remove("mutual")) {
fb = new MutualPropertyBinding(trigger, sb, tb, this.&getTriggerBinding)
} else {
fb = trigger.createBinding(sb, tb)
}
} else if (!(sea || sva || spa)) {
// if no sourcing is defined then assume we are a closure binding and return
def newAttributes = [:]
newAttributes.putAll(attributes)
def ctb = new ClosureTriggerBinding(syntheticBindings)
bindContext.put(ctb, newAttributes)
attributes.clear()
return ctb
} else {
throw new RuntimeException("Both sourceEvent: and sourceValue: cannot be specified along with sourceProperty: or a value argument")
}
if (attributes.containsKey("value")) {
bindContext.put(fb, [value: attributes.remove("value")])
}
bindContext.get(fb, [:]).put('update', update)
Object o = attributes.remove("bind")
if (((o == null) && !attributes.containsKey('group'))
|| ((o instanceof Boolean) && ((Boolean) o).booleanValue())) {
fb.bind()
}
if ((attributes.group instanceof AggregateBinding) && fb != null) {
attributes.remove('group').addBinding(fb)
}
builder.addDisposalClosure(fb.&unbind)
return fb
}