LayoutBinder.java revision fead9ca09b117136b35bc5bf137340a754f9eddd
1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/*
2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License.
6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at
7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and
14d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License.
15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
16d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool;
18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport com.google.common.base.Preconditions;
20d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.Dependency;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.Expr;
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.ExprModel;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.IdentifierExpr;
25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.ResourceBundle;
26fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.ParserHelper;
27fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.LayoutBinderWriter;
28d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
29d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.ArrayList;
305bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyarimport java.util.HashMap;
31d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List;
325bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyarimport java.util.Map;
33d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
34d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/**
35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Keeps all information about the bindings per layout file
36d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
37d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class LayoutBinder {
383bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar
39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /*
40d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    * val pkg: String, val projectPackage: String, val baseClassName: String,
41d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val layoutName:String, val lb: LayoutExprBinding*/
42d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private final ExprModel mExprModel;
43d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private final ExpressionParser mExpressionParser;
44d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private final List<BindingTarget> mBindingTargets;
45d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private String mPackage;
46a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private String mModulePackage;
47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private String mProjectPackage;
48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private String mBaseClassName;
49895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    private final HashMap<String, String> mUserDefinedVariables = new HashMap<String, String>();
50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    private LayoutBinderWriter mWriter;
523bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar    private ResourceBundle.LayoutFileBundle mBundle;
5343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
543bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar    public LayoutBinder(ResourceBundle resourceBundle,
553bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar            ResourceBundle.LayoutFileBundle layoutBundle) {
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel = new ExprModel();
57d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExpressionParser = new ExpressionParser(mExprModel);
58895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        mBindingTargets = new ArrayList<BindingTarget>();
593bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        mBundle = layoutBundle;
603bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        mProjectPackage = resourceBundle.getAppPackage();
61a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        mModulePackage = layoutBundle.getModulePackage();
62a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        mPackage = layoutBundle.getModulePackage() + ".generated";
634c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        mBaseClassName = ParserHelper.INSTANCE$.toClassName(layoutBundle.getFileName()) + "Binding";
643bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        // copy over data.
653bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        for (Map.Entry<String, String> variable : mBundle.getVariables().entrySet()) {
663bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar            addVariable(variable.getKey(), variable.getValue());
673bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        }
683bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar
693bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        for (Map.Entry<String, String> userImport : mBundle.getImports().entrySet()) {
70a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount            mExprModel.addImport(userImport.getKey(), userImport.getValue());
713bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        }
723bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        for (ResourceBundle.BindingTargetBundle targetBundle : mBundle.getBindingTargetBundles()) {
733bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar            final BindingTarget bindingTarget = createBindingTarget(targetBundle);
743bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar            for (ResourceBundle.BindingTargetBundle.BindingBundle bindingBundle : targetBundle
753bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar                    .getBindingBundleList()) {
763bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar                bindingTarget.addBinding(bindingBundle.getName(), parse(bindingBundle.getExpr()));
773bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar            }
783bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        }
79d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
80d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
815bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public void resolveWhichExpressionsAreUsed() {
82895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        List<Expr> used = new ArrayList<Expr>();
835bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        for (BindingTarget target : mBindingTargets) {
845bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            for (Binding binding : target.getBindings()) {
855bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                binding.getExpr().setIsUsed(true);
865bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                used.add(binding.getExpr());
875bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
885bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }
895bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        while (!used.isEmpty()) {
905bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            Expr e = used.remove(used.size() - 1);
915bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            for (Dependency dep : e.getDependencies()) {
925bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                if (!dep.getOther().isUsed()) {
935bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                    used.add(dep.getOther());
945bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                    dep.getOther().setIsUsed(true);
955bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                }
965bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
975bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }
985bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
995bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
100d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public IdentifierExpr addVariable(String name, String type) {
1015bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        Preconditions.checkState(!mUserDefinedVariables.containsKey(name),
1025bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                "%s has already been defined as %s", name, type);
103d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final IdentifierExpr id = mExprModel.identifier(name);
104d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        id.setUserDefinedType(type);
105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        id.enableDirectInvalidation();
1065bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        mUserDefinedVariables.put(name, type);
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return id;
108d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1105bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public HashMap<String, String> getUserDefinedVariables() {
1115bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        return mUserDefinedVariables;
1125bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
1135bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
1143bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar    public BindingTarget createBindingTarget(ResourceBundle.BindingTargetBundle targetBundle) {
1153bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        final BindingTarget target = new BindingTarget(targetBundle);
116d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mBindingTargets.add(target);
117d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        target.setModel(mExprModel);
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return target;
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr parse(String input) {
122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final Expr parsed = mExpressionParser.parse(input);
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        parsed.setBindingExpression(true);
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return parsed;
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
127d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<BindingTarget> getBindingTargets() {
128d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mBindingTargets;
129d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
131d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isEmpty() {
132d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mExprModel.size() == 0;
133d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
134d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
135d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public ExprModel getModel() {
136d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mExprModel;
137d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
13943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    private void ensureWriter() {
14043596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        if (mWriter == null) {
14143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            mWriter = new LayoutBinderWriter(this);
14243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        }
14343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    }
1443bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar
14543596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    public String writeViewBinderInterface() {
14643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        ensureWriter();
1474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        return mWriter.writeBaseClass();
14843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    }
14943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
15043596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
15143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    public String writeViewBinder() {
152d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel.seal();
15343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        ensureWriter();
154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Preconditions.checkNotNull(mPackage, "package cannot be null");
155d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Preconditions.checkNotNull(mProjectPackage, "project package cannot be null");
156d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Preconditions.checkNotNull(mBaseClassName, "base class name cannot be null");
15743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        return mWriter.write();
158d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
159d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getPackage() {
161d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mPackage;
162d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
163d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
164a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public String getModulePackage() {
165a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return mModulePackage;
166a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
167a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
168d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setPackage(String aPackage) {
169d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mPackage = aPackage;
170d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
171d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
172d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getProjectPackage() {
173d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mProjectPackage;
174d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
175d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
176d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getLayoutname() {
1773bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.getFileName();
178d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
179d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
180d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getClassName() {
1815bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        final String suffix;
1825bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        if (hasVariations()) {
1833bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar            suffix = mBundle.getConfigName();
1845bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        } else {
1855bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            suffix = "";
1865bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }
1875bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        return mBaseClassName + suffix + "Impl";
1885bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
189d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
1903bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar
19143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    public String getInterfaceName() {
19243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        return mBaseClassName;
19343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    }
1945bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
1955bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public int getId() {
1963bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.getLayoutId();
1975bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
1985bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
1995bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public boolean hasVariations() {
2003bd87eef217d80a233677d7e267224d0ed3c2c55Yigit Boyar        return mBundle.hasVariations();
2015bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
2025bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
203d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
204