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.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.AndroidConstants; 21 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; 22 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; 23 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; 24 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; 25 import com.android.sdklib.xml.AndroidXPathFactory; 26 27 import org.eclipse.core.resources.IFile; 28 import org.eclipse.ui.IEditorInput; 29 import org.eclipse.ui.IEditorPart; 30 import org.eclipse.ui.PartInitException; 31 import org.eclipse.ui.part.FileEditorInput; 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 MenuEditor extends AndroidXmlEditor { 43 44 public static final String ID = AndroidConstants.EDITORS_NAMESPACE + ".menu.MenuEditor"; //$NON-NLS-1$ 45 46 /** Root node of the UI element hierarchy */ 47 private UiElementNode mUiRootNode; 48 49 /** 50 * Creates the form editor for resources XML files. 51 */ 52 public MenuEditor() { 53 super(); 54 } 55 56 /** 57 * Returns the root node of the UI element hierarchy, which here is 58 * the "menu" node. 59 */ 60 @Override 61 public UiElementNode getUiRootNode() { 62 return mUiRootNode; 63 } 64 65 // ---- Base Class Overrides ---- 66 67 /** 68 * Returns whether the "save as" operation is supported by this editor. 69 * <p/> 70 * Save-As is a valid operation for the ManifestEditor since it acts on a 71 * single source file. 72 * 73 * @see IEditorPart 74 */ 75 @Override 76 public boolean isSaveAsAllowed() { 77 return true; 78 } 79 80 /** 81 * Create the various form pages. 82 */ 83 @Override 84 protected void createFormPages() { 85 try { 86 addPage(new MenuTreePage(this)); 87 } catch (PartInitException e) { 88 AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$ 89 } 90 91 } 92 93 /* (non-java doc) 94 * Change the tab/title name to include the project name. 95 */ 96 @Override 97 protected void setInput(IEditorInput input) { 98 super.setInput(input); 99 if (input instanceof FileEditorInput) { 100 FileEditorInput fileInput = (FileEditorInput) input; 101 IFile file = fileInput.getFile(); 102 setPartName(String.format("%1$s", file.getName())); 103 } 104 } 105 106 /** 107 * Processes the new XML Model, which XML root node is given. 108 * 109 * @param xml_doc The XML document, if available, or null if none exists. 110 */ 111 @Override 112 protected void xmlModelChanged(Document xml_doc) { 113 // init the ui root on demand 114 initUiRootNode(false /*force*/); 115 116 mUiRootNode.setXmlDocument(xml_doc); 117 if (xml_doc != null) { 118 ElementDescriptor root_desc = mUiRootNode.getDescriptor(); 119 try { 120 XPath xpath = AndroidXPathFactory.newXPath(); 121 Node node = (Node) xpath.evaluate("/" + root_desc.getXmlName(), //$NON-NLS-1$ 122 xml_doc, 123 XPathConstants.NODE); 124 if (node == null && root_desc.isMandatory()) { 125 // Create the root element if it doesn't exist yet (for empty new documents) 126 node = mUiRootNode.createXmlNode(); 127 } 128 129 // Refresh the manifest UI node and all its descendants 130 mUiRootNode.loadFromXmlNode(node); 131 132 // TODO ? startMonitoringMarkers(); 133 } catch (XPathExpressionException e) { 134 AdtPlugin.log(e, "XPath error when trying to find '%s' element in XML.", //$NON-NLS-1$ 135 root_desc.getXmlName()); 136 } 137 } 138 139 super.xmlModelChanged(xml_doc); 140 } 141 142 /** 143 * Creates the initial UI Root Node, including the known mandatory elements. 144 * @param force if true, a new UiRootNode is recreated even if it already exists. 145 */ 146 @Override 147 protected void initUiRootNode(boolean force) { 148 // The root UI node is always created, even if there's no corresponding XML node. 149 if (mUiRootNode == null || force) { 150 Document doc = null; 151 if (mUiRootNode != null) { 152 doc = mUiRootNode.getXmlDocument(); 153 } 154 155 // get the target data from the opened file (and its project) 156 AndroidTargetData data = getTargetData(); 157 158 ElementDescriptor desc; 159 if (data == null) { 160 desc = new ElementDescriptor("temp", null /*children*/); 161 } else { 162 desc = data.getMenuDescriptors().getDescriptor(); 163 } 164 165 mUiRootNode = desc.createUiNode(); 166 mUiRootNode.setEditor(this); 167 168 onDescriptorsChanged(doc); 169 } 170 } 171 172 // ---- Local Methods ---- 173 174 /** 175 * Reloads the UI manifest node from the XML, and calls the pages to update. 176 */ 177 private void onDescriptorsChanged(Document document) { 178 if (document != null) { 179 mUiRootNode.loadFromXmlNode(document); 180 } else { 181 mUiRootNode.reloadFromXmlNode(mUiRootNode.getXmlNode()); 182 } 183 } 184 } 185