OSDN Git Service

AI 146237: ADT #1789339: Manifest editor now displays all extra sub-elements.
authorRaphael Moll <>
Tue, 14 Apr 2009 23:13:37 +0000 (16:13 -0700)
committerThe Android Open Source Project <initial-contribution@android.com>
Tue, 14 Apr 2009 23:13:37 +0000 (16:13 -0700)
  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.
  BUG=1789339

Automated import of CL 146237

eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewInfoPart.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewPage.java

index 026b760..cab7f73 100644 (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.descriptors.AndroidManifestDescriptors;
 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 org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.forms.IManagedForm;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 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 {
 
@@ -38,8 +37,8 @@ final class OverviewInfoPart extends UiElementPart {
 
     public OverviewInfoPart(Composite body, FormToolkit toolkit, ManifestEditor editor) {
         super(body, toolkit, editor,
-                null,  // uiElementNode
-                "General Information", // section title
+                getManifestUiNode(editor),  // uiElementNode
+                "Manifest General Attributes", // section title
                 "Defines general information about the AndroidManifest.xml", // section description
                 Section.TWISTIE | Section.EXPANDED);
     }
@@ -65,22 +64,6 @@ final class OverviewInfoPart extends UiElementPart {
     }
 
     /**
-     * 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.
      * 
      * {@inheritDoc}
@@ -98,125 +81,7 @@ final class OverviewInfoPart extends UiElementPart {
      * SDK has changed.
      */
     public void onSdkChanged() {
+        setUiElementNode(getManifestUiNode(getEditor()));
         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);
-    }
 }
index 62954bd..a06cc74 100644 (file)
 package com.android.ide.eclipse.editors.manifest.pages;
 
 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.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.ui.forms.IManagedForm;
 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.ScrolledForm;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+
 
 /**
  * Page for overview settings, part of the AndroidManifest form editor.
@@ -45,9 +53,11 @@ public final class OverviewPage extends FormPage {
     private OverviewInfoPart mOverviewPart;
     /** Overview link part */
     private OverviewLinksPart mOverviewLinkPart;
+
+    private UiTreeBlock mTreeBlock;
     
     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;
     }
 
@@ -60,21 +70,40 @@ public final class OverviewPage extends FormPage {
     protected void createFormContent(IManagedForm managedForm) {
         super.createFormContent(managedForm);
         ScrolledForm form = managedForm.getForm();
-        form.setText("Android Manifest Overview");
+        form.setText("Android Manifest");
         form.setImage(AdtPlugin.getAndroidLogo());
         
         Composite body = form.getBody();
         FormToolkit toolkit = managedForm.getToolkit();
-        ColumnLayout cl = new ColumnLayout();
-        cl.minNumColumns = cl.maxNumColumns = 1;
-        body.setLayout(cl);
+        
+        // Usually we would set a ColumnLayout on body here. However the presence of the
+        // UiTreeBlock forces a GridLayout with one column so we comply with it.
+
         mOverviewPart = new OverviewInfoPart(body, toolkit, mEditor);
+        mOverviewPart.getSection().setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
         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.getSection().setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
         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.
      */
@@ -86,5 +115,43 @@ public final class OverviewPage extends FormPage {
         if (mOverviewLinkPart != null) {
             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()]);
     }
 }