diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/EclipseXmlPrettyPrinter.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/EclipseXmlPrettyPrinter.java | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/EclipseXmlPrettyPrinter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/EclipseXmlPrettyPrinter.java new file mode 100644 index 000000000..d3f7ec866 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/EclipseXmlPrettyPrinter.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.eclipse.adt.internal.editors.formatting; + +import com.android.SdkConstants; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.common.xml.XmlFormatPreferences; +import com.android.ide.common.xml.XmlFormatStyle; +import com.android.ide.common.xml.XmlPrettyPrinter; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; +import com.android.resources.ResourceFolderType; +import com.android.resources.ResourceType; +import com.android.utils.SdkUtils; +import com.android.utils.XmlUtils; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.text.TextUtilities; +import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement; +import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Eclipse customization of the {@link EclipseXmlPrettyPrinter} which takes advantage of the + * Eclipse DOM Api to track additional information, such as whether an element with no children + * was of the open form ({@code <foo></foo>}) or the closed form ({@code <foo/>}), the ability to + * look up the original source (for proper entity handling), the ability to preserve attribute + * source order, etc. + */ +@SuppressWarnings("restriction") // WST XML API +public class EclipseXmlPrettyPrinter extends XmlPrettyPrinter { + + /** + * Creates a new {@link com.android.ide.common.xml.XmlPrettyPrinter} + * + * @param prefs the preferences to format with + * @param style the style to format with + * @param lineSeparator the line separator to use, such as "\n" (can be null, in which case the + * system default is looked up via the line.separator property) + */ + public EclipseXmlPrettyPrinter( + XmlFormatPreferences prefs, + XmlFormatStyle style, + String lineSeparator) { + super(prefs, style, lineSeparator == null ? getDefaultLineSeparator() : lineSeparator); + } + + /** + * Pretty-prints the given XML document, which must be well-formed. If it is not, + * the original unformatted XML document is returned + * + * @param xml the XML content to format + * @param prefs the preferences to format with + * @param style the style to format with + * @param lineSeparator the line separator to use, such as "\n" (can be null, in which + * case the system default is looked up via the line.separator property) + * @return the formatted document (or if a parsing error occurred, returns the + * unformatted document) + */ + @NonNull + public static String prettyPrint( + @NonNull String xml, + @NonNull XmlFormatPreferences prefs, + @NonNull XmlFormatStyle style, + @Nullable String lineSeparator) { + Document document = DomUtilities.parseStructuredDocument(xml); + if (document != null) { + EclipseXmlPrettyPrinter printer = new EclipseXmlPrettyPrinter(prefs, style, + lineSeparator); + if (xml.endsWith("\n")) { //$NON-NLS-1$ + printer.setEndWithNewline(true); + } + + StringBuilder sb = new StringBuilder(3 * xml.length() / 2); + printer.prettyPrint(-1, document, null, null, sb, false /*openTagOnly*/); + return sb.toString(); + } else { + // Parser error: just return the unformatted content + return xml; + } + } + + @NonNull + public static String prettyPrint(@NonNull Node node, boolean endWithNewline) { + return prettyPrint(node, EclipseXmlFormatPreferences.create(), XmlFormatStyle.get(node), + null, endWithNewline); + } + + private static String getDefaultLineSeparator() { + org.eclipse.jface.text.Document blank = new org.eclipse.jface.text.Document(); + String lineSeparator = TextUtilities.getDefaultLineDelimiter(blank); + if (lineSeparator == null) { + lineSeparator = SdkUtils.getLineSeparator(); + } + + return lineSeparator; + } + + /** + * Pretty prints the given node + * + * @param node the node, usually a document, to be printed + * @param prefs the formatting preferences + * @param style the formatting style to use + * @param lineSeparator the line separator to use, or null to use the + * default + * @return a formatted string + */ + @NonNull + public static String prettyPrint( + @NonNull Node node, + @NonNull XmlFormatPreferences prefs, + @NonNull XmlFormatStyle style, + @Nullable String lineSeparator, + boolean endWithNewline) { + XmlPrettyPrinter printer = new EclipseXmlPrettyPrinter(prefs, style, lineSeparator); + printer.setEndWithNewline(endWithNewline); + StringBuilder sb = new StringBuilder(1000); + printer.prettyPrint(-1, node, null, null, sb, false /*openTagOnly*/); + String xml = sb.toString(); + if (node.getNodeType() == Node.DOCUMENT_NODE && !xml.startsWith("<?")) { //$NON-NLS-1$ + xml = XmlUtils.XML_PROLOG + xml; + } + return xml; + } + + @Nullable + @Override + protected String getSource(@NonNull Node node) { + // In Eclipse, org.w3c.dom.DocumentType.getTextContent() returns null + if (node instanceof IDOMNode) { + // Get the original source string. This will contain the actual entities + // such as ">" instead of ">" which it gets turned into for the DOM nodes. + // By operating on source we can preserve the user's entities rather than + // having > for example always turned into >. + IDOMNode textImpl = (IDOMNode) node; + return textImpl.getSource(); + } + + return super.getSource(node); + } + + @Override + protected boolean isEmptyTag(Element element) { + if (element instanceof IDOMElement) { + IDOMElement elementImpl = (IDOMElement) element; + if (elementImpl.isEmptyTag()) { + return true; + } + } + + return false; + } + + /** + * Returns the {@link XmlFormatStyle} to use for a resource of the given type + * + * @param resourceType the type of resource to be formatted + * @return the suitable format style to use + */ + public static XmlFormatStyle get(ResourceType resourceType) { + switch (resourceType) { + case ARRAY: + case ATTR: + case BOOL: + case DECLARE_STYLEABLE: + case DIMEN: + case FRACTION: + case ID: + case INTEGER: + case STRING: + case PLURALS: + case STYLE: + case STYLEABLE: + case COLOR: + return XmlFormatStyle.RESOURCE; + + case LAYOUT: + return XmlFormatStyle.LAYOUT; + + case DRAWABLE: + case MENU: + case ANIM: + case ANIMATOR: + case INTERPOLATOR: + default: + return XmlFormatStyle.FILE; + } + } + + /** + * Returns the {@link XmlFormatStyle} to use for resource files in the given resource + * folder + * + * @param folderType the type of folder containing the resource file + * @return the suitable format style to use + */ + public static XmlFormatStyle getForFolderType(ResourceFolderType folderType) { + switch (folderType) { + case LAYOUT: + return XmlFormatStyle.LAYOUT; + case COLOR: + case VALUES: + return XmlFormatStyle.RESOURCE; + case ANIM: + case ANIMATOR: + case DRAWABLE: + case INTERPOLATOR: + case MENU: + default: + return XmlFormatStyle.FILE; + } + } + + /** + * Returns the {@link XmlFormatStyle} to use for resource files of the given path. + * + * @param path the path to the resource file + * @return the suitable format style to use + */ + public static XmlFormatStyle getForFile(IPath path) { + if (SdkConstants.FN_ANDROID_MANIFEST_XML.equals(path.lastSegment())) { + return XmlFormatStyle.MANIFEST; + } + + if (path.segmentCount() > 2) { + String parentName = path.segment(path.segmentCount() - 2); + ResourceFolderType folderType = ResourceFolderType.getFolderType(parentName); + return getForFolderType(folderType); + } + + return XmlFormatStyle.FILE; + } +} |