AI 146554: am: CL 146249 am: CL 146237 ADT #1789339: Manifest editor now displays all extra sub-elements.

Bug description is to add support for <uses-configuration>.
  Currently the Manifest editor already supports <uses-sdk> (which is an
  element node, not an attribute) by exposing it as a manifest attribute.
  That doesn't scale. So instead just provide a tree for all <manifest>
  child elements that are not handled in other pages. Currently that
  contains uses-sdk and uses-configuration but the nice part of it is that
  it will pick up automatically any new manfiest sub elements in the future.
  Original author: raphael
  Merged from: //branches/cupcake/...
  Original author: android-build

Automated import of CL 146554
This commit is contained in:
Raphael Moll
2009-04-18 16:05:38 -07:00
committed by The Android Open Source Project
parent 5540de28e2
commit aa4c92d8e7
2 changed files with 79 additions and 147 deletions

View File

@@ -20,17 +20,16 @@ import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.editors.manifest.ManifestEditor; import com.android.ide.eclipse.editors.manifest.ManifestEditor;
import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors;
import com.android.ide.eclipse.editors.ui.UiElementPart; import com.android.ide.eclipse.editors.ui.UiElementPart;
import com.android.ide.eclipse.editors.uimodel.UiAttributeNode;
import com.android.ide.eclipse.editors.uimodel.UiElementNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.forms.widgets.Section;
import org.w3c.dom.Node;
/** /**
* Generic info section part for overview page * Generic info section part for overview page: it displays all the attributes from
* the manifest element.
*/ */
final class OverviewInfoPart extends UiElementPart { final class OverviewInfoPart extends UiElementPart {
@@ -38,8 +37,8 @@ final class OverviewInfoPart extends UiElementPart {
public OverviewInfoPart(Composite body, FormToolkit toolkit, ManifestEditor editor) { public OverviewInfoPart(Composite body, FormToolkit toolkit, ManifestEditor editor) {
super(body, toolkit, editor, super(body, toolkit, editor,
null, // uiElementNode getManifestUiNode(editor), // uiElementNode
"General Information", // section title "Manifest General Attributes", // section title
"Defines general information about the AndroidManifest.xml", // section description "Defines general information about the AndroidManifest.xml", // section description
Section.TWISTIE | Section.EXPANDED); Section.TWISTIE | Section.EXPANDED);
} }
@@ -64,22 +63,6 @@ final class OverviewInfoPart extends UiElementPart {
return editor.getUiRootNode(); return editor.getUiRootNode();
} }
/**
* Retrieves the uses-sdk UI node. Since this is a mandatory node, it *always*
* exists, even if there is no matching XML node.
*/
private UiElementNode getUsesSdkUiNode(ManifestEditor editor) {
AndroidManifestDescriptors manifestDescriptors = editor.getManifestDescriptors();
if (manifestDescriptors != null) {
ElementDescriptor desc = manifestDescriptors.getUsesSdkElement();
return editor.getUiRootNode().findUiChildNode(desc.getXmlName());
}
// No manifest descriptor: we have a dummy UiRootNode, so we return that.
// The editor will be reloaded once we have the proper descriptors anyway.
return editor.getUiRootNode();
}
/** /**
* Overridden in order to capture the current managed form. * Overridden in order to capture the current managed form.
* *
@@ -98,125 +81,7 @@ final class OverviewInfoPart extends UiElementPart {
* SDK has changed. * SDK has changed.
*/ */
public void onSdkChanged() { public void onSdkChanged() {
setUiElementNode(getManifestUiNode(getEditor()));
createUiAttributes(mManagedForm); createUiAttributes(mManagedForm);
} }
/**
* Overridden to add the description and the ui attributes of both the
* manifest and uses-sdk UI nodes.
* <p/>
* {@inheritDoc}
*/
@Override
protected void fillTable(Composite table, IManagedForm managedForm) {
int n = 0;
UiElementNode uiNode = getManifestUiNode(getEditor());
n += insertUiAttributes(uiNode, table, managedForm);
uiNode = getUsesSdkUiNode(getEditor());
n += insertUiAttributes(uiNode, table, managedForm);
if (n == 0) {
createLabel(table, managedForm.getToolkit(),
"No attributes to display, waiting for SDK to finish loading...",
null /* tooltip */ );
}
layoutChanged();
}
/**
* Overridden to tests whether either the manifest or uses-sdk nodes parts are dirty.
* <p/>
* {@inheritDoc}
*
* @return <code>true</code> if the part is dirty, <code>false</code>
* otherwise.
*/
@Override
public boolean isDirty() {
boolean dirty = super.isDirty();
if (!dirty) {
UiElementNode uiNode = getManifestUiNode(getEditor());
if (uiNode != null) {
for (UiAttributeNode ui_attr : uiNode.getUiAttributes()) {
if (ui_attr.isDirty()) {
markDirty();
dirty = true;
break;
}
}
}
}
if (!dirty) {
UiElementNode uiNode = getUsesSdkUiNode(getEditor());
if (uiNode != null) {
for (UiAttributeNode ui_attr : uiNode.getUiAttributes()) {
if (ui_attr.isDirty()) {
markDirty();
dirty = true;
break;
}
}
}
}
return dirty;
}
/**
* Overridden to save both the manifest or uses-sdk nodes.
* <p/>
* {@inheritDoc}
*/
@Override
public void commit(boolean onSave) {
final UiElementNode manifestUiNode = getManifestUiNode(getEditor());
final UiElementNode usesSdkUiNode = getUsesSdkUiNode(getEditor());
getEditor().editXmlModel(new Runnable() {
public void run() {
if (manifestUiNode != null && manifestUiNode.isDirty()) {
for (UiAttributeNode ui_attr : manifestUiNode.getUiAttributes()) {
ui_attr.commit();
}
}
if (usesSdkUiNode != null && usesSdkUiNode.isDirty()) {
for (UiAttributeNode ui_attr : usesSdkUiNode.getUiAttributes()) {
ui_attr.commit();
}
if (!usesSdkUiNode.isDirty()) {
// Remove the <uses-sdk> XML element if it is empty.
// Rather than rely on the internal UI state, actually check that the
// XML element has no attributes and no child element so that we don't
// trash some user-generated content.
Node element = usesSdkUiNode.prepareCommit();
if (element != null &&
!element.hasAttributes() &&
!element.hasChildNodes()) {
// Important note: we MUST NOT use usesSdkUiNode.deleteXmlNode()
// here, as it would clear the UiAttribute list and thus break the
// link between the controls and the ui attribute field.
// Instead what we want is simply to remove the XML node and let the
// UiElementNode node know.
Node parent = element.getParentNode();
if (parent != null) {
parent.removeChild(element);
usesSdkUiNode.loadFromXmlNode(null /*xml_node*/);
}
}
}
}
}
});
// We need to call super's commit after we synchronized the nodes to make sure we
// reset the dirty flag after all the side effects from committing have occurred.
super.commit(onSave);
}
} }

