diff options
Diffstat (limited to 'hierarchyviewer2/libs')
53 files changed, 1840 insertions, 521 deletions
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java deleted file mode 100644 index a50478e..0000000 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ComponentRegistry.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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; - -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 - * Hierarchy Viewer. Components register themselves with the class using the - * setters and can be accessed using the getters. - */ -public class ComponentRegistry { - - private static HierarchyViewerDirector director; - - private static DeviceSelectionModel deviceSelectionModel; - - private static PixelPerfectModel pixelPerfectModel; - - private static TreeViewModel treeViewModel; - - public static HierarchyViewerDirector getDirector() { - return director; - } - - public static void setDirector(HierarchyViewerDirector director) { - ComponentRegistry.director = director; - } - - public static DeviceSelectionModel getDeviceSelectionModel() { - return deviceSelectionModel; - } - - public static void setDeviceSelectionModel(DeviceSelectionModel deviceSelectionModel) { - ComponentRegistry.deviceSelectionModel = deviceSelectionModel; - } - - public static void setPixelPerfectModel(PixelPerfectModel pixelPerfectModel) { - ComponentRegistry.pixelPerfectModel = pixelPerfectModel; - } - - 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 48a45dd..29b35f1 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java @@ -28,18 +28,28 @@ import com.android.hierarchyviewerlib.device.Window; import com.android.hierarchyviewerlib.device.WindowUpdater; import com.android.hierarchyviewerlib.device.DeviceBridge.ViewServerInfo; import com.android.hierarchyviewerlib.device.WindowUpdater.IWindowChangeListener; +import com.android.hierarchyviewerlib.models.DeviceSelectionModel; +import com.android.hierarchyviewerlib.models.PixelPerfectModel; +import com.android.hierarchyviewerlib.models.TreeViewModel; import com.android.hierarchyviewerlib.ui.CaptureDisplay; +import com.android.hierarchyviewerlib.ui.TreeView; +import com.android.hierarchyviewerlib.ui.util.DrawableViewNode; +import com.android.hierarchyviewerlib.ui.util.PsdFile; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.util.HashSet; /** * This is the class where most of the logic resides. @@ -47,6 +57,8 @@ import java.io.IOException; public abstract class HierarchyViewerDirector implements IDeviceChangeListener, IWindowChangeListener { + protected static HierarchyViewerDirector director; + public static final String TAG = "hierarchyviewer"; private int pixelPerfectRefreshesInProgress = 0; @@ -57,6 +69,10 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, public abstract String getAdbLocation(); + public static HierarchyViewerDirector getDirector() { + return director; + } + public void initDebugBridge() { DeviceBridge.initDebugBridge(getAdbLocation()); } @@ -80,23 +96,20 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, DeviceBridge.stopListenForDevices(this); } - public abstract void executeInBackground(Runnable task); + public abstract void executeInBackground(String taskName, Runnable task); public void deviceConnected(final IDevice device) { - if (device.isOnline()) { - DeviceBridge.setupDeviceForward(device); - if (!DeviceBridge.isViewServerRunning(device)) { - if (!DeviceBridge.startViewServer(device)) { - // Let's do something interesting here... Try again in 2 - // seconds. - executeInBackground(new Runnable() { - public void run() { + executeInBackground("Connecting device", new Runnable() { + public void run() { + if (device.isOnline()) { + DeviceBridge.setupDeviceForward(device); + if (!DeviceBridge.isViewServerRunning(device)) { + if (!DeviceBridge.startViewServer(device)) { + // Let's do something interesting here... Try again + // in 2 seconds. try { Thread.sleep(2000); } catch (InterruptedException e) { - Log.e(TAG, "Unable to debug device " + device); - DeviceBridge.removeDeviceForward(device); - return; } if (!DeviceBridge.startViewServer(device)) { Log.e(TAG, "Unable to debug device " + device); @@ -104,46 +117,49 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, } else { loadViewServerInfoAndWindows(device); } + return; } - }); - return; + } + loadViewServerInfoAndWindows(device); } } - loadViewServerInfoAndWindows(device); - } + }); } private void loadViewServerInfoAndWindows(final IDevice device) { - executeInBackground(new Runnable() { - public void run() { - ViewServerInfo viewServerInfo = DeviceBridge.loadViewServerInfo(device); - if (viewServerInfo == null) { - return; - } - Window[] windows = DeviceBridge.loadWindows(device); - ComponentRegistry.getDeviceSelectionModel().addDevice(device, windows); - if (viewServerInfo.protocolVersion >= 3) { - WindowUpdater.startListenForWindowChanges(HierarchyViewerDirector.this, device); - focusChanged(device); - } - } - }); - } - public void deviceDisconnected(IDevice device) { - ViewServerInfo viewServerInfo = DeviceBridge.getViewServerInfo(device); + ViewServerInfo viewServerInfo = DeviceBridge.loadViewServerInfo(device); if (viewServerInfo == null) { return; } + Window[] windows = DeviceBridge.loadWindows(device); + DeviceSelectionModel.getModel().addDevice(device, windows); if (viewServerInfo.protocolVersion >= 3) { - WindowUpdater.stopListenForWindowChanges(this, device); - } - DeviceBridge.removeDeviceForward(device); - DeviceBridge.removeViewServerInfo(device); - ComponentRegistry.getDeviceSelectionModel().removeDevice(device); - if (ComponentRegistry.getPixelPerfectModel().getDevice() == device) { - ComponentRegistry.getPixelPerfectModel().setData(null, null, null); + WindowUpdater.startListenForWindowChanges(HierarchyViewerDirector.this, device); + focusChanged(device); } + + } + + public void deviceDisconnected(final IDevice device) { + executeInBackground("Disconnecting device", new Runnable() { + public void run() { + ViewServerInfo viewServerInfo = DeviceBridge.getViewServerInfo(device); + if (viewServerInfo != null && viewServerInfo.protocolVersion >= 3) { + WindowUpdater.stopListenForWindowChanges(HierarchyViewerDirector.this, device); + } + DeviceBridge.removeDeviceForward(device); + DeviceBridge.removeViewServerInfo(device); + DeviceSelectionModel.getModel().removeDevice(device); + if (PixelPerfectModel.getModel().getDevice() == device) { + PixelPerfectModel.getModel().setData(null, null, null); + } + Window treeViewWindow = TreeViewModel.getModel().getWindow(); + if (treeViewWindow != null && treeViewWindow.getDevice() == device) { + TreeViewModel.getModel().setData(null, null); + } + } + }); } public void deviceChanged(IDevice device, int changeMask) { @@ -153,48 +169,63 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, } public void windowsChanged(final IDevice device) { - executeInBackground(new Runnable() { + executeInBackground("Refreshing windows", new Runnable() { public void run() { Window[] windows = DeviceBridge.loadWindows(device); - ComponentRegistry.getDeviceSelectionModel().updateDevice(device, windows); + DeviceSelectionModel.getModel().updateDevice(device, windows); } }); } public void focusChanged(final IDevice device) { - executeInBackground(new Runnable() { + executeInBackground("Updating focus", new Runnable() { public void run() { int focusedWindow = DeviceBridge.getFocusedWindow(device); - ComponentRegistry.getDeviceSelectionModel().updateFocusedWindow(device, - focusedWindow); + DeviceSelectionModel.getModel().updateFocusedWindow(device, focusedWindow); } }); + } - // Some interesting logic here. We don't want to refresh the pixel - // perfect view 1000 times in a row if the focus keeps changing. We just - // want it to refresh following the last focus change. - boolean proceed = false; - synchronized (this) { - if (pixelPerfectRefreshesInProgress <= 1) { - proceed = true; - pixelPerfectRefreshesInProgress++; + public void refreshPixelPerfect() { + final IDevice device = PixelPerfectModel.getModel().getDevice(); + if (device != null) { + // Some interesting logic here. We don't want to refresh the pixel + // perfect view 1000 times in a row if the focus keeps changing. We + // just + // want it to refresh following the last focus change. + boolean proceed = false; + synchronized (this) { + if (pixelPerfectRefreshesInProgress <= 1) { + proceed = true; + pixelPerfectRefreshesInProgress++; + } } - } - if (proceed) { - executeInBackground(new Runnable() { - public void run() { - if (ComponentRegistry.getDeviceSelectionModel().getFocusedWindow(device) != -1 - && device == ComponentRegistry.getPixelPerfectModel().getDevice()) { - ViewNode viewNode = - DeviceBridge.loadWindowData(Window.getFocusedWindow(device)); + if (proceed) { + executeInBackground("Refreshing pixel perfect screenshot", new Runnable() { + public void run() { Image screenshotImage = getScreenshotImage(device); if (screenshotImage != null) { - ComponentRegistry.getPixelPerfectModel().setFocusData(screenshotImage, - viewNode); + PixelPerfectModel.getModel().setImage(screenshotImage); + } + synchronized (HierarchyViewerDirector.this) { + pixelPerfectRefreshesInProgress--; } } - synchronized (HierarchyViewerDirector.this) { - pixelPerfectRefreshesInProgress--; + + }); + } + } + } + + public void refreshPixelPerfectTree() { + final IDevice device = PixelPerfectModel.getModel().getDevice(); + if (device != null) { + executeInBackground("Refreshing pixel perfect tree", new Runnable() { + public void run() { + ViewNode viewNode = + DeviceBridge.loadWindowData(Window.getFocusedWindow(device)); + if (viewNode != null) { + PixelPerfectModel.getModel().setTree(viewNode); } } @@ -203,14 +234,15 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, } public void loadPixelPerfectData(final IDevice device) { - executeInBackground(new Runnable() { + executeInBackground("Loading pixel perfect data", new Runnable() { public void run() { Image screenshotImage = getScreenshotImage(device); if (screenshotImage != null) { ViewNode viewNode = DeviceBridge.loadWindowData(Window.getFocusedWindow(device)); - ComponentRegistry.getPixelPerfectModel().setData(device, screenshotImage, - viewNode); + if (viewNode != null) { + PixelPerfectModel.getModel().setData(device, screenshotImage, viewNode); + } } } }); @@ -248,13 +280,14 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, } public void loadViewTreeData(final Window window) { - executeInBackground(new Runnable() { + executeInBackground("Loading view hierarchy", new Runnable() { public void run() { ViewNode viewNode = DeviceBridge.loadWindowData(window); if (viewNode != null) { DeviceBridge.loadProfileData(window, viewNode); - ComponentRegistry.getTreeViewModel().setData(window, viewNode); + viewNode.setViewCount(); + TreeViewModel.getModel().setData(window, viewNode); } } }); @@ -270,11 +303,12 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, fileDialog.setFilterNames(new String[] { "Image (*.jpg, *.jpeg, *.png, *.gif, *.bmp)" }); + fileDialog.setText("Choose an overlay image"); String fileName = fileDialog.open(); if (fileName != null) { try { Image image = new Image(Display.getDefault(), fileName); - ComponentRegistry.getPixelPerfectModel().setOverlayImage(image); + PixelPerfectModel.getModel().setOverlayImage(image); } catch (SWTException e) { Log.e(TAG, "Unable to load image from " + fileName); } @@ -284,14 +318,14 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, } public void showCapture(final Shell shell, final ViewNode viewNode) { - executeInBackground(new Runnable() { + executeInBackground("Capturing node", new Runnable() { public void run() { final Image image = DeviceBridge.loadCapture(viewNode.window, viewNode); if (image != null) { viewNode.image = image; // Force the layout viewer to redraw. - ComponentRegistry.getTreeViewModel().notifySelectionChanged(); + TreeViewModel.getModel().notifySelectionChanged(); Display.getDefault().asyncExec(new Runnable() { public void run() { @@ -302,4 +336,231 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener, } }); } + + public void showCapture(Shell shell) { + DrawableViewNode viewNode = TreeViewModel.getModel().getSelection(); + if (viewNode != null) { + showCapture(shell, viewNode.viewNode); + } + } + + public void refreshWindows() { + executeInBackground("Refreshing windows", new Runnable() { + public void run() { + IDevice[] devicesA = DeviceSelectionModel.getModel().getDevices(); + IDevice[] devicesB = DeviceBridge.getDevices(); + HashSet<IDevice> deviceSet = new HashSet<IDevice>(); + for (int i = 0; i < devicesB.length; i++) { + deviceSet.add(devicesB[i]); + } + for (int i = 0; i < devicesA.length; i++) { + if (deviceSet.contains(devicesA[i])) { + windowsChanged(devicesA[i]); + deviceSet.remove(devicesA[i]); + } else { + deviceDisconnected(devicesA[i]); + } + } + for (IDevice device : deviceSet) { + deviceConnected(device); + } + } + }); + } + + public void loadViewHierarchy() { + Window window = DeviceSelectionModel.getModel().getSelectedWindow(); + if (window != null) { + loadViewTreeData(window); + } + } + + public void inspectScreenshot() { + IDevice device = DeviceSelectionModel.getModel().getSelectedDevice(); + if (device != null) { + loadPixelPerfectData(device); + } + } + + public void saveTreeView(final Shell shell) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + final DrawableViewNode viewNode = TreeViewModel.getModel().getTree(); + if (viewNode != null) { + FileDialog fileDialog = new FileDialog(shell, SWT.SAVE); + fileDialog.setFilterExtensions(new String[] { + "*.png" + }); + fileDialog.setFilterNames(new String[] { + "Portable Network Graphics File (*.png)" + }); + fileDialog.setText("Choose where to save the tree image"); + final String fileName = fileDialog.open(); + if (fileName != null) { + executeInBackground("Saving tree view", new Runnable() { + public void run() { + Image image = TreeView.paintToImage(viewNode); + ImageLoader imageLoader = new ImageLoader(); + imageLoader.data = new ImageData[] { + image.getImageData() + }; + String extensionedFileName = fileName; + if (!extensionedFileName.toLowerCase().endsWith(".png")) { + extensionedFileName += ".png"; + } + try { + imageLoader.save(extensionedFileName, SWT.IMAGE_PNG); + } catch (SWTException e) { + Log.e(TAG, "Unable to save tree view as a PNG image at " + + fileName); + } + image.dispose(); + } + }); + } + } + } + }); + } + + public void savePixelPerfect(final Shell shell) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + Image untouchableImage = PixelPerfectModel.getModel().getImage(); + if (untouchableImage != null) { + final ImageData imageData = untouchableImage.getImageData(); + FileDialog fileDialog = new FileDialog(shell, SWT.SAVE); + fileDialog.setFilterExtensions(new String[] { + "*.png" + }); + fileDialog.setFilterNames(new String[] { + "Portable Network Graphics File (*.png)" + }); + fileDialog.setText("Choose where to save the screenshot"); + final String fileName = fileDialog.open(); + if (fileName != null) { + executeInBackground("Saving pixel perfect", new Runnable() { + public void run() { + ImageLoader imageLoader = new ImageLoader(); + imageLoader.data = new ImageData[] { + imageData + }; + String extensionedFileName = fileName; + if (!extensionedFileName.toLowerCase().endsWith(".png")) { + extensionedFileName += ".png"; + } + try { + imageLoader.save(extensionedFileName, SWT.IMAGE_PNG); + } catch (SWTException e) { + Log.e(TAG, "Unable to save tree view as a PNG image at " + + fileName); + } + } + }); + } + } + } + }); + } + + public void capturePSD(final Shell shell) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + final Window window = TreeViewModel.getModel().getWindow(); + if (window != null) { + FileDialog fileDialog = new FileDialog(shell, SWT.SAVE); + fileDialog.setFilterExtensions(new String[] { + "*.psd" + }); + fileDialog.setFilterNames(new String[] { + "Photoshop Document (*.psd)" + }); + fileDialog.setText("Choose where to save the window layers"); + final String fileName = fileDialog.open(); + if (fileName != null) { + executeInBackground("Saving window layers", new Runnable() { + public void run() { + PsdFile psdFile = DeviceBridge.captureLayers(window); + if (psdFile != null) { + String extensionedFileName = fileName; + if (!extensionedFileName.toLowerCase().endsWith(".psd")) { + extensionedFileName += ".psd"; + } + try { + psdFile.write(new FileOutputStream(extensionedFileName)); + } catch (FileNotFoundException e) { + Log.e(TAG, "Unable to write to file " + fileName); + } + } + } + }); + } + } + } + }); + } + + public void reloadViewHierarchy() { + Window window = TreeViewModel.getModel().getWindow(); + if (window != null) { + loadViewTreeData(window); + } + } + + public void invalidateCurrentNode() { + final DrawableViewNode selectedNode = TreeViewModel.getModel().getSelection(); + if (selectedNode != null) { + executeInBackground("Invalidating view", new Runnable() { + public void run() { + DeviceBridge.invalidateView(selectedNode.viewNode); + } + }); + } + } + + public void relayoutCurrentNode() { + final DrawableViewNode selectedNode = TreeViewModel.getModel().getSelection(); + if (selectedNode != null) { + executeInBackground("Request layout", new Runnable() { + public void run() { + DeviceBridge.requestLayout(selectedNode.viewNode); + } + }); + } + } + + public void loadAllViews() { + executeInBackground("Loading all views", new Runnable() { + public void run() { + DrawableViewNode tree = TreeViewModel.getModel().getTree(); + if (tree != null) { + loadViewRecursive(tree.viewNode); + // Force the layout viewer to redraw. + TreeViewModel.getModel().notifySelectionChanged(); + } + } + }); + } + + private void loadViewRecursive(ViewNode viewNode) { + Image image = DeviceBridge.loadCapture(viewNode.window, viewNode); + if (image == null) { + return; + } + viewNode.image = image; + final int N = viewNode.children.size(); + for (int i = 0; i < N; i++) { + loadViewRecursive(viewNode.children.get(i)); + } + } + + public void filterNodes(String filterText) { + DrawableViewNode tree = TreeViewModel.getModel().getTree(); + if (tree != null) { + tree.viewNode.filter(filterText); + // Force redraw + TreeViewModel.getModel().notifySelectionChanged(); + } + } + } 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 23c6f07..c2cb668 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceBridge.java @@ -23,17 +23,26 @@ import com.android.ddmlib.Log; import com.android.ddmlib.MultiLineReceiver; import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; +import com.android.hierarchyviewerlib.ui.util.PsdFile; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.imageio.ImageIO; + /** * A bridge to the device. */ @@ -120,7 +129,7 @@ public class DeviceBridge { } catch (AdbCommandRejectedException e) { Log.e(TAG, String.format("Adb rejected forward command for device %1$s: %2$s", device, e.getMessage())); - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, String.format("Failed to create forward for device %1$s: %2$s", device, e.getMessage())); } @@ -139,7 +148,7 @@ public class DeviceBridge { Log.e(TAG, "Timeout removing port forwarding for " + device); } catch (AdbCommandRejectedException e) { // In this case, we want to fail silently. - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, String.format("Failed to remove forward for device %1$s: %2$s", device, e.getMessage())); } @@ -354,7 +363,7 @@ public class DeviceBridge { if (serverInfo.protocolVersion < 3) { windows.add(Window.getFocusedWindow(device)); } - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, "Unable to load the window list from device " + device); } finally { if (connection != null) { @@ -385,7 +394,7 @@ public class DeviceBridge { return -1; } return (int) Long.parseLong(line.substring(0, line.indexOf(' ')), 16); - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, "Unable to get the focused window from device " + device); } finally { if (connection != null) { @@ -425,8 +434,12 @@ public class DeviceBridge { while (currentNode.parent != null) { currentNode = currentNode.parent; } + ViewServerInfo serverInfo = getViewServerInfo(window.getDevice()); + if (serverInfo != null) { + currentNode.protocolVersion = serverInfo.protocolVersion; + } return currentNode; - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, "Unable to load window data for window " + window.getTitle() + " on device " + window.getDevice()); } finally { @@ -456,7 +469,7 @@ public class DeviceBridge { } return ret; } - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, "Unable to load profiling data for window " + window.getTitle() + " on device " + window.getDevice()); } finally { @@ -510,4 +523,104 @@ public class DeviceBridge { return null; } + public static PsdFile captureLayers(Window window) { + DeviceConnection connection = null; + DataInputStream in = null; + + try { + connection = new DeviceConnection(window.getDevice()); + + connection.sendCommand("CAPTURE_LAYERS " + window.encode()); + + in = + new DataInputStream(new BufferedInputStream(connection.getSocket() + .getInputStream())); + + int width = in.readInt(); + int height = in.readInt(); + + PsdFile psd = new PsdFile(width, height); + + while (readLayer(in, psd)) { + } + + return psd; + } catch (Exception e) { + Log.e(TAG, "Unable to capture layers for window " + window.getTitle() + " on device " + + window.getDevice()); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception ex) { + } + } + connection.close(); + } + + return null; + } + + private static boolean readLayer(DataInputStream in, PsdFile psd) { + try { + if (in.read() == 2) { + return false; + } + String name = in.readUTF(); + boolean visible = in.read() == 1; + int x = in.readInt(); + int y = in.readInt(); + int dataSize = in.readInt(); + + byte[] data = new byte[dataSize]; + int read = 0; + while (read < dataSize) { + read += in.read(data, read, dataSize - read); + } + + ByteArrayInputStream arrayIn = new ByteArrayInputStream(data); + BufferedImage chunk = ImageIO.read(arrayIn); + + // Ensure the image is in the right format + BufferedImage image = + new BufferedImage(chunk.getWidth(), chunk.getHeight(), + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.drawImage(chunk, null, 0, 0); + g.dispose(); + + psd.addLayer(name, image, new Point(x, y), visible); + + return true; + } catch (Exception e) { + return false; + } + } + + public static void invalidateView(ViewNode viewNode) { + DeviceConnection connection = null; + try { + connection = new DeviceConnection(viewNode.window.getDevice()); + connection.sendCommand("INVALIDATE " + viewNode.window.encode() + " " + viewNode); + } catch (Exception e) { + Log.e(TAG, "Unable to invalidate view " + viewNode + " in window " + viewNode.window + + " on device " + viewNode.window.getDevice()); + } finally { + connection.close(); + } + } + + public static void requestLayout(ViewNode viewNode) { + DeviceConnection connection = null; + try { + connection = new DeviceConnection(viewNode.window.getDevice()); + connection.sendCommand("REQUEST_LAYOUT " + viewNode.window.encode() + " " + viewNode); + } catch (Exception e) { + Log.e(TAG, "Unable to request layout for node " + viewNode + " in window " + + viewNode.window + " on device " + viewNode.window.getDevice()); + } finally { + connection.close(); + } + } + } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceConnection.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceConnection.java index 18b9619..3080cc1 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceConnection.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DeviceConnection.java @@ -42,8 +42,14 @@ public class DeviceConnection { public DeviceConnection(IDevice device) throws IOException { socketChannel = SocketChannel.open(); - socketChannel.connect(new InetSocketAddress("127.0.0.1", DeviceBridge - .getDeviceLocalPort(device))); + int port = DeviceBridge.getDeviceLocalPort(device); + + if (port == -1) { + throw new IOException(); + } + + socketChannel.connect(new InetSocketAddress("127.0.0.1", port)); + socketChannel.socket().setSoTimeout(120000); } public BufferedReader getInputStream() throws IOException { 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 2872952..6457159 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewNode.java @@ -111,6 +111,12 @@ public class ViewNode { public int imageReferences = 1; + public int viewCount; + + public boolean filtered; + + public int protocolVersion; + public ViewNode(Window window, ViewNode parent, String data) { this.window = window; this.parent = parent; @@ -132,7 +138,7 @@ public class ViewNode { public void dispose() { final int N = children.size(); - for(int i = 0; i<N; i++) { + for (int i = 0; i < N; i++) { children.get(i).dispose(); } dereferenceImage(); @@ -179,59 +185,68 @@ public class ViewNode { id = namedProperties.get("mID").value; - left = namedProperties.containsKey("mLeft") ? - getInt("mLeft", 0) : getInt("layout:mLeft", 0); - top = namedProperties.containsKey("mTop") ? - getInt("mTop", 0) : getInt("layout:mTop", 0); - width = namedProperties.containsKey("getWidth()") ? - getInt("getWidth()", 0) : getInt("layout:getWidth()", 0); - height = namedProperties.containsKey("getHeight()") ? - getInt("getHeight()", 0) : getInt("layout:getHeight()", 0); - scrollX = namedProperties.containsKey("mScrollX") ? - getInt("mScrollX", 0) : getInt("scrolling:mScrollX", 0); - scrollY = namedProperties.containsKey("mScrollY") ? - getInt("mScrollY", 0) : getInt("scrolling:mScrollY", 0); - paddingLeft = namedProperties.containsKey("mPaddingLeft") ? - getInt("mPaddingLeft", 0) : getInt("padding:mPaddingLeft", 0); - paddingRight = namedProperties.containsKey("mPaddingRight") ? - getInt("mPaddingRight", 0) : getInt("padding:mPaddingRight", 0); - paddingTop = namedProperties.containsKey("mPaddingTop") ? - getInt("mPaddingTop", 0) : getInt("padding:mPaddingTop", 0); - paddingBottom = namedProperties.containsKey("mPaddingBottom") ? - getInt("mPaddingBottom", 0) : getInt("padding:mPaddingBottom", 0); - marginLeft = namedProperties.containsKey("layout_leftMargin") ? - getInt("layout_leftMargin", Integer.MIN_VALUE) : - getInt("layout:layout_leftMargin", Integer.MIN_VALUE); - marginRight = namedProperties.containsKey("layout_rightMargin") ? - getInt("layout_rightMargin", Integer.MIN_VALUE) : - getInt("layout:layout_rightMargin", Integer.MIN_VALUE); - marginTop = namedProperties.containsKey("layout_topMargin") ? - getInt("layout_topMargin", Integer.MIN_VALUE) : - getInt("layout:layout_topMargin", Integer.MIN_VALUE); - marginBottom = namedProperties.containsKey("layout_bottomMargin") ? - getInt("layout_bottomMargin", Integer.MIN_VALUE) : - getInt("layout:layout_bottomMargin", Integer.MIN_VALUE); - baseline = namedProperties.containsKey("getBaseline()") ? - getInt("getBaseline()", 0) : - getInt("layout:getBaseline()", 0); - willNotDraw = namedProperties.containsKey("willNotDraw()") ? - getBoolean("willNotDraw()", false) : - getBoolean("drawing:willNotDraw()", false); - hasFocus = namedProperties.containsKey("hasFocus()") ? - getBoolean("hasFocus()", false) : - getBoolean("focus:hasFocus()", false); + left = + namedProperties.containsKey("mLeft") ? getInt("mLeft", 0) : getInt("layout:mLeft", + 0); + top = namedProperties.containsKey("mTop") ? getInt("mTop", 0) : getInt("layout:mTop", 0); + width = + namedProperties.containsKey("getWidth()") ? getInt("getWidth()", 0) : getInt( + "layout:getWidth()", 0); + height = + namedProperties.containsKey("getHeight()") ? getInt("getHeight()", 0) : getInt( + "layout:getHeight()", 0); + scrollX = + namedProperties.containsKey("mScrollX") ? getInt("mScrollX", 0) : getInt( + "scrolling:mScrollX", 0); + scrollY = + namedProperties.containsKey("mScrollY") ? getInt("mScrollY", 0) : getInt( + "scrolling:mScrollY", 0); + paddingLeft = + namedProperties.containsKey("mPaddingLeft") ? getInt("mPaddingLeft", 0) : getInt( + "padding:mPaddingLeft", 0); + paddingRight = + namedProperties.containsKey("mPaddingRight") ? getInt("mPaddingRight", 0) : getInt( + "padding:mPaddingRight", 0); + paddingTop = + namedProperties.containsKey("mPaddingTop") ? getInt("mPaddingTop", 0) : getInt( + "padding:mPaddingTop", 0); + paddingBottom = + namedProperties.containsKey("mPaddingBottom") ? getInt("mPaddingBottom", 0) + : getInt("padding:mPaddingBottom", 0); + marginLeft = + namedProperties.containsKey("layout_leftMargin") ? getInt("layout_leftMargin", + Integer.MIN_VALUE) : getInt("layout:layout_leftMargin", Integer.MIN_VALUE); + marginRight = + namedProperties.containsKey("layout_rightMargin") ? getInt("layout_rightMargin", + Integer.MIN_VALUE) : getInt("layout:layout_rightMargin", Integer.MIN_VALUE); + marginTop = + namedProperties.containsKey("layout_topMargin") ? getInt("layout_topMargin", + Integer.MIN_VALUE) : getInt("layout:layout_topMargin", Integer.MIN_VALUE); + marginBottom = + namedProperties.containsKey("layout_bottomMargin") ? getInt("layout_bottomMargin", + Integer.MIN_VALUE) + : getInt("layout:layout_bottomMargin", Integer.MIN_VALUE); + baseline = + namedProperties.containsKey("getBaseline()") ? getInt("getBaseline()", 0) : getInt( + "layout:getBaseline()", 0); + willNotDraw = + namedProperties.containsKey("willNotDraw()") ? getBoolean("willNotDraw()", false) + : getBoolean("drawing:willNotDraw()", false); + hasFocus = + namedProperties.containsKey("hasFocus()") ? getBoolean("hasFocus()", false) + : getBoolean("focus:hasFocus()", false); hasMargins = marginLeft != Integer.MIN_VALUE && marginRight != Integer.MIN_VALUE && marginTop != Integer.MIN_VALUE && marginBottom != Integer.MIN_VALUE; - for(String name : namedProperties.keySet()) { + for (String name : namedProperties.keySet()) { int index = name.indexOf(':'); - if(index != -1) { + if (index != -1) { categories.add(name.substring(0, index)); } } - if(categories.size() != 0) { + if (categories.size() != 0) { categories.add(MISCELLANIOUS); } } @@ -278,6 +293,29 @@ public class ViewNode { } } + public void setViewCount() { + viewCount = 1; + final int N = children.size(); + for (int i = 0; i < N; i++) { + ViewNode child = children.get(i); + child.setViewCount(); + viewCount += child.viewCount; + } + } + + public void filter(String text) { + int dotIndex = name.lastIndexOf('.'); + String shortName = (dotIndex == -1) ? name : name.substring(dotIndex + 1); + filtered = + !text.equals("") + && (shortName.toLowerCase().contains(text.toLowerCase()) || (!id + .equals("NO_ID") && id.toLowerCase().contains(text.toLowerCase()))); + final int N = children.size(); + for (int i = 0; i < N; i++) { + children.get(i).filter(text); + } + } + private boolean getBoolean(String name, boolean defaultValue) { Property p = namedProperties.get(name); if (p != null) { diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/DeviceSelectionModel.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/DeviceSelectionModel.java index 7c4f2f6..d8a9a4f 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/DeviceSelectionModel.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/DeviceSelectionModel.java @@ -42,6 +42,15 @@ public class DeviceSelectionModel { private Window selectedWindow; + private static DeviceSelectionModel model; + + public static DeviceSelectionModel getModel() { + if (model == null) { + model = new DeviceSelectionModel(); + } + return model; + } + public void addDevice(IDevice device, Window[] windows) { synchronized (deviceMap) { deviceMap.put(device, windows); @@ -51,23 +60,31 @@ public class DeviceSelectionModel { } public void removeDevice(IDevice device) { + boolean selectionChanged = false; synchronized (deviceMap) { - deviceMap.remove(device); deviceList.remove(device); - focusedWindowHashes.remove(device); - if (selectedDevice == device) { - selectedDevice = null; - selectedWindow = null; + if (!deviceList.contains(device)) { + deviceMap.remove(device); + focusedWindowHashes.remove(device); + if (selectedDevice == device) { + selectedDevice = null; + selectedWindow = null; + selectionChanged = true; + } } } notifyDeviceDisconnected(device); + if (selectionChanged) { + notifySelectionChanged(selectedDevice, selectedWindow); + } } public void updateDevice(IDevice device, Window[] windows) { + boolean selectionChanged = false; synchronized (deviceMap) { deviceMap.put(device, windows); // If the selected window no longer exists, we clear the selection. - if (selectedDevice == device) { + if (selectedDevice == device && selectedWindow != null) { boolean windowStillExists = false; for (int i = 0; i < windows.length && !windowStillExists; i++) { if (windows[i].equals(selectedWindow)) { @@ -77,10 +94,14 @@ public class DeviceSelectionModel { if (!windowStillExists) { selectedDevice = null; selectedWindow = null; + selectionChanged = true; } } } notifyDeviceChanged(device); + if (selectionChanged) { + notifySelectionChanged(selectedDevice, selectedWindow); + } } /* @@ -113,6 +134,8 @@ public class DeviceSelectionModel { public void deviceDisconnected(IDevice device); public void focusChanged(IDevice device); + + public void selectionChanged(IDevice device, Window window); } private WindowChangeListener[] getWindowChangeListenerList() { @@ -164,6 +187,15 @@ public class DeviceSelectionModel { } } + private void notifySelectionChanged(IDevice device, Window window) { + WindowChangeListener[] listeners = getWindowChangeListenerList(); + if (listeners != null) { + for (int i = 0; i < listeners.length; i++) { + listeners[i].selectionChanged(device, window); + } + } + } + public void addWindowChangeListener(WindowChangeListener listener) { synchronized (windowChangeListeners) { windowChangeListeners.add(listener); @@ -208,6 +240,7 @@ public class DeviceSelectionModel { selectedDevice = device; selectedWindow = window; } + notifySelectionChanged(device, window); } public IDevice getSelectedDevice() { 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 e8f8240..7702f49 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/PixelPerfectModel.java @@ -17,7 +17,6 @@ package com.android.hierarchyviewerlib.models; import com.android.ddmlib.IDevice; -import com.android.ddmlib.RawImage; import com.android.hierarchyviewerlib.device.ViewNode; import org.eclipse.swt.graphics.Image; @@ -32,7 +31,7 @@ public class PixelPerfectModel { public static final int MAX_ZOOM = 24; - private static final int DEFAULT_ZOOM = 8; + public static final int DEFAULT_ZOOM = 8; private IDevice device; @@ -53,14 +52,22 @@ public class PixelPerfectModel { private double overlayTransparency = 0.5; + private static PixelPerfectModel model; + + public static PixelPerfectModel getModel() { + if (model == null) { + model = new PixelPerfectModel(); + } + return model; + } + public void setData(final IDevice device, final Image image, final ViewNode viewNode) { + final Image toDispose = this.image; + final Image toDispose2 = this.overlayImage; Display.getDefault().syncExec(new Runnable() { public void run() { synchronized (PixelPerfectModel.this) { PixelPerfectModel.this.device = device; - if (PixelPerfectModel.this.image != null) { - PixelPerfectModel.this.image.dispose(); - } PixelPerfectModel.this.image = image; PixelPerfectModel.this.viewNode = viewNode; if (image != null) { @@ -69,12 +76,28 @@ public class PixelPerfectModel { } else { PixelPerfectModel.this.crosshairLocation = null; } + overlayImage = null; PixelPerfectModel.this.selected = null; zoom = DEFAULT_ZOOM; } } }); notifyImageLoaded(); + if (toDispose != null) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + toDispose.dispose(); + } + }); + } + if (toDispose2 != null) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + toDispose2.dispose(); + } + }); + } + } public void setCrosshairLocation(int x, int y) { @@ -91,20 +114,35 @@ public class PixelPerfectModel { notifySelectionChanged(); } - public void setFocusData(final Image image, final ViewNode viewNode) { + public void setTree(final ViewNode viewNode) { Display.getDefault().syncExec(new Runnable() { public void run() { synchronized (PixelPerfectModel.this) { - if (PixelPerfectModel.this.image != null) { - PixelPerfectModel.this.image.dispose(); - } - PixelPerfectModel.this.image = image; PixelPerfectModel.this.viewNode = viewNode; PixelPerfectModel.this.selected = null; } } }); - notifyFocusChanged(); + notifyTreeChanged(); + } + + public void setImage(final Image image) { + final Image toDispose = this.image; + Display.getDefault().syncExec(new Runnable() { + public void run() { + synchronized (PixelPerfectModel.this) { + PixelPerfectModel.this.image = image; + } + } + }); + notifyImageChanged(); + if (toDispose != null) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + toDispose.dispose(); + } + }); + } } public void setZoom(int newZoom) { @@ -121,17 +159,22 @@ public class PixelPerfectModel { } public void setOverlayImage(final Image overlayImage) { + final Image toDispose = this.overlayImage; Display.getDefault().syncExec(new Runnable() { public void run() { synchronized (PixelPerfectModel.this) { - if (PixelPerfectModel.this.overlayImage != null) { - PixelPerfectModel.this.overlayImage.dispose(); - } PixelPerfectModel.this.overlayImage = overlayImage; } } }); notifyOverlayChanged(); + if (toDispose != null) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + toDispose.dispose(); + } + }); + } } public void setOverlayTransparency(double value) { @@ -200,7 +243,7 @@ public class PixelPerfectModel { public void selectionChanged(); - public void focusChanged(); + public void treeChanged(); public void zoomChanged(); @@ -258,11 +301,11 @@ public class PixelPerfectModel { } } - public void notifyFocusChanged() { + public void notifyTreeChanged() { ImageChangeListener[] listeners = getImageChangeListenerList(); if (listeners != null) { for (int i = 0; i < listeners.length; i++) { - listeners[i].focusChanged(); + listeners[i].treeChanged(); } } } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java index c49ce95..ba0fa57 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/models/TreeViewModel.java @@ -42,15 +42,28 @@ public class TreeViewModel { private final ArrayList<TreeChangeListener> treeChangeListeners = new ArrayList<TreeChangeListener>(); + private static TreeViewModel model; + + public static TreeViewModel getModel() { + if (model == null) { + model = new TreeViewModel(); + } + return model; + } + public void setData(Window window, ViewNode viewNode) { synchronized (this) { if (tree != null) { tree.viewNode.dispose(); } this.window = window; - tree = new DrawableViewNode(viewNode); - tree.setLeft(); - tree.placeRoot(); + if (viewNode == null) { + tree = null; + } else { + tree = new DrawableViewNode(viewNode); + tree.setLeft(); + tree.placeRoot(); + } viewport = null; zoom = 1; selectedNode = null; diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/CaptureDisplay.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/CaptureDisplay.java index 54a94fd..a17baac 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/CaptureDisplay.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/CaptureDisplay.java @@ -35,8 +35,6 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; public class CaptureDisplay { @@ -66,12 +64,7 @@ public class CaptureDisplay { CaptureDisplay.image = image; CaptureDisplay.viewNode = viewNode; viewNode.referenceImage(); - int dotIndex = viewNode.name.lastIndexOf('.'); - if (dotIndex != -1) { - shell.setText(viewNode.name.substring(dotIndex + 1)); - } else { - shell.setText(viewNode.name); - } + shell.setText(viewNode.name); boolean shellVisible = shell.isVisible(); if (!shellVisible) { @@ -82,7 +75,6 @@ public class CaptureDisplay { shell.computeTrim(0, 0, Math.max(buttonBar.getBounds().width, image.getBounds().width), buttonBar.getBounds().height + image.getBounds().height + 5); - System.out.println(bounds); shell.setSize(bounds.width, bounds.height); if (!shellVisible) { shell.setLocation(parentShell.getBounds().x @@ -92,6 +84,8 @@ public class CaptureDisplay { if (shellVisible) { canvas.redraw(); } + // Odd bug in setting the size... Do it again. + shell.setSize(bounds.width, bounds.height); } private static void createShell() { @@ -102,12 +96,14 @@ public class CaptureDisplay { shell.setLayout(gridLayout); buttonBar = new Composite(shell, SWT.NONE); + // buttonBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL); rowLayout.pack = true; rowLayout.center = true; buttonBar.setLayout(rowLayout); Composite buttons = new Composite(buttonBar, SWT.NONE); buttons.setLayout(new FillLayout()); + // buttons.setLayoutData(new RowData()); onWhite = new Button(buttons, SWT.TOGGLE); onWhite.setText("On White"); @@ -118,11 +114,12 @@ public class CaptureDisplay { onBlack.addSelectionListener(blackSelectionListener); showExtras = new Button(buttonBar, SWT.CHECK); + // showExtras.setLayoutData(new RowData()); showExtras.setText("Show Extras"); showExtras.addSelectionListener(extrasSelectionListener); canvas = new Canvas(shell, SWT.NONE); - canvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + canvas.setLayoutData(new GridData(GridData.FILL_BOTH)); canvas.addPaintListener(paintListener); shell.addShellListener(shellListener); diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DeviceSelector.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DeviceSelector.java index 5e7c606..2a11df1 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DeviceSelector.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DeviceSelector.java @@ -18,7 +18,7 @@ package com.android.hierarchyviewerlib.ui; import com.android.ddmlib.IDevice; import com.android.ddmuilib.ImageLoader; -import com.android.hierarchyviewerlib.ComponentRegistry; +import com.android.hierarchyviewerlib.HierarchyViewerDirector; import com.android.hierarchyviewerlib.device.Window; import com.android.hierarchyviewerlib.models.DeviceSelectionModel; import com.android.hierarchyviewerlib.models.DeviceSelectionModel.WindowChangeListener; @@ -31,6 +31,9 @@ import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionEvent; @@ -159,12 +162,14 @@ public class DeviceSelector extends Composite implements WindowChangeListener, S loadResources(); - model = ComponentRegistry.getDeviceSelectionModel(); + model = DeviceSelectionModel.getModel(); ContentProvider contentProvider = new ContentProvider(); treeViewer.setContentProvider(contentProvider); treeViewer.setLabelProvider(contentProvider); model.addWindowChangeListener(this); treeViewer.setInput(model); + + addControlListener(controlListener); } public void loadResources() { @@ -197,6 +202,23 @@ public class DeviceSelector extends Composite implements WindowChangeListener, S } }; + // HACK TO GET RID OF AN ERROR + + private ControlListener controlListener = new ControlAdapter() { + private boolean noInput = false; + + @Override + public void controlResized(ControlEvent e) { + if (getBounds().height <= 38) { + treeViewer.setInput(null); + noInput = true; + } else if (noInput) { + treeViewer.setInput(model); + noInput = false; + } + } + }; + @Override public boolean setFocus() { return tree.setFocus(); @@ -245,13 +267,17 @@ public class DeviceSelector extends Composite implements WindowChangeListener, S }); } + public void selectionChanged(IDevice device, Window window) { + // pass + } + public void widgetDefaultSelected(SelectionEvent e) { // TODO: Double click to open view hierarchy Object selection = ((TreeItem) e.item).getData(); if (selection instanceof IDevice) { - ComponentRegistry.getDirector().loadPixelPerfectData((IDevice) selection); + HierarchyViewerDirector.getDirector().loadPixelPerfectData((IDevice) selection); } else if (selection instanceof Window) { - ComponentRegistry.getDirector().loadViewTreeData((Window) selection); + HierarchyViewerDirector.getDirector().loadViewTreeData((Window) selection); } } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/LayoutViewer.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/LayoutViewer.java index 917e96e..458bae6 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/LayoutViewer.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/LayoutViewer.java @@ -16,7 +16,7 @@ package com.android.hierarchyviewerlib.ui; -import com.android.hierarchyviewerlib.ComponentRegistry; +import com.android.hierarchyviewerlib.HierarchyViewerDirector; import com.android.hierarchyviewerlib.models.TreeViewModel; import com.android.hierarchyviewerlib.models.TreeViewModel.TreeChangeListener; import com.android.hierarchyviewerlib.ui.util.DrawableViewNode; @@ -54,11 +54,13 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { private double scale; - private boolean showExtras = true; + private boolean showExtras = false; + + private boolean onBlack = true; public LayoutViewer(Composite parent) { super(parent, SWT.NONE); - model = ComponentRegistry.getTreeViewModel(); + model = TreeViewModel.getModel(); model.addTreeChangeListener(this); addDisposeListener(disposeListener); @@ -72,6 +74,16 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { public void setShowExtras(boolean show) { showExtras = show; + doRedraw(); + } + + public void setOnBlack(boolean value) { + onBlack = value; + doRedraw(); + } + + public boolean getOnBlack() { + return onBlack; } private DisposeListener disposeListener = new DisposeListener() { @@ -93,12 +105,12 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { public void mouseDoubleClick(MouseEvent e) { if (selectedNode != null) { - ComponentRegistry.getDirector().showCapture(getShell(), selectedNode.viewNode); + HierarchyViewerDirector.getDirector() + .showCapture(getShell(), selectedNode.viewNode); } } public void mouseDown(MouseEvent e) { - System.out.println("CLICK"); boolean selectionChanged = false; DrawableViewNode newSelection = null; synchronized (LayoutViewer.this) { @@ -125,8 +137,8 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { } }; - private DrawableViewNode updateSelection(DrawableViewNode node, float x, float y, int left, int top, - int clipX, int clipY, int clipWidth, int clipHeight) { + private DrawableViewNode updateSelection(DrawableViewNode node, float x, float y, int left, + int top, int clipX, int clipY, int clipWidth, int clipHeight) { if (!node.treeDrawn) { return null; } @@ -145,10 +157,12 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { final int N = node.children.size(); for (int i = N - 1; i >= 0; i--) { DrawableViewNode child = node.children.get(i); - DrawableViewNode ret = updateSelection(child, x, y, left + child.viewNode.left - node.viewNode.scrollX, - top + child.viewNode.top - node.viewNode.scrollY, clipX, clipY, clipWidth, - clipHeight); - if(ret != null) { + DrawableViewNode ret = + updateSelection(child, x, y, + left + child.viewNode.left - node.viewNode.scrollX, top + + child.viewNode.top - node.viewNode.scrollY, clipX, clipY, + clipWidth, clipHeight); + if (ret != null) { return ret; } } @@ -158,14 +172,23 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { private PaintListener paintListener = new PaintListener() { public void paintControl(PaintEvent e) { synchronized (LayoutViewer.this) { - e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); + if (onBlack) { + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); + } else { + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + } e.gc.fillRectangle(0, 0, getBounds().width, getBounds().height); if (tree != null) { - e.gc.setLineWidth((int) Math.ceil(0.2 / scale)); + e.gc.setLineWidth((int) Math.ceil(0.3 / scale)); e.gc.setTransform(transform); - e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + if (onBlack) { + e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + } else { + e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); + } Rectangle parentClipping = e.gc.getClipping(); - e.gc.setClipping(0, 0, tree.viewNode.width, tree.viewNode.height); + e.gc.setClipping(0, 0, tree.viewNode.width + (int) Math.ceil(0.3 / scale), + tree.viewNode.height + (int) Math.ceil(0.3 / scale)); paintRecursive(e.gc, tree, 0, 0, true); if (selectedNode != null) { @@ -191,25 +214,27 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { for (int i = 0; i < N; i++) { e.gc.drawRectangle((int) (left - rightLeftDistances.get(i).x), (int) (top - rightLeftDistances.get(i).y), - currentNode.viewNode.width - (int) Math.ceil(0.2 / scale), - currentNode.viewNode.height - (int) Math.ceil(0.2 / scale)); + currentNode.viewNode.width, currentNode.viewNode.height); currentNode = currentNode.parent; } if (showExtras && selectedNode.viewNode.image != null) { e.gc.drawImage(selectedNode.viewNode.image, left, top); - e.gc - .setForeground(Display.getDefault().getSystemColor( - SWT.COLOR_WHITE)); + if (onBlack) { + e.gc.setForeground(Display.getDefault().getSystemColor( + SWT.COLOR_WHITE)); + } else { + e.gc.setForeground(Display.getDefault().getSystemColor( + SWT.COLOR_BLACK)); + } paintRecursive(e.gc, selectedNode, left, top, true); } e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); e.gc.setLineWidth((int) Math.ceil(2 / scale)); - e.gc.drawRectangle(left, top, selectedNode.viewNode.width - - (int) Math.ceil(2 / scale) + 1, selectedNode.viewNode.height - - (int) Math.ceil(2 / scale) + 1); + e.gc.drawRectangle(left, top, selectedNode.viewNode.width, + selectedNode.viewNode.height); } } } @@ -227,9 +252,16 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { } Rectangle parentClipping = gc.getClipping(); int x1 = Math.max(parentClipping.x, left); - int x2 = Math.min(parentClipping.x + parentClipping.width, left + node.viewNode.width); + int x2 = + Math.min(parentClipping.x + parentClipping.width, left + node.viewNode.width + + (int) Math.ceil(0.3 / scale)); int y1 = Math.max(parentClipping.y, top); - int y2 = Math.min(parentClipping.y + parentClipping.height, top + node.viewNode.height); + int y2 = + Math.min(parentClipping.y + parentClipping.height, top + node.viewNode.height + + (int) Math.ceil(0.3 / scale)); + if (x2 <= x1 || y2 <= y1) { + return; + } gc.setClipping(x1, y1, x2 - x1, y2 - y1); final int N = node.children.size(); for (int i = 0; i < N; i++) { @@ -238,8 +270,7 @@ public class LayoutViewer extends Canvas implements TreeChangeListener { } gc.setClipping(parentClipping); if (!node.viewNode.willNotDraw) { - gc.drawRectangle(left, top, node.viewNode.width - (int) Math.ceil(0.2 / scale), - node.viewNode.height - (int) Math.ceil(0.2 / scale)); + gc.drawRectangle(left, top, node.viewNode.width, node.viewNode.height); } } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfect.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfect.java index 1a2876b..05b9679 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfect.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfect.java @@ -16,8 +16,6 @@ package com.android.hierarchyviewerlib.ui; -import com.android.ddmlib.RawImage; -import com.android.hierarchyviewerlib.ComponentRegistry; import com.android.hierarchyviewerlib.device.ViewNode; import com.android.hierarchyviewerlib.models.PixelPerfectModel; import com.android.hierarchyviewerlib.models.PixelPerfectModel.ImageChangeListener; @@ -26,6 +24,8 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; @@ -33,8 +33,6 @@ import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Canvas; @@ -74,12 +72,13 @@ public class PixelPerfect extends ScrolledComposite implements ImageChangeListen setContent(canvas); setExpandHorizontal(true); setExpandVertical(true); - model = ComponentRegistry.getPixelPerfectModel(); + model = PixelPerfectModel.getModel(); model.addImageChangeListener(this); canvas.addPaintListener(paintListener); canvas.addMouseListener(mouseListener); canvas.addMouseMoveListener(mouseMoveListener); + canvas.addKeyListener(keyListener); addDisposeListener(disposeListener); @@ -92,9 +91,6 @@ public class PixelPerfect extends ScrolledComposite implements ImageChangeListen private DisposeListener disposeListener = new DisposeListener() { public void widgetDisposed(DisposeEvent e) { model.removeImageChangeListener(PixelPerfect.this); - if (image != null) { - image.dispose(); - } crosshairColor.dispose(); borderColor.dispose(); paddingColor.dispose(); @@ -147,6 +143,51 @@ public class PixelPerfect extends ScrolledComposite implements ImageChangeListen model.setCrosshairLocation(e.x, e.y); } + private KeyListener keyListener = new KeyListener() { + + public void keyPressed(KeyEvent e) { + boolean crosshairMoved = false; + synchronized (PixelPerfect.this) { + if (image != null) { + switch (e.keyCode) { + case SWT.ARROW_UP: + if (crosshairLocation.y != 0) { + crosshairLocation.y--; + crosshairMoved = true; + } + break; + case SWT.ARROW_DOWN: + if (crosshairLocation.y != height - 1) { + crosshairLocation.y++; + crosshairMoved = true; + } + break; + case SWT.ARROW_LEFT: + if (crosshairLocation.x != 0) { + crosshairLocation.x--; + crosshairMoved = true; + } + break; + case SWT.ARROW_RIGHT: + if (crosshairLocation.x != width - 1) { + crosshairLocation.x++; + crosshairMoved = true; + } + break; + } + } + } + if (crosshairMoved) { + model.setCrosshairLocation(crosshairLocation.x, crosshairLocation.y); + } + } + + public void keyReleased(KeyEvent e) { + // pass + } + + }; + private PaintListener paintListener = new PaintListener() { public void paintControl(PaintEvent e) { synchronized (PixelPerfect.this) { @@ -266,6 +307,7 @@ public class PixelPerfect extends ScrolledComposite implements ImageChangeListen loadImage(); crosshairLocation = model.getCrosshairLocation(); selectedNode = model.getSelected(); + overlayImage = model.getOverlayImage(); } } }); @@ -297,11 +339,10 @@ public class PixelPerfect extends ScrolledComposite implements ImageChangeListen doRedraw(); } - public void focusChanged() { + public void treeChanged() { Display.getDefault().syncExec(new Runnable() { public void run() { synchronized (this) { - loadImage(); selectedNode = model.getSelected(); } } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectLoupe.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectLoupe.java index 84ce08f..5497a3f 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectLoupe.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectLoupe.java @@ -16,14 +16,14 @@ package com.android.hierarchyviewerlib.ui; -import com.android.ddmlib.RawImage; -import com.android.hierarchyviewerlib.ComponentRegistry; import com.android.hierarchyviewerlib.models.PixelPerfectModel; import com.android.hierarchyviewerlib.models.PixelPerfectModel.ImageChangeListener; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseWheelListener; @@ -73,13 +73,14 @@ public class PixelPerfectLoupe extends Canvas implements ImageChangeListener { public PixelPerfectLoupe(Composite parent) { super(parent, SWT.NONE); - model = ComponentRegistry.getPixelPerfectModel(); + model = PixelPerfectModel.getModel(); model.addImageChangeListener(this); addPaintListener(paintListener); addMouseListener(mouseListener); addMouseWheelListener(mouseWheelListener); addDisposeListener(disposeListener); + addKeyListener(keyListener); crosshairColor = new Color(Display.getDefault(), new RGB(255, 94, 254)); @@ -90,14 +91,12 @@ public class PixelPerfectLoupe extends Canvas implements ImageChangeListener { synchronized (this) { showOverlay = value; } + doRedraw(); } private DisposeListener disposeListener = new DisposeListener() { public void widgetDisposed(DisposeEvent e) { model.removeImageChangeListener(PixelPerfectLoupe.this); - if (image != null) { - image.dispose(); - } crosshairColor.dispose(); transform.dispose(); if (grid != null) { @@ -161,7 +160,53 @@ public class PixelPerfectLoupe extends Canvas implements ImageChangeListener { } } + private KeyListener keyListener = new KeyListener() { + + public void keyPressed(KeyEvent e) { + boolean crosshairMoved = false; + synchronized (PixelPerfectLoupe.this) { + if (image != null) { + switch (e.keyCode) { + case SWT.ARROW_UP: + if (crosshairLocation.y != 0) { + crosshairLocation.y--; + crosshairMoved = true; + } + break; + case SWT.ARROW_DOWN: + if (crosshairLocation.y != height - 1) { + crosshairLocation.y++; + crosshairMoved = true; + } + break; + case SWT.ARROW_LEFT: + if (crosshairLocation.x != 0) { + crosshairLocation.x--; + crosshairMoved = true; + } + break; + case SWT.ARROW_RIGHT: + if (crosshairLocation.x != width - 1) { + crosshairLocation.x++; + crosshairMoved = true; + } + break; + } + } + } + if (crosshairMoved) { + model.setCrosshairLocation(crosshairLocation.x, crosshairLocation.y); + } + } + + public void keyReleased(KeyEvent e) { + // pass + } + + }; + private PaintListener paintListener = new PaintListener() { + @SuppressWarnings("deprecation") public void paintControl(PaintEvent e) { synchronized (PixelPerfectLoupe.this) { e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); @@ -255,6 +300,7 @@ public class PixelPerfectLoupe extends Canvas implements ImageChangeListener { loadImage(); crosshairLocation = model.getCrosshairLocation(); zoom = model.getZoom(); + overlayImage = model.getOverlayImage(); } } }); @@ -283,8 +329,8 @@ public class PixelPerfectLoupe extends Canvas implements ImageChangeListener { // pass } - public void focusChanged() { - imageChanged(); + public void treeChanged() { + // pass } public void zoomChanged() { diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectPixelPanel.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectPixelPanel.java new file mode 100644 index 0000000..8fce603 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectPixelPanel.java @@ -0,0 +1,190 @@ +/* + * 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.ui; + +import com.android.hierarchyviewerlib.models.PixelPerfectModel; +import com.android.hierarchyviewerlib.models.PixelPerfectModel.ImageChangeListener; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; + +public class PixelPerfectPixelPanel extends Canvas implements ImageChangeListener { + private PixelPerfectModel model; + + private Image image; + + private Image overlayImage; + + private Point crosshairLocation; + + public static final int PREFERRED_WIDTH = 180; + + public static final int PREFERRED_HEIGHT = 52; + + public PixelPerfectPixelPanel(Composite parent) { + super(parent, SWT.NONE); + model = PixelPerfectModel.getModel(); + model.addImageChangeListener(this); + + addPaintListener(paintListener); + addDisposeListener(disposeListener); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + int height = PREFERRED_HEIGHT; + int width = (wHint == SWT.DEFAULT) ? PREFERRED_WIDTH : wHint; + return new Point(width, height); + } + + private DisposeListener disposeListener = new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + model.removeImageChangeListener(PixelPerfectPixelPanel.this); + } + }; + + private PaintListener paintListener = new PaintListener() { + public void paintControl(PaintEvent e) { + synchronized (PixelPerfectPixelPanel.this) { + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); + e.gc.fillRectangle(0, 0, getBounds().width, getBounds().height); + if (image != null) { + RGB pixel = + image.getImageData().palette.getRGB(image.getImageData().getPixel( + crosshairLocation.x, crosshairLocation.y)); + Color rgbColor = new Color(Display.getDefault(), pixel); + e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + e.gc.setBackground(rgbColor); + e.gc.drawRectangle(4, 4, 60, 30); + e.gc.fillRectangle(5, 5, 59, 29); + rgbColor.dispose(); + e.gc.drawText("#" + + Integer + .toHexString( + (1 << 24) + (pixel.red << 16) + (pixel.green << 8) + + pixel.blue).substring(1), 4, 35, true); + e.gc.drawText("R:", 80, 4, true); + e.gc.drawText("G:", 80, 20, true); + e.gc.drawText("B:", 80, 35, true); + e.gc.drawText(Integer.toString(pixel.red), 97, 4, true); + e.gc.drawText(Integer.toString(pixel.green), 97, 20, true); + e.gc.drawText(Integer.toString(pixel.blue), 97, 35, true); + e.gc.drawText("X:", 132, 4, true); + e.gc.drawText("Y:", 132, 20, true); + e.gc.drawText(Integer.toString(crosshairLocation.x) + " px", 149, 4, true); + e.gc.drawText(Integer.toString(crosshairLocation.y) + " px", 149, 20, true); + + if (overlayImage != null) { + int xInOverlay = crosshairLocation.x; + int yInOverlay = + crosshairLocation.y + - (image.getBounds().height - overlayImage.getBounds().height); + if (xInOverlay >= 0 && yInOverlay >= 0 + && xInOverlay < overlayImage.getBounds().width + && yInOverlay < overlayImage.getBounds().height) { + pixel = + overlayImage.getImageData().palette.getRGB(overlayImage + .getImageData().getPixel(xInOverlay, yInOverlay)); + rgbColor = new Color(Display.getDefault(), pixel); + e.gc + .setForeground(Display.getDefault().getSystemColor( + SWT.COLOR_WHITE)); + e.gc.setBackground(rgbColor); + e.gc.drawRectangle(204, 4, 60, 30); + e.gc.fillRectangle(205, 5, 59, 29); + rgbColor.dispose(); + e.gc.drawText("#" + + Integer.toHexString( + (1 << 24) + (pixel.red << 16) + (pixel.green << 8) + + pixel.blue).substring(1), 204, 35, true); + e.gc.drawText("R:", 280, 4, true); + e.gc.drawText("G:", 280, 20, true); + e.gc.drawText("B:", 280, 35, true); + e.gc.drawText(Integer.toString(pixel.red), 297, 4, true); + e.gc.drawText(Integer.toString(pixel.green), 297, 20, true); + e.gc.drawText(Integer.toString(pixel.blue), 297, 35, true); + } + } + } + } + } + }; + + private void doRedraw() { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + redraw(); + } + }); + } + + public void crosshairMoved() { + synchronized (this) { + crosshairLocation = model.getCrosshairLocation(); + } + doRedraw(); + } + + public void imageChanged() { + synchronized (this) { + image = model.getImage(); + } + doRedraw(); + } + + public void imageLoaded() { + synchronized (this) { + image = model.getImage(); + crosshairLocation = model.getCrosshairLocation(); + overlayImage = model.getOverlayImage(); + } + doRedraw(); + } + + public void overlayChanged() { + synchronized (this) { + overlayImage = model.getOverlayImage(); + } + doRedraw(); + } + + public void overlayTransparencyChanged() { + // pass + } + + public void selectionChanged() { + // pass + } + + public void treeChanged() { + // pass + } + + public void zoomChanged() { + // pass + } +} diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectTree.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectTree.java index 7df4d9d..80e4091 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectTree.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PixelPerfectTree.java @@ -17,7 +17,6 @@ package com.android.hierarchyviewerlib.ui; import com.android.ddmuilib.ImageLoader; -import com.android.hierarchyviewerlib.ComponentRegistry; import com.android.hierarchyviewerlib.device.ViewNode; import com.android.hierarchyviewerlib.models.PixelPerfectModel; import com.android.hierarchyviewerlib.models.PixelPerfectModel.ImageChangeListener; @@ -141,7 +140,7 @@ public class PixelPerfectTree extends Composite implements ImageChangeListener, addDisposeListener(disposeListener); - model = ComponentRegistry.getPixelPerfectModel(); + model = PixelPerfectModel.getModel(); ContentProvider contentProvider = new ContentProvider(); treeViewer.setContentProvider(contentProvider); treeViewer.setLabelProvider(contentProvider); @@ -150,7 +149,7 @@ public class PixelPerfectTree extends Composite implements ImageChangeListener, } - public void loadResources() { + private void loadResources() { ImageLoader loader = ImageLoader.getDdmUiLibLoader(); fileImage = loader.loadImage("file.png", Display.getDefault()); @@ -191,7 +190,7 @@ public class PixelPerfectTree extends Composite implements ImageChangeListener, // pass } - public void focusChanged() { + public void treeChanged() { imageLoaded(); } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/ProfileViewer.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/ProfileViewer.java deleted file mode 100644 index f83ba3d..0000000 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/ProfileViewer.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.ui; - -import com.android.hierarchyviewerlib.ComponentRegistry; -import com.android.hierarchyviewerlib.models.TreeViewModel; -import com.android.hierarchyviewerlib.models.TreeViewModel.TreeChangeListener; -import com.android.hierarchyviewerlib.ui.util.DrawableViewNode; -import com.android.hierarchyviewerlib.ui.util.TreeColumnResizer; - -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; - -import java.text.DecimalFormat; - -public class ProfileViewer extends Composite implements TreeChangeListener { - private TreeViewModel model; - - private TreeViewer treeViewer; - - private Tree tree; - - private DrawableViewNode selectedNode; - - private class ContentProvider implements ITreeContentProvider, ITableLabelProvider { - - public Object[] getChildren(Object parentElement) { - synchronized (ProfileViewer.this) { - return new Object[0]; - } - } - - public Object getParent(Object element) { - synchronized (ProfileViewer.this) { - return new Object[0]; - } - } - - public boolean hasChildren(Object element) { - synchronized (ProfileViewer.this) { - return false; - } - } - - public Object[] getElements(Object inputElement) { - synchronized (ProfileViewer.this) { - if (selectedNode != null && selectedNode.viewNode.measureTime != -1) { - return new String[] { - "measure", "layout", "draw" - }; - } - return new Object[0]; - } - } - - public void dispose() { - // pass - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } - - public Image getColumnImage(Object element, int column) { - return null; - } - - public String getColumnText(Object element, int column) { - synchronized (ProfileViewer.this) { - if (selectedNode != null) { - if (column == 0) { - return (String) element; - } else if (column == 1) { - DecimalFormat formatter = new DecimalFormat("0.000"); - if(((String)element).equals("measure")) { - if (selectedNode.viewNode.measureTime == -1) { - return "unknown"; - } - return formatter.format(selectedNode.viewNode.measureTime); - } else if (((String) element).equals("layout")) { - if (selectedNode.viewNode.layoutTime == -1) { - return "unknown"; - } - return formatter.format(selectedNode.viewNode.layoutTime); - } else { - if (selectedNode.viewNode.drawTime == -1) { - return "unknown"; - } - return formatter.format(selectedNode.viewNode.drawTime); - } - } - } - return ""; - } - } - - public void addListener(ILabelProviderListener listener) { - // pass - } - - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - public ProfileViewer(Composite parent) { - super(parent, SWT.NONE); - setLayout(new FillLayout()); - treeViewer = new TreeViewer(this, SWT.NONE); - - tree = treeViewer.getTree(); - tree.setLinesVisible(true); - tree.setHeaderVisible(true); - - TreeColumn operationColumn = new TreeColumn(tree, SWT.NONE); - operationColumn.setText("Operation"); - TreeColumn durationColumn = new TreeColumn(tree, SWT.NONE); - durationColumn.setText("Duration (ms)"); - - model = ComponentRegistry.getTreeViewModel(); - ContentProvider contentProvider = new ContentProvider(); - treeViewer.setContentProvider(contentProvider); - treeViewer.setLabelProvider(contentProvider); - treeViewer.setInput(model); - model.addTreeChangeListener(this); - - new TreeColumnResizer(this, operationColumn, durationColumn); - } - - public void selectionChanged() { - synchronized (this) { - selectedNode = model.getSelection(); - } - doRefresh(); - } - - public void treeChanged() { - synchronized (this) { - selectedNode = model.getSelection(); - } - doRefresh(); - } - - public void viewportChanged() { - // pass - } - - public void zoomChanged() { - // pass - } - - private void doRefresh() { - Display.getDefault().asyncExec(new Runnable() { - public void run() { - treeViewer.refresh(); - } - }); - } -} diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java index d262d16..0b76909 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java @@ -16,7 +16,6 @@ package com.android.hierarchyviewerlib.ui; -import com.android.hierarchyviewerlib.ComponentRegistry; import com.android.hierarchyviewerlib.device.ViewNode; import com.android.hierarchyviewerlib.device.ViewNode.Property; import com.android.hierarchyviewerlib.models.TreeViewModel; @@ -30,6 +29,13 @@ import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; @@ -48,6 +54,8 @@ public class PropertyViewer extends Composite implements TreeChangeListener { private DrawableViewNode selectedNode; + private Font smallFont; + private class ContentProvider implements ITreeContentProvider, ITableLabelProvider { public Object[] getChildren(Object parentElement) { @@ -187,16 +195,66 @@ public class PropertyViewer extends Composite implements TreeChangeListener { TreeColumn valueColumn = new TreeColumn(tree, SWT.NONE); valueColumn.setText("Value"); - model = ComponentRegistry.getTreeViewModel(); + model = TreeViewModel.getModel(); ContentProvider contentProvider = new ContentProvider(); treeViewer.setContentProvider(contentProvider); treeViewer.setLabelProvider(contentProvider); treeViewer.setInput(model); model.addTreeChangeListener(this); + loadResources(); + addDisposeListener(disposeListener); + + tree.setFont(smallFont); + new TreeColumnResizer(this, propertyColumn, valueColumn); + + addControlListener(controlListener); } + public void loadResources() { + Display display = Display.getDefault(); + Font systemFont = display.getSystemFont(); + FontData[] fontData = systemFont.getFontData(); + FontData[] newFontData = new FontData[fontData.length]; + for (int i = 0; i < fontData.length; i++) { + newFontData[i] = new FontData(fontData[i].getName(), 8, fontData[i].getStyle()); + } + smallFont = new Font(Display.getDefault(), newFontData); + } + + private DisposeListener disposeListener = new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + model.removeTreeChangeListener(PropertyViewer.this); + smallFont.dispose(); + } + }; + + // HACK TO GET RID OF AN ERROR + + private ControlListener controlListener = new ControlAdapter() { + private boolean noInput = false; + + private boolean noHeader = false; + + @Override + public void controlResized(ControlEvent e) { + if (getBounds().height <= 20) { + tree.setHeaderVisible(false); + noHeader = true; + } else if (noHeader) { + tree.setHeaderVisible(true); + noHeader = false; + } + if (getBounds().height <= 38) { + treeViewer.setInput(null); + noInput = true; + } else if (noInput) { + treeViewer.setInput(model); + noInput = false; + } + } + }; public void selectionChanged() { synchronized (this) { diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeView.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeView.java index abf5690..4dfdf19 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeView.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeView.java @@ -17,7 +17,7 @@ package com.android.hierarchyviewerlib.ui; import com.android.ddmuilib.ImageLoader; -import com.android.hierarchyviewerlib.ComponentRegistry; +import com.android.hierarchyviewerlib.HierarchyViewerDirector; import com.android.hierarchyviewerlib.device.ViewNode.ProfileRating; import com.android.hierarchyviewerlib.models.TreeViewModel; import com.android.hierarchyviewerlib.models.TreeViewModel.TreeChangeListener; @@ -36,6 +36,7 @@ import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseWheelListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Path; @@ -46,6 +47,8 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; +import java.text.DecimalFormat; + public class TreeView extends Canvas implements TreeChangeListener { private TreeViewModel model; @@ -70,16 +73,24 @@ public class TreeView extends Canvas implements TreeChangeListener { public static final float BEZIER_FRACTION = 0.35f; - private Image redImage; + private static Image redImage; + + private static Image yellowImage; + + private static Image greenImage; - private Image yellowImage; + private static Image notSelectedImage; - private Image greenImage; + private static Image selectedImage; + + private static Image filteredImage; + + private static Image filteredSelectedImage; public TreeView(Composite parent) { super(parent, SWT.NONE); - model = ComponentRegistry.getTreeViewModel(); + model = TreeViewModel.getModel(); model.addTreeChangeListener(this); addPaintListener(paintListener); @@ -90,13 +101,22 @@ public class TreeView extends Canvas implements TreeChangeListener { addDisposeListener(disposeListener); addKeyListener(keyListener); + loadResources(); + transform = new Transform(Display.getDefault()); inverse = new Transform(Display.getDefault()); + } + + private void loadResources() { ImageLoader loader = ImageLoader.getLoader(this.getClass()); redImage = loader.loadImage("red.png", Display.getDefault()); yellowImage = loader.loadImage("yellow.png", Display.getDefault()); greenImage = loader.loadImage("green.png", Display.getDefault()); + notSelectedImage = loader.loadImage("not-selected.png", Display.getDefault()); + selectedImage = loader.loadImage("selected.png", Display.getDefault()); + filteredImage = loader.loadImage("filtered.png", Display.getDefault()); + filteredSelectedImage = loader.loadImage("selected-filtered.png", Display.getDefault()); } private DisposeListener disposeListener = new DisposeListener() { @@ -138,7 +158,7 @@ public class TreeView extends Canvas implements TreeChangeListener { if (tree != null && viewport != null && selectedNode != null) { switch (e.keyCode) { case SWT.ARROW_LEFT: - if(selectedNode.parent != null) { + if (selectedNode.parent != null) { selectedNode = selectedNode.parent; selectionChanged = true; } @@ -171,7 +191,7 @@ public class TreeView extends Canvas implements TreeChangeListener { currentNode = selectedNode; while (currentNode.parent != null && currentNode.viewNode.index + 1 == currentNode.parent.children - .size()) { + .size()) { levelsOut++; currentNode = currentNode.parent; } @@ -193,7 +213,7 @@ public class TreeView extends Canvas implements TreeChangeListener { DrawableViewNode rightNode = null; double mostOverlap = 0; final int N = selectedNode.children.size(); - for(int i = 0; i<N; i++) { + for (int i = 0; i < N; i++) { DrawableViewNode child = selectedNode.children.get(i); DrawableViewNode topMostChild = child; while (topMostChild.children.size() != 0) { @@ -224,7 +244,7 @@ public class TreeView extends Canvas implements TreeChangeListener { model.setSelection(selectedNode); } if (clickedNode != null) { - ComponentRegistry.getDirector().showCapture(getShell(), clickedNode.viewNode); + HierarchyViewerDirector.getDirector().showCapture(getShell(), clickedNode.viewNode); } } @@ -243,7 +263,7 @@ public class TreeView extends Canvas implements TreeChangeListener { } } if (clickedNode != null) { - ComponentRegistry.getDirector().showCapture(getShell(), clickedNode.viewNode); + HierarchyViewerDirector.getDirector().showCapture(getShell(), clickedNode.viewNode); } } @@ -399,27 +419,115 @@ public class TreeView extends Canvas implements TreeChangeListener { private PaintListener paintListener = new PaintListener() { public void paintControl(PaintEvent e) { synchronized (TreeView.this) { - e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); e.gc.fillRectangle(0, 0, getBounds().width, getBounds().height); if (tree != null && viewport != null) { e.gc.setTransform(transform); - e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY)); + e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); Path connectionPath = new Path(Display.getDefault()); - paintRecursive(e.gc, tree, connectionPath); + paintRecursive(e.gc, transform, tree, selectedNode, connectionPath); e.gc.drawPath(connectionPath); connectionPath.dispose(); + + Transform tempTransform = new Transform(Display.getDefault()); + e.gc.setTransform(tempTransform); + + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY)); + e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); + + // Draw the number of views. + String viewsString = Integer.toString(tree.viewNode.viewCount) + " view"; + if (tree.viewNode.viewCount != 1) { + viewsString += 's'; + } + org.eclipse.swt.graphics.Point stringExtent = e.gc.stringExtent(viewsString); + + e.gc.fillRectangle(0, getBounds().height - stringExtent.y - 4, + stringExtent.x + 4, stringExtent.y + 4); + + e.gc.drawText(viewsString, 2, getBounds().height - stringExtent.y - 2); + + DrawableViewNode profiledNode = + (tree.viewNode.protocolVersion < 3) ? tree : selectedNode; + + // Draw the profiling stuff + if (profiledNode != null && profiledNode.viewNode.measureTime != -1) { + DecimalFormat formatter = new DecimalFormat("0.000"); + String measureString = "Measure:"; + String measureTimeString = + formatter.format(profiledNode.viewNode.measureTime) + " ms"; + String layoutString = "Layout:"; + String layoutTimeString = + formatter.format(profiledNode.viewNode.layoutTime) + " ms"; + String drawString = "Draw:"; + String drawTimeString = + formatter.format(profiledNode.viewNode.drawTime) + " ms"; + + org.eclipse.swt.graphics.Point measureExtent = + e.gc.stringExtent(measureString); + org.eclipse.swt.graphics.Point measureTimeExtent = + e.gc.stringExtent(measureTimeString); + org.eclipse.swt.graphics.Point layoutExtent = + e.gc.stringExtent(layoutString); + org.eclipse.swt.graphics.Point layoutTimeExtent = + e.gc.stringExtent(layoutTimeString); + org.eclipse.swt.graphics.Point drawExtent = e.gc.stringExtent(drawString); + org.eclipse.swt.graphics.Point drawTimeExtent = + e.gc.stringExtent(drawTimeString); + + int letterHeight = e.gc.getFontMetrics().getHeight(); + + int width = + Math.max(measureExtent.x, Math.max(layoutExtent.x, drawExtent.x)) + + Math.max(measureTimeExtent.x, Math.max( + layoutTimeExtent.x, drawTimeExtent.x)) + 8; + int height = 3 * letterHeight + 8; + + int x = getBounds().width - width; + int y = getBounds().height - height; + + e.gc.fillRectangle(x, y, width, height); + + x += 2; + y += 2; + e.gc.drawText(measureString, x, y); + + y += letterHeight + 2; + e.gc.drawText(layoutString, x, y); + + y += letterHeight + 2; + e.gc.drawText(drawString, x, y); + + x = getBounds().width - measureTimeExtent.x - 2; + y = getBounds().height - height + 2; + e.gc.drawText(measureTimeString, x, y); + + x = getBounds().width - layoutTimeExtent.x - 2; + y += letterHeight + 2; + e.gc.drawText(layoutTimeString, x, y); + + x = getBounds().width - drawTimeExtent.x - 2; + y += letterHeight + 2; + e.gc.drawText(drawTimeString, x, y); + + } + tempTransform.dispose(); + } } } }; - private void paintRecursive(GC gc, DrawableViewNode node, Path connectionPath) { - if (selectedNode == node) { - gc.fillRectangle(node.left, (int) Math.round(node.top), DrawableViewNode.NODE_WIDTH, - DrawableViewNode.NODE_HEIGHT); + private static void paintRecursive(GC gc, Transform transform, DrawableViewNode node, + DrawableViewNode selectedNode, Path connectionPath) { + if (selectedNode == node && node.viewNode.filtered) { + gc.drawImage(filteredSelectedImage, node.left, (int) Math.round(node.top)); + } else if (selectedNode == node) { + gc.drawImage(selectedImage, node.left, (int) Math.round(node.top)); + } else if (node.viewNode.filtered) { + gc.drawImage(filteredImage, node.left, (int) Math.round(node.top)); } else { - gc.drawRectangle(node.left, (int) Math.round(node.top), DrawableViewNode.NODE_WIDTH, - DrawableViewNode.NODE_HEIGHT); + gc.drawImage(notSelectedImage, node.left, (int) Math.round(node.top)); } int fontHeight = gc.getFontMetrics().getHeight(); @@ -434,7 +542,7 @@ public class TreeView extends Canvas implements TreeChangeListener { } double x = node.left + DrawableViewNode.CONTENT_LEFT_RIGHT_PADDING; double y = node.top + DrawableViewNode.CONTENT_TOP_BOTTOM_PADDING; - drawTextInArea(gc, name, x, y, contentWidth, fontHeight); + drawTextInArea(gc, transform, name, x, y, contentWidth, fontHeight); y += fontHeight + DrawableViewNode.CONTENT_INTER_PADDING; @@ -442,7 +550,7 @@ public class TreeView extends Canvas implements TreeChangeListener { y += fontHeight + DrawableViewNode.CONTENT_INTER_PADDING; if (!node.viewNode.id.equals("NO_ID")) { - drawTextInArea(gc, node.viewNode.id, x, y, contentWidth, fontHeight); + drawTextInArea(gc, transform, node.viewNode.id, x, y, contentWidth, fontHeight); } if (node.viewNode.measureRating != ProfileRating.NONE) { @@ -491,15 +599,16 @@ public class TreeView extends Canvas implements TreeChangeListener { } } - org.eclipse.swt.graphics.Point indexExtent = gc.stringExtent(Integer.toString(node.viewNode.index)); - x = node.left+DrawableViewNode.NODE_WIDTH-DrawableViewNode.INDEX_PADDING-indexExtent.x; - y = node.top+DrawableViewNode.NODE_HEIGHT-DrawableViewNode.INDEX_PADDING-indexExtent.y; + x = + node.left + DrawableViewNode.NODE_WIDTH - DrawableViewNode.INDEX_PADDING + - indexExtent.x; + y = + node.top + DrawableViewNode.NODE_HEIGHT - DrawableViewNode.INDEX_PADDING + - indexExtent.y; gc.drawText(Integer.toString(node.viewNode.index), (int) x, (int) y, SWT.DRAW_TRANSPARENT); - - int N = node.children.size(); if (N == 0) { return; @@ -507,7 +616,7 @@ public class TreeView extends Canvas implements TreeChangeListener { float childSpacing = (1.0f * (DrawableViewNode.NODE_HEIGHT - 2 * LINE_PADDING)) / N; for (int i = 0; i < N; i++) { DrawableViewNode child = node.children.get(i); - paintRecursive(gc, child, connectionPath); + paintRecursive(gc, transform, child, selectedNode, connectionPath); float x1 = node.left + DrawableViewNode.NODE_WIDTH; float y1 = (float) node.top + LINE_PADDING + childSpacing * i + childSpacing / 2; float x2 = child.left; @@ -521,7 +630,8 @@ public class TreeView extends Canvas implements TreeChangeListener { } } - private void drawTextInArea(GC gc, String text, double x, double y, double width, double height) { + private static void drawTextInArea(GC gc, Transform transform, String text, double x, double y, + double width, double height) { org.eclipse.swt.graphics.Point extent = gc.stringExtent(text); if (extent.x > width) { @@ -532,8 +642,8 @@ public class TreeView extends Canvas implements TreeChangeListener { transform.scale((float) scale, (float) scale); gc.setTransform(transform); - x/=scale; - y/=scale; + x /= scale; + y /= scale; y += (extent.y / scale - extent.y) / 2; gc.drawText(text, (int) x, (int) y, SWT.DRAW_TRANSPARENT); @@ -547,6 +657,31 @@ public class TreeView extends Canvas implements TreeChangeListener { } + public static Image paintToImage(DrawableViewNode tree) { + Image image = + new Image(Display.getDefault(), (int) Math.ceil(tree.bounds.width), (int) Math + .ceil(tree.bounds.height)); + + Transform transform = new Transform(Display.getDefault()); + transform.identity(); + transform.translate((float) -tree.bounds.x, (float) -tree.bounds.y); + Path connectionPath = new Path(Display.getDefault()); + GC gc = new GC(image); + Color white = new Color(Display.getDefault(), 255, 255, 255); + Color black = new Color(Display.getDefault(), 0, 0, 0); + gc.setForeground(white); + gc.setBackground(black); + gc.fillRectangle(0, 0, image.getBounds().width, image.getBounds().height); + gc.setTransform(transform); + paintRecursive(gc, transform, tree, null, connectionPath); + gc.drawPath(connectionPath); + gc.dispose(); + connectionPath.dispose(); + white.dispose(); + black.dispose(); + return image; + } + private void doRedraw() { Display.getDefault().asyncExec(new Runnable() { public void run() { @@ -565,9 +700,9 @@ public class TreeView extends Canvas implements TreeChangeListener { viewport = null; } else { viewport = - new Rectangle((tree.bounds.width - getBounds().width) / 2, - (tree.bounds.height - getBounds().height) / 2, - getBounds().width, getBounds().height); + new Rectangle(0, tree.top + DrawableViewNode.NODE_HEIGHT / 2 + - getBounds().height / 2, getBounds().width, + getBounds().height); } } } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeViewOverview.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeViewOverview.java index 83a2b0d..9a44694 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeViewOverview.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/TreeViewOverview.java @@ -16,7 +16,7 @@ package com.android.hierarchyviewerlib.ui; -import com.android.hierarchyviewerlib.ComponentRegistry; +import com.android.ddmuilib.ImageLoader; import com.android.hierarchyviewerlib.models.TreeViewModel; import com.android.hierarchyviewerlib.models.TreeViewModel.TreeChangeListener; import com.android.hierarchyviewerlib.ui.util.DrawableViewNode; @@ -32,6 +32,7 @@ import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Path; import org.eclipse.swt.graphics.Transform; import org.eclipse.swt.widgets.Canvas; @@ -58,12 +59,24 @@ public class TreeViewOverview extends Canvas implements TreeChangeListener { private boolean dragging = false; + private DrawableViewNode selectedNode; + + private static Image notSelectedImage; + + private static Image selectedImage; + + private static Image filteredImage; + + private static Image filteredSelectedImage; + public TreeViewOverview(Composite parent) { super(parent, SWT.NONE); - model = ComponentRegistry.getTreeViewModel(); + model = TreeViewModel.getModel(); model.addTreeChangeListener(this); + loadResources(); + addPaintListener(paintListener); addMouseListener(mouseListener); addMouseMoveListener(mouseMoveListener); @@ -74,6 +87,15 @@ public class TreeViewOverview extends Canvas implements TreeChangeListener { inverse = new Transform(Display.getDefault()); } + private void loadResources() { + ImageLoader loader = ImageLoader.getLoader(this.getClass()); + notSelectedImage = loader.loadImage("not-selected.png", Display.getDefault()); + selectedImage = loader.loadImage("selected-small.png", Display.getDefault()); + filteredImage = loader.loadImage("filtered.png", Display.getDefault()); + filteredSelectedImage = + loader.loadImage("selected-filtered-small.png", Display.getDefault()); + } + private DisposeListener disposeListener = new DisposeListener() { public void widgetDisposed(DisposeEvent e) { model.removeTreeChangeListener(TreeViewOverview.this); @@ -182,21 +204,23 @@ public class TreeViewOverview extends Canvas implements TreeChangeListener { public void paintControl(PaintEvent e) { synchronized (TreeViewOverview.this) { if (tree != null && viewport != null) { - e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); + e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); e.gc.fillRectangle(0, 0, getBounds().width, getBounds().height); e.gc.setTransform(transform); + e.gc.setLineWidth((int) Math.ceil(0.7 / scale)); Path connectionPath = new Path(Display.getDefault()); paintRecursive(e.gc, tree, connectionPath); e.gc.drawPath(connectionPath); connectionPath.dispose(); - e.gc.setAlpha(80); - e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY)); + e.gc.setAlpha(50); + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); e.gc.fillRectangle((int) viewport.x, (int) viewport.y, (int) Math .ceil(viewport.width), (int) Math.ceil(viewport.height)); e.gc.setAlpha(255); - e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); + e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY)); e.gc.setLineWidth((int) Math.ceil(2 / scale)); e.gc.drawRectangle((int) viewport.x, (int) viewport.y, (int) Math .ceil(viewport.width), (int) Math.ceil(viewport.height)); @@ -206,8 +230,15 @@ public class TreeViewOverview extends Canvas implements TreeChangeListener { }; private void paintRecursive(GC gc, DrawableViewNode node, Path connectionPath) { - gc.drawRectangle(node.left, (int) Math.round(node.top), DrawableViewNode.NODE_WIDTH, - DrawableViewNode.NODE_HEIGHT); + if (selectedNode == node && node.viewNode.filtered) { + gc.drawImage(filteredSelectedImage, node.left, (int) Math.round(node.top)); + } else if (selectedNode == node) { + gc.drawImage(selectedImage, node.left, (int) Math.round(node.top)); + } else if (node.viewNode.filtered) { + gc.drawImage(filteredImage, node.left, (int) Math.round(node.top)); + } else { + gc.drawImage(notSelectedImage, node.left, (int) Math.round(node.top)); + } int N = node.children.size(); if (N == 0) { return; @@ -244,6 +275,7 @@ public class TreeViewOverview extends Canvas implements TreeChangeListener { public void run() { synchronized (this) { tree = model.getTree(); + selectedNode = model.getSelection(); setBounds(); setTransform(); } @@ -311,6 +343,9 @@ public class TreeViewOverview extends Canvas implements TreeChangeListener { } public void selectionChanged() { - // pass + synchronized (this) { + selectedNode = model.getSelection(); + } + doRedraw(); } } diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/DrawableViewNode.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/DrawableViewNode.java index fccc3ba..0d64e86 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/DrawableViewNode.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/DrawableViewNode.java @@ -25,17 +25,17 @@ public class DrawableViewNode { public final ArrayList<DrawableViewNode> children = new ArrayList<DrawableViewNode>(); - public final static int NODE_HEIGHT = 110; + public final static int NODE_HEIGHT = 100; - public final static int NODE_WIDTH = 170; + public final static int NODE_WIDTH = 180; - public final static int CONTENT_LEFT_RIGHT_PADDING = 3; + public final static int CONTENT_LEFT_RIGHT_PADDING = 7; - public final static int CONTENT_TOP_BOTTOM_PADDING = 7; + public final static int CONTENT_TOP_BOTTOM_PADDING = 8; public final static int CONTENT_INTER_PADDING = 3; - public final static int INDEX_PADDING = 5; + public final static int INDEX_PADDING = 7; public final static int LEAF_NODE_SPACING = 9; diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/PsdFile.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/PsdFile.java new file mode 100644 index 0000000..275ea36 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/PsdFile.java @@ -0,0 +1,508 @@ +/* + * 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.ui.util; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +/** + * Writes PSD file. Supports only 8 bits, RGB images with 4 channels. + */ +public class PsdFile { + private final Header mHeader; + + private final ColorMode mColorMode; + + private final ImageResources mImageResources; + + private final LayersMasksInfo mLayersMasksInfo; + + private final LayersInfo mLayersInfo; + + private final BufferedImage mMergedImage; + + private final Graphics2D mGraphics; + + public PsdFile(int width, int height) { + mHeader = new Header(width, height); + mColorMode = new ColorMode(); + mImageResources = new ImageResources(); + mLayersMasksInfo = new LayersMasksInfo(); + mLayersInfo = new LayersInfo(); + + mMergedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + mGraphics = mMergedImage.createGraphics(); + } + + public void addLayer(String name, BufferedImage image, Point offset) { + addLayer(name, image, offset, true); + } + + public void addLayer(String name, BufferedImage image, Point offset, boolean visible) { + mLayersInfo.addLayer(name, image, offset, visible); + if (visible) + mGraphics.drawImage(image, null, offset.x, offset.y); + } + + public void write(OutputStream stream) { + mLayersMasksInfo.setLayersInfo(mLayersInfo); + + DataOutputStream out = new DataOutputStream(new BufferedOutputStream(stream)); + try { + mHeader.write(out); + out.flush(); + + mColorMode.write(out); + mImageResources.write(out); + mLayersMasksInfo.write(out); + mLayersInfo.write(out); + out.flush(); + + mLayersInfo.writeImageData(out); + out.flush(); + + writeImage(mMergedImage, out, false); + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private static void writeImage(BufferedImage image, DataOutputStream out, boolean split) + throws IOException { + + if (!split) + out.writeShort(0); + + int width = image.getWidth(); + int height = image.getHeight(); + + final int length = width * height; + int[] pixels = new int[length]; + + image.getData().getDataElements(0, 0, width, height, pixels); + + byte[] a = new byte[length]; + byte[] r = new byte[length]; + byte[] g = new byte[length]; + byte[] b = new byte[length]; + + for (int i = 0; i < length; i++) { + final int pixel = pixels[i]; + a[i] = (byte) ((pixel >> 24) & 0xFF); + r[i] = (byte) ((pixel >> 16) & 0xFF); + g[i] = (byte) ((pixel >> 8) & 0xFF); + b[i] = (byte) (pixel & 0xFF); + } + + if (split) + out.writeShort(0); + if (split) + out.write(a); + if (split) + out.writeShort(0); + out.write(r); + if (split) + out.writeShort(0); + out.write(g); + if (split) + out.writeShort(0); + out.write(b); + if (!split) + out.write(a); + } + + @SuppressWarnings( { + "UnusedDeclaration" + }) + static class Header { + static final short MODE_BITMAP = 0; + + static final short MODE_GRAYSCALE = 1; + + static final short MODE_INDEXED = 2; + + static final short MODE_RGB = 3; + + static final short MODE_CMYK = 4; + + static final short MODE_MULTI_CHANNEL = 7; + + static final short MODE_DUOTONE = 8; + + static final short MODE_LAB = 9; + + final byte[] mSignature = "8BPS".getBytes(); + + final short mVersion = 1; + + final byte[] mReserved = new byte[6]; + + final short mChannelCount = 4; + + final int mHeight; + + final int mWidth; + + final short mDepth = 8; + + final short mMode = MODE_RGB; + + Header(int width, int height) { + mWidth = width; + mHeight = height; + } + + void write(DataOutputStream out) throws IOException { + out.write(mSignature); + out.writeShort(mVersion); + out.write(mReserved); + out.writeShort(mChannelCount); + out.writeInt(mHeight); + out.writeInt(mWidth); + out.writeShort(mDepth); + out.writeShort(mMode); + } + } + + // Unused at the moment + @SuppressWarnings( { + "UnusedDeclaration" + }) + static class ColorMode { + final int mLength = 0; + + void write(DataOutputStream out) throws IOException { + out.writeInt(mLength); + } + } + + // Unused at the moment + @SuppressWarnings( { + "UnusedDeclaration" + }) + static class ImageResources { + static final short RESOURCE_RESOLUTION_INFO = 0x03ED; + + int mLength = 0; + + final byte[] mSignature = "8BIM".getBytes(); + + final short mResourceId = RESOURCE_RESOLUTION_INFO; + + final short mPad = 0; + + final int mDataLength = 16; + + final short mHorizontalDisplayUnit = 0x48; // 72 dpi + + final int mHorizontalResolution = 1; + + final short mWidthDisplayUnit = 1; + + final short mVerticalDisplayUnit = 0x48; // 72 dpi + + final int mVerticalResolution = 1; + + final short mHeightDisplayUnit = 1; + + ImageResources() { + mLength = mSignature.length; + mLength += 2; + mLength += 2; + mLength += 4; + mLength += 8; + mLength += 8; + } + + void write(DataOutputStream out) throws IOException { + out.writeInt(mLength); + out.write(mSignature); + out.writeShort(mResourceId); + out.writeShort(mPad); + out.writeInt(mDataLength); + out.writeShort(mHorizontalDisplayUnit); + out.writeInt(mHorizontalResolution); + out.writeShort(mWidthDisplayUnit); + out.writeShort(mVerticalDisplayUnit); + out.writeInt(mVerticalResolution); + out.writeShort(mHeightDisplayUnit); + } + } + + @SuppressWarnings( { + "UnusedDeclaration" + }) + static class LayersMasksInfo { + int mMiscLength; + + int mLayerInfoLength; + + void setLayersInfo(LayersInfo layersInfo) { + mLayerInfoLength = layersInfo.getLength(); + // Round to the next multiple of 2 + if ((mLayerInfoLength & 0x1) == 0x1) + mLayerInfoLength++; + mMiscLength = mLayerInfoLength + 8; + } + + void write(DataOutputStream out) throws IOException { + out.writeInt(mMiscLength); + out.writeInt(mLayerInfoLength); + } + } + + @SuppressWarnings( { + "UnusedDeclaration" + }) + static class LayersInfo { + final List<Layer> mLayers = new ArrayList<Layer>(); + + void addLayer(String name, BufferedImage image, Point offset, boolean visible) { + mLayers.add(new Layer(name, image, offset, visible)); + } + + int getLength() { + int length = 2; + for (Layer layer : mLayers) { + length += layer.getLength(); + } + return length; + } + + void write(DataOutputStream out) throws IOException { + out.writeShort((short) -mLayers.size()); + for (Layer layer : mLayers) { + layer.write(out); + } + } + + void writeImageData(DataOutputStream out) throws IOException { + for (Layer layer : mLayers) { + layer.writeImageData(out); + } + // Global layer mask info length + out.writeInt(0); + } + } + + @SuppressWarnings( { + "UnusedDeclaration" + }) + static class Layer { + static final byte OPACITY_TRANSPARENT = 0x0; + + static final byte OPACITY_OPAQUE = (byte) 0xFF; + + static final byte CLIPPING_BASE = 0x0; + + static final byte CLIPPING_NON_BASE = 0x1; + + static final byte FLAG_TRANSPARENCY_PROTECTED = 0x1; + + static final byte FLAG_INVISIBLE = 0x2; + + final int mTop; + + final int mLeft; + + final int mBottom; + + final int mRight; + + final short mChannelCount = 4; + + final Channel[] mChannelInfo = new Channel[mChannelCount]; + + final byte[] mBlendSignature = "8BIM".getBytes(); + + final byte[] mBlendMode = "norm".getBytes(); + + final byte mOpacity = OPACITY_OPAQUE; + + final byte mClipping = CLIPPING_BASE; + + byte mFlags = 0x0; + + final byte mFiller = 0x0; + + int mExtraSize = 4 + 4; + + final int mMaskDataLength = 0; + + final int mBlendRangeDataLength = 0; + + final byte[] mName; + + final byte[] mLayerExtraSignature = "8BIM".getBytes(); + + final byte[] mLayerExtraKey = "luni".getBytes(); + + int mLayerExtraLength; + + final String mOriginalName; + + private BufferedImage mImage; + + Layer(String name, BufferedImage image, Point offset, boolean visible) { + final int height = image.getHeight(); + final int width = image.getWidth(); + final int length = width * height; + + mChannelInfo[0] = new Channel(Channel.ID_ALPHA, length); + mChannelInfo[1] = new Channel(Channel.ID_RED, length); + mChannelInfo[2] = new Channel(Channel.ID_GREEN, length); + mChannelInfo[3] = new Channel(Channel.ID_BLUE, length); + + mTop = offset.y; + mLeft = offset.x; + mBottom = offset.y + height; + mRight = offset.x + width; + + mOriginalName = name; + byte[] data = name.getBytes(); + + try { + mLayerExtraLength = 4 + mOriginalName.getBytes("UTF-16").length; + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + final byte[] nameData = new byte[data.length + 1]; + nameData[0] = (byte) (data.length & 0xFF); + System.arraycopy(data, 0, nameData, 1, data.length); + + // This could be done in the same pass as above + if (nameData.length % 4 != 0) { + data = new byte[nameData.length + 4 - (nameData.length % 4)]; + System.arraycopy(nameData, 0, data, 0, nameData.length); + mName = data; + } else { + mName = nameData; + } + mExtraSize += mName.length; + mExtraSize += + mLayerExtraLength + 4 + mLayerExtraKey.length + mLayerExtraSignature.length; + + mImage = image; + + if (!visible) { + mFlags |= FLAG_INVISIBLE; + } + } + + int getLength() { + int length = 4 * 4 + 2; + + for (Channel channel : mChannelInfo) { + length += channel.getLength(); + } + + length += mBlendSignature.length; + length += mBlendMode.length; + length += 4; + length += 4; + length += mExtraSize; + + return length; + } + + void write(DataOutputStream out) throws IOException { + out.writeInt(mTop); + out.writeInt(mLeft); + out.writeInt(mBottom); + out.writeInt(mRight); + + out.writeShort(mChannelCount); + for (Channel channel : mChannelInfo) { + channel.write(out); + } + + out.write(mBlendSignature); + out.write(mBlendMode); + + out.write(mOpacity); + out.write(mClipping); + out.write(mFlags); + out.write(mFiller); + + out.writeInt(mExtraSize); + out.writeInt(mMaskDataLength); + + out.writeInt(mBlendRangeDataLength); + + out.write(mName); + + out.write(mLayerExtraSignature); + out.write(mLayerExtraKey); + out.writeInt(mLayerExtraLength); + out.writeInt(mOriginalName.length() + 1); + out.write(mOriginalName.getBytes("UTF-16")); + } + + void writeImageData(DataOutputStream out) throws IOException { + writeImage(mImage, out, true); + } + } + + @SuppressWarnings( { + "UnusedDeclaration" + }) + static class Channel { + static final short ID_RED = 0; + + static final short ID_GREEN = 1; + + static final short ID_BLUE = 2; + + static final short ID_ALPHA = -1; + + static final short ID_LAYER_MASK = -2; + + final short mId; + + final int mDataLength; + + Channel(short id, int dataLength) { + mId = id; + mDataLength = dataLength + 2; + } + + int getLength() { + return 2 + 4 + mDataLength; + } + + void write(DataOutputStream out) throws IOException { + out.writeShort(mId); + out.writeInt(mDataLength); + } + } +} diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/TreeColumnResizer.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/TreeColumnResizer.java index ad18540..6b20366 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/TreeColumnResizer.java +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/util/TreeColumnResizer.java @@ -25,10 +25,13 @@ import org.eclipse.swt.widgets.TreeColumn; public class TreeColumnResizer { private TreeColumn column1; + private TreeColumn column2; private Composite control; + private int column1Width; + private int column2Width; private final static int MIN_COLUMN1_WIDTH = 18; diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about-small.jpg b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about-small.jpg Binary files differnew file mode 100644 index 0000000..72ecabc --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about-small.jpg diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg Binary files differnew file mode 100644 index 0000000..2183168 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/about.jpg diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png Binary files differnew file mode 100644 index 0000000..240862f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/auto-refresh.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png Binary files differnew file mode 100644 index 0000000..0f25426 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/capture-psd.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png Binary files differnew file mode 100644 index 0000000..fd107ed --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png Binary files differnew file mode 100644 index 0000000..9a7eed4 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/device-view.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png Binary files differnew file mode 100644 index 0000000..a9de0ec --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/display.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png Binary files differnew file mode 100644 index 0000000..4fcab3f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/filtered.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png Binary files differindex b52a342..800000d 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/green.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png Binary files differnew file mode 100644 index 0000000..6e51701 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/inspect-screenshot.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png Binary files differnew file mode 100644 index 0000000..ee75f69 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/invalidate.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png Binary files differnew file mode 100644 index 0000000..3329ec9 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-all-views.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png Binary files differnew file mode 100644 index 0000000..4817252 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-overlay.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png Binary files differnew file mode 100644 index 0000000..8f01dda --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/load-view-hierarchy.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png Binary files differnew file mode 100644 index 0000000..db6f13b --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/not-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png Binary files differnew file mode 100644 index 0000000..cd88803 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-black.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png Binary files differnew file mode 100644 index 0000000..5f05662 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/on-white.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.png Binary files differnew file mode 100644 index 0000000..1e44000 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png Binary files differnew file mode 100644 index 0000000..ec51cec --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/pixel-perfect-view.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png Binary files differindex 338c2d9..a2ab855 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/red.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png Binary files differnew file mode 100644 index 0000000..8fddcae --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/refresh-windows.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png Binary files differnew file mode 100644 index 0000000..92a78c8 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/request-layout.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png Binary files differnew file mode 100644 index 0000000..2c0bab1 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/save.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png Binary files differnew file mode 100644 index 0000000..9ef6b34 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered-small.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png Binary files differnew file mode 100644 index 0000000..1f59685 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-filtered.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png Binary files differnew file mode 100644 index 0000000..538e385 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected-small.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png Binary files differnew file mode 100644 index 0000000..5cd5c3f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png Binary files differnew file mode 100644 index 0000000..e39e90a --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/show-overlay.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png Binary files differnew file mode 100644 index 0000000..175ad1f --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view-selected.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png Binary files differnew file mode 100644 index 0000000..23aa424 --- /dev/null +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/tree-view.png diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png Binary files differindex b6fadac..e9b5781 100644 --- a/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png +++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/resources/images/yellow.png |