diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java | 326 |
1 files changed, 0 insertions, 326 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java deleted file mode 100644 index 43d52d137..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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.common.layout.relative; - -import static com.android.SdkConstants.ATTR_ID; -import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX; -import static com.android.SdkConstants.VALUE_TRUE; - - -import com.android.SdkConstants; -import static com.android.SdkConstants.ANDROID_URI; -import com.android.ide.common.api.IDragElement; -import com.android.ide.common.api.IDragElement.IDragAttribute; -import com.android.ide.common.api.INode; -import com.android.ide.common.api.INode.IAttribute; -import com.android.ide.common.layout.BaseLayoutRule; - -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.Set; - -/** - * Data structure about relative layout relationships which makes it possible to: - * <ul> - * <li> Quickly determine not just the dependencies on other nodes, but which nodes - * depend on this node such that they can be visualized for the selection - * <li> Determine if there are cyclic dependencies, and whether a potential move - * would result in a cycle - * <li> Determine the "depth" of a given node (in terms of how many connections it - * is away from a parent edge) such that we can prioritize connections which - * minimizes the depth - * </ul> - */ -class DependencyGraph { - /** Format to chain include cycles in: a=>b=>c=>d etc */ - static final String CHAIN_FORMAT = "%1$s=>%2$s"; //$NON-NLS-1$ - - /** Format to chain constraint dependencies: button 1 above button2 etc */ - private static final String DEPENDENCY_FORMAT = "%1$s %2$s %3$s"; //$NON-NLS-1$ - - private final Map<String, ViewData> mIdToView = new HashMap<String, ViewData>(); - private final Map<INode, ViewData> mNodeToView = new HashMap<INode, ViewData>(); - - /** Constructs a new {@link DependencyGraph} for the given relative layout */ - DependencyGraph(INode layout) { - INode[] nodes = layout.getChildren(); - - // Parent view: - String parentId = layout.getStringAttr(ANDROID_URI, ATTR_ID); - if (parentId != null) { - parentId = BaseLayoutRule.stripIdPrefix(parentId); - } else { - parentId = "RelativeLayout"; // For display purposes; we never reference - // the parent id from a constraint, only via parent-relative params - // like centerInParent - } - ViewData parentView = new ViewData(layout, parentId); - mNodeToView.put(layout, parentView); - if (parentId != null) { - mIdToView.put(parentId, parentView); - } - - for (INode child : nodes) { - String id = child.getStringAttr(ANDROID_URI, ATTR_ID); - if (id != null) { - id = BaseLayoutRule.stripIdPrefix(id); - } - ViewData view = new ViewData(child, id); - mNodeToView.put(child, view); - if (id != null) { - mIdToView.put(id, view); - } - } - - for (ViewData view : mNodeToView.values()) { - for (IAttribute attribute : view.node.getLiveAttributes()) { - String name = attribute.getName(); - ConstraintType type = ConstraintType.fromAttribute(name); - if (type != null) { - String value = attribute.getValue(); - - if (type.targetParent) { - if (value.equals(VALUE_TRUE)) { - Constraint constraint = new Constraint(type, view, parentView); - view.dependsOn.add(constraint); - parentView.dependedOnBy.add(constraint); - } - } else { - // id-based constraint. - // NOTE: The id could refer to some widget that is NOT a sibling! - String targetId = BaseLayoutRule.stripIdPrefix(value); - ViewData target = mIdToView.get(targetId); - if (target == view) { - // Self-reference. RelativeLayout ignores these so it's - // not an error like a deeper cycle (where RelativeLayout - // will throw an exception), but we might as well warn - // the user about it. - // TODO: Where do we emit this error? - } else if (target != null) { - Constraint constraint = new Constraint(type, view, target); - view.dependsOn.add(constraint); - target.dependedOnBy.add(constraint); - } else { - // This is valid but we might want to warn... - //System.out.println("Warning: no view data found for " + targetId); - } - } - } - } - } - } - - public ViewData getView(IDragElement element) { - IDragAttribute attribute = element.getAttribute(ANDROID_URI, ATTR_ID); - if (attribute != null) { - String id = attribute.getValue(); - id = BaseLayoutRule.stripIdPrefix(id); - return getView(id); - } - - return null; - } - - public ViewData getView(String id) { - return mIdToView.get(id); - } - - public ViewData getView(INode node) { - return mNodeToView.get(node); - } - - /** - * Returns the set of views that depend on the given node in either the horizontal or - * vertical direction - * - * @param nodes the set of nodes that we want to compute the transitive dependencies - * for - * @param vertical if true, look for vertical edge dependencies, otherwise look for - * horizontal edge dependencies - * @return the set of nodes that directly or indirectly depend on the given nodes in - * the given direction - */ - public Set<INode> dependsOn(Collection<? extends INode> nodes, boolean vertical) { - List<ViewData> reachable = new ArrayList<ViewData>(); - - // Traverse the graph of constraints and determine all nodes affected by - // this node - Set<ViewData> visiting = new HashSet<ViewData>(); - for (INode node : nodes) { - ViewData view = mNodeToView.get(node); - if (view != null) { - findBackwards(view, visiting, reachable, vertical, view); - } - } - - Set<INode> dependents = new HashSet<INode>(reachable.size()); - - for (ViewData v : reachable) { - dependents.add(v.node); - } - - return dependents; - } - - private void findBackwards(ViewData view, - Set<ViewData> visiting, List<ViewData> reachable, - boolean vertical, ViewData start) { - visiting.add(view); - reachable.add(view); - - for (Constraint constraint : view.dependedOnBy) { - if (vertical && !constraint.type.verticalEdge) { - continue; - } else if (!vertical && !constraint.type.horizontalEdge) { - continue; - } - - assert constraint.to == view; - ViewData from = constraint.from; - if (visiting.contains(from)) { - // Cycle - what do we do to highlight this? - List<Constraint> path = getPathTo(start.node, view.node, vertical); - if (path != null) { - // TODO: display to the user somehow. We need log access for the - // view rules. - System.out.println(Constraint.describePath(path, null, null)); - } - } else { - findBackwards(from, visiting, reachable, vertical, start); - } - } - - visiting.remove(view); - } - - public List<Constraint> getPathTo(INode from, INode to, boolean vertical) { - // Traverse the graph of constraints and determine all nodes affected by - // this node - Set<ViewData> visiting = new HashSet<ViewData>(); - List<Constraint> path = new ArrayList<Constraint>(); - ViewData view = mNodeToView.get(from); - if (view != null) { - return findForwards(view, visiting, path, vertical, to); - } - - return null; - } - - private List<Constraint> findForwards(ViewData view, Set<ViewData> visiting, - List<Constraint> path, boolean vertical, INode target) { - visiting.add(view); - - for (Constraint constraint : view.dependsOn) { - if (vertical && !constraint.type.verticalEdge) { - continue; - } else if (!vertical && !constraint.type.horizontalEdge) { - continue; - } - - try { - path.add(constraint); - - if (constraint.to.node == target) { - return new ArrayList<Constraint>(path); - } - - assert constraint.from == view; - ViewData to = constraint.to; - if (visiting.contains(to)) { - // CYCLE! - continue; - } - - List<Constraint> chain = findForwards(to, visiting, path, vertical, target); - if (chain != null) { - return chain; - } - } finally { - path.remove(constraint); - } - } - - visiting.remove(view); - - return null; - } - - /** - * Info about a specific widget child of a relative layout and its constraints. This - * is a node in the dependency graph. - */ - static class ViewData { - public final INode node; - public final String id; - public final List<Constraint> dependsOn = new ArrayList<Constraint>(4); - public final List<Constraint> dependedOnBy = new ArrayList<Constraint>(8); - - ViewData(INode node, String id) { - this.node = node; - this.id = id; - } - } - - /** - * Info about a specific constraint between two widgets in a relative layout. This is - * an edge in the dependency graph. - */ - static class Constraint { - public final ConstraintType type; - public final ViewData from; - public final ViewData to; - - // TODO: Initialize depth -- should be computed independently for top, left, etc. - // We can use this in GuidelineHandler.MatchComparator to prefer matches that - // are closer to a parent edge: - //public int depth; - - Constraint(ConstraintType type, ViewData from, ViewData to) { - this.type = type; - this.from = from; - this.to = to; - } - - static String describePath(List<Constraint> path, String newName, String newId) { - String s = ""; - for (int i = path.size() - 1; i >= 0; i--) { - Constraint constraint = path.get(i); - String suffix = (i == path.size() -1) ? constraint.to.id : s; - s = String.format(DEPENDENCY_FORMAT, constraint.from.id, - stripLayoutAttributePrefix(constraint.type.name), suffix); - } - - if (newName != null) { - s = String.format(DEPENDENCY_FORMAT, s, stripLayoutAttributePrefix(newName), - BaseLayoutRule.stripIdPrefix(newId)); - } - - return s; - } - - private static String stripLayoutAttributePrefix(String name) { - if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)) { - return name.substring(ATTR_LAYOUT_RESOURCE_PREFIX.length()); - } - - return name; - } - } -} |