Home | History | Annotate | Download | only in menu
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      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
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     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.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.editors.menu;
     18 
     19 import com.android.annotations.NonNull;
     20 import com.android.annotations.Nullable;
     21 import com.android.ide.eclipse.adt.AdtConstants;
     22 import com.android.ide.eclipse.adt.AdtPlugin;
     23 import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate;
     24 import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
     25 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
     26 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor.Mandatory;
     27 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
     28 import com.android.resources.ResourceFolderType;
     29 import com.android.xml.AndroidXPathFactory;
     30 
     31 import org.eclipse.ui.PartInitException;
     32 import org.w3c.dom.Document;
     33 import org.w3c.dom.Node;
     34 
     35 import javax.xml.xpath.XPath;
     36 import javax.xml.xpath.XPathConstants;
     37 import javax.xml.xpath.XPathExpressionException;
     38 
     39 /**
     40  * Multi-page form editor for /res/menu XML files.
     41  */
     42 public class MenuEditorDelegate extends CommonXmlDelegate {
     43 
     44     public static class Creator implements IDelegateCreator {
     45         @Override
     46         @SuppressWarnings("unchecked")
     47         public MenuEditorDelegate createForFile(
     48                 @NonNull CommonXmlEditor delegator,
     49                 @Nullable ResourceFolderType type) {
     50             if (ResourceFolderType.MENU == type) {
     51                 return new MenuEditorDelegate(delegator);
     52             }
     53 
     54             return null;
     55         }
     56     }
     57 
     58     /**
     59      * Old standalone-editor ID.
     60      * Use {@link CommonXmlEditor#ID} instead.
     61      */
     62     public static final String LEGACY_EDITOR_ID =
     63         AdtConstants.EDITORS_NAMESPACE + ".menu.MenuEditor"; //$NON-NLS-1$
     64 
     65     /**
     66      * Creates the form editor for resources XML files.
     67      */
     68     private MenuEditorDelegate(CommonXmlEditor editor) {
     69         super(editor, new MenuContentAssist());
     70         editor.addDefaultTargetListener();
     71     }
     72 
     73     /**
     74      * Create the various form pages.
     75      */
     76     @Override
     77     public void delegateCreateFormPages() {
     78         try {
     79             getEditor().addPage(new MenuTreePage(getEditor()));
     80         } catch (PartInitException e) {
     81             AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$
     82         }
     83 
     84      }
     85 
     86     private boolean mUpdatingModel;
     87 
     88     /**
     89      * Processes the new XML Model, which XML root node is given.
     90      *
     91      * @param xml_doc The XML document, if available, or null if none exists.
     92      */
     93     @Override
     94     public void delegateXmlModelChanged(Document xml_doc) {
     95         if (mUpdatingModel) {
     96             return;
     97         }
     98 
     99         try {
    100             mUpdatingModel = true;
    101 
    102             // init the ui root on demand
    103             delegateInitUiRootNode(false /*force*/);
    104 
    105             getUiRootNode().setXmlDocument(xml_doc);
    106             if (xml_doc != null) {
    107                 ElementDescriptor root_desc = getUiRootNode().getDescriptor();
    108                 try {
    109                     XPath xpath = AndroidXPathFactory.newXPath();
    110                     Node node = (Node) xpath.evaluate("/" + root_desc.getXmlName(),  //$NON-NLS-1$
    111                             xml_doc,
    112                             XPathConstants.NODE);
    113                     if (node == null && root_desc.getMandatory() != Mandatory.NOT_MANDATORY) {
    114                         // Create the root element if it doesn't exist yet (for empty new documents)
    115                         node = getUiRootNode().createXmlNode();
    116                     }
    117 
    118                     // Refresh the manifest UI node and all its descendants
    119                     getUiRootNode().loadFromXmlNode(node);
    120 
    121                     // TODO ? startMonitoringMarkers();
    122                 } catch (XPathExpressionException e) {
    123                     AdtPlugin.log(e, "XPath error when trying to find '%s' element in XML.", //$NON-NLS-1$
    124                             root_desc.getXmlName());
    125                 }
    126             }
    127 
    128         } finally {
    129             mUpdatingModel = false;
    130         }
    131     }
    132 
    133     /**
    134      * Creates the initial UI Root Node, including the known mandatory elements.
    135      * @param force if true, a new UiRootNode is recreated even if it already exists.
    136      */
    137     @Override
    138     public void delegateInitUiRootNode(boolean force) {
    139         // The root UI node is always created, even if there's no corresponding XML node.
    140         if (getUiRootNode() == null || force) {
    141             Document doc = null;
    142             if (getUiRootNode() != null) {
    143                 doc = getUiRootNode().getXmlDocument();
    144             }
    145 
    146             // get the target data from the opened file (and its project)
    147             AndroidTargetData data = getEditor().getTargetData();
    148 
    149             ElementDescriptor desc;
    150             if (data == null) {
    151                 desc = new ElementDescriptor("temp", null /*children*/);
    152             } else {
    153                 desc = data.getMenuDescriptors().getDescriptor();
    154             }
    155 
    156             setUiRootNode(desc.createUiNode());
    157             getUiRootNode().setEditor(getEditor());
    158 
    159             onDescriptorsChanged(doc);
    160         }
    161     }
    162 
    163     // ---- Local Methods ----
    164 
    165     /**
    166      * Reloads the UI manifest node from the XML, and calls the pages to update.
    167      */
    168     private void onDescriptorsChanged(Document document) {
    169         if (document != null) {
    170             getUiRootNode().loadFromXmlNode(document);
    171         } else {
    172             getUiRootNode().reloadFromXmlNode(getUiRootNode().getXmlNode());
    173         }
    174     }
    175 }
    176