blob: a70086d8063727a8dbf3eb1e237a4d7342bed866 [file] [log] [blame]
/*
* Copyright (C) 2009 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.android.layoutopt.uix.groovy;
import com.android.layoutopt.uix.LayoutAnalysis;
import com.android.layoutopt.uix.xml.XmlDocumentBuilder;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import groovy.lang.GString;
import groovy.xml.dom.DOMCategory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
/**
* Support class for Groovy rules. This class adds new Groovy capabilities
* to {@link com.android.layoutopt.uix.LayoutAnalysis} and {@link org.w3c.dom.Node}.
*/
public class LayoutAnalysisCategory {
private static final String ANDROID_PADDING = "android:padding";
private static final String ANDROID_PADDING_LEFT = "android:paddingLeft";
private static final String ANDROID_PADDING_TOP = "android:paddingTop";
private static final String ANDROID_PADDING_RIGHT = "android:paddingRight";
private static final String ANDROID_PADDING_BOTTOM = "android:paddingBottom";
private static final String ANDROID_LAYOUT_WIDTH = "android:layout_width";
private static final String ANDROID_LAYOUT_HEIGHT = "android:layout_height";
private static final String VALUE_FILL_PARENT = "fill_parent";
private static final String VALUE_WRAP_CONTENT = "wrap_content";
private static final String[] sContainers = new String[] {
"FrameLayout", "LinearLayout", "RelativeLayout", "SlidingDrawer",
"AbsoluteLayout", "TableLayout", "Gallery", "GridView", "ListView",
"RadioGroup", "ScrollView", "HorizontalScrollView", "Spinner",
"ViewSwitcher", "ViewFlipper", "ViewAnimator", "ImageSwitcher",
"TextSwitcher", "android.gesture.GestureOverlayView", "TabHost"
};
static {
Arrays.sort(sContainers);
}
/**
* xmlNode.isContainer()
*
* @return True if the specified node corresponds to a container widget.
*/
public static boolean isContainer(Element element) {
return Arrays.binarySearch(sContainers, element.getNodeName()) >= 0;
}
/**
* xmlNode.all()
*
* Same as xmlNode.'**' but excludes xmlNode from the results.
*
* @return All descendants, this node excluded.
*/
public static List<Node> all(Element element) {
NodeList list = DOMCategory.depthFirst(element);
int count = list.getLength();
List<Node> nodes = new ArrayList<Node>(count - 1);
for (int i = 1; i < count; i++) {
nodes.add(list.item(i));
}
return nodes;
}
/**
* Returns the start line of this node.
*
* @return The start line or -1 if the line is unknown.
*/
public static int getStartLine(Node node) {
final Object data = node == null ? null :
node.getUserData(XmlDocumentBuilder.NODE_START_LINE);
return data == null ? -1 : (Integer) data;
}
/**
* Returns the end line of this node.
*
* @return The end line or -1 if the line is unknown.
*/
public static int getEndLine(Node node) {
final Object data = node == null ? null :
node.getUserData(XmlDocumentBuilder.NODE_END_LINE);
return data == null ? -1 : (Integer) data;
}
/**
* xmlNode.hasPadding()
*
* @return True if the node has one ore more padding attributes.
*/
public static boolean hasPadding(Element element) {
return element.getAttribute(ANDROID_PADDING).length() > 0 ||
element.getAttribute(ANDROID_PADDING_LEFT).length() > 0 ||
element.getAttribute(ANDROID_PADDING_TOP).length() > 0 ||
element.getAttribute(ANDROID_PADDING_BOTTOM).length() > 0 ||
element.getAttribute(ANDROID_PADDING_RIGHT).length() > 0;
}
/**
* Returns whether this node's width is fill_parent.
*/
public static boolean isWidthFillParent(Element element) {
return element.getAttribute(ANDROID_LAYOUT_WIDTH).equals(VALUE_FILL_PARENT);
}
/**
* Returns whether this node's width is wrap_content.
*/
public static boolean isWidthWrapContent(Element element) {
return element.getAttribute(ANDROID_LAYOUT_WIDTH).equals(VALUE_WRAP_CONTENT);
}
/**
* Returns whether this node's height is fill_parent.
*/
public static boolean isHeightFillParent(Element element) {
return element.getAttribute(ANDROID_LAYOUT_HEIGHT).equals(VALUE_FILL_PARENT);
}
/**
* Returns whether this node's height is wrap_content.
*/
public static boolean isHeightWrapContent(Element element) {
return element.getAttribute(ANDROID_LAYOUT_HEIGHT).equals(VALUE_WRAP_CONTENT);
}
/**
* xmlNode.isRoot()
*
* @return True if xmlNode is the root of the document, false otherwise
*/
public static boolean isRoot(Node node) {
return node.getOwnerDocument().getDocumentElement() == node;
}
/**
* xmlNode.is("tagName")
*
* @return True if xmlNode.getNodeName().equals(name), false otherwise.
*/
public static boolean is(Node node, String name) {
return node.getNodeName().equals(name);
}
/**
* xmlNode.depth()
*
* @return The maximum depth of the node.
*/
public static int depth(Node node) {
int maxDepth = 0;
NodeList list = node.getChildNodes();
int count = list.getLength();
for (int i = 0; i < count; i++) {
maxDepth = Math.max(maxDepth, depth(list.item(i)));
}
return maxDepth + 1;
}
/**
* analysis << "The issue"
*
* @return The analysis itself to chain calls.
*/
public static LayoutAnalysis leftShift(LayoutAnalysis analysis, GString description) {
analysis.addIssue(description.toString());
return analysis;
}
/**
* analysis << "The issue"
*
* @return The analysis itself to chain calls.
*/
public static LayoutAnalysis leftShift(LayoutAnalysis analysis, String description) {
analysis.addIssue(description);
return analysis;
}
/**
* analysis << [node: node, description: "The issue"]
*
* @return The analysis itself to chain calls.
*/
public static LayoutAnalysis leftShift(LayoutAnalysis analysis, Map issue) {
analysis.addIssue((Node) issue.get("node"), issue.get("description").toString());
return analysis;
}
}