| /* |
| * Copyright (C) 2009 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.editors.manifest.model; |
| |
| import com.android.ide.common.xml.ManifestData; |
| import com.android.ide.eclipse.adt.AdtPlugin; |
| import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; |
| import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor; |
| import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestEditor; |
| import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper; |
| import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; |
| import com.android.ide.eclipse.adt.internal.editors.uimodel.UiTextAttributeNode; |
| import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; |
| import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; |
| import com.android.ide.eclipse.adt.internal.project.ProjectHelper; |
| import com.android.ide.eclipse.adt.internal.wizards.actions.NewProjectAction; |
| import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizard; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.IMessageProvider; |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.ILabelProviderListener; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| 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.graphics.Image; |
| 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.Text; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.dialogs.ElementListSelectionDialog; |
| import org.eclipse.ui.forms.IManagedForm; |
| import org.eclipse.ui.forms.events.HyperlinkAdapter; |
| import org.eclipse.ui.forms.events.HyperlinkEvent; |
| import org.eclipse.ui.forms.widgets.FormText; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| import org.eclipse.ui.forms.widgets.TableWrapData; |
| import org.eclipse.ui.part.FileEditorInput; |
| |
| import java.util.TreeSet; |
| |
| /** |
| * Represents an XML attribute to select an existing manifest package, that can be modified using |
| * a simple text field or a dialog to choose an existing package. |
| * <p/> |
| * See {@link UiTextAttributeNode} for more information. |
| */ |
| public class UiManifestPkgAttrNode extends UiTextAttributeNode { |
| |
| /** |
| * Creates a {@link UiManifestPkgAttrNode} object that will display ui to select or create |
| * a manifest package. |
| * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node. |
| */ |
| public UiManifestPkgAttrNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { |
| super(attributeDescriptor, uiParent); |
| } |
| |
| /* (non-java doc) |
| * Creates a label widget and an associated text field. |
| * <p/> |
| * As most other parts of the android manifest editor, this assumes the |
| * parent uses a table layout with 2 columns. |
| */ |
| @Override |
| public void createUiControl(final Composite parent, final IManagedForm managedForm) { |
| setManagedForm(managedForm); |
| FormToolkit toolkit = managedForm.getToolkit(); |
| TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); |
| |
| StringBuilder label = new StringBuilder(); |
| label.append("<form><p><a href='unused'>"); //$NON-NLS-1$ |
| label.append(desc.getUiName()); |
| label.append("</a></p></form>"); //$NON-NLS-1$ |
| FormText formText = SectionHelper.createFormText(parent, toolkit, true /* isHtml */, |
| label.toString(), true /* setupLayoutData */); |
| formText.addHyperlinkListener(new HyperlinkAdapter() { |
| @Override |
| public void linkActivated(HyperlinkEvent e) { |
| super.linkActivated(e); |
| doLabelClick(); |
| } |
| }); |
| formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); |
| SectionHelper.addControlTooltip(formText, desc.getTooltip()); |
| |
| Composite composite = toolkit.createComposite(parent); |
| composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); |
| GridLayout gl = new GridLayout(2, false); |
| gl.marginHeight = gl.marginWidth = 0; |
| composite.setLayout(gl); |
| // Fixes missing text borders under GTK... also requires adding a 1-pixel margin |
| // for the text field below |
| toolkit.paintBordersFor(composite); |
| |
| final Text text = toolkit.createText(composite, getCurrentValue()); |
| GridData gd = new GridData(GridData.FILL_HORIZONTAL); |
| gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK |
| text.setLayoutData(gd); |
| |
| setTextWidget(text); |
| |
| Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH); |
| |
| browseButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| super.widgetSelected(e); |
| doBrowseClick(); |
| } |
| }); |
| |
| } |
| |
| /* (non-java doc) |
| * Adds a validator to the text field that calls managedForm.getMessageManager(). |
| */ |
| @Override |
| protected void onAddValidators(final Text text) { |
| ModifyListener listener = new ModifyListener() { |
| @Override |
| public void modifyText(ModifyEvent e) { |
| String package_name = text.getText(); |
| if (package_name.indexOf('.') < 1) { |
| getManagedForm().getMessageManager().addMessage(text, |
| "Package name should contain at least two identifiers.", |
| null /* data */, IMessageProvider.ERROR, text); |
| } else { |
| getManagedForm().getMessageManager().removeMessage(text, text); |
| } |
| } |
| }; |
| |
| text.addModifyListener(listener); |
| |
| // Make sure the validator removes its message(s) when the widget is disposed |
| text.addDisposeListener(new DisposeListener() { |
| @Override |
| public void widgetDisposed(DisposeEvent e) { |
| getManagedForm().getMessageManager().removeMessage(text, text); |
| } |
| }); |
| |
| // Finally call the validator once to make sure the initial value is processed |
| listener.modifyText(null); |
| } |
| |
| /** |
| * Handles response to the Browse button by creating a Package dialog. |
| * */ |
| private void doBrowseClick() { |
| |
| // Display the list of AndroidManifest packages in a selection dialog |
| ElementListSelectionDialog dialog = new ElementListSelectionDialog( |
| getTextWidget().getShell(), |
| new ILabelProvider() { |
| @Override |
| public Image getImage(Object element) { |
| return null; |
| } |
| |
| @Override |
| public String getText(Object element) { |
| return element.toString(); |
| } |
| |
| @Override |
| public void addListener(ILabelProviderListener listener) { |
| } |
| |
| @Override |
| public void dispose() { |
| } |
| |
| @Override |
| public boolean isLabelProperty(Object element, String property) { |
| return false; |
| } |
| |
| @Override |
| public void removeListener(ILabelProviderListener listener) { |
| } |
| }); |
| |
| dialog.setTitle("Android Manifest Package Selection"); |
| dialog.setMessage("Select the Android Manifest package to target."); |
| |
| dialog.setElements(getPossibleValues(null)); |
| |
| // open the dialog and use the object selected if OK was clicked, or null otherwise |
| if (dialog.open() == Window.OK) { |
| String result = (String) dialog.getFirstResult(); |
| if (result != null && result.length() > 0) { |
| getTextWidget().setText(result); |
| } |
| } |
| } |
| |
| /** |
| * Handles response to the Label hyper link being activated. |
| */ |
| private void doLabelClick() { |
| // get the current package name |
| String package_name = getTextWidget().getText().trim(); |
| |
| if (package_name.length() == 0) { |
| createNewProject(); |
| } else { |
| displayExistingManifest(package_name); |
| } |
| } |
| |
| /** |
| * When the label is clicked and there's already a package name, this method |
| * attempts to find the project matching the android package name and it attempts |
| * to open the manifest editor. |
| * |
| * @param package_name The android package name to find. Must not be null. |
| */ |
| private void displayExistingManifest(String package_name) { |
| |
| // Look for the first project that uses this package name |
| for (IJavaProject project : BaseProjectHelper.getAndroidProjects(null /*filter*/)) { |
| // check that there is indeed a manifest file. |
| IFile manifestFile = ProjectHelper.getManifest(project.getProject()); |
| if (manifestFile == null) { |
| // no file? skip this project. |
| continue; |
| } |
| |
| ManifestData manifestData = AndroidManifestHelper.parseForData(manifestFile); |
| if (manifestData == null) { |
| // skip this project. |
| continue; |
| } |
| |
| if (package_name.equals(manifestData.getPackage())) { |
| // Found the project. |
| |
| IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); |
| if (win != null) { |
| IWorkbenchPage page = win.getActivePage(); |
| if (page != null) { |
| try { |
| page.openEditor( |
| new FileEditorInput(manifestFile), |
| ManifestEditor.ID, |
| true, /* activate */ |
| IWorkbenchPage.MATCH_INPUT); |
| } catch (PartInitException e) { |
| AdtPlugin.log(e, |
| "Opening editor failed for %s", //$NON-NLS-1$ |
| manifestFile.getFullPath()); |
| } |
| } |
| } |
| |
| // We found the project; even if we failed there's no need to keep looking. |
| return; |
| } |
| } |
| } |
| |
| /** |
| * Displays the New Project Wizard to create a new project. |
| * If one is successfully created, use the Android Package name. |
| */ |
| private void createNewProject() { |
| |
| NewProjectAction npwAction = new NewProjectAction(); |
| npwAction.run(null /*action*/); |
| if (npwAction.getDialogResult() == Dialog.OK) { |
| NewProjectWizard npw = (NewProjectWizard) npwAction.getWizard(); |
| String name = npw.getPackageName(); |
| if (name != null && name.length() > 0) { |
| getTextWidget().setText(name); |
| } |
| } |
| } |
| |
| /** |
| * Returns all the possible android package names that could be used. |
| * The prefix is not used. |
| * |
| * {@inheritDoc} |
| */ |
| @Override |
| public String[] getPossibleValues(String prefix) { |
| TreeSet<String> packages = new TreeSet<String>(); |
| |
| for (IJavaProject project : BaseProjectHelper.getAndroidProjects(null /*filter*/)) { |
| // check that there is indeed a manifest file. |
| ManifestData manifestData = AndroidManifestHelper.parseForData(project.getProject()); |
| if (manifestData == null) { |
| // skip this project. |
| continue; |
| } |
| |
| packages.add(manifestData.getPackage()); |
| } |
| |
| return packages.toArray(new String[packages.size()]); |
| } |
| } |
| |