aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ContextPullParser.java
blob: f30406520ad7244fd6252588df268356b4b7efb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.eclipse.org/org/documents/epl-v10.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ide.eclipse.adt.internal.editors.layout;

import static com.android.SdkConstants.ATTR_IGNORE;
import static com.android.SdkConstants.ATTR_LAYOUT;
import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
import static com.android.SdkConstants.EXPANDABLE_LIST_VIEW;
import static com.android.SdkConstants.GRID_VIEW;
import static com.android.SdkConstants.LIST_VIEW;
import static com.android.SdkConstants.SPINNER;
import static com.android.SdkConstants.TOOLS_URI;
import static com.android.SdkConstants.VALUE_FILL_PARENT;
import static com.android.SdkConstants.VALUE_MATCH_PARENT;
import static com.android.SdkConstants.VIEW_FRAGMENT;
import static com.android.SdkConstants.VIEW_INCLUDE;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata.KEY_FRAGMENT_LAYOUT;

import com.android.SdkConstants;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.res2.ValueXmlHelper;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata;
import com.google.common.collect.Maps;

import org.kxml2.io.KXmlParser;

import java.io.File;
import java.util.Map;

/**
 * Modified {@link KXmlParser} that adds the methods of {@link ILayoutPullParser}, and
 * performs other layout-specific parser behavior like translating fragment tags into
 * include tags.
 * <p/>
 * It will return a given parser when queried for one through
 * {@link ILayoutPullParser#getParser(String)} for a given name.
 *
 */
public class ContextPullParser extends KXmlParser implements ILayoutPullParser {
    private static final String COMMENT_PREFIX = "<!--"; //$NON-NLS-1$
    private static final String COMMENT_SUFFIX = "-->"; //$NON-NLS-1$
    /** The callback to request parsers from */
    private final IProjectCallback mProjectCallback;
    /** The {@link File} for the layout currently being parsed */
    private File mFile;
    /** The layout to be shown for the current {@code <fragment>} tag. Usually null. */
    private String mFragmentLayout = null;

    /**
     * Creates a new {@link ContextPullParser}
     *
     * @param projectCallback the associated callback
     * @param file the file to be parsed
     */
    public ContextPullParser(IProjectCallback projectCallback, File file) {
        super();
        mProjectCallback = projectCallback;
        mFile = file;
    }

    // --- Layout lib API methods

    @Override
    /**
     * this is deprecated but must still be implemented for older layout libraries.
     * @deprecated use {@link IProjectCallback#getParser(String)}.
     */
    @Deprecated
    public ILayoutPullParser getParser(String layoutName) {
        return mProjectCallback.getParser(layoutName);
    }

    @Override
    public Object getViewCookie() {
        String name = super.getName();
        if (name == null) {
            return null;
        }

        // Store tools attributes if this looks like a layout we'll need adapter view
        // bindings for in the ProjectCallback.
        if (LIST_VIEW.equals(name)
                || EXPANDABLE_LIST_VIEW.equals(name)
                || GRID_VIEW.equals(name)
                || SPINNER.equals(name)) {
            Map<String, String> map = null;
            int count = getAttributeCount();
            for (int i = 0; i < count; i++) {
                String namespace = getAttributeNamespace(i);
                if (namespace != null && namespace.equals(TOOLS_URI)) {
                    String attribute = getAttributeName(i);
                    if (attribute.equals(ATTR_IGNORE)) {
                        continue;
                    }
                    if (map == null) {
                        map = Maps.newHashMapWithExpectedSize(4);
                    }
                    map.put(attribute, getAttributeValue(i));
                }
            }

            return map;
        }

        return null;
    }

    // --- KXMLParser override

    @Override
    public String getName() {
        String name = super.getName();

        // At designtime, replace fragments with includes.
        if (name.equals(VIEW_FRAGMENT)) {
            mFragmentLayout = LayoutMetadata.getProperty(this, KEY_FRAGMENT_LAYOUT);
            if (mFragmentLayout != null) {
                return VIEW_INCLUDE;
            }
        } else {
            mFragmentLayout = null;
        }


        return name;
    }

    @Override
    public String getAttributeValue(String namespace, String localName) {
        if (ATTR_LAYOUT.equals(localName) && mFragmentLayout != null) {
            return mFragmentLayout;
        }

        String value = super.getAttributeValue(namespace, localName);

        // on the fly convert match_parent to fill_parent for compatibility with older
        // platforms.
        if (VALUE_MATCH_PARENT.equals(value) &&
                (ATTR_LAYOUT_WIDTH.equals(localName) ||
                        ATTR_LAYOUT_HEIGHT.equals(localName)) &&
                SdkConstants.NS_RESOURCES.equals(namespace)) {
            return VALUE_FILL_PARENT;
        }

        // Handle unicode escapes etc
        value = ValueXmlHelper.unescapeResourceString(value, false, false);

        return value;
    }
}