1774424394537c69975f8fc0044765db8c252f66fTor Norbye/*
2774424394537c69975f8fc0044765db8c252f66fTor Norbye * Copyright (C) 2012 The Android Open Source Project
3774424394537c69975f8fc0044765db8c252f66fTor Norbye *
4774424394537c69975f8fc0044765db8c252f66fTor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5774424394537c69975f8fc0044765db8c252f66fTor Norbye * you may not use this file except in compliance with the License.
6774424394537c69975f8fc0044765db8c252f66fTor Norbye * You may obtain a copy of the License at
7774424394537c69975f8fc0044765db8c252f66fTor Norbye *
8774424394537c69975f8fc0044765db8c252f66fTor Norbye *      http://www.eclipse.org/org/documents/epl-v10.php
9774424394537c69975f8fc0044765db8c252f66fTor Norbye *
10774424394537c69975f8fc0044765db8c252f66fTor Norbye * Unless required by applicable law or agreed to in writing, software
11774424394537c69975f8fc0044765db8c252f66fTor Norbye * distributed under the License is distributed on an "AS IS" BASIS,
12774424394537c69975f8fc0044765db8c252f66fTor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13774424394537c69975f8fc0044765db8c252f66fTor Norbye * See the License for the specific language governing permissions and
14774424394537c69975f8fc0044765db8c252f66fTor Norbye * limitations under the License.
15774424394537c69975f8fc0044765db8c252f66fTor Norbye */
16774424394537c69975f8fc0044765db8c252f66fTor Norbyepackage com.android.ide.eclipse.adt.internal.editors.layout.properties;
17774424394537c69975f8fc0044765db8c252f66fTor Norbye
1812d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ATTR_TEXT_SIZE;
1912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.PREFIX_RESOURCE_REF;
2012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.PREFIX_THEME_REF;
2112d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.UNIT_DP;
2212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.UNIT_SP;
2312d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.VALUE_FALSE;
2412d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.VALUE_TRUE;
25774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.BOOLEAN;
26774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.DIMENSION;
27774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.ENUM;
28774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.FLAG;
29774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.FLOAT;
30774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.INTEGER;
31774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.REFERENCE;
32774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.STRING;
33774424394537c69975f8fc0044765db8c252f66fTor Norbye
34774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport com.android.annotations.NonNull;
35774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport com.android.annotations.Nullable;
36774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport com.android.ide.common.api.IAttributeInfo;
37774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport com.android.ide.common.api.IAttributeInfo.Format;
38774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
39774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
401fb460987f7d832adf12290f41448d0c16a95972Siva Velusamyimport com.android.utils.SdkUtils;
41774424394537c69975f8fc0044765db8c252f66fTor Norbye
42774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport org.eclipse.jface.fieldassist.ContentProposal;
43774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport org.eclipse.jface.fieldassist.IContentProposal;
44774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport org.eclipse.jface.fieldassist.IContentProposalProvider;
45774424394537c69975f8fc0044765db8c252f66fTor Norbye
46774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport java.util.ArrayList;
47774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport java.util.EnumSet;
48774424394537c69975f8fc0044765db8c252f66fTor Norbyeimport java.util.List;
49774424394537c69975f8fc0044765db8c252f66fTor Norbye
50774424394537c69975f8fc0044765db8c252f66fTor Norbye/**
51774424394537c69975f8fc0044765db8c252f66fTor Norbye * An {@link IContentProposalProvider} which completes possible property values
52774424394537c69975f8fc0044765db8c252f66fTor Norbye * for Android properties, completing resource strings, flag values, enum
53774424394537c69975f8fc0044765db8c252f66fTor Norbye * values, as well as dimension units.
54774424394537c69975f8fc0044765db8c252f66fTor Norbye */
55774424394537c69975f8fc0044765db8c252f66fTor Norbyeabstract class ValueCompleter implements IContentProposalProvider {
56774424394537c69975f8fc0044765db8c252f66fTor Norbye    @Nullable
57774424394537c69975f8fc0044765db8c252f66fTor Norbye    protected abstract CommonXmlEditor getEditor();
58774424394537c69975f8fc0044765db8c252f66fTor Norbye
59774424394537c69975f8fc0044765db8c252f66fTor Norbye    @NonNull
60774424394537c69975f8fc0044765db8c252f66fTor Norbye    protected abstract AttributeDescriptor getDescriptor();
61774424394537c69975f8fc0044765db8c252f66fTor Norbye
62774424394537c69975f8fc0044765db8c252f66fTor Norbye    @Override
63774424394537c69975f8fc0044765db8c252f66fTor Norbye    public IContentProposal[] getProposals(String contents, int position) {
64774424394537c69975f8fc0044765db8c252f66fTor Norbye        AttributeDescriptor descriptor = getDescriptor();
65774424394537c69975f8fc0044765db8c252f66fTor Norbye        IAttributeInfo info = descriptor.getAttributeInfo();
66774424394537c69975f8fc0044765db8c252f66fTor Norbye        EnumSet<Format> formats = info.getFormats();
67774424394537c69975f8fc0044765db8c252f66fTor Norbye
68774424394537c69975f8fc0044765db8c252f66fTor Norbye        List<IContentProposal> proposals = new ArrayList<IContentProposal>();
69774424394537c69975f8fc0044765db8c252f66fTor Norbye
70774424394537c69975f8fc0044765db8c252f66fTor Norbye        String prefix = contents; // TODO: Go back to position inside the array?
71774424394537c69975f8fc0044765db8c252f66fTor Norbye
72774424394537c69975f8fc0044765db8c252f66fTor Norbye        // TODO: If the user is typing in a number, or a number plus a prefix of a dimension unit,
73774424394537c69975f8fc0044765db8c252f66fTor Norbye        // then propose that number plus the completed dimension unit (using sp for text, dp
74774424394537c69975f8fc0044765db8c252f66fTor Norbye        // for other properties and maybe both if I'm not sure)
75774424394537c69975f8fc0044765db8c252f66fTor Norbye        if (formats.contains(STRING)
76774424394537c69975f8fc0044765db8c252f66fTor Norbye                && !contents.isEmpty()
77774424394537c69975f8fc0044765db8c252f66fTor Norbye                && (formats.size() > 1 && formats.contains(REFERENCE) ||
78774424394537c69975f8fc0044765db8c252f66fTor Norbye                        formats.size() > 2)
79774424394537c69975f8fc0044765db8c252f66fTor Norbye                && !contents.startsWith(PREFIX_RESOURCE_REF)
80774424394537c69975f8fc0044765db8c252f66fTor Norbye                && !contents.startsWith(PREFIX_THEME_REF)) {
81774424394537c69975f8fc0044765db8c252f66fTor Norbye            proposals.add(new ContentProposal(contents));
82774424394537c69975f8fc0044765db8c252f66fTor Norbye        }
83774424394537c69975f8fc0044765db8c252f66fTor Norbye
84774424394537c69975f8fc0044765db8c252f66fTor Norbye        if (!contents.isEmpty() && Character.isDigit(contents.charAt(0))
85774424394537c69975f8fc0044765db8c252f66fTor Norbye                && (formats.contains(DIMENSION)
86774424394537c69975f8fc0044765db8c252f66fTor Norbye                        || formats.contains(INTEGER)
87774424394537c69975f8fc0044765db8c252f66fTor Norbye                        || formats.contains(FLOAT))) {
88774424394537c69975f8fc0044765db8c252f66fTor Norbye            StringBuilder sb = new StringBuilder();
89774424394537c69975f8fc0044765db8c252f66fTor Norbye            for (int i = 0, n = contents.length(); i < n; i++) {
90774424394537c69975f8fc0044765db8c252f66fTor Norbye                char c = contents.charAt(i);
91774424394537c69975f8fc0044765db8c252f66fTor Norbye                if (Character.isDigit(c)) {
92774424394537c69975f8fc0044765db8c252f66fTor Norbye                    sb.append(c);
93774424394537c69975f8fc0044765db8c252f66fTor Norbye                } else {
94774424394537c69975f8fc0044765db8c252f66fTor Norbye                    break;
95774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
96774424394537c69975f8fc0044765db8c252f66fTor Norbye            }
97774424394537c69975f8fc0044765db8c252f66fTor Norbye
98774424394537c69975f8fc0044765db8c252f66fTor Norbye            String number = sb.toString();
99774424394537c69975f8fc0044765db8c252f66fTor Norbye            if (formats.contains(Format.DIMENSION)) {
100774424394537c69975f8fc0044765db8c252f66fTor Norbye                if (descriptor.getXmlLocalName().equals(ATTR_TEXT_SIZE)) {
101774424394537c69975f8fc0044765db8c252f66fTor Norbye                    proposals.add(new ContentProposal(number + UNIT_SP));
102774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
103774424394537c69975f8fc0044765db8c252f66fTor Norbye                proposals.add(new ContentProposal(number + UNIT_DP));
104774424394537c69975f8fc0044765db8c252f66fTor Norbye            } else if (formats.contains(Format.INTEGER)) {
105774424394537c69975f8fc0044765db8c252f66fTor Norbye                proposals.add(new ContentProposal(number));
106774424394537c69975f8fc0044765db8c252f66fTor Norbye            }
107774424394537c69975f8fc0044765db8c252f66fTor Norbye            // Perhaps offer other units too -- see AndroidContentAssist.sDimensionUnits
108774424394537c69975f8fc0044765db8c252f66fTor Norbye        }
109774424394537c69975f8fc0044765db8c252f66fTor Norbye
110774424394537c69975f8fc0044765db8c252f66fTor Norbye        if (formats.contains(REFERENCE) || contents.startsWith(PREFIX_RESOURCE_REF)
111774424394537c69975f8fc0044765db8c252f66fTor Norbye                || contents.startsWith(PREFIX_THEME_REF)) {
112774424394537c69975f8fc0044765db8c252f66fTor Norbye            CommonXmlEditor editor = getEditor();
113774424394537c69975f8fc0044765db8c252f66fTor Norbye            if (editor != null) {
114774424394537c69975f8fc0044765db8c252f66fTor Norbye                String[] matches = ResourceValueCompleter.computeResourceStringMatches(
115774424394537c69975f8fc0044765db8c252f66fTor Norbye                        editor,
116774424394537c69975f8fc0044765db8c252f66fTor Norbye                        descriptor, contents.substring(0, position));
117774424394537c69975f8fc0044765db8c252f66fTor Norbye                for (String match : matches) {
118774424394537c69975f8fc0044765db8c252f66fTor Norbye                    proposals.add(new ContentProposal(match));
119774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
120774424394537c69975f8fc0044765db8c252f66fTor Norbye            }
121774424394537c69975f8fc0044765db8c252f66fTor Norbye        }
122774424394537c69975f8fc0044765db8c252f66fTor Norbye
123774424394537c69975f8fc0044765db8c252f66fTor Norbye        if (formats.contains(FLAG)) {
124774424394537c69975f8fc0044765db8c252f66fTor Norbye            String[] values = info.getFlagValues();
125774424394537c69975f8fc0044765db8c252f66fTor Norbye            if (values != null) {
126774424394537c69975f8fc0044765db8c252f66fTor Norbye                // Flag completion
127774424394537c69975f8fc0044765db8c252f66fTor Norbye                int flagStart = prefix.lastIndexOf('|');
128774424394537c69975f8fc0044765db8c252f66fTor Norbye                String prepend = null;
129774424394537c69975f8fc0044765db8c252f66fTor Norbye                if (flagStart != -1) {
130774424394537c69975f8fc0044765db8c252f66fTor Norbye                    prepend = prefix.substring(0, flagStart + 1);
131774424394537c69975f8fc0044765db8c252f66fTor Norbye                    prefix = prefix.substring(flagStart + 1).trim();
132774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
133774424394537c69975f8fc0044765db8c252f66fTor Norbye
134774424394537c69975f8fc0044765db8c252f66fTor Norbye                boolean exactMatch = false;
135774424394537c69975f8fc0044765db8c252f66fTor Norbye                for (String value : values) {
136774424394537c69975f8fc0044765db8c252f66fTor Norbye                    if (prefix.equals(value)) {
137774424394537c69975f8fc0044765db8c252f66fTor Norbye                        exactMatch = true;
138774424394537c69975f8fc0044765db8c252f66fTor Norbye                        proposals.add(new ContentProposal(contents));
139774424394537c69975f8fc0044765db8c252f66fTor Norbye
140774424394537c69975f8fc0044765db8c252f66fTor Norbye                        break;
141774424394537c69975f8fc0044765db8c252f66fTor Norbye                    }
142774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
143774424394537c69975f8fc0044765db8c252f66fTor Norbye
144774424394537c69975f8fc0044765db8c252f66fTor Norbye                if (exactMatch) {
145774424394537c69975f8fc0044765db8c252f66fTor Norbye                    prepend = contents + '|';
146774424394537c69975f8fc0044765db8c252f66fTor Norbye                    prefix = "";
147774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
148774424394537c69975f8fc0044765db8c252f66fTor Norbye
149774424394537c69975f8fc0044765db8c252f66fTor Norbye                for (String value : values) {
1501fb460987f7d832adf12290f41448d0c16a95972Siva Velusamy                    if (SdkUtils.startsWithIgnoreCase(value, prefix)) {
151774424394537c69975f8fc0044765db8c252f66fTor Norbye                        if (prepend != null && prepend.contains(value)) {
152774424394537c69975f8fc0044765db8c252f66fTor Norbye                            continue;
153774424394537c69975f8fc0044765db8c252f66fTor Norbye                        }
154774424394537c69975f8fc0044765db8c252f66fTor Norbye                        String match;
155774424394537c69975f8fc0044765db8c252f66fTor Norbye                        if (prepend != null) {
156774424394537c69975f8fc0044765db8c252f66fTor Norbye                            match = prepend + value;
157774424394537c69975f8fc0044765db8c252f66fTor Norbye                        } else {
158774424394537c69975f8fc0044765db8c252f66fTor Norbye                            match = value;
159774424394537c69975f8fc0044765db8c252f66fTor Norbye                        }
160774424394537c69975f8fc0044765db8c252f66fTor Norbye                        proposals.add(new ContentProposal(match));
161774424394537c69975f8fc0044765db8c252f66fTor Norbye                    }
162774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
163774424394537c69975f8fc0044765db8c252f66fTor Norbye            }
164774424394537c69975f8fc0044765db8c252f66fTor Norbye        } else if (formats.contains(ENUM)) {
165774424394537c69975f8fc0044765db8c252f66fTor Norbye            String[] values = info.getEnumValues();
166774424394537c69975f8fc0044765db8c252f66fTor Norbye            if (values != null) {
167774424394537c69975f8fc0044765db8c252f66fTor Norbye                for (String value : values) {
1681fb460987f7d832adf12290f41448d0c16a95972Siva Velusamy                    if (SdkUtils.startsWithIgnoreCase(value, prefix)) {
169774424394537c69975f8fc0044765db8c252f66fTor Norbye                        proposals.add(new ContentProposal(value));
170774424394537c69975f8fc0044765db8c252f66fTor Norbye                    }
171774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
172774424394537c69975f8fc0044765db8c252f66fTor Norbye
173774424394537c69975f8fc0044765db8c252f66fTor Norbye                for (String value : values) {
1741fb460987f7d832adf12290f41448d0c16a95972Siva Velusamy                    if (!SdkUtils.startsWithIgnoreCase(value, prefix)) {
175774424394537c69975f8fc0044765db8c252f66fTor Norbye                        proposals.add(new ContentProposal(value));
176774424394537c69975f8fc0044765db8c252f66fTor Norbye                    }
177774424394537c69975f8fc0044765db8c252f66fTor Norbye                }
178774424394537c69975f8fc0044765db8c252f66fTor Norbye            }
179774424394537c69975f8fc0044765db8c252f66fTor Norbye        } else if (formats.contains(BOOLEAN)) {
180774424394537c69975f8fc0044765db8c252f66fTor Norbye            proposals.add(new ContentProposal(VALUE_TRUE));
181774424394537c69975f8fc0044765db8c252f66fTor Norbye            proposals.add(new ContentProposal(VALUE_FALSE));
182774424394537c69975f8fc0044765db8c252f66fTor Norbye        }
183774424394537c69975f8fc0044765db8c252f66fTor Norbye
184774424394537c69975f8fc0044765db8c252f66fTor Norbye        return proposals.toArray(new IContentProposal[proposals.size()]);
185774424394537c69975f8fc0044765db8c252f66fTor Norbye    }
18612d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye}
187