1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.hierarchyviewerlib.models; 18 19 import com.android.hierarchyviewerlib.device.ViewNode; 20 import com.android.hierarchyviewerlib.device.Window; 21 import com.android.hierarchyviewerlib.ui.util.DrawableViewNode; 22 import com.android.hierarchyviewerlib.ui.util.DrawableViewNode.Point; 23 import com.android.hierarchyviewerlib.ui.util.DrawableViewNode.Rectangle; 24 25 import java.util.ArrayList; 26 27 public class TreeViewModel { 28 public static final double MAX_ZOOM = 2; 29 30 public static final double MIN_ZOOM = 0.2; 31 32 private Window mWindow; 33 34 private DrawableViewNode mTree; 35 36 private DrawableViewNode mSelectedNode; 37 38 private Rectangle mViewport; 39 40 private double mZoom; 41 42 private final ArrayList<ITreeChangeListener> mTreeChangeListeners = 43 new ArrayList<ITreeChangeListener>(); 44 45 private static TreeViewModel sModel; 46 47 public static TreeViewModel getModel() { 48 if (sModel == null) { 49 sModel = new TreeViewModel(); 50 } 51 return sModel; 52 } 53 54 public void setData(Window window, ViewNode viewNode) { 55 synchronized (this) { 56 if (mTree != null) { 57 mTree.viewNode.dispose(); 58 } 59 this.mWindow = window; 60 if (viewNode == null) { 61 mTree = null; 62 } else { 63 mTree = new DrawableViewNode(viewNode); 64 mTree.setLeft(); 65 mTree.placeRoot(); 66 } 67 mViewport = null; 68 mZoom = 1; 69 mSelectedNode = null; 70 } 71 notifyTreeChanged(); 72 } 73 74 public void setSelection(DrawableViewNode selectedNode) { 75 synchronized (this) { 76 this.mSelectedNode = selectedNode; 77 } 78 notifySelectionChanged(); 79 } 80 81 public void setViewport(Rectangle viewport) { 82 synchronized (this) { 83 this.mViewport = viewport; 84 } 85 notifyViewportChanged(); 86 } 87 88 public void setZoom(double newZoom) { 89 Point zoomPoint = null; 90 synchronized (this) { 91 if (mTree != null && mViewport != null) { 92 zoomPoint = 93 new Point(mViewport.x + mViewport.width / 2, mViewport.y + mViewport.height / 2); 94 } 95 } 96 zoomOnPoint(newZoom, zoomPoint); 97 } 98 99 public void zoomOnPoint(double newZoom, Point zoomPoint) { 100 synchronized (this) { 101 if (mTree != null && this.mViewport != null) { 102 if (newZoom < MIN_ZOOM) { 103 newZoom = MIN_ZOOM; 104 } 105 if (newZoom > MAX_ZOOM) { 106 newZoom = MAX_ZOOM; 107 } 108 mViewport.x = zoomPoint.x - (zoomPoint.x - mViewport.x) * mZoom / newZoom; 109 mViewport.y = zoomPoint.y - (zoomPoint.y - mViewport.y) * mZoom / newZoom; 110 mViewport.width = mViewport.width * mZoom / newZoom; 111 mViewport.height = mViewport.height * mZoom / newZoom; 112 mZoom = newZoom; 113 } 114 } 115 notifyZoomChanged(); 116 } 117 118 public DrawableViewNode getTree() { 119 synchronized (this) { 120 return mTree; 121 } 122 } 123 124 public Window getWindow() { 125 synchronized (this) { 126 return mWindow; 127 } 128 } 129 130 public Rectangle getViewport() { 131 synchronized (this) { 132 return mViewport; 133 } 134 } 135 136 public double getZoom() { 137 synchronized (this) { 138 return mZoom; 139 } 140 } 141 142 public DrawableViewNode getSelection() { 143 synchronized (this) { 144 return mSelectedNode; 145 } 146 } 147 148 public static interface ITreeChangeListener { 149 public void treeChanged(); 150 151 public void selectionChanged(); 152 153 public void viewportChanged(); 154 155 public void zoomChanged(); 156 } 157 158 private ITreeChangeListener[] getTreeChangeListenerList() { 159 ITreeChangeListener[] listeners = null; 160 synchronized (mTreeChangeListeners) { 161 if (mTreeChangeListeners.size() == 0) { 162 return null; 163 } 164 listeners = 165 mTreeChangeListeners.toArray(new ITreeChangeListener[mTreeChangeListeners.size()]); 166 } 167 return listeners; 168 } 169 170 public void notifyTreeChanged() { 171 ITreeChangeListener[] listeners = getTreeChangeListenerList(); 172 if (listeners != null) { 173 for (int i = 0; i < listeners.length; i++) { 174 listeners[i].treeChanged(); 175 } 176 } 177 } 178 179 public void notifySelectionChanged() { 180 ITreeChangeListener[] listeners = getTreeChangeListenerList(); 181 if (listeners != null) { 182 for (int i = 0; i < listeners.length; i++) { 183 listeners[i].selectionChanged(); 184 } 185 } 186 } 187 188 public void notifyViewportChanged() { 189 ITreeChangeListener[] listeners = getTreeChangeListenerList(); 190 if (listeners != null) { 191 for (int i = 0; i < listeners.length; i++) { 192 listeners[i].viewportChanged(); 193 } 194 } 195 } 196 197 public void notifyZoomChanged() { 198 ITreeChangeListener[] listeners = getTreeChangeListenerList(); 199 if (listeners != null) { 200 for (int i = 0; i < listeners.length; i++) { 201 listeners[i].zoomChanged(); 202 } 203 } 204 } 205 206 public void addTreeChangeListener(ITreeChangeListener listener) { 207 synchronized (mTreeChangeListeners) { 208 mTreeChangeListeners.add(listener); 209 } 210 } 211 212 public void removeTreeChangeListener(ITreeChangeListener listener) { 213 synchronized (mTreeChangeListeners) { 214 mTreeChangeListeners.remove(listener); 215 } 216 } 217 } 218