2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.eclipse.org/org/documents/epl-v10.php
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.ide.eclipse.adt.internal.ui;
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringRefactoring;
21 import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringWizard;
22 import com.android.ide.eclipse.adt.internal.resources.IResourceRepository;
23 import com.android.ide.eclipse.adt.internal.resources.ResourceItem;
24 import com.android.ide.eclipse.adt.internal.resources.ResourceType;
26 import org.eclipse.core.resources.IProject;
27 import org.eclipse.core.runtime.IStatus;
28 import org.eclipse.core.runtime.Status;
29 import org.eclipse.jface.dialogs.DialogSettings;
30 import org.eclipse.jface.dialogs.IDialogConstants;
31 import org.eclipse.jface.dialogs.IDialogSettings;
32 import org.eclipse.jface.viewers.ISelection;
33 import org.eclipse.jface.viewers.TreePath;
34 import org.eclipse.jface.viewers.TreeSelection;
35 import org.eclipse.jface.viewers.TreeViewer;
36 import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
37 import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.events.SelectionAdapter;
40 import org.eclipse.swt.events.SelectionEvent;
41 import org.eclipse.swt.events.SelectionListener;
42 import org.eclipse.swt.layout.GridData;
43 import org.eclipse.swt.widgets.Button;
44 import org.eclipse.swt.widgets.Composite;
45 import org.eclipse.swt.widgets.Control;
46 import org.eclipse.swt.widgets.Shell;
47 import org.eclipse.swt.widgets.Tree;
48 import org.eclipse.ui.IWorkbench;
49 import org.eclipse.ui.PlatformUI;
50 import org.eclipse.ui.dialogs.FilteredTree;
51 import org.eclipse.ui.dialogs.PatternFilter;
52 import org.eclipse.ui.dialogs.SelectionStatusDialog;
54 import java.util.regex.Matcher;
55 import java.util.regex.Pattern;
58 * A dialog to let the user choose a reference to a resource.
61 public class ReferenceChooserDialog extends SelectionStatusDialog {
63 private static Pattern sResourcePattern = Pattern.compile("@(.*)/(.+)"); //$NON-NLS-1$
64 private static Pattern sInlineIdResourcePattern = Pattern.compile("@\\+id/(.+)"); //$NON-NLS-1$
66 private static IDialogSettings sDialogSettings = new DialogSettings("");
68 private IResourceRepository mResources;
69 private String mCurrentResource;
70 private FilteredTree mFilteredTree;
71 private Button mNewResButton;
72 private final IProject mProject;
73 private TreeViewer mTreeViewer;
79 public ReferenceChooserDialog(IProject project, IResourceRepository resources, Shell parent) {
82 mResources = resources;
84 int shellStyle = getShellStyle();
85 setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
87 setTitle("Reference Chooser");
88 setMessage(String.format("Choose a resource"));
90 setDialogBoundsSettings(sDialogSettings, getDialogBoundsStrategy());
93 public void setCurrentResource(String resource) {
94 mCurrentResource = resource;
97 public String getCurrentResource() {
98 return mCurrentResource;
103 * @see org.eclipse.ui.dialogs.SelectionStatusDialog#computeResult()
106 protected void computeResult() {
108 TreePath treeSelection = getSelection();
109 if (treeSelection != null) {
110 if (treeSelection.getSegmentCount() == 2) {
111 // get the resource type and the resource item
112 ResourceType resourceType = (ResourceType)treeSelection.getFirstSegment();
113 ResourceItem resourceItem = (ResourceItem)treeSelection.getLastSegment();
115 mCurrentResource = resourceType.getXmlString(resourceItem, false /* system */);
121 protected Control createDialogArea(Composite parent) {
122 Composite top = (Composite)super.createDialogArea(parent);
124 // create the standard message area
125 createMessageArea(top);
127 // create the filtered tree
128 createFilteredTree(top);
130 // setup the initial selection
131 setupInitialSelection();
133 // create the "New Resource" button
134 createNewResButtons(top);
140 * Creates the "New Resource" button.
141 * @param top the parent composite
143 private void createNewResButtons(Composite top) {
144 mNewResButton = new Button(top, SWT.NONE);
145 mNewResButton.addSelectionListener(new OnNewResButtonSelected());
146 updateNewResButton();
149 private void createFilteredTree(Composite parent) {
150 mFilteredTree = new FilteredTree(parent, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION,
151 new PatternFilter());
153 GridData data = new GridData();
154 data.widthHint = convertWidthInCharsToPixels(60);
155 data.heightHint = convertHeightInCharsToPixels(18);
156 data.grabExcessVerticalSpace = true;
157 data.grabExcessHorizontalSpace = true;
158 data.horizontalAlignment = GridData.FILL;
159 data.verticalAlignment = GridData.FILL;
160 mFilteredTree.setLayoutData(data);
161 mFilteredTree.setFont(parent.getFont());
163 mTreeViewer = mFilteredTree.getViewer();
164 Tree tree = mTreeViewer.getTree();
166 tree.addSelectionListener(new SelectionListener() {
167 public void widgetDefaultSelected(SelectionEvent e) {
171 public void widgetSelected(SelectionEvent e) {
176 mTreeViewer.setLabelProvider(new ResourceLabelProvider());
177 mTreeViewer.setContentProvider(new ResourceContentProvider(false /* fullLevels */));
178 mTreeViewer.setInput(mResources);
181 protected void handleSelection() {
182 validateCurrentSelection();
183 updateNewResButton();
186 protected void handleDoubleClick() {
187 if (validateCurrentSelection()) {
188 buttonPressed(IDialogConstants.OK_ID);
193 * Returns the selected item in the tree as a {@link TreePath} object.
194 * @return the <code>TreePath</code> object or <code>null</code> if there was no selection.
196 private TreePath getSelection() {
197 ISelection selection = mFilteredTree.getViewer().getSelection();
198 if (selection instanceof TreeSelection) {
199 TreeSelection treeSelection = (TreeSelection)selection;
200 TreePath[] treePaths = treeSelection.getPaths();
202 // the selection mode is SWT.SINGLE, so we just get the first one.
203 if (treePaths.length > 0) {
211 private boolean validateCurrentSelection() {
212 TreePath treeSelection = getSelection();
215 if (treeSelection != null) {
216 if (treeSelection.getSegmentCount() == 2) {
217 status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID,
218 IStatus.OK, "", //$NON-NLS-1$
221 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
222 IStatus.ERROR, "You must select a Resource Item",
226 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
227 IStatus.ERROR, "", //$NON-NLS-1$
231 updateStatus(status);
233 return status.isOK();
237 * Updates the new res button when the list selection changes.
238 * The name of the button changes depending on the resource.
240 private void updateNewResButton() {
241 ResourceType type = getSelectedResourceType();
243 // We only support adding new strings right now
244 mNewResButton.setEnabled(type == ResourceType.STRING);
246 String title = String.format("New %1$s...",
247 type == null ? "Resource" : type.getDisplayName());
248 mNewResButton.setText(title);
249 mNewResButton.pack();
253 * Callback invoked when the mNewResButton is selected by the user.
255 private class OnNewResButtonSelected extends SelectionAdapter {
257 public void widgetSelected(SelectionEvent e) {
258 super.widgetSelected(e);
260 ResourceType type = getSelectedResourceType();
262 // We currently only support strings
263 if (type == ResourceType.STRING) {
265 ExtractStringRefactoring ref = new ExtractStringRefactoring(
266 mProject, true /*enforceNew*/);
267 RefactoringWizard wizard = new ExtractStringWizard(ref, mProject);
268 RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
270 IWorkbench w = PlatformUI.getWorkbench();
271 if (op.run(w.getDisplay().getActiveShell(), wizard.getDefaultPageTitle()) ==
272 IDialogConstants.OK_ID) {
273 mTreeViewer.refresh();
275 // select it if possible
276 setupInitialSelection(type, ref.getXmlStringId());
278 } catch (InterruptedException ex) {
279 // Interrupted. Pass.
286 * Returns the {@link ResourceType} of the selected element, if any.
287 * Returns null if nothing suitable is selected.
289 private ResourceType getSelectedResourceType() {
290 ResourceType type = null;
292 TreePath selection = getSelection();
293 if (selection != null && selection.getSegmentCount() > 0) {
294 Object first = selection.getFirstSegment();
295 if (first instanceof ResourceType) {
296 type = (ResourceType) first;
303 * Sets up the initial selection.
305 * This parses {@link #mCurrentResource} to find out the resource type and the resource name.
307 private void setupInitialSelection() {
308 // checks the inline id pattern first as it's more restrictive than the other one.
309 Matcher m = sInlineIdResourcePattern.matcher(mCurrentResource);
311 // get the matching name
312 String resourceName = m.group(1);
314 // setup initial selection
315 setupInitialSelection(ResourceType.ID, resourceName);
317 // attempts the inline id pattern
318 m = sResourcePattern.matcher(mCurrentResource);
320 // get the resource type.
321 ResourceType resourceType = ResourceType.getEnum(m.group(1));
322 if (resourceType != null) {
323 // get the matching name
324 String resourceName = m.group(2);
326 // setup initial selection
327 setupInitialSelection(resourceType, resourceName);
334 * Sets up the initial selection based on a {@link ResourceType} and a resource name.
335 * @param resourceType the resource type.
336 * @param resourceName the resource name.
338 private void setupInitialSelection(ResourceType resourceType, String resourceName) {
339 // get all the resources of this type
340 ResourceItem[] resourceItems = mResources.getResources(resourceType);
342 for (ResourceItem resourceItem : resourceItems) {
343 if (resourceName.equals(resourceItem.getName())) {
344 // name of the resource match, we select it,
345 TreePath treePath = new TreePath(new Object[] { resourceType, resourceItem });
346 mFilteredTree.getViewer().setSelection(
347 new TreeSelection(treePath),
355 // if we get here, the resource type is valid, but the resource is missing.
356 // we select and expand the resource type element.
357 TreePath treePath = new TreePath(new Object[] { resourceType });
358 mFilteredTree.getViewer().setSelection(
359 new TreeSelection(treePath),
361 mFilteredTree.getViewer().setExpandedState(resourceType, true /* expanded */);