OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / sdk / eclipse / plugins / com.android.ide.eclipse.adt / src / com / android / ide / eclipse / adt / internal / ui / ReferenceChooserDialog.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
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.
15  */
16
17 package com.android.ide.eclipse.adt.internal.ui;
18
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;
25
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;
53
54 import java.util.regex.Matcher;
55 import java.util.regex.Pattern;
56
57 /**
58  * A dialog to let the user choose a reference to a resource.
59  *
60  */
61 public class ReferenceChooserDialog extends SelectionStatusDialog {
62
63     private static Pattern sResourcePattern = Pattern.compile("@(.*)/(.+)"); //$NON-NLS-1$
64     private static Pattern sInlineIdResourcePattern = Pattern.compile("@\\+id/(.+)"); //$NON-NLS-1$
65
66     private static IDialogSettings sDialogSettings = new DialogSettings("");
67     
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;
74
75     /**
76      * @param project 
77      * @param parent
78      */
79     public ReferenceChooserDialog(IProject project, IResourceRepository resources, Shell parent) {
80         super(parent);
81         mProject = project;
82         mResources = resources;
83
84         int shellStyle = getShellStyle();
85         setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
86
87         setTitle("Reference Chooser");
88         setMessage(String.format("Choose a resource"));
89         
90         setDialogBoundsSettings(sDialogSettings, getDialogBoundsStrategy());
91     }
92
93     public void setCurrentResource(String resource) {
94         mCurrentResource = resource;
95     }
96     
97     public String getCurrentResource() {
98         return mCurrentResource;
99     }
100
101
102     /* (non-Javadoc)
103      * @see org.eclipse.ui.dialogs.SelectionStatusDialog#computeResult()
104      */
105     @Override
106     protected void computeResult() {
107         // get the selection
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();
114                 
115                 mCurrentResource = resourceType.getXmlString(resourceItem, false /* system */); 
116             }
117         }
118     }
119     
120     @Override
121     protected Control createDialogArea(Composite parent) {
122         Composite top = (Composite)super.createDialogArea(parent);
123
124         // create the standard message area
125         createMessageArea(top);
126
127         // create the filtered tree
128         createFilteredTree(top);
129
130         // setup the initial selection
131         setupInitialSelection();
132         
133         // create the "New Resource" button
134         createNewResButtons(top);
135         
136         return top;
137     }
138
139     /**
140      * Creates the "New Resource" button.
141      * @param top the parent composite
142      */
143     private void createNewResButtons(Composite top) {
144         mNewResButton = new Button(top, SWT.NONE);
145         mNewResButton.addSelectionListener(new OnNewResButtonSelected());
146         updateNewResButton();
147     }
148
149     private void createFilteredTree(Composite parent) {
150         mFilteredTree = new FilteredTree(parent, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION,
151                 new PatternFilter());
152         
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());
162         
163         mTreeViewer = mFilteredTree.getViewer();
164         Tree tree = mTreeViewer.getTree();
165         
166         tree.addSelectionListener(new SelectionListener() {
167             public void widgetDefaultSelected(SelectionEvent e) {
168                 handleDoubleClick();
169             }
170
171             public void widgetSelected(SelectionEvent e) {
172                 handleSelection();
173             }
174         });
175         
176         mTreeViewer.setLabelProvider(new ResourceLabelProvider());
177         mTreeViewer.setContentProvider(new ResourceContentProvider(false /* fullLevels */));
178         mTreeViewer.setInput(mResources);
179     }
180
181     protected void handleSelection() {
182         validateCurrentSelection();
183         updateNewResButton();
184     }
185
186     protected void handleDoubleClick() {
187         if (validateCurrentSelection()) {
188             buttonPressed(IDialogConstants.OK_ID);
189         }
190     }
191     
192     /**
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.
195      */
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();
201             
202             // the selection mode is SWT.SINGLE, so we just get the first one.
203             if (treePaths.length > 0) {
204                 return treePaths[0];
205             }
206         }
207         
208         return null;
209     }
210     
211     private boolean validateCurrentSelection() {
212         TreePath treeSelection = getSelection();
213         
214         IStatus status;
215         if (treeSelection != null) {
216             if (treeSelection.getSegmentCount() == 2) {
217                 status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID,
218                         IStatus.OK, "", //$NON-NLS-1$
219                         null);
220             } else {
221                 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
222                         IStatus.ERROR, "You must select a Resource Item",
223                         null);
224             }
225         } else {
226             status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
227                     IStatus.ERROR, "", //$NON-NLS-1$
228                     null);
229         }
230         
231         updateStatus(status);
232
233         return status.isOK();
234     }
235
236     /**
237      * Updates the new res button when the list selection changes.
238      * The name of the button changes depending on the resource.
239      */
240     private void updateNewResButton() {
241         ResourceType type = getSelectedResourceType();
242         
243         // We only support adding new strings right now
244         mNewResButton.setEnabled(type == ResourceType.STRING);
245         
246         String title = String.format("New %1$s...",
247                 type == null ? "Resource" : type.getDisplayName());
248         mNewResButton.setText(title);
249         mNewResButton.pack();
250     }
251
252     /**
253      * Callback invoked when the mNewResButton is selected by the user.
254      */
255     private class OnNewResButtonSelected extends SelectionAdapter {
256         @Override
257          public void widgetSelected(SelectionEvent e) {
258              super.widgetSelected(e);
259              
260              ResourceType type = getSelectedResourceType();
261
262              // We currently only support strings
263              if (type == ResourceType.STRING) {
264
265                  ExtractStringRefactoring ref = new ExtractStringRefactoring(
266                          mProject, true /*enforceNew*/);
267                  RefactoringWizard wizard = new ExtractStringWizard(ref, mProject);
268                  RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
269                  try {
270                      IWorkbench w = PlatformUI.getWorkbench();
271                      if (op.run(w.getDisplay().getActiveShell(), wizard.getDefaultPageTitle()) ==
272                              IDialogConstants.OK_ID) {
273                          mTreeViewer.refresh();
274                          
275                          // select it if possible
276                          setupInitialSelection(type, ref.getXmlStringId());
277                      }
278                  } catch (InterruptedException ex) {
279                      // Interrupted. Pass.
280                  }
281              }
282          } 
283      }
284
285     /**
286      * Returns the {@link ResourceType} of the selected element, if any.
287      * Returns null if nothing suitable is selected.
288      */
289     private ResourceType getSelectedResourceType() {
290         ResourceType type = null;
291
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;
297             }
298         }
299         return type;
300     }
301     
302     /**
303      * Sets up the initial selection.
304      * <p/>
305      * This parses {@link #mCurrentResource} to find out the resource type and the resource name.
306      */
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);
310         if (m.matches()) {
311             // get the matching name
312             String resourceName = m.group(1);
313
314             // setup initial selection
315             setupInitialSelection(ResourceType.ID, resourceName);
316         } else {
317             // attempts the inline id pattern
318             m = sResourcePattern.matcher(mCurrentResource);
319             if (m.matches()) {
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);
325                     
326                     // setup initial selection
327                     setupInitialSelection(resourceType, resourceName);
328                 }
329             }
330         }
331     }
332     
333     /**
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.
337      */
338     private void setupInitialSelection(ResourceType resourceType, String resourceName) {
339         // get all the resources of this type
340         ResourceItem[] resourceItems = mResources.getResources(resourceType);
341         
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),
348                         true /*reveal*/);
349                 
350                 // and we're done.
351                 return;
352             }
353         }
354         
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),
360                 true /*reveal*/);
361         mFilteredTree.getViewer().setExpandedState(resourceType, true /* expanded */);
362     }
363 }