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