1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.databinding.tool.expr;
18
19import android.databinding.tool.reflection.ModelAnalyzer;
20import android.databinding.tool.reflection.ModelClass;
21import android.databinding.tool.reflection.ModelMethod;
22import android.databinding.tool.writer.KCode;
23import android.databinding.tool.writer.LayoutBinderWriterKt;
24
25import java.util.ArrayList;
26import java.util.List;
27
28/**
29 * This wraps an expression, but makes it unique for a particular event listener type.
30 * This is used to differentiate listener methods. For example:
31 * <pre>
32 *     public void onFoo(String str) {...}
33 *     public void onFoo(int i) {...}
34 * </pre>
35 */
36public class ListenerExpr extends Expr {
37    private final String mName;
38    private final ModelClass mListenerType;
39    private final ModelMethod mMethod;
40
41    ListenerExpr(Expr expr, String name, ModelClass listenerType, ModelMethod method) {
42        super(expr);
43        mName = name;
44        mListenerType = listenerType;
45        mMethod = method;
46    }
47
48    @Override
49    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
50        return mListenerType;
51    }
52
53    public ModelMethod getMethod() {
54        return mMethod;
55    }
56
57    public Expr getTarget() {
58        return getChildren().get(0);
59    }
60
61    public String getName() {
62        return mName;
63    }
64
65    @Override
66    public boolean isDynamic() {
67        return getTarget().isDynamic();
68    }
69
70    @Override
71    protected List<Dependency> constructDependencies() {
72        final List<Dependency> dependencies = new ArrayList<Dependency>();
73        Dependency dependency = new Dependency(this, getTarget());
74        dependency.setMandatory(true);
75        dependencies.add(dependency);
76        return dependencies;
77    }
78
79    protected String computeUniqueKey() {
80        return join(getResolvedType().getCanonicalName(), getTarget().computeUniqueKey(), mName);
81    }
82
83    @Override
84    public KCode generateCode() {
85        KCode code = new KCode("(");
86        final int minApi = Math.max(mListenerType.getMinApi(), mMethod.getMinApi());
87        if (minApi > 1) {
88            code.app("(getBuildSdkInt() < " + minApi + ") ? null : ");
89        }
90        final String fieldName = LayoutBinderWriterKt.getFieldName(this);
91        final String listenerClassName = LayoutBinderWriterKt.getListenerClassName(this);
92        final KCode value = getTarget().toCode();
93            code.app("((")
94                    .app(fieldName)
95                    .app(" == null) ? (")
96                    .app(fieldName)
97                    .app(" = new ")
98                    .app(listenerClassName)
99                    .app("()) : ")
100                    .app(fieldName)
101                    .app(")");
102        if (getTarget().isDynamic()) {
103            code.app(".setValue(", value)
104                    .app(")");
105        }
106        code.app(")");
107        return code;
108    }
109
110    @Override
111    public Expr cloneToModel(ExprModel model) {
112        return model.listenerExpr(getTarget().cloneToModel(model), mName, mListenerType, mMethod);
113    }
114
115    @Override
116    public String getInvertibleError() {
117        return "Listeners cannot be the target of a two-way binding";
118    }
119
120    @Override
121    public String toString() {
122        return getTarget().toString() + "::" + mName;
123    }
124}
125