diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java | 523 |
1 files changed, 0 insertions, 523 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java deleted file mode 100644 index eb51d3f86..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (C) 2007 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.uimodel; - -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.ATTR_ID; -import static com.android.SdkConstants.ATTR_LAYOUT; -import static com.android.SdkConstants.ATTR_STYLE; -import static com.android.SdkConstants.PREFIX_RESOURCE_REF; -import static com.android.SdkConstants.PREFIX_THEME_REF; - -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.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.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper; -import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; -import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.ui.ReferenceChooserDialog; -import com.android.ide.eclipse.adt.internal.ui.ResourceChooser; -import com.android.resources.ResourceType; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.TableWrapData; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Represents an XML attribute for a resource that can be modified using a simple text field or - * a dialog to choose an existing resource. - * <p/> - * It can be configured to represent any kind of resource, by providing the desired - * {@link ResourceType} in the constructor. - * <p/> - * See {@link UiTextAttributeNode} for more information. - */ -public class UiResourceAttributeNode extends UiTextAttributeNode { - private ResourceType mType; - - /** - * Creates a new {@linkplain UiResourceAttributeNode} - * - * @param type the associated resource type - * @param attributeDescriptor the attribute descriptor for this attribute - * @param uiParent the parent ui node, if any - */ - public UiResourceAttributeNode(ResourceType type, - AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - - mType = type; - } - - /* (non-java doc) - * Creates a label widget and an associated text field. - * <p/> - * As most other parts of the android manifest editor, this assumes the - * parent uses a table layout with 2 columns. - */ - @Override - public void createUiControl(final Composite parent, IManagedForm managedForm) { - setManagedForm(managedForm); - FormToolkit toolkit = managedForm.getToolkit(); - TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); - - Label label = toolkit.createLabel(parent, desc.getUiName()); - label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); - SectionHelper.addControlTooltip(label, DescriptorsUtils.formatTooltip(desc.getTooltip())); - - Composite composite = toolkit.createComposite(parent); - composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); - GridLayout gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - composite.setLayout(gl); - // Fixes missing text borders under GTK... also requires adding a 1-pixel margin - // for the text field below - toolkit.paintBordersFor(composite); - - final Text text = toolkit.createText(composite, getCurrentValue()); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK - text.setLayoutData(gd); - Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH); - - setTextWidget(text); - - // TODO Add a validator using onAddModifyListener - - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - String result = showDialog(parent.getShell(), text.getText().trim()); - if (result != null) { - text.setText(result); - } - } - }); - } - - /** - * Shows a dialog letting the user choose a set of enum, and returns a - * string containing the result. - * - * @param shell the parent shell - * @param currentValue an initial value, if any - * @return the chosen string, or null - */ - @Nullable - public String showDialog(@NonNull Shell shell, @Nullable String currentValue) { - // we need to get the project of the file being edited. - UiElementNode uiNode = getUiParent(); - AndroidXmlEditor editor = uiNode.getEditor(); - IProject project = editor.getProject(); - if (project != null) { - // get the resource repository for this project and the system resources. - ResourceRepository projectRepository = - ResourceManager.getInstance().getProjectResources(project); - - if (mType != null) { - // get the Target Data to get the system resources - AndroidTargetData data = editor.getTargetData(); - ResourceChooser dlg = ResourceChooser.create(project, mType, data, shell) - .setCurrentResource(currentValue); - if (dlg.open() == Window.OK) { - return dlg.getCurrentResource(); - } - } else { - ReferenceChooserDialog dlg = new ReferenceChooserDialog( - project, - projectRepository, - shell); - - dlg.setCurrentResource(currentValue); - - if (dlg.open() == Window.OK) { - return dlg.getCurrentResource(); - } - } - } - - return null; - } - - /** - * Gets all the values one could use to auto-complete a "resource" value in an XML - * content assist. - * <p/> - * Typically the user is editing the value of an attribute in a resource XML, e.g. - * <pre> "<Button android:test="@string/my_[caret]_string..." </pre> - * <p/> - * - * "prefix" is the value that the user has typed so far (or more exactly whatever is on the - * left side of the insertion point). In the example above it would be "@style/my_". - * <p/> - * - * To avoid a huge long list of values, the completion works on two levels: - * <ul> - * <li> If a resource type as been typed so far (e.g. "@style/"), then limit the values to - * the possible completions that match this type. - * <li> If no resource type as been typed so far, then return the various types that could be - * completed. So if the project has only strings and layouts resources, for example, - * the returned list will only include "@string/" and "@layout/". - * </ul> - * - * Finally if anywhere in the string we find the special token "android:", we use the - * current framework system resources rather than the project resources. - * This works for both "@android:style/foo" and "@style/android:foo" conventions even though - * the reconstructed name will always be of the former form. - * - * Note that "android:" here is a keyword specific to Android resources and should not be - * mixed with an XML namespace for an XML attribute name. - */ - @Override - public String[] getPossibleValues(String prefix) { - return computeResourceStringMatches(getUiParent().getEditor(), getDescriptor(), prefix); - } - - /** - * Computes the set of resource string matches for a given resource prefix in a given editor - * - * @param editor the editor context - * @param descriptor the attribute descriptor, if any - * @param prefix the prefix, if any - * @return an array of resource string matches - */ - @Nullable - public static String[] computeResourceStringMatches( - @NonNull AndroidXmlEditor editor, - @Nullable AttributeDescriptor descriptor, - @Nullable String prefix) { - - if (prefix == null || !prefix.regionMatches(1, ANDROID_PKG, 0, ANDROID_PKG.length())) { - IProject project = editor.getProject(); - if (project != null) { - // get the resource repository for this project and the system resources. - ResourceManager resourceManager = ResourceManager.getInstance(); - ResourceRepository repository = resourceManager.getProjectResources(project); - - List<IProject> libraries = null; - ProjectState projectState = Sdk.getProjectState(project); - if (projectState != null) { - libraries = projectState.getFullLibraryProjects(); - } - - String[] projectMatches = computeResourceStringMatches(descriptor, prefix, - repository, false); - - if (libraries == null || libraries.isEmpty()) { - return projectMatches; - } - - // Also compute matches for each of the libraries, and combine them - Set<String> matches = new HashSet<String>(200); - for (String s : projectMatches) { - matches.add(s); - } - - for (IProject library : libraries) { - repository = resourceManager.getProjectResources(library); - projectMatches = computeResourceStringMatches(descriptor, prefix, - repository, false); - for (String s : projectMatches) { - matches.add(s); - } - } - - String[] sorted = matches.toArray(new String[matches.size()]); - Arrays.sort(sorted); - return sorted; - } - } else { - // If there's a prefix with "android:" in it, use the system resources - // Non-public framework resources are filtered out later. - AndroidTargetData data = editor.getTargetData(); - if (data != null) { - ResourceRepository repository = data.getFrameworkResources(); - return computeResourceStringMatches(descriptor, prefix, repository, true); - } - } - - return null; - } - - /** - * Computes the set of resource string matches for a given prefix and a - * given resource repository - * - * @param attributeDescriptor the attribute descriptor, if any - * @param prefix the prefix, if any - * @param repository the repository to seaerch in - * @param isSystem if true, the repository contains framework repository, - * otherwise it contains project repositories - * @return an array of resource string matches - */ - @NonNull - public static String[] computeResourceStringMatches( - @Nullable AttributeDescriptor attributeDescriptor, - @Nullable String prefix, - @NonNull ResourceRepository repository, - boolean isSystem) { - // Get list of potential resource types, either specific to this project - // or the generic list. - Collection<ResourceType> resTypes = (repository != null) ? - repository.getAvailableResourceTypes() : - EnumSet.allOf(ResourceType.class); - - // Get the type name from the prefix, if any. It's any word before the / if there's one - String typeName = null; - if (prefix != null) { - Matcher m = Pattern.compile(".*?([a-z]+)/.*").matcher(prefix); //$NON-NLS-1$ - if (m.matches()) { - typeName = m.group(1); - } - } - - // Now collect results - List<String> results = new ArrayList<String>(); - - if (typeName == null) { - // This prefix does not have a / in it, so the resource string is either empty - // or does not have the resource type in it. Simply offer the list of potential - // resource types. - if (prefix != null && prefix.startsWith(PREFIX_THEME_REF)) { - results.add(ANDROID_THEME_PREFIX + ResourceType.ATTR.getName() + '/'); - if (resTypes.contains(ResourceType.ATTR) - || resTypes.contains(ResourceType.STYLE)) { - results.add(PREFIX_THEME_REF + ResourceType.ATTR.getName() + '/'); - if (prefix != null && prefix.startsWith(ANDROID_THEME_PREFIX)) { - // including attr isn't required - for (ResourceItem item : repository.getResourceItemsOfType( - ResourceType.ATTR)) { - results.add(ANDROID_THEME_PREFIX + item.getName()); - } - } - } - return results.toArray(new String[results.size()]); - } - - for (ResourceType resType : resTypes) { - if (isSystem) { - results.add(ANDROID_PREFIX + resType.getName() + '/'); - } else { - results.add('@' + resType.getName() + '/'); - } - if (resType == ResourceType.ID) { - // Also offer the + version to create an id from scratch - results.add("@+" + resType.getName() + '/'); //$NON-NLS-1$ - } - } - - // Also add in @android: prefix to completion such that if user has typed - // "@an" we offer to complete it. - if (prefix == null || - ANDROID_PKG.regionMatches(0, prefix, 1, prefix.length() - 1)) { - results.add(ANDROID_PREFIX); - } - } else if (repository != null) { - // We have a style name and a repository. Find all resources that match this - // type and recreate suggestions out of them. - - String initial = prefix != null && prefix.startsWith(PREFIX_THEME_REF) - ? PREFIX_THEME_REF : PREFIX_RESOURCE_REF; - ResourceType resType = ResourceType.getEnum(typeName); - if (resType != null) { - StringBuilder sb = new StringBuilder(); - sb.append(initial); - if (prefix != null && prefix.indexOf('+') >= 0) { - sb.append('+'); - } - - if (isSystem) { - sb.append(ANDROID_PKG).append(':'); - } - - sb.append(typeName).append('/'); - String base = sb.toString(); - - for (ResourceItem item : repository.getResourceItemsOfType(resType)) { - results.add(base + item.getName()); - } - - if (!isSystem && resType == ResourceType.ATTR) { - for (ResourceItem item : repository.getResourceItemsOfType( - ResourceType.STYLE)) { - results.add(base + item.getName()); - } - } - } - } - - if (attributeDescriptor != null) { - sortAttributeChoices(attributeDescriptor, results); - } else { - Collections.sort(results); - } - - return results.toArray(new String[results.size()]); - } - - /** - * Attempts to sort the attribute values to bubble up the most likely choices to - * the top. - * <p> - * For example, if you are editing a style attribute, it's likely that among the - * resource values you would rather see @style or @android than @string. - * @param descriptor the descriptor that the resource values are being completed for, - * used to prioritize some of the resource types - * @param choices the set of string resource values - */ - public static void sortAttributeChoices(AttributeDescriptor descriptor, - List<String> choices) { - final IAttributeInfo attributeInfo = descriptor.getAttributeInfo(); - Collections.sort(choices, new Comparator<String>() { - @Override - public int compare(String s1, String s2) { - int compare = score(attributeInfo, s1) - score(attributeInfo, s2); - if (compare == 0) { - // Sort alphabetically as a fallback - compare = s1.compareToIgnoreCase(s2); - } - return compare; - } - }); - } - - /** Compute a suitable sorting score for the given */ - private static final int score(IAttributeInfo attributeInfo, String value) { - if (value.equals(ANDROID_PREFIX)) { - return -1; - } - - for (Format format : attributeInfo.getFormats()) { - String type = null; - switch (format) { - case BOOLEAN: - type = "bool"; //$NON-NLS-1$ - break; - case COLOR: - type = "color"; //$NON-NLS-1$ - break; - case DIMENSION: - type = "dimen"; //$NON-NLS-1$ - break; - case INTEGER: - type = "integer"; //$NON-NLS-1$ - break; - case STRING: - type = "string"; //$NON-NLS-1$ - break; - // default: REFERENCE, FLAG, ENUM, etc - don't have type info about individual - // elements to help make a decision - } - - if (type != null) { - if (value.startsWith(PREFIX_RESOURCE_REF)) { - if (value.startsWith(PREFIX_RESOURCE_REF + type + '/')) { - return -2; - } - - if (value.startsWith(ANDROID_PREFIX + type + '/')) { - return -2; - } - } - if (value.startsWith(PREFIX_THEME_REF)) { - if (value.startsWith(PREFIX_THEME_REF + type + '/')) { - return -2; - } - - if (value.startsWith(ANDROID_THEME_PREFIX + type + '/')) { - return -2; - } - } - } - } - - // Handle a few more cases not covered by the Format metadata check - String type = null; - - String attribute = attributeInfo.getName(); - if (attribute.equals(ATTR_ID)) { - type = "id"; //$NON-NLS-1$ - } else if (attribute.equals(ATTR_STYLE)) { - type = "style"; //$NON-NLS-1$ - } else if (attribute.equals(ATTR_LAYOUT)) { - type = "layout"; //$NON-NLS-1$ - } else if (attribute.equals("drawable")) { //$NON-NLS-1$ - type = "drawable"; //$NON-NLS-1$ - } else if (attribute.equals("entries")) { //$NON-NLS-1$ - // Spinner - type = "array"; //$NON-NLS-1$ - } - - if (type != null) { - if (value.startsWith(PREFIX_RESOURCE_REF)) { - if (value.startsWith(PREFIX_RESOURCE_REF + type + '/')) { - return -2; - } - - if (value.startsWith(ANDROID_PREFIX + type + '/')) { - return -2; - } - } - if (value.startsWith(PREFIX_THEME_REF)) { - if (value.startsWith(PREFIX_THEME_REF + type + '/')) { - return -2; - } - - if (value.startsWith(ANDROID_THEME_PREFIX + type + '/')) { - return -2; - } - } - } - - return 0; - } -} |