aboutsummaryrefslogtreecommitdiffstats
path: root/hierarchyviewer2/libs/hierarchyviewerlib
diff options
context:
space:
mode:
Diffstat (limited to 'hierarchyviewer2/libs/hierarchyviewerlib')
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java11
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java16
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java37
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java10
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java45
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java174
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/scene/DrawableViewNode.java249
7 files changed, 541 insertions, 1 deletions
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java
index 528c35c..a50478e 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java
@@ -18,6 +18,7 @@ package com.android.hierarchyviewerlib;
import com.android.hierarchyviewerlib.models.DeviceSelectionModel;
import com.android.hierarchyviewerlib.models.PixelPerfectModel;
+import com.android.hierarchyviewerlib.models.TreeViewModel;
/**
* This is the central point for getting access to the various parts of the
@@ -32,6 +33,8 @@ public class ComponentRegistry {
private static PixelPerfectModel pixelPerfectModel;
+ private static TreeViewModel treeViewModel;
+
public static HierarchyViewerDirector getDirector() {
return director;
}
@@ -55,4 +58,12 @@ public class ComponentRegistry {
public static PixelPerfectModel getPixelPerfectModel() {
return pixelPerfectModel;
}
+
+ public static void setTreeViewModel(TreeViewModel treeViewModel) {
+ ComponentRegistry.treeViewModel = treeViewModel;
+ }
+
+ public static TreeViewModel getTreeViewModel() {
+ return treeViewModel;
+ }
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
index c21da49..b63fba8 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
@@ -109,6 +109,9 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener,
DeviceBridge.removeDeviceForward(device);
DeviceBridge.removeViewServerInfo(device);
ComponentRegistry.getDeviceSelectionModel().removeDevice(device);
+ if (ComponentRegistry.getPixelPerfectModel().getDevice() == device) {
+ ComponentRegistry.getPixelPerfectModel().setData(null, null, null);
+ }
}
public void deviceChanged(IDevice device, int changeMask) {
@@ -192,4 +195,17 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener,
}
});
}
+
+ public void loadViewTreeData(final Window window) {
+ executeInBackground(new Runnable() {
+ public void run() {
+
+ ViewNode viewNode = DeviceBridge.loadWindowData(window);
+ if (viewNode != null) {
+ DeviceBridge.loadProfileData(window, viewNode);
+ ComponentRegistry.getTreeViewModel().setData(window, viewNode);
+ }
+ }
+ });
+ }
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java
index 001f98b..34e7c03 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java
@@ -430,4 +430,41 @@ public class DeviceBridge {
}
return null;
}
+
+ public static boolean loadProfileData(Window window, ViewNode viewNode) {
+ DeviceConnection connection = null;
+ try {
+ connection = new DeviceConnection(window.getDevice());
+ connection.sendCommand("PROFILE " + window.encode() + " " + viewNode.toString());
+ BufferedReader in = connection.getInputStream();
+ return loadProfileDataRecursive(viewNode, in);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to load profiling data for window " + window.getTitle()
+ + " on device " + window.getDevice());
+ } finally {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ return false;
+ }
+
+ private static boolean loadProfileDataRecursive(ViewNode node, BufferedReader in)
+ throws IOException {
+ String line;
+ if ((line = in.readLine()) == null || line.equalsIgnoreCase("-1 -1 -1")
+ || line.equalsIgnoreCase("DONE.")) {
+ return false;
+ }
+ String[] data = line.split(" ");
+ node.measureTime = (Long.parseLong(data[0]) / 1000.0) / 1000.0;
+ node.layoutTime = (Long.parseLong(data[1]) / 1000.0) / 1000.0;
+ node.drawTime = (Long.parseLong(data[2]) / 1000.0) / 1000.0;
+ for (int i = 0; i < node.children.size(); i++) {
+ if (!loadProfileDataRecursive(node.children.get(i), in)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java
index 00453ee..2e22b56 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java
@@ -76,6 +76,12 @@ public class ViewNode {
public int index;
+ public double measureTime;
+
+ public double layoutTime;
+
+ public double drawTime;
+
public ViewNode(ViewNode parent, String data) {
this.parent = parent;
index = this.parent == null ? 0 : this.parent.children.size();
@@ -88,6 +94,10 @@ public class ViewNode {
delimIndex = data.indexOf(' ');
hashCode = data.substring(0, delimIndex);
loadProperties(data.substring(delimIndex + 1).trim());
+
+ measureTime = -1;
+ layoutTime = -1;
+ drawTime = -1;
}
private void loadProperties(String data) {
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java
index 6963b25..4f19368 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java
@@ -24,6 +24,12 @@ import java.util.ArrayList;
public class PixelPerfectModel {
+ public static final int MIN_ZOOM = 2;
+
+ public static final int MAX_ZOOM = 24;
+
+ private static final int DEFAULT_ZOOM = 8;
+
public static class Point {
public int x;
@@ -45,6 +51,8 @@ public class PixelPerfectModel {
private ViewNode selected;
+ private int zoom;
+
private final ArrayList<ImageChangeListener> imageChangeListeners =
new ArrayList<ImageChangeListener>();
@@ -53,8 +61,13 @@ public class PixelPerfectModel {
this.device = device;
this.image = image;
this.viewNode = viewNode;
- this.crosshairLocation = new Point(image.width / 2, image.height / 2);
+ if (image != null) {
+ this.crosshairLocation = new Point(image.width / 2, image.height / 2);
+ } else {
+ this.crosshairLocation = null;
+ }
this.selected = null;
+ zoom = DEFAULT_ZOOM;
}
notifyImageLoaded();
}
@@ -82,6 +95,19 @@ public class PixelPerfectModel {
notifyFocusChanged();
}
+ public void setZoom(int newZoom) {
+ synchronized (this) {
+ if (newZoom < MIN_ZOOM) {
+ newZoom = MIN_ZOOM;
+ }
+ if (newZoom > MAX_ZOOM) {
+ newZoom = MAX_ZOOM;
+ }
+ zoom = newZoom;
+ }
+ notifyZoomChanged();
+ }
+
public ViewNode getViewNode() {
synchronized (this) {
return viewNode;
@@ -112,6 +138,12 @@ public class PixelPerfectModel {
}
}
+ public int getZoom() {
+ synchronized (this) {
+ return zoom;
+ }
+ }
+
public static interface ImageChangeListener {
public void imageLoaded();
@@ -122,6 +154,8 @@ public class PixelPerfectModel {
public void selectionChanged();
public void focusChanged();
+
+ public void zoomChanged();
}
private ImageChangeListener[] getImageChangeListenerList() {
@@ -182,6 +216,15 @@ public class PixelPerfectModel {
}
}
+ public void notifyZoomChanged() {
+ ImageChangeListener[] listeners = getImageChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].zoomChanged();
+ }
+ }
+ }
+
public void addImageChangeListener(ImageChangeListener listener) {
synchronized (imageChangeListeners) {
imageChangeListeners.add(listener);
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java
new file mode 100644
index 0000000..890b88c
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2010 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.hierarchyviewerlib.models;
+
+import com.android.hierarchyviewerlib.device.ViewNode;
+import com.android.hierarchyviewerlib.device.Window;
+import com.android.hierarchyviewerlib.scene.DrawableViewNode;
+import com.android.hierarchyviewerlib.scene.DrawableViewNode.Point;
+import com.android.hierarchyviewerlib.scene.DrawableViewNode.Rectangle;
+
+import java.util.ArrayList;
+
+public class TreeViewModel {
+ public static final double MAX_ZOOM = 2;
+
+ public static final double MIN_ZOOM = 0.2;
+
+ private Window window;
+
+ private DrawableViewNode tree;
+
+ private Rectangle viewport;
+
+ private double zoom;
+
+ private final ArrayList<TreeChangeListener> treeChangeListeners =
+ new ArrayList<TreeChangeListener>();
+
+ public void setData(Window window, ViewNode viewNode) {
+ synchronized (this) {
+ this.window = window;
+ tree = new DrawableViewNode(viewNode);
+ tree.setLeft();
+ tree.placeRoot();
+ viewport = null;
+ zoom = 1;
+ }
+ notifyTreeChanged();
+ }
+
+ public void setViewport(Rectangle viewport) {
+ synchronized (this) {
+ this.viewport = viewport;
+ }
+ notifyViewportChanged();
+ }
+
+ public void setZoom(double newZoom) {
+ Point zoomPoint = null;
+ synchronized (this) {
+ if (tree != null && viewport != null) {
+ zoomPoint =
+ new Point(viewport.x + viewport.width / 2, viewport.y + viewport.height / 2);
+ }
+ }
+ zoomOnPoint(newZoom, zoomPoint);
+ }
+
+ public void zoomOnPoint(double newZoom, Point zoomPoint) {
+ synchronized (this) {
+ if (tree != null && this.viewport != null) {
+ if (newZoom < MIN_ZOOM) {
+ newZoom = MIN_ZOOM;
+ }
+ if (newZoom > MAX_ZOOM) {
+ newZoom = MAX_ZOOM;
+ }
+ viewport.x = zoomPoint.x - (zoomPoint.x - viewport.x) * zoom / newZoom;
+ viewport.y = zoomPoint.y - (zoomPoint.y - viewport.y) * zoom / newZoom;
+ viewport.width = viewport.width * zoom / newZoom;
+ viewport.height = viewport.height * zoom / newZoom;
+ zoom = newZoom;
+ }
+ }
+ notifyZoomChanged();
+ }
+
+ public DrawableViewNode getTree() {
+ synchronized (this) {
+ return tree;
+ }
+ }
+
+ public Window getWindow() {
+ synchronized (this) {
+ return window;
+ }
+ }
+
+ public Rectangle getViewport() {
+ synchronized (this) {
+ return viewport;
+ }
+ }
+
+ public double getZoom() {
+ synchronized (this) {
+ return zoom;
+ }
+ }
+
+ public static interface TreeChangeListener {
+ public void treeChanged();
+
+ public void viewportChanged();
+
+ public void zoomChanged();
+ }
+
+ private TreeChangeListener[] getTreeChangeListenerList() {
+ TreeChangeListener[] listeners = null;
+ synchronized (treeChangeListeners) {
+ if (treeChangeListeners.size() == 0) {
+ return null;
+ }
+ listeners =
+ treeChangeListeners.toArray(new TreeChangeListener[treeChangeListeners.size()]);
+ }
+ return listeners;
+ }
+
+ public void notifyTreeChanged() {
+ TreeChangeListener[] listeners = getTreeChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].treeChanged();
+ }
+ }
+ }
+
+ public void notifyViewportChanged() {
+ TreeChangeListener[] listeners = getTreeChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].viewportChanged();
+ }
+ }
+ }
+
+ public void notifyZoomChanged() {
+ TreeChangeListener[] listeners = getTreeChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].zoomChanged();
+ }
+ }
+ }
+
+ public void addTreeChangeListener(TreeChangeListener listener) {
+ synchronized (treeChangeListeners) {
+ treeChangeListeners.add(listener);
+ }
+ }
+
+ public void removeTreeChangeListener(TreeChangeListener listener) {
+ synchronized (treeChangeListeners) {
+ treeChangeListeners.remove(listener);
+ }
+ }
+}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/scene/DrawableViewNode.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/scene/DrawableViewNode.java
new file mode 100644
index 0000000..aff3d6d
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/scene/DrawableViewNode.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2010 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.hierarchyviewerlib.scene;
+
+import com.android.hierarchyviewerlib.device.ViewNode;
+
+import java.util.ArrayList;
+
+public class DrawableViewNode {
+ public ViewNode viewNode;
+
+ public final ArrayList<DrawableViewNode> children = new ArrayList<DrawableViewNode>();
+
+ public final static int NODE_HEIGHT = 70;
+
+ public final static int NODE_WIDTH = 100;
+
+ public final static int LEAF_NODE_SPACING = 5;
+
+ public final static int NON_LEAF_NODE_SPACING = 10;
+
+ public final static int PARENT_CHILD_SPACING = 40;
+
+ public final static int PADDING = 30;
+
+ public int treeHeight;
+
+ public int treeWidth;
+
+ public boolean leaf;
+
+ public DrawableViewNode parent;
+
+ public int left;
+
+ public double top;
+
+ public int topSpacing;
+
+ public int bottomSpacing;
+
+ public static class Rectangle {
+ public double x, y, width, height;
+
+ public Rectangle() {
+
+ }
+
+ public Rectangle(Rectangle other) {
+ this.x = other.x;
+ this.y = other.y;
+ this.width = other.width;
+ this.height = other.height;
+ }
+
+ public Rectangle(double x, double y, double width, double height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public String toString() {
+ return "{" + x + ", " + y + ", " + width + ", " + height + "}";
+ }
+
+ }
+
+ public static class Point {
+ public double x, y;
+
+ public Point() {
+ }
+
+ public Point(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
+ public Rectangle bounds = new Rectangle();
+
+ public DrawableViewNode(ViewNode viewNode) {
+ this.viewNode = viewNode;
+ if (viewNode.children.size() == 0) {
+ treeHeight = NODE_HEIGHT;
+ treeWidth = NODE_WIDTH;
+ leaf = true;
+ } else {
+ leaf = false;
+ int N = viewNode.children.size();
+ treeHeight = 0;
+ treeWidth = 0;
+ for (int i = 0; i < N; i++) {
+ DrawableViewNode child = new DrawableViewNode(viewNode.children.get(i));
+ children.add(child);
+ child.parent = this;
+ treeHeight += child.treeHeight;
+ treeWidth = Math.max(treeWidth, child.treeWidth);
+ if (i != 0) {
+ DrawableViewNode prevChild = children.get(i - 1);
+ if (prevChild.leaf && child.leaf) {
+ treeHeight += LEAF_NODE_SPACING;
+ prevChild.bottomSpacing = LEAF_NODE_SPACING;
+ child.topSpacing = LEAF_NODE_SPACING;
+ } else {
+ treeHeight += NON_LEAF_NODE_SPACING;
+ prevChild.bottomSpacing = NON_LEAF_NODE_SPACING;
+ child.topSpacing = NON_LEAF_NODE_SPACING;
+ }
+ }
+ }
+ treeWidth += NODE_WIDTH + PARENT_CHILD_SPACING;
+ }
+ }
+
+ public void setLeft() {
+ if (parent == null) {
+ left = PADDING;
+ bounds.x = 0;
+ bounds.width = treeWidth + 2 * PADDING;
+ } else {
+ left = parent.left + NODE_WIDTH + PARENT_CHILD_SPACING;
+ }
+ int N = children.size();
+ for (int i = 0; i < N; i++) {
+ children.get(i).setLeft();
+ }
+ }
+
+ public void placeRoot() {
+ top = PADDING + (treeHeight - NODE_HEIGHT) / 2.0;
+ double currentTop = PADDING;
+ int N = children.size();
+ for (int i = 0; i < N; i++) {
+ DrawableViewNode child = children.get(i);
+ child.place(currentTop, top - currentTop);
+ currentTop += child.treeHeight + child.bottomSpacing;
+ }
+ bounds.y = 0;
+ bounds.height = treeHeight + 2 * PADDING;
+ }
+
+ private void place(double treeTop, double rootDistance) {
+ if (treeHeight <= rootDistance) {
+ top = treeTop + treeHeight - NODE_HEIGHT;
+ } else if (rootDistance <= -NODE_HEIGHT) {
+ top = treeTop;
+ } else {
+ if (children.size() == 0) {
+ top = treeTop;
+ } else {
+ top =
+ rootDistance + treeTop - NODE_HEIGHT + (2.0 * NODE_HEIGHT)
+ / (treeHeight + NODE_HEIGHT) * (treeHeight - rootDistance);
+ }
+ }
+ int N = children.size();
+ double currentTop = treeTop;
+ for (int i = 0; i < N; i++) {
+ DrawableViewNode child = children.get(i);
+ child.place(currentTop, rootDistance);
+ currentTop += child.treeHeight + child.bottomSpacing;
+ rootDistance -= child.treeHeight + child.bottomSpacing;
+ }
+ }
+
+ public DrawableViewNode getSelected(double x, double y) {
+ if (x >= left && x < left + NODE_WIDTH && y >= top && y <= top + NODE_HEIGHT) {
+ return this;
+ }
+ int N = children.size();
+ for (int i = 0; i < N; i++) {
+ DrawableViewNode selected = children.get(i).getSelected(x, y);
+ if (selected != null) {
+ return selected;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Moves the node the specified distance up.
+ */
+ public void move(double distance) {
+ top -= distance;
+
+ // Get the root
+ DrawableViewNode root = this;
+ while (root.parent != null) {
+ root = root.parent;
+ }
+
+ // Figure out the new tree top.
+ double treeTop;
+ if (top + NODE_HEIGHT <= root.top) {
+ treeTop = top + NODE_HEIGHT - treeHeight;
+ } else if (top >= root.top + NODE_HEIGHT) {
+ treeTop = top;
+ } else {
+ if (leaf) {
+ treeTop = top;
+ } else {
+ double distanceRatio = 1 - (root.top + NODE_HEIGHT - top) / (2.0 * NODE_HEIGHT);
+ treeTop = root.top - treeHeight + distanceRatio * (treeHeight + NODE_HEIGHT);
+ }
+ }
+ // Go up the tree and figure out the tree top.
+ DrawableViewNode node = this;
+ while (node.parent != null) {
+ int index = node.viewNode.index;
+ for (int i = 0; i < index; i++) {
+ DrawableViewNode sibling = node.parent.children.get(i);
+ treeTop -= sibling.treeHeight + sibling.bottomSpacing;
+ }
+ node = node.parent;
+ }
+
+ // Update the bounds.
+ root.bounds.y = Math.min(root.top - PADDING, treeTop - PADDING);
+ root.bounds.height =
+ Math.max(treeTop + root.treeHeight + PADDING, root.top + NODE_HEIGHT + PADDING)
+ - root.bounds.y;
+ // Place all the children of the root
+ double currentTop = treeTop;
+ int N = root.children.size();
+ for (int i = 0; i < N; i++) {
+ DrawableViewNode child = root.children.get(i);
+ child.place(currentTop, root.top - currentTop);
+ currentTop += child.treeHeight + child.bottomSpacing;
+ }
+
+ }
+}