summaryrefslogtreecommitdiff
path: root/src/plugins/android.codeutils/src/com/motorola/studio/android/model/resources/ResourceFile.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/android.codeutils/src/com/motorola/studio/android/model/resources/ResourceFile.java')
-rw-r--r--src/plugins/android.codeutils/src/com/motorola/studio/android/model/resources/ResourceFile.java335
1 files changed, 335 insertions, 0 deletions
diff --git a/src/plugins/android.codeutils/src/com/motorola/studio/android/model/resources/ResourceFile.java b/src/plugins/android.codeutils/src/com/motorola/studio/android/model/resources/ResourceFile.java
new file mode 100644
index 0000000..e459476
--- /dev/null
+++ b/src/plugins/android.codeutils/src/com/motorola/studio/android/model/resources/ResourceFile.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.motorola.studio.android.model.resources;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
+import org.eclipse.jface.text.IDocument;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.motorola.studio.android.codeutils.i18n.CodeUtilsNLS;
+import com.motorola.studio.android.common.exception.AndroidException;
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.model.resources.parser.AbstractResourceFileParser;
+import com.motorola.studio.android.model.resources.types.AbstractResourceNode;
+import com.motorola.studio.android.model.resources.types.AbstractResourceNode.NodeType;
+import com.motorola.studio.android.model.resources.types.AbstractSimpleNameResourceNode;
+import com.motorola.studio.android.model.resources.types.ResourcesNode;
+import com.motorola.studio.android.model.resources.types.UnknownNode;
+
+/**
+ * Class that represents a resource file
+ */
+@SuppressWarnings("deprecation")
+public class ResourceFile extends AbstractResourceFileParser
+{
+ /**
+ * Adds a resource entry to the resources file
+ *
+ * @param node The entry to be added
+ * @return true if the entry has been added or false otherwise
+ */
+ public boolean addResourceEntry(AbstractResourceNode node)
+ {
+ boolean added = false;
+
+ if (!rootNodes.contains(node))
+ {
+ rootNodes.add(node);
+ added = true;
+ }
+
+ return added;
+ }
+
+ /**
+ * Removes a resource entry from the resources file
+ *
+ * @param node the entry to be removed
+ * @return true if the entry has been removed or false otherwise
+ */
+ public boolean removeResourceEntry(AbstractResourceNode node)
+ {
+ boolean removed = false;
+
+ if (rootNodes.contains(node))
+ {
+ rootNodes.remove(node);
+ removed = true;
+ }
+
+ return removed;
+ }
+
+ /**
+ * Retrieves an array containing all root nodes of the resources file.
+ * If the file is well-formed, only the <resources> node must be present
+ * in the array.
+ *
+ * @return an array containing all root nodes of the resources file.
+ */
+ public AbstractResourceNode[] getResourceEntries()
+ {
+ AbstractResourceNode[] nodes = new AbstractResourceNode[rootNodes.size()];
+
+ nodes = rootNodes.toArray(nodes);
+
+ return nodes;
+ }
+
+ /**
+ * Retrieves the <resources> main node
+ *
+ * @return the <resources> main node or null if it does not exist.
+ */
+ public ResourcesNode getResourcesNode()
+ {
+ ResourcesNode resourcesNode = null;
+
+ for (AbstractResourceNode node : rootNodes)
+ {
+ if (node.getNodeType() == NodeType.Resources)
+ {
+ resourcesNode = (ResourcesNode) node;
+ break;
+ }
+ }
+
+ return resourcesNode;
+ }
+
+ /**
+ * Retrieves an IDocument object containing the xml content for the file
+ *
+ * @return an IDocument object containing the xml content for the file
+ */
+ public IDocument getContent() throws AndroidException
+ {
+ IDocument document = null;
+ DocumentBuilder documentBuilder = null;
+
+ try
+ {
+ documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ }
+ catch (ParserConfigurationException e)
+ {
+ StudioLogger.error(ResourceFile.class,
+ CodeUtilsNLS.EXC_ResourceFile_ErrorCreatingTheDocumentBuilder, e);
+ throw new AndroidException(
+ CodeUtilsNLS.EXC_ResourceFile_ErrorCreatingTheDocumentBuilder);
+ }
+
+ Document xmlDocument = documentBuilder.newDocument();
+
+ for (AbstractResourceNode node : rootNodes)
+ {
+ addNode(xmlDocument, null, node);
+ }
+
+ document = new org.eclipse.jface.text.Document(getXmlContent(xmlDocument));
+
+ return document;
+ }
+
+ /**
+ * Recursive function to build a XML file from AbstractResourceNode objects
+ *
+ * @param xmlDocument The XML Document
+ * @param xmlParentNode The XML parent node
+ * @param nodeToAdd The AndroidManifestNode to be added
+ */
+ private void addNode(Document xmlDocument, Node xmlParentNode, AbstractResourceNode nodeToAdd)
+ {
+ Node xmlNode = xmlDocument.createElement(nodeToAdd.getNodeName());
+ String[] attributes = nodeToAdd.getAttributes();
+ String[] unknownAttributes = nodeToAdd.getUnknownAttributes();
+ AbstractResourceNode[] children = nodeToAdd.getChildNodes();
+ AbstractResourceNode[] unknownChildren = nodeToAdd.getUnknownChildNodes();
+
+ // Sets the node value
+ if (nodeToAdd instanceof AbstractSimpleNameResourceNode)
+ {
+ AbstractSimpleNameResourceNode asnrNode = (AbstractSimpleNameResourceNode) nodeToAdd;
+ if (asnrNode.getNodeValue() != null)
+ {
+ xmlNode.appendChild(xmlDocument.createTextNode(asnrNode.getNodeValue()));
+ }
+ }
+ else if (nodeToAdd.getNodeType() == NodeType.Unknown)
+ {
+ UnknownNode unknownNode = (UnknownNode) nodeToAdd;
+
+ if (unknownNode.getNodeValue() != null)
+ {
+ xmlNode.appendChild(xmlDocument.createTextNode(unknownNode.getNodeValue()));
+ }
+ }
+
+ // Adds valid attributes
+ if (attributes.length > 0)
+ {
+ NamedNodeMap xmlAttributes = xmlNode.getAttributes();
+
+ for (String attrName : attributes)
+ {
+ Attr attr = xmlDocument.createAttribute(attrName);
+ attr.setValue(nodeToAdd.getAttributeValue(attrName));
+ xmlAttributes.setNamedItem(attr);
+ }
+ }
+
+ // Adds invalid attributes
+ if (unknownAttributes.length > 0)
+ {
+ NamedNodeMap xmlAttributes = xmlNode.getAttributes();
+
+ for (String attrName : unknownAttributes)
+ {
+ Attr attr = xmlDocument.createAttribute(attrName);
+ attr.setValue(nodeToAdd.getUnknownAttributeValue(attrName));
+ xmlAttributes.setNamedItem(attr);
+ }
+ }
+
+ // Adds known child nodes
+ for (AbstractResourceNode child : children)
+ {
+ addNode(xmlDocument, xmlNode, child);
+ }
+
+ // Adds unknown child nodes
+ for (AbstractResourceNode child : unknownChildren)
+ {
+ addNode(xmlDocument, xmlNode, child);
+ }
+
+ if (xmlParentNode == null)
+ {
+ xmlDocument.appendChild(xmlNode);
+ }
+ else
+ {
+ xmlParentNode.appendChild(xmlNode);
+ }
+ }
+
+ /**
+ * Creates the XML content from a XML Document
+ *
+ * @param xmlDocument The XML Document
+ * @return a String object containing the XML content
+ */
+ private String getXmlContent(Document xmlDocument) throws AndroidException
+ {
+ // Despite Xerces is deprecated, its formatted xml source output works
+ // better than W3C xml output classes
+ OutputFormat outputFormat = new OutputFormat();
+ XMLSerializer xmlSerializer = new XMLSerializer();
+ StringWriter writer = null;
+ String content = null;
+ try
+ {
+ writer = new StringWriter();
+
+ outputFormat.setEncoding("UTF-8");
+ outputFormat.setLineSeparator(System.getProperty("line.separator"));
+ outputFormat.setIndenting(true);
+
+ xmlSerializer.setOutputCharStream(writer);
+ xmlSerializer.setOutputFormat(outputFormat);
+
+ xmlSerializer.serialize(xmlDocument);
+ content = writer.toString();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(ResourceFile.class,
+ CodeUtilsNLS.EXC_ResourceFile_ErrorFormattingTheXMLOutput, e);
+ throw new AndroidException(CodeUtilsNLS.EXC_ResourceFile_ErrorFormattingTheXMLOutput);
+ }
+ finally
+ {
+ if (writer != null)
+ {
+ try
+ {
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger
+ .error("Could not close stream while retrieving resource xml content. "
+ + e.getMessage());
+ }
+ }
+ }
+
+ return content;
+ }
+
+ /**
+ * Returns a new resource name to create a new resource entry. This method grants that you are not
+ * creating a resource with a duplicated name.
+ *
+ * @param baseName The initial resource name
+ * @return The baseName value if a resource with this name does not exist or a new suggested name otherwise
+ */
+ public String getNewResourceName(String baseName)
+ {
+ int count = 0;
+ String newName = baseName;
+ boolean found = true;
+
+ if (getResourcesNode() != null)
+ {
+ while (found)
+ {
+ found = false;
+ for (AbstractResourceNode resNode : getResourcesNode().getChildNodes())
+ {
+ newName = baseName + (count == 0 ? "" : "_" + Integer.toString(count));
+
+ if (resNode instanceof AbstractSimpleNameResourceNode)
+ {
+ AbstractSimpleNameResourceNode validResNode =
+ (AbstractSimpleNameResourceNode) resNode;
+ if (validResNode.getName().equals(newName))
+ {
+ found = true;
+ count++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return newName;
+ }
+
+}