View File

@@ -17,15 +17,23 @@
package com.android.ide.eclipse.editors.manifest.pages; package com.android.ide.eclipse.editors.manifest.pages;
import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.editors.manifest.ManifestEditor; import com.android.ide.eclipse.editors.manifest.ManifestEditor;
import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors;
import com.android.ide.eclipse.editors.ui.tree.UiTreeBlock;
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.editor.FormPage;
import org.eclipse.ui.forms.widgets.ColumnLayout;
import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.ScrolledForm;
import java.util.ArrayList;
import java.util.HashSet;
/** /**
* Page for overview settings, part of the AndroidManifest form editor. * Page for overview settings, part of the AndroidManifest form editor.
@@ -45,9 +53,11 @@ public final class OverviewPage extends FormPage {
private OverviewInfoPart mOverviewPart; private OverviewInfoPart mOverviewPart;
/** Overview link part */ /** Overview link part */
private OverviewLinksPart mOverviewLinkPart; private OverviewLinksPart mOverviewLinkPart;
private UiTreeBlock mTreeBlock;
public OverviewPage(ManifestEditor editor) { public OverviewPage(ManifestEditor editor) {
super(editor, PAGE_ID, "Overview"); // tab's label, user visible, keep it short super(editor, PAGE_ID, "Manifest"); // tab's label, user visible, keep it short
mEditor = editor; mEditor = editor;
} }
@@ -60,21 +70,40 @@ public final class OverviewPage extends FormPage {
protected void createFormContent(IManagedForm managedForm) { protected void createFormContent(IManagedForm managedForm) {
super.createFormContent(managedForm); super.createFormContent(managedForm);
ScrolledForm form = managedForm.getForm(); ScrolledForm form = managedForm.getForm();
form.setText("Android Manifest Overview"); form.setText("Android Manifest");
form.setImage(AdtPlugin.getAndroidLogo()); form.setImage(AdtPlugin.getAndroidLogo());
Composite body = form.getBody(); Composite body = form.getBody();
FormToolkit toolkit = managedForm.getToolkit(); FormToolkit toolkit = managedForm.getToolkit();
ColumnLayout cl = new ColumnLayout();
cl.minNumColumns = cl.maxNumColumns = 1; // Usually we would set a ColumnLayout on body here. However the presence of the
body.setLayout(cl); // UiTreeBlock forces a GridLayout with one column so we comply with it.
mOverviewPart = new OverviewInfoPart(body, toolkit, mEditor); mOverviewPart = new OverviewInfoPart(body, toolkit, mEditor);
mOverviewPart.getSection().setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
managedForm.addPart(mOverviewPart); managedForm.addPart(mOverviewPart);
managedForm.addPart(new OverviewExportPart(this, body, toolkit, mEditor));
newManifestExtrasPart(managedForm);
OverviewExportPart exportPart = new OverviewExportPart(this, body, toolkit, mEditor);
exportPart.getSection().setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
managedForm.addPart(exportPart);
mOverviewLinkPart = new OverviewLinksPart(body, toolkit, mEditor); mOverviewLinkPart = new OverviewLinksPart(body, toolkit, mEditor);
mOverviewLinkPart.getSection().setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
managedForm.addPart(mOverviewLinkPart); managedForm.addPart(mOverviewLinkPart);
} }
private void newManifestExtrasPart(IManagedForm managedForm) {
UiElementNode manifest = mEditor.getUiRootNode();
mTreeBlock = new UiTreeBlock(mEditor, manifest,
true /* autoCreateRoot */,
computeManifestExtraFilters(),
"Manifest Extras",
"Extra manifest elements");
mTreeBlock.createContent(managedForm);
}
/** /**
* Changes and refreshes the Application UI node handle by the sub parts. * Changes and refreshes the Application UI node handle by the sub parts.
*/ */
@@ -86,5 +115,43 @@ public final class OverviewPage extends FormPage {
if (mOverviewLinkPart != null) { if (mOverviewLinkPart != null) {
mOverviewLinkPart.onSdkChanged(); mOverviewLinkPart.onSdkChanged();
} }
if (mTreeBlock != null) {
UiElementNode manifest = mEditor.getUiRootNode();
mTreeBlock.changeRootAndDescriptors(manifest,
computeManifestExtraFilters(),
true /* refresh */);
}
}
private ElementDescriptor[] computeManifestExtraFilters() {
UiElementNode manifest = mEditor.getUiRootNode();
AndroidManifestDescriptors manifestDescriptor = mEditor.getManifestDescriptors();
if (manifestDescriptor == null) {
return null;
}
// get the elements we want to exclude
HashSet<ElementDescriptor> excludes = new HashSet<ElementDescriptor>();
excludes.add(manifestDescriptor.getApplicationElement());
excludes.add(manifestDescriptor.getInstrumentationElement());
excludes.add(manifestDescriptor.getPermissionElement());
excludes.add(manifestDescriptor.getPermissionGroupElement());
excludes.add(manifestDescriptor.getPermissionTreeElement());
excludes.add(manifestDescriptor.getUsesPermissionElement());
// walk through the known children of the manifest descriptor and keep what's not excluded
ArrayList<ElementDescriptor> descriptorFilters = new ArrayList<ElementDescriptor>();
for (ElementDescriptor child : manifest.getDescriptor().getChildren()) {
if (!excludes.contains(child)) {
descriptorFilters.add(child);
}
}
if (descriptorFilters.size() == 0) {
return null;
}
return descriptorFilters.toArray(new ElementDescriptor[descriptorFilters.size()]);
} }
} }