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.ui; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.ddmuilib.ImageLoader; 21 import com.android.hierarchyviewerlib.HierarchyViewerDirector; 22 import com.android.hierarchyviewerlib.device.Window; 23 import com.android.hierarchyviewerlib.models.DeviceSelectionModel; 24 import com.android.hierarchyviewerlib.models.DeviceSelectionModel.IWindowChangeListener; 25 26 import org.eclipse.jface.viewers.IFontProvider; 27 import org.eclipse.jface.viewers.ILabelProvider; 28 import org.eclipse.jface.viewers.ILabelProviderListener; 29 import org.eclipse.jface.viewers.ITreeContentProvider; 30 import org.eclipse.jface.viewers.TreeSelection; 31 import org.eclipse.jface.viewers.TreeViewer; 32 import org.eclipse.jface.viewers.Viewer; 33 import org.eclipse.swt.SWT; 34 import org.eclipse.swt.events.ControlAdapter; 35 import org.eclipse.swt.events.ControlEvent; 36 import org.eclipse.swt.events.ControlListener; 37 import org.eclipse.swt.events.DisposeEvent; 38 import org.eclipse.swt.events.DisposeListener; 39 import org.eclipse.swt.events.SelectionEvent; 40 import org.eclipse.swt.events.SelectionListener; 41 import org.eclipse.swt.graphics.Font; 42 import org.eclipse.swt.graphics.FontData; 43 import org.eclipse.swt.graphics.Image; 44 import org.eclipse.swt.layout.FillLayout; 45 import org.eclipse.swt.widgets.Composite; 46 import org.eclipse.swt.widgets.Display; 47 import org.eclipse.swt.widgets.Tree; 48 import org.eclipse.swt.widgets.TreeItem; 49 50 public class DeviceSelector extends Composite implements IWindowChangeListener, SelectionListener { 51 private TreeViewer mTreeViewer; 52 53 private Tree mTree; 54 55 private DeviceSelectionModel mModel; 56 57 private Font mBoldFont; 58 59 private Image mDeviceImage; 60 61 private Image mEmulatorImage; 62 63 private final static int ICON_WIDTH = 16; 64 65 private boolean mDoTreeViewStuff; 66 67 private boolean mDoPixelPerfectStuff; 68 69 private class ContentProvider implements ITreeContentProvider, ILabelProvider, IFontProvider { 70 @Override 71 public Object[] getChildren(Object parentElement) { 72 if (parentElement instanceof IDevice && mDoTreeViewStuff) { 73 Window[] list = mModel.getWindows((IDevice) parentElement); 74 if (list != null) { 75 return list; 76 } 77 } 78 return new Object[0]; 79 } 80 81 @Override 82 public Object getParent(Object element) { 83 if (element instanceof Window) { 84 return ((Window) element).getDevice(); 85 } 86 return null; 87 } 88 89 @Override 90 public boolean hasChildren(Object element) { 91 if (element instanceof IDevice && mDoTreeViewStuff) { 92 Window[] list = mModel.getWindows((IDevice) element); 93 if (list != null) { 94 return list.length != 0; 95 } 96 } 97 return false; 98 } 99 100 @Override 101 public Object[] getElements(Object inputElement) { 102 if (inputElement instanceof DeviceSelectionModel) { 103 return mModel.getDevices(); 104 } 105 return new Object[0]; 106 } 107 108 @Override 109 public void dispose() { 110 // pass 111 } 112 113 @Override 114 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 115 // pass 116 } 117 118 @Override 119 public Image getImage(Object element) { 120 if (element instanceof IDevice) { 121 if (((IDevice) element).isEmulator()) { 122 return mEmulatorImage; 123 } 124 return mDeviceImage; 125 } 126 return null; 127 } 128 129 @Override 130 public String getText(Object element) { 131 if (element instanceof IDevice) { 132 return ((IDevice) element).toString(); 133 } else if (element instanceof Window) { 134 return ((Window) element).getTitle(); 135 } 136 return null; 137 } 138 139 @Override 140 public Font getFont(Object element) { 141 if (element instanceof Window) { 142 int focusedWindow = mModel.getFocusedWindow(((Window) element).getDevice()); 143 if (focusedWindow == ((Window) element).getHashCode()) { 144 return mBoldFont; 145 } 146 } 147 return null; 148 } 149 150 @Override 151 public void addListener(ILabelProviderListener listener) { 152 // pass 153 } 154 155 @Override 156 public boolean isLabelProperty(Object element, String property) { 157 // pass 158 return false; 159 } 160 161 @Override 162 public void removeListener(ILabelProviderListener listener) { 163 // pass 164 } 165 } 166 167 public DeviceSelector(Composite parent, boolean doTreeViewStuff, boolean doPixelPerfectStuff) { 168 super(parent, SWT.NONE); 169 this.mDoTreeViewStuff = doTreeViewStuff; 170 this.mDoPixelPerfectStuff = doPixelPerfectStuff; 171 setLayout(new FillLayout()); 172 mTreeViewer = new TreeViewer(this, SWT.SINGLE); 173 mTreeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS); 174 175 mTree = mTreeViewer.getTree(); 176 mTree.setLinesVisible(true); 177 mTree.addSelectionListener(this); 178 179 addDisposeListener(mDisposeListener); 180 181 loadResources(); 182 183 mModel = DeviceSelectionModel.getModel(); 184 ContentProvider contentProvider = new ContentProvider(); 185 mTreeViewer.setContentProvider(contentProvider); 186 mTreeViewer.setLabelProvider(contentProvider); 187 mModel.addWindowChangeListener(this); 188 mTreeViewer.setInput(mModel); 189 190 addControlListener(mControlListener); 191 } 192 193 public void loadResources() { 194 Display display = Display.getDefault(); 195 Font systemFont = display.getSystemFont(); 196 FontData[] fontData = systemFont.getFontData(); 197 FontData[] newFontData = new FontData[fontData.length]; 198 for (int i = 0; i < fontData.length; i++) { 199 newFontData[i] = 200 new FontData(fontData[i].getName(), fontData[i].getHeight(), fontData[i] 201 .getStyle() 202 | SWT.BOLD); 203 } 204 mBoldFont = new Font(Display.getDefault(), newFontData); 205 206 ImageLoader loader = ImageLoader.getDdmUiLibLoader(); 207 mDeviceImage = 208 loader.loadImage(display, "device.png", ICON_WIDTH, ICON_WIDTH, display //$NON-NLS-1$ 209 .getSystemColor(SWT.COLOR_RED)); 210 211 mEmulatorImage = 212 loader.loadImage(display, "emulator.png", ICON_WIDTH, ICON_WIDTH, display //$NON-NLS-1$ 213 .getSystemColor(SWT.COLOR_BLUE)); 214 } 215 216 private DisposeListener mDisposeListener = new DisposeListener() { 217 @Override 218 public void widgetDisposed(DisposeEvent e) { 219 mModel.removeWindowChangeListener(DeviceSelector.this); 220 mBoldFont.dispose(); 221 } 222 }; 223 224 // If the window gets too small, hide the data, otherwise SWT throws an 225 // ERROR. 226 227 private ControlListener mControlListener = new ControlAdapter() { 228 private boolean noInput = false; 229 230 @Override 231 public void controlResized(ControlEvent e) { 232 if (getBounds().height <= 38) { 233 mTreeViewer.setInput(null); 234 noInput = true; 235 } else if (noInput) { 236 mTreeViewer.setInput(mModel); 237 noInput = false; 238 } 239 } 240 }; 241 242 @Override 243 public boolean setFocus() { 244 return mTree.setFocus(); 245 } 246 247 public void setMode(boolean doTreeViewStuff, boolean doPixelPerfectStuff) { 248 if (this.mDoTreeViewStuff != doTreeViewStuff 249 || this.mDoPixelPerfectStuff != doPixelPerfectStuff) { 250 final boolean expandAll = !this.mDoTreeViewStuff && doTreeViewStuff; 251 this.mDoTreeViewStuff = doTreeViewStuff; 252 this.mDoPixelPerfectStuff = doPixelPerfectStuff; 253 Display.getDefault().syncExec(new Runnable() { 254 @Override 255 public void run() { 256 mTreeViewer.refresh(); 257 if (expandAll) { 258 mTreeViewer.expandAll(); 259 } 260 } 261 }); 262 } 263 } 264 265 @Override 266 public void deviceConnected(final IDevice device) { 267 Display.getDefault().syncExec(new Runnable() { 268 @Override 269 public void run() { 270 mTreeViewer.refresh(); 271 mTreeViewer.setExpandedState(device, true); 272 } 273 }); 274 } 275 276 @Override 277 public void deviceChanged(final IDevice device) { 278 Display.getDefault().syncExec(new Runnable() { 279 @Override 280 public void run() { 281 TreeSelection selection = (TreeSelection) mTreeViewer.getSelection(); 282 mTreeViewer.refresh(device); 283 if (selection.getFirstElement() instanceof Window 284 && ((Window) selection.getFirstElement()).getDevice() == device) { 285 mTreeViewer.setSelection(selection, true); 286 } 287 } 288 }); 289 } 290 291 @Override 292 public void deviceDisconnected(final IDevice device) { 293 Display.getDefault().syncExec(new Runnable() { 294 @Override 295 public void run() { 296 mTreeViewer.refresh(); 297 } 298 }); 299 } 300 301 @Override 302 public void focusChanged(final IDevice device) { 303 Display.getDefault().syncExec(new Runnable() { 304 @Override 305 public void run() { 306 TreeSelection selection = (TreeSelection) mTreeViewer.getSelection(); 307 mTreeViewer.refresh(device); 308 if (selection.getFirstElement() instanceof Window 309 && ((Window) selection.getFirstElement()).getDevice() == device) { 310 mTreeViewer.setSelection(selection, true); 311 } 312 } 313 }); 314 } 315 316 @Override 317 public void selectionChanged(IDevice device, Window window) { 318 // pass 319 } 320 321 @Override 322 public void widgetDefaultSelected(SelectionEvent e) { 323 Object selection = ((TreeItem) e.item).getData(); 324 if (selection instanceof IDevice && mDoPixelPerfectStuff) { 325 HierarchyViewerDirector.getDirector().loadPixelPerfectData((IDevice) selection); 326 } else if (selection instanceof Window && mDoTreeViewStuff) { 327 HierarchyViewerDirector.getDirector().loadViewTreeData((Window) selection); 328 } 329 } 330 331 @Override 332 public void widgetSelected(SelectionEvent e) { 333 Object selection = ((TreeItem) e.item).getData(); 334 if (selection instanceof IDevice) { 335 mModel.setSelection((IDevice) selection, null); 336 } else if (selection instanceof Window) { 337 mModel.setSelection(((Window) selection).getDevice(), (Window) selection); 338 } 339 } 340 } 341