blob: 5559349fc0e781ce8913ace6fe4ec46b67a17560 [file] [log] [blame]
/*
* 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()]);
}
}