MetaComponentFactory.groovy
001 /*
002  * Copyright 2008-2014 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *     http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.builder.core.factory
017 
018 import griffon.core.ApplicationEvent
019 import griffon.core.mvc.MVCGroup
020 
021 /**
022  * Enables MVC groups to be used as component nodes
023  *
024  @author Andres Almiray
025  @author Alexander Klein
026  */
027 @SuppressWarnings("rawtypes")
028 class MetaComponentFactory extends AbstractFactory {
029     Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) {
030         String mvcType = ''
031         if (value != null && value instanceof CharSequence) {
032             mvcType = value.toString()
033         else {
034             throw new IllegalArgumentException("In $name value must be an MVC group type")
035         }
036 
037         String mvcId = attributes.remove('mvcId')
038         mvcId = attributes.containsKey('mvcId') ? attributes.remove('mvcId') : mvcId
039 
040         MVCGroup mvcGroup = builder.application.buildMVCGroup(mvcType, mvcId, attributes)
041         def root = mvcGroup.getScriptResult('view')
042 
043         Closure destroyEventHandler
044         destroyEventHandler = String parentId, MVCGroup childGroup, MVCGroup destroyedGroup ->
045             if (destroyedGroup.mvcId == parentId) {
046                 childGroup.destroy()
047                 builder.application.removeApplicationEventListener(ApplicationEvent.DESTROY_MVC_GROUP.name, destroyEventHandler)
048             }
049         }.curry(mvcId, mvcGroup)
050         builder.application.addApplicationEventListener(ApplicationEvent.DESTROY_MVC_GROUP.name, destroyEventHandler)
051 
052         builder.context.root = root
053         builder.context.mvcGroup = mvcGroup
054         root
055     }
056 
057     boolean onHandleNodeAttributes(FactoryBuilderSupport builder, Object node, Map attributes) {
058         try {
059             return builder.context.mvcGroup.controller.metaClass.invokeMethod(builder.context.mvcGroup.controller, 'onHandleNodeAttributes', builder, node, attributes)
060         catch (MissingMethodException e) {
061             return false
062         }
063     }
064 
065     boolean onNodeChildren(FactoryBuilderSupport builder, Object node, Closure childContent) {
066         def root = builder.context.root
067         builder = builder.context.mvcGroup.builder
068         Closure handleChildContent = builder.getVariables().get('handleChildContent')
069         if (handleChildContent != null) {
070             handleChildContent(childContent)
071         else {
072             builder.container(root, childContent)
073         }
074         false
075     }
076 
077     boolean isHandlesNodeChildren() {
078         false
079     }
080 
081     @Override
082     void setChild(FactoryBuilderSupport builder, Object parent, Object child) {
083         safeInvoke(builder.parentContext.mvcGroup.builder, 'setChild', builder, parent, child)
084     }
085 
086     @Override
087     void setParent(FactoryBuilderSupport builder, Object parent, Object child) {
088         safeInvoke(builder.context.mvcGroup.builder, 'setParent', builder, parent, child)
089     }
090 
091     @Override
092     void onNodeCompleted(FactoryBuilderSupport builder, Object parent, Object node) {
093         safeInvoke(builder.context.mvcGroup.builder, 'onNodeCompleted', builder, parent, node)
094     }
095 
096     static protected def safeInvoke(Object obj, String method, Object... args) {
097         try {
098             return obj.metaClass.invokeMethod(obj, method, args)
099         catch (MissingMethodException e) {
100             return null
101         }
102     }
103 }