001/**
002 * Copyright 2013 John Ericksen
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 */
016package org.androidtransfuse.gen.variableBuilder;
017
018import com.sun.codemodel.*;
019import org.androidtransfuse.TransfuseAnalysisException;
020import org.androidtransfuse.adapter.ASTJDefinedClassType;
021import org.androidtransfuse.analysis.astAnalyzer.ASTInjectionAspect;
022import org.androidtransfuse.gen.*;
023import org.androidtransfuse.gen.variableDecorator.TypedExpressionFactory;
024import org.androidtransfuse.model.FieldInjectionPoint;
025import org.androidtransfuse.model.InjectionNode;
026import org.androidtransfuse.model.MethodInjectionPoint;
027import org.androidtransfuse.model.TypedExpression;
028import org.androidtransfuse.model.r.RResource;
029import org.androidtransfuse.model.r.RResourceReferenceBuilder;
030import org.androidtransfuse.model.r.ResourceIdentifier;
031import org.androidtransfuse.util.AndroidLiterals;
032
033import javax.inject.Inject;
034
035public class ViewVariableBuilder extends ConsistentTypeVariableBuilder {
036
037    private static final String FIND_VIEW_BY_ID = "findViewById";
038    private static final String FIND_VIEW_BY_TAG = "findViewWithTag";
039
040    private final JType viewType;
041    private final Integer viewId;
042    private final String viewTag;
043    private final InjectionNode activityInjectionNode;
044    private final InjectionExpressionBuilder injectionExpressionBuilder;
045    private final RResourceReferenceBuilder rResourceReferenceBuilder;
046    private final ClassGenerationUtil generationUtil;
047    private final UniqueVariableNamer variableNamer;
048    private final InvocationBuilder injectionInvocationBuilder;
049    private final RResource rResource;
050    private final ExpressionMatchingListFactory generatorFactory;
051
052    @Inject
053    public ViewVariableBuilder(/*@Assisted*/ /*@Nullable*/ Integer viewId,
054                               /*@Assisted*/ /*@Nullable*/ String viewTag,
055                               /*@Assisted*/ InjectionNode activityInjectionNode,
056                               /*@Assisted*/ JType viewType,
057                               InjectionExpressionBuilder injectionExpressionBuilder,
058                               RResourceReferenceBuilder rResourceReferenceBuilder,
059                               ClassGenerationUtil generationUtil,
060                               InvocationBuilder injectionInvocationBuilder,
061                               UniqueVariableNamer variableNamer,
062                               RResource rResource,
063                               TypedExpressionFactory typedExpressionFactory,
064                               ExpressionMatchingListFactory generatorFactory) {
065        super(AndroidLiterals.VIEW, typedExpressionFactory);
066        this.viewId = viewId;
067        this.viewTag = viewTag;
068        this.activityInjectionNode = activityInjectionNode;
069        this.viewType = viewType;
070        this.injectionExpressionBuilder = injectionExpressionBuilder;
071        this.rResourceReferenceBuilder = rResourceReferenceBuilder;
072        this.generationUtil = generationUtil;
073        this.injectionInvocationBuilder = injectionInvocationBuilder;
074        this.variableNamer = variableNamer;
075        this.rResource = rResource;
076        this.generatorFactory = generatorFactory;
077    }
078
079    @Override
080    public JExpression buildExpression(InjectionBuilderContext injectionBuilderContext, InjectionNode injectionNode) {
081        try {
082            injectionExpressionBuilder.setupInjectionRequirements(injectionBuilderContext, injectionNode);
083
084            TypedExpression contextVar = injectionExpressionBuilder.buildVariable(injectionBuilderContext, activityInjectionNode);
085
086            JExpression viewExpression;
087            if (viewId != null) {
088                ResourceIdentifier viewResourceIdentifier = rResource.getResourceIdentifier(viewId);
089                JExpression viewIdRef = rResourceReferenceBuilder.buildReference(viewResourceIdentifier);
090                viewExpression = contextVar.getExpression().invoke(FIND_VIEW_BY_ID).arg(viewIdRef);
091            } else {
092                //viewTag is not null
093                //<Activity>.getWindow().getDecorView().findViewWithTag(...)
094                viewExpression = contextVar.getExpression()
095                        .invoke("getWindow").invoke("getDecorView").invoke(FIND_VIEW_BY_TAG).arg(JExpr.lit(viewTag));
096            }
097
098            ASTInjectionAspect injectionAspect = injectionNode.getAspect(ASTInjectionAspect.class);
099            if (injectionAspect == null) {
100                return viewExpression;
101            } else {
102                return inject(injectionAspect, injectionBuilderContext, injectionNode, viewExpression);
103            }
104        } catch (JClassAlreadyExistsException e) {
105            throw new TransfuseAnalysisException("JClassAlreadyExistsException while generating injection: " + injectionNode.getClassName(), e);
106        }
107    }
108
109    public JVar inject(ASTInjectionAspect injectionAspect, InjectionBuilderContext injectionBuilderContext, InjectionNode injectionNode, JExpression viewExpression) throws JClassAlreadyExistsException {
110        JVar variableRef;
111        JType nodeType = generationUtil.type(injectionNode.getASTType());
112
113        if (injectionAspect.getAssignmentType().equals(ASTInjectionAspect.InjectionAssignmentType.LOCAL)) {
114            variableRef = injectionBuilderContext.getBlock().decl(nodeType, variableNamer.generateName(injectionNode));
115        } else {
116            variableRef = injectionBuilderContext.getDefinedClass().field(JMod.PRIVATE, nodeType, variableNamer.generateName(injectionNode));
117        }
118        JBlock block = injectionBuilderContext.getBlock();
119
120
121        block.assign(variableRef, JExpr.cast(viewType, viewExpression));
122
123        for (ASTInjectionAspect.InjectionGroup injectionGroup : injectionAspect.getGroups()) {
124            //field injection
125            for (FieldInjectionPoint fieldInjectionPoint : injectionGroup.getFieldInjectionPoints()) {
126                block.add(
127                        injectionInvocationBuilder.buildFieldSet(
128                                new ASTJDefinedClassType(injectionBuilderContext.getDefinedClass()),
129                                injectionBuilderContext.getVariableMap().get(fieldInjectionPoint.getInjectionNode()),
130                                fieldInjectionPoint,
131                                variableRef));
132            }
133
134            //method injection
135            for (MethodInjectionPoint methodInjectionPoint : injectionGroup.getMethodInjectionPoints()) {
136                block.add(
137                        injectionInvocationBuilder.buildMethodCall(
138                                new ASTJDefinedClassType(injectionBuilderContext.getDefinedClass()),
139                                methodInjectionPoint.getRootContainingType(),
140                                methodInjectionPoint.getMethod(),
141                                generatorFactory.build(
142                                        injectionBuilderContext.getVariableMap(),
143                                        methodInjectionPoint.getInjectionNodes()),
144                                new TypedExpression(methodInjectionPoint.getContainingType(), variableRef)));
145            }
146        }
147
148        return variableRef;
149    }
150}