diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleter.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleter.java | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleter.java new file mode 100644 index 000000000..5559349fc --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleter.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2012 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.properties; + +import static com.android.SdkConstants.ATTR_TEXT_SIZE; +import static com.android.SdkConstants.PREFIX_RESOURCE_REF; +import static com.android.SdkConstants.PREFIX_THEME_REF; +import static com.android.SdkConstants.UNIT_DP; +import static com.android.SdkConstants.UNIT_SP; +import static com.android.SdkConstants.VALUE_FALSE; +import static com.android.SdkConstants.VALUE_TRUE; +import static com.android.ide.common.api.IAttributeInfo.Format.BOOLEAN; +import static com.android.ide.common.api.IAttributeInfo.Format.DIMENSION; +import static com.android.ide.common.api.IAttributeInfo.Format.ENUM; +import static com.android.ide.common.api.IAttributeInfo.Format.FLAG; +import static com.android.ide.common.api.IAttributeInfo.Format.FLOAT; +import static com.android.ide.common.api.IAttributeInfo.Format.INTEGER; +import static com.android.ide.common.api.IAttributeInfo.Format.REFERENCE; +import static com.android.ide.common.api.IAttributeInfo.Format.STRING; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.common.api.IAttributeInfo; +import com.android.ide.common.api.IAttributeInfo.Format; +import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; +import com.android.utils.SdkUtils; + +import org.eclipse.jface.fieldassist.ContentProposal; +import org.eclipse.jface.fieldassist.IContentProposal; +import org.eclipse.jface.fieldassist.IContentProposalProvider; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +/** + * An {@link IContentProposalProvider} which completes possible property values + * for Android properties, completing resource strings, flag values, enum + * values, as well as dimension units. + */ +abstract class ValueCompleter implements IContentProposalProvider { + @Nullable + protected abstract CommonXmlEditor getEditor(); + + @NonNull + protected abstract AttributeDescriptor getDescriptor(); + + @Override + public IContentProposal[] getProposals(String contents, int position) { + AttributeDescriptor descriptor = getDescriptor(); + IAttributeInfo info = descriptor.getAttributeInfo(); + EnumSet<Format> formats = info.getFormats(); + + List<IContentProposal> proposals = new ArrayList<IContentProposal>(); + + String prefix = contents; // TODO: Go back to position inside the array? + + // TODO: If the user is typing in a number, or a number plus a prefix of a dimension unit, + // then propose that number plus the completed dimension unit (using sp for text, dp + // for other properties and maybe both if I'm not sure) + if (formats.contains(STRING) + && !contents.isEmpty() + && (formats.size() > 1 && formats.contains(REFERENCE) || + formats.size() > 2) + && !contents.startsWith(PREFIX_RESOURCE_REF) + && !contents.startsWith(PREFIX_THEME_REF)) { + proposals.add(new ContentProposal(contents)); + } + + if (!contents.isEmpty() && Character.isDigit(contents.charAt(0)) + && (formats.contains(DIMENSION) + || formats.contains(INTEGER) + || formats.contains(FLOAT))) { + StringBuilder sb = new StringBuilder(); + for (int i = 0, n = contents.length(); i < n; i++) { + char c = contents.charAt(i); + if (Character.isDigit(c)) { + sb.append(c); + } else { + break; + } + } + + String number = sb.toString(); + if (formats.contains(Format.DIMENSION)) { + if (descriptor.getXmlLocalName().equals(ATTR_TEXT_SIZE)) { + proposals.add(new ContentProposal(number + UNIT_SP)); + } + proposals.add(new ContentProposal(number + UNIT_DP)); + } else if (formats.contains(Format.INTEGER)) { + proposals.add(new ContentProposal(number)); + } + // Perhaps offer other units too -- see AndroidContentAssist.sDimensionUnits + } + + if (formats.contains(REFERENCE) || contents.startsWith(PREFIX_RESOURCE_REF) + || contents.startsWith(PREFIX_THEME_REF)) { + CommonXmlEditor editor = getEditor(); + if (editor != null) { + String[] matches = ResourceValueCompleter.computeResourceStringMatches( + editor, + descriptor, contents.substring(0, position)); + for (String match : matches) { + proposals.add(new ContentProposal(match)); + } + } + } + + if (formats.contains(FLAG)) { + String[] values = info.getFlagValues(); + if (values != null) { + // Flag completion + int flagStart = prefix.lastIndexOf('|'); + String prepend = null; + if (flagStart != -1) { + prepend = prefix.substring(0, flagStart + 1); + prefix = prefix.substring(flagStart + 1).trim(); + } + + boolean exactMatch = false; + for (String value : values) { + if (prefix.equals(value)) { + exactMatch = true; + proposals.add(new ContentProposal(contents)); + + break; + } + } + + if (exactMatch) { + prepend = contents + '|'; + prefix = ""; + } + + for (String value : values) { + if (SdkUtils.startsWithIgnoreCase(value, prefix)) { + if (prepend != null && prepend.contains(value)) { + continue; + } + String match; + if (prepend != null) { + match = prepend + value; + } else { + match = value; + } + proposals.add(new ContentProposal(match)); + } + } + } + } else if (formats.contains(ENUM)) { + String[] values = info.getEnumValues(); + if (values != null) { + for (String value : values) { + if (SdkUtils.startsWithIgnoreCase(value, prefix)) { + proposals.add(new ContentProposal(value)); + } + } + + for (String value : values) { + if (!SdkUtils.startsWithIgnoreCase(value, prefix)) { + proposals.add(new ContentProposal(value)); + } + } + } + } else if (formats.contains(BOOLEAN)) { + proposals.add(new ContentProposal(VALUE_TRUE)); + proposals.add(new ContentProposal(VALUE_FALSE)); + } + + return proposals.toArray(new IContentProposal[proposals.size()]); + } +} |