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