--- /dev/null
+/*
+ * 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.ui.util.DrawableViewNode;
+import com.android.hierarchyviewerlib.ui.util.DrawableViewNode.Point;
+import com.android.hierarchyviewerlib.ui.util.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 mWindow;
+
+ private DrawableViewNode mTree;
+
+ private DrawableViewNode mSelectedNode;
+
+ private Rectangle mViewport;
+
+ private double mZoom;
+
+ private final ArrayList<ITreeChangeListener> mTreeChangeListeners =
+ new ArrayList<ITreeChangeListener>();
+
+ private static TreeViewModel sModel;
+
+ public static TreeViewModel getModel() {
+ if (sModel == null) {
+ sModel = new TreeViewModel();
+ }
+ return sModel;
+ }
+
+ public void setData(Window window, ViewNode viewNode) {
+ synchronized (this) {
+ if (mTree != null) {
+ mTree.viewNode.dispose();
+ }
+ this.mWindow = window;
+ if (viewNode == null) {
+ mTree = null;
+ } else {
+ mTree = new DrawableViewNode(viewNode);
+ mTree.setLeft();
+ mTree.placeRoot();
+ }
+ mViewport = null;
+ mZoom = 1;
+ mSelectedNode = null;
+ }
+ notifyTreeChanged();
+ }
+
+ public void setSelection(DrawableViewNode selectedNode) {
+ synchronized (this) {
+ this.mSelectedNode = selectedNode;
+ }
+ notifySelectionChanged();
+ }
+
+ public void setViewport(Rectangle viewport) {
+ synchronized (this) {
+ this.mViewport = viewport;
+ }
+ notifyViewportChanged();
+ }
+
+ public void setZoom(double newZoom) {
+ Point zoomPoint = null;
+ synchronized (this) {
+ if (mTree != null && mViewport != null) {
+ zoomPoint =
+ new Point(mViewport.x + mViewport.width / 2, mViewport.y + mViewport.height / 2);
+ }
+ }
+ zoomOnPoint(newZoom, zoomPoint);
+ }
+
+ public void zoomOnPoint(double newZoom, Point zoomPoint) {
+ synchronized (this) {
+ if (mTree != null && this.mViewport != null) {
+ if (newZoom < MIN_ZOOM) {
+ newZoom = MIN_ZOOM;
+ }
+ if (newZoom > MAX_ZOOM) {
+ newZoom = MAX_ZOOM;
+ }
+ mViewport.x = zoomPoint.x - (zoomPoint.x - mViewport.x) * mZoom / newZoom;
+ mViewport.y = zoomPoint.y - (zoomPoint.y - mViewport.y) * mZoom / newZoom;
+ mViewport.width = mViewport.width * mZoom / newZoom;
+ mViewport.height = mViewport.height * mZoom / newZoom;
+ mZoom = newZoom;
+ }
+ }
+ notifyZoomChanged();
+ }
+
+ public DrawableViewNode getTree() {
+ synchronized (this) {
+ return mTree;
+ }
+ }
+
+ public Window getWindow() {
+ synchronized (this) {
+ return mWindow;
+ }
+ }
+
+ public Rectangle getViewport() {
+ synchronized (this) {
+ return mViewport;
+ }
+ }
+
+ public double getZoom() {
+ synchronized (this) {
+ return mZoom;
+ }
+ }
+
+ public DrawableViewNode getSelection() {
+ synchronized (this) {
+ return mSelectedNode;
+ }
+ }
+
+ public static interface ITreeChangeListener {
+ public void treeChanged();
+
+ public void selectionChanged();
+
+ public void viewportChanged();
+
+ public void zoomChanged();
+ }
+
+ private ITreeChangeListener[] getTreeChangeListenerList() {
+ ITreeChangeListener[] listeners = null;
+ synchronized (mTreeChangeListeners) {
+ if (mTreeChangeListeners.size() == 0) {
+ return null;
+ }
+ listeners =
+ mTreeChangeListeners.toArray(new ITreeChangeListener[mTreeChangeListeners.size()]);
+ }
+ return listeners;
+ }
+
+ public void notifyTreeChanged() {
+ ITreeChangeListener[] listeners = getTreeChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].treeChanged();
+ }
+ }
+ }
+
+ public void notifySelectionChanged() {
+ ITreeChangeListener[] listeners = getTreeChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].selectionChanged();
+ }
+ }
+ }
+
+ public void notifyViewportChanged() {
+ ITreeChangeListener[] listeners = getTreeChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].viewportChanged();
+ }
+ }
+ }
+
+ public void notifyZoomChanged() {
+ ITreeChangeListener[] listeners = getTreeChangeListenerList();
+ if (listeners != null) {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].zoomChanged();
+ }
+ }
+ }
+
+ public void addTreeChangeListener(ITreeChangeListener listener) {
+ synchronized (mTreeChangeListeners) {
+ mTreeChangeListeners.add(listener);
+ }
+ }
+
+ public void removeTreeChangeListener(ITreeChangeListener listener) {
+ synchronized (mTreeChangeListeners) {
+ mTreeChangeListeners.remove(listener);
+ }
+ }
+}