OSDN Git Service

android-2.1_r1 snapshot
[android-x86/sdk.git] / eclipse / plugins / com.android.ide.eclipse.adt / src / com / android / ide / eclipse / adt / internal / editors / manifest / model / UiManifestPkgAttrNode.java
1 /*
2  * Copyright (C) 2009 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.editors.manifest.model;
18
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
21 import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
22 import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestEditor;
23 import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;
24 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
25 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiTextAttributeNode;
26 import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser;
27 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
28 import com.android.ide.eclipse.adt.internal.wizards.actions.NewProjectAction;
29 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizard;
30
31 import org.eclipse.core.resources.IFile;
32 import org.eclipse.core.runtime.CoreException;
33 import org.eclipse.jdt.core.IJavaProject;
34 import org.eclipse.jface.dialogs.Dialog;
35 import org.eclipse.jface.dialogs.IMessageProvider;
36 import org.eclipse.jface.viewers.ILabelProvider;
37 import org.eclipse.jface.viewers.ILabelProviderListener;
38 import org.eclipse.jface.window.Window;
39 import org.eclipse.swt.SWT;
40 import org.eclipse.swt.events.DisposeEvent;
41 import org.eclipse.swt.events.DisposeListener;
42 import org.eclipse.swt.events.ModifyEvent;
43 import org.eclipse.swt.events.ModifyListener;
44 import org.eclipse.swt.events.SelectionAdapter;
45 import org.eclipse.swt.events.SelectionEvent;
46 import org.eclipse.swt.graphics.Image;
47 import org.eclipse.swt.layout.GridData;
48 import org.eclipse.swt.layout.GridLayout;
49 import org.eclipse.swt.widgets.Button;
50 import org.eclipse.swt.widgets.Composite;
51 import org.eclipse.swt.widgets.Text;
52 import org.eclipse.ui.IWorkbenchPage;
53 import org.eclipse.ui.IWorkbenchWindow;
54 import org.eclipse.ui.PartInitException;
55 import org.eclipse.ui.PlatformUI;
56 import org.eclipse.ui.dialogs.ElementListSelectionDialog;
57 import org.eclipse.ui.forms.IManagedForm;
58 import org.eclipse.ui.forms.events.HyperlinkAdapter;
59 import org.eclipse.ui.forms.events.HyperlinkEvent;
60 import org.eclipse.ui.forms.widgets.FormText;
61 import org.eclipse.ui.forms.widgets.FormToolkit;
62 import org.eclipse.ui.forms.widgets.TableWrapData;
63 import org.eclipse.ui.part.FileEditorInput;
64
65 import java.util.TreeSet;
66
67 /**
68  * Represents an XML attribute to select an exisintg manifest package, that can be modified using
69  * a simple text field or a dialog to choose an existing package.
70  * <p/>
71  * See {@link UiTextAttributeNode} for more information.
72  */
73 public class UiManifestPkgAttrNode extends UiTextAttributeNode {
74
75     /**
76      * Creates a {@link UiManifestPkgAttrNode} object that will display ui to select or create
77      * a manifest package.
78      * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node.
79      */
80     public UiManifestPkgAttrNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) {
81         super(attributeDescriptor, uiParent);
82     }
83
84     /* (non-java doc)
85      * Creates a label widget and an associated text field.
86      * <p/>
87      * As most other parts of the android manifest editor, this assumes the
88      * parent uses a table layout with 2 columns.
89      */
90     @Override
91     public void createUiControl(final Composite parent, final IManagedForm managedForm) {
92         setManagedForm(managedForm);
93         FormToolkit toolkit = managedForm.getToolkit();
94         TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor();
95
96         StringBuilder label = new StringBuilder();
97         label.append("<form><p><a href='unused'>");  //$NON-NLS-1$
98         label.append(desc.getUiName());
99         label.append("</a></p></form>");  //$NON-NLS-1$
100         FormText formText = SectionHelper.createFormText(parent, toolkit, true /* isHtml */,
101                 label.toString(), true /* setupLayoutData */);
102         formText.addHyperlinkListener(new HyperlinkAdapter() {
103             @Override
104             public void linkActivated(HyperlinkEvent e) {
105                 super.linkActivated(e);
106                 doLabelClick();
107             }
108         });
109         formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
110         SectionHelper.addControlTooltip(formText, desc.getTooltip());
111         
112         Composite composite = toolkit.createComposite(parent);
113         composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE));
114         GridLayout gl = new GridLayout(2, false);
115         gl.marginHeight = gl.marginWidth = 0;
116         composite.setLayout(gl);
117         // Fixes missing text borders under GTK... also requires adding a 1-pixel margin
118         // for the text field below
119         toolkit.paintBordersFor(composite);
120         
121         final Text text = toolkit.createText(composite, getCurrentValue());
122         GridData gd = new GridData(GridData.FILL_HORIZONTAL);
123         gd.horizontalIndent = 1;  // Needed by the fixed composite borders under GTK
124         text.setLayoutData(gd);
125
126         setTextWidget(text);
127
128         Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH);
129         
130         browseButton.addSelectionListener(new SelectionAdapter() {
131             @Override
132             public void widgetSelected(SelectionEvent e) {
133                 super.widgetSelected(e);
134                 doBrowseClick();
135             }
136         });
137         
138     }
139     
140     /* (non-java doc)
141      * Adds a validator to the text field that calls managedForm.getMessageManager().
142      */
143     @Override
144     protected void onAddValidators(final Text text) {
145         ModifyListener listener = new ModifyListener() {
146             public void modifyText(ModifyEvent e) {
147                 String package_name = text.getText();
148                 if (package_name.indexOf('.') < 1) {
149                     getManagedForm().getMessageManager().addMessage(text,
150                             "Package name should contain at least two identifiers.",
151                             null /* data */, IMessageProvider.ERROR, text);
152                 } else {
153                     getManagedForm().getMessageManager().removeMessage(text, text);
154                 }
155             }
156         };
157
158         text.addModifyListener(listener);
159
160         // Make sure the validator removes its message(s) when the widget is disposed
161         text.addDisposeListener(new DisposeListener() {
162             public void widgetDisposed(DisposeEvent e) {
163                 getManagedForm().getMessageManager().removeMessage(text, text);
164             }
165         });
166
167         // Finally call the validator once to make sure the initial value is processed
168         listener.modifyText(null);
169     }
170
171     /**
172      * Handles response to the Browse button by creating a Package dialog.
173      * */
174     private void doBrowseClick() {
175         
176         // Display the list of AndroidManifest packages in a selection dialog
177         ElementListSelectionDialog dialog = new ElementListSelectionDialog(
178                 getTextWidget().getShell(),
179                 new ILabelProvider() {
180                     public Image getImage(Object element) {
181                         return null;
182                     }
183
184                     public String getText(Object element) {
185                         return element.toString();
186                     }
187
188                     public void addListener(ILabelProviderListener listener) {
189                     }
190
191                     public void dispose() {
192                     }
193
194                     public boolean isLabelProperty(Object element, String property) {
195                         return false;
196                     }
197
198                     public void removeListener(ILabelProviderListener listener) {
199                     }
200                 });
201
202         dialog.setTitle("Android Manifest Package Selection");
203         dialog.setMessage("Select the Android Manifest package to target.");
204
205         dialog.setElements(getPossibleValues(null));
206
207         // open the dialog and use the object selected if OK was clicked, or null otherwise
208         if (dialog.open() == Window.OK) {
209             String result = (String) dialog.getFirstResult();
210             if (result != null && result.length() > 0) {
211                 getTextWidget().setText(result);
212             }
213         }
214     }
215
216     /**
217      * Handles response to the Label hyper link being activated.
218      */
219     private void doLabelClick() {
220         // get the current package name
221         String package_name = getTextWidget().getText().trim();
222         
223         if (package_name.length() == 0) {
224             createNewProject();
225         } else {
226             displayExistingManifest(package_name);
227         }
228     }
229
230     /**
231      * When the label is clicked and there's already a package name, this method
232      * attempts to find the project matching the android package name and it attempts
233      * to open the manifest editor.
234      * 
235      * @param package_name The android package name to find. Must not be null.
236      */
237     private void displayExistingManifest(String package_name) {
238
239         // Look for the first project that uses this package name
240         for (IJavaProject project : BaseProjectHelper.getAndroidProjects()) {
241             // check that there is indeed a manifest file.
242             IFile manifestFile = AndroidManifestParser.getManifest(project.getProject());
243             if (manifestFile == null) {
244                 // no file? skip this project.
245                 continue;
246             }
247
248             AndroidManifestParser parser = null;
249             try {
250                 parser = AndroidManifestParser.parseForData(manifestFile);
251             } catch (CoreException e) {
252                 // ignore, handled below.
253             }
254             if (parser == null) {
255                 // skip this project.
256                 continue;
257             }
258
259             if (package_name.equals(parser.getPackage())) {
260                 // Found the project. 
261
262                 IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
263                 if (win != null) {
264                     IWorkbenchPage page = win.getActivePage();
265                     if (page != null) {
266                         try {
267                             page.openEditor(
268                                     new FileEditorInput(manifestFile),
269                                     ManifestEditor.ID,
270                                     true, /* activate */
271                                     IWorkbenchPage.MATCH_INPUT);
272                         } catch (PartInitException e) {
273                             AdtPlugin.log(e,
274                                     "Opening editor failed for %s",  //$NON-NLS-1$
275                                     manifestFile.getFullPath());
276                         }
277                     }
278                 }
279
280                 // We found the project; even if we failed there's no need to keep looking.
281                 return;
282             }
283         }
284     }
285
286     /**
287      * Displays the New Project Wizard to create a new project.
288      * If one is successfully created, use the Android Package name.
289      */
290     private void createNewProject() {
291
292         NewProjectAction npwAction = new NewProjectAction();
293         npwAction.run(null /*action*/);
294         if (npwAction.getDialogResult() == Dialog.OK) {
295             NewProjectWizard npw = (NewProjectWizard) npwAction.getWizard();
296             String name = npw.getPackageName();
297             if (name != null && name.length() > 0) {
298                 getTextWidget().setText(name);
299             }
300         }
301     }
302
303     /**
304      * Returns all the possible android package names that could be used.
305      * The prefix is not used.
306      * 
307      * {@inheritDoc}
308      */
309     @Override
310     public String[] getPossibleValues(String prefix) {
311         TreeSet<String> packages = new TreeSet<String>();
312
313         for (IJavaProject project : BaseProjectHelper.getAndroidProjects()) {
314             // check that there is indeed a manifest file.
315             IFile manifestFile = AndroidManifestParser.getManifest(project.getProject());
316             if (manifestFile == null) {
317                 // no file? skip this project.
318                 continue;
319             }
320
321             AndroidManifestParser parser = null;
322             try {
323                 parser = AndroidManifestParser.parseForData(manifestFile);
324             } catch (CoreException e) {
325                 // ignore, handled below.
326             }
327             if (parser == null) {
328                 // skip this project.
329                 continue;
330             }
331
332             packages.add(parser.getPackage());
333         }
334
335         return packages.toArray(new String[packages.size()]);
336     }
337 }
338