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.xml; 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.AndroidEditor; 22 import com.android.ide.eclipse.adt.internal.editors.FirstElementParser; 23 import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor; 24 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; 25 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode; 26 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; 27 import com.android.ide.eclipse.adt.internal.sdk.Sdk; 28 import com.android.sdklib.IAndroidTarget; 29 import com.android.sdklib.SdkConstants; 30 31 import org.eclipse.core.resources.IFile; 32 import org.eclipse.core.resources.IProject; 33 import org.eclipse.ui.IEditorInput; 34 import org.eclipse.ui.IEditorPart; 35 import org.eclipse.ui.PartInitException; 36 import org.eclipse.ui.part.FileEditorInput; 37 import org.w3c.dom.Document; 38 39 /** 40 * Multi-page form editor for /res/xml XML files. 41 */ 42 public class XmlEditor extends AndroidEditor { 43 44 public static final String ID = AndroidConstants.EDITORS_NAMESPACE + ".xml.XmlEditor"; //$NON-NLS-1$ 45 46 /** Root node of the UI element hierarchy */ 47 private UiDocumentNode mUiRootNode; 48 49 /** 50 * Creates the form editor for resources XML files. 51 */ XmlEditor()52 public XmlEditor() { 53 super(); 54 } 55 56 /** 57 * Returns the root node of the UI element hierarchy, which here 58 * is the document node. 59 */ 60 @Override getUiRootNode()61 public UiDocumentNode getUiRootNode() { 62 return mUiRootNode; 63 } 64 65 // ---- Static ---- 66 67 /** 68 * Indicates if this is a file that this {@link XmlEditor} can handle. 69 * <p/> 70 * The {@link XmlEditor} can handle XML files that have a <searchable> or 71 * <Preferences> root XML element with the adequate xmlns:android attribute. 72 * 73 * @return True if the {@link XmlEditor} can handle that file. 74 */ canHandleFile(IFile file)75 public static boolean canHandleFile(IFile file) { 76 // we need the target of the file's project to access the descriptors. 77 IProject project = file.getProject(); 78 IAndroidTarget target = Sdk.getCurrent().getTarget(project); 79 if (target != null) { 80 // Note: the target data can be null when an SDK is not finished loading yet. 81 // We can potentially arrive here when Eclipse is started with a file previously 82 // open and the resource gets refreshed -- at that point we may not have the SDK yet. 83 AndroidTargetData data = Sdk.getCurrent().getTargetData(target); 84 85 FirstElementParser.Result result = FirstElementParser.parse( 86 file.getLocation().toOSString(), 87 SdkConstants.NS_RESOURCES); 88 89 if (result != null && data != null) { 90 String name = result.getElement(); 91 if (name != null && result.getXmlnsPrefix() != null) { 92 DocumentDescriptor desc = data.getXmlDescriptors().getDescriptor(); 93 for (ElementDescriptor elem : desc.getChildren()) { 94 if (elem.getXmlName().equals(name)) { 95 // This is an element that this document can handle 96 return true; 97 } 98 } 99 } 100 } 101 } 102 103 return false; 104 } 105 106 // ---- Base Class Overrides ---- 107 108 /** 109 * Returns whether the "save as" operation is supported by this editor. 110 * <p/> 111 * Save-As is a valid operation for the ManifestEditor since it acts on a 112 * single source file. 113 * 114 * @see IEditorPart 115 */ 116 @Override isSaveAsAllowed()117 public boolean isSaveAsAllowed() { 118 return true; 119 } 120 121 /** 122 * Create the various form pages. 123 */ 124 @Override createFormPages()125 protected void createFormPages() { 126 try { 127 addPage(new XmlTreePage(this)); 128 } catch (PartInitException e) { 129 AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$ 130 } 131 132 } 133 134 /* (non-java doc) 135 * Change the tab/title name to include the project name. 136 */ 137 @Override setInput(IEditorInput input)138 protected void setInput(IEditorInput input) { 139 super.setInput(input); 140 if (input instanceof FileEditorInput) { 141 FileEditorInput fileInput = (FileEditorInput) input; 142 IFile file = fileInput.getFile(); 143 setPartName(String.format("%1$s", file.getName())); 144 } 145 } 146 147 /** 148 * Processes the new XML Model, which XML root node is given. 149 * 150 * @param xml_doc The XML document, if available, or null if none exists. 151 */ 152 @Override xmlModelChanged(Document xml_doc)153 protected void xmlModelChanged(Document xml_doc) { 154 // init the ui root on demand 155 initUiRootNode(false /*force*/); 156 157 mUiRootNode.loadFromXmlNode(xml_doc); 158 159 super.xmlModelChanged(xml_doc); 160 } 161 162 /** 163 * Creates the initial UI Root Node, including the known mandatory elements. 164 * @param force if true, a new UiRootNode is recreated even if it already exists. 165 */ 166 @Override initUiRootNode(boolean force)167 protected void initUiRootNode(boolean force) { 168 // The root UI node is always created, even if there's no corresponding XML node. 169 if (mUiRootNode == null || force) { 170 Document doc = null; 171 if (mUiRootNode != null) { 172 doc = mUiRootNode.getXmlDocument(); 173 } 174 175 // get the target data from the opened file (and its project) 176 AndroidTargetData data = getTargetData(); 177 178 DocumentDescriptor desc; 179 if (data == null) { 180 desc = new DocumentDescriptor("temp", null /*children*/); 181 } else { 182 desc = data.getXmlDescriptors().getDescriptor(); 183 } 184 185 mUiRootNode = (UiDocumentNode) desc.createUiNode(); 186 mUiRootNode.setEditor(this); 187 188 onDescriptorsChanged(doc); 189 } 190 } 191 192 // ---- Local Methods ---- 193 194 /** 195 * Reloads the UI manifest node from the XML, and calls the pages to update. 196 */ onDescriptorsChanged(Document document)197 private void onDescriptorsChanged(Document document) { 198 if (document != null) { 199 mUiRootNode.loadFromXmlNode(document); 200 } else { 201 mUiRootNode.reloadFromXmlNode(mUiRootNode.getXmlNode()); 202 } 203 } 204 205 } 206