2 * Copyright (C) 2009 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.editors.manifest.model;
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;
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;
65 import java.util.TreeSet;
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.
71 * See {@link UiTextAttributeNode} for more information.
73 public class UiManifestPkgAttrNode extends UiTextAttributeNode {
76 * Creates a {@link UiManifestPkgAttrNode} object that will display ui to select or create
78 * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node.
80 public UiManifestPkgAttrNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) {
81 super(attributeDescriptor, uiParent);
85 * Creates a label widget and an associated text field.
87 * As most other parts of the android manifest editor, this assumes the
88 * parent uses a table layout with 2 columns.
91 public void createUiControl(final Composite parent, final IManagedForm managedForm) {
92 setManagedForm(managedForm);
93 FormToolkit toolkit = managedForm.getToolkit();
94 TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor();
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() {
104 public void linkActivated(HyperlinkEvent e) {
105 super.linkActivated(e);
109 formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
110 SectionHelper.addControlTooltip(formText, desc.getTooltip());
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);
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);
128 Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH);
130 browseButton.addSelectionListener(new SelectionAdapter() {
132 public void widgetSelected(SelectionEvent e) {
133 super.widgetSelected(e);
141 * Adds a validator to the text field that calls managedForm.getMessageManager().
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);
153 getManagedForm().getMessageManager().removeMessage(text, text);
158 text.addModifyListener(listener);
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);
167 // Finally call the validator once to make sure the initial value is processed
168 listener.modifyText(null);
172 * Handles response to the Browse button by creating a Package dialog.
174 private void doBrowseClick() {
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) {
184 public String getText(Object element) {
185 return element.toString();
188 public void addListener(ILabelProviderListener listener) {
191 public void dispose() {
194 public boolean isLabelProperty(Object element, String property) {
198 public void removeListener(ILabelProviderListener listener) {
202 dialog.setTitle("Android Manifest Package Selection");
203 dialog.setMessage("Select the Android Manifest package to target.");
205 dialog.setElements(getPossibleValues(null));
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);
217 * Handles response to the Label hyper link being activated.
219 private void doLabelClick() {
220 // get the current package name
221 String package_name = getTextWidget().getText().trim();
223 if (package_name.length() == 0) {
226 displayExistingManifest(package_name);
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.
235 * @param package_name The android package name to find. Must not be null.
237 private void displayExistingManifest(String package_name) {
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.
248 AndroidManifestParser parser = null;
250 parser = AndroidManifestParser.parseForData(manifestFile);
251 } catch (CoreException e) {
252 // ignore, handled below.
254 if (parser == null) {
255 // skip this project.
259 if (package_name.equals(parser.getPackage())) {
260 // Found the project.
262 IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
264 IWorkbenchPage page = win.getActivePage();
268 new FileEditorInput(manifestFile),
271 IWorkbenchPage.MATCH_INPUT);
272 } catch (PartInitException e) {
274 "Opening editor failed for %s", //$NON-NLS-1$
275 manifestFile.getFullPath());
280 // We found the project; even if we failed there's no need to keep looking.
287 * Displays the New Project Wizard to create a new project.
288 * If one is successfully created, use the Android Package name.
290 private void createNewProject() {
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);
304 * Returns all the possible android package names that could be used.
305 * The prefix is not used.
310 public String[] getPossibleValues(String prefix) {
311 TreeSet<String> packages = new TreeSet<String>();
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.
321 AndroidManifestParser parser = null;
323 parser = AndroidManifestParser.parseForData(manifestFile);
324 } catch (CoreException e) {
325 // ignore, handled below.
327 if (parser == null) {
328 // skip this project.
332 packages.add(parser.getPackage());
335 return packages.toArray(new String[packages.size()]);