aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java
diff options
context:
space:
mode:
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.java958
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;
+ }
+}