Object newInstance()

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
    }