diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java | 421 |
1 files changed, 0 insertions, 421 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java deleted file mode 100644 index 25fa3e991..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (C) 2009 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.layout; - -import com.android.SdkConstants; -import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; -import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; -import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IProject; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * This class computes the new screen size in "exploded rendering" mode. - * It goes through the whole layout tree and figures out how many embedded layouts will have - * extra padding and compute how that will affect the screen size. - * - * TODO - * - find a better class name :) - * - move the logic for each layout to the layout rule classes? - * - support custom classes (by querying JDT for its super class and reverting to its behavior) - */ -public final class ExplodedRenderingHelper { - /** value of the padding in pixel. - * TODO: make a preference? - */ - public final static int PADDING_VALUE = 10; - - private final int[] mPadding = new int[] { 0, 0 }; - private Set<String> mLayoutNames; - - /** - * Computes the padding. access the result through {@link #getWidthPadding()} and - * {@link #getHeightPadding()}. - * @param root the root node (ie the top layout). - * @param iProject the project to which the layout belong. - */ - public ExplodedRenderingHelper(Node root, IProject iProject) { - // get the layout descriptors to get the name of all the layout classes. - IAndroidTarget target = Sdk.getCurrent().getTarget(iProject); - AndroidTargetData data = Sdk.getCurrent().getTargetData(target); - LayoutDescriptors descriptors = data.getLayoutDescriptors(); - - mLayoutNames = new HashSet<String>(); - List<ViewElementDescriptor> layoutDescriptors = descriptors.getLayoutDescriptors(); - for (ViewElementDescriptor desc : layoutDescriptors) { - mLayoutNames.add(desc.getXmlLocalName()); - } - - computePadding(root, mPadding); - } - - /** - * (Unit tests only) - * Computes the padding. access the result through {@link #getWidthPadding()} and - * {@link #getHeightPadding()}. - * @param root the root node (ie the top layout). - * @param layoutNames the list of layout classes - */ - public ExplodedRenderingHelper(Node root, Set<String> layoutNames) { - mLayoutNames = layoutNames; - - computePadding(root, mPadding); - } - - /** - * Returns the number of extra padding in the X axis. This doesn't return a number of pixel - * or dip, but how many paddings are pushing the screen dimension out. - */ - public int getWidthPadding() { - return mPadding[0]; - } - - /** - * Returns the number of extra padding in the Y axis. This doesn't return a number of pixel - * or dip, but how many paddings are pushing the screen dimension out. - */ - public int getHeightPadding() { - return mPadding[1]; - } - - /** - * Computes the number of padding for a given view, and fills the given array of int. - * <p/>index 0 is X axis, index 1 is Y axis - * @param view the view to compute - * @param padding the result padding (index 0 is X axis, index 1 is Y axis) - */ - private void computePadding(Node view, int[] padding) { - String localName = view.getLocalName(); - - // first compute for each children - NodeList children = view.getChildNodes(); - int count = children.getLength(); - if (count > 0) { - // compute the padding for all the children. - Map<Node, int[]> childrenPadding = new HashMap<Node, int[]>(count); - for (int i = 0 ; i < count ; i++) { - Node child = children.item(i); - short type = child.getNodeType(); - if (type == Node.ELEMENT_NODE) { // ignore TEXT/CDATA nodes. - int[] p = new int[] { 0, 0 }; - childrenPadding.put(child, p); - computePadding(child, p); - } - } - - // since the non ELEMENT_NODE children were filtered out, count must be updated. - count = childrenPadding.size(); - - // now combine/compare based on the parent. - if (count == 1) { - int[] p = childrenPadding.get(childrenPadding.keySet().iterator().next()); - padding[0] = p[0]; - padding[1] = p[1]; - } else { - if ("LinearLayout".equals(localName)) { //$NON-NLS-1$ - String orientation = getAttribute(view, "orientation", null); //$NON-NLS-1$ - - // default value is horizontal - boolean horizontal = orientation == null || - "horizontal".equals("vertical"); //$NON-NLS-1$ //$NON-NLS-2$ - combineLinearLayout(childrenPadding.values(), padding, horizontal); - } else if ("TableLayout".equals(localName)) { //$NON-NLS-1$ - combineLinearLayout(childrenPadding.values(), padding, false /*horizontal*/); - } else if ("TableRow".equals(localName)) { //$NON-NLS-1$ - combineLinearLayout(childrenPadding.values(), padding, true /*true*/); - // TODO: properly support Relative Layouts. -// } else if ("RelativeLayout".equals(localName)) { //$NON-NLS-1$ -// combineRelativeLayout(childrenPadding, padding); - } else { - // unknown layout. For now, let's consider it's better to add the children - // margins in both dimensions than not at all. - for (int[] p : childrenPadding.values()) { - padding[0] += p[0]; - padding[1] += p[1]; - } - } - } - } - - // if the view itself is a layout, add its padding - if (mLayoutNames.contains(localName)) { - padding[0]++; - padding[1]++; - } - } - - /** - * Combines the padding of the children of a linear layout. - * <p/>For this layout, the padding of the children are added in the direction of - * the layout, while the max is taken for the other direction. - * @param paddings the list of the padding for the children. - * @param resultPadding the result padding array to fill. - * @param horizontal whether this layout is horizontal (<code>true</code>) or vertical - * (<code>false</code>) - */ - private void combineLinearLayout(Collection<int[]> paddings, int[] resultPadding, - boolean horizontal) { - // The way the children are combined will depend on the direction. - // For instance in a vertical layout, we add the y padding as they all add to the length - // of the needed canvas, while we take the biggest x padding needed by the children - - // the axis in which we take the sum of the padding of the children - int sumIndex = horizontal ? 0 : 1; - // the axis in which we take the max of the padding of the children - int maxIndex = horizontal ? 1 : 0; - - int max = -1; - for (int[] p : paddings) { - resultPadding[sumIndex] += p[sumIndex]; - if (max == -1 || max < p[maxIndex]) { - max = p[maxIndex]; - } - } - resultPadding[maxIndex] = max; - } - - /** - * Combine the padding of children of a relative layout. - * @param childrenPadding a map of the children. This is guaranteed that the node object - * are of type ELEMENT_NODE - * @param padding - * - * TODO: Not used yet. Still need (lots of) work. - */ - private void combineRelativeLayout(Map<Node, int[]> childrenPadding, int[] padding) { - /* - * Combines the children of the layout. - * The way this works: for each children, for each direction, look for all the chidrens - * connected and compute the combined margin in that direction. - * - * There's a chance the returned value will be too much. this is due to the layout sometimes - * dropping views which will not be dropped here. It's ok, as it's better to have too - * much than not enough. - * We could fix this by matching those UiElementNode with their bounds as returned - * by the rendering (ie if bounds is 0/0 in h/w, then ignore the child) - */ - - // list of the UiElementNode - Set<Node> nodeSet = childrenPadding.keySet(); - // map of Id -> node - Map<String, Node> idNodeMap = computeIdNodeMap(nodeSet); - - for (Entry<Node, int[]> entry : childrenPadding.entrySet()) { - Node node = entry.getKey(); - - // first horizontal, to the left. - int[] leftResult = getBiggestMarginInDirection(node, 0 /*horizontal*/, - "layout_toRightOf", "layout_toLeftOf", //$NON-NLS-1$ //$NON-NLS-2$ - childrenPadding, nodeSet, idNodeMap, - false /*includeThisPadding*/); - - // then to the right - int[] rightResult = getBiggestMarginInDirection(node, 0 /*horizontal*/, - "layout_toLeftOf", "layout_toRightOf", //$NON-NLS-1$ //$NON-NLS-2$ - childrenPadding, nodeSet, idNodeMap, - false /*includeThisPadding*/); - - // compute total horizontal margins - int[] thisPadding = childrenPadding.get(node); - int combinedMargin = - (thisPadding != null ? thisPadding[0] : 0) + - (leftResult != null ? leftResult[0] : 0) + - (rightResult != null ? rightResult[0] : 0); - if (combinedMargin > padding[0]) { - padding[0] = combinedMargin; - } - - // first vertical, above. - int[] topResult = getBiggestMarginInDirection(node, 1 /*horizontal*/, - "layout_below", "layout_above", //$NON-NLS-1$ //$NON-NLS-2$ - childrenPadding, nodeSet, idNodeMap, - false /*includeThisPadding*/); - - // then below - int[] bottomResult = getBiggestMarginInDirection(node, 1 /*horizontal*/, - "layout_above", "layout_below", //$NON-NLS-1$ //$NON-NLS-2$ - childrenPadding, nodeSet, idNodeMap, - false /*includeThisPadding*/); - - // compute total horizontal margins - combinedMargin = - (thisPadding != null ? thisPadding[1] : 0) + - (topResult != null ? topResult[1] : 0) + - (bottomResult != null ? bottomResult[1] : 0); - if (combinedMargin > padding[1]) { - padding[1] = combinedMargin; - } - } - } - - /** - * Computes the biggest margin in a given direction. - * - * TODO: Not used yet. Still need (lots of) work. - */ - private int[] getBiggestMarginInDirection(Node node, int resIndex, String relativeTo, - String inverseRelation, Map<Node, int[]> childrenPadding, - Set<Node> nodeSet, Map<String, Node> idNodeMap, - boolean includeThisPadding) { - NamedNodeMap attributes = node.getAttributes(); - - String viewId = getAttribute(node, "id", attributes); //$NON-NLS-1$ - - // first get the item this one is positioned relative to. - String toLeftOfRef = getAttribute(node, relativeTo, attributes); - Node toLeftOf = null; - if (toLeftOfRef != null) { - toLeftOf = idNodeMap.get(cleanUpIdReference(toLeftOfRef)); - } - - ArrayList<Node> list = null; - if (viewId != null) { - // now to the left for items being placed to the left of this one. - list = getMatchingNode(nodeSet, cleanUpIdReference(viewId), inverseRelation); - } - - // now process each children in the same direction. - if (toLeftOf != null) { - if (list == null) { - list = new ArrayList<Node>(); - } - - if (list.indexOf(toLeftOf) == -1) { - list.add(toLeftOf); - } - } - - int[] thisPadding = childrenPadding.get(node); - - if (list != null) { - // since there's a combination to do, we'll return a new result object - int[] result = null; - for (Node nodeOnLeft : list) { - int[] tempRes = getBiggestMarginInDirection(nodeOnLeft, resIndex, relativeTo, - inverseRelation, childrenPadding, nodeSet, idNodeMap, true); - if (tempRes != null && (result == null || result[resIndex] < tempRes[resIndex])) { - result = tempRes; - } - } - - // return the combined padding - if (includeThisPadding == false || thisPadding[resIndex] == 0) { - // just return the one we got since this object adds no padding (or doesn't - // need to be comibined) - return result; - } else if (result != null) { // if result is null, the main return below is used. - // add the result we got with the padding from the current node - int[] realRes = new int [2]; - realRes[resIndex] = thisPadding[resIndex] + result[resIndex]; - return realRes; - } - } - - // if we reach this, there were no other views to the left of this one, so just return - // the view padding. - return includeThisPadding ? thisPadding : null; - } - - /** - * Computes and returns a map of (id, node) for each node of a given {@link Set}. - * <p/> - * Nodes with no id are ignored and not put in the map. - * @param nodes the nodes to fill the map with. - * @return a newly allocated, non-null, map of (id, node) - */ - private Map<String, Node> computeIdNodeMap(Set<Node> nodes) { - Map<String, Node> map = new HashMap<String, Node>(); - for (Node node : nodes) { - String viewId = getAttribute(node, "id", null); //$NON-NLS-1$ - if (viewId != null) { - map.put(cleanUpIdReference(viewId), node); - } - } - return map; - } - - /** - * Cleans up a reference to an ID to return the ID itself only. - * @param reference the reference to "clean up". - * @return the id string only. - */ - private String cleanUpIdReference(String reference) { - // format is @id/foo or @+id/foo or @android:id/foo, or something similar. - int slash = reference.indexOf('/'); - return reference.substring(slash); - } - - /** - * Returns a list of nodes for which a given attribute contains a reference to a given ID. - * - * @param nodes the list of nodes to search through - * @param resId the requested ID - * @param attribute the name of the attribute to test. - * @return a newly allocated, non-null, list of nodes. Could be empty. - */ - private ArrayList<Node> getMatchingNode(Set<Node> nodes, String resId, - String attribute) { - ArrayList<Node> list = new ArrayList<Node>(); - - for (Node node : nodes) { - String value = getAttribute(node, attribute, null); - if (value != null) { - value = cleanUpIdReference(value); - if (value.equals(resId)) { - list.add(node); - } - } - } - - return list; - } - - /** - * Returns an attribute for a given node. - * @param node the node to query - * @param name the name of an attribute - * @param attributes the option {@link NamedNodeMap} object to use to read the attributes from. - */ - private static String getAttribute(Node node, String name, NamedNodeMap attributes) { - if (attributes == null) { - attributes = node.getAttributes(); - } - - if (attributes != null) { - Node attribute = attributes.getNamedItemNS(SdkConstants.NS_RESOURCES, name); - if (attribute != null) { - return attribute.getNodeValue(); - } - } - - return null; - } -} |