diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java | 958 |
1 files changed, 958 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java new file mode 100644 index 000000000..ce828cf2a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java @@ -0,0 +1,958 @@ +/* + * 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.ui; + +import static com.android.SdkConstants.ANDROID_PREFIX; +import static com.android.SdkConstants.PREFIX_RESOURCE_REF; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.common.rendering.api.ResourceValue; +import com.android.ide.common.resources.ResourceItem; +import com.android.ide.common.resources.ResourceRepository; +import com.android.ide.common.resources.ResourceResolver; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.AdtUtils; +import com.android.ide.eclipse.adt.internal.assetstudio.OpenCreateAssetSetWizardAction; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart; +import com.android.ide.eclipse.adt.internal.editors.layout.properties.PropertyFactory; +import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringRefactoring; +import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringWizard; +import com.android.ide.eclipse.adt.internal.resources.ResourceHelper; +import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; +import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; +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.resources.ResourceType; +import com.android.utils.Pair; +import com.google.common.collect.Maps; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.window.Window; +import org.eclipse.ltk.ui.refactoring.RefactoringWizard; +import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +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.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog; +import org.eclipse.ui.dialogs.SelectionStatusDialog; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A dialog to let the user select a resource based on a resource type. + */ +public class ResourceChooser extends AbstractElementListSelectionDialog implements ModifyListener { + /** The return code from the dialog for the user choosing "Clear" */ + public static final int CLEAR_RETURN_CODE = -5; + /** The dialog button ID for the user choosing "Clear" */ + private static final int CLEAR_BUTTON_ID = CLEAR_RETURN_CODE; + + private Pattern mProjectResourcePattern; + private ResourceType mResourceType; + private final List<ResourceRepository> mProjectResources; + private final ResourceRepository mFrameworkResources; + private Pattern mSystemResourcePattern; + private Button mProjectButton; + private Button mSystemButton; + private Button mNewButton; + private String mCurrentResource; + private final IProject mProject; + private IInputValidator mInputValidator; + + /** Helper object used to draw previews for drawables and colors. */ + private ResourcePreviewHelper mPreviewHelper; + + /** + * Textfield for editing the actual returned value, updated when selection + * changes. Only shown if {@link #mShowValueText} is true. + */ + private Text mEditValueText; + + /** + * Whether the {@link #mEditValueText} textfield should be shown when the dialog is created. + */ + private boolean mShowValueText; + + /** + * Flag indicating whether it's the first time {@link #handleSelectionChanged()} is called. + * This is used to filter out the first selection event, always called by the superclass + * when the widget is created, to distinguish between "the dialog was created" and + * "the user clicked on a selection result", since only the latter should wipe out the + * manual user edit shown in the value text. + */ + private boolean mFirstSelect = true; + + /** + * Label used to show the resolved value in the resource chooser. Only shown + * if the {@link #mResourceResolver} field is set. + */ + private Label mResolvedLabel; + + /** Resource resolver used to show actual values for resources selected. (Optional). */ + private ResourceResolver mResourceResolver; + + /** + * Creates a Resource Chooser dialog. + * @param project Project being worked on + * @param type The type of the resource to choose + * @param projectResources The repository for the project + * @param frameworkResources The Framework resource repository + * @param parent the parent shell + */ + private ResourceChooser( + @NonNull IProject project, + @NonNull ResourceType type, + @NonNull List<ResourceRepository> projectResources, + @Nullable ResourceRepository frameworkResources, + @NonNull Shell parent) { + super(parent, new ResourceLabelProvider()); + mProject = project; + + mResourceType = type; + mProjectResources = projectResources; + mFrameworkResources = frameworkResources; + + mProjectResourcePattern = Pattern.compile( + PREFIX_RESOURCE_REF + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ + + mSystemResourcePattern = Pattern.compile( + ANDROID_PREFIX + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ + + setTitle("Resource Chooser"); + setMessage(String.format("Choose a %1$s resource", + mResourceType.getDisplayName().toLowerCase(Locale.US))); + } + + /** + * Creates a new {@link ResourceChooser} + * + * @param editor the associated layout editor + * @param type the resource type to choose + * @return a new {@link ResourceChooser} + */ + @NonNull + public static ResourceChooser create( + @NonNull GraphicalEditorPart editor, + @NonNull ResourceType type) { + IProject project = editor.getProject(); + Shell parent = editor.getCanvasControl().getShell(); + AndroidTargetData targetData = editor.getEditorDelegate().getEditor().getTargetData(); + ResourceChooser chooser = create(project, type, targetData, parent); + + // When editing Strings, allow editing the value text directly. When we + // get inline editing support (where values entered directly into the + // textual widget are translated automatically into a resource) this can + // go away. + if (type == ResourceType.STRING) { + chooser.setResourceResolver(editor.getResourceResolver()); + chooser.setShowValueText(true); + } else if (type == ResourceType.DIMEN || type == ResourceType.INTEGER) { + chooser.setResourceResolver(editor.getResourceResolver()); + } + + chooser.setPreviewHelper(new ResourcePreviewHelper(chooser, editor)); + return chooser; + } + + /** + * Creates a new {@link ResourceChooser} + * + * @param project the associated project + * @param type the resource type to choose + * @param targetData the associated framework target data + * @param parent the target shell + * @return a new {@link ResourceChooser} + */ + @NonNull + public static ResourceChooser create( + @NonNull IProject project, + @NonNull ResourceType type, + @Nullable AndroidTargetData targetData, + @NonNull Shell parent) { + ResourceManager manager = ResourceManager.getInstance(); + + List<ResourceRepository> projectResources = new ArrayList<ResourceRepository>(); + ProjectResources resources = manager.getProjectResources(project); + projectResources.add(resources); + + // Add in library project resources + ProjectState projectState = Sdk.getProjectState(project); + if (projectState != null) { + List<IProject> libraries = projectState.getFullLibraryProjects(); + if (libraries != null && !libraries.isEmpty()) { + for (IProject library : libraries) { + projectResources.add(manager.getProjectResources(library)); + } + } + } + + ResourceRepository frameworkResources = + targetData != null ? targetData.getFrameworkResources() : null; + return new ResourceChooser(project, type, projectResources, frameworkResources, parent); + } + + /** + * Sets whether this dialog should show the value field as a separate text + * value (and take the resulting value of the dialog from this text field + * rather than from the selection) + * + * @param showValueText if true, show the value text field + * @return this, for constructor chaining + */ + public ResourceChooser setShowValueText(boolean showValueText) { + mShowValueText = showValueText; + + return this; + } + + /** + * Sets the resource resolver to use to show resolved values for the current + * selection + * + * @param resourceResolver the resource resolver to use + * @return this, for constructor chaining + */ + public ResourceChooser setResourceResolver(ResourceResolver resourceResolver) { + mResourceResolver = resourceResolver; + + return this; + } + + /** + * Sets the {@link ResourcePreviewHelper} to use to preview drawable + * resources, if any + * + * @param previewHelper the helper to use + * @return this, for constructor chaining + */ + public ResourceChooser setPreviewHelper(ResourcePreviewHelper previewHelper) { + mPreviewHelper = previewHelper; + + return this; + } + + /** + * Sets the initial dialog size + * + * @param width the initial width + * @param height the initial height + * @return this, for constructor chaining + */ + public ResourceChooser setInitialSize(int width, int height) { + setSize(width, height); + + return this; + } + + @Override + public void create() { + super.create(); + + if (mShowValueText) { + mEditValueText.selectAll(); + mEditValueText.setFocus(); + } + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, CLEAR_BUTTON_ID, "Clear", false /*defaultButton*/); + super.createButtonsForButtonBar(parent); + } + + @Override + protected void buttonPressed(int buttonId) { + super.buttonPressed(buttonId); + + if (buttonId == CLEAR_BUTTON_ID) { + assert CLEAR_RETURN_CODE != Window.OK && CLEAR_RETURN_CODE != Window.CANCEL; + setReturnCode(CLEAR_RETURN_CODE); + close(); + } + } + + /** + * Sets the currently selected item + * + * @param resource the resource url for the currently selected item + * @return this, for constructor chaining + */ + public ResourceChooser setCurrentResource(@Nullable String resource) { + mCurrentResource = resource; + + if (mShowValueText && mEditValueText != null) { + mEditValueText.setText(resource); + } + + return this; + } + + /** + * Returns the currently selected url + * + * @return the currently selected url + */ + @Nullable + public String getCurrentResource() { + return mCurrentResource; + } + + /** + * Sets the input validator to use, if any + * + * @param inputValidator the validator + * @return this, for constructor chaining + */ + public ResourceChooser setInputValidator(@Nullable IInputValidator inputValidator) { + mInputValidator = inputValidator; + + return this; + } + + @Override + protected void computeResult() { + if (mShowValueText) { + mCurrentResource = mEditValueText.getText(); + if (mCurrentResource.length() == 0) { + mCurrentResource = null; + } + return; + } + + computeResultFromSelection(); + } + + private void computeResultFromSelection() { + if (getSelectionIndex() == -1) { + mCurrentResource = null; + return; + } + + Object[] elements = getSelectedElements(); + if (elements.length == 1 && elements[0] instanceof ResourceItem) { + ResourceItem item = (ResourceItem)elements[0]; + + mCurrentResource = item.getXmlString(mResourceType, mSystemButton.getSelection()); + + if (mInputValidator != null && mInputValidator.isValid(mCurrentResource) != null) { + mCurrentResource = null; + } + } + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite top = (Composite)super.createDialogArea(parent); + + createMessageArea(top); + + createButtons(top); + createFilterText(top); + createFilteredList(top); + + // create the "New Resource" button + createNewResButtons(top); + + // Optionally create the value text field, if {@link #mShowValueText} is true + createValueField(top); + + setupResourceList(); + selectResourceString(mCurrentResource); + + return top; + } + + /** + * Creates the radio button to switch between project and system resources. + * @param top the parent composite + */ + private void createButtons(Composite top) { + mProjectButton = new Button(top, SWT.RADIO); + mProjectButton.setText("Project Resources"); + mProjectButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + super.widgetSelected(e); + if (mProjectButton.getSelection()) { + // Clear selection before changing the list contents. This works around + // a bug in the superclass where switching to the framework resources, + // choosing one of the last resources, then switching to the project + // resources would cause an exception when calling getSelection() because + // selection state doesn't get cleared when we set new contents on + // the filtered list. + fFilteredList.setSelection(new int[0]); + setupResourceList(); + updateNewButton(false /*isSystem*/); + updateValue(); + } + } + }); + mSystemButton = new Button(top, SWT.RADIO); + mSystemButton.setText("System Resources"); + mSystemButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + super.widgetSelected(e); + if (mSystemButton.getSelection()) { + fFilteredList.setSelection(new int[0]); + setupResourceList(); + updateNewButton(true /*isSystem*/); + updateValue(); + } + } + }); + if (mFrameworkResources == null) { + mSystemButton.setVisible(false); + } + } + + /** + * Creates the "New Resource" button. + * @param top the parent composite + */ + private void createNewResButtons(Composite top) { + mNewButton = new Button(top, SWT.NONE); + + String title = String.format("New %1$s...", mResourceType.getDisplayName()); + if (mResourceType == ResourceType.DRAWABLE) { + title = "Create New Icon..."; + } + mNewButton.setText(title); + + mNewButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + super.widgetSelected(e); + + if (mResourceType == ResourceType.STRING) { + // Special case: Use Extract String refactoring wizard UI + String newName = createNewString(); + selectAddedItem(newName); + } else if (mResourceType == ResourceType.DRAWABLE) { + // Special case: Use the "Create Icon Set" wizard + OpenCreateAssetSetWizardAction action = + new OpenCreateAssetSetWizardAction(mProject); + action.run(); + List<IResource> files = action.getCreatedFiles(); + if (files != null && files.size() > 0) { + String newName = AdtUtils.stripAllExtensions(files.get(0).getName()); + // Recompute the "current resource" to select the new id + ResourceItem[] items = setupResourceList(); + selectItemName(newName, items); + } + } else { + if (ResourceHelper.isValueBasedResourceType(mResourceType)) { + String newName = createNewValue(mResourceType); + if (newName != null) { + selectAddedItem(newName); + } + } else { + String newName = createNewFile(mResourceType); + if (newName != null) { + selectAddedItem(newName); + } + } + } + } + + private void selectAddedItem(@NonNull String newName) { + // Recompute the "current resource" to select the new id + ResourceItem[] items = setupResourceList(); + + // Ensure that the name is in the list. There's a delay after + // an item is added (until the builder runs and processes the delta) + // so if it's not in the list, add it + boolean found = false; + for (ResourceItem item : items) { + if (newName.equals(item.getName())) { + found = true; + break; + } + } + if (!found) { + ResourceItem[] newItems = new ResourceItem[items.length + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + newItems[items.length] = new ResourceItem(newName); + items = newItems; + Arrays.sort(items); + setListElements(items); + fFilteredList.setEnabled(newItems.length > 0); + } + + selectItemName(newName, items); + } + }); + } + + /** + * Creates the value text field. + * + * @param top the parent composite + */ + private void createValueField(Composite top) { + if (mShowValueText) { + mEditValueText = new Text(top, SWT.BORDER); + if (mCurrentResource != null) { + mEditValueText.setText(mCurrentResource); + } + mEditValueText.addModifyListener(this); + + GridData data = new GridData(); + data.grabExcessVerticalSpace = false; + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.BEGINNING; + mEditValueText.setLayoutData(data); + mEditValueText.setFont(top.getFont()); + } + + if (mResourceResolver != null) { + mResolvedLabel = new Label(top, SWT.NONE); + GridData data = new GridData(); + data.grabExcessVerticalSpace = false; + data.grabExcessHorizontalSpace = true; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.BEGINNING; + mResolvedLabel.setLayoutData(data); + } + + Composite workaround = PropertyFactory.addWorkaround(top); + if (workaround != null) { + workaround.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1)); + } + } + + private void updateResolvedLabel() { + if (mResourceResolver == null) { + return; + } + + String v = null; + if (mCurrentResource != null) { + v = mCurrentResource; + if (mCurrentResource.startsWith(PREFIX_RESOURCE_REF)) { + ResourceValue value = mResourceResolver.findResValue(mCurrentResource, false); + if (value != null) { + v = value.getValue(); + } + } + } + + if (v == null) { + v = ""; + } + + mResolvedLabel.setText(String.format("Resolved Value: %1$s", v)); + } + + @Override + protected void handleSelectionChanged() { + super.handleSelectionChanged(); + if (mInputValidator != null) { + Object[] elements = getSelectedElements(); + if (elements.length == 1 && elements[0] instanceof ResourceItem) { + ResourceItem item = (ResourceItem)elements[0]; + String current = item.getXmlString(mResourceType, mSystemButton.getSelection()); + String error = mInputValidator.isValid(current); + IStatus status; + if (error != null) { + status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error); + } else { + status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID, null); + } + updateStatus(status); + } + } + + updateValue(); + } + + private void updateValue() { + if (mPreviewHelper != null) { + computeResult(); + mPreviewHelper.updatePreview(mResourceType, mCurrentResource); + } + + if (mShowValueText) { + if (mFirstSelect) { + mFirstSelect = false; + mEditValueText.selectAll(); + } else { + computeResultFromSelection(); + mEditValueText.setText(mCurrentResource != null ? mCurrentResource : ""); + } + } + + if (mResourceResolver != null) { + if (!mShowValueText) { + computeResultFromSelection(); + } + updateResolvedLabel(); + } + } + + @Nullable + private String createNewFile(ResourceType type) { + // Show a name/value dialog entering the key name and the value + Shell shell = AdtPlugin.getShell(); + if (shell == null) { + return null; + } + + ResourceNameValidator validator = ResourceNameValidator.create(true /*allowXmlExtension*/, + mProject, mResourceType); + InputDialog d = new InputDialog( + AdtPlugin.getShell(), + "Enter name", // title + "Enter name", + "", //$NON-NLS-1$ + validator); + if (d.open() == Window.OK) { + String name = d.getValue().trim(); + if (name.length() == 0) { + return null; + } + + Pair<IFile, IRegion> resource = ResourceHelper.createResource(mProject, type, name, + null); + if (resource != null) { + return name; + } + } + + return null; + } + + + @Nullable + private String createNewValue(ResourceType type) { + // Show a name/value dialog entering the key name and the value + Shell shell = AdtPlugin.getShell(); + if (shell == null) { + return null; + } + NameValueDialog dialog = new NameValueDialog(shell, getFilter()); + if (dialog.open() != Window.OK) { + return null; + } + + String name = dialog.getName(); + String value = dialog.getValue(); + if (name.length() == 0 || value.length() == 0) { + return null; + } + + Pair<IFile, IRegion> resource = ResourceHelper.createResource(mProject, type, name, value); + if (resource != null) { + return name; + } + + return null; + } + + private String createNewString() { + ExtractStringRefactoring ref = new ExtractStringRefactoring( + mProject, true /*enforceNew*/); + RefactoringWizard wizard = new ExtractStringWizard(ref, mProject); + RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard); + try { + IWorkbench w = PlatformUI.getWorkbench(); + if (op.run(w.getDisplay().getActiveShell(), wizard.getDefaultPageTitle()) == + IDialogConstants.OK_ID) { + return ref.getXmlStringId(); + } + } catch (InterruptedException ex) { + // Interrupted. Pass. + } + + return null; + } + + /** + * Setups the current list. + */ + private ResourceItem[] setupResourceList() { + Collection<ResourceItem> items = null; + if (mProjectButton.getSelection()) { + if (mProjectResources.size() == 1) { + items = mProjectResources.get(0).getResourceItemsOfType(mResourceType); + } else { + Map<String, ResourceItem> merged = Maps.newHashMapWithExpectedSize(200); + for (ResourceRepository repository : mProjectResources) { + for (ResourceItem item : repository.getResourceItemsOfType(mResourceType)) { + if (!merged.containsKey(item.getName())) { + merged.put(item.getName(), item); + } + } + } + items = merged.values(); + } + } else if (mSystemButton.getSelection()) { + items = mFrameworkResources.getResourceItemsOfType(mResourceType); + } + + if (items == null) { + items = Collections.emptyList(); + } + + ResourceItem[] arrayItems = items.toArray(new ResourceItem[items.size()]); + + // sort the array + Arrays.sort(arrayItems); + + setListElements(arrayItems); + fFilteredList.setEnabled(arrayItems.length > 0); + + return arrayItems; + } + + /** + * Select an item by its name, if possible. + */ + private void selectItemName(String itemName, ResourceItem[] items) { + if (itemName == null || items == null) { + return; + } + + for (ResourceItem item : items) { + if (itemName.equals(item.getName())) { + setSelection(new Object[] { item }); + break; + } + } + } + + /** + * Select an item by its full resource string. + * This also selects between project and system repository based on the resource string. + */ + private void selectResourceString(String resourceString) { + boolean isSystem = false; + String itemName = null; + + if (resourceString != null) { + // Is this a system resource? + // If not a system resource or if they are not available, this will be a project res. + Matcher m = mSystemResourcePattern.matcher(resourceString); + if (m.matches()) { + itemName = m.group(1); + isSystem = true; + } + + if (!isSystem && itemName == null) { + // Try to match project resource name + m = mProjectResourcePattern.matcher(resourceString); + if (m.matches()) { + itemName = m.group(1); + } + } + } + + // Update the repository selection + mProjectButton.setSelection(!isSystem); + mSystemButton.setSelection(isSystem); + updateNewButton(isSystem); + + // Update the list + ResourceItem[] items = setupResourceList(); + + // If we have a selection name, select it + if (itemName != null) { + selectItemName(itemName, items); + } + } + + private void updateNewButton(boolean isSystem) { + mNewButton.setEnabled(!isSystem && ResourceHelper.canCreateResourceType(mResourceType)); + } + + // ---- Implements ModifyListener ---- + + @Override + public void modifyText(ModifyEvent e) { + if (e.getSource() == mEditValueText && mResourceResolver != null) { + mCurrentResource = mEditValueText.getText(); + + if (mCurrentResource.startsWith(PREFIX_RESOURCE_REF)) { + if (mProjectResourcePattern.matcher(mCurrentResource).matches() || + mSystemResourcePattern.matcher(mCurrentResource).matches()) { + updateResolvedLabel(); + } + } else { + updateResolvedLabel(); + } + } + } + + /** Dialog asking for a Name/Value pair */ + private class NameValueDialog extends SelectionStatusDialog implements Listener { + private org.eclipse.swt.widgets.Text mNameText; + private org.eclipse.swt.widgets.Text mValueText; + private String mInitialName; + private String mName; + private String mValue; + private ResourceNameValidator mValidator; + + public NameValueDialog(Shell parent, String initialName) { + super(parent); + mInitialName = initialName; + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite container = new Composite(parent, SWT.NONE); + container.setLayout(new GridLayout(2, false)); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); + // Wide enough to accommodate the error label + gridData.widthHint = 500; + container.setLayoutData(gridData); + + + Label nameLabel = new Label(container, SWT.NONE); + nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + nameLabel.setText("Name:"); + + mNameText = new org.eclipse.swt.widgets.Text(container, SWT.BORDER); + mNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + if (mInitialName != null) { + mNameText.setText(mInitialName); + mNameText.selectAll(); + } + + Label valueLabel = new Label(container, SWT.NONE); + valueLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + valueLabel.setText("Value:"); + + mValueText = new org.eclipse.swt.widgets.Text(container, SWT.BORDER); + mValueText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + + mNameText.addListener(SWT.Modify, this); + mValueText.addListener(SWT.Modify, this); + + validate(); + + return container; + } + + @Override + protected void computeResult() { + mName = mNameText.getText().trim(); + mValue = mValueText.getText().trim(); + } + + private String getName() { + return mName; + } + + private String getValue() { + return mValue; + } + + @Override + public void handleEvent(Event event) { + validate(); + } + + private void validate() { + IStatus status; + computeResult(); + if (mName.length() == 0) { + status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Enter a name"); + } else if (mValue.length() == 0) { + status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Enter a value"); + } else { + if (mValidator == null) { + mValidator = ResourceNameValidator.create(false, mProject, mResourceType); + } + String error = mValidator.isValid(mName); + if (error != null) { + status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error); + } else { + status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID, null); + } + } + updateStatus(status); + } + } + + /** + * Open the resource chooser for the given type, associated with the given + * editor + * + * @param graphicalEditor the editor associated with the resource to be + * chosen (used to find the associated Android target to be used + * for framework resources etc) + * @param type the resource type to be chosen + * @param currentValue the current value, or null + * @param validator a validator to be used, or null + * @return the chosen resource, null if cancelled and "" if value should be + * cleared + */ + public static String chooseResource( + @NonNull GraphicalEditorPart graphicalEditor, + @NonNull ResourceType type, + String currentValue, IInputValidator validator) { + ResourceChooser chooser = create(graphicalEditor, type). + setCurrentResource(currentValue); + if (validator != null) { + // Ensure wide enough to accommodate validator error message + chooser.setSize(85, 10); + chooser.setInputValidator(validator); + } + int result = chooser.open(); + if (result == ResourceChooser.CLEAR_RETURN_CODE) { + return ""; //$NON-NLS-1$ + } else if (result == Window.OK) { + return chooser.getCurrentResource(); + } + + return null; + } +} |