blob: 60d9125f688093b757bbf842fc376275f51f9639 [file] [log] [blame]
/*
* 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()]);
}
}