aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ResourceValueCompleter.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ResourceValueCompleter.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ResourceValueCompleter.java182
1 files changed, 182 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ResourceValueCompleter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ResourceValueCompleter.java
new file mode 100644
index 000000000..081ec8069
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/ResourceValueCompleter.java
@@ -0,0 +1,182 @@
+/*
+ * 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.ANDROID_PKG;
+import static com.android.SdkConstants.ANDROID_PREFIX;
+import static com.android.SdkConstants.ANDROID_THEME_PREFIX;
+import static com.android.SdkConstants.NEW_ID_PREFIX;
+import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
+import static com.android.SdkConstants.PREFIX_THEME_REF;
+
+import com.android.ide.common.resources.ResourceItem;
+import com.android.ide.common.resources.ResourceRepository;
+import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiResourceAttributeNode;
+import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.resources.ResourceType;
+import com.android.utils.SdkUtils;
+
+import org.eclipse.core.resources.IProject;
+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.Collections;
+import java.util.List;
+
+/**
+ * Resource value completion for the given property
+ * <p>
+ * TODO:
+ * <ul>
+ * <li>also offer other values seen in the app
+ * <li>also offer previously set values for this property
+ * <li>also complete on properties
+ * </ul>
+ */
+class ResourceValueCompleter implements IContentProposalProvider {
+ protected final XmlProperty xmlProperty;
+
+ ResourceValueCompleter(XmlProperty xmlProperty) {
+ this.xmlProperty = xmlProperty;
+ }
+
+ @Override
+ public IContentProposal[] getProposals(String contents, int position) {
+ if (contents.startsWith(PREFIX_RESOURCE_REF)) {
+ CommonXmlEditor editor = this.xmlProperty.getXmlEditor();
+ if (editor != null) {
+ String[] matches = computeResourceStringMatches(
+ editor,
+ this.xmlProperty.mDescriptor, contents.substring(0, position));
+ List<IContentProposal> proposals = null;
+ if (matches != null && matches.length > 0) {
+ proposals = new ArrayList<IContentProposal>(matches.length);
+ for (String match : matches) {
+ proposals.add(new ContentProposal(match));
+ }
+ return proposals.toArray(new IContentProposal[proposals.size()]);
+ }
+ }
+ }
+
+ return new IContentProposal[0];
+ }
+
+ /**
+ * Similar to {@link UiResourceAttributeNode#computeResourceStringMatches}
+ * but computes complete results up front rather than dividing it up into
+ * smaller chunks like @{code @android:}, {@code string/}, and {@code ok}.
+ */
+ static String[] computeResourceStringMatches(AndroidXmlEditor editor,
+ AttributeDescriptor attributeDescriptor, String prefix) {
+ List<String> results = new ArrayList<String>(200);
+
+ // System matches: only do this if the value already matches at least @a,
+ // and doesn't start with something that can't possibly be @android
+ if (prefix.startsWith("@a") && //$NON-NLS-1$
+ prefix.regionMatches(true /* ignoreCase */, 0, ANDROID_PREFIX, 0,
+ Math.min(prefix.length() - 1, ANDROID_PREFIX.length()))) {
+ AndroidTargetData data = editor.getTargetData();
+ if (data != null) {
+ ResourceRepository repository = data.getFrameworkResources();
+ addMatches(repository, prefix, true /* isSystem */, results);
+ }
+ } else if (prefix.startsWith("?") && //$NON-NLS-1$
+ prefix.regionMatches(true /* ignoreCase */, 0, ANDROID_THEME_PREFIX, 0,
+ Math.min(prefix.length() - 1, ANDROID_THEME_PREFIX.length()))) {
+ AndroidTargetData data = editor.getTargetData();
+ if (data != null) {
+ ResourceRepository repository = data.getFrameworkResources();
+ addMatches(repository, prefix, true /* isSystem */, results);
+ }
+ }
+
+
+ // When completing project resources skip framework resources unless
+ // the prefix possibly completes both, such as "@an" which can match
+ // both the project resource @animator as well as @android:string
+ if (!prefix.startsWith("@and") && !prefix.startsWith("?and")) { //$NON-NLS-1$ //$NON-NLS-2$
+ IProject project = editor.getProject();
+ if (project != null) {
+ // get the resource repository for this project and the system resources.
+ ResourceManager manager = ResourceManager.getInstance();
+ ResourceRepository repository = manager.getProjectResources(project);
+ if (repository != null) {
+ // We have a style name and a repository. Find all resources that match this
+ // type and recreate suggestions out of them.
+ addMatches(repository, prefix, false /* isSystem */, results);
+ }
+
+ }
+ }
+
+ if (attributeDescriptor != null) {
+ UiResourceAttributeNode.sortAttributeChoices(attributeDescriptor, results);
+ } else {
+ Collections.sort(results);
+ }
+
+ return results.toArray(new String[results.size()]);
+ }
+
+ private static void addMatches(ResourceRepository repository, String prefix, boolean isSystem,
+ List<String> results) {
+ int typeStart = isSystem
+ ? ANDROID_PREFIX.length() : PREFIX_RESOURCE_REF.length();
+
+ for (ResourceType type : repository.getAvailableResourceTypes()) {
+ if (prefix.regionMatches(typeStart, type.getName(), 0,
+ Math.min(type.getName().length(), prefix.length() - typeStart))) {
+ StringBuilder sb = new StringBuilder();
+ if (prefix.length() == 0 || prefix.startsWith(PREFIX_RESOURCE_REF)) {
+ sb.append(PREFIX_RESOURCE_REF);
+ } else {
+ if (type != ResourceType.ATTR) {
+ continue;
+ }
+ sb.append(PREFIX_THEME_REF);
+ }
+
+ if (type == ResourceType.ID && prefix.startsWith(NEW_ID_PREFIX)) {
+ sb.append('+');
+ }
+
+ if (isSystem) {
+ sb.append(ANDROID_PKG).append(':');
+ }
+
+ sb.append(type.getName()).append('/');
+ String base = sb.toString();
+
+ int nameStart = typeStart + type.getName().length() + 1; // +1: add "/" divider
+ String namePrefix =
+ prefix.length() <= nameStart ? "" : prefix.substring(nameStart);
+ for (ResourceItem item : repository.getResourceItemsOfType(type)) {
+ String name = item.getName();
+ if (SdkUtils.startsWithIgnoreCase(name, namePrefix)) {
+ results.add(base + name);
+ }
+ }
+ }
+ }
+ }
+